diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 0301a9fe81e..00000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,1383 +0,0 @@ -version: 2.1 -orbs: - aws-cli: circleci/aws-cli@4.1.1 - docker: circleci/docker@2.3.0 - -executors: - golang: - docker: - # Must match GO_VERSION_MIN in project root - - image: cimg/go:1.21.7 - resource_class: medium+ - golang-2xl: - docker: - # Must match GO_VERSION_MIN in project root - - image: cimg/go:1.21.7 - resource_class: 2xlarge - ubuntu: - docker: - - image: ubuntu:20.04 - -commands: - build-platform-specific: - parameters: - linux: - default: true - description: is a linux build environment? - type: boolean - darwin: - 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 - - run: git submodule sync - - run: git submodule update --init - - when: - condition: <> - steps: - - install-ubuntu-deps - - check-go-version - - when: - condition: <> - steps: - - run: - name: Install Go - command: | - 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 - command: | - echo 'export GOPATH="${HOME}/go"' >> $BASH_ENV - - run: go version - - run: - name: Install dependencies with Homebrew - command: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config coreutils jq hwloc - - run: - name: Install Rust - command: | - curl https://sh.rustup.rs -sSf | sh -s -- -y - - run: make deps - download-params: - steps: - - restore_cache: - name: Restore parameters cache - keys: - - 'v26-2k-lotus-params' - - run: ./lotus fetch-params 2048 - - save_cache: - name: Save parameters cache - key: 'v26-2k-lotus-params' - paths: - - /var/tmp/filecoin-proof-parameters/ - install_ipfs: - steps: - - run: | - curl -O https://dist.ipfs.tech/kubo/v0.16.0/kubo_v0.16.0_linux-amd64.tar.gz - tar -xvzf kubo_v0.16.0_linux-amd64.tar.gz - pushd kubo - sudo bash install.sh - popd - rm -rf kubo - rm kubo_v0.16.0_linux-amd64.tar.gz - git_fetch_all_tags: - steps: - - run: - name: fetch all tags - command: | - git fetch --all - install-ubuntu-deps: - steps: - - run: sudo apt install curl ca-certificates gnupg - - run: sudo apt-get update - - run: sudo apt-get install ocl-icd-opencl-dev libhwloc-dev - check-go-version: - steps: - - run: | - v=`go version | { read _ _ v _; echo ${v#go}; }` - if [[ $v != `cat GO_VERSION_MIN` ]]; then - echo "GO_VERSION_MIN file does not match the go version being used." - echo "Please update image to cimg/go:`cat GO_VERSION_MIN` or update GO_VERSION_MIN to $v." - exit 1 - fi - -jobs: - build: - executor: golang - working_directory: ~/lotus - steps: - - checkout - - git_fetch_all_tags - - run: git submodule sync - - run: git submodule update --init - - install-ubuntu-deps - - check-go-version - - run: make deps lotus - - persist_to_workspace: - root: ~/ - paths: - - "lotus" - mod-tidy-check: - executor: golang - working_directory: ~/lotus - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - run: go mod tidy -v - - run: - name: Check git diff - command: | - git --no-pager diff go.mod go.sum - git --no-pager diff --quiet go.mod go.sum - - test: - description: | - Run tests with gotestsum. - working_directory: ~/lotus - parameters: &test-params - resource_class: - type: string - default: medium+ - go-test-flags: - type: string - default: "-timeout 20m" - description: Flags passed to go test. - target: - type: string - default: "./..." - description: Import paths of packages to be tested. - proofs-log-test: - type: string - default: "0" - get-params: - type: boolean - default: false - suite: - type: string - default: unit - description: Test suite name to report to CircleCI. - docker: - - image: cimg/go:1.21 - environment: - LOTUS_HARMONYDB_HOSTS: yugabyte - - image: yugabytedb/yugabyte:2.18.0.0-b65 - command: bin/yugabyted start --daemon=false - name: yugabyte - resource_class: << parameters.resource_class >> - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - when: - condition: << parameters.get-params >> - steps: - - download-params - - run: - name: go test - environment: - TEST_RUSTPROOFS_LOGS: << parameters.proofs-log-test >> - SKIP_CONFORMANCE: "1" - LOTUS_SRC_DIR: /home/circleci/project - command: | - mkdir -p /tmp/test-reports/<< parameters.suite >> - mkdir -p /tmp/test-artifacts - dockerize -wait tcp://yugabyte:5433 -timeout 3m - env - gotestsum \ - --format standard-verbose \ - --junitfile /tmp/test-reports/<< parameters.suite >>/junit.xml \ - --jsonfile /tmp/test-artifacts/<< parameters.suite >>.json \ - --packages="<< parameters.target >>" \ - -- << parameters.go-test-flags >> - no_output_timeout: 30m - - store_test_results: - path: /tmp/test-reports - - store_artifacts: - path: /tmp/test-artifacts/<< parameters.suite >>.json - - test-conformance: - working_directory: ~/lotus - description: | - Run tests using a corpus of interoperable test vectors for Filecoin - implementations to test their correctness and compliance with the Filecoin - specifications. - parameters: - <<: *test-params - vectors-branch: - type: string - default: "" - description: | - Branch on github.com/filecoin-project/test-vectors to checkout and - test with. If empty (the default) the commit defined by the git - submodule is used. - docker: - - image: cimg/go:1.21 - resource_class: << parameters.resource_class >> - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - download-params - - when: - condition: - not: - equal: [ "", << parameters.vectors-branch >> ] - steps: - - run: - name: checkout vectors branch - command: | - cd extern/test-vectors - git fetch - git checkout origin/<< parameters.vectors-branch >> - - run: - name: install statediff globally - command: | - ## statediff is optional; we succeed even if compilation fails. - mkdir -p /tmp/statediff - git clone https://github.com/filecoin-project/statediff.git /tmp/statediff - cd /tmp/statediff - go install ./cmd/statediff || exit 0 - - run: - name: go test - environment: - SKIP_CONFORMANCE: "0" - command: | - mkdir -p /tmp/test-reports - mkdir -p /tmp/test-artifacts - gotestsum \ - --format pkgname-and-test-fails \ - --junitfile /tmp/test-reports/junit.xml \ - -- \ - -v -coverpkg ./chain/vm/,github.com/filecoin-project/specs-actors/... -coverprofile=/tmp/conformance.out ./conformance/ - go tool cover -html=/tmp/conformance.out -o /tmp/test-artifacts/conformance-coverage.html - no_output_timeout: 30m - - store_test_results: - path: /tmp/test-reports - - store_artifacts: - path: /tmp/test-artifacts/conformance-coverage.html - - build-linux-amd64: - executor: golang - steps: - - build-platform-specific - - run: make lotus lotus-miner lotus-worker - - run: - name: check tag and version output match - command: ./scripts/version-check.sh ./lotus - - run: | - mkdir -p /tmp/workspace/linux_amd64_v1 && \ - mv lotus lotus-miner lotus-worker /tmp/workspace/linux_amd64_v1/ - - persist_to_workspace: - root: /tmp/workspace - paths: - - linux_amd64_v1 - - build-darwin-amd64: - description: build darwin lotus binary - working_directory: ~/go/src/github.com/filecoin-project/lotus - macos: - xcode: "13.4.1" - steps: - - build-platform-specific: - 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 - - run: | - mkdir -p /tmp/workspace/darwin_amd64_v1 && \ - mv lotus lotus-miner lotus-worker /tmp/workspace/darwin_amd64_v1/ - - persist_to_workspace: - root: /tmp/workspace - paths: - - darwin_amd64_v1 - - build-darwin-arm64: - description: self-hosted m1 runner - working_directory: ~/go/src/github.com/filecoin-project/lotus - machine: true - resource_class: filecoin-project/self-hosted-m1 - steps: - - run: echo 'export PATH=/opt/homebrew/bin:"$PATH"' >> "$BASH_ENV" - - build-platform-specific: - 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 - - run: | - mkdir -p /tmp/workspace/darwin_arm64 && \ - mv lotus lotus-miner lotus-worker /tmp/workspace/darwin_arm64/ - - persist_to_workspace: - root: /tmp/workspace - paths: - - darwin_arm64 - - run: - command: make clean - when: always - - run: - name: cleanup homebrew - command: HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall pkg-config coreutils jq hwloc - when: always - - release: - executor: golang - parameters: - dry-run: - default: false - description: should this release actually publish it's artifacts? - type: boolean - steps: - - checkout - - run: | - echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list - sudo apt update - sudo apt install goreleaser-pro - - install_ipfs - - attach_workspace: - at: /tmp/workspace - - when: - condition: << parameters.dry-run >> - steps: - - run: goreleaser release --rm-dist --snapshot --debug - - run: ./scripts/generate-checksums.sh - - when: - condition: - not: << parameters.dry-run >> - steps: - - run: goreleaser release --rm-dist --debug - - run: ./scripts/generate-checksums.sh - - run: ./scripts/publish-checksums.sh - - gofmt: - executor: golang - working_directory: ~/lotus - steps: - - run: - command: "! go fmt ./... 2>&1 | read" - - gen-check: - executor: golang - working_directory: ~/lotus - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - 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 && git --no-pager diff --quiet - - run: make docsgen-cli - - run: git --no-pager diff && git --no-pager diff --quiet - - docs-check: - executor: golang - working_directory: ~/lotus - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - run: go install golang.org/x/tools/cmd/goimports - - run: zcat build/openrpc/full.json.gz | jq > ../pre-openrpc-full - - run: zcat build/openrpc/miner.json.gz | jq > ../pre-openrpc-miner - - run: zcat build/openrpc/worker.json.gz | jq > ../pre-openrpc-worker - - run: make docsgen - - 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: 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-all: - description: | - Run golangci-lint. - working_directory: ~/lotus - parameters: - args: - type: string - default: '' - description: | - Arguments to pass to golangci-lint - docker: - - image: cimg/go:1.21 - resource_class: medium+ - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - run: - name: Lint - command: | - golangci-lint run -v --timeout 10m \ - --concurrency 4 << parameters.args >> - - 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: "" - description: > - The release channel to use for this image. - push: - type: boolean - default: false - description: > - When true, pushes the image to Dockerhub - steps: - - setup_remote_docker - - checkout - - git_fetch_all_tags - - run: git submodule sync - - run: git submodule update --init - - - 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: - ci: - jobs: - - build - - lint-all: - requires: - - build - - mod-tidy-check: - requires: - - build - - gofmt: - requires: - - build - - gen-check: - requires: - - build - - docs-check: - requires: - - build - - test: - name: test-itest-api - requires: - - build - suite: itest-api - target: "./itests/api_test.go" - - test: - name: test-itest-batch_deal - requires: - - build - suite: itest-batch_deal - target: "./itests/batch_deal_test.go" - - test: - name: test-itest-cli - requires: - - build - suite: itest-cli - target: "./itests/cli_test.go" - - test: - name: test-itest-deadlines - requires: - - build - suite: itest-deadlines - target: "./itests/deadlines_test.go" - - test: - name: test-itest-deals_512mb - requires: - - build - suite: itest-deals_512mb - target: "./itests/deals_512mb_test.go" - - test: - name: test-itest-deals_anycid - requires: - - build - suite: itest-deals_anycid - target: "./itests/deals_anycid_test.go" - - test: - name: test-itest-deals_concurrent - requires: - - build - suite: itest-deals_concurrent - target: "./itests/deals_concurrent_test.go" - resource_class: 2xlarge - - test: - name: test-itest-deals_invalid_utf8_label - requires: - - build - suite: itest-deals_invalid_utf8_label - target: "./itests/deals_invalid_utf8_label_test.go" - - test: - name: test-itest-deals_max_staging_deals - requires: - - build - suite: itest-deals_max_staging_deals - target: "./itests/deals_max_staging_deals_test.go" - - test: - name: test-itest-deals_offline - requires: - - build - suite: itest-deals_offline - target: "./itests/deals_offline_test.go" - - test: - name: test-itest-deals_padding - requires: - - build - suite: itest-deals_padding - target: "./itests/deals_padding_test.go" - - test: - name: test-itest-deals_partial_retrieval_dm-level - requires: - - build - suite: itest-deals_partial_retrieval_dm-level - target: "./itests/deals_partial_retrieval_dm-level_test.go" - - test: - name: test-itest-deals_partial_retrieval - requires: - - build - suite: itest-deals_partial_retrieval - target: "./itests/deals_partial_retrieval_test.go" - - test: - name: test-itest-deals_power - requires: - - build - suite: itest-deals_power - target: "./itests/deals_power_test.go" - - test: - name: test-itest-deals_pricing - requires: - - build - suite: itest-deals_pricing - target: "./itests/deals_pricing_test.go" - - test: - name: test-itest-deals_publish - requires: - - build - suite: itest-deals_publish - target: "./itests/deals_publish_test.go" - - test: - name: test-itest-deals_remote_retrieval - requires: - - build - suite: itest-deals_remote_retrieval - target: "./itests/deals_remote_retrieval_test.go" - - test: - name: test-itest-deals_retry_deal_no_funds - requires: - - build - suite: itest-deals_retry_deal_no_funds - target: "./itests/deals_retry_deal_no_funds_test.go" - - test: - name: test-itest-deals - requires: - - build - suite: itest-deals - target: "./itests/deals_test.go" - - test: - name: test-itest-decode_params - requires: - - build - suite: itest-decode_params - target: "./itests/decode_params_test.go" - - test: - name: test-itest-direct_data_onboard - requires: - - build - suite: itest-direct_data_onboard - target: "./itests/direct_data_onboard_test.go" - - test: - name: test-itest-direct_data_onboard_verified - requires: - - build - suite: itest-direct_data_onboard_verified - target: "./itests/direct_data_onboard_verified_test.go" - - test: - name: test-itest-dup_mpool_messages - requires: - - build - suite: itest-dup_mpool_messages - target: "./itests/dup_mpool_messages_test.go" - - test: - name: test-itest-eth_account_abstraction - requires: - - build - suite: itest-eth_account_abstraction - target: "./itests/eth_account_abstraction_test.go" - - test: - name: test-itest-eth_api - requires: - - build - suite: itest-eth_api - target: "./itests/eth_api_test.go" - - test: - name: test-itest-eth_balance - requires: - - build - suite: itest-eth_balance - target: "./itests/eth_balance_test.go" - - test: - name: test-itest-eth_block_hash - requires: - - build - suite: itest-eth_block_hash - target: "./itests/eth_block_hash_test.go" - - test: - name: test-itest-eth_bytecode - requires: - - build - suite: itest-eth_bytecode - target: "./itests/eth_bytecode_test.go" - - test: - name: test-itest-eth_config - requires: - - build - suite: itest-eth_config - target: "./itests/eth_config_test.go" - - test: - name: test-itest-eth_conformance - requires: - - build - suite: itest-eth_conformance - target: "./itests/eth_conformance_test.go" - - test: - name: test-itest-eth_deploy - requires: - - build - suite: itest-eth_deploy - target: "./itests/eth_deploy_test.go" - - test: - name: test-itest-eth_fee_history - requires: - - build - suite: itest-eth_fee_history - target: "./itests/eth_fee_history_test.go" - - test: - name: test-itest-eth_filter - requires: - - build - suite: itest-eth_filter - target: "./itests/eth_filter_test.go" - - test: - name: test-itest-eth_hash_lookup - requires: - - build - suite: itest-eth_hash_lookup - target: "./itests/eth_hash_lookup_test.go" - - test: - name: test-itest-eth_transactions - requires: - - build - suite: itest-eth_transactions - target: "./itests/eth_transactions_test.go" - - test: - name: test-itest-fevm_address - requires: - - build - suite: itest-fevm_address - target: "./itests/fevm_address_test.go" - - test: - name: test-itest-fevm_events - requires: - - build - suite: itest-fevm_events - target: "./itests/fevm_events_test.go" - - test: - name: test-itest-fevm - requires: - - build - suite: itest-fevm - target: "./itests/fevm_test.go" - - test: - name: test-itest-gas_estimation - requires: - - build - suite: itest-gas_estimation - target: "./itests/gas_estimation_test.go" - - test: - name: test-itest-gateway - requires: - - build - suite: itest-gateway - target: "./itests/gateway_test.go" - - test: - name: test-itest-get_messages_in_ts - requires: - - build - suite: itest-get_messages_in_ts - target: "./itests/get_messages_in_ts_test.go" - - test: - name: test-itest-harmonydb - requires: - - build - suite: itest-harmonydb - target: "./itests/harmonydb_test.go" - - test: - name: test-itest-harmonytask - requires: - - build - suite: itest-harmonytask - target: "./itests/harmonytask_test.go" - - test: - name: test-itest-lite_migration - requires: - - build - suite: itest-lite_migration - target: "./itests/lite_migration_test.go" - - test: - name: test-itest-lookup_robust_address - requires: - - build - suite: itest-lookup_robust_address - target: "./itests/lookup_robust_address_test.go" - - test: - name: test-itest-mempool - requires: - - build - suite: itest-mempool - target: "./itests/mempool_test.go" - - test: - name: test-itest-migration - requires: - - build - suite: itest-migration - target: "./itests/migration_test.go" - - test: - name: test-itest-mpool_msg_uuid - requires: - - build - suite: itest-mpool_msg_uuid - target: "./itests/mpool_msg_uuid_test.go" - - test: - name: test-itest-mpool_push_with_uuid - requires: - - build - suite: itest-mpool_push_with_uuid - target: "./itests/mpool_push_with_uuid_test.go" - - test: - name: test-itest-msgindex - requires: - - build - suite: itest-msgindex - target: "./itests/msgindex_test.go" - - test: - name: test-itest-multisig - requires: - - build - suite: itest-multisig - target: "./itests/multisig_test.go" - - test: - name: test-itest-net - requires: - - build - suite: itest-net - target: "./itests/net_test.go" - - test: - name: test-itest-nonce - requires: - - build - suite: itest-nonce - target: "./itests/nonce_test.go" - - test: - name: test-itest-path_detach_redeclare - requires: - - build - suite: itest-path_detach_redeclare - target: "./itests/path_detach_redeclare_test.go" - - test: - name: test-itest-path_type_filters - requires: - - build - suite: itest-path_type_filters - target: "./itests/path_type_filters_test.go" - - test: - name: test-itest-paych_api - requires: - - build - suite: itest-paych_api - target: "./itests/paych_api_test.go" - - test: - name: test-itest-paych_cli - requires: - - build - suite: itest-paych_cli - target: "./itests/paych_cli_test.go" - - test: - name: test-itest-pending_deal_allocation - requires: - - build - suite: itest-pending_deal_allocation - target: "./itests/pending_deal_allocation_test.go" - - test: - name: test-itest-raft_messagesigner - requires: - - build - suite: itest-raft_messagesigner - target: "./itests/raft_messagesigner_test.go" - - test: - name: test-itest-remove_verifreg_datacap - requires: - - build - suite: itest-remove_verifreg_datacap - target: "./itests/remove_verifreg_datacap_test.go" - - test: - name: test-itest-sealing_resources - requires: - - build - suite: itest-sealing_resources - target: "./itests/sealing_resources_test.go" - - test: - name: test-itest-sector_finalize_early - requires: - - build - suite: itest-sector_finalize_early - target: "./itests/sector_finalize_early_test.go" - - test: - name: test-itest-sector_import_full - requires: - - build - suite: itest-sector_import_full - target: "./itests/sector_import_full_test.go" - - test: - name: test-itest-sector_import_simple - requires: - - build - suite: itest-sector_import_simple - target: "./itests/sector_import_simple_test.go" - - test: - name: test-itest-sector_miner_collateral - requires: - - build - suite: itest-sector_miner_collateral - target: "./itests/sector_miner_collateral_test.go" - - test: - name: test-itest-sector_numassign - requires: - - build - suite: itest-sector_numassign - target: "./itests/sector_numassign_test.go" - - test: - name: test-itest-sector_pledge - requires: - - build - suite: itest-sector_pledge - target: "./itests/sector_pledge_test.go" - resource_class: 2xlarge - get-params: true - - - test: - name: test-itest-sector_terminate - requires: - - build - suite: itest-sector_terminate - target: "./itests/sector_terminate_test.go" - - test: - name: test-itest-sector_unseal - requires: - - build - suite: itest-sector_unseal - target: "./itests/sector_unseal_test.go" - - test: - name: test-itest-self_sent_txn - requires: - - build - suite: itest-self_sent_txn - target: "./itests/self_sent_txn_test.go" - - test: - name: test-itest-splitstore - requires: - - build - suite: itest-splitstore - target: "./itests/splitstore_test.go" - - test: - name: test-itest-verifreg - requires: - - build - suite: itest-verifreg - target: "./itests/verifreg_test.go" - - test: - name: test-itest-wdpost_config - requires: - - build - suite: itest-wdpost_config - target: "./itests/wdpost_config_test.go" - - test: - name: test-itest-wdpost_dispute - requires: - - build - suite: itest-wdpost_dispute - target: "./itests/wdpost_dispute_test.go" - - test: - name: test-itest-wdpost_no_miner_storage - requires: - - build - suite: itest-wdpost_no_miner_storage - target: "./itests/wdpost_no_miner_storage_test.go" - - test: - name: test-itest-wdpost - requires: - - build - suite: itest-wdpost - target: "./itests/wdpost_test.go" - get-params: true - - - test: - name: test-itest-wdpost_worker_config - requires: - - build - suite: itest-wdpost_worker_config - target: "./itests/wdpost_worker_config_test.go" - resource_class: 2xlarge - - test: - name: test-itest-worker - requires: - - build - suite: itest-worker - target: "./itests/worker_test.go" - resource_class: 2xlarge - - test: - name: test-itest-worker_upgrade - requires: - - build - suite: itest-worker_upgrade - target: "./itests/worker_upgrade_test.go" - - test: - name: test-unit-cli - requires: - - build - suite: utest-unit-cli - target: "./cli/... ./cmd/... ./api/..." - resource_class: 2xlarge - get-params: true - - test: - name: test-unit-node - requires: - - build - suite: utest-unit-node - target: "./node/..." - - test: - name: test-unit-rest - requires: - - build - suite: utest-unit-rest - target: "./blockstore/... ./build/... ./chain/... ./conformance/... ./gateway/... ./journal/... ./lib/... ./markets/... ./paychmgr/... ./tools/..." - resource_class: 2xlarge - - test: - name: test-unit-storage - requires: - - build - suite: utest-unit-storage - target: "./storage/... ./extern/..." - get-params: true - - test: - go-test-flags: "-run=TestMulticoreSDR" - requires: - - build - suite: multicore-sdr-check - target: "./storage/sealer/ffiwrapper" - proofs-log-test: "1" - - test-conformance: - requires: - - build - suite: conformance - target: "./conformance" - - release: - jobs: - - build-linux-amd64: - name: "Build ( linux / amd64 )" - filters: - branches: - only: - - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - - /^ci\/.*$/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - build-darwin-amd64: - name: "Build ( darwin / amd64 )" - filters: - branches: - only: - - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - - /^ci\/.*$/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - build-darwin-arm64: - name: "Build ( darwin / arm64 )" - filters: - branches: - only: - - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - - /^ci\/.*$/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - release: - name: "Release" - requires: - - "Build ( darwin / amd64 )" - - "Build ( linux / amd64 )" - - "Build ( darwin / arm64 )" - filters: - branches: - ignore: - - /^.*$/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - release: - name: "Release (dry-run)" - dry-run: true - requires: - - "Build ( darwin / amd64 )" - - "Build ( linux / amd64 )" - - "Build ( darwin / arm64 )" - filters: - branches: - only: - - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - - /^ci\/.*$/ - - 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+)?$/ - - build-docker: - name: "Docker push (lotus-all-in-one / stable / butterflynet)" - image: lotus-all-in-one - channel: stable - network: butterflynet - push: true - filters: - branches: - ignore: - - /.*/ - tags: - only: - - /^v\d+\.\d+\.\d+$/ - - build-docker: - name: "Docker push (lotus-all-in-one / candidate / butterflynet)" - image: lotus-all-in-one - channel: candidate - network: butterflynet - push: true - filters: - branches: - ignore: - - /.*/ - tags: - only: - - /^v\d+\.\d+\.\d+-rc\d+$/ - - 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 - network: calibnet - push: true - filters: - branches: - ignore: - - /.*/ - tags: - only: - - /^v\d+\.\d+\.\d+$/ - - build-docker: - name: "Docker push (lotus-all-in-one / candidate / calibnet)" - image: lotus-all-in-one - channel: candidate - network: calibnet - push: true - filters: - branches: - ignore: - - /.*/ - tags: - only: - - /^v\d+\.\d+\.\d+-rc\d+$/ - - 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: - - /.*/ - tags: - only: - - /^v\d+\.\d+\.\d+$/ - - 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: - - /.*/ - 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: - - schedule: - cron: "0 0 * * *" - filters: - branches: - only: - - master - jobs: - - 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 deleted file mode 100644 index 19329247a83..00000000000 --- a/.circleci/gen.go +++ /dev/null @@ -1,156 +0,0 @@ -package main - -import ( - "embed" - "fmt" - "os" - "path/filepath" - "sort" - "strings" - "text/template" -) - -var GoVersion = "" // from init below. Ex: 1.19.7 - -//go:generate go run ./gen.go .. - -//go:embed template.yml -var templateFile embed.FS - -func init() { - b, err := os.ReadFile("../go.mod") - if err != nil { - panic("cannot find go.mod in parent folder") - } - for _, line := range strings.Split(string(b), "\n") { - if strings.HasPrefix(line, "go ") { - GoVersion = line[3:] - } - } -} - -type ( - dirs = []string - suite = string -) - -// groupedUnitTests maps suite names to top-level directories that should be -// included in that suite. The program adds an implicit group "rest" that -// includes all other top-level directories. -var groupedUnitTests = map[suite]dirs{ - "unit-node": {"node"}, - "unit-storage": {"storage", "extern"}, - "unit-cli": {"cli", "cmd", "api"}, -} - -func main() { - if len(os.Args) != 2 { - panic("expected path to repo as argument") - } - - repo := os.Args[1] - - tmpl := template.New("template.yml") - tmpl.Delims("[[", "]]") - tmpl.Funcs(template.FuncMap{ - "stripSuffix": func(in string) string { - return strings.TrimSuffix(in, "_test.go") - }, - }) - tmpl = template.Must(tmpl.ParseFS(templateFile, "*")) - - // list all itests. - itests, err := filepath.Glob(filepath.Join(repo, "./itests/*_test.go")) - if err != nil { - panic(err) - } - - // strip the dir from all entries. - for i, f := range itests { - itests[i] = filepath.Base(f) - } - - // calculate the exclusion set of unit test directories to exclude because - // they are already included in a grouped suite. - var excluded = map[string]struct{}{} - for _, ss := range groupedUnitTests { - for _, s := range ss { - e, err := filepath.Abs(filepath.Join(repo, s)) - if err != nil { - panic(err) - } - // Redundantly flag both absolute and relative paths as excluded - excluded[filepath.Join(repo, s)] = struct{}{} - excluded[e] = struct{}{} - } - } - - // all unit tests top-level dirs that are not itests, nor included in other suites. - var rest = map[string]struct{}{} - err = filepath.Walk(repo, func(path string, f os.FileInfo, err error) error { - // include all tests that aren't in the itests directory. - if strings.Contains(path, "itests") { - return filepath.SkipDir - } - // exclude all tests included in other suites - if f.IsDir() { - if _, ok := excluded[path]; ok { - return filepath.SkipDir - } - } - if strings.HasSuffix(path, "_test.go") { - rel, err := filepath.Rel(repo, path) - if err != nil { - panic(err) - } - // take the first directory - rest[strings.Split(rel, string(os.PathSeparator))[0]] = struct{}{} - } - return err - }) - if err != nil { - panic(err) - } - - // add other directories to a 'rest' suite. - for k := range rest { - groupedUnitTests["unit-rest"] = append(groupedUnitTests["unit-rest"], k) - } - - // map iteration guarantees no order, so sort the array in-place. - sort.Strings(groupedUnitTests["unit-rest"]) - - // form the input data. - type data struct { - Networks []string - ItestFiles []string - UnitSuites map[string]string - GoVersion string - } - in := data{ - Networks: []string{"mainnet", "butterflynet", "calibnet", "debug"}, - ItestFiles: itests, - UnitSuites: func() map[string]string { - ret := make(map[string]string) - for name, dirs := range groupedUnitTests { - for i, d := range dirs { - dirs[i] = fmt.Sprintf("./%s/...", d) // turn into package - } - ret[name] = strings.Join(dirs, " ") - } - return ret - }(), - GoVersion: GoVersion, - } - - out, err := os.Create("./config.yml") - if err != nil { - panic(err) - } - defer out.Close() - - // execute the template. - if err := tmpl.Execute(out, in); err != nil { - panic(err) - } -} diff --git a/.circleci/template.yml b/.circleci/template.yml deleted file mode 100644 index c0644c80d33..00000000000 --- a/.circleci/template.yml +++ /dev/null @@ -1,759 +0,0 @@ -version: 2.1 -orbs: - aws-cli: circleci/aws-cli@4.1.1 - docker: circleci/docker@2.3.0 - -executors: - golang: - docker: - # Must match GO_VERSION_MIN in project root - - image: cimg/go:1.21.7 - resource_class: medium+ - golang-2xl: - docker: - # Must match GO_VERSION_MIN in project root - - image: cimg/go:1.21.7 - resource_class: 2xlarge - ubuntu: - docker: - - image: ubuntu:20.04 - -commands: - build-platform-specific: - parameters: - linux: - default: true - description: is a linux build environment? - type: boolean - darwin: - 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 - - run: git submodule sync - - run: git submodule update --init - - when: - condition: <> - steps: - - install-ubuntu-deps - - check-go-version - - when: - condition: <> - steps: - - run: - name: Install Go - command: | - 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 - command: | - echo 'export GOPATH="${HOME}/go"' >> $BASH_ENV - - run: go version - - run: - name: Install dependencies with Homebrew - command: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config coreutils jq hwloc - - run: - name: Install Rust - command: | - curl https://sh.rustup.rs -sSf | sh -s -- -y - - run: make deps - download-params: - steps: - - restore_cache: - name: Restore parameters cache - keys: - - 'v26-2k-lotus-params' - - run: ./lotus fetch-params 2048 - - save_cache: - name: Save parameters cache - key: 'v26-2k-lotus-params' - paths: - - /var/tmp/filecoin-proof-parameters/ - install_ipfs: - steps: - - run: | - curl -O https://dist.ipfs.tech/kubo/v0.16.0/kubo_v0.16.0_linux-amd64.tar.gz - tar -xvzf kubo_v0.16.0_linux-amd64.tar.gz - pushd kubo - sudo bash install.sh - popd - rm -rf kubo - rm kubo_v0.16.0_linux-amd64.tar.gz - git_fetch_all_tags: - steps: - - run: - name: fetch all tags - command: | - git fetch --all - install-ubuntu-deps: - steps: - - run: sudo apt install curl ca-certificates gnupg - - run: sudo apt-get update - - run: sudo apt-get install ocl-icd-opencl-dev libhwloc-dev - check-go-version: - steps: - - run: | - v=`go version | { read _ _ v _; echo ${v#go}; }` - if [["[[ $v != `cat GO_VERSION_MIN` ]]"]]; then - echo "GO_VERSION_MIN file does not match the go version being used." - echo "Please update image to cimg/go:`cat GO_VERSION_MIN` or update GO_VERSION_MIN to $v." - exit 1 - fi - -jobs: - build: - executor: golang - working_directory: ~/lotus - steps: - - checkout - - git_fetch_all_tags - - run: git submodule sync - - run: git submodule update --init - - install-ubuntu-deps - - check-go-version - - run: make deps lotus - - persist_to_workspace: - root: ~/ - paths: - - "lotus" - mod-tidy-check: - executor: golang - working_directory: ~/lotus - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - run: go mod tidy -v - - run: - name: Check git diff - command: | - git --no-pager diff go.mod go.sum - git --no-pager diff --quiet go.mod go.sum - - test: - description: | - Run tests with gotestsum. - working_directory: ~/lotus - parameters: &test-params - resource_class: - type: string - default: medium+ - go-test-flags: - type: string - default: "-timeout 20m" - description: Flags passed to go test. - target: - type: string - default: "./..." - description: Import paths of packages to be tested. - proofs-log-test: - type: string - default: "0" - get-params: - type: boolean - default: false - suite: - type: string - default: unit - description: Test suite name to report to CircleCI. - docker: - - image: cimg/go:[[ .GoVersion]] - environment: - LOTUS_HARMONYDB_HOSTS: yugabyte - - image: yugabytedb/yugabyte:2.18.0.0-b65 - command: bin/yugabyted start --daemon=false - name: yugabyte - resource_class: << parameters.resource_class >> - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - when: - condition: << parameters.get-params >> - steps: - - download-params - - run: - name: go test - environment: - TEST_RUSTPROOFS_LOGS: << parameters.proofs-log-test >> - SKIP_CONFORMANCE: "1" - LOTUS_SRC_DIR: /home/circleci/project - command: | - mkdir -p /tmp/test-reports/<< parameters.suite >> - mkdir -p /tmp/test-artifacts - dockerize -wait tcp://yugabyte:5433 -timeout 3m - env - gotestsum \ - --format standard-verbose \ - --junitfile /tmp/test-reports/<< parameters.suite >>/junit.xml \ - --jsonfile /tmp/test-artifacts/<< parameters.suite >>.json \ - --packages="<< parameters.target >>" \ - -- << parameters.go-test-flags >> - no_output_timeout: 30m - - store_test_results: - path: /tmp/test-reports - - store_artifacts: - path: /tmp/test-artifacts/<< parameters.suite >>.json - - test-conformance: - working_directory: ~/lotus - description: | - Run tests using a corpus of interoperable test vectors for Filecoin - implementations to test their correctness and compliance with the Filecoin - specifications. - parameters: - <<: *test-params - vectors-branch: - type: string - default: "" - description: | - Branch on github.com/filecoin-project/test-vectors to checkout and - test with. If empty (the default) the commit defined by the git - submodule is used. - docker: - - image: cimg/go:[[ .GoVersion]] - resource_class: << parameters.resource_class >> - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - download-params - - when: - condition: - not: - equal: [ "", << parameters.vectors-branch >> ] - steps: - - run: - name: checkout vectors branch - command: | - cd extern/test-vectors - git fetch - git checkout origin/<< parameters.vectors-branch >> - - run: - name: install statediff globally - command: | - ## statediff is optional; we succeed even if compilation fails. - mkdir -p /tmp/statediff - git clone https://github.com/filecoin-project/statediff.git /tmp/statediff - cd /tmp/statediff - go install ./cmd/statediff || exit 0 - - run: - name: go test - environment: - SKIP_CONFORMANCE: "0" - command: | - mkdir -p /tmp/test-reports - mkdir -p /tmp/test-artifacts - gotestsum \ - --format pkgname-and-test-fails \ - --junitfile /tmp/test-reports/junit.xml \ - -- \ - -v -coverpkg ./chain/vm/,github.com/filecoin-project/specs-actors/... -coverprofile=/tmp/conformance.out ./conformance/ - go tool cover -html=/tmp/conformance.out -o /tmp/test-artifacts/conformance-coverage.html - no_output_timeout: 30m - - store_test_results: - path: /tmp/test-reports - - store_artifacts: - path: /tmp/test-artifacts/conformance-coverage.html - - build-linux-amd64: - executor: golang - steps: - - build-platform-specific - - run: make lotus lotus-miner lotus-worker - - run: - name: check tag and version output match - command: ./scripts/version-check.sh ./lotus - - run: | - mkdir -p /tmp/workspace/linux_amd64_v1 && \ - mv lotus lotus-miner lotus-worker /tmp/workspace/linux_amd64_v1/ - - persist_to_workspace: - root: /tmp/workspace - paths: - - linux_amd64_v1 - - build-darwin-amd64: - description: build darwin lotus binary - working_directory: ~/go/src/github.com/filecoin-project/lotus - macos: - xcode: "13.4.1" - steps: - - build-platform-specific: - 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 - - run: | - mkdir -p /tmp/workspace/darwin_amd64_v1 && \ - mv lotus lotus-miner lotus-worker /tmp/workspace/darwin_amd64_v1/ - - persist_to_workspace: - root: /tmp/workspace - paths: - - darwin_amd64_v1 - - build-darwin-arm64: - description: self-hosted m1 runner - working_directory: ~/go/src/github.com/filecoin-project/lotus - machine: true - resource_class: filecoin-project/self-hosted-m1 - steps: - - run: echo 'export PATH=/opt/homebrew/bin:"$PATH"' >> "$BASH_ENV" - - build-platform-specific: - 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 - - run: | - mkdir -p /tmp/workspace/darwin_arm64 && \ - mv lotus lotus-miner lotus-worker /tmp/workspace/darwin_arm64/ - - persist_to_workspace: - root: /tmp/workspace - paths: - - darwin_arm64 - - run: - command: make clean - when: always - - run: - name: cleanup homebrew - command: HOMEBREW_NO_AUTO_UPDATE=1 brew uninstall pkg-config coreutils jq hwloc - when: always - - release: - executor: golang - parameters: - dry-run: - default: false - description: should this release actually publish it's artifacts? - type: boolean - steps: - - checkout - - run: | - echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list - sudo apt update - sudo apt install goreleaser-pro - - install_ipfs - - attach_workspace: - at: /tmp/workspace - - when: - condition: << parameters.dry-run >> - steps: - - run: goreleaser release --rm-dist --snapshot --debug - - run: ./scripts/generate-checksums.sh - - when: - condition: - not: << parameters.dry-run >> - steps: - - run: goreleaser release --rm-dist --debug - - run: ./scripts/generate-checksums.sh - - run: ./scripts/publish-checksums.sh - - gofmt: - executor: golang - working_directory: ~/lotus - steps: - - run: - command: "! go fmt ./... 2>&1 | read" - - gen-check: - executor: golang - working_directory: ~/lotus - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - 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 && git --no-pager diff --quiet - - run: make docsgen-cli - - run: git --no-pager diff && git --no-pager diff --quiet - - docs-check: - executor: golang - working_directory: ~/lotus - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - run: go install golang.org/x/tools/cmd/goimports - - run: zcat build/openrpc/full.json.gz | jq > ../pre-openrpc-full - - run: zcat build/openrpc/miner.json.gz | jq > ../pre-openrpc-miner - - run: zcat build/openrpc/worker.json.gz | jq > ../pre-openrpc-worker - - run: make docsgen - - 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: 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-all: - description: | - Run golangci-lint. - working_directory: ~/lotus - parameters: - args: - type: string - default: '' - description: | - Arguments to pass to golangci-lint - docker: - - image: cimg/go:[[ .GoVersion]] - resource_class: medium+ - steps: - - install-ubuntu-deps - - attach_workspace: - at: ~/ - - run: - name: Lint - command: | - golangci-lint run -v --timeout 10m \ - --concurrency 4 << parameters.args >> - - 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: "" - description: > - The release channel to use for this image. - push: - type: boolean - default: false - description: > - When true, pushes the image to Dockerhub - steps: - - setup_remote_docker - - checkout - - git_fetch_all_tags - - run: git submodule sync - - run: git submodule update --init - - - 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: - ci: - jobs: - - build - - lint-all: - requires: - - build - - mod-tidy-check: - requires: - - build - - gofmt: - requires: - - build - - gen-check: - requires: - - build - - docs-check: - requires: - - build - - [[- range $file := .ItestFiles -]] - [[ with $name := $file | stripSuffix ]] - - test: - name: test-itest-[[ $name ]] - requires: - - build - suite: itest-[[ $name ]] - target: "./itests/[[ $file ]]" - [[- if or (eq $name "worker") (eq $name "deals_concurrent") (eq $name "wdpost_worker_config") (eq $name "sector_pledge")]] - resource_class: 2xlarge - [[- end]] - [[- if or (eq $name "wdpost") (eq $name "sector_pledge")]] - get-params: true - [[end]] - [[- end ]][[- end]] - - [[- range $suite, $pkgs := .UnitSuites]] - - test: - name: test-[[ $suite ]] - requires: - - build - suite: utest-[[ $suite ]] - target: "[[ $pkgs ]]" - [[- if eq $suite "unit-storage"]] - get-params: true - [[- end -]] - [[- if eq $suite "unit-cli"]] - resource_class: 2xlarge - get-params: true - [[- end -]] - [[- if eq $suite "unit-rest"]] - resource_class: 2xlarge - [[- end -]] - [[- end]] - - test: - go-test-flags: "-run=TestMulticoreSDR" - requires: - - build - suite: multicore-sdr-check - target: "./storage/sealer/ffiwrapper" - proofs-log-test: "1" - - test-conformance: - requires: - - build - suite: conformance - target: "./conformance" - - release: - jobs: - - build-linux-amd64: - name: "Build ( linux / amd64 )" - filters: - branches: - only: - - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - - /^ci\/.*$/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - build-darwin-amd64: - name: "Build ( darwin / amd64 )" - filters: - branches: - only: - - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - - /^ci\/.*$/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - build-darwin-arm64: - name: "Build ( darwin / arm64 )" - filters: - branches: - only: - - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - - /^ci\/.*$/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - release: - name: "Release" - requires: - - "Build ( darwin / amd64 )" - - "Build ( linux / amd64 )" - - "Build ( darwin / arm64 )" - filters: - branches: - ignore: - - /^.*$/ - tags: - only: - - /^v\d+\.\d+\.\d+(-rc\d+)?$/ - - release: - name: "Release (dry-run)" - dry-run: true - requires: - - "Build ( darwin / amd64 )" - - "Build ( linux / amd64 )" - - "Build ( darwin / arm64 )" - filters: - branches: - only: - - /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - - /^ci\/.*$/ - [[- 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+)?$/ - [[- end]] - - 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: - - schedule: - cron: "0 0 * * *" - filters: - branches: - only: - - master - jobs: - [[- 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/.github/CODEOWNERS b/.github/CODEOWNERS index b8ec66f00ea..5eeba24f292 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,6 +1,3 @@ # Reference # https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners -# Global owners -# Ensure maintainers team is a requested reviewer for non-draft PRs -* @filecoin-project/lotus-maintainers diff --git a/.github/actions/install-go/action.yml b/.github/actions/install-go/action.yml new file mode 100644 index 00000000000..173559284f7 --- /dev/null +++ b/.github/actions/install-go/action.yml @@ -0,0 +1,16 @@ +name: Install Go +description: Install Go for Filecoin Lotus + +runs: + using: composite + steps: + - uses: actions/setup-go@v5 + with: + go-version: stable + cache: false + - id: go-mod + uses: ipdxco/unified-github-workflows/.github/actions/read-go-mod@main + - uses: actions/setup-go@v5 + with: + go-version: ${{ fromJSON(steps.go-mod.outputs.json).Go }}.x + cache: false diff --git a/.github/actions/install-system-dependencies/action.yml b/.github/actions/install-system-dependencies/action.yml new file mode 100644 index 00000000000..f1b090ed70a --- /dev/null +++ b/.github/actions/install-system-dependencies/action.yml @@ -0,0 +1,21 @@ +name: Install System Dependencies +description: Install System dependencies for Filecoin Lotus + +runs: + using: composite + steps: + - if: runner.os == 'Linux' + run: | + # List processes to enable debugging in case /var/lib/apt/lists/ is locked + ps aux + sudo apt-get update -y + sudo apt-get install -y ocl-icd-opencl-dev libhwloc-dev pkg-config + shell: bash + - if: runner.os == 'macOS' + env: + HOMEBREW_NO_AUTO_UPDATE: '1' + run: | + brew install hwloc pkg-config + echo "CPATH=$(brew --prefix)/include" | tee -a $GITHUB_ENV + echo "LIBRARY_PATH=$(brew --prefix)/lib" | tee -a $GITHUB_ENV + shell: bash diff --git a/.github/actions/start-yugabytedb/action.yml b/.github/actions/start-yugabytedb/action.yml new file mode 100644 index 00000000000..13c480c6640 --- /dev/null +++ b/.github/actions/start-yugabytedb/action.yml @@ -0,0 +1,16 @@ +name: Start YugabyteDB +description: Install Yugabyte Database for Filecoin Lotus + +runs: + using: composite + steps: + - run: docker run --rm --name yugabyte -d -p 5433:5433 yugabytedb/yugabyte:2.18.0.0-b65 bin/yugabyted start --daemon=false + shell: bash + - run: | + while true; do + status=$(docker exec yugabyte bin/yugabyted status); + echo $status; + echo $status | grep Running && break; + sleep 1; + done + shell: bash diff --git a/.github/labels.yml b/.github/labels.yml deleted file mode 100644 index 7102f13117a..00000000000 --- a/.github/labels.yml +++ /dev/null @@ -1,248 +0,0 @@ -### -### Special magic GitHub labels -### https://help.github.com/en/github/building-a-strong-community/encouraging-helpful-contributions-to-your-project-with-labels -# -- name: "good first issue" - color: 7057ff - description: "Good for newcomers" -- name: "help wanted" - color: 008672 - description: "Extra attention is needed" - -### -### Goals -# -- name: goal/incentives - color: ff004d - description: "Incentinet" - -### -### Areas -# -- name: area/ux - color: 00A4E0 - description: "Area: UX" -- name: area/chain/vm - color: 00A4E2 - description: "Area: Chain/VM" -- name: area/chain/sync - color: 00A4E4 - description: "Area: Chain/Sync" -- name: area/chain/misc - color: 00A4E6 - description: "Area: Chain/Misc" -- name: area/markets - color: 00A4E8 - description: "Area: Markets" -- name: area/sealing/fsm - color: 0bb1ed - description: "Area: Sealing/FSM" -- name: area/sealing/storage - color: 0EB4F0 - description: "Area: Sealing/Storage" -- name: area/proving - color: 0EB4F0 - description: "Area: Proving" -- name: area/mining - color: 10B6F2 - description: "Area: Mining" -- name: area/client/storage - color: 13B9F5 - description: "Area: Client/Storage" -- name: area/client/retrieval - color: 15BBF7 - description: "Area: Client/Retrieval" -- name: area/wallet - color: 15BBF7 - description: "Area: Wallet" -- name: area/payment-channel - color: ff6767 - description: "Area: Payment Channel" -- name: area/multisig - color: fff0ff - description: "Area: Multisig" -- name: area/networking - color: 273f8a - description: "Area: Networking" - -### -### Kinds -# -- name: kind/bug - color: c92712 - description: "Kind: Bug" -- name: kind/chore - color: fcf0b5 - description: "Kind: Chore" -- name: kind/feature - color: FFF3B8 - description: "Kind: Feature" -- name: kind/improvement - color: FFF5BA - description: "Kind: Improvement" -- name: kind/test - color: FFF8BD - description: "Kind: Test" -- name: kind/question - color: FFFDC2 - description: "Kind: Question" -- name: kind/enhancement - color: FFFFC5 - description: "Kind: Enhancement" -- name: kind/discussion - color: FFFFC7 - description: "Kind: Discussion" - -### -### Difficulties -# -- name: dif/trivial - color: b2b7ff - description: "Can be confidently tackled by newcomers, who are widely unfamiliar with lotus" -- name: dif/easy - color: 7886d7 - description: "An existing lotus user should be able to pick this up" -- name: dif/medium - color: 6574cd - description: "Prior development experience with lotus is likely helpful" -- name: dif/hard - color: 5661b3 - description: "Suggests that having worked on the specific component affected by this issue is important" -- name: dif/expert - color: 2f365f - description: "Requires extensive knowledge of the history, implications, ramifications of the issue" - -### -### Efforts -# -- name: effort/minutes - color: e8fffe - description: "Effort: Minutes" -- name: effort/hours - color: a0f0ed - description: "Effort: Hours" -- name: effort/day - color: 64d5ca - description: "Effort: One Day" -- name: effort/days - color: 4dc0b5 - description: "Effort: Multiple Days" -- name: effort/week - color: 38a89d - description: "Effort: One Week" -- name: effort/weeks - color: 20504f - description: "Effort: Multiple Weeks" - -### -### Impacts -# -- name: impact/regression - color: f1f5f8 - description: "Impact: Regression" -- name: impact/api-breakage - color: ECF0F3 - description: "Impact: API Breakage" -- name: impact/quality - color: E7EBEE - description: "Impact: Quality" -- name: impact/dx - color: E2E6E9 - description: "Impact: Developer Experience" -- name: impact/test-flakiness - color: DDE1E4 - description: "Impact: Test Flakiness" -- name: impact/consensus - color: b20014 - description: "Impact: Consensus" - -### -### Topics -# -- name: topic/interoperability - color: bf0f73 - description: "Topic: Interoperability" -- name: topic/specs - color: CC1C80 - description: "Topic: Specs" -- name: topic/docs - color: D9298D - description: "Topic: Documentation" -- name: topic/architecture - color: E53599 - description: "Topic: Architecture" - -### -### Priorities -### -- name: P0 - color: dd362a - description: "P0: Critical Blocker" -- name: P1 - color: ce8048 - description: "P1: Must be resolved" -- name: P2 - color: dbd81a - description: "P2: Should be resolved" -- name: P3 - color: 9fea8f - description: "P3: Might get resolved" - -### -### Hints -# -#- name: hint/good-first-issue -# color: 7057ff -# description: "Hint: Good First Issue" -#- name: hint/help-wanted -# color: 008672 -# description: "Hint: Help Wanted" -- name: hint/needs-decision - color: 33B9A5 - description: "Hint: Needs Decision" -- name: hint/needs-triage - color: 1AA08C - description: "Hint: Needs Triage" -- name: hint/needs-analysis - color: 26AC98 - description: "Hint: Needs Analysis" -- name: hint/needs-author-input - color: 33B9A5 - description: "Hint: Needs Author Input" -- name: hint/needs-team-input - color: 40C6B2 - description: "Hint: Needs Team Input" -- name: hint/needs-community-input - color: 4DD3BF - description: "Hint: Needs Community Input" -- name: hint/needs-review - color: 5AE0CC - description: "Hint: Needs Review" - -### -### Statuses -# -- name: status/done - color: edb3a6 - description: "Status: Done" -- name: status/deferred - color: E0A699 - description: "Status: Deferred" -- name: status/in-progress - color: D49A8D - description: "Status: In Progress" -- name: status/blocked - color: C78D80 - description: "Status: Blocked" -- name: status/inactive - color: BA8073 - description: "Status: Inactive" -- name: status/waiting - color: AD7366 - description: "Status: Waiting" -- name: status/rotten - color: 7A4033 - description: "Status: Rotten" -- name: status/discarded - color: 6D3326 - description: "Status: Discarded / Won't fix" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000000..d7dd59e143e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,31 @@ +name: Build + +on: + pull_request: + push: + branches: + - master + - release/* + workflow_dispatch: + +defaults: + run: + shell: bash + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: {} + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - uses: ./.github/actions/install-system-dependencies + - uses: ./.github/actions/install-go + - run: make deps lotus diff --git a/.github/workflows/builtin-actor-tests.yml b/.github/workflows/builtin-actor-tests.yml new file mode 100644 index 00000000000..93d4c669e59 --- /dev/null +++ b/.github/workflows/builtin-actor-tests.yml @@ -0,0 +1,22 @@ +name: Built-in Actors + +on: + push: + paths: + - build/actors + - build/builtin_actors_gen.go + branches: + - release/* + +permissions: {} + +jobs: + release: + name: Release Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: 1.21 + - run: go test -tags=release ./build diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 00000000000..8d19589f728 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,82 @@ +name: Check + +on: + pull_request: + push: + branches: + - master + - release/* + workflow_dispatch: + +defaults: + run: + shell: bash + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: {} + +jobs: + check-docsgen: + name: Check (docs-check) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - uses: ./.github/actions/install-system-dependencies + - uses: ./.github/actions/install-go + - run: go install golang.org/x/tools/cmd/goimports + - run: make deps + - run: make docsgen + - run: git diff --exit-code + check-gen: + name: Check (gen-check) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - uses: ./.github/actions/install-system-dependencies + - uses: ./.github/actions/install-go + - run: make deps lotus + - run: go install golang.org/x/tools/cmd/goimports + - run: go install github.com/hannahhoward/cbor-gen-for + - run: make gen + - run: git diff --exit-code + - run: make docsgen-cli + - run: git diff --exit-code + check-lint: + name: Check (lint-all) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - uses: ./.github/actions/install-system-dependencies + - uses: ./.github/actions/install-go + - run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + - run: make deps + - run: golangci-lint run -v --timeout 10m --concurrency 4 + check-fmt: + name: Check (gofmt) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - uses: ./.github/actions/install-go + - run: go fmt ./... + - run: git diff --exit-code + check-mod-tidy: + name: Check (mod-tidy-check) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - uses: ./.github/actions/install-go + - run: go mod tidy -v + - run: git diff --exit-code diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 0cba5457e0d..00000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,73 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: - - master - - 'release/*' - pull_request: - # The branches below must be a subset of the branches above - branches: - - master - - 'release/*' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - language: [ 'go' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - uses: actions/setup-go@v3 - with: - go-version: '1.18.8' - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - 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. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # 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@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 00000000000..f6afe68bf01 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,94 @@ +name: Docker + +on: + push: + branches: + - master + - release/* + tags: + - v* + schedule: + - cron: '0 0 * * *' + workflow_dispatch: + +defaults: + run: + shell: bash + +permissions: {} + +jobs: + docker: + name: Docker (${{ matrix.image }} / ${{ matrix.network }}) [publish=${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/') }}] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + image: + - lotus-all-in-one + network: + - mainnet + - butterflynet + - calibnet + - debug + include: + - image: lotus + network: mainnet + env: + PUBLISH: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/') }} + steps: + - id: channel + env: + IS_MASTER: ${{ github.ref == 'refs/heads/master' }} + IS_TAG: ${{ startsWith(github.ref, 'refs/tags/') }} + IS_RC: ${{ endsWith(github.ref, '-rc') }} + IS_SCHEDULED: ${{ github.event_name == 'schedule' }} + run: | + channel='' + if [[ "$IS_MASTER" == 'true' ]]; then + if [[ "$IS_SCHEDULED" == 'true' ]]; then + channel=nightly + else + channel=master + fi + elif [[ "$IS_TAG" == 'true' ]]; then + if [[ "$IS_RC" == 'true' ]]; then + channel=candidate + else + channel=stable + fi + fi + echo "channel=$channel" | tee -a $GITHUB_ENV + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: filecoin/${{ matrix.image }} + tags: | + type=schedule + type=raw,enable=${{ github.event_name != 'schedule' && steps.channel.outputs.channel != '' }},value=${{ steps.channel.outputs.channel }} + type=ref,event=tag + type=sha,prefix= + flavor: | + latest=false + suffix=${{ matrix.network != 'mainnet' && format('-{0}', matrix.network) || '' }} + - if: env.PUBLISH == 'true' + name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push if channel is set (channel=${{ steps.channel.outputs.channel }}) + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ env.PUBLISH == 'true' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + ${{ matrix.network != 'mainnet' && format('GOFLAGS=-tags={0}', matrix.network) || ''}} diff --git a/.github/workflows/label-syncer.yml b/.github/workflows/label-syncer.yml deleted file mode 100644 index a94b0edb631..00000000000 --- a/.github/workflows/label-syncer.yml +++ /dev/null @@ -1,17 +0,0 @@ - -name: Label syncer -on: - push: - paths: - - '.github/labels.yml' - branches: - - master -jobs: - build: - name: Sync labels - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@1.0.0 - - uses: micnncim/action-label-syncer@v1.0.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000000..797473bb330 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,105 @@ +name: Release + +on: + push: + branches: + - ci/* + - release/* + tags: + - v* + workflow_dispatch: + +defaults: + run: + shell: bash + +permissions: {} + +jobs: + build: + name: Build (${{ matrix.os }}/${{ matrix.arch }}) + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - runner: ubuntu-latest + os: Linux + arch: X64 + - runner: macos-13 + os: macOS + arch: X64 + - runner: macos-14 + os: macOS + arch: ARM64 + steps: + - env: + OS: ${{ matrix.os }} + ARCH: ${{ matrix.arch }} + run: | + if [[ "$OS" != "$RUNNER_OS" || "$ARCH" != "$RUNNER_ARCH" ]]; then + echo "::error title=Unexpected Runner::Expected $OS/$ARCH, got $RUNNER_OS/$RUNNER_ARCH" + exit 1 + fi + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - uses: ./.github/actions/install-system-dependencies + - uses: ./.github/actions/install-go + - env: + GITHUB_TOKEN: ${{ github.token }} + run: make deps lotus lotus-miner lotus-worker + - if: runner.os == 'macOS' + run: otool -hv lotus + - run: ./scripts/version-check.sh ./lotus + - uses: actions/upload-artifact@v4 + with: + name: lotus-${{ matrix.os }}-${{ matrix.arch }} + path: | + lotus + lotus-miner + lotus-worker + release: + name: Release [publish=${{ startsWith(github.ref, 'refs/tags/') }}] + permissions: + # This enables the job to create and/or update GitHub releases + contents: write + runs-on: ubuntu-latest + needs: [build] + env: + PUBLISH: ${{ startsWith(github.ref, 'refs/tags/') }} + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + fetch-depth: 0 + - uses: actions/download-artifact@v4 + with: + name: lotus-Linux-X64 + path: linux_amd64_v1 + - uses: actions/download-artifact@v4 + with: + name: lotus-macOS-X64 + path: darwin_amd64_v1 + - uses: actions/download-artifact@v4 + with: + name: lotus-macOS-ARM64 + path: darwin_arm64 + - uses: ./.github/actions/install-go + - uses: ipfs/download-ipfs-distribution-action@v1 + with: + name: kubo + version: v0.16.0 + - uses: goreleaser/goreleaser-action@7ec5c2b0c6cdda6e8bbb49444bc797dd33d74dd8 # v5.0.0 + with: + distribution: goreleaser-pro + version: latest + args: release --clean --debug ${{ env.PUBLISH == 'false' && '--snapshot' || '' }} + env: + GITHUB_TOKEN: ${{ env.PUBLISH == 'true' && github.token || '' }} + GORELEASER_KEY: ${{ env.PUBLISH == 'true' && secrets.GORELEASER_KEY || '' }} + - run: ./scripts/generate-checksums.sh + - if: env.PUBLISH == 'true' + env: + GITHUB_TOKEN: ${{ github.token }} + run: ./scripts/publish-checksums.sh diff --git a/.github/workflows/sorted-pr-checks.yml b/.github/workflows/sorted-pr-checks.yml new file mode 100644 index 00000000000..0c2b0ee8a6f --- /dev/null +++ b/.github/workflows/sorted-pr-checks.yml @@ -0,0 +1,32 @@ +name: Comment with sorted PR checks + +on: + workflow_dispatch: + inputs: + pull_number: + description: 'Pull request number' + required: true + workflow_run: + workflows: + - Build + - Check + - CodeQL + - Test + types: + - requested + - completed + +permissions: + pull-requests: write + +concurrency: + group: ${{ github.workflow }}-${{ github.event.inputs.pull_number || github.event.workflow_run.pull_requests[0].number || 'unknown' }} + cancel-in-progress: true + +jobs: + comment: + if: github.event.inputs.pull_number || github.event.workflow_run.pull_requests[0] + uses: ipdxco/sorted-pr-checks/.github/workflows/comment.yml@v1 + with: + pull_number: ${{ github.event.inputs.pull_number || github.event.workflow_run.pull_requests[0].number }} + template: unsuccessful_only diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 35b97e369f4..3116da07c74 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -4,18 +4,18 @@ on: schedule: - cron: '0 12 * * *' +permissions: {} + jobs: stale: - - runs-on: ubuntu-latest permissions: issues: write pull-requests: write - + runs-on: ubuntu-latest steps: - - uses: actions/stale@v3 + - uses: actions/stale@v9 with: - repo-token: ${{ secrets.GITHUB_TOKEN }} + repo-token: ${{ github.token }} stale-issue-message: 'Oops, seems like we needed more information for this issue, please comment with more details or this issue will be closed in 24 hours.' close-issue-message: 'This issue was closed because it is missing author input.' stale-pr-message: 'Thank you for submitting the PR and contributing to lotus! Lotus maintainers need more of your input before merging it, please address the suggested changes or reply to the comments or this PR will be closed in 48 hours. You are always more than welcome to reopen the PR later as well!' @@ -29,5 +29,3 @@ jobs: days-before-pr-close: 2 remove-stale-when-updated: true enable-statistics: true - - diff --git a/.github/workflows/sync-master-main.yaml b/.github/workflows/sync-master-main.yaml index a55454eff24..b629b560433 100644 --- a/.github/workflows/sync-master-main.yaml +++ b/.github/workflows/sync-master-main.yaml @@ -1,13 +1,19 @@ name: sync-master-main + on: push: branches: - master + +permissions: {} + jobs: sync: + permissions: + contents: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: update remote branch main run: | # overrides the remote branch (origin:github) `main` diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000000..a64a613a878 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,306 @@ +name: Test + +on: + pull_request: + push: + branches: + - master + - release/* + workflow_dispatch: + +defaults: + run: + shell: bash + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: {} + +jobs: + discover: + name: Discover Test Groups + runs-on: ubuntu-latest + outputs: + groups: ${{ steps.test.outputs.groups }} + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - id: test + env: + # Unit test groups other than unit-rest + utests: | + [ + {"name": "unit-cli", "packages": ["./cli/...", "./cmd/...", "./api/..."]}, + {"name": "unit-storage", "packages": ["./storage/...", "./extern/..."]}, + {"name": "unit-node", "packages": ["./node/..."]} + ] + # Other tests that require special configuration + otests: | + [ + { + "name": "multicore-sdr", + "packages": ["./storage/sealer/ffiwrapper"], + "go_test_flags": "-run=TestMulticoreSDR", + "test_rustproofs_logs": "1" + }, { + "name": "conformance", + "packages": ["./conformance"], + "go_test_flags": "-run=TestConformance", + "skip_conformance": "0" + } + ] + # Mapping from test group names to custom runner labels + # The jobs default to running on the default hosted runners (4 CPU, 16 RAM). + # We use self-hosted xlarge (4 CPU, 8 RAM; and large - 2 CPU, 4 RAM) runners + # to extend the available runner capacity (60 default hosted runners). + # We use self-hosted 4xlarge (16 CPU, 32 RAM; and 2xlarge - 8 CPU, 16 RAM) self-hosted + # to support resource intensive jobs. + runners: | + { + "itest-deals_concurrent": ["self-hosted", "linux", "x64", "4xlarge"], + "itest-sector_pledge": ["self-hosted", "linux", "x64", "4xlarge"], + "itest-worker": ["self-hosted", "linux", "x64", "4xlarge"], + + "itest-gateway": ["self-hosted", "linux", "x64", "2xlarge"], + "itest-sector_import_full": ["self-hosted", "linux", "x64", "2xlarge"], + "itest-sector_import_simple": ["self-hosted", "linux", "x64", "2xlarge"], + "itest-wdpost": ["self-hosted", "linux", "x64", "2xlarge"], + "unit-storage": ["self-hosted", "linux", "x64", "2xlarge"], + + "itest-batch_deal": ["self-hosted", "linux", "x64", "xlarge"], + "itest-cli": ["self-hosted", "linux", "x64", "xlarge"], + "itest-deals_512mb": ["self-hosted", "linux", "x64", "xlarge"], + "itest-deals_anycid": ["self-hosted", "linux", "x64", "xlarge"], + "itest-deals_invalid_utf8_label": ["self-hosted", "linux", "x64", "xlarge"], + "itest-deals_max_staging_deals": ["self-hosted", "linux", "x64", "xlarge"], + "itest-deals_partial_retrieval": ["self-hosted", "linux", "x64", "xlarge"], + "itest-deals_publish": ["self-hosted", "linux", "x64", "xlarge"], + "itest-deals_remote_retrieval": ["self-hosted", "linux", "x64", "xlarge"], + "itest-decode_params": ["self-hosted", "linux", "x64", "xlarge"], + "itest-dup_mpool_messages": ["self-hosted", "linux", "x64", "xlarge"], + "itest-eth_account_abstraction": ["self-hosted", "linux", "x64", "xlarge"], + "itest-eth_api": ["self-hosted", "linux", "x64", "xlarge"], + "itest-eth_balance": ["self-hosted", "linux", "x64", "xlarge"], + "itest-eth_bytecode": ["self-hosted", "linux", "x64", "xlarge"], + "itest-eth_config": ["self-hosted", "linux", "x64", "xlarge"], + "itest-eth_conformance": ["self-hosted", "linux", "x64", "xlarge"], + "itest-eth_deploy": ["self-hosted", "linux", "x64", "xlarge"], + "itest-eth_fee_history": ["self-hosted", "linux", "x64", "xlarge"], + "itest-eth_transactions": ["self-hosted", "linux", "x64", "xlarge"], + "itest-fevm_address": ["self-hosted", "linux", "x64", "xlarge"], + "itest-fevm_events": ["self-hosted", "linux", "x64", "xlarge"], + "itest-gas_estimation": ["self-hosted", "linux", "x64", "xlarge"], + "itest-get_messages_in_ts": ["self-hosted", "linux", "x64", "xlarge"], + "itest-lite_migration": ["self-hosted", "linux", "x64", "xlarge"], + "itest-lookup_robust_address": ["self-hosted", "linux", "x64", "xlarge"], + "itest-mempool": ["self-hosted", "linux", "x64", "xlarge"], + "itest-mpool_msg_uuid": ["self-hosted", "linux", "x64", "xlarge"], + "itest-mpool_push_with_uuid": ["self-hosted", "linux", "x64", "xlarge"], + "itest-msgindex": ["self-hosted", "linux", "x64", "xlarge"], + "itest-multisig": ["self-hosted", "linux", "x64", "xlarge"], + "itest-net": ["self-hosted", "linux", "x64", "xlarge"], + "itest-nonce": ["self-hosted", "linux", "x64", "xlarge"], + "itest-path_detach_redeclare": ["self-hosted", "linux", "x64", "xlarge"], + "itest-pending_deal_allocation": ["self-hosted", "linux", "x64", "xlarge"], + "itest-remove_verifreg_datacap": ["self-hosted", "linux", "x64", "xlarge"], + "itest-sector_miner_collateral": ["self-hosted", "linux", "x64", "xlarge"], + "itest-sector_numassign": ["self-hosted", "linux", "x64", "xlarge"], + "itest-self_sent_txn": ["self-hosted", "linux", "x64", "xlarge"], + "itest-verifreg": ["self-hosted", "linux", "x64", "xlarge"], + "multicore-sdr": ["self-hosted", "linux", "x64", "xlarge"], + "unit-node": ["self-hosted", "linux", "x64", "xlarge"] + } + # A list of test groups that require YugabyteDB to be running + yugabytedb: | + ["itest-harmonydb", "itest-harmonytask", "itest-curio"] + # A list of test groups that require Proof Parameters to be fetched + parameters: | + [ + "conformance", + "itest-api", + "itest-deals_offline", + "itest-deals_padding", + "itest-deals_partial_retrieval_dm-level", + "itest-deals_pricing", + "itest-deals", + "itest-direct_data_onboard_verified", + "itest-direct_data_onboard", + "itest-net", + "itest-path_detach_redeclare", + "itest-path_type_filters", + "itest-sealing_resources", + "itest-sector_finalize_early", + "itest-sector_import_full", + "itest-sector_import_simple", + "itest-sector_pledge", + "itest-sector_unseal", + "itest-wdpost_no_miner_storage", + "itest-wdpost_worker_config", + "itest-wdpost", + "itest-worker_upgrade", + "itest-worker", + "multicore-sdr", + "unit-cli", + "unit-storage" + ] + run: | + # Create a list of integration test groups + itests="$( + find ./itests -name "*_test.go" | \ + jq -R '{ + "name": "itest-\(. | split("/") | .[2] | sub("_test.go$";""))", + "packages": [.] + }' | jq -s + )" + + # Create a list of packages that are covered by the integration and unit tests + packages="$(jq -n --argjson utests "$utests" '$utests | map(.packages) | flatten | . + ["./itests/..."]')" + + # Create a new group for the unit tests that are not yet covered + rest="$( + find . -name "*_test.go" | cut -d/ -f2 | sort | uniq | \ + jq -R '"./\(.)/..."' | \ + jq -s --argjson p "$packages" '{"name": "unit-rest", "packages": (. - $p)}' + )" + + # Combine the groups for integration tests, unit tests, the new unit-rest group, and the other tests + groups="$(jq -n --argjson i "$itests" --argjson u "$utests" --argjson r "$rest" --argjson o "$otests" '$i + $u + [$r] + $o')" + + # Apply custom runner labels to the groups + groups="$(jq -n --argjson g "$groups" --argjson r "$runners" '$g | map(. + {"runner": (.name as $n | $r | .[$n]) })')" + + # Apply the needs_yugabytedb flag to the groups + groups="$(jq -n --argjson g "$groups" --argjson y "$yugabytedb" '$g | map(. + {"needs_yugabytedb": ([.name] | inside($y)) })')" + + # Apply the needs_parameters flag to the groups + groups="$(jq -n --argjson g "$groups" --argjson p "$parameters" '$g | map(. + {"needs_parameters": ([.name] | inside($p)) })')" + + # Output the groups + echo "groups=$groups" + echo "groups=$(jq -nc --argjson g "$groups" '$g')" >> $GITHUB_OUTPUT + cache: + name: Cache Dependencies + runs-on: ubuntu-latest + outputs: + fetch_params_key: ${{ steps.fetch_params.outputs.key }} + fetch_params_path: ${{ steps.fetch_params.outputs.path }} + make_deps_key: ${{ steps.make_deps.outputs.key }} + make_deps_path: ${{ steps.make_deps.outputs.path }} + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - id: fetch_params + env: + CACHE_KEY: fetch-params-${{ hashFiles('./extern/filecoin-ffi/parameters.json') }} + CACHE_PATH: | + /var/tmp/filecoin-proof-parameters/ + run: | + echo -e "key=$CACHE_KEY" | tee -a $GITHUB_OUTPUT + echo -e "path< FIL and FIL -> ETH address conversion APIs to the Gateway (#11979) ([filecoin-project/lotus#11979](https://github.com/filecoin-project/lotus/pull/11979)) + +## Improvements + +- fix: api: return the correct block gas limit in the EthAPI (#11747) ([filecoin-project/lotus#11747](https://github.com/filecoin-project/lotus/pull/11747)) +- fix: exchange: explicitly cast the block message limit const (#11511) ([filecoin-project/lotus#11511](https://github.com/filecoin-project/lotus/pull/11511)) +- fix: Eth API: accept input data in call arguments under field 'input' (#11505) ([filecoin-project/lotus#11505](https://github.com/filecoin-project/lotus/pull/11505)) +- fix: api: Length check the array sent to eth_feeHistory RPC (#11696) ([filecoin-project/lotus#11696](https://github.com/filecoin-project/lotus/pull/11696)) +- fix: api: fix EthSubscribe tipsets off by one (#11858) ([filecoin-project/lotus#11858](https://github.com/filecoin-project/lotus/pull/11858)) +- fix: lotus-provider: Fix log output format in wdPostTaskCmd ([filecoin-project/lotus#11504](https://github.com/filecoin-project/lotus/pull/11504)) +- fix: lmcli: make 'sectors list' DDO-aware (#11839) ([filecoin-project/lotus#11839](https://github.com/filecoin-project/lotus/pull/11839)) +- fix: lpwinning: Fix MiningBase.afterPropDelay ([filecoin-project/lotus#11654](https://github.com/filecoin-project/lotus/pull/11654)) +- fix: exchange: allow up to 10k messages per block ([filecoin-project/lotus#11506](https://github.com/filecoin-project/lotus/pull/11506)) +- fix: harmony: Fix task reclaim on restart ([filecoin-project/lotus#11498](https://github.com/filecoin-project/lotus/pull/11498)) +- fix: lotus-provider: Wait for the correct taskID ([filecoin-project/lotus#11493](https://github.com/filecoin-project/lotus/pull/11493)) +- fix: lotus-provider: show addresses in log ([filecoin-project/lotus#11490](https://github.com/filecoin-project/lotus/pull/11490)) +- fix: sql Scan cannot write to an object ([filecoin-project/lotus#11485](https://github.com/filecoin-project/lotus/pull/11485)) +- fix: lotus-provider: Fix winning PoSt ([filecoin-project/lotus#11482](https://github.com/filecoin-project/lotus/pull/11482)) +- fix: lotus-provider: lotus-provider msg sending ([filecoin-project/lotus#11480](https://github.com/filecoin-project/lotus/pull/11480)) +- fix: chain: use latest go-state-types types for miner UI ([filecoin-project/lotus#11566](https://github.com/filecoin-project/lotus/pull/11566)) +- fix: Dockerfile non-interactive snapshot import (#11579) ([filecoin-project/lotus#11579](https://github.com/filecoin-project/lotus/pull/11579)) +- fix: daemon: avoid prompting to remove chain when noninteractive (#11582) ([filecoin-project/lotus#11582](https://github.com/filecoin-project/lotus/pull/11582)) +- fix: (events): check for sync-in-progress (#11932) ([filecoin-project/lotus#11932](https://github.com/filecoin-project/lotus/pull/11932)) +- fix: curio: common commands (#11879) ([filecoin-project/lotus#11879](https://github.com/filecoin-project/lotus/pull/11879)) +- fix: curio: fix incorrect null check for varchar column (#11881) ([filecoin-project/lotus#11881](https://github.com/filecoin-project/lotus/pull/11881)) +- fix: local storage reservations fixes (#11866) ([filecoin-project/lotus#11866](https://github.com/filecoin-project/lotus/pull/11866)) +- fix: curio: Check deal start epoch passed in PrecommitSubmit (#11873) ([filecoin-project/lotus#11873](https://github.com/filecoin-project/lotus/pull/11873)) +- fix: curio: base config by default (#11676) ([filecoin-project/lotus#11676](https://github.com/filecoin-project/lotus/pull/11676)) +- fix: curio: Start BoostAdapters before blocking rpc serve (#11871) ([filecoin-project/lotus#11871](https://github.com/filecoin-project/lotus/pull/11871)) +- fix: cli: json flag (#11868) ([filecoin-project/lotus#11868](https://github.com/filecoin-project/lotus/pull/11868)) +- feat: curio/lmrpc: Ingest backpressure (#11865) ([filecoin-project/lotus#11865](https://github.com/filecoin-project/lotus/pull/11865)) +- feat: curio: Cleanup data copies after seal ops (#11847) ([filecoin-project/lotus#11847](https://github.com/filecoin-project/lotus/pull/11847)) +- fix: spcli: add reference to the terminate command (#11851) ([filecoin-project/lotus#11851](https://github.com/filecoin-project/lotus/pull/11851)) +- fix: sealing: improve gasEstimate logging (#11840) ([filecoin-project/lotus#11840](https://github.com/filecoin-project/lotus/pull/11840)) +- fix: harmony: Try other tasks when storage claim fails +- fix: test: TestForkPreMigration hanging when env-var is set (#11838) ([filecoin-project/lotus#11838](https://github.com/filecoin-project/lotus/pull/11838)) +- fix: piece: Don't return StartEport in PieceDealInfo.EndEpoch (#11832) ([filecoin-project/lotus#11832](https://github.com/filecoin-project/lotus/pull/11832)) +- fix: paths/local: Fix on-disk storage accounting in new reservations (#11825) ([filecoin-project/lotus#11825](https://github.com/filecoin-project/lotus/pull/11825)) +- fix: sealing pipeline: Fix panic on padding pieces in WaitDeals (#11708) ([filecoin-project/lotus#11708](https://github.com/filecoin-project/lotus/pull/11708)) +- feat: ipfs: remove IPFS client backend (#11661) ([filecoin-project/lotus#11661](https://github.com/filecoin-project/lotus/pull/11661)) +- fix: docs: Modify generate-lotus-cli.py to ignoring aliases. ([filecoin-project/lotus#11535](https://github.com/filecoin-project/lotus/pull/11535)) +- fix: eth: decode as actor creation iff "to" is the EAM (#11520) ([filecoin-project/lotus#11520](https://github.com/filecoin-project/lotus/pull/11520)) +- fix(events): properly decorate events db errors (#11856) ([filecoin-project/lotus#11856](https://github.com/filecoin-project/lotus/pull/11856)) +- fix: CLI: adjust TermMax for extend-claim used by a different client (#11764) ([filecoin-project/lotus#11764](https://github.com/filecoin-project/lotus/pull/111764)) +- fix: copy Flags field from SectorOnChainInfo (#11963) ([filecoin-project/lotus#11963](https://github.com/filecoin-project/lotus/pull/11963)) +- feat: libp2p: Lotus stream cleanup (#11993) ([filecoin-project/lotus#11993](https://github.com/filecoin-project/lotus/pull/11993)) + +## Dependencies + +- chore: update deps (#11819) ([filecoin-project/lotus#11819](https://github.com/filecoin-project/lotus/pull/11819)) +- chore: mod: use upstream poseidon ([filecoin-project/lotus#11557](https://github.com/filecoin-project/lotus/pull/11557)) +- deps: multiaddress ([filecoin-project/lotus#11558](https://github.com/filecoin-project/lotus/pull/11558)) +- chore:libp2p: update libp2p deps in master ([filecoin-project/lotus#11522](https://github.com/filecoin-project/lotus/pull/11522)) +- dep: go-multi-address ([filecoin-project/lotus#11563](https://github.com/filecoin-project/lotus/pull/11563)) +- chore: update go-data-transfer and go-graphsync (#12000) ([filecoin-project/lotus#12000](https://github.com/filecoin-project/lotus/pull/2000)) +- chore: update drand (#12021) ([filecoin-project/lotus#12021](https://github.com/filecoin-project/lotus/pull/12021)) +- chore: libp2p: update to v0.34.1 (12027) ([filecoin-project/lotus#12027](https://github.com/filecoin-project/lotus/pull/12027)) +- github.com/filecoin-project/go-amt-ipld/ (v4.2.0 -> v4.3.0) +- github.com/filecoin-project/go-state-types (v0.13.1 -> v0.13.3) +- github.com/libp2p/go-libp2p-pubsub (v0.10.0 -> v0.10.1) +- github.com/libp2p/go-libp2p (v0.33.2 -> v0.34.1) + + +## Others + +- ci: ci: create gh workflow that runs go checks (#11761) ([filecoin-project/lotus#11761](https://github.com/filecoin-project/lotus/pull/11761)) +- ci: ci: create gh workflow that runs go build (#11760) ([filecoin-project/lotus#11760](https://github.com/filecoin-project/lotus/pull/11760)) +- ci: cancel in progress runs on pull requests only (#11842) ([filecoin-project/lotus#11842](https://github.com/filecoin-project/lotus/pull/11842)) +- ci: ci: list processes before calling apt-get to enable debugging (#11815) ([filecoin-project/lotus#11815](https://github.com/filecoin-project/lotus/pull/11815)) +- ci: ci: allow master main sync to write to the repository (#11784) ([filecoin-project/lotus#11784](https://github.com/filecoin-project/lotus/pull/11784)) +- ci: ci: create gh workflow that runs go tests (#11762) ([filecoin-project/lotus#11762](https://github.com/filecoin-project/lotus/pull/11762)) +- ci: ci: deprecate circle ci in favour of github actions (#11786) ([filecoin-project/lotus#11786](https://github.com/filecoin-project/lotus/pull/1786)) +- misc: Drop the raft-cluster experiment ([filecoin-project/lotus#11468](https://github.com/filecoin-project/lotus/pull/11468)) +- chore: fix some typos in comments (#11892) ([filecoin-project/lotus#11892](https://github.com/filecoin-project/lotus/pull/11892)) +- chore: fix typos (#11848) ([filecoin-project/lotus#11848](https://github.com/filecoin-project/lotus/pull/11848)) +- chore: fix typo (#11697) ([filecoin-project/lotus#11697](https://github.com/filecoin-project/lotus/pull/11697)) +- chore: fix 2 typo's (#11542) ([filecoin-project/lotus#11542](https://github.com/filecoin-project/lotus/pull/11542)) +- chore: calibnet: Update bootstrap peer list ([filecoin-project/lotus#11672](https://github.com/filecoin-project/lotus/pull/11672)) +- chore: build: Bump version in master ([filecoin-project/lotus#11475](https://github.com/filecoin-project/lotus/pull/11475)) +- chore: releases: merge releases branch to master ([filecoin-project/lotus#11578](https://github.com/filecoin-project/lotus/pull/11578)) +- chore: Add systemd memory note on install and in config (#11641) ([filecoin-project/lotus#11641](https://github.com/filecoin-project/lotus/pull/11641)) +- chore: switch back to upstream ledger library (#11651) ([filecoin-project/lotus#11651](https://github.com/filecoin-project/lotus/pull/11651)) +- chore: build: update minimum go version to 1.21.7 (#11652) ([filecoin-project/lotus#11652](https://github.com/filecoin-project/lotus/pull/11652)) +- chore: docs: nv-skeleton documentation (#11065) ([filecoin-project/lotus#11065](https://github.com/filecoin-project/lotus/pull/11065)) +- chore: Add v13 support to invariants-checker (#11931) ([filecoin-project/lotus#11931](https://github.com/filecoin-project/lotus/pull/11931)) +- chore: remove unmaintained bootstrappers (#11983) ([filecoin-project/lotus#11983](https://github.com/filecoin-project/lotus/pull/11983)) +- chore: go mod: revert go version change as it breaks Docker build (#12050) ([filecoin-project/lotus#12050](https://github.com/filecoin-project/lotus/pull/12050)) + +## Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Rod Vagg | 20 | +55315/-204 | 58 | +| Łukasz Magiera | 201 | +16244/-6541 | 647 | +| Andrew Jackson (Ajax) | 53 | +15293/-6764 | 394 | +| Phi-rjan | 6 | +12669/-4521 | 221 | +| LexLuthr | 20 | +5972/-2815 | 120 | +| Steven Allen | 22 | +1626/-1264 | 77 | +| Piotr Galar | 9 | +790/-412 | 33 | +| Aayush Rajasekaran | 4 | +642/-509 | 12 | +| Lee | 1 | +601/-533 | 9 | +| qwdsds | 3 | +617/-510 | 11 | +| Phi | 11 | +551/-83 | 32 | +| Jiaying Wang | 5 | +433/-20 | 13 | +| Masih H. Derkani | 4 | +350/-101 | 18 | +| Aayush | 4 | +143/-76 | 17 | +| Aarsh Shah | 3 | +63/-11 | 5 | +| jennijuju | 3 | +22/-22 | 12 | +| hunjixin | 1 | +21/-14 | 4 | +| beck | 2 | +17/-17 | 2 | +| tom123222 | 2 | +28/-4 | 2 | +| Ian Norden | 1 | +21/-1 | 1 | +| ZenGround0 | 1 | +3/-15 | 1 | +| shuangcui | 1 | +7/-7 | 6 | +| Vid Bregar | 1 | +7/-4 | 2 | +| writegr | 1 | +5/-5 | 5 | +| Nagaprasad V R | 1 | +9/-0 | 1 | +| forcedebug | 1 | +4/-4 | 4 | +| parthshah1 | 2 | +6/-1 | 2 | +| fuyangpengqi | 1 | +3/-3 | 3 | +| Samuel Arogbonlo | 1 | +6/-0 | 2 | +| GlacierWalrus | 1 | +0/-6 | 1 | +| Aloxaf | 1 | +6/-0 | 2 | +| Rob Quist | 2 | +2/-3 | 3 | +| wersfeds | 1 | +2/-2 | 1 | +| Jon | 1 | +2/-0 | 1 | +| 0x5459 | 1 | +1/-0 | 1 | + +# v1.26.3 / 2024-04-22 + +**This is a patch release that addresses high memory load concerns for the Lotus daemon in the coming network migration for network version 22, scheduled on epoch `3855360 - 2024-04-24 - 14:00:00Z`.** + +If your Lotus daemon is running on a machine with less memory and swap than 160GB, you should upgrade to this patch release to ensure you do not encounter any Out-Of-Memory issues during the pre-migration. + # v1.26.2 / 2024-04-08 **This is a mandatory patch release for the Filecoin network version 22 mainnet upgrade, for all node operators.** @@ -74,6 +287,7 @@ The Filecoin network version 22 delivers the following FIPs: lotus state actor-cids --network-version=22 Network Version: 22 Actor Version: 13 + Manifest CID: bafy2bzacecdhvfmtirtojwhw2tyciu4jkbpsbk5g53oe24br27oy62sn4dc4e Actor CID @@ -448,8 +662,6 @@ This patch release allows for up to 10k messages per block. Additionally, it int ## Improvements - fix: exchange: allow up to 10k messages per block ([filecoin-project/lotus#11506](https://github.com/filecoin-project/lotus/pull/11506)) ->>>>>>> releases - # v 1.25.0 / 2023-11-22 This is a highly recommended feature release of Lotus. This optional release supports the Filecoin network version 21 upgrade, codenamed Watermelon 🍉, in addition to the numerous improvements and enhancements for node operators, ETH RPC-providers and storage providers. @@ -3752,7 +3964,7 @@ This is a **highly recommended** but optional Lotus v1.11.1 release that introd - Config for deal publishing control addresses ([filecoin-project/lotus#6697](https://github.com/filecoin-project/lotus/pull/6697)) - Set `DealPublishControl` to set the wallet used for sending `PublishStorageDeals` messages, instructions [here](https://lotus.filecoin.io/storage-providers/operate/addresses/#control-addresses). - Config UX improvements ([filecoin-project/lotus#6848](https://github.com/filecoin-project/lotus/pull/6848)) - - You can now preview the the default and updated node config by running `lotus/lotus-miner config default/updated` + - You can now preview the default and updated node config by running `lotus/lotus-miner config default/updated` ## New Features - ⭐️⭐️⭐️ Support standalone miner-market process ([filecoin-project/lotus#6356](https://github.com/filecoin-project/lotus/pull/6356)) @@ -5199,7 +5411,7 @@ This consensus-breaking release of Lotus upgrades the actors version to v2.0.0. #### Mining -- Increased ExpectedSealDuration and and WaitDealsDelay (https://github.com/filecoin-project/lotus/pull/3743) +- Increased ExpectedSealDuration and WaitDealsDelay (https://github.com/filecoin-project/lotus/pull/3743) - Miner backup/restore commands (https://github.com/filecoin-project/lotus/pull/4133) - lotus-miner: add more help text to storage / attach (https://github.com/filecoin-project/lotus/pull/3961) - Reject deals that are > 7 days in the future in the BasicDealFilter (https://github.com/filecoin-project/lotus/pull/4173) diff --git a/Dockerfile b/Dockerfile index ae83911d39e..5b77b134afb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -73,7 +73,7 @@ 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 +ARG DOCKER_LOTUS_IMPORT_SNAPSHOT=https://forest-archive.chainsafe.dev/latest/mainnet/ ENV DOCKER_LOTUS_IMPORT_SNAPSHOT ${DOCKER_LOTUS_IMPORT_SNAPSHOT} ENV FILECOIN_PARAMETER_CACHE /var/tmp/filecoin-proof-parameters ENV LOTUS_PATH /var/lib/lotus @@ -109,7 +109,7 @@ 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-provider /usr/local/bin/ +COPY --from=lotus-builder /opt/filecoin/curio /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/ @@ -118,13 +118,13 @@ RUN mkdir /var/lib/lotus RUN mkdir /var/lib/lotus-miner RUN mkdir /var/lib/lotus-worker RUN mkdir /var/lib/lotus-wallet -RUN mkdir /var/lib/lotus-provider +RUN mkdir /var/lib/curio 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 -RUN chown fc: /var/lib/lotus-provider +RUN chown fc: /var/lib/curio VOLUME /var/tmp/filecoin-proof-parameters @@ -132,7 +132,7 @@ VOLUME /var/lib/lotus VOLUME /var/lib/lotus-miner VOLUME /var/lib/lotus-worker VOLUME /var/lib/lotus-wallet -VOLUME /var/lib/lotus-provider +VOLUME /var/lib/curio EXPOSE 1234 EXPOSE 2345 diff --git a/Makefile b/Makefile index 236d2d98e45..901c8dc00a9 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ CLEAN+=build/.update-modules deps: $(BUILD_DEPS) .PHONY: deps -build-devnets: build lotus-seed lotus-shed lotus-provider +build-devnets: build lotus-seed lotus-shed curio sptool .PHONY: build-devnets debug: GOFLAGS+=-tags=debug @@ -97,14 +97,20 @@ lotus-miner: $(BUILD_DEPS) .PHONY: lotus-miner BINS+=lotus-miner -lotus-provider: $(BUILD_DEPS) - rm -f lotus-provider - $(GOCC) build $(GOFLAGS) -o lotus-provider ./cmd/lotus-provider -.PHONY: lotus-provider -BINS+=lotus-provider +curio: $(BUILD_DEPS) + rm -f curio + $(GOCC) build $(GOFLAGS) -o curio ./cmd/curio +.PHONY: curio +BINS+=curio -lp2k: GOFLAGS+=-tags=2k -lp2k: lotus-provider +cu2k: GOFLAGS+=-tags=2k +cu2k: curio + +sptool: $(BUILD_DEPS) + rm -f sptool + $(GOCC) build $(GOFLAGS) -o sptool ./cmd/sptool +.PHONY: sptool +BINS+=sptool lotus-worker: $(BUILD_DEPS) rm -f lotus-worker @@ -124,13 +130,13 @@ lotus-gateway: $(BUILD_DEPS) .PHONY: lotus-gateway BINS+=lotus-gateway -build: lotus lotus-miner lotus-worker lotus-provider +build: lotus lotus-miner lotus-worker curio sptool @[[ $$(type -P "lotus") ]] && echo "Caution: you have \ an existing lotus binary in your PATH. This may cause problems if you don't run 'sudo make install'" || true .PHONY: build -install: install-daemon install-miner install-worker install-provider +install: install-daemon install-miner install-worker install-curio install-sptool install-daemon: install -C ./lotus /usr/local/bin/lotus @@ -138,8 +144,11 @@ install-daemon: install-miner: install -C ./lotus-miner /usr/local/bin/lotus-miner -install-provider: - install -C ./lotus-provider /usr/local/bin/lotus-provider +install-curio: + install -C ./curio /usr/local/bin/curio + +install-sptool: + install -C ./sptool /usr/local/bin/sptool install-worker: install -C ./lotus-worker /usr/local/bin/lotus-worker @@ -156,8 +165,11 @@ uninstall-daemon: uninstall-miner: rm -f /usr/local/bin/lotus-miner -uninstall-provider: - rm -f /usr/local/bin/lotus-provider +uninstall-curio: + rm -f /usr/local/bin/curio + +uninstall-sptool: + rm -f /usr/local/bin/sptool uninstall-worker: rm -f /usr/local/bin/lotus-worker @@ -246,7 +258,9 @@ install-daemon-service: install-daemon install -C -m 0644 ./scripts/lotus-daemon.service /etc/systemd/system/lotus-daemon.service systemctl daemon-reload @echo - @echo "lotus-daemon service installed. Don't forget to run 'sudo systemctl start lotus-daemon' to start it and 'sudo systemctl enable lotus-daemon' for it to be enabled on startup." + @echo "lotus-daemon service installed." + @echo "To start the service, run: 'sudo systemctl start lotus-daemon'" + @echo "To enable the service on startup, run: 'sudo systemctl enable lotus-daemon'" install-miner-service: install-miner install-daemon-service mkdir -p /etc/systemd/system @@ -254,15 +268,17 @@ install-miner-service: install-miner install-daemon-service install -C -m 0644 ./scripts/lotus-miner.service /etc/systemd/system/lotus-miner.service systemctl daemon-reload @echo - @echo "lotus-miner service installed. Don't forget to run 'sudo systemctl start lotus-miner' to start it and 'sudo systemctl enable lotus-miner' for it to be enabled on startup." + @echo "lotus-miner service installed." + @echo "To start the service, run: 'sudo systemctl start lotus-miner'" + @echo "To enable the service on startup, run: 'sudo systemctl enable lotus-miner'" -install-provider-service: install-provider install-daemon-service +install-curio-service: install-curio install-sptool install-daemon-service mkdir -p /etc/systemd/system mkdir -p /var/log/lotus - install -C -m 0644 ./scripts/lotus-provider.service /etc/systemd/system/lotus-provider.service + install -C -m 0644 ./scripts/curio.service /etc/systemd/system/curio.service systemctl daemon-reload @echo - @echo "lotus-provider service installed. Don't forget to run 'sudo systemctl start lotus-provider' to start it and 'sudo systemctl enable lotus-provider' for it to be enabled on startup." + @echo "Curio service installed. Don't forget to run 'sudo systemctl start curio' to start it and 'sudo systemctl enable curio' for it to be enabled on startup." install-main-services: install-miner-service @@ -282,10 +298,10 @@ clean-miner-service: rm -f /etc/systemd/system/lotus-miner.service systemctl daemon-reload -clean-provider-service: - -systemctl stop lotus-provider - -systemctl disable lotus-provider - rm -f /etc/systemd/system/lotus-provider.service +clean-curio-service: + -systemctl stop curio + -systemctl disable curio + rm -f /etc/systemd/system/curio.service systemctl daemon-reload clean-main-services: clean-daemon-service @@ -303,6 +319,10 @@ install-completions: install -C ./scripts/bash-completion/lotus /usr/share/bash-completion/completions/lotus install -C ./scripts/zsh-completion/lotus /usr/local/share/zsh/site-functions/_lotus +unittests: + @$(GOCC) test $(shell go list ./... | grep -v /lotus/itests) +.PHONY: unittests + clean: rm -rf $(CLEAN) $(BINS) -$(MAKE) -C $(FFI_PATH) clean @@ -323,8 +343,8 @@ actors-code-gen: $(GOCC) run ./chain/actors/agen $(GOCC) fmt ./... -actors-gen: actors-code-gen - ./scripts/fiximports +actors-gen: actors-code-gen + $(GOCC) run ./scripts/fiximports .PHONY: actors-gen bundle-gen: @@ -358,7 +378,7 @@ docsgen-md-bin: api-gen actors-gen docsgen-openrpc-bin: api-gen actors-gen $(GOCC) build $(GOFLAGS) -o docgen-openrpc ./api/docgen-openrpc/cmd -docsgen-md: docsgen-md-full docsgen-md-storage docsgen-md-worker docsgen-md-provider +docsgen-md: docsgen-md-full docsgen-md-storage docsgen-md-worker docsgen-md-curio docsgen-md-full: docsgen-md-bin ./docgen-md "api/api_full.go" "FullNode" "api" "./api" > documentation/en/api-v1-unstable-methods.md @@ -367,46 +387,73 @@ docsgen-md-storage: docsgen-md-bin ./docgen-md "api/api_storage.go" "StorageMiner" "api" "./api" > documentation/en/api-v0-methods-miner.md docsgen-md-worker: docsgen-md-bin ./docgen-md "api/api_worker.go" "Worker" "api" "./api" > documentation/en/api-v0-methods-worker.md -docsgen-md-provider: docsgen-md-bin - ./docgen-md "api/api_lp.go" "Provider" "api" "./api" > documentation/en/api-v0-methods-provider.md +docsgen-md-curio: docsgen-md-bin + ./docgen-md "api/api_curio.go" "Curio" "api" "./api" > documentation/en/api-v0-methods-curio.md docsgen-openrpc: docsgen-openrpc-full docsgen-openrpc-storage docsgen-openrpc-worker docsgen-openrpc-gateway docsgen-openrpc-full: docsgen-openrpc-bin - ./docgen-openrpc "api/api_full.go" "FullNode" "api" "./api" -gzip > build/openrpc/full.json.gz + ./docgen-openrpc "api/api_full.go" "FullNode" "api" "./api" > build/openrpc/full.json docsgen-openrpc-storage: docsgen-openrpc-bin - ./docgen-openrpc "api/api_storage.go" "StorageMiner" "api" "./api" -gzip > build/openrpc/miner.json.gz + ./docgen-openrpc "api/api_storage.go" "StorageMiner" "api" "./api" > build/openrpc/miner.json docsgen-openrpc-worker: docsgen-openrpc-bin - ./docgen-openrpc "api/api_worker.go" "Worker" "api" "./api" -gzip > build/openrpc/worker.json.gz + ./docgen-openrpc "api/api_worker.go" "Worker" "api" "./api" > build/openrpc/worker.json docsgen-openrpc-gateway: docsgen-openrpc-bin - ./docgen-openrpc "api/api_gateway.go" "Gateway" "api" "./api" -gzip > build/openrpc/gateway.json.gz + ./docgen-openrpc "api/api_gateway.go" "Gateway" "api" "./api" > build/openrpc/gateway.json .PHONY: docsgen docsgen-md-bin docsgen-openrpc-bin fiximports: - ./scripts/fiximports + $(GOCC) run ./scripts/fiximports -gen: actors-code-gen type-gen cfgdoc-gen docsgen api-gen circleci - ./scripts/fiximports +gen: actors-code-gen type-gen cfgdoc-gen docsgen api-gen + $(GOCC) run ./scripts/fiximports @echo ">>> IF YOU'VE MODIFIED THE CLI OR CONFIG, REMEMBER TO ALSO RUN 'make docsgen-cli'" .PHONY: gen jen: gen -snap: lotus lotus-miner lotus-worker lotus-provider +snap: lotus lotus-miner lotus-worker curio sptool snapcraft # snapcraft upload ./lotus_*.snap # separate from gen because it needs binaries -docsgen-cli: lotus lotus-miner lotus-worker lotus-provider +docsgen-cli: lotus lotus-miner lotus-worker curio sptool 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 - ./lotus-provider config default > documentation/en/default-lotus-provider-config.toml + ./curio config default > documentation/en/default-curio-config.toml .PHONY: docsgen-cli print-%: @echo $*=$($*) -circleci: - go generate -x ./.circleci +### Curio devnet images +curio_docker_user?=curio +curio_base_image=$(curio_docker_user)/curio-all-in-one:latest-debug +ffi_from_source?=0 + +curio-devnet: lotus lotus-miner lotus-shed lotus-seed curio sptool +.PHONY: curio-devnet + +curio_docker_build_cmd=docker build --build-arg CURIO_TEST_IMAGE=$(curio_base_image) \ + --build-arg FFI_BUILD_FROM_SOURCE=$(ffi_from_source) $(docker_args) + +docker/curio-all-in-one: + $(curio_docker_build_cmd) -f Dockerfile.curio --target curio-all-in-one \ + -t $(curio_base_image) --build-arg GOFLAGS=-tags=debug . +.PHONY: docker/curio-all-in-one + +docker/%: + cd curiosrc/docker/$* && DOCKER_BUILDKIT=1 $(curio_docker_build_cmd) -t $(curio_docker_user)/$*-dev:dev \ + --build-arg BUILD_VERSION=dev . + +docker/curio-devnet: $(lotus_build_cmd) \ + docker/curio-all-in-one docker/lotus docker/lotus-miner docker/curio docker/yugabyte +.PHONY: docker/curio-devnet + +curio-devnet/up: + rm -rf ./curiosrc/docker/data && docker compose -f ./curiosrc/docker/docker-compose.yaml up -d + +curio-devnet/down: + docker compose -f ./curiosrc/docker/docker-compose.yaml down --rmi=local && sleep 2 && rm -rf ./curiosrc/docker/data diff --git a/README.md b/README.md index dd4ff3b5436..561b20166e5 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,12 @@

Project Lotus - 莲

- - - - +![example workflow](https://github.com/github/docs/actions/workflows/main.yml/badge.svg) + + + + +

@@ -19,7 +21,7 @@ Lotus is an implementation of the Filecoin Distributed Storage Network. For more ## Building & Documentation > Note: The default `master` branch is the dev branch, please use with caution. For the latest stable version, checkout the most recent [`Latest release`](https://github.com/filecoin-project/lotus/releases). - + For complete instructions on how to build, install and setup lotus, please visit [https://lotus.filecoin.io](https://lotus.filecoin.io/lotus/install/prerequisites/#supported-platforms). Basic build instructions can be found further down in this readme. ## Reporting a Vulnerability @@ -96,7 +98,7 @@ Once all the dependencies are installed, you can build and install the Lotus sui git clone https://github.com/filecoin-project/lotus.git cd lotus/ ``` - + Note: The default branch `master` is the dev branch where the latest new features, bug fixes and improvement are in. However, if you want to run lotus on Filecoin mainnet and want to run a production-ready lotus, get the latest release[ here](https://github.com/filecoin-project/lotus/releases). 2. To join mainnet, checkout the [latest release](https://github.com/filecoin-project/lotus/releases). diff --git a/api/api_curio.go b/api/api_curio.go new file mode 100644 index 00000000000..0eceb484fdb --- /dev/null +++ b/api/api_curio.go @@ -0,0 +1,34 @@ +package api + +import ( + "context" + "net/http" + "net/url" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/storage/sealer/fsutil" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +type Curio interface { + Version(context.Context) (Version, error) //perm:admin + + AllocatePieceToSector(ctx context.Context, maddr address.Address, piece PieceDealInfo, rawSize int64, source url.URL, header http.Header) (SectorOffset, error) //perm:write + + StorageInit(ctx context.Context, path string, opts storiface.LocalStorageMeta) error //perm:admin + StorageAddLocal(ctx context.Context, path string) error //perm:admin + StorageDetachLocal(ctx context.Context, path string) error //perm:admin + StorageList(ctx context.Context) (map[storiface.ID][]storiface.Decl, error) //perm:admin + StorageLocal(ctx context.Context) (map[storiface.ID]string, error) //perm:admin + StorageStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, error) //perm:admin + StorageInfo(context.Context, storiface.ID) (storiface.StorageInfo, error) //perm:admin + StorageFindSector(ctx context.Context, sector abi.SectorID, ft storiface.SectorFileType, ssize abi.SectorSize, allowFetch bool) ([]storiface.SectorStorageInfo, error) //perm:admin + + LogList(ctx context.Context) ([]string, error) //perm:read + LogSetLevel(ctx context.Context, subsystem, level string) error //perm:admin + + // Trigger shutdown + Shutdown(context.Context) error //perm:admin +} diff --git a/api/api_full.go b/api/api_full.go index 23a50471b97..bbfcae0a2eb 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -335,7 +335,7 @@ type FullNode interface { WalletVerify(context.Context, address.Address, []byte, *crypto.Signature) (bool, error) //perm:read // WalletDefaultAddress returns the address marked as default in the wallet. WalletDefaultAddress(context.Context) (address.Address, error) //perm:write - // WalletSetDefault marks the given address as as the default one. + // WalletSetDefault marks the given address as the default one. WalletSetDefault(context.Context, address.Address) error //perm:write // WalletExport returns the private key of an address in the wallet. WalletExport(context.Context, address.Address) (*types.KeyInfo, error) //perm:admin @@ -904,9 +904,6 @@ type FullNode interface { // the path specified when calling CreateBackup is within the base path CreateBackup(ctx context.Context, fpath string) error //perm:admin - RaftState(ctx context.Context) (*RaftStateData, error) //perm:read - RaftLeader(ctx context.Context) (peer.ID, error) //perm:read - // Actor events // GetActorEventsRaw returns all user-programmed and built-in actor events that match the given diff --git a/api/api_gateway.go b/api/api_gateway.go index 2a30ae5018c..62bff64cfad 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -77,6 +77,7 @@ type Gateway interface { StateMarketBalance(ctx context.Context, addr address.Address, tsk types.TipSetKey) (MarketBalance, error) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID, tsk types.TipSetKey) (*MarketDeal, error) StateMinerInfo(ctx context.Context, actor address.Address, tsk types.TipSetKey) (MinerInfo, error) + StateMinerDeadlines(context.Context, address.Address, types.TipSetKey) ([]Deadline, error) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error) StateNetworkName(context.Context) (dtypes.NetworkName, error) @@ -90,6 +91,8 @@ type Gateway interface { Version(context.Context) (APIVersion, error) Discover(context.Context) (apitypes.OpenRPCDocument, error) + EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) + FilecoinAddressToEthAddress(ctx context.Context, filecoinAddress address.Address) (ethtypes.EthAddress, 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) diff --git a/api/api_lp.go b/api/api_lp.go deleted file mode 100644 index 8b58379f8e1..00000000000 --- a/api/api_lp.go +++ /dev/null @@ -1,10 +0,0 @@ -package api - -import "context" - -type LotusProvider interface { - Version(context.Context) (Version, error) //perm:admin - - // Trigger shutdown - Shutdown(context.Context) error //perm:admin -} diff --git a/api/api_storage.go b/api/api_storage.go index b24ee2af39e..410fa2af16c 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -200,11 +200,11 @@ type StorageMiner interface { // StorageBestAlloc returns list of paths where sector files of the specified type can be allocated, ordered by preference. // Paths with more weight and more % of free space are preferred. // Note: This method doesn't filter paths based on AllowTypes/DenyTypes. - StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType) ([]storiface.StorageInfo, error) //perm:admin - StorageLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) error //perm:admin - StorageTryLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) (bool, error) //perm:admin - StorageList(ctx context.Context) (map[storiface.ID][]storiface.Decl, error) //perm:admin - StorageGetLocks(ctx context.Context) (storiface.SectorLocks, error) //perm:admin + StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType, miner abi.ActorID) ([]storiface.StorageInfo, error) //perm:admin + StorageLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) error //perm:admin + StorageTryLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) (bool, error) //perm:admin + StorageList(ctx context.Context) (map[storiface.ID][]storiface.Decl, error) //perm:admin + StorageGetLocks(ctx context.Context) (storiface.SectorLocks, error) //perm:admin StorageLocal(ctx context.Context) (map[storiface.ID]string, error) //perm:admin StorageStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, error) //perm:admin diff --git a/api/client/client.go b/api/client/client.go index 4d51221f92b..4a8ff927227 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -15,9 +15,9 @@ import ( "github.com/filecoin-project/lotus/lib/rpcenc" ) -// NewProviderRpc creates a new http jsonrpc client. -func NewProviderRpc(ctx context.Context, addr string, requestHeader http.Header) (api.LotusProvider, jsonrpc.ClientCloser, error) { - var res v1api.LotusProviderStruct +// NewCurioRpc creates a new http jsonrpc client. +func NewCurioRpc(ctx context.Context, addr string, requestHeader http.Header) (api.Curio, jsonrpc.ClientCloser, error) { + var res v1api.CurioStruct closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin", api.GetInternalStructs(&res), requestHeader, jsonrpc.WithErrors(api.RPCErrors)) diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index bf76444e63d..2d34a0903cc 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -146,6 +146,7 @@ func init() { allocationId := verifreg.AllocationId(0) addExample(allocationId) addExample(&allocationId) + addExample(miner.SectorOnChainInfoFlags(0)) addExample(map[verifreg.AllocationId]verifreg.Allocation{}) claimId := verifreg.ClaimId(0) addExample(claimId) @@ -356,10 +357,6 @@ func init() { addExample(map[string]bitfield.BitField{ "": bitfield.NewFromSet([]uint64{5, 6, 7, 10}), }) - addExample(&api.RaftStateData{ - NonceMap: make(map[address.Address]uint64), - MsgUuids: make(map[uuid.UUID]*types.SignedMessage), - }) addExample(http.Header{ "Authorization": []string{"Bearer ey.."}, @@ -459,10 +456,10 @@ func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []r i = &api.GatewayStruct{} t = reflect.TypeOf(new(struct{ api.Gateway })).Elem() permStruct = append(permStruct, reflect.TypeOf(api.GatewayStruct{}.Internal)) - case "Provider": - i = &api.LotusProviderStruct{} - t = reflect.TypeOf(new(struct{ api.LotusProvider })).Elem() - permStruct = append(permStruct, reflect.TypeOf(api.LotusProviderStruct{}.Internal)) + case "Curio": + i = &api.CurioStruct{} + t = reflect.TypeOf(new(struct{ api.Curio })).Elem() + permStruct = append(permStruct, reflect.TypeOf(api.CurioStruct{}.Internal)) default: panic("unknown type") } diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 2f4eb2990b9..9960faeffe5 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -27,8 +27,9 @@ import ( 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" + miner "github.com/filecoin-project/go-state-types/builtin/v13/miner" paych "github.com/filecoin-project/go-state-types/builtin/v8/paych" - miner "github.com/filecoin-project/go-state-types/builtin/v9/miner" + miner0 "github.com/filecoin-project/go-state-types/builtin/v9/miner" verifreg "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" crypto "github.com/filecoin-project/go-state-types/crypto" dline "github.com/filecoin-project/go-state-types/dline" @@ -36,7 +37,7 @@ import ( api "github.com/filecoin-project/lotus/api" apitypes "github.com/filecoin-project/lotus/api/types" - miner0 "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + miner1 "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" @@ -2934,36 +2935,6 @@ func (mr *MockFullNodeMockRecorder) PaychVoucherSubmit(arg0, arg1, arg2, arg3, a return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PaychVoucherSubmit", reflect.TypeOf((*MockFullNode)(nil).PaychVoucherSubmit), arg0, arg1, arg2, arg3, arg4) } -// RaftLeader mocks base method. -func (m *MockFullNode) RaftLeader(arg0 context.Context) (peer.ID, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RaftLeader", arg0) - ret0, _ := ret[0].(peer.ID) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// RaftLeader indicates an expected call of RaftLeader. -func (mr *MockFullNodeMockRecorder) RaftLeader(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RaftLeader", reflect.TypeOf((*MockFullNode)(nil).RaftLeader), arg0) -} - -// RaftState mocks base method. -func (m *MockFullNode) RaftState(arg0 context.Context) (*api.RaftStateData, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RaftState", arg0) - ret0, _ := ret[0].(*api.RaftStateData) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// RaftState indicates an expected call of RaftState. -func (mr *MockFullNodeMockRecorder) RaftState(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RaftState", reflect.TypeOf((*MockFullNode)(nil).RaftState), arg0) -} - // Session mocks base method. func (m *MockFullNode) Session(arg0 context.Context) (uuid.UUID, error) { m.ctrl.T.Helper() @@ -3639,7 +3610,7 @@ func (mr *MockFullNodeMockRecorder) StateMinerInfo(arg0, arg1, arg2 interface{}) } // StateMinerInitialPledgeCollateral mocks base method. -func (m *MockFullNode) StateMinerInitialPledgeCollateral(arg0 context.Context, arg1 address.Address, arg2 miner.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { +func (m *MockFullNode) StateMinerInitialPledgeCollateral(arg0 context.Context, arg1 address.Address, arg2 miner0.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateMinerInitialPledgeCollateral", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(big.Int) @@ -3684,7 +3655,7 @@ func (mr *MockFullNodeMockRecorder) StateMinerPower(arg0, arg1, arg2 interface{} } // StateMinerPreCommitDepositForPower mocks base method. -func (m *MockFullNode) StateMinerPreCommitDepositForPower(arg0 context.Context, arg1 address.Address, arg2 miner.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { +func (m *MockFullNode) StateMinerPreCommitDepositForPower(arg0 context.Context, arg1 address.Address, arg2 miner0.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateMinerPreCommitDepositForPower", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(big.Int) @@ -3849,10 +3820,10 @@ func (mr *MockFullNodeMockRecorder) StateSearchMsg(arg0, arg1, arg2, arg3, arg4 } // StateSectorExpiration mocks base method. -func (m *MockFullNode) StateSectorExpiration(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner0.SectorExpiration, error) { +func (m *MockFullNode) StateSectorExpiration(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner1.SectorExpiration, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateSectorExpiration", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(*miner0.SectorExpiration) + ret0, _ := ret[0].(*miner1.SectorExpiration) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -3879,10 +3850,10 @@ func (mr *MockFullNodeMockRecorder) StateSectorGetInfo(arg0, arg1, arg2, arg3 in } // StateSectorPartition mocks base method. -func (m *MockFullNode) StateSectorPartition(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner0.SectorLocation, error) { +func (m *MockFullNode) StateSectorPartition(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner1.SectorLocation, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateSectorPartition", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(*miner0.SectorLocation) + ret0, _ := ret[0].(*miner1.SectorLocation) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -3894,10 +3865,10 @@ func (mr *MockFullNodeMockRecorder) StateSectorPartition(arg0, arg1, arg2, arg3 } // StateSectorPreCommitInfo mocks base method. -func (m *MockFullNode) StateSectorPreCommitInfo(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) { +func (m *MockFullNode) StateSectorPreCommitInfo(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner0.SectorPreCommitOnChainInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateSectorPreCommitInfo", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(*miner.SectorPreCommitOnChainInfo) + ret0, _ := ret[0].(*miner0.SectorPreCommitOnChainInfo) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 4df81369be4..cde8230c4a7 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -5,6 +5,8 @@ package api import ( "context" "encoding/json" + "net/http" + "net/url" "time" "github.com/google/uuid" @@ -113,6 +115,41 @@ type CommonNetStub struct { NetStub } +type CurioStruct struct { + Internal CurioMethods +} + +type CurioMethods struct { + AllocatePieceToSector func(p0 context.Context, p1 address.Address, p2 PieceDealInfo, p3 int64, p4 url.URL, p5 http.Header) (SectorOffset, error) `perm:"write"` + + LogList func(p0 context.Context) ([]string, error) `perm:"read"` + + LogSetLevel func(p0 context.Context, p1 string, p2 string) error `perm:"admin"` + + Shutdown 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"` + + 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"` + + StorageInit func(p0 context.Context, p1 string, p2 storiface.LocalStorageMeta) error `perm:"admin"` + + StorageList func(p0 context.Context) (map[storiface.ID][]storiface.Decl, error) `perm:"admin"` + + StorageLocal func(p0 context.Context) (map[storiface.ID]string, error) `perm:"admin"` + + StorageStat func(p0 context.Context, p1 storiface.ID) (fsutil.FsStat, error) `perm:"admin"` + + Version func(p0 context.Context) (Version, error) `perm:"admin"` +} + +type CurioStub struct { +} + type EthSubscriberStruct struct { Internal EthSubscriberMethods } @@ -457,10 +494,6 @@ type FullNodeMethods struct { PaychVoucherSubmit func(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (cid.Cid, error) `perm:"sign"` - RaftLeader func(p0 context.Context) (peer.ID, error) `perm:"read"` - - RaftState func(p0 context.Context) (*RaftStateData, error) `perm:"read"` - StateAccountKey func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) `perm:"read"` StateActorCodeCIDs func(p0 context.Context, p1 abinetwork.Version) (map[string]cid.Cid, error) `perm:"read"` @@ -687,6 +720,8 @@ type GatewayMethods struct { EthAccounts func(p0 context.Context) ([]ethtypes.EthAddress, error) `` + EthAddressToFilecoinAddress func(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) `` + EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `` EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) `` @@ -757,6 +792,8 @@ type GatewayMethods struct { EthUnsubscribe func(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) `` + FilecoinAddressToEthAddress func(p0 context.Context, p1 address.Address) (ethtypes.EthAddress, error) `` + GasEstimateGasPremium func(p0 context.Context, p1 uint64, p2 address.Address, p3 int64, p4 types.TipSetKey) (types.BigInt, error) `` GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `` @@ -811,6 +848,8 @@ type GatewayMethods struct { StateMarketStorageDeal func(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*MarketDeal, error) `` + StateMinerDeadlines func(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]Deadline, 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) `` @@ -849,19 +888,6 @@ type GatewayMethods struct { type GatewayStub struct { } -type LotusProviderStruct struct { - Internal LotusProviderMethods -} - -type LotusProviderMethods struct { - Shutdown func(p0 context.Context) error `perm:"admin"` - - Version func(p0 context.Context) (Version, error) `perm:"admin"` -} - -type LotusProviderStub struct { -} - type NetStruct struct { Internal NetMethods } @@ -1169,7 +1195,7 @@ type StorageMinerMethods struct { StorageAuthVerify func(p0 context.Context, p1 string) ([]auth.Permission, error) `perm:"read"` - StorageBestAlloc func(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType) ([]storiface.StorageInfo, error) `perm:"admin"` + StorageBestAlloc func(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType, p4 abi.ActorID) ([]storiface.StorageInfo, error) `perm:"admin"` StorageDeclareSector func(p0 context.Context, p1 storiface.ID, p2 abi.SectorID, p3 storiface.SectorFileType, p4 bool) error `perm:"admin"` @@ -1472,6 +1498,149 @@ func (s *CommonStub) Version(p0 context.Context) (APIVersion, error) { return *new(APIVersion), ErrNotSupported } +func (s *CurioStruct) AllocatePieceToSector(p0 context.Context, p1 address.Address, p2 PieceDealInfo, p3 int64, p4 url.URL, p5 http.Header) (SectorOffset, error) { + if s.Internal.AllocatePieceToSector == nil { + return *new(SectorOffset), ErrNotSupported + } + return s.Internal.AllocatePieceToSector(p0, p1, p2, p3, p4, p5) +} + +func (s *CurioStub) AllocatePieceToSector(p0 context.Context, p1 address.Address, p2 PieceDealInfo, p3 int64, p4 url.URL, p5 http.Header) (SectorOffset, error) { + return *new(SectorOffset), ErrNotSupported +} + +func (s *CurioStruct) LogList(p0 context.Context) ([]string, error) { + if s.Internal.LogList == nil { + return *new([]string), ErrNotSupported + } + return s.Internal.LogList(p0) +} + +func (s *CurioStub) LogList(p0 context.Context) ([]string, error) { + return *new([]string), ErrNotSupported +} + +func (s *CurioStruct) LogSetLevel(p0 context.Context, p1 string, p2 string) error { + if s.Internal.LogSetLevel == nil { + return ErrNotSupported + } + return s.Internal.LogSetLevel(p0, p1, p2) +} + +func (s *CurioStub) LogSetLevel(p0 context.Context, p1 string, p2 string) error { + return ErrNotSupported +} + +func (s *CurioStruct) Shutdown(p0 context.Context) error { + if s.Internal.Shutdown == nil { + return ErrNotSupported + } + return s.Internal.Shutdown(p0) +} + +func (s *CurioStub) Shutdown(p0 context.Context) error { + return ErrNotSupported +} + +func (s *CurioStruct) StorageAddLocal(p0 context.Context, p1 string) error { + if s.Internal.StorageAddLocal == nil { + return ErrNotSupported + } + return s.Internal.StorageAddLocal(p0, p1) +} + +func (s *CurioStub) StorageAddLocal(p0 context.Context, p1 string) error { + return ErrNotSupported +} + +func (s *CurioStruct) StorageDetachLocal(p0 context.Context, p1 string) error { + if s.Internal.StorageDetachLocal == nil { + return ErrNotSupported + } + return s.Internal.StorageDetachLocal(p0, p1) +} + +func (s *CurioStub) StorageDetachLocal(p0 context.Context, p1 string) error { + return ErrNotSupported +} + +func (s *CurioStruct) StorageFindSector(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 abi.SectorSize, p4 bool) ([]storiface.SectorStorageInfo, error) { + if s.Internal.StorageFindSector == nil { + return *new([]storiface.SectorStorageInfo), ErrNotSupported + } + return s.Internal.StorageFindSector(p0, p1, p2, p3, p4) +} + +func (s *CurioStub) StorageFindSector(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 abi.SectorSize, p4 bool) ([]storiface.SectorStorageInfo, error) { + return *new([]storiface.SectorStorageInfo), ErrNotSupported +} + +func (s *CurioStruct) StorageInfo(p0 context.Context, p1 storiface.ID) (storiface.StorageInfo, error) { + if s.Internal.StorageInfo == nil { + return *new(storiface.StorageInfo), ErrNotSupported + } + return s.Internal.StorageInfo(p0, p1) +} + +func (s *CurioStub) StorageInfo(p0 context.Context, p1 storiface.ID) (storiface.StorageInfo, error) { + return *new(storiface.StorageInfo), ErrNotSupported +} + +func (s *CurioStruct) StorageInit(p0 context.Context, p1 string, p2 storiface.LocalStorageMeta) error { + if s.Internal.StorageInit == nil { + return ErrNotSupported + } + return s.Internal.StorageInit(p0, p1, p2) +} + +func (s *CurioStub) StorageInit(p0 context.Context, p1 string, p2 storiface.LocalStorageMeta) error { + return ErrNotSupported +} + +func (s *CurioStruct) StorageList(p0 context.Context) (map[storiface.ID][]storiface.Decl, error) { + if s.Internal.StorageList == nil { + return *new(map[storiface.ID][]storiface.Decl), ErrNotSupported + } + return s.Internal.StorageList(p0) +} + +func (s *CurioStub) StorageList(p0 context.Context) (map[storiface.ID][]storiface.Decl, error) { + return *new(map[storiface.ID][]storiface.Decl), ErrNotSupported +} + +func (s *CurioStruct) StorageLocal(p0 context.Context) (map[storiface.ID]string, error) { + if s.Internal.StorageLocal == nil { + return *new(map[storiface.ID]string), ErrNotSupported + } + return s.Internal.StorageLocal(p0) +} + +func (s *CurioStub) StorageLocal(p0 context.Context) (map[storiface.ID]string, error) { + return *new(map[storiface.ID]string), ErrNotSupported +} + +func (s *CurioStruct) StorageStat(p0 context.Context, p1 storiface.ID) (fsutil.FsStat, error) { + if s.Internal.StorageStat == nil { + return *new(fsutil.FsStat), ErrNotSupported + } + return s.Internal.StorageStat(p0, p1) +} + +func (s *CurioStub) StorageStat(p0 context.Context, p1 storiface.ID) (fsutil.FsStat, error) { + return *new(fsutil.FsStat), ErrNotSupported +} + +func (s *CurioStruct) Version(p0 context.Context) (Version, error) { + if s.Internal.Version == nil { + return *new(Version), ErrNotSupported + } + return s.Internal.Version(p0) +} + +func (s *CurioStub) Version(p0 context.Context) (Version, error) { + return *new(Version), ErrNotSupported +} + func (s *EthSubscriberStruct) EthSubscription(p0 context.Context, p1 jsonrpc.RawParams) error { if s.Internal.EthSubscription == nil { return ErrNotSupported @@ -3265,28 +3434,6 @@ func (s *FullNodeStub) PaychVoucherSubmit(p0 context.Context, p1 address.Address return *new(cid.Cid), ErrNotSupported } -func (s *FullNodeStruct) RaftLeader(p0 context.Context) (peer.ID, error) { - if s.Internal.RaftLeader == nil { - return *new(peer.ID), ErrNotSupported - } - return s.Internal.RaftLeader(p0) -} - -func (s *FullNodeStub) RaftLeader(p0 context.Context) (peer.ID, error) { - return *new(peer.ID), ErrNotSupported -} - -func (s *FullNodeStruct) RaftState(p0 context.Context) (*RaftStateData, error) { - if s.Internal.RaftState == nil { - return nil, ErrNotSupported - } - return s.Internal.RaftState(p0) -} - -func (s *FullNodeStub) RaftState(p0 context.Context) (*RaftStateData, error) { - return nil, ErrNotSupported -} - func (s *FullNodeStruct) StateAccountKey(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) { if s.Internal.StateAccountKey == nil { return *new(address.Address), ErrNotSupported @@ -4464,6 +4611,17 @@ func (s *GatewayStub) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, er return *new([]ethtypes.EthAddress), ErrNotSupported } +func (s *GatewayStruct) 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 *GatewayStub) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) { + return *new(address.Address), ErrNotSupported +} + func (s *GatewayStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) { if s.Internal.EthBlockNumber == nil { return *new(ethtypes.EthUint64), ErrNotSupported @@ -4849,6 +5007,17 @@ func (s *GatewayStub) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscrip return false, ErrNotSupported } +func (s *GatewayStruct) 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 *GatewayStub) FilecoinAddressToEthAddress(p0 context.Context, p1 address.Address) (ethtypes.EthAddress, error) { + return *new(ethtypes.EthAddress), ErrNotSupported +} + func (s *GatewayStruct) GasEstimateGasPremium(p0 context.Context, p1 uint64, p2 address.Address, p3 int64, p4 types.TipSetKey) (types.BigInt, error) { if s.Internal.GasEstimateGasPremium == nil { return *new(types.BigInt), ErrNotSupported @@ -5146,6 +5315,17 @@ func (s *GatewayStub) StateMarketStorageDeal(p0 context.Context, p1 abi.DealID, return nil, ErrNotSupported } +func (s *GatewayStruct) StateMinerDeadlines(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]Deadline, error) { + if s.Internal.StateMinerDeadlines == nil { + return *new([]Deadline), ErrNotSupported + } + return s.Internal.StateMinerDeadlines(p0, p1, p2) +} + +func (s *GatewayStub) StateMinerDeadlines(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]Deadline, error) { + return *new([]Deadline), ErrNotSupported +} + func (s *GatewayStruct) StateMinerInfo(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerInfo, error) { if s.Internal.StateMinerInfo == nil { return *new(MinerInfo), ErrNotSupported @@ -5333,28 +5513,6 @@ func (s *GatewayStub) Web3ClientVersion(p0 context.Context) (string, error) { return "", ErrNotSupported } -func (s *LotusProviderStruct) Shutdown(p0 context.Context) error { - if s.Internal.Shutdown == nil { - return ErrNotSupported - } - return s.Internal.Shutdown(p0) -} - -func (s *LotusProviderStub) Shutdown(p0 context.Context) error { - return ErrNotSupported -} - -func (s *LotusProviderStruct) Version(p0 context.Context) (Version, error) { - if s.Internal.Version == nil { - return *new(Version), ErrNotSupported - } - return s.Internal.Version(p0) -} - -func (s *LotusProviderStub) Version(p0 context.Context) (Version, error) { - return *new(Version), ErrNotSupported -} - func (s *NetStruct) ID(p0 context.Context) (peer.ID, error) { if s.Internal.ID == nil { return *new(peer.ID), ErrNotSupported @@ -6895,14 +7053,14 @@ func (s *StorageMinerStub) StorageAuthVerify(p0 context.Context, p1 string) ([]a return *new([]auth.Permission), ErrNotSupported } -func (s *StorageMinerStruct) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType) ([]storiface.StorageInfo, error) { +func (s *StorageMinerStruct) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType, p4 abi.ActorID) ([]storiface.StorageInfo, error) { if s.Internal.StorageBestAlloc == nil { return *new([]storiface.StorageInfo), ErrNotSupported } - return s.Internal.StorageBestAlloc(p0, p1, p2, p3) + return s.Internal.StorageBestAlloc(p0, p1, p2, p3, p4) } -func (s *StorageMinerStub) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType) ([]storiface.StorageInfo, error) { +func (s *StorageMinerStub) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType, p4 abi.ActorID) ([]storiface.StorageInfo, error) { return *new([]storiface.StorageInfo), ErrNotSupported } @@ -7580,10 +7738,10 @@ func (s *WorkerStub) WaitQuiet(p0 context.Context) error { var _ ChainIO = new(ChainIOStruct) var _ Common = new(CommonStruct) var _ CommonNet = new(CommonNetStruct) +var _ Curio = new(CurioStruct) var _ EthSubscriber = new(EthSubscriberStruct) var _ FullNode = new(FullNodeStruct) var _ Gateway = new(GatewayStruct) -var _ LotusProvider = new(LotusProviderStruct) var _ Net = new(NetStruct) var _ Signable = new(SignableStruct) var _ StorageMiner = new(StorageMinerStruct) diff --git a/api/types.go b/api/types.go index 5fe9ffca397..b7dbe7b3625 100644 --- a/api/types.go +++ b/api/types.go @@ -69,11 +69,6 @@ type MessageSendSpec struct { MaximizeFeeCap bool } -type MpoolMessageWhole struct { - Msg *types.Message - Spec *MessageSendSpec -} - // GraphSyncDataTransfer provides diagnostics on a data transfer happening over graphsync type GraphSyncDataTransfer struct { // GraphSync request id for this transfer @@ -353,64 +348,6 @@ type ForkUpgradeParams struct { UpgradePhoenixHeight abi.ChainEpoch } -type NonceMapType map[address.Address]uint64 -type MsgUuidMapType map[uuid.UUID]*types.SignedMessage - -type RaftStateData struct { - NonceMap NonceMapType - MsgUuids MsgUuidMapType -} - -func (n *NonceMapType) MarshalJSON() ([]byte, error) { - marshalled := make(map[string]uint64) - for a, n := range *n { - marshalled[a.String()] = n - } - return json.Marshal(marshalled) -} - -func (n *NonceMapType) UnmarshalJSON(b []byte) error { - unmarshalled := make(map[string]uint64) - err := json.Unmarshal(b, &unmarshalled) - if err != nil { - return err - } - *n = make(map[address.Address]uint64) - for saddr, nonce := range unmarshalled { - a, err := address.NewFromString(saddr) - if err != nil { - return err - } - (*n)[a] = nonce - } - return nil -} - -func (m *MsgUuidMapType) MarshalJSON() ([]byte, error) { - marshalled := make(map[string]*types.SignedMessage) - for u, msg := range *m { - marshalled[u.String()] = msg - } - return json.Marshal(marshalled) -} - -func (m *MsgUuidMapType) UnmarshalJSON(b []byte) error { - unmarshalled := make(map[string]*types.SignedMessage) - err := json.Unmarshal(b, &unmarshalled) - if err != nil { - return err - } - *m = make(map[uuid.UUID]*types.SignedMessage) - for suid, msg := range unmarshalled { - u, err := uuid.Parse(suid) - if err != nil { - return err - } - (*m)[u] = msg - } - return nil -} - // ChainExportConfig holds configuration for chain ranged exports. type ChainExportConfig struct { WriteBufferSize int diff --git a/api/v0api/full.go b/api/v0api/full.go index db84ddc8745..b61fc157025 100644 --- a/api/v0api/full.go +++ b/api/v0api/full.go @@ -293,7 +293,7 @@ type FullNode interface { WalletVerify(context.Context, address.Address, []byte, *crypto.Signature) (bool, error) //perm:read // WalletDefaultAddress returns the address marked as default in the wallet. WalletDefaultAddress(context.Context) (address.Address, error) //perm:write - // WalletSetDefault marks the given address as as the default one. + // WalletSetDefault marks the given address as the default one. WalletSetDefault(context.Context, address.Address) error //perm:write // WalletExport returns the private key of an address in the wallet. WalletExport(context.Context, address.Address) (*types.KeyInfo, error) //perm:admin diff --git a/api/v0api/v0mocks/mock_full.go b/api/v0api/v0mocks/mock_full.go index 6b70e0e49f8..df67d087656 100644 --- a/api/v0api/v0mocks/mock_full.go +++ b/api/v0api/v0mocks/mock_full.go @@ -26,8 +26,9 @@ import ( 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" + miner "github.com/filecoin-project/go-state-types/builtin/v13/miner" paych "github.com/filecoin-project/go-state-types/builtin/v8/paych" - miner "github.com/filecoin-project/go-state-types/builtin/v9/miner" + miner0 "github.com/filecoin-project/go-state-types/builtin/v9/miner" verifreg "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" crypto "github.com/filecoin-project/go-state-types/crypto" dline "github.com/filecoin-project/go-state-types/dline" @@ -36,7 +37,7 @@ import ( api "github.com/filecoin-project/lotus/api" apitypes "github.com/filecoin-project/lotus/api/types" v0api "github.com/filecoin-project/lotus/api/v0api" - miner0 "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + miner1 "github.com/filecoin-project/lotus/chain/actors/builtin/miner" types "github.com/filecoin-project/lotus/chain/types" alerting "github.com/filecoin-project/lotus/journal/alerting" marketevents "github.com/filecoin-project/lotus/markets/loggers" @@ -2699,7 +2700,7 @@ func (mr *MockFullNodeMockRecorder) StateMinerInfo(arg0, arg1, arg2 interface{}) } // StateMinerInitialPledgeCollateral mocks base method. -func (m *MockFullNode) StateMinerInitialPledgeCollateral(arg0 context.Context, arg1 address.Address, arg2 miner.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { +func (m *MockFullNode) StateMinerInitialPledgeCollateral(arg0 context.Context, arg1 address.Address, arg2 miner0.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateMinerInitialPledgeCollateral", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(big.Int) @@ -2744,7 +2745,7 @@ func (mr *MockFullNodeMockRecorder) StateMinerPower(arg0, arg1, arg2 interface{} } // StateMinerPreCommitDepositForPower mocks base method. -func (m *MockFullNode) StateMinerPreCommitDepositForPower(arg0 context.Context, arg1 address.Address, arg2 miner.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { +func (m *MockFullNode) StateMinerPreCommitDepositForPower(arg0 context.Context, arg1 address.Address, arg2 miner0.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateMinerPreCommitDepositForPower", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(big.Int) @@ -2924,10 +2925,10 @@ func (mr *MockFullNodeMockRecorder) StateSearchMsgLimited(arg0, arg1, arg2 inter } // StateSectorExpiration mocks base method. -func (m *MockFullNode) StateSectorExpiration(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner0.SectorExpiration, error) { +func (m *MockFullNode) StateSectorExpiration(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner1.SectorExpiration, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateSectorExpiration", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(*miner0.SectorExpiration) + ret0, _ := ret[0].(*miner1.SectorExpiration) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -2954,10 +2955,10 @@ func (mr *MockFullNodeMockRecorder) StateSectorGetInfo(arg0, arg1, arg2, arg3 in } // StateSectorPartition mocks base method. -func (m *MockFullNode) StateSectorPartition(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner0.SectorLocation, error) { +func (m *MockFullNode) StateSectorPartition(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner1.SectorLocation, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateSectorPartition", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(*miner0.SectorLocation) + ret0, _ := ret[0].(*miner1.SectorLocation) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -2969,10 +2970,10 @@ func (mr *MockFullNodeMockRecorder) StateSectorPartition(arg0, arg1, arg2, arg3 } // StateSectorPreCommitInfo mocks base method. -func (m *MockFullNode) StateSectorPreCommitInfo(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) { +func (m *MockFullNode) StateSectorPreCommitInfo(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (miner0.SectorPreCommitOnChainInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateSectorPreCommitInfo", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(miner.SectorPreCommitOnChainInfo) + ret0, _ := ret[0].(miner0.SectorPreCommitOnChainInfo) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/api/v1api/latest.go b/api/v1api/latest.go index b8eeed2de57..a1e63b6ada7 100644 --- a/api/v1api/latest.go +++ b/api/v1api/latest.go @@ -13,4 +13,4 @@ func PermissionedFullAPI(a FullNode) FullNode { return api.PermissionedFullAPI(a) } -type LotusProviderStruct = api.LotusProviderStruct +type CurioStruct = api.CurioStruct diff --git a/api/version.go b/api/version.go index e968bf93bc4..124f53dabfb 100644 --- a/api/version.go +++ b/api/version.go @@ -60,7 +60,7 @@ var ( MinerAPIVersion0 = newVer(1, 5, 0) WorkerAPIVersion0 = newVer(1, 7, 0) - ProviderAPIVersion0 = newVer(1, 0, 0) + CurioAPIVersion0 = newVer(1, 0, 0) ) //nolint:varcheck,deadcode diff --git a/blockstore/buffered.go b/blockstore/buffered.go index 2a789b6371a..9cfc12e65fb 100644 --- a/blockstore/buffered.go +++ b/blockstore/buffered.go @@ -109,11 +109,9 @@ func (bs *BufferedBlockstore) DeleteMany(ctx context.Context, cids []cid.Cid) er func (bs *BufferedBlockstore) View(ctx context.Context, c cid.Cid, callback func([]byte) error) error { // both stores are viewable. - if err := bs.write.View(ctx, c, callback); ipld.IsNotFound(err) { - // not found in write blockstore; fall through. - } else { + if err := bs.write.View(ctx, c, callback); !ipld.IsNotFound(err) { return err // propagate errors, or nil, i.e. found. - } + } // else not found in write blockstore; fall through. return bs.read.View(ctx, c, callback) } diff --git a/blockstore/cached.go b/blockstore/cached.go new file mode 100644 index 00000000000..113ec599035 --- /dev/null +++ b/blockstore/cached.go @@ -0,0 +1,113 @@ +package blockstore + +import ( + "context" + + blocks "github.com/ipfs/go-block-format" + "github.com/ipfs/go-cid" +) + +// BlockstoreCache is a cache for blocks, compatible with lru.Cache; Must be safe for concurrent access +type BlockstoreCache interface { + Remove(mhString MhString) bool + Contains(mhString MhString) bool + Get(mhString MhString) (blocks.Block, bool) + Add(mhString MhString, block blocks.Block) (evicted bool) +} + +type ReadCachedBlockstore struct { + top Blockstore + cache BlockstoreCache +} + +type MhString string + +func NewReadCachedBlockstore(top Blockstore, cache BlockstoreCache) *ReadCachedBlockstore { + return &ReadCachedBlockstore{ + top: top, + cache: cache, + } +} + +func (c *ReadCachedBlockstore) DeleteBlock(ctx context.Context, cid cid.Cid) error { + c.cache.Remove(MhString(cid.Hash())) + return c.top.DeleteBlock(ctx, cid) +} + +func (c *ReadCachedBlockstore) Has(ctx context.Context, cid cid.Cid) (bool, error) { + if c.cache.Contains(MhString(cid.Hash())) { + return true, nil + } + + return c.top.Has(ctx, cid) +} + +func (c *ReadCachedBlockstore) Get(ctx context.Context, cid cid.Cid) (blocks.Block, error) { + if out, ok := c.cache.Get(MhString(cid.Hash())); ok { + return out, nil + } + + out, err := c.top.Get(ctx, cid) + if err != nil { + return nil, err + } + + c.cache.Add(MhString(cid.Hash()), out) + return out, nil +} + +func (c *ReadCachedBlockstore) GetSize(ctx context.Context, cid cid.Cid) (int, error) { + if b, ok := c.cache.Get(MhString(cid.Hash())); ok { + return len(b.RawData()), nil + } + + return c.top.GetSize(ctx, cid) +} + +func (c *ReadCachedBlockstore) Put(ctx context.Context, block blocks.Block) error { + c.cache.Add(MhString(block.Cid().Hash()), block) + return c.top.Put(ctx, block) +} + +func (c *ReadCachedBlockstore) PutMany(ctx context.Context, blocks []blocks.Block) error { + for _, b := range blocks { + c.cache.Add(MhString(b.Cid().Hash()), b) + } + + return c.top.PutMany(ctx, blocks) +} + +func (c *ReadCachedBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { + return c.top.AllKeysChan(ctx) +} + +func (c *ReadCachedBlockstore) HashOnRead(enabled bool) { + c.top.HashOnRead(enabled) +} + +func (c *ReadCachedBlockstore) View(ctx context.Context, cid cid.Cid, callback func([]byte) error) error { + return c.top.View(ctx, cid, func(bb []byte) error { + blk, err := blocks.NewBlockWithCid(bb, cid) + if err != nil { + return err + } + + c.cache.Add(MhString(cid.Hash()), blk) + + return callback(bb) + }) +} + +func (c *ReadCachedBlockstore) DeleteMany(ctx context.Context, cids []cid.Cid) error { + for _, ci := range cids { + c.cache.Remove(MhString(ci.Hash())) + } + + return c.top.DeleteMany(ctx, cids) +} + +func (c *ReadCachedBlockstore) Flush(ctx context.Context) error { + return c.top.Flush(ctx) +} + +var _ Blockstore = (*ReadCachedBlockstore)(nil) diff --git a/blockstore/ipfs.go b/blockstore/ipfs.go deleted file mode 100644 index f0606519ffb..00000000000 --- a/blockstore/ipfs.go +++ /dev/null @@ -1,154 +0,0 @@ -package blockstore - -import ( - "bytes" - "context" - "io" - - "github.com/ipfs/boxo/path" - blocks "github.com/ipfs/go-block-format" - "github.com/ipfs/go-cid" - "github.com/multiformats/go-multiaddr" - "github.com/multiformats/go-multihash" - "golang.org/x/xerrors" - - rpc "github.com/filecoin-project/kubo-api-client" - iface "github.com/filecoin-project/kubo-api-client/coreiface" - "github.com/filecoin-project/kubo-api-client/coreiface/options" -) - -type IPFSBlockstore struct { - ctx context.Context - api, offlineAPI iface.CoreAPI -} - -var _ BasicBlockstore = (*IPFSBlockstore)(nil) - -func NewLocalIPFSBlockstore(ctx context.Context, onlineMode bool) (Blockstore, error) { - localApi, err := rpc.NewLocalApi() - if err != nil { - return nil, xerrors.Errorf("getting local ipfs api: %w", err) - } - api, err := localApi.WithOptions(options.Api.Offline(!onlineMode)) - if err != nil { - return nil, xerrors.Errorf("setting offline mode: %s", err) - } - - offlineAPI := api - if onlineMode { - offlineAPI, err = localApi.WithOptions(options.Api.Offline(true)) - if err != nil { - return nil, xerrors.Errorf("applying offline mode: %s", err) - } - } - - bs := &IPFSBlockstore{ - ctx: ctx, - api: api, - offlineAPI: offlineAPI, - } - - return Adapt(bs), nil -} - -func NewRemoteIPFSBlockstore(ctx context.Context, maddr multiaddr.Multiaddr, onlineMode bool) (Blockstore, error) { - httpApi, err := rpc.NewApi(maddr) - if err != nil { - return nil, xerrors.Errorf("setting remote ipfs api: %w", err) - } - api, err := httpApi.WithOptions(options.Api.Offline(!onlineMode)) - if err != nil { - return nil, xerrors.Errorf("applying offline mode: %s", err) - } - - offlineAPI := api - if onlineMode { - offlineAPI, err = httpApi.WithOptions(options.Api.Offline(true)) - if err != nil { - return nil, xerrors.Errorf("applying offline mode: %s", err) - } - } - - bs := &IPFSBlockstore{ - ctx: ctx, - api: api, - offlineAPI: offlineAPI, - } - - return Adapt(bs), nil -} - -func (i *IPFSBlockstore) DeleteBlock(ctx context.Context, cid cid.Cid) error { - return xerrors.Errorf("not supported") -} - -func (i *IPFSBlockstore) Has(ctx context.Context, cid cid.Cid) (bool, error) { - _, err := i.offlineAPI.Block().Stat(ctx, path.FromCid(cid)) - if err != nil { - // The underlying client is running in Offline mode. - // Stat() will fail with an err if the block isn't in the - // blockstore. If that's the case, return false without - // an error since that's the original intention of this method. - if err.Error() == "blockservice: key not found" { - return false, nil - } - return false, xerrors.Errorf("getting ipfs block: %w", err) - } - - return true, nil -} - -func (i *IPFSBlockstore) Get(ctx context.Context, cid cid.Cid) (blocks.Block, error) { - rd, err := i.api.Block().Get(ctx, path.FromCid(cid)) - if err != nil { - return nil, xerrors.Errorf("getting ipfs block: %w", err) - } - - data, err := io.ReadAll(rd) - if err != nil { - return nil, err - } - - return blocks.NewBlockWithCid(data, cid) -} - -func (i *IPFSBlockstore) GetSize(ctx context.Context, cid cid.Cid) (int, error) { - st, err := i.api.Block().Stat(ctx, path.FromCid(cid)) - if err != nil { - return 0, xerrors.Errorf("getting ipfs block: %w", err) - } - - return st.Size(), nil -} - -func (i *IPFSBlockstore) Put(ctx context.Context, block blocks.Block) error { - mhd, err := multihash.Decode(block.Cid().Hash()) - if err != nil { - return err - } - - _, err = i.api.Block().Put(ctx, bytes.NewReader(block.RawData()), - options.Block.Hash(mhd.Code, mhd.Length), - options.Block.Format(multihash.Codes[block.Cid().Type()])) - return err -} - -func (i *IPFSBlockstore) PutMany(ctx context.Context, blocks []blocks.Block) error { - // TODO: could be done in parallel - - for _, block := range blocks { - if err := i.Put(ctx, block); err != nil { - return err - } - } - - return nil -} - -func (i *IPFSBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { - return nil, xerrors.Errorf("not supported") -} - -func (i *IPFSBlockstore) HashOnRead(enabled bool) { - return // TODO: We could technically support this, but.. -} diff --git a/blockstore/splitstore/splitstore.go b/blockstore/splitstore/splitstore.go index c1a95c8b060..6da1cf7f3cc 100644 --- a/blockstore/splitstore/splitstore.go +++ b/blockstore/splitstore/splitstore.go @@ -282,14 +282,14 @@ func Open(path string, ds dstore.Datastore, hot, cold bstore.Blockstore, cfg *Co if ss.checkpointExists() { log.Info("found compaction checkpoint; resuming compaction") if err := ss.completeCompaction(); err != nil { - markSetEnv.Close() //nolint:errcheck + _ = markSetEnv.Close() return nil, xerrors.Errorf("error resuming compaction: %w", err) } } if ss.pruneCheckpointExists() { log.Info("found prune checkpoint; resuming prune") if err := ss.completePrune(); err != nil { - markSetEnv.Close() //nolint:errcheck + _ = markSetEnv.Close() return nil, xerrors.Errorf("error resuming prune: %w", err) } } diff --git a/blockstore/splitstore/splitstore_compact.go b/blockstore/splitstore/splitstore_compact.go index 47caca886da..c8e4caa45b5 100644 --- a/blockstore/splitstore/splitstore_compact.go +++ b/blockstore/splitstore/splitstore_compact.go @@ -109,16 +109,13 @@ func (s *SplitStore) HeadChange(_, apply []*types.TipSet) error { // TODO: ok to use hysteresis with no transitions between 30s and 1m? if time.Since(timestamp) < SyncWaitTime { /* Chain in sync */ - if atomic.CompareAndSwapInt32(&s.outOfSync, 0, 0) { - // already in sync, no signaling necessary - } else { + if !atomic.CompareAndSwapInt32(&s.outOfSync, 0, 0) { // transition from out of sync to in sync s.chainSyncMx.Lock() s.chainSyncFinished = true s.chainSyncCond.Broadcast() s.chainSyncMx.Unlock() - } - + } // else already in sync, no signaling necessary } // 2. protect the new tipset(s) s.protectTipSets(apply) diff --git a/blockstore/splitstore/splitstore_test.go b/blockstore/splitstore/splitstore_test.go index 1b821654d08..b28f45c8441 100644 --- a/blockstore/splitstore/splitstore_test.go +++ b/blockstore/splitstore/splitstore_test.go @@ -32,7 +32,7 @@ func init() { CompactionBoundary = 2 WarmupBoundary = 0 SyncWaitTime = time.Millisecond - logging.SetLogLevel("splitstore", "DEBUG") + _ = logging.SetLogLevel("splitstore", "DEBUG") } func testSplitStore(t *testing.T, cfg *Config) { diff --git a/build/bootstrap/mainnet.pi b/build/bootstrap/mainnet.pi index 5b13ae755e7..2afe6f29750 100644 --- a/build/bootstrap/mainnet.pi +++ b/build/bootstrap/mainnet.pi @@ -1,6 +1,3 @@ -/dns4/lotus-bootstrap.ipfsforce.com/tcp/41778/p2p/12D3KooWGhufNmZHF3sv48aQeS13ng5XVJZ9E6qy2Ms4VzqeUsHk -/dns4/bootstrap-0.starpool.in/tcp/12757/p2p/12D3KooWGHpBMeZbestVEWkfdnC9u7p6uFHXL1n7m1ZBqsEmiUzz -/dns4/bootstrap-1.starpool.in/tcp/12757/p2p/12D3KooWQZrGH1PxSNZPum99M1zNvjNFM33d1AAu5DcvdHptuU7u /dns4/node.glif.io/tcp/1235/p2p/12D3KooWBF8cpp65hp2u9LK5mh19x67ftAam84z9LsfaquTDSBpt /dns4/bootstarp-0.1475.io/tcp/61256/p2p/12D3KooWRzCVDwHUkgdK7eRgnoXbjDAELhxPErjHzbRLguSV1aRt /dns4/bootstrap-venus.mainnet.filincubator.com/tcp/8888/p2p/QmQu8C6deXwKvJP2D8B6QGyhngc3ZiDnFzEHBDx8yeBXST diff --git a/build/builtin_actors.go b/build/builtin_actors.go index 6aace0bec50..1cc43c3749c 100644 --- a/build/builtin_actors.go +++ b/build/builtin_actors.go @@ -145,10 +145,10 @@ func readEmbeddedBuiltinActorsMetadata(bundle string) ([]*BuiltinActorsMetadata, ) if !strings.HasPrefix(bundle, "v") { - return nil, xerrors.Errorf("bundle bundle '%q' doesn't start with a 'v'", bundle) + return nil, xerrors.Errorf("bundle '%q' doesn't start with a 'v'", bundle) } if !strings.HasSuffix(bundle, archiveExt) { - return nil, xerrors.Errorf("bundle bundle '%q' doesn't end with '%s'", bundle, archiveExt) + return nil, xerrors.Errorf("bundle '%q' doesn't end with '%s'", bundle, archiveExt) } version, err := strconv.ParseInt(bundle[1:len(bundle)-len(archiveExt)], 10, 0) if err != nil { diff --git a/build/builtin_actors_gen.go b/build/builtin_actors_gen.go index 4d2a6674c57..6d046306712 100644 --- a/build/builtin_actors_gen.go +++ b/build/builtin_actors_gen.go @@ -6,7 +6,7 @@ import ( "github.com/ipfs/go-cid" ) -var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMetadata{{ +var EmbeddedBuiltinActorsMetadata = []*BuiltinActorsMetadata{{ Network: "butterflynet", Version: 8, diff --git a/build/builtin_actors_gen_test.go b/build/builtin_actors_gen_test.go new file mode 100644 index 00000000000..1338097f7b2 --- /dev/null +++ b/build/builtin_actors_gen_test.go @@ -0,0 +1,107 @@ +//go:build release +// +build release + +package build_test + +import ( + "archive/tar" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "io" + "net/http" + "os" + "strings" + "testing" + + "github.com/DataDog/zstd" + "github.com/ipfs/go-cid" + "github.com/ipld/go-car/v2" + "github.com/stretchr/testify/require" + + actorstypes "github.com/filecoin-project/go-state-types/actors" + + "github.com/filecoin-project/lotus/build" +) + +func TestEmbeddedBuiltinActorsMetadata(t *testing.T) { + subjectsByVersionByNetworks := make(map[actorstypes.Version]map[string]*build.BuiltinActorsMetadata) + for _, subject := range build.EmbeddedBuiltinActorsMetadata { + if subject.BundleGitTag == "" { + // BundleGitTag is required to verify the SHA-256 checksum. + // The pack script only includes this for the latest network version, and it is good enough to only + // check the latest network version metadata. Hence the skip. + continue + } + v, ok := subjectsByVersionByNetworks[subject.Version] + if !ok { + v = make(map[string]*build.BuiltinActorsMetadata) + } + v[subject.Network] = subject + subjectsByVersionByNetworks[subject.Version] = v + } + + for version, networks := range subjectsByVersionByNetworks { + cachedCar, err := os.Open(fmt.Sprintf("./actors/v%v.tar.zst", version)) + require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, cachedCar.Close()) }) + tarReader := tar.NewReader(zstd.NewReader(cachedCar)) + for { + header, err := tarReader.Next() + if errors.Is(err, io.EOF) { + break + } + require.NoError(t, err) + + network := strings.TrimSuffix(strings.TrimPrefix(header.Name, "builtin-actors-"), ".car") + subject, found := networks[network] + if !found { + continue + } + + shaURL := fmt.Sprintf("https://github.com/filecoin-project/builtin-actors/releases/download/%s/builtin-actors-%s.sha256", subject.BundleGitTag, subject.Network) + resp, err := http.Get(shaURL) + require.NoError(t, err, "failed to retrieve CAR SHA") + require.Equal(t, http.StatusOK, resp.StatusCode, "unexpected response status code while retrieving CAR SHA") + + respBody, err := io.ReadAll(resp.Body) + require.NoError(t, resp.Body.Close()) + require.NoError(t, err) + fields := strings.Fields(string(respBody)) + require.Len(t, fields, 2) + wantShaHex := fields[0] + + hasher := sha256.New() + reader, err := car.NewBlockReader(io.TeeReader(tarReader, hasher)) + require.NoError(t, err) + + require.EqualValues(t, 1, reader.Version) + require.Len(t, reader.Roots, 1, "expected exactly one root CID for builtin actors bundle network %s, version %v", subject.Network, subject.Version) + require.True(t, reader.Roots[0].Equals(subject.ManifestCid), "manifest CID does not match") + + subjectActorsByCid := make(map[cid.Cid]string) + for name, c := range subject.Actors { + subjectActorsByCid[c] = name + } + for { + next, err := reader.Next() + if errors.Is(err, io.EOF) { + break + } + require.NoError(t, err) + name, found := subjectActorsByCid[next.Cid()] + if found { + t.Logf("OK: %sv%v/%s -> %s", subject.Network, subject.Version, name, next.Cid()) + delete(subjectActorsByCid, next.Cid()) + } + } + require.Empty(t, subjectActorsByCid, "ZST CAR bundle did not contain CIDs for all actors; missing: %v", subjectActorsByCid) + + gotShaHex := hex.EncodeToString(hasher.Sum(nil)) + require.Equal(t, wantShaHex, gotShaHex, "SHA-256 digest of ZST CAR bundle does not match builtin-actors release") + delete(networks, network) + } + require.Empty(t, networks, "CAR bundle did not contain CIDs for network; missing: %v", networks) + } +} diff --git a/build/drand.go b/build/drand.go index 782ac869230..c4ba4b3b7af 100644 --- a/build/drand.go +++ b/build/drand.go @@ -67,12 +67,10 @@ var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{ Servers: []string{ "https://pl-eu.testnet.drand.sh", "https://pl-us.testnet.drand.sh", - "https://pl-sin.testnet.drand.sh", }, Relays: []string{ "/dnsaddr/pl-eu.testnet.drand.sh/", "/dnsaddr/pl-us.testnet.drand.sh/", - "/dnsaddr/pl-sin.testnet.drand.sh/", }, IsChained: true, ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"84b2234fb34e835dccd048255d7ad3194b81af7d978c3bf157e3469592ae4e02","groupHash":"4dd408e5fdff9323c76a9b6f087ba8fdc5a6da907bd9217d9d10f2287d081957"}`, diff --git a/build/openrpc.go b/build/openrpc.go index a50d6f51e78..1c644bf9666 100644 --- a/build/openrpc.go +++ b/build/openrpc.go @@ -2,7 +2,6 @@ package build import ( "bytes" - "compress/gzip" "embed" "encoding/json" @@ -12,17 +11,9 @@ import ( //go:embed openrpc var openrpcfs embed.FS -func mustReadGzippedOpenRPCDocument(data []byte) apitypes.OpenRPCDocument { - zr, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - log.Fatal(err) - } +func mustReadOpenRPCDocument(data []byte) apitypes.OpenRPCDocument { m := apitypes.OpenRPCDocument{} - err = json.NewDecoder(zr).Decode(&m) - if err != nil { - log.Fatal(err) - } - err = zr.Close() + err := json.NewDecoder(bytes.NewBuffer(data)).Decode(&m) if err != nil { log.Fatal(err) } @@ -30,33 +21,33 @@ func mustReadGzippedOpenRPCDocument(data []byte) apitypes.OpenRPCDocument { } func OpenRPCDiscoverJSON_Full() apitypes.OpenRPCDocument { - data, err := openrpcfs.ReadFile("openrpc/full.json.gz") + data, err := openrpcfs.ReadFile("openrpc/full.json") if err != nil { panic(err) } - return mustReadGzippedOpenRPCDocument(data) + return mustReadOpenRPCDocument(data) } func OpenRPCDiscoverJSON_Miner() apitypes.OpenRPCDocument { - data, err := openrpcfs.ReadFile("openrpc/miner.json.gz") + data, err := openrpcfs.ReadFile("openrpc/miner.json") if err != nil { panic(err) } - return mustReadGzippedOpenRPCDocument(data) + return mustReadOpenRPCDocument(data) } func OpenRPCDiscoverJSON_Worker() apitypes.OpenRPCDocument { - data, err := openrpcfs.ReadFile("openrpc/worker.json.gz") + data, err := openrpcfs.ReadFile("openrpc/worker.json") if err != nil { panic(err) } - return mustReadGzippedOpenRPCDocument(data) + return mustReadOpenRPCDocument(data) } func OpenRPCDiscoverJSON_Gateway() apitypes.OpenRPCDocument { - data, err := openrpcfs.ReadFile("openrpc/gateway.json.gz") + data, err := openrpcfs.ReadFile("openrpc/gateway.json") if err != nil { panic(err) } - return mustReadGzippedOpenRPCDocument(data) + return mustReadOpenRPCDocument(data) } diff --git a/build/openrpc/full.json b/build/openrpc/full.json new file mode 100644 index 00000000000..3fda272671c --- /dev/null +++ b/build/openrpc/full.json @@ -0,0 +1,26867 @@ +{ + "openrpc": "1.2.6", + "info": { + "title": "Lotus RPC API", + "version": "1.27.0" + }, + "methods": [ + { + "name": "Filecoin.ChainBlockstoreInfo", + "description": "```go\nfunc (s *FullNodeStruct) ChainBlockstoreInfo(p0 context.Context) (map[string]interface{}, error) {\n\tif s.Internal.ChainBlockstoreInfo == nil {\n\t\treturn *new(map[string]interface{}), ErrNotSupported\n\t}\n\treturn s.Internal.ChainBlockstoreInfo(p0)\n}\n```", + "summary": "ChainBlockstoreInfo returns some basic information about the blockstore\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "map[string]interface{}", + "description": "map[string]interface{}", + "summary": "", + "schema": { + "examples": [ + { + "abc": 123 + } + ], + "patternProperties": { + ".*": { + "additionalProperties": true, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1655" + } + }, + { + "name": "Filecoin.ChainCheckBlockstore", + "description": "```go\nfunc (s *FullNodeStruct) ChainCheckBlockstore(p0 context.Context) error {\n\tif s.Internal.ChainCheckBlockstore == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ChainCheckBlockstore(p0)\n}\n```", + "summary": "ChainCheckBlockstore performs an (asynchronous) health check on the chain/state blockstore\nif supported by the underlying implementation.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1666" + } + }, + { + "name": "Filecoin.ChainDeleteObj", + "description": "```go\nfunc (s *FullNodeStruct) ChainDeleteObj(p0 context.Context, p1 cid.Cid) error {\n\tif s.Internal.ChainDeleteObj == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ChainDeleteObj(p0, p1)\n}\n```", + "summary": "ChainDeleteObj deletes node referenced by the given CID\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1677" + } + }, + { + "name": "Filecoin.ChainExportRangeInternal", + "description": "```go\nfunc (s *FullNodeStruct) ChainExportRangeInternal(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey, p3 ChainExportConfig) error {\n\tif s.Internal.ChainExportRangeInternal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ChainExportRangeInternal(p0, p1, p2, p3)\n}\n```", + "summary": "ChainExportRangeInternal triggers the export of a chain\nCAR-snapshot directly to disk. It is similar to ChainExport,\nexcept, depending on options, the snapshot can include receipts,\nmessages and stateroots for the length between the specified head\nand tail, thus producing \"archival-grade\" snapshots that include\nall the on-chain data. The header chain is included back to\ngenesis and these snapshots can be used to initialize Filecoin\nnodes.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "ChainExportConfig", + "summary": "", + "schema": { + "examples": [ + { + "WriteBufferSize": 123, + "NumWorkers": 123, + "IncludeMessages": true, + "IncludeReceipts": true, + "IncludeStateRoots": true + } + ], + "additionalProperties": false, + "properties": { + "IncludeMessages": { + "type": "boolean" + }, + "IncludeReceipts": { + "type": "boolean" + }, + "IncludeStateRoots": { + "type": "boolean" + }, + "NumWorkers": { + "title": "number", + "type": "number" + }, + "WriteBufferSize": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1699" + } + }, + { + "name": "Filecoin.ChainGetBlock", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetBlock(p0 context.Context, p1 cid.Cid) (*types.BlockHeader, error) {\n\tif s.Internal.ChainGetBlock == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetBlock(p0, p1)\n}\n```", + "summary": "ChainGetBlock returns the block specified by the given CID.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.BlockHeader", + "description": "*types.BlockHeader", + "summary": "", + "schema": { + "examples": [ + { + "Miner": "f01234", + "Ticket": { + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "ElectionProof": { + "WinCount": 9, + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": [ + { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + } + ], + "WinPoStProof": [ + { + "PoStProof": 8, + "ProofBytes": "Ynl0ZSBhcnJheQ==" + } + ], + "Parents": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "ParentWeight": "0", + "Height": 10101, + "ParentStateRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Messages": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "BLSAggregate": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Timestamp": 42, + "BlockSig": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "ForkSignaling": 42, + "ParentBaseFee": "0" + } + ], + "additionalProperties": false, + "properties": { + "BLSAggregate": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "BeaconEntries": { + "items": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Round": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "BlockSig": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ElectionProof": { + "additionalProperties": false, + "properties": { + "VRFProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "WinCount": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ForkSignaling": { + "title": "number", + "type": "number" + }, + "Height": { + "title": "number", + "type": "number" + }, + "Messages": { + "title": "Content Identifier", + "type": "string" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "ParentBaseFee": { + "additionalProperties": false, + "type": "object" + }, + "ParentMessageReceipts": { + "title": "Content Identifier", + "type": "string" + }, + "ParentStateRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ParentWeight": { + "additionalProperties": false, + "type": "object" + }, + "Parents": { + "items": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + }, + "type": "array" + }, + "Ticket": { + "additionalProperties": false, + "properties": { + "VRFProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "Timestamp": { + "title": "number", + "type": "number" + }, + "WinPoStProof": { + "items": { + "additionalProperties": false, + "properties": { + "PoStProof": { + "title": "number", + "type": "number" + }, + "ProofBytes": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1710" + } + }, + { + "name": "Filecoin.ChainGetBlockMessages", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetBlockMessages(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) {\n\tif s.Internal.ChainGetBlockMessages == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetBlockMessages(p0, p1)\n}\n```", + "summary": "ChainGetBlockMessages returns messages stored in the specified block.\n\nNote: If there are multiple blocks in a tipset, it's likely that some\nmessages will be duplicated. It's also possible for blocks in a tipset to have\ndifferent messages from the same sender at the same nonce. When that happens,\nonly the first message (in a block with lowest ticket) will be considered\nfor execution\n\nNOTE: THIS METHOD SHOULD ONLY BE USED FOR GETTING MESSAGES IN A SPECIFIC BLOCK\n\nDO NOT USE THIS METHOD TO GET MESSAGES INCLUDED IN A TIPSET\nUse ChainGetParentMessages, which will perform correct message deduplication\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*BlockMessages", + "description": "*BlockMessages", + "summary": "", + "schema": { + "examples": [ + { + "BlsMessages": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "SecpkMessages": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "Cids": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + } + ], + "additionalProperties": false, + "properties": { + "BlsMessages": { + "items": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "Cids": { + "items": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + }, + "type": "array" + }, + "SecpkMessages": { + "items": { + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1721" + } + }, + { + "name": "Filecoin.ChainGetEvents", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetEvents(p0 context.Context, p1 cid.Cid) ([]types.Event, error) {\n\tif s.Internal.ChainGetEvents == nil {\n\t\treturn *new([]types.Event), ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetEvents(p0, p1)\n}\n```", + "summary": "ChainGetEvents returns the events under an event AMT root CID.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]types.Event", + "description": "[]types.Event", + "summary": "", + "schema": { + "examples": [ + [ + { + "Emitter": 1000, + "Entries": [ + { + "Flags": 7, + "Key": "string value", + "Codec": 42, + "Value": "Ynl0ZSBhcnJheQ==" + } + ] + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Emitter": { + "title": "number", + "type": "number" + }, + "Entries": { + "items": { + "additionalProperties": false, + "properties": { + "Codec": { + "title": "number", + "type": "number" + }, + "Flags": { + "title": "number", + "type": "number" + }, + "Key": { + "type": "string" + }, + "Value": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1732" + } + }, + { + "name": "Filecoin.ChainGetGenesis", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetGenesis(p0 context.Context) (*types.TipSet, error) {\n\tif s.Internal.ChainGetGenesis == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetGenesis(p0)\n}\n```", + "summary": "ChainGetGenesis returns the genesis tipset.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1743" + } + }, + { + "name": "Filecoin.ChainGetMessage", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetMessage(p0 context.Context, p1 cid.Cid) (*types.Message, error) {\n\tif s.Internal.ChainGetMessage == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetMessage(p0, p1)\n}\n```", + "summary": "ChainGetMessage reads a message referenced by the specified CID from the\nchain blockstore.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.Message", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1754" + } + }, + { + "name": "Filecoin.ChainGetMessagesInTipset", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetMessagesInTipset(p0 context.Context, p1 types.TipSetKey) ([]Message, error) {\n\tif s.Internal.ChainGetMessagesInTipset == nil {\n\t\treturn *new([]Message), ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetMessagesInTipset(p0, p1)\n}\n```", + "summary": "ChainGetMessagesInTipset returns message stores in current tipset\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]Message", + "description": "[]Message", + "summary": "", + "schema": { + "examples": [ + [ + { + "Cid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Cid": { + "title": "Content Identifier", + "type": "string" + }, + "Message": { + "additionalProperties": false, + "properties": { + "Cid": { + "title": "Content Identifier", + "type": "string" + }, + "Message": {} + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1765" + } + }, + { + "name": "Filecoin.ChainGetNode", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetNode(p0 context.Context, p1 string) (*IpldObject, error) {\n\tif s.Internal.ChainGetNode == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetNode(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*IpldObject", + "description": "*IpldObject", + "summary": "", + "schema": { + "examples": [ + { + "Cid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Obj": {} + } + ], + "additionalProperties": false, + "properties": { + "Cid": { + "title": "Content Identifier", + "type": "string" + }, + "Obj": { + "additionalProperties": true, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1776" + } + }, + { + "name": "Filecoin.ChainGetParentMessages", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetParentMessages(p0 context.Context, p1 cid.Cid) ([]Message, error) {\n\tif s.Internal.ChainGetParentMessages == nil {\n\t\treturn *new([]Message), ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetParentMessages(p0, p1)\n}\n```", + "summary": "ChainGetParentMessages returns messages stored in parent tipset of the\nspecified block.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]Message", + "description": "[]Message", + "summary": "", + "schema": { + "examples": [ + [ + { + "Cid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Cid": { + "title": "Content Identifier", + "type": "string" + }, + "Message": { + "additionalProperties": false, + "properties": { + "Cid": { + "title": "Content Identifier", + "type": "string" + }, + "Message": {} + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1787" + } + }, + { + "name": "Filecoin.ChainGetParentReceipts", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetParentReceipts(p0 context.Context, p1 cid.Cid) ([]*types.MessageReceipt, error) {\n\tif s.Internal.ChainGetParentReceipts == nil {\n\t\treturn *new([]*types.MessageReceipt), ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetParentReceipts(p0, p1)\n}\n```", + "summary": "ChainGetParentReceipts returns receipts for messages in parent tipset of\nthe specified block. The receipts in the list returned is one-to-one with the\nmessages returned by a call to ChainGetParentMessages with the same blockCid.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*types.MessageReceipt", + "description": "[]*types.MessageReceipt", + "summary": "", + "schema": { + "examples": [ + [ + { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1798" + } + }, + { + "name": "Filecoin.ChainGetPath", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetPath(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey) ([]*HeadChange, error) {\n\tif s.Internal.ChainGetPath == nil {\n\t\treturn *new([]*HeadChange), ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetPath(p0, p1, p2)\n}\n```", + "summary": "ChainGetPath returns a set of revert/apply operations needed to get from\none tipset to another, for example:\n```\n to\n ^\nfrom tAA\n ^ ^\ntBA tAB\n ^---*--^\n ^\n tRR\n```\nWould return `[revert(tBA), apply(tAB), apply(tAA)]`\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*HeadChange", + "description": "[]*HeadChange", + "summary": "", + "schema": { + "examples": [ + [ + { + "Type": "string value", + "Val": { + "Cids": null, + "Blocks": null, + "Height": 0 + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Type": { + "type": "string" + }, + "Val": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1809" + } + }, + { + "name": "Filecoin.ChainGetTipSet", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetTipSet(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) {\n\tif s.Internal.ChainGetTipSet == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetTipSet(p0, p1)\n}\n```", + "summary": "ChainGetTipSet returns the tipset specified by the given TipSetKey.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1820" + } + }, + { + "name": "Filecoin.ChainGetTipSetAfterHeight", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetTipSetAfterHeight(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) {\n\tif s.Internal.ChainGetTipSetAfterHeight == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetTipSetAfterHeight(p0, p1, p2)\n}\n```", + "summary": "ChainGetTipSetAfterHeight looks back for a tipset at the specified epoch.\nIf there are no blocks at the specified epoch, the first non-nil tipset at a later epoch\nwill be returned.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1831" + } + }, + { + "name": "Filecoin.ChainGetTipSetByHeight", + "description": "```go\nfunc (s *FullNodeStruct) ChainGetTipSetByHeight(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) {\n\tif s.Internal.ChainGetTipSetByHeight == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetTipSetByHeight(p0, p1, p2)\n}\n```", + "summary": "ChainGetTipSetByHeight looks back for a tipset at the specified epoch.\nIf there are no blocks at the specified epoch, a tipset at an earlier epoch\nwill be returned.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1842" + } + }, + { + "name": "Filecoin.ChainHasObj", + "description": "```go\nfunc (s *FullNodeStruct) ChainHasObj(p0 context.Context, p1 cid.Cid) (bool, error) {\n\tif s.Internal.ChainHasObj == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.ChainHasObj(p0, p1)\n}\n```", + "summary": "ChainHasObj checks if a given CID exists in the chain blockstore.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1853" + } + }, + { + "name": "Filecoin.ChainHead", + "description": "```go\nfunc (s *FullNodeStruct) ChainHead(p0 context.Context) (*types.TipSet, error) {\n\tif s.Internal.ChainHead == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainHead(p0)\n}\n```", + "summary": "ChainHead returns the current head of the chain.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1864" + } + }, + { + "name": "Filecoin.ChainHotGC", + "description": "```go\nfunc (s *FullNodeStruct) ChainHotGC(p0 context.Context, p1 HotGCOpts) error {\n\tif s.Internal.ChainHotGC == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ChainHotGC(p0, p1)\n}\n```", + "summary": "ChainHotGC does online (badger) GC on the hot store; only supported if you are using\nthe splitstore\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "HotGCOpts", + "summary": "", + "schema": { + "examples": [ + { + "Threshold": 12.3, + "Periodic": true, + "Moving": true + } + ], + "additionalProperties": false, + "properties": { + "Moving": { + "type": "boolean" + }, + "Periodic": { + "type": "boolean" + }, + "Threshold": { + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1875" + } + }, + { + "name": "Filecoin.ChainPrune", + "description": "```go\nfunc (s *FullNodeStruct) ChainPrune(p0 context.Context, p1 PruneOpts) error {\n\tif s.Internal.ChainPrune == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ChainPrune(p0, p1)\n}\n```", + "summary": "ChainPrune forces compaction on cold store and garbage collects; only supported if you\nare using the splitstore\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "PruneOpts", + "summary": "", + "schema": { + "examples": [ + { + "MovingGC": true, + "RetainState": 9 + } + ], + "additionalProperties": false, + "properties": { + "MovingGC": { + "type": "boolean" + }, + "RetainState": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1897" + } + }, + { + "name": "Filecoin.ChainPutObj", + "description": "```go\nfunc (s *FullNodeStruct) ChainPutObj(p0 context.Context, p1 blocks.Block) error {\n\tif s.Internal.ChainPutObj == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ChainPutObj(p0, p1)\n}\n```", + "summary": "ChainPutObj puts a given object into the block store\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "blocks.Block", + "summary": "", + "schema": { + "examples": [ + {} + ], + "additionalProperties": true + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1908" + } + }, + { + "name": "Filecoin.ChainReadObj", + "description": "```go\nfunc (s *FullNodeStruct) ChainReadObj(p0 context.Context, p1 cid.Cid) ([]byte, error) {\n\tif s.Internal.ChainReadObj == nil {\n\t\treturn *new([]byte), ErrNotSupported\n\t}\n\treturn s.Internal.ChainReadObj(p0, p1)\n}\n```", + "summary": "ChainReadObj reads ipld nodes referenced by the specified CID from chain\nblockstore and returns raw bytes.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]byte", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1919" + } + }, + { + "name": "Filecoin.ChainSetHead", + "description": "```go\nfunc (s *FullNodeStruct) ChainSetHead(p0 context.Context, p1 types.TipSetKey) error {\n\tif s.Internal.ChainSetHead == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ChainSetHead(p0, p1)\n}\n```", + "summary": "ChainSetHead forcefully sets current chain head. Use with caution.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1930" + } + }, + { + "name": "Filecoin.ChainStatObj", + "description": "```go\nfunc (s *FullNodeStruct) ChainStatObj(p0 context.Context, p1 cid.Cid, p2 cid.Cid) (ObjStat, error) {\n\tif s.Internal.ChainStatObj == nil {\n\t\treturn *new(ObjStat), ErrNotSupported\n\t}\n\treturn s.Internal.ChainStatObj(p0, p1, p2)\n}\n```", + "summary": "ChainStatObj returns statistics about the graph referenced by 'obj'.\nIf 'base' is also specified, then the returned stat will be a diff\nbetween the two objects.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ObjStat", + "description": "ObjStat", + "summary": "", + "schema": { + "examples": [ + { + "Size": 42, + "Links": 42 + } + ], + "additionalProperties": false, + "properties": { + "Links": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1941" + } + }, + { + "name": "Filecoin.ChainTipSetWeight", + "description": "```go\nfunc (s *FullNodeStruct) ChainTipSetWeight(p0 context.Context, p1 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.ChainTipSetWeight == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.ChainTipSetWeight(p0, p1)\n}\n```", + "summary": "ChainTipSetWeight computes weight for the specified tipset.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1952" + } + }, + { + "name": "Filecoin.ClientCalcCommP", + "description": "```go\nfunc (s *FullNodeStruct) ClientCalcCommP(p0 context.Context, p1 string) (*CommPRet, error) {\n\tif s.Internal.ClientCalcCommP == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ClientCalcCommP(p0, p1)\n}\n```", + "summary": "ClientCalcCommP calculates the CommP for a specified file\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*CommPRet", + "description": "*CommPRet", + "summary": "", + "schema": { + "examples": [ + { + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 1024 + } + ], + "additionalProperties": false, + "properties": { + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1963" + } + }, + { + "name": "Filecoin.ClientCancelDataTransfer", + "description": "```go\nfunc (s *FullNodeStruct) ClientCancelDataTransfer(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error {\n\tif s.Internal.ClientCancelDataTransfer == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ClientCancelDataTransfer(p0, p1, p2, p3)\n}\n```", + "summary": "ClientCancelDataTransfer cancels a data transfer with the given transfer ID and other peer\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "datatransfer.TransferID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 3 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "peer.ID", + "summary": "", + "schema": { + "examples": [ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1974" + } + }, + { + "name": "Filecoin.ClientCancelRetrievalDeal", + "description": "```go\nfunc (s *FullNodeStruct) ClientCancelRetrievalDeal(p0 context.Context, p1 retrievalmarket.DealID) error {\n\tif s.Internal.ClientCancelRetrievalDeal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ClientCancelRetrievalDeal(p0, p1)\n}\n```", + "summary": "ClientCancelRetrievalDeal cancels an ongoing retrieval deal based on DealID\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "retrievalmarket.DealID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 5 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L1985" + } + }, + { + "name": "Filecoin.ClientDealPieceCID", + "description": "```go\nfunc (s *FullNodeStruct) ClientDealPieceCID(p0 context.Context, p1 cid.Cid) (DataCIDSize, error) {\n\tif s.Internal.ClientDealPieceCID == nil {\n\t\treturn *new(DataCIDSize), ErrNotSupported\n\t}\n\treturn s.Internal.ClientDealPieceCID(p0, p1)\n}\n```", + "summary": "ClientCalcCommP calculates the CommP and data size of the specified CID\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "DataCIDSize", + "description": "DataCIDSize", + "summary": "", + "schema": { + "examples": [ + { + "PayloadSize": 9, + "PieceSize": 1032, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "PayloadSize": { + "title": "number", + "type": "number" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2007" + } + }, + { + "name": "Filecoin.ClientDealSize", + "description": "```go\nfunc (s *FullNodeStruct) ClientDealSize(p0 context.Context, p1 cid.Cid) (DataSize, error) {\n\tif s.Internal.ClientDealSize == nil {\n\t\treturn *new(DataSize), ErrNotSupported\n\t}\n\treturn s.Internal.ClientDealSize(p0, p1)\n}\n```", + "summary": "ClientDealSize calculates real deal data size\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "DataSize", + "description": "DataSize", + "summary": "", + "schema": { + "examples": [ + { + "PayloadSize": 9, + "PieceSize": 1032 + } + ], + "additionalProperties": false, + "properties": { + "PayloadSize": { + "title": "number", + "type": "number" + }, + "PieceSize": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2018" + } + }, + { + "name": "Filecoin.ClientExport", + "description": "```go\nfunc (s *FullNodeStruct) ClientExport(p0 context.Context, p1 ExportRef, p2 FileRef) error {\n\tif s.Internal.ClientExport == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ClientExport(p0, p1, p2)\n}\n```", + "summary": "ClientExport exports a file stored in the local filestore to a system file\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ExportRef", + "summary": "", + "schema": { + "examples": [ + { + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DAGs": [ + { + "DataSelector": "Links/21/Hash/Links/42/Hash", + "ExportMerkleProof": true + } + ], + "FromLocalCAR": "string value", + "DealID": 5 + } + ], + "additionalProperties": false, + "properties": { + "DAGs": { + "items": { + "additionalProperties": false, + "properties": { + "DataSelector": { + "type": "string" + }, + "ExportMerkleProof": { + "type": "boolean" + } + }, + "type": "object" + }, + "type": "array" + }, + "DealID": { + "title": "number", + "type": "number" + }, + "FromLocalCAR": { + "type": "string" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "FileRef", + "summary": "", + "schema": { + "examples": [ + { + "Path": "string value", + "IsCAR": true + } + ], + "additionalProperties": false, + "properties": { + "IsCAR": { + "type": "boolean" + }, + "Path": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2029" + } + }, + { + "name": "Filecoin.ClientFindData", + "description": "```go\nfunc (s *FullNodeStruct) ClientFindData(p0 context.Context, p1 cid.Cid, p2 *cid.Cid) ([]QueryOffer, error) {\n\tif s.Internal.ClientFindData == nil {\n\t\treturn *new([]QueryOffer), ErrNotSupported\n\t}\n\treturn s.Internal.ClientFindData(p0, p1, p2)\n}\n```", + "summary": "ClientFindData identifies peers that have a certain file, and returns QueryOffers (one per peer).\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]QueryOffer", + "description": "[]QueryOffer", + "summary": "", + "schema": { + "examples": [ + [ + { + "Err": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Piece": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 42, + "MinPrice": "0", + "UnsealPrice": "0", + "PricePerByte": "0", + "PaymentInterval": 42, + "PaymentIntervalIncrease": 42, + "Miner": "f01234", + "MinerPeer": { + "Address": "f01234", + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Err": { + "type": "string" + }, + "MinPrice": { + "additionalProperties": false, + "type": "object" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "MinerPeer": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "ID": { + "type": "string" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": "object" + }, + "PaymentInterval": { + "title": "number", + "type": "number" + }, + "PaymentIntervalIncrease": { + "title": "number", + "type": "number" + }, + "Piece": { + "title": "Content Identifier", + "type": "string" + }, + "PricePerByte": { + "additionalProperties": false, + "type": "object" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + }, + "UnsealPrice": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2040" + } + }, + { + "name": "Filecoin.ClientGenCar", + "description": "```go\nfunc (s *FullNodeStruct) ClientGenCar(p0 context.Context, p1 FileRef, p2 string) error {\n\tif s.Internal.ClientGenCar == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ClientGenCar(p0, p1, p2)\n}\n```", + "summary": "ClientGenCar generates a CAR file for the specified file.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "FileRef", + "summary": "", + "schema": { + "examples": [ + { + "Path": "string value", + "IsCAR": true + } + ], + "additionalProperties": false, + "properties": { + "IsCAR": { + "type": "boolean" + }, + "Path": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2051" + } + }, + { + "name": "Filecoin.ClientGetDealInfo", + "description": "```go\nfunc (s *FullNodeStruct) ClientGetDealInfo(p0 context.Context, p1 cid.Cid) (*DealInfo, error) {\n\tif s.Internal.ClientGetDealInfo == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ClientGetDealInfo(p0, p1)\n}\n```", + "summary": "ClientGetDealInfo returns the latest information about a given deal.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*DealInfo", + "description": "*DealInfo", + "summary": "", + "schema": { + "examples": [ + { + "ProposalCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "State": 42, + "Message": "string value", + "DealStages": { + "Stages": [ + { + "Name": "string value", + "Description": "string value", + "ExpectedDuration": "string value", + "CreatedTime": "0001-01-01T00:00:00Z", + "UpdatedTime": "0001-01-01T00:00:00Z", + "Logs": [ + { + "Log": "string value", + "UpdatedTime": "0001-01-01T00:00:00Z" + } + ] + } + ] + }, + "Provider": "f01234", + "DataRef": { + "TransferType": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1024, + "RawBlockSize": 42 + }, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 42, + "PricePerEpoch": "0", + "Duration": 42, + "DealID": 5432, + "CreationTime": "0001-01-01T00:00:00Z", + "Verified": true, + "TransferChannelID": { + "Initiator": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Responder": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "ID": 3 + }, + "DataTransfer": { + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42, + "Stages": { + "Stages": [ + { + "Name": "string value", + "Description": "string value", + "CreatedTime": "0001-01-01T00:00:00Z", + "UpdatedTime": "0001-01-01T00:00:00Z", + "Logs": [ + { + "Log": "string value", + "UpdatedTime": "0001-01-01T00:00:00Z" + } + ] + } + ] + } + } + } + ], + "additionalProperties": false, + "properties": { + "CreationTime": { + "format": "date-time", + "type": "string" + }, + "DataRef": { + "additionalProperties": false, + "properties": { + "PieceCid": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "RawBlockSize": { + "title": "number", + "type": "number" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "TransferType": { + "type": "string" + } + }, + "type": "object" + }, + "DataTransfer": { + "additionalProperties": false, + "properties": { + "BaseCID": { + "title": "Content Identifier", + "type": "string" + }, + "IsInitiator": { + "type": "boolean" + }, + "IsSender": { + "type": "boolean" + }, + "Message": { + "type": "string" + }, + "OtherPeer": { + "type": "string" + }, + "Stages": { + "additionalProperties": false, + "properties": { + "Stages": { + "items": { + "additionalProperties": false, + "properties": { + "CreatedTime": { + "additionalProperties": false, + "type": "object" + }, + "Description": { + "type": "string" + }, + "Logs": { + "items": { + "additionalProperties": false, + "properties": { + "Log": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Name": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "Status": { + "title": "number", + "type": "number" + }, + "TransferID": { + "title": "number", + "type": "number" + }, + "Transferred": { + "title": "number", + "type": "number" + }, + "Voucher": { + "type": "string" + } + }, + "type": "object" + }, + "DealID": { + "title": "number", + "type": "number" + }, + "DealStages": { + "additionalProperties": false, + "properties": { + "Stages": { + "items": { + "additionalProperties": false, + "properties": { + "CreatedTime": { + "additionalProperties": false, + "type": "object" + }, + "Description": { + "type": "string" + }, + "ExpectedDuration": { + "type": "string" + }, + "Logs": { + "items": { + "additionalProperties": false, + "properties": { + "Log": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Name": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "Duration": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "ProposalCid": { + "title": "Content Identifier", + "type": "string" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "Size": { + "title": "number", + "type": "number" + }, + "State": { + "title": "number", + "type": "number" + }, + "TransferChannelID": { + "additionalProperties": false, + "properties": { + "ID": { + "title": "number", + "type": "number" + }, + "Initiator": { + "type": "string" + }, + "Responder": { + "type": "string" + } + }, + "type": "object" + }, + "Verified": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2062" + } + }, + { + "name": "Filecoin.ClientGetDealStatus", + "description": "```go\nfunc (s *FullNodeStruct) ClientGetDealStatus(p0 context.Context, p1 uint64) (string, error) {\n\tif s.Internal.ClientGetDealStatus == nil {\n\t\treturn \"\", ErrNotSupported\n\t}\n\treturn s.Internal.ClientGetDealStatus(p0, p1)\n}\n```", + "summary": "ClientGetDealStatus returns status given a code\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "string", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2073" + } + }, + { + "name": "Filecoin.ClientHasLocal", + "description": "```go\nfunc (s *FullNodeStruct) ClientHasLocal(p0 context.Context, p1 cid.Cid) (bool, error) {\n\tif s.Internal.ClientHasLocal == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.ClientHasLocal(p0, p1)\n}\n```", + "summary": "ClientHasLocal indicates whether a certain CID is locally stored.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2106" + } + }, + { + "name": "Filecoin.ClientImport", + "description": "```go\nfunc (s *FullNodeStruct) ClientImport(p0 context.Context, p1 FileRef) (*ImportRes, error) {\n\tif s.Internal.ClientImport == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ClientImport(p0, p1)\n}\n```", + "summary": "ClientImport imports file under the specified path into filestore.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "FileRef", + "summary": "", + "schema": { + "examples": [ + { + "Path": "string value", + "IsCAR": true + } + ], + "additionalProperties": false, + "properties": { + "IsCAR": { + "type": "boolean" + }, + "Path": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ImportRes", + "description": "*ImportRes", + "summary": "", + "schema": { + "examples": [ + { + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ImportID": 50 + } + ], + "additionalProperties": false, + "properties": { + "ImportID": { + "title": "number", + "type": "number" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2117" + } + }, + { + "name": "Filecoin.ClientListDataTransfers", + "description": "```go\nfunc (s *FullNodeStruct) ClientListDataTransfers(p0 context.Context) ([]DataTransferChannel, error) {\n\tif s.Internal.ClientListDataTransfers == nil {\n\t\treturn *new([]DataTransferChannel), ErrNotSupported\n\t}\n\treturn s.Internal.ClientListDataTransfers(p0)\n}\n```", + "summary": "ClientListTransfers returns the status of all ongoing transfers of data\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]DataTransferChannel", + "description": "[]DataTransferChannel", + "summary": "", + "schema": { + "examples": [ + [ + { + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42, + "Stages": { + "Stages": [ + { + "Name": "string value", + "Description": "string value", + "CreatedTime": "0001-01-01T00:00:00Z", + "UpdatedTime": "0001-01-01T00:00:00Z", + "Logs": [ + { + "Log": "string value", + "UpdatedTime": "0001-01-01T00:00:00Z" + } + ] + } + ] + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "BaseCID": { + "title": "Content Identifier", + "type": "string" + }, + "IsInitiator": { + "type": "boolean" + }, + "IsSender": { + "type": "boolean" + }, + "Message": { + "type": "string" + }, + "OtherPeer": { + "type": "string" + }, + "Stages": { + "additionalProperties": false, + "properties": { + "Stages": { + "items": { + "additionalProperties": false, + "properties": { + "CreatedTime": { + "additionalProperties": false, + "type": "object" + }, + "Description": { + "type": "string" + }, + "Logs": { + "items": { + "additionalProperties": false, + "properties": { + "Log": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Name": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "Status": { + "title": "number", + "type": "number" + }, + "TransferID": { + "title": "number", + "type": "number" + }, + "Transferred": { + "title": "number", + "type": "number" + }, + "Voucher": { + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2128" + } + }, + { + "name": "Filecoin.ClientListDeals", + "description": "```go\nfunc (s *FullNodeStruct) ClientListDeals(p0 context.Context) ([]DealInfo, error) {\n\tif s.Internal.ClientListDeals == nil {\n\t\treturn *new([]DealInfo), ErrNotSupported\n\t}\n\treturn s.Internal.ClientListDeals(p0)\n}\n```", + "summary": "ClientListDeals returns information about the deals made by the local client.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]DealInfo", + "description": "[]DealInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "ProposalCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "State": 42, + "Message": "string value", + "DealStages": { + "Stages": [ + { + "Name": "string value", + "Description": "string value", + "ExpectedDuration": "string value", + "CreatedTime": "0001-01-01T00:00:00Z", + "UpdatedTime": "0001-01-01T00:00:00Z", + "Logs": [ + { + "Log": "string value", + "UpdatedTime": "0001-01-01T00:00:00Z" + } + ] + } + ] + }, + "Provider": "f01234", + "DataRef": { + "TransferType": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1024, + "RawBlockSize": 42 + }, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 42, + "PricePerEpoch": "0", + "Duration": 42, + "DealID": 5432, + "CreationTime": "0001-01-01T00:00:00Z", + "Verified": true, + "TransferChannelID": { + "Initiator": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Responder": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "ID": 3 + }, + "DataTransfer": { + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42, + "Stages": { + "Stages": [ + { + "Name": "string value", + "Description": "string value", + "CreatedTime": "0001-01-01T00:00:00Z", + "UpdatedTime": "0001-01-01T00:00:00Z", + "Logs": [ + { + "Log": "string value", + "UpdatedTime": "0001-01-01T00:00:00Z" + } + ] + } + ] + } + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "CreationTime": { + "format": "date-time", + "type": "string" + }, + "DataRef": { + "additionalProperties": false, + "properties": { + "PieceCid": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "RawBlockSize": { + "title": "number", + "type": "number" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "TransferType": { + "type": "string" + } + }, + "type": "object" + }, + "DataTransfer": { + "additionalProperties": false, + "properties": { + "BaseCID": { + "title": "Content Identifier", + "type": "string" + }, + "IsInitiator": { + "type": "boolean" + }, + "IsSender": { + "type": "boolean" + }, + "Message": { + "type": "string" + }, + "OtherPeer": { + "type": "string" + }, + "Stages": { + "additionalProperties": false, + "properties": { + "Stages": { + "items": { + "additionalProperties": false, + "properties": { + "CreatedTime": { + "additionalProperties": false, + "type": "object" + }, + "Description": { + "type": "string" + }, + "Logs": { + "items": { + "additionalProperties": false, + "properties": { + "Log": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Name": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "Status": { + "title": "number", + "type": "number" + }, + "TransferID": { + "title": "number", + "type": "number" + }, + "Transferred": { + "title": "number", + "type": "number" + }, + "Voucher": { + "type": "string" + } + }, + "type": "object" + }, + "DealID": { + "title": "number", + "type": "number" + }, + "DealStages": { + "additionalProperties": false, + "properties": { + "Stages": { + "items": { + "additionalProperties": false, + "properties": { + "CreatedTime": { + "additionalProperties": false, + "type": "object" + }, + "Description": { + "type": "string" + }, + "ExpectedDuration": { + "type": "string" + }, + "Logs": { + "items": { + "additionalProperties": false, + "properties": { + "Log": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Name": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "Duration": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "ProposalCid": { + "title": "Content Identifier", + "type": "string" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "Size": { + "title": "number", + "type": "number" + }, + "State": { + "title": "number", + "type": "number" + }, + "TransferChannelID": { + "additionalProperties": false, + "properties": { + "ID": { + "title": "number", + "type": "number" + }, + "Initiator": { + "type": "string" + }, + "Responder": { + "type": "string" + } + }, + "type": "object" + }, + "Verified": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2139" + } + }, + { + "name": "Filecoin.ClientListImports", + "description": "```go\nfunc (s *FullNodeStruct) ClientListImports(p0 context.Context) ([]Import, error) {\n\tif s.Internal.ClientListImports == nil {\n\t\treturn *new([]Import), ErrNotSupported\n\t}\n\treturn s.Internal.ClientListImports(p0)\n}\n```", + "summary": "ClientListImports lists imported files and their root CIDs\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]Import", + "description": "[]Import", + "summary": "", + "schema": { + "examples": [ + [ + { + "Key": 50, + "Err": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Source": "string value", + "FilePath": "string value", + "CARPath": "string value" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "CARPath": { + "type": "string" + }, + "Err": { + "type": "string" + }, + "FilePath": { + "type": "string" + }, + "Key": { + "title": "number", + "type": "number" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "Source": { + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2150" + } + }, + { + "name": "Filecoin.ClientListRetrievals", + "description": "```go\nfunc (s *FullNodeStruct) ClientListRetrievals(p0 context.Context) ([]RetrievalInfo, error) {\n\tif s.Internal.ClientListRetrievals == nil {\n\t\treturn *new([]RetrievalInfo), ErrNotSupported\n\t}\n\treturn s.Internal.ClientListRetrievals(p0)\n}\n```", + "summary": "ClientListRetrievals returns information about retrievals made by the local client\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]RetrievalInfo", + "description": "[]RetrievalInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "PayloadCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ID": 5, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PricePerByte": "0", + "UnsealPrice": "0", + "Status": 0, + "Message": "string value", + "Provider": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "BytesReceived": 42, + "BytesPaidFor": 42, + "TotalPaid": "0", + "TransferChannelID": { + "Initiator": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Responder": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "ID": 3 + }, + "DataTransfer": { + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42, + "Stages": { + "Stages": [ + { + "Name": "string value", + "Description": "string value", + "CreatedTime": "0001-01-01T00:00:00Z", + "UpdatedTime": "0001-01-01T00:00:00Z", + "Logs": [ + { + "Log": "string value", + "UpdatedTime": "0001-01-01T00:00:00Z" + } + ] + } + ] + } + }, + "Event": 5 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "BytesPaidFor": { + "title": "number", + "type": "number" + }, + "BytesReceived": { + "title": "number", + "type": "number" + }, + "DataTransfer": { + "additionalProperties": false, + "properties": { + "BaseCID": { + "title": "Content Identifier", + "type": "string" + }, + "IsInitiator": { + "type": "boolean" + }, + "IsSender": { + "type": "boolean" + }, + "Message": { + "type": "string" + }, + "OtherPeer": { + "type": "string" + }, + "Stages": { + "additionalProperties": false, + "properties": { + "Stages": { + "items": { + "additionalProperties": false, + "properties": { + "CreatedTime": { + "additionalProperties": false, + "type": "object" + }, + "Description": { + "type": "string" + }, + "Logs": { + "items": { + "additionalProperties": false, + "properties": { + "Log": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Name": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "Status": { + "title": "number", + "type": "number" + }, + "TransferID": { + "title": "number", + "type": "number" + }, + "Transferred": { + "title": "number", + "type": "number" + }, + "Voucher": { + "type": "string" + } + }, + "type": "object" + }, + "Event": { + "title": "number", + "type": "number" + }, + "ID": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + }, + "PayloadCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PricePerByte": { + "additionalProperties": false, + "type": "object" + }, + "Provider": { + "type": "string" + }, + "Status": { + "title": "number", + "type": "number" + }, + "TotalPaid": { + "additionalProperties": false, + "type": "object" + }, + "TransferChannelID": { + "additionalProperties": false, + "properties": { + "ID": { + "title": "number", + "type": "number" + }, + "Initiator": { + "type": "string" + }, + "Responder": { + "type": "string" + } + }, + "type": "object" + }, + "UnsealPrice": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2161" + } + }, + { + "name": "Filecoin.ClientMinerQueryOffer", + "description": "```go\nfunc (s *FullNodeStruct) ClientMinerQueryOffer(p0 context.Context, p1 address.Address, p2 cid.Cid, p3 *cid.Cid) (QueryOffer, error) {\n\tif s.Internal.ClientMinerQueryOffer == nil {\n\t\treturn *new(QueryOffer), ErrNotSupported\n\t}\n\treturn s.Internal.ClientMinerQueryOffer(p0, p1, p2, p3)\n}\n```", + "summary": "ClientMinerQueryOffer returns a QueryOffer for the specific miner and file.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "QueryOffer", + "description": "QueryOffer", + "summary": "", + "schema": { + "examples": [ + { + "Err": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Piece": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 42, + "MinPrice": "0", + "UnsealPrice": "0", + "PricePerByte": "0", + "PaymentInterval": 42, + "PaymentIntervalIncrease": 42, + "Miner": "f01234", + "MinerPeer": { + "Address": "f01234", + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + } + ], + "additionalProperties": false, + "properties": { + "Err": { + "type": "string" + }, + "MinPrice": { + "additionalProperties": false, + "type": "object" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "MinerPeer": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "ID": { + "type": "string" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": "object" + }, + "PaymentInterval": { + "title": "number", + "type": "number" + }, + "PaymentIntervalIncrease": { + "title": "number", + "type": "number" + }, + "Piece": { + "title": "Content Identifier", + "type": "string" + }, + "PricePerByte": { + "additionalProperties": false, + "type": "object" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + }, + "UnsealPrice": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2172" + } + }, + { + "name": "Filecoin.ClientQueryAsk", + "description": "```go\nfunc (s *FullNodeStruct) ClientQueryAsk(p0 context.Context, p1 peer.ID, p2 address.Address) (*StorageAsk, error) {\n\tif s.Internal.ClientQueryAsk == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ClientQueryAsk(p0, p1, p2)\n}\n```", + "summary": "ClientQueryAsk returns a signed StorageAsk from the specified miner.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "peer.ID", + "summary": "", + "schema": { + "examples": [ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*StorageAsk", + "description": "*StorageAsk", + "summary": "", + "schema": { + "examples": [ + { + "Response": { + "Price": "0", + "VerifiedPrice": "0", + "MinPieceSize": 1032, + "MaxPieceSize": 1032, + "Miner": "f01234", + "Timestamp": 10101, + "Expiry": 10101, + "SeqNo": 42 + }, + "DealProtocols": [ + "string value" + ] + } + ], + "additionalProperties": false, + "properties": { + "DealProtocols": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Response": {} + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2183" + } + }, + { + "name": "Filecoin.ClientRemoveImport", + "description": "```go\nfunc (s *FullNodeStruct) ClientRemoveImport(p0 context.Context, p1 imports.ID) error {\n\tif s.Internal.ClientRemoveImport == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ClientRemoveImport(p0, p1)\n}\n```", + "summary": "ClientRemoveImport removes file import\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "imports.ID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 50 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2194" + } + }, + { + "name": "Filecoin.ClientRestartDataTransfer", + "description": "```go\nfunc (s *FullNodeStruct) ClientRestartDataTransfer(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error {\n\tif s.Internal.ClientRestartDataTransfer == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ClientRestartDataTransfer(p0, p1, p2, p3)\n}\n```", + "summary": "ClientRestartDataTransfer attempts to restart a data transfer with the given transfer ID and other peer\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "datatransfer.TransferID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 3 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "peer.ID", + "summary": "", + "schema": { + "examples": [ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2205" + } + }, + { + "name": "Filecoin.ClientRetrieve", + "description": "```go\nfunc (s *FullNodeStruct) ClientRetrieve(p0 context.Context, p1 RetrievalOrder) (*RestrievalRes, error) {\n\tif s.Internal.ClientRetrieve == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ClientRetrieve(p0, p1)\n}\n```", + "summary": "ClientRetrieve initiates the retrieval of a file, as specified in the order.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "RetrievalOrder", + "summary": "", + "schema": { + "examples": [ + { + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Piece": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DataSelector": "Links/21/Hash/Links/42/Hash", + "Size": 42, + "Total": "0", + "UnsealPrice": "0", + "PaymentInterval": 42, + "PaymentIntervalIncrease": 42, + "Client": "f01234", + "Miner": "f01234", + "MinerPeer": { + "Address": "f01234", + "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "RemoteStore": "00000000-0000-0000-0000-000000000000" + } + ], + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "DataSelector": { + "type": "string" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "MinerPeer": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "ID": { + "type": "string" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": "object" + }, + "PaymentInterval": { + "title": "number", + "type": "number" + }, + "PaymentIntervalIncrease": { + "title": "number", + "type": "number" + }, + "Piece": { + "title": "Content Identifier", + "type": "string" + }, + "RemoteStore": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + }, + "Total": { + "additionalProperties": false, + "type": "object" + }, + "UnsealPrice": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*RestrievalRes", + "description": "*RestrievalRes", + "summary": "", + "schema": { + "examples": [ + { + "DealID": 5 + } + ], + "additionalProperties": false, + "properties": { + "DealID": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2216" + } + }, + { + "name": "Filecoin.ClientRetrieveTryRestartInsufficientFunds", + "description": "```go\nfunc (s *FullNodeStruct) ClientRetrieveTryRestartInsufficientFunds(p0 context.Context, p1 address.Address) error {\n\tif s.Internal.ClientRetrieveTryRestartInsufficientFunds == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ClientRetrieveTryRestartInsufficientFunds(p0, p1)\n}\n```", + "summary": "ClientRetrieveTryRestartInsufficientFunds attempts to restart stalled retrievals on a given payment channel\nwhich are stuck due to insufficient funds\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2227" + } + }, + { + "name": "Filecoin.ClientRetrieveWait", + "description": "```go\nfunc (s *FullNodeStruct) ClientRetrieveWait(p0 context.Context, p1 retrievalmarket.DealID) error {\n\tif s.Internal.ClientRetrieveWait == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ClientRetrieveWait(p0, p1)\n}\n```", + "summary": "ClientRetrieveWait waits for retrieval to be complete\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "retrievalmarket.DealID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 5 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2238" + } + }, + { + "name": "Filecoin.ClientStartDeal", + "description": "```go\nfunc (s *FullNodeStruct) ClientStartDeal(p0 context.Context, p1 *StartDealParams) (*cid.Cid, error) {\n\tif s.Internal.ClientStartDeal == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ClientStartDeal(p0, p1)\n}\n```", + "summary": "ClientStartDeal proposes a deal with a miner.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*StartDealParams", + "summary": "", + "schema": { + "examples": [ + { + "Data": { + "TransferType": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1024, + "RawBlockSize": 42 + }, + "Wallet": "f01234", + "Miner": "f01234", + "EpochPrice": "0", + "MinBlocksDuration": 42, + "ProviderCollateral": "0", + "DealStartEpoch": 10101, + "FastRetrieval": true, + "VerifiedDeal": true + } + ], + "additionalProperties": false, + "properties": { + "Data": { + "additionalProperties": false, + "properties": { + "PieceCid": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "RawBlockSize": { + "title": "number", + "type": "number" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "TransferType": { + "type": "string" + } + }, + "type": "object" + }, + "DealStartEpoch": { + "title": "number", + "type": "number" + }, + "EpochPrice": { + "additionalProperties": false, + "type": "object" + }, + "FastRetrieval": { + "type": "boolean" + }, + "MinBlocksDuration": { + "title": "number", + "type": "number" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + }, + "Wallet": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*cid.Cid", + "description": "*cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2249" + } + }, + { + "name": "Filecoin.ClientStatelessDeal", + "description": "```go\nfunc (s *FullNodeStruct) ClientStatelessDeal(p0 context.Context, p1 *StartDealParams) (*cid.Cid, error) {\n\tif s.Internal.ClientStatelessDeal == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ClientStatelessDeal(p0, p1)\n}\n```", + "summary": "ClientStatelessDeal fire-and-forget-proposes an offline deal to a miner without subsequent tracking.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*StartDealParams", + "summary": "", + "schema": { + "examples": [ + { + "Data": { + "TransferType": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1024, + "RawBlockSize": 42 + }, + "Wallet": "f01234", + "Miner": "f01234", + "EpochPrice": "0", + "MinBlocksDuration": 42, + "ProviderCollateral": "0", + "DealStartEpoch": 10101, + "FastRetrieval": true, + "VerifiedDeal": true + } + ], + "additionalProperties": false, + "properties": { + "Data": { + "additionalProperties": false, + "properties": { + "PieceCid": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "RawBlockSize": { + "title": "number", + "type": "number" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "TransferType": { + "type": "string" + } + }, + "type": "object" + }, + "DealStartEpoch": { + "title": "number", + "type": "number" + }, + "EpochPrice": { + "additionalProperties": false, + "type": "object" + }, + "FastRetrieval": { + "type": "boolean" + }, + "MinBlocksDuration": { + "title": "number", + "type": "number" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + }, + "Wallet": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*cid.Cid", + "description": "*cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2260" + } + }, + { + "name": "Filecoin.CreateBackup", + "description": "```go\nfunc (s *FullNodeStruct) CreateBackup(p0 context.Context, p1 string) error {\n\tif s.Internal.CreateBackup == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.CreateBackup(p0, p1)\n}\n```", + "summary": "CreateBackup creates node backup onder the specified file name. The\nmethod requires that the lotus daemon is running with the\nLOTUS_BACKUP_BASE_PATH environment variable set to some path, and that\nthe path specified when calling CreateBackup is within the base path\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2271" + } + }, + { + "name": "Filecoin.EthAccounts", + "description": "```go\nfunc (s *FullNodeStruct) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, error) {\n\tif s.Internal.EthAccounts == nil {\n\t\treturn *new([]ethtypes.EthAddress), ErrNotSupported\n\t}\n\treturn s.Internal.EthAccounts(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]ethtypes.EthAddress", + "description": "[]ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ] + ], + "items": [ + { + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2282" + } + }, + { + "name": "Filecoin.EthAddressToFilecoinAddress", + "description": "```go\nfunc (s *FullNodeStruct) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) {\n\tif s.Internal.EthAddressToFilecoinAddress == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.EthAddressToFilecoinAddress(p0, p1)\n}\n```", + "summary": "EthAddressToFilecoinAddress converts an EthAddress into an f410 Filecoin Address\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2293" + } + }, + { + "name": "Filecoin.EthBlockNumber", + "description": "```go\nfunc (s *FullNodeStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthBlockNumber == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthBlockNumber(p0)\n}\n```", + "summary": "EthBlockNumber returns the height of the latest (heaviest) TipSet\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2304" + } + }, + { + "name": "Filecoin.EthCall", + "description": "```go\nfunc (s *FullNodeStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) {\n\tif s.Internal.EthCall == nil {\n\t\treturn *new(ethtypes.EthBytes), ErrNotSupported\n\t}\n\treturn s.Internal.EthCall(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthCall", + "summary": "", + "schema": { + "examples": [ + { + "from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "gas": "0x5", + "gasPrice": "0x0", + "value": "0x0", + "data": "0x07" + } + ], + "additionalProperties": false, + "properties": { + "data": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gas": { + "title": "number", + "type": "number" + }, + "gasPrice": { + "additionalProperties": false, + "type": "object" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthBlockNumberOrHash", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "requireCanonical": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBytes", + "description": "ethtypes.EthBytes", + "summary": "", + "schema": { + "examples": [ + "0x07" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2315" + } + }, + { + "name": "Filecoin.EthChainId", + "description": "```go\nfunc (s *FullNodeStruct) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthChainId == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthChainId(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2326" + } + }, + { + "name": "Filecoin.EthEstimateGas", + "description": "```go\nfunc (s *FullNodeStruct) EthEstimateGas(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthEstimateGas == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthEstimateGas(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "jsonrpc.RawParams", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2337" + } + }, + { + "name": "Filecoin.EthFeeHistory", + "description": "```go\nfunc (s *FullNodeStruct) EthFeeHistory(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) {\n\tif s.Internal.EthFeeHistory == nil {\n\t\treturn *new(ethtypes.EthFeeHistory), ErrNotSupported\n\t}\n\treturn s.Internal.EthFeeHistory(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "jsonrpc.RawParams", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthFeeHistory", + "description": "ethtypes.EthFeeHistory", + "summary": "", + "schema": { + "examples": [ + { + "oldestBlock": "0x5", + "baseFeePerGas": [ + "0x0" + ], + "gasUsedRatio": [ + 12.3 + ], + "reward": [] + } + ], + "additionalProperties": false, + "properties": { + "baseFeePerGas": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "gasUsedRatio": { + "items": { + "type": "number" + }, + "type": "array" + }, + "oldestBlock": { + "title": "number", + "type": "number" + }, + "reward": { + "items": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2348" + } + }, + { + "name": "Filecoin.EthGasPrice", + "description": "```go\nfunc (s *FullNodeStruct) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error) {\n\tif s.Internal.EthGasPrice == nil {\n\t\treturn *new(ethtypes.EthBigInt), ErrNotSupported\n\t}\n\treturn s.Internal.EthGasPrice(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthBigInt", + "description": "ethtypes.EthBigInt", + "summary": "", + "schema": { + "examples": [ + "0x0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2359" + } + }, + { + "name": "Filecoin.EthGetBalance", + "description": "```go\nfunc (s *FullNodeStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) {\n\tif s.Internal.EthGetBalance == nil {\n\t\treturn *new(ethtypes.EthBigInt), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetBalance(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthBlockNumberOrHash", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "requireCanonical": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBigInt", + "description": "ethtypes.EthBigInt", + "summary": "", + "schema": { + "examples": [ + "0x0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2370" + } + }, + { + "name": "Filecoin.EthGetBlockByHash", + "description": "```go\nfunc (s *FullNodeStruct) EthGetBlockByHash(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) {\n\tif s.Internal.EthGetBlockByHash == nil {\n\t\treturn *new(ethtypes.EthBlock), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetBlockByHash(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBlock", + "description": "ethtypes.EthBlock", + "summary": "", + "schema": { + "examples": [ + { + "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" + ] + } + ], + "additionalProperties": false, + "properties": { + "baseFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "difficulty": { + "title": "number", + "type": "number" + }, + "extraData": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "gasLimit": { + "title": "number", + "type": "number" + }, + "gasUsed": { + "title": "number", + "type": "number" + }, + "hash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "logsBloom": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "miner": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "mixHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "nonce": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 8, + "minItems": 8, + "type": "array" + }, + "number": { + "title": "number", + "type": "number" + }, + "parentHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "receiptsRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "sha3Uncles": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "size": { + "title": "number", + "type": "number" + }, + "stateRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "timestamp": { + "title": "number", + "type": "number" + }, + "totalDifficulty": { + "title": "number", + "type": "number" + }, + "transactions": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + }, + "transactionsRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "uncles": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2381" + } + }, + { + "name": "Filecoin.EthGetBlockByNumber", + "description": "```go\nfunc (s *FullNodeStruct) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) {\n\tif s.Internal.EthGetBlockByNumber == nil {\n\t\treturn *new(ethtypes.EthBlock), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetBlockByNumber(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBlock", + "description": "ethtypes.EthBlock", + "summary": "", + "schema": { + "examples": [ + { + "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" + ] + } + ], + "additionalProperties": false, + "properties": { + "baseFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "difficulty": { + "title": "number", + "type": "number" + }, + "extraData": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "gasLimit": { + "title": "number", + "type": "number" + }, + "gasUsed": { + "title": "number", + "type": "number" + }, + "hash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "logsBloom": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "miner": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "mixHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "nonce": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 8, + "minItems": 8, + "type": "array" + }, + "number": { + "title": "number", + "type": "number" + }, + "parentHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "receiptsRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "sha3Uncles": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "size": { + "title": "number", + "type": "number" + }, + "stateRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "timestamp": { + "title": "number", + "type": "number" + }, + "totalDifficulty": { + "title": "number", + "type": "number" + }, + "transactions": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + }, + "transactionsRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "uncles": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2392" + } + }, + { + "name": "Filecoin.EthGetBlockTransactionCountByHash", + "description": "```go\nfunc (s *FullNodeStruct) EthGetBlockTransactionCountByHash(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthGetBlockTransactionCountByHash == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetBlockTransactionCountByHash(p0, p1)\n}\n```", + "summary": "EthGetBlockTransactionCountByHash returns the number of messages in the TipSet\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2403" + } + }, + { + "name": "Filecoin.EthGetBlockTransactionCountByNumber", + "description": "```go\nfunc (s *FullNodeStruct) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthGetBlockTransactionCountByNumber == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetBlockTransactionCountByNumber(p0, p1)\n}\n```", + "summary": "EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2414" + } + }, + { + "name": "Filecoin.EthGetCode", + "description": "```go\nfunc (s *FullNodeStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) {\n\tif s.Internal.EthGetCode == nil {\n\t\treturn *new(ethtypes.EthBytes), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetCode(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthBlockNumberOrHash", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "requireCanonical": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBytes", + "description": "ethtypes.EthBytes", + "summary": "", + "schema": { + "examples": [ + "0x07" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2425" + } + }, + { + "name": "Filecoin.EthGetFilterChanges", + "description": "```go\nfunc (s *FullNodeStruct) EthGetFilterChanges(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {\n\tif s.Internal.EthGetFilterChanges == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetFilterChanges(p0, p1)\n}\n```", + "summary": "Polling method for a filter, returns event logs which occurred since last poll.\n(requires write perm since timestamp of last filter execution will be written)\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthFilterResult", + "description": "*ethtypes.EthFilterResult", + "summary": "", + "schema": { + "examples": [ + [ + {} + ] + ], + "additionalProperties": false, + "properties": { + "Results": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2436" + } + }, + { + "name": "Filecoin.EthGetFilterLogs", + "description": "```go\nfunc (s *FullNodeStruct) EthGetFilterLogs(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {\n\tif s.Internal.EthGetFilterLogs == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetFilterLogs(p0, p1)\n}\n```", + "summary": "Returns event logs matching filter with given id.\n(requires write perm since timestamp of last filter execution will be written)\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthFilterResult", + "description": "*ethtypes.EthFilterResult", + "summary": "", + "schema": { + "examples": [ + [ + {} + ] + ], + "additionalProperties": false, + "properties": { + "Results": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2447" + } + }, + { + "name": "Filecoin.EthGetLogs", + "description": "```go\nfunc (s *FullNodeStruct) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) {\n\tif s.Internal.EthGetLogs == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetLogs(p0, p1)\n}\n```", + "summary": "Returns event logs matching given filter spec.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*ethtypes.EthFilterSpec", + "summary": "", + "schema": { + "examples": [ + { + "fromBlock": "2301220", + "address": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "topics": null + } + ], + "additionalProperties": false, + "properties": { + "address": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "fromBlock": { + "type": "string" + }, + "toBlock": { + "type": "string" + }, + "topics": { + "items": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthFilterResult", + "description": "*ethtypes.EthFilterResult", + "summary": "", + "schema": { + "examples": [ + [ + {} + ] + ], + "additionalProperties": false, + "properties": { + "Results": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2458" + } + }, + { + "name": "Filecoin.EthGetMessageCidByTransactionHash", + "description": "```go\nfunc (s *FullNodeStruct) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) {\n\tif s.Internal.EthGetMessageCidByTransactionHash == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetMessageCidByTransactionHash(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*cid.Cid", + "description": "*cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2469" + } + }, + { + "name": "Filecoin.EthGetStorageAt", + "description": "```go\nfunc (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) {\n\tif s.Internal.EthGetStorageAt == nil {\n\t\treturn *new(ethtypes.EthBytes), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetStorageAt(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthBytes", + "summary": "", + "schema": { + "examples": [ + "0x07" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "ethtypes.EthBlockNumberOrHash", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "requireCanonical": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBytes", + "description": "ethtypes.EthBytes", + "summary": "", + "schema": { + "examples": [ + "0x07" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2480" + } + }, + { + "name": "Filecoin.EthGetTransactionByBlockHashAndIndex", + "description": "```go\nfunc (s *FullNodeStruct) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) {\n\tif s.Internal.EthGetTransactionByBlockHashAndIndex == nil {\n\t\treturn *new(ethtypes.EthTx), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionByBlockHashAndIndex(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthTx", + "description": "ethtypes.EthTx", + "summary": "", + "schema": { + "examples": [ + { + "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" + } + ], + "additionalProperties": false, + "properties": { + "accessList": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "chainId": { + "title": "number", + "type": "number" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gas": { + "title": "number", + "type": "number" + }, + "hash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "input": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "maxFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "maxPriorityFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "nonce": { + "title": "number", + "type": "number" + }, + "r": { + "additionalProperties": false, + "type": "object" + }, + "s": { + "additionalProperties": false, + "type": "object" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + }, + "type": { + "title": "number", + "type": "number" + }, + "v": { + "additionalProperties": false, + "type": "object" + }, + "value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2491" + } + }, + { + "name": "Filecoin.EthGetTransactionByBlockNumberAndIndex", + "description": "```go\nfunc (s *FullNodeStruct) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) {\n\tif s.Internal.EthGetTransactionByBlockNumberAndIndex == nil {\n\t\treturn *new(ethtypes.EthTx), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionByBlockNumberAndIndex(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthTx", + "description": "ethtypes.EthTx", + "summary": "", + "schema": { + "examples": [ + { + "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" + } + ], + "additionalProperties": false, + "properties": { + "accessList": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "chainId": { + "title": "number", + "type": "number" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gas": { + "title": "number", + "type": "number" + }, + "hash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "input": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "maxFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "maxPriorityFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "nonce": { + "title": "number", + "type": "number" + }, + "r": { + "additionalProperties": false, + "type": "object" + }, + "s": { + "additionalProperties": false, + "type": "object" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + }, + "type": { + "title": "number", + "type": "number" + }, + "v": { + "additionalProperties": false, + "type": "object" + }, + "value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2502" + } + }, + { + "name": "Filecoin.EthGetTransactionByHash", + "description": "```go\nfunc (s *FullNodeStruct) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) {\n\tif s.Internal.EthGetTransactionByHash == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionByHash(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthTx", + "description": "*ethtypes.EthTx", + "summary": "", + "schema": { + "examples": [ + { + "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" + } + ], + "additionalProperties": false, + "properties": { + "accessList": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "chainId": { + "title": "number", + "type": "number" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gas": { + "title": "number", + "type": "number" + }, + "hash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "input": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "maxFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "maxPriorityFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "nonce": { + "title": "number", + "type": "number" + }, + "r": { + "additionalProperties": false, + "type": "object" + }, + "s": { + "additionalProperties": false, + "type": "object" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + }, + "type": { + "title": "number", + "type": "number" + }, + "v": { + "additionalProperties": false, + "type": "object" + }, + "value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2513" + } + }, + { + "name": "Filecoin.EthGetTransactionByHashLimited", + "description": "```go\nfunc (s *FullNodeStruct) EthGetTransactionByHashLimited(p0 context.Context, p1 *ethtypes.EthHash, p2 abi.ChainEpoch) (*ethtypes.EthTx, error) {\n\tif s.Internal.EthGetTransactionByHashLimited == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionByHashLimited(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthTx", + "description": "*ethtypes.EthTx", + "summary": "", + "schema": { + "examples": [ + { + "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" + } + ], + "additionalProperties": false, + "properties": { + "accessList": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "chainId": { + "title": "number", + "type": "number" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gas": { + "title": "number", + "type": "number" + }, + "hash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "input": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "maxFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "maxPriorityFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "nonce": { + "title": "number", + "type": "number" + }, + "r": { + "additionalProperties": false, + "type": "object" + }, + "s": { + "additionalProperties": false, + "type": "object" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + }, + "type": { + "title": "number", + "type": "number" + }, + "v": { + "additionalProperties": false, + "type": "object" + }, + "value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2524" + } + }, + { + "name": "Filecoin.EthGetTransactionCount", + "description": "```go\nfunc (s *FullNodeStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthGetTransactionCount == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionCount(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthBlockNumberOrHash", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "requireCanonical": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2535" + } + }, + { + "name": "Filecoin.EthGetTransactionHashByCid", + "description": "```go\nfunc (s *FullNodeStruct) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) {\n\tif s.Internal.EthGetTransactionHashByCid == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionHashByCid(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthHash", + "description": "*ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2546" + } + }, + { + "name": "Filecoin.EthGetTransactionReceipt", + "description": "```go\nfunc (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) {\n\tif s.Internal.EthGetTransactionReceipt == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionReceipt(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*EthTxReceipt", + "description": "*EthTxReceipt", + "summary": "", + "schema": { + "examples": [ + { + "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" + } + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "contractAddress": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "cumulativeGasUsed": { + "title": "number", + "type": "number" + }, + "effectiveGasPrice": { + "additionalProperties": false, + "type": "object" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gasUsed": { + "title": "number", + "type": "number" + }, + "logs": { + "items": { + "additionalProperties": false, + "properties": { + "address": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "data": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "logIndex": { + "title": "number", + "type": "number" + }, + "removed": { + "type": "boolean" + }, + "topics": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "logsBloom": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "root": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "status": { + "title": "number", + "type": "number" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + }, + "type": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2557" + } + }, + { + "name": "Filecoin.EthGetTransactionReceiptLimited", + "description": "```go\nfunc (s *FullNodeStruct) EthGetTransactionReceiptLimited(p0 context.Context, p1 ethtypes.EthHash, p2 abi.ChainEpoch) (*EthTxReceipt, error) {\n\tif s.Internal.EthGetTransactionReceiptLimited == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionReceiptLimited(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*EthTxReceipt", + "description": "*EthTxReceipt", + "summary": "", + "schema": { + "examples": [ + { + "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" + } + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "contractAddress": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "cumulativeGasUsed": { + "title": "number", + "type": "number" + }, + "effectiveGasPrice": { + "additionalProperties": false, + "type": "object" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gasUsed": { + "title": "number", + "type": "number" + }, + "logs": { + "items": { + "additionalProperties": false, + "properties": { + "address": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "data": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "logIndex": { + "title": "number", + "type": "number" + }, + "removed": { + "type": "boolean" + }, + "topics": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "logsBloom": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "root": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "status": { + "title": "number", + "type": "number" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + }, + "type": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2568" + } + }, + { + "name": "Filecoin.EthMaxPriorityFeePerGas", + "description": "```go\nfunc (s *FullNodeStruct) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) {\n\tif s.Internal.EthMaxPriorityFeePerGas == nil {\n\t\treturn *new(ethtypes.EthBigInt), ErrNotSupported\n\t}\n\treturn s.Internal.EthMaxPriorityFeePerGas(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthBigInt", + "description": "ethtypes.EthBigInt", + "summary": "", + "schema": { + "examples": [ + "0x0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2579" + } + }, + { + "name": "Filecoin.EthNewBlockFilter", + "description": "```go\nfunc (s *FullNodeStruct) EthNewBlockFilter(p0 context.Context) (ethtypes.EthFilterID, error) {\n\tif s.Internal.EthNewBlockFilter == nil {\n\t\treturn *new(ethtypes.EthFilterID), ErrNotSupported\n\t}\n\treturn s.Internal.EthNewBlockFilter(p0)\n}\n```", + "summary": "Installs a persistent filter to notify when a new block arrives.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthFilterID", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2590" + } + }, + { + "name": "Filecoin.EthNewFilter", + "description": "```go\nfunc (s *FullNodeStruct) EthNewFilter(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) {\n\tif s.Internal.EthNewFilter == nil {\n\t\treturn *new(ethtypes.EthFilterID), ErrNotSupported\n\t}\n\treturn s.Internal.EthNewFilter(p0, p1)\n}\n```", + "summary": "Installs a persistent filter based on given filter spec.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*ethtypes.EthFilterSpec", + "summary": "", + "schema": { + "examples": [ + { + "fromBlock": "2301220", + "address": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "topics": null + } + ], + "additionalProperties": false, + "properties": { + "address": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "fromBlock": { + "type": "string" + }, + "toBlock": { + "type": "string" + }, + "topics": { + "items": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthFilterID", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2601" + } + }, + { + "name": "Filecoin.EthNewPendingTransactionFilter", + "description": "```go\nfunc (s *FullNodeStruct) EthNewPendingTransactionFilter(p0 context.Context) (ethtypes.EthFilterID, error) {\n\tif s.Internal.EthNewPendingTransactionFilter == nil {\n\t\treturn *new(ethtypes.EthFilterID), ErrNotSupported\n\t}\n\treturn s.Internal.EthNewPendingTransactionFilter(p0)\n}\n```", + "summary": "Installs a persistent filter to notify when new messages arrive in the message pool.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthFilterID", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2612" + } + }, + { + "name": "Filecoin.EthProtocolVersion", + "description": "```go\nfunc (s *FullNodeStruct) EthProtocolVersion(p0 context.Context) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthProtocolVersion == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthProtocolVersion(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2623" + } + }, + { + "name": "Filecoin.EthSendRawTransaction", + "description": "```go\nfunc (s *FullNodeStruct) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) {\n\tif s.Internal.EthSendRawTransaction == nil {\n\t\treturn *new(ethtypes.EthHash), ErrNotSupported\n\t}\n\treturn s.Internal.EthSendRawTransaction(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthBytes", + "summary": "", + "schema": { + "examples": [ + "0x07" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthHash", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2634" + } + }, + { + "name": "Filecoin.EthSubscribe", + "description": "```go\nfunc (s *FullNodeStruct) EthSubscribe(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {\n\tif s.Internal.EthSubscribe == nil {\n\t\treturn *new(ethtypes.EthSubscriptionID), ErrNotSupported\n\t}\n\treturn s.Internal.EthSubscribe(p0, p1)\n}\n```", + "summary": "Subscribe to different event types using websockets\neventTypes is one or more of:\n - newHeads: notify when new blocks arrive.\n - pendingTransactions: notify when new messages arrive in the message pool.\n - logs: notify new event logs that match a criteria\nparams contains additional parameters used with the log event type\nThe client will receive a stream of EthSubscriptionResponse values until EthUnsubscribe is called.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "jsonrpc.RawParams", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthSubscriptionID", + "description": "ethtypes.EthSubscriptionID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2645" + } + }, + { + "name": "Filecoin.EthSyncing", + "description": "```go\nfunc (s *FullNodeStruct) EthSyncing(p0 context.Context) (ethtypes.EthSyncingResult, error) {\n\tif s.Internal.EthSyncing == nil {\n\t\treturn *new(ethtypes.EthSyncingResult), ErrNotSupported\n\t}\n\treturn s.Internal.EthSyncing(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthSyncingResult", + "description": "ethtypes.EthSyncingResult", + "summary": "", + "schema": { + "examples": [ + false + ], + "additionalProperties": false, + "properties": { + "CurrentBlock": { + "title": "number", + "type": "number" + }, + "DoneSync": { + "type": "boolean" + }, + "HighestBlock": { + "title": "number", + "type": "number" + }, + "StartingBlock": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2656" + } + }, + { + "name": "Filecoin.EthTraceBlock", + "description": "```go\nfunc (s *FullNodeStruct) EthTraceBlock(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) {\n\tif s.Internal.EthTraceBlock == nil {\n\t\treturn *new([]*ethtypes.EthTraceBlock), ErrNotSupported\n\t}\n\treturn s.Internal.EthTraceBlock(p0, p1)\n}\n```", + "summary": "Returns an OpenEthereum-compatible trace of the given block (implementing `trace_block`),\ntranslating Filecoin semantics into Ethereum semantics and tracing both EVM and FVM calls.\n\nFeatures:\n\n- FVM actor create events, calls, etc. show up as if they were EVM smart contract events.\n- Native FVM call inputs are ABI-encoded (Solidity ABI) as if they were calls to a\n `handle_filecoin_method(uint64 method, uint64 codec, bytes params)` function\n (where `codec` is the IPLD codec of `params`).\n- Native FVM call outputs (return values) are ABI-encoded as `(uint32 exit_code, uint64\n codec, bytes output)` where `codec` is the IPLD codec of `output`.\n\nLimitations (for now):\n\n1. Block rewards are not included in the trace.\n2. SELFDESTRUCT operations are not included in the trace.\n3. EVM smart contract \"create\" events always specify `0xfe` as the \"code\" for newly created EVM smart contracts.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*ethtypes.EthTraceBlock", + "description": "[]*ethtypes.EthTraceBlock", + "summary": "", + "schema": { + "examples": [ + [ + { + "type": "string value", + "error": "string value", + "subtraces": 123, + "traceAddress": [ + 123 + ], + "action": {}, + "result": {}, + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockNumber": 9, + "transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "transactionPosition": 123 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "action": { + "additionalProperties": true, + "type": "object" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "error": { + "type": "string" + }, + "result": { + "additionalProperties": true, + "type": "object" + }, + "subtraces": { + "title": "number", + "type": "number" + }, + "traceAddress": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "transactionPosition": { + "title": "number", + "type": "number" + }, + "type": { + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2667" + } + }, + { + "name": "Filecoin.EthTraceReplayBlockTransactions", + "description": "```go\nfunc (s *FullNodeStruct) EthTraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) {\n\tif s.Internal.EthTraceReplayBlockTransactions == nil {\n\t\treturn *new([]*ethtypes.EthTraceReplayBlockTransaction), ErrNotSupported\n\t}\n\treturn s.Internal.EthTraceReplayBlockTransactions(p0, p1, p2)\n}\n```", + "summary": "Replays all transactions in a block returning the requested traces for each transaction\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "[]string", + "summary": "", + "schema": { + "examples": [ + [ + "string value" + ] + ], + "items": [ + { + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*ethtypes.EthTraceReplayBlockTransaction", + "description": "[]*ethtypes.EthTraceReplayBlockTransaction", + "summary": "", + "schema": { + "examples": [ + [ + { + "output": "0x07", + "stateDiff": "string value", + "trace": [ + { + "type": "string value", + "error": "string value", + "subtraces": 123, + "traceAddress": [ + 123 + ], + "action": {}, + "result": {} + } + ], + "transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "vmTrace": "string value" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "output": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "stateDiff": { + "type": "string" + }, + "trace": { + "items": { + "additionalProperties": false, + "properties": { + "action": { + "additionalProperties": true, + "type": "object" + }, + "error": { + "type": "string" + }, + "result": { + "additionalProperties": true, + "type": "object" + }, + "subtraces": { + "title": "number", + "type": "number" + }, + "traceAddress": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "type": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "vmTrace": { + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2678" + } + }, + { + "name": "Filecoin.EthUninstallFilter", + "description": "```go\nfunc (s *FullNodeStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) {\n\tif s.Internal.EthUninstallFilter == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.EthUninstallFilter(p0, p1)\n}\n```", + "summary": "Uninstalls a filter with given id.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2689" + } + }, + { + "name": "Filecoin.EthUnsubscribe", + "description": "```go\nfunc (s *FullNodeStruct) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) {\n\tif s.Internal.EthUnsubscribe == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.EthUnsubscribe(p0, p1)\n}\n```", + "summary": "Unsubscribe from a websocket subscription\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthSubscriptionID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2700" + } + }, + { + "name": "Filecoin.FilecoinAddressToEthAddress", + "description": "```go\nfunc (s *FullNodeStruct) FilecoinAddressToEthAddress(p0 context.Context, p1 address.Address) (ethtypes.EthAddress, error) {\n\tif s.Internal.FilecoinAddressToEthAddress == nil {\n\t\treturn *new(ethtypes.EthAddress), ErrNotSupported\n\t}\n\treturn s.Internal.FilecoinAddressToEthAddress(p0, p1)\n}\n```", + "summary": "FilecoinAddressToEthAddress converts an f410 or f0 Filecoin Address to an EthAddress\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthAddress", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2711" + } + }, + { + "name": "Filecoin.GasEstimateFeeCap", + "description": "```go\nfunc (s *FullNodeStruct) GasEstimateFeeCap(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.GasEstimateFeeCap == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.GasEstimateFeeCap(p0, p1, p2, p3)\n}\n```", + "summary": "GasEstimateFeeCap estimates gas fee cap\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "int64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2722" + } + }, + { + "name": "Filecoin.GasEstimateGasLimit", + "description": "```go\nfunc (s *FullNodeStruct) GasEstimateGasLimit(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (int64, error) {\n\tif s.Internal.GasEstimateGasLimit == nil {\n\t\treturn 0, ErrNotSupported\n\t}\n\treturn s.Internal.GasEstimateGasLimit(p0, p1, p2)\n}\n```", + "summary": "GasEstimateGasLimit estimates gas used by the message and returns it.\nIt fails if message fails to execute.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "int64", + "description": "int64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2733" + } + }, + { + "name": "Filecoin.GasEstimateGasPremium", + "description": "```go\nfunc (s *FullNodeStruct) GasEstimateGasPremium(p0 context.Context, p1 uint64, p2 address.Address, p3 int64, p4 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.GasEstimateGasPremium == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.GasEstimateGasPremium(p0, p1, p2, p3, p4)\n}\n```", + "summary": "GasEstimateGasPremium estimates what gas price should be used for a\nmessage to have high likelihood of inclusion in `nblocksincl` epochs.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "int64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2744" + } + }, + { + "name": "Filecoin.GasEstimateMessageGas", + "description": "```go\nfunc (s *FullNodeStruct) GasEstimateMessageGas(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) {\n\tif s.Internal.GasEstimateMessageGas == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.GasEstimateMessageGas(p0, p1, p2, p3)\n}\n```", + "summary": "GasEstimateMessageGas estimates gas values for unset message gas fields\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*MessageSendSpec", + "summary": "", + "schema": { + "examples": [ + { + "MaxFee": "0", + "MsgUuid": "07070707-0707-0707-0707-070707070707", + "MaximizeFeeCap": true + } + ], + "additionalProperties": false, + "properties": { + "MaxFee": { + "additionalProperties": false, + "type": "object" + }, + "MaximizeFeeCap": { + "type": "boolean" + }, + "MsgUuid": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.Message", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2755" + } + }, + { + "name": "Filecoin.GetActorEventsRaw", + "description": "```go\nfunc (s *FullNodeStruct) GetActorEventsRaw(p0 context.Context, p1 *types.ActorEventFilter) ([]*types.ActorEvent, error) {\n\tif s.Internal.GetActorEventsRaw == nil {\n\t\treturn *new([]*types.ActorEvent), ErrNotSupported\n\t}\n\treturn s.Internal.GetActorEventsRaw(p0, p1)\n}\n```", + "summary": "GetActorEventsRaw returns all user-programmed and built-in actor events that match the given\nfilter.\nThis is a request/response API.\nResults available from this API may be limited by the MaxFilterResults and MaxFilterHeightRange\nconfiguration options and also the amount of historical data available in the node.\n\nThis is an EXPERIMENTAL API and may be subject to change.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.ActorEventFilter", + "summary": "", + "schema": { + "examples": [ + { + "addresses": [ + "f01234" + ], + "fields": { + "abc": [ + { + "codec": 81, + "value": "ZGRhdGE=" + } + ] + }, + "fromHeight": 1010, + "toHeight": 1020 + } + ], + "additionalProperties": false, + "properties": { + "addresses": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "fields": { + "patternProperties": { + ".*": { + "items": { + "additionalProperties": false, + "properties": { + "codec": { + "title": "number", + "type": "number" + }, + "value": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "fromHeight": { + "title": "number", + "type": "number" + }, + "tipsetKey": { + "additionalProperties": false, + "type": "object" + }, + "toHeight": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*types.ActorEvent", + "description": "[]*types.ActorEvent", + "summary": "", + "schema": { + "examples": [ + [ + { + "entries": [ + { + "Flags": 7, + "Key": "string value", + "Codec": 42, + "Value": "Ynl0ZSBhcnJheQ==" + } + ], + "emitter": "f01234", + "reverted": true, + "height": 10101, + "tipsetKey": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "msgCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "emitter": { + "additionalProperties": false, + "type": "object" + }, + "entries": { + "items": { + "additionalProperties": false, + "properties": { + "Codec": { + "title": "number", + "type": "number" + }, + "Flags": { + "title": "number", + "type": "number" + }, + "Key": { + "type": "string" + }, + "Value": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "height": { + "title": "number", + "type": "number" + }, + "msgCid": { + "title": "Content Identifier", + "type": "string" + }, + "reverted": { + "type": "boolean" + }, + "tipsetKey": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2766" + } + }, + { + "name": "Filecoin.MarketAddBalance", + "description": "```go\nfunc (s *FullNodeStruct) MarketAddBalance(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) {\n\tif s.Internal.MarketAddBalance == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.MarketAddBalance(p0, p1, p2, p3)\n}\n```", + "summary": "MarketAddBalance adds funds to the market actor\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2777" + } + }, + { + "name": "Filecoin.MarketGetReserved", + "description": "```go\nfunc (s *FullNodeStruct) MarketGetReserved(p0 context.Context, p1 address.Address) (types.BigInt, error) {\n\tif s.Internal.MarketGetReserved == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.MarketGetReserved(p0, p1)\n}\n```", + "summary": "MarketGetReserved gets the amount of funds that are currently reserved for the address\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2788" + } + }, + { + "name": "Filecoin.MarketReleaseFunds", + "description": "```go\nfunc (s *FullNodeStruct) MarketReleaseFunds(p0 context.Context, p1 address.Address, p2 types.BigInt) error {\n\tif s.Internal.MarketReleaseFunds == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.MarketReleaseFunds(p0, p1, p2)\n}\n```", + "summary": "MarketReleaseFunds releases funds reserved by MarketReserveFunds\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2799" + } + }, + { + "name": "Filecoin.MarketReserveFunds", + "description": "```go\nfunc (s *FullNodeStruct) MarketReserveFunds(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) {\n\tif s.Internal.MarketReserveFunds == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.MarketReserveFunds(p0, p1, p2, p3)\n}\n```", + "summary": "MarketReserveFunds reserves funds for a deal\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2810" + } + }, + { + "name": "Filecoin.MarketWithdraw", + "description": "```go\nfunc (s *FullNodeStruct) MarketWithdraw(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) {\n\tif s.Internal.MarketWithdraw == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.MarketWithdraw(p0, p1, p2, p3)\n}\n```", + "summary": "MarketWithdraw withdraws unlocked funds from the market actor\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2821" + } + }, + { + "name": "Filecoin.MinerCreateBlock", + "description": "```go\nfunc (s *FullNodeStruct) MinerCreateBlock(p0 context.Context, p1 *BlockTemplate) (*types.BlockMsg, error) {\n\tif s.Internal.MinerCreateBlock == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MinerCreateBlock(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*BlockTemplate", + "summary": "", + "schema": { + "examples": [ + { + "Miner": "f01234", + "Parents": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "Ticket": { + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "Eproof": { + "WinCount": 9, + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "BeaconValues": [ + { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + } + ], + "Messages": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "Epoch": 10101, + "Timestamp": 42, + "WinningPoStProof": [ + { + "PoStProof": 8, + "ProofBytes": "Ynl0ZSBhcnJheQ==" + } + ] + } + ], + "additionalProperties": false, + "properties": { + "BeaconValues": { + "items": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Round": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "Epoch": { + "title": "number", + "type": "number" + }, + "Eproof": { + "additionalProperties": false, + "properties": { + "VRFProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "WinCount": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Messages": { + "items": { + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "Parents": { + "additionalProperties": false, + "type": "object" + }, + "Ticket": { + "additionalProperties": false, + "properties": { + "VRFProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "Timestamp": { + "title": "number", + "type": "number" + }, + "WinningPoStProof": { + "items": { + "additionalProperties": false, + "properties": { + "PoStProof": { + "title": "number", + "type": "number" + }, + "ProofBytes": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.BlockMsg", + "description": "*types.BlockMsg", + "summary": "", + "schema": { + "examples": [ + { + "Header": { + "Miner": "f01234", + "Ticket": { + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "ElectionProof": { + "WinCount": 9, + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": [ + { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + } + ], + "WinPoStProof": [ + { + "PoStProof": 8, + "ProofBytes": "Ynl0ZSBhcnJheQ==" + } + ], + "Parents": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "ParentWeight": "0", + "Height": 10101, + "ParentStateRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Messages": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "BLSAggregate": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Timestamp": 42, + "BlockSig": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "ForkSignaling": 42, + "ParentBaseFee": "0" + }, + "BlsMessages": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "SecpkMessages": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + } + ], + "additionalProperties": false, + "properties": { + "BlsMessages": { + "items": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + }, + "type": "array" + }, + "Header": { + "additionalProperties": false, + "properties": { + "BLSAggregate": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "BeaconEntries": { + "items": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Round": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "BlockSig": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ElectionProof": { + "additionalProperties": false, + "properties": { + "VRFProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "WinCount": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ForkSignaling": { + "title": "number", + "type": "number" + }, + "Height": { + "title": "number", + "type": "number" + }, + "Messages": { + "title": "Content Identifier", + "type": "string" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "ParentBaseFee": { + "additionalProperties": false, + "type": "object" + }, + "ParentMessageReceipts": { + "title": "Content Identifier", + "type": "string" + }, + "ParentStateRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ParentWeight": { + "additionalProperties": false, + "type": "object" + }, + "Parents": { + "items": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + }, + "type": "array" + }, + "Ticket": { + "additionalProperties": false, + "properties": { + "VRFProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "Timestamp": { + "title": "number", + "type": "number" + }, + "WinPoStProof": { + "items": { + "additionalProperties": false, + "properties": { + "PoStProof": { + "title": "number", + "type": "number" + }, + "ProofBytes": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "SecpkMessages": { + "items": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2832" + } + }, + { + "name": "Filecoin.MinerGetBaseInfo", + "description": "```go\nfunc (s *FullNodeStruct) MinerGetBaseInfo(p0 context.Context, p1 address.Address, p2 abi.ChainEpoch, p3 types.TipSetKey) (*MiningBaseInfo, error) {\n\tif s.Internal.MinerGetBaseInfo == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MinerGetBaseInfo(p0, p1, p2, p3)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MiningBaseInfo", + "description": "*MiningBaseInfo", + "summary": "", + "schema": { + "examples": [ + { + "MinerPower": "0", + "NetworkPower": "0", + "Sectors": [ + { + "SealProof": 8, + "SectorNumber": 9, + "SectorKey": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "WorkerKey": "f01234", + "SectorSize": 34359738368, + "PrevBeaconEntry": { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": [ + { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + } + ], + "EligibleForMining": true + } + ], + "additionalProperties": false, + "properties": { + "BeaconEntries": { + "items": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Round": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "EligibleForMining": { + "type": "boolean" + }, + "MinerPower": { + "additionalProperties": false, + "type": "object" + }, + "NetworkPower": { + "additionalProperties": false, + "type": "object" + }, + "PrevBeaconEntry": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Round": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "SectorSize": { + "title": "number", + "type": "number" + }, + "Sectors": { + "items": { + "additionalProperties": false, + "properties": { + "SealProof": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorKey": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "WorkerKey": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2843" + } + }, + { + "name": "Filecoin.MpoolBatchPush", + "description": "```go\nfunc (s *FullNodeStruct) MpoolBatchPush(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) {\n\tif s.Internal.MpoolBatchPush == nil {\n\t\treturn *new([]cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolBatchPush(p0, p1)\n}\n```", + "summary": "MpoolBatchPush batch pushes a signed message to mempool.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "[]*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]cid.Cid", + "description": "[]cid.Cid", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + ], + "items": [ + { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2854" + } + }, + { + "name": "Filecoin.MpoolBatchPushMessage", + "description": "```go\nfunc (s *FullNodeStruct) MpoolBatchPushMessage(p0 context.Context, p1 []*types.Message, p2 *MessageSendSpec) ([]*types.SignedMessage, error) {\n\tif s.Internal.MpoolBatchPushMessage == nil {\n\t\treturn *new([]*types.SignedMessage), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolBatchPushMessage(p0, p1, p2)\n}\n```", + "summary": "MpoolBatchPushMessage batch pushes a unsigned message to mempool.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "[]*types.Message", + "summary": "", + "schema": { + "examples": [ + [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*MessageSendSpec", + "summary": "", + "schema": { + "examples": [ + { + "MaxFee": "0", + "MsgUuid": "07070707-0707-0707-0707-070707070707", + "MaximizeFeeCap": true + } + ], + "additionalProperties": false, + "properties": { + "MaxFee": { + "additionalProperties": false, + "type": "object" + }, + "MaximizeFeeCap": { + "type": "boolean" + }, + "MsgUuid": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*types.SignedMessage", + "description": "[]*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2865" + } + }, + { + "name": "Filecoin.MpoolBatchPushUntrusted", + "description": "```go\nfunc (s *FullNodeStruct) MpoolBatchPushUntrusted(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) {\n\tif s.Internal.MpoolBatchPushUntrusted == nil {\n\t\treturn *new([]cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolBatchPushUntrusted(p0, p1)\n}\n```", + "summary": "MpoolBatchPushUntrusted batch pushes a signed message to mempool from untrusted sources.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "[]*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]cid.Cid", + "description": "[]cid.Cid", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + ], + "items": [ + { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2876" + } + }, + { + "name": "Filecoin.MpoolCheckMessages", + "description": "```go\nfunc (s *FullNodeStruct) MpoolCheckMessages(p0 context.Context, p1 []*MessagePrototype) ([][]MessageCheckStatus, error) {\n\tif s.Internal.MpoolCheckMessages == nil {\n\t\treturn *new([][]MessageCheckStatus), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolCheckMessages(p0, p1)\n}\n```", + "summary": "MpoolCheckMessages performs logical checks on a batch of messages\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "[]*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[][]MessageCheckStatus", + "description": "[][]MessageCheckStatus", + "summary": "", + "schema": { + "examples": [ + [ + [ + { + "Cid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Code": 0, + "OK": true, + "Err": "string value", + "Hint": { + "abc": 123 + } + } + ] + ] + ], + "items": [ + { + "items": [ + { + "additionalProperties": false, + "properties": { + "Cid": { + "title": "Content Identifier", + "type": "string" + }, + "Code": { + "title": "number", + "type": "number" + }, + "Err": { + "type": "string" + }, + "Hint": { + "patternProperties": { + ".*": { + "additionalProperties": true, + "type": "object" + } + }, + "type": "object" + }, + "OK": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2887" + } + }, + { + "name": "Filecoin.MpoolCheckPendingMessages", + "description": "```go\nfunc (s *FullNodeStruct) MpoolCheckPendingMessages(p0 context.Context, p1 address.Address) ([][]MessageCheckStatus, error) {\n\tif s.Internal.MpoolCheckPendingMessages == nil {\n\t\treturn *new([][]MessageCheckStatus), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolCheckPendingMessages(p0, p1)\n}\n```", + "summary": "MpoolCheckPendingMessages performs logical checks for all pending messages from a given address\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[][]MessageCheckStatus", + "description": "[][]MessageCheckStatus", + "summary": "", + "schema": { + "examples": [ + [ + [ + { + "Cid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Code": 0, + "OK": true, + "Err": "string value", + "Hint": { + "abc": 123 + } + } + ] + ] + ], + "items": [ + { + "items": [ + { + "additionalProperties": false, + "properties": { + "Cid": { + "title": "Content Identifier", + "type": "string" + }, + "Code": { + "title": "number", + "type": "number" + }, + "Err": { + "type": "string" + }, + "Hint": { + "patternProperties": { + ".*": { + "additionalProperties": true, + "type": "object" + } + }, + "type": "object" + }, + "OK": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2898" + } + }, + { + "name": "Filecoin.MpoolCheckReplaceMessages", + "description": "```go\nfunc (s *FullNodeStruct) MpoolCheckReplaceMessages(p0 context.Context, p1 []*types.Message) ([][]MessageCheckStatus, error) {\n\tif s.Internal.MpoolCheckReplaceMessages == nil {\n\t\treturn *new([][]MessageCheckStatus), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolCheckReplaceMessages(p0, p1)\n}\n```", + "summary": "MpoolCheckReplaceMessages performs logical checks on pending messages with replacement\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "[]*types.Message", + "summary": "", + "schema": { + "examples": [ + [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[][]MessageCheckStatus", + "description": "[][]MessageCheckStatus", + "summary": "", + "schema": { + "examples": [ + [ + [ + { + "Cid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Code": 0, + "OK": true, + "Err": "string value", + "Hint": { + "abc": 123 + } + } + ] + ] + ], + "items": [ + { + "items": [ + { + "additionalProperties": false, + "properties": { + "Cid": { + "title": "Content Identifier", + "type": "string" + }, + "Code": { + "title": "number", + "type": "number" + }, + "Err": { + "type": "string" + }, + "Hint": { + "patternProperties": { + ".*": { + "additionalProperties": true, + "type": "object" + } + }, + "type": "object" + }, + "OK": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2909" + } + }, + { + "name": "Filecoin.MpoolClear", + "description": "```go\nfunc (s *FullNodeStruct) MpoolClear(p0 context.Context, p1 bool) error {\n\tif s.Internal.MpoolClear == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.MpoolClear(p0, p1)\n}\n```", + "summary": "MpoolClear clears pending messages from the mpool.\nIf clearLocal is true, ALL messages will be cleared.\nIf clearLocal is false, local messages will be protected, all others will be cleared.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2920" + } + }, + { + "name": "Filecoin.MpoolGetConfig", + "description": "```go\nfunc (s *FullNodeStruct) MpoolGetConfig(p0 context.Context) (*types.MpoolConfig, error) {\n\tif s.Internal.MpoolGetConfig == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MpoolGetConfig(p0)\n}\n```", + "summary": "MpoolGetConfig returns (a copy of) the current mpool config\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*types.MpoolConfig", + "description": "*types.MpoolConfig", + "summary": "", + "schema": { + "examples": [ + { + "PriorityAddrs": [ + "f01234" + ], + "SizeLimitHigh": 123, + "SizeLimitLow": 123, + "ReplaceByFeeRatio": 1.23, + "PruneCooldown": 60000000000, + "GasLimitOverestimation": 12.3 + } + ], + "additionalProperties": false, + "properties": { + "GasLimitOverestimation": { + "type": "number" + }, + "PriorityAddrs": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "PruneCooldown": { + "title": "number", + "type": "number" + }, + "ReplaceByFeeRatio": { + "title": "number", + "type": "number" + }, + "SizeLimitHigh": { + "title": "number", + "type": "number" + }, + "SizeLimitLow": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2931" + } + }, + { + "name": "Filecoin.MpoolGetNonce", + "description": "```go\nfunc (s *FullNodeStruct) MpoolGetNonce(p0 context.Context, p1 address.Address) (uint64, error) {\n\tif s.Internal.MpoolGetNonce == nil {\n\t\treturn 0, ErrNotSupported\n\t}\n\treturn s.Internal.MpoolGetNonce(p0, p1)\n}\n```", + "summary": "MpoolGetNonce gets next nonce for the specified sender.\nNote that this method may not be atomic. Use MpoolPushMessage instead.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "uint64", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2942" + } + }, + { + "name": "Filecoin.MpoolPending", + "description": "```go\nfunc (s *FullNodeStruct) MpoolPending(p0 context.Context, p1 types.TipSetKey) ([]*types.SignedMessage, error) {\n\tif s.Internal.MpoolPending == nil {\n\t\treturn *new([]*types.SignedMessage), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolPending(p0, p1)\n}\n```", + "summary": "MpoolPending returns pending mempool messages.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*types.SignedMessage", + "description": "[]*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2953" + } + }, + { + "name": "Filecoin.MpoolPush", + "description": "```go\nfunc (s *FullNodeStruct) MpoolPush(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) {\n\tif s.Internal.MpoolPush == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolPush(p0, p1)\n}\n```", + "summary": "MpoolPush pushes a signed message to mempool.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2964" + } + }, + { + "name": "Filecoin.MpoolPushMessage", + "description": "```go\nfunc (s *FullNodeStruct) MpoolPushMessage(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec) (*types.SignedMessage, error) {\n\tif s.Internal.MpoolPushMessage == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MpoolPushMessage(p0, p1, p2)\n}\n```", + "summary": "MpoolPushMessage atomically assigns a nonce, signs, and pushes a message\nto mempool.\nmaxFee is only used when GasFeeCap/GasPremium fields aren't specified\n\nWhen maxFee is set to 0, MpoolPushMessage will guess appropriate fee\nbased on current chain conditions\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*MessageSendSpec", + "summary": "", + "schema": { + "examples": [ + { + "MaxFee": "0", + "MsgUuid": "07070707-0707-0707-0707-070707070707", + "MaximizeFeeCap": true + } + ], + "additionalProperties": false, + "properties": { + "MaxFee": { + "additionalProperties": false, + "type": "object" + }, + "MaximizeFeeCap": { + "type": "boolean" + }, + "MsgUuid": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.SignedMessage", + "description": "*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2975" + } + }, + { + "name": "Filecoin.MpoolPushUntrusted", + "description": "```go\nfunc (s *FullNodeStruct) MpoolPushUntrusted(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) {\n\tif s.Internal.MpoolPushUntrusted == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolPushUntrusted(p0, p1)\n}\n```", + "summary": "MpoolPushUntrusted pushes a signed message to mempool from untrusted sources.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2986" + } + }, + { + "name": "Filecoin.MpoolSelect", + "description": "```go\nfunc (s *FullNodeStruct) MpoolSelect(p0 context.Context, p1 types.TipSetKey, p2 float64) ([]*types.SignedMessage, error) {\n\tif s.Internal.MpoolSelect == nil {\n\t\treturn *new([]*types.SignedMessage), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolSelect(p0, p1, p2)\n}\n```", + "summary": "MpoolSelect returns a list of pending messages for inclusion in the next block\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "float64", + "summary": "", + "schema": { + "examples": [ + 12.3 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*types.SignedMessage", + "description": "[]*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L2997" + } + }, + { + "name": "Filecoin.MpoolSetConfig", + "description": "```go\nfunc (s *FullNodeStruct) MpoolSetConfig(p0 context.Context, p1 *types.MpoolConfig) error {\n\tif s.Internal.MpoolSetConfig == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.MpoolSetConfig(p0, p1)\n}\n```", + "summary": "MpoolSetConfig sets the mpool config to (a copy of) the supplied config\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.MpoolConfig", + "summary": "", + "schema": { + "examples": [ + { + "PriorityAddrs": [ + "f01234" + ], + "SizeLimitHigh": 123, + "SizeLimitLow": 123, + "ReplaceByFeeRatio": 1.23, + "PruneCooldown": 60000000000, + "GasLimitOverestimation": 12.3 + } + ], + "additionalProperties": false, + "properties": { + "GasLimitOverestimation": { + "type": "number" + }, + "PriorityAddrs": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "PruneCooldown": { + "title": "number", + "type": "number" + }, + "ReplaceByFeeRatio": { + "title": "number", + "type": "number" + }, + "SizeLimitHigh": { + "title": "number", + "type": "number" + }, + "SizeLimitLow": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3008" + } + }, + { + "name": "Filecoin.MsigAddApprove", + "description": "```go\nfunc (s *FullNodeStruct) MsigAddApprove(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address, p6 bool) (*MessagePrototype, error) {\n\tif s.Internal.MsigAddApprove == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigAddApprove(p0, p1, p2, p3, p4, p5, p6)\n}\n```", + "summary": "MsigAddApprove approves a previously proposed AddSigner message\nIt takes the following params: \u003cmultisig address\u003e, \u003csender address of the approve msg\u003e, \u003cproposed message ID\u003e,\n\u003cproposer address\u003e, \u003cnew signer\u003e, \u003cwhether the number of required signers should be increased\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p6", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3030" + } + }, + { + "name": "Filecoin.MsigAddCancel", + "description": "```go\nfunc (s *FullNodeStruct) MsigAddCancel(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 bool) (*MessagePrototype, error) {\n\tif s.Internal.MsigAddCancel == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigAddCancel(p0, p1, p2, p3, p4, p5)\n}\n```", + "summary": "MsigAddCancel cancels a previously proposed AddSigner message\nIt takes the following params: \u003cmultisig address\u003e, \u003csender address of the cancel msg\u003e, \u003cproposed message ID\u003e,\n\u003cnew signer\u003e, \u003cwhether the number of required signers should be increased\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3041" + } + }, + { + "name": "Filecoin.MsigAddPropose", + "description": "```go\nfunc (s *FullNodeStruct) MsigAddPropose(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 bool) (*MessagePrototype, error) {\n\tif s.Internal.MsigAddPropose == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigAddPropose(p0, p1, p2, p3, p4)\n}\n```", + "summary": "MsigAddPropose proposes adding a signer in the multisig\nIt takes the following params: \u003cmultisig address\u003e, \u003csender address of the propose msg\u003e,\n\u003cnew signer\u003e, \u003cwhether the number of required signers should be increased\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3052" + } + }, + { + "name": "Filecoin.MsigApprove", + "description": "```go\nfunc (s *FullNodeStruct) MsigApprove(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (*MessagePrototype, error) {\n\tif s.Internal.MsigApprove == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigApprove(p0, p1, p2, p3)\n}\n```", + "summary": "MsigApprove approves a previously-proposed multisig message by transaction ID\nIt takes the following params: \u003cmultisig address\u003e, \u003cproposed transaction ID\u003e \u003csigner address\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3063" + } + }, + { + "name": "Filecoin.MsigApproveTxnHash", + "description": "```go\nfunc (s *FullNodeStruct) MsigApproveTxnHash(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) {\n\tif s.Internal.MsigApproveTxnHash == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigApproveTxnHash(p0, p1, p2, p3, p4, p5, p6, p7, p8)\n}\n```", + "summary": "MsigApproveTxnHash approves a previously-proposed multisig message, specified\nusing both transaction ID and a hash of the parameters used in the\nproposal. This method of approval can be used to ensure you only approve\nexactly the transaction you think you are.\nIt takes the following params: \u003cmultisig address\u003e, \u003cproposed message ID\u003e, \u003cproposer address\u003e, \u003crecipient address\u003e, \u003cvalue to transfer\u003e,\n\u003csender address of the approve msg\u003e, \u003cmethod to call in the proposed message\u003e, \u003cparams to include in the proposed message\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p6", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p7", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p8", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3074" + } + }, + { + "name": "Filecoin.MsigCancel", + "description": "```go\nfunc (s *FullNodeStruct) MsigCancel(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address) (*MessagePrototype, error) {\n\tif s.Internal.MsigCancel == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigCancel(p0, p1, p2, p3)\n}\n```", + "summary": "MsigCancel cancels a previously-proposed multisig message\nIt takes the following params: \u003cmultisig address\u003e, \u003cproposed transaction ID\u003e \u003csigner address\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3085" + } + }, + { + "name": "Filecoin.MsigCancelTxnHash", + "description": "```go\nfunc (s *FullNodeStruct) MsigCancelTxnHash(p0 context.Context, p1 address.Address, p2 uint64, p3 address.Address, p4 types.BigInt, p5 address.Address, p6 uint64, p7 []byte) (*MessagePrototype, error) {\n\tif s.Internal.MsigCancelTxnHash == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigCancelTxnHash(p0, p1, p2, p3, p4, p5, p6, p7)\n}\n```", + "summary": "MsigCancel cancels a previously-proposed multisig message\nIt takes the following params: \u003cmultisig address\u003e, \u003cproposed transaction ID\u003e, \u003crecipient address\u003e, \u003cvalue to transfer\u003e,\n\u003csender address of the cancel msg\u003e, \u003cmethod to call in the proposed message\u003e, \u003cparams to include in the proposed message\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p6", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p7", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3096" + } + }, + { + "name": "Filecoin.MsigCreate", + "description": "```go\nfunc (s *FullNodeStruct) MsigCreate(p0 context.Context, p1 uint64, p2 []address.Address, p3 abi.ChainEpoch, p4 types.BigInt, p5 address.Address, p6 types.BigInt) (*MessagePrototype, error) {\n\tif s.Internal.MsigCreate == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigCreate(p0, p1, p2, p3, p4, p5, p6)\n}\n```", + "summary": "MsigCreate creates a multisig wallet\nIt takes the following params: \u003crequired number of senders\u003e, \u003capproving addresses\u003e, \u003cunlock duration\u003e\n\u003cinitial balance\u003e, \u003csender address of the create msg\u003e, \u003cgas price\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "[]address.Address", + "summary": "", + "schema": { + "examples": [ + [ + "f01234" + ] + ], + "items": [ + { + "additionalProperties": false, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p6", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3107" + } + }, + { + "name": "Filecoin.MsigGetAvailableBalance", + "description": "```go\nfunc (s *FullNodeStruct) MsigGetAvailableBalance(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.MsigGetAvailableBalance == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.MsigGetAvailableBalance(p0, p1, p2)\n}\n```", + "summary": "MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3118" + } + }, + { + "name": "Filecoin.MsigGetPending", + "description": "```go\nfunc (s *FullNodeStruct) MsigGetPending(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*MsigTransaction, error) {\n\tif s.Internal.MsigGetPending == nil {\n\t\treturn *new([]*MsigTransaction), ErrNotSupported\n\t}\n\treturn s.Internal.MsigGetPending(p0, p1, p2)\n}\n```", + "summary": "MsigGetPending returns pending transactions for the given multisig\nwallet. Once pending transactions are fully approved, they will no longer\nappear here.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*MsigTransaction", + "description": "[]*MsigTransaction", + "summary": "", + "schema": { + "examples": [ + [ + { + "ID": 9, + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "Approved": [ + "f01234" + ] + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Approved": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "ID": { + "title": "number", + "type": "number" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3129" + } + }, + { + "name": "Filecoin.MsigGetVested", + "description": "```go\nfunc (s *FullNodeStruct) MsigGetVested(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.MsigGetVested == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.MsigGetVested(p0, p1, p2, p3)\n}\n```", + "summary": "MsigGetVested returns the amount of FIL that vested in a multisig in a certain period.\nIt takes the following params: \u003cmultisig address\u003e, \u003cstart epoch\u003e, \u003cend epoch\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3140" + } + }, + { + "name": "Filecoin.MsigGetVestingSchedule", + "description": "```go\nfunc (s *FullNodeStruct) MsigGetVestingSchedule(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MsigVesting, error) {\n\tif s.Internal.MsigGetVestingSchedule == nil {\n\t\treturn *new(MsigVesting), ErrNotSupported\n\t}\n\treturn s.Internal.MsigGetVestingSchedule(p0, p1, p2)\n}\n```", + "summary": "MsigGetVestingSchedule returns the vesting details of a given multisig.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "MsigVesting", + "description": "MsigVesting", + "summary": "", + "schema": { + "examples": [ + { + "InitialBalance": "0", + "StartEpoch": 10101, + "UnlockDuration": 10101 + } + ], + "additionalProperties": false, + "properties": { + "InitialBalance": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "UnlockDuration": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3151" + } + }, + { + "name": "Filecoin.MsigPropose", + "description": "```go\nfunc (s *FullNodeStruct) MsigPropose(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt, p4 address.Address, p5 uint64, p6 []byte) (*MessagePrototype, error) {\n\tif s.Internal.MsigPropose == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigPropose(p0, p1, p2, p3, p4, p5, p6)\n}\n```", + "summary": "MsigPropose proposes a multisig message\nIt takes the following params: \u003cmultisig address\u003e, \u003crecipient address\u003e, \u003cvalue to transfer\u003e,\n\u003csender address of the propose msg\u003e, \u003cmethod to call in the proposed message\u003e, \u003cparams to include in the proposed message\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p6", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3162" + } + }, + { + "name": "Filecoin.MsigRemoveSigner", + "description": "```go\nfunc (s *FullNodeStruct) MsigRemoveSigner(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 bool) (*MessagePrototype, error) {\n\tif s.Internal.MsigRemoveSigner == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigRemoveSigner(p0, p1, p2, p3, p4)\n}\n```", + "summary": "MsigRemoveSigner proposes the removal of a signer from the multisig.\nIt accepts the multisig to make the change on, the proposer address to\nsend the message from, the address to be removed, and a boolean\nindicating whether or not the signing threshold should be lowered by one\nalong with the address removal.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3173" + } + }, + { + "name": "Filecoin.MsigSwapApprove", + "description": "```go\nfunc (s *FullNodeStruct) MsigSwapApprove(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address, p6 address.Address) (*MessagePrototype, error) {\n\tif s.Internal.MsigSwapApprove == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigSwapApprove(p0, p1, p2, p3, p4, p5, p6)\n}\n```", + "summary": "MsigSwapApprove approves a previously proposed SwapSigner\nIt takes the following params: \u003cmultisig address\u003e, \u003csender address of the approve msg\u003e, \u003cproposed message ID\u003e,\n\u003cproposer address\u003e, \u003cold signer\u003e, \u003cnew signer\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p6", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3184" + } + }, + { + "name": "Filecoin.MsigSwapCancel", + "description": "```go\nfunc (s *FullNodeStruct) MsigSwapCancel(p0 context.Context, p1 address.Address, p2 address.Address, p3 uint64, p4 address.Address, p5 address.Address) (*MessagePrototype, error) {\n\tif s.Internal.MsigSwapCancel == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigSwapCancel(p0, p1, p2, p3, p4, p5)\n}\n```", + "summary": "MsigSwapCancel cancels a previously proposed SwapSigner message\nIt takes the following params: \u003cmultisig address\u003e, \u003csender address of the cancel msg\u003e, \u003cproposed message ID\u003e,\n\u003cold signer\u003e, \u003cnew signer\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3195" + } + }, + { + "name": "Filecoin.MsigSwapPropose", + "description": "```go\nfunc (s *FullNodeStruct) MsigSwapPropose(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 address.Address) (*MessagePrototype, error) {\n\tif s.Internal.MsigSwapPropose == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MsigSwapPropose(p0, p1, p2, p3, p4)\n}\n```", + "summary": "MsigSwapPropose proposes swapping 2 signers in the multisig\nIt takes the following params: \u003cmultisig address\u003e, \u003csender address of the propose msg\u003e,\n\u003cold signer\u003e, \u003cnew signer\u003e\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MessagePrototype", + "description": "*MessagePrototype", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "ValidNonce": true + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ValidNonce": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3206" + } + }, + { + "name": "Filecoin.NetListening", + "description": "```go\nfunc (s *FullNodeStruct) NetListening(p0 context.Context) (bool, error) {\n\tif s.Internal.NetListening == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.NetListening(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3217" + } + }, + { + "name": "Filecoin.NetVersion", + "description": "```go\nfunc (s *FullNodeStruct) NetVersion(p0 context.Context) (string, error) {\n\tif s.Internal.NetVersion == nil {\n\t\treturn \"\", ErrNotSupported\n\t}\n\treturn s.Internal.NetVersion(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "string", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3228" + } + }, + { + "name": "Filecoin.NodeStatus", + "description": "```go\nfunc (s *FullNodeStruct) NodeStatus(p0 context.Context, p1 bool) (NodeStatus, error) {\n\tif s.Internal.NodeStatus == nil {\n\t\treturn *new(NodeStatus), ErrNotSupported\n\t}\n\treturn s.Internal.NodeStatus(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "NodeStatus", + "description": "NodeStatus", + "summary": "", + "schema": { + "examples": [ + { + "SyncStatus": { + "Epoch": 42, + "Behind": 42 + }, + "PeerStatus": { + "PeersToPublishMsgs": 123, + "PeersToPublishBlocks": 123 + }, + "ChainStatus": { + "BlocksPerTipsetLast100": 12.3, + "BlocksPerTipsetLastFinality": 12.3 + } + } + ], + "additionalProperties": false, + "properties": { + "ChainStatus": { + "additionalProperties": false, + "properties": { + "BlocksPerTipsetLast100": { + "type": "number" + }, + "BlocksPerTipsetLastFinality": { + "type": "number" + } + }, + "type": "object" + }, + "PeerStatus": { + "additionalProperties": false, + "properties": { + "PeersToPublishBlocks": { + "title": "number", + "type": "number" + }, + "PeersToPublishMsgs": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "SyncStatus": { + "additionalProperties": false, + "properties": { + "Behind": { + "title": "number", + "type": "number" + }, + "Epoch": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3239" + } + }, + { + "name": "Filecoin.PaychAllocateLane", + "description": "```go\nfunc (s *FullNodeStruct) PaychAllocateLane(p0 context.Context, p1 address.Address) (uint64, error) {\n\tif s.Internal.PaychAllocateLane == nil {\n\t\treturn 0, ErrNotSupported\n\t}\n\treturn s.Internal.PaychAllocateLane(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "uint64", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3250" + } + }, + { + "name": "Filecoin.PaychAvailableFunds", + "description": "```go\nfunc (s *FullNodeStruct) PaychAvailableFunds(p0 context.Context, p1 address.Address) (*ChannelAvailableFunds, error) {\n\tif s.Internal.PaychAvailableFunds == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.PaychAvailableFunds(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ChannelAvailableFunds", + "description": "*ChannelAvailableFunds", + "summary": "", + "schema": { + "examples": [ + { + "Channel": "f01234", + "From": "f01234", + "To": "f01234", + "ConfirmedAmt": "0", + "PendingAmt": "0", + "NonReservedAmt": "0", + "PendingAvailableAmt": "0", + "PendingWaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "QueuedAmt": "0", + "VoucherReedeemedAmt": "0" + } + ], + "additionalProperties": false, + "properties": { + "Channel": { + "additionalProperties": false, + "type": "object" + }, + "ConfirmedAmt": { + "additionalProperties": false, + "type": "object" + }, + "From": { + "additionalProperties": false, + "type": "object" + }, + "NonReservedAmt": { + "additionalProperties": false, + "type": "object" + }, + "PendingAmt": { + "additionalProperties": false, + "type": "object" + }, + "PendingAvailableAmt": { + "additionalProperties": false, + "type": "object" + }, + "PendingWaitSentinel": { + "title": "Content Identifier", + "type": "string" + }, + "QueuedAmt": { + "additionalProperties": false, + "type": "object" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "VoucherReedeemedAmt": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3261" + } + }, + { + "name": "Filecoin.PaychAvailableFundsByFromTo", + "description": "```go\nfunc (s *FullNodeStruct) PaychAvailableFundsByFromTo(p0 context.Context, p1 address.Address, p2 address.Address) (*ChannelAvailableFunds, error) {\n\tif s.Internal.PaychAvailableFundsByFromTo == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.PaychAvailableFundsByFromTo(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ChannelAvailableFunds", + "description": "*ChannelAvailableFunds", + "summary": "", + "schema": { + "examples": [ + { + "Channel": "f01234", + "From": "f01234", + "To": "f01234", + "ConfirmedAmt": "0", + "PendingAmt": "0", + "NonReservedAmt": "0", + "PendingAvailableAmt": "0", + "PendingWaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "QueuedAmt": "0", + "VoucherReedeemedAmt": "0" + } + ], + "additionalProperties": false, + "properties": { + "Channel": { + "additionalProperties": false, + "type": "object" + }, + "ConfirmedAmt": { + "additionalProperties": false, + "type": "object" + }, + "From": { + "additionalProperties": false, + "type": "object" + }, + "NonReservedAmt": { + "additionalProperties": false, + "type": "object" + }, + "PendingAmt": { + "additionalProperties": false, + "type": "object" + }, + "PendingAvailableAmt": { + "additionalProperties": false, + "type": "object" + }, + "PendingWaitSentinel": { + "title": "Content Identifier", + "type": "string" + }, + "QueuedAmt": { + "additionalProperties": false, + "type": "object" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "VoucherReedeemedAmt": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3272" + } + }, + { + "name": "Filecoin.PaychCollect", + "description": "```go\nfunc (s *FullNodeStruct) PaychCollect(p0 context.Context, p1 address.Address) (cid.Cid, error) {\n\tif s.Internal.PaychCollect == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.PaychCollect(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3283" + } + }, + { + "name": "Filecoin.PaychFund", + "description": "```go\nfunc (s *FullNodeStruct) PaychFund(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (*ChannelInfo, error) {\n\tif s.Internal.PaychFund == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.PaychFund(p0, p1, p2, p3)\n}\n```", + "summary": "PaychFund gets or creates a payment channel between address pair.\nThe specified amount will be added to the channel through on-chain send for future use\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ChannelInfo", + "description": "*ChannelInfo", + "summary": "", + "schema": { + "examples": [ + { + "Channel": "f01234", + "WaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "Channel": { + "additionalProperties": false, + "type": "object" + }, + "WaitSentinel": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3294" + } + }, + { + "name": "Filecoin.PaychGet", + "description": "```go\nfunc (s *FullNodeStruct) PaychGet(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt, p4 PaychGetOpts) (*ChannelInfo, error) {\n\tif s.Internal.PaychGet == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.PaychGet(p0, p1, p2, p3, p4)\n}\n```", + "summary": "PaychGet gets or creates a payment channel between address pair\n The specified amount will be reserved for use. If there aren't enough non-reserved funds\n available, funds will be added through an on-chain message.\n - When opts.OffChain is true, this call will not cause any messages to be sent to the chain (no automatic\n channel creation/funds adding). If the operation can't be performed without sending a message an error will be\n returned. Note that even when this option is specified, this call can be blocked by previous operations on the\n channel waiting for on-chain operations.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "PaychGetOpts", + "summary": "", + "schema": { + "examples": [ + { + "OffChain": true + } + ], + "additionalProperties": false, + "properties": { + "OffChain": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ChannelInfo", + "description": "*ChannelInfo", + "summary": "", + "schema": { + "examples": [ + { + "Channel": "f01234", + "WaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "Channel": { + "additionalProperties": false, + "type": "object" + }, + "WaitSentinel": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3305" + } + }, + { + "name": "Filecoin.PaychGetWaitReady", + "description": "```go\nfunc (s *FullNodeStruct) PaychGetWaitReady(p0 context.Context, p1 cid.Cid) (address.Address, error) {\n\tif s.Internal.PaychGetWaitReady == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.PaychGetWaitReady(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3316" + } + }, + { + "name": "Filecoin.PaychList", + "description": "```go\nfunc (s *FullNodeStruct) PaychList(p0 context.Context) ([]address.Address, error) {\n\tif s.Internal.PaychList == nil {\n\t\treturn *new([]address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.PaychList(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]address.Address", + "description": "[]address.Address", + "summary": "", + "schema": { + "examples": [ + [ + "f01234" + ] + ], + "items": [ + { + "additionalProperties": false, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3327" + } + }, + { + "name": "Filecoin.PaychNewPayment", + "description": "```go\nfunc (s *FullNodeStruct) PaychNewPayment(p0 context.Context, p1 address.Address, p2 address.Address, p3 []VoucherSpec) (*PaymentInfo, error) {\n\tif s.Internal.PaychNewPayment == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.PaychNewPayment(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]VoucherSpec", + "summary": "", + "schema": { + "examples": [ + [ + { + "Amount": "0", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "MinSettle": 10101, + "Extra": { + "Actor": "f01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Amount": { + "additionalProperties": false, + "type": "object" + }, + "Extra": { + "additionalProperties": false, + "properties": { + "Actor": { + "additionalProperties": false, + "type": "object" + }, + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Method": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "MinSettle": { + "title": "number", + "type": "number" + }, + "TimeLockMax": { + "title": "number", + "type": "number" + }, + "TimeLockMin": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*PaymentInfo", + "description": "*PaymentInfo", + "summary": "", + "schema": { + "examples": [ + { + "Channel": "f01234", + "WaitSentinel": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Vouchers": [ + { + "ChannelAddr": "f01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretHash": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "f01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": [ + { + "Lane": 42, + "Nonce": 42 + } + ], + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } + ] + } + ], + "additionalProperties": false, + "properties": { + "Channel": { + "additionalProperties": false, + "type": "object" + }, + "Vouchers": { + "items": { + "additionalProperties": false, + "properties": { + "Amount": { + "additionalProperties": false, + "type": "object" + }, + "ChannelAddr": { + "additionalProperties": false, + "type": "object" + }, + "Extra": { + "additionalProperties": false, + "properties": { + "Actor": { + "additionalProperties": false, + "type": "object" + }, + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Method": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Lane": { + "title": "number", + "type": "number" + }, + "Merges": { + "items": { + "additionalProperties": false, + "properties": { + "Lane": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "MinSettleHeight": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "SecretHash": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "TimeLockMax": { + "title": "number", + "type": "number" + }, + "TimeLockMin": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "WaitSentinel": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3338" + } + }, + { + "name": "Filecoin.PaychSettle", + "description": "```go\nfunc (s *FullNodeStruct) PaychSettle(p0 context.Context, p1 address.Address) (cid.Cid, error) {\n\tif s.Internal.PaychSettle == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.PaychSettle(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3349" + } + }, + { + "name": "Filecoin.PaychStatus", + "description": "```go\nfunc (s *FullNodeStruct) PaychStatus(p0 context.Context, p1 address.Address) (*PaychStatus, error) {\n\tif s.Internal.PaychStatus == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.PaychStatus(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*PaychStatus", + "description": "*PaychStatus", + "summary": "", + "schema": { + "examples": [ + { + "ControlAddr": "f01234", + "Direction": 1 + } + ], + "additionalProperties": false, + "properties": { + "ControlAddr": { + "additionalProperties": false, + "type": "object" + }, + "Direction": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3360" + } + }, + { + "name": "Filecoin.PaychVoucherAdd", + "description": "```go\nfunc (s *FullNodeStruct) PaychVoucherAdd(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 types.BigInt) (types.BigInt, error) {\n\tif s.Internal.PaychVoucherAdd == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.PaychVoucherAdd(p0, p1, p2, p3, p4)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*paych.SignedVoucher", + "summary": "", + "schema": { + "examples": [ + { + "ChannelAddr": "f01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretHash": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "f01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": [ + { + "Lane": 42, + "Nonce": 42 + } + ], + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } + ], + "additionalProperties": false, + "properties": { + "Amount": { + "additionalProperties": false, + "type": "object" + }, + "ChannelAddr": { + "additionalProperties": false, + "type": "object" + }, + "Extra": { + "additionalProperties": false, + "properties": { + "Actor": { + "additionalProperties": false, + "type": "object" + }, + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Method": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Lane": { + "title": "number", + "type": "number" + }, + "Merges": { + "items": { + "additionalProperties": false, + "properties": { + "Lane": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "MinSettleHeight": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "SecretHash": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "TimeLockMax": { + "title": "number", + "type": "number" + }, + "TimeLockMin": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3371" + } + }, + { + "name": "Filecoin.PaychVoucherCheckSpendable", + "description": "```go\nfunc (s *FullNodeStruct) PaychVoucherCheckSpendable(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (bool, error) {\n\tif s.Internal.PaychVoucherCheckSpendable == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.PaychVoucherCheckSpendable(p0, p1, p2, p3, p4)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*paych.SignedVoucher", + "summary": "", + "schema": { + "examples": [ + { + "ChannelAddr": "f01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretHash": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "f01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": [ + { + "Lane": 42, + "Nonce": 42 + } + ], + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } + ], + "additionalProperties": false, + "properties": { + "Amount": { + "additionalProperties": false, + "type": "object" + }, + "ChannelAddr": { + "additionalProperties": false, + "type": "object" + }, + "Extra": { + "additionalProperties": false, + "properties": { + "Actor": { + "additionalProperties": false, + "type": "object" + }, + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Method": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Lane": { + "title": "number", + "type": "number" + }, + "Merges": { + "items": { + "additionalProperties": false, + "properties": { + "Lane": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "MinSettleHeight": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "SecretHash": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "TimeLockMax": { + "title": "number", + "type": "number" + }, + "TimeLockMin": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3382" + } + }, + { + "name": "Filecoin.PaychVoucherCheckValid", + "description": "```go\nfunc (s *FullNodeStruct) PaychVoucherCheckValid(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher) error {\n\tif s.Internal.PaychVoucherCheckValid == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.PaychVoucherCheckValid(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*paych.SignedVoucher", + "summary": "", + "schema": { + "examples": [ + { + "ChannelAddr": "f01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretHash": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "f01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": [ + { + "Lane": 42, + "Nonce": 42 + } + ], + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } + ], + "additionalProperties": false, + "properties": { + "Amount": { + "additionalProperties": false, + "type": "object" + }, + "ChannelAddr": { + "additionalProperties": false, + "type": "object" + }, + "Extra": { + "additionalProperties": false, + "properties": { + "Actor": { + "additionalProperties": false, + "type": "object" + }, + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Method": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Lane": { + "title": "number", + "type": "number" + }, + "Merges": { + "items": { + "additionalProperties": false, + "properties": { + "Lane": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "MinSettleHeight": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "SecretHash": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "TimeLockMax": { + "title": "number", + "type": "number" + }, + "TimeLockMin": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3393" + } + }, + { + "name": "Filecoin.PaychVoucherCreate", + "description": "```go\nfunc (s *FullNodeStruct) PaychVoucherCreate(p0 context.Context, p1 address.Address, p2 types.BigInt, p3 uint64) (*VoucherCreateResult, error) {\n\tif s.Internal.PaychVoucherCreate == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.PaychVoucherCreate(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*VoucherCreateResult", + "description": "*VoucherCreateResult", + "summary": "", + "schema": { + "examples": [ + { + "Voucher": { + "ChannelAddr": "f01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretHash": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "f01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": [ + { + "Lane": 42, + "Nonce": 42 + } + ], + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + }, + "Shortfall": "0" + } + ], + "additionalProperties": false, + "properties": { + "Shortfall": { + "additionalProperties": false, + "type": "object" + }, + "Voucher": { + "additionalProperties": false, + "properties": { + "Amount": { + "additionalProperties": false, + "type": "object" + }, + "ChannelAddr": { + "additionalProperties": false, + "type": "object" + }, + "Extra": { + "additionalProperties": false, + "properties": { + "Actor": { + "additionalProperties": false, + "type": "object" + }, + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Method": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Lane": { + "title": "number", + "type": "number" + }, + "Merges": { + "items": { + "additionalProperties": false, + "properties": { + "Lane": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "MinSettleHeight": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "SecretHash": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "TimeLockMax": { + "title": "number", + "type": "number" + }, + "TimeLockMin": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3404" + } + }, + { + "name": "Filecoin.PaychVoucherList", + "description": "```go\nfunc (s *FullNodeStruct) PaychVoucherList(p0 context.Context, p1 address.Address) ([]*paych.SignedVoucher, error) {\n\tif s.Internal.PaychVoucherList == nil {\n\t\treturn *new([]*paych.SignedVoucher), ErrNotSupported\n\t}\n\treturn s.Internal.PaychVoucherList(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*paych.SignedVoucher", + "description": "[]*paych.SignedVoucher", + "summary": "", + "schema": { + "examples": [ + [ + { + "ChannelAddr": "f01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretHash": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "f01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": [ + { + "Lane": 42, + "Nonce": 42 + } + ], + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Amount": { + "additionalProperties": false, + "type": "object" + }, + "ChannelAddr": { + "additionalProperties": false, + "type": "object" + }, + "Extra": { + "additionalProperties": false, + "properties": { + "Actor": { + "additionalProperties": false, + "type": "object" + }, + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Method": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Lane": { + "title": "number", + "type": "number" + }, + "Merges": { + "items": { + "additionalProperties": false, + "properties": { + "Lane": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "MinSettleHeight": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "SecretHash": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "TimeLockMax": { + "title": "number", + "type": "number" + }, + "TimeLockMin": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3415" + } + }, + { + "name": "Filecoin.PaychVoucherSubmit", + "description": "```go\nfunc (s *FullNodeStruct) PaychVoucherSubmit(p0 context.Context, p1 address.Address, p2 *paych.SignedVoucher, p3 []byte, p4 []byte) (cid.Cid, error) {\n\tif s.Internal.PaychVoucherSubmit == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.PaychVoucherSubmit(p0, p1, p2, p3, p4)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*paych.SignedVoucher", + "summary": "", + "schema": { + "examples": [ + { + "ChannelAddr": "f01234", + "TimeLockMin": 10101, + "TimeLockMax": 10101, + "SecretHash": "Ynl0ZSBhcnJheQ==", + "Extra": { + "Actor": "f01234", + "Method": 1, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Lane": 42, + "Nonce": 42, + "Amount": "0", + "MinSettleHeight": 10101, + "Merges": [ + { + "Lane": 42, + "Nonce": 42 + } + ], + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } + ], + "additionalProperties": false, + "properties": { + "Amount": { + "additionalProperties": false, + "type": "object" + }, + "ChannelAddr": { + "additionalProperties": false, + "type": "object" + }, + "Extra": { + "additionalProperties": false, + "properties": { + "Actor": { + "additionalProperties": false, + "type": "object" + }, + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Method": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Lane": { + "title": "number", + "type": "number" + }, + "Merges": { + "items": { + "additionalProperties": false, + "properties": { + "Lane": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "MinSettleHeight": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "SecretHash": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "TimeLockMax": { + "title": "number", + "type": "number" + }, + "TimeLockMin": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3426" + } + }, + { + "name": "Filecoin.StateAccountKey", + "description": "```go\nfunc (s *FullNodeStruct) StateAccountKey(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) {\n\tif s.Internal.StateAccountKey == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.StateAccountKey(p0, p1, p2)\n}\n```", + "summary": "StateAccountKey returns the public key address of the given ID address for secp and bls accounts\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3437" + } + }, + { + "name": "Filecoin.StateActorCodeCIDs", + "description": "```go\nfunc (s *FullNodeStruct) StateActorCodeCIDs(p0 context.Context, p1 abinetwork.Version) (map[string]cid.Cid, error) {\n\tif s.Internal.StateActorCodeCIDs == nil {\n\t\treturn *new(map[string]cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.StateActorCodeCIDs(p0, p1)\n}\n```", + "summary": "StateActorCodeCIDs returns the CIDs of all the builtin actors for the given network version\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abinetwork.Version", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 22 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[string]cid.Cid", + "description": "map[string]cid.Cid", + "summary": "", + "schema": { + "examples": [ + {} + ], + "patternProperties": { + ".*": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3448" + } + }, + { + "name": "Filecoin.StateActorManifestCID", + "description": "```go\nfunc (s *FullNodeStruct) StateActorManifestCID(p0 context.Context, p1 abinetwork.Version) (cid.Cid, error) {\n\tif s.Internal.StateActorManifestCID == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.StateActorManifestCID(p0, p1)\n}\n```", + "summary": "StateActorManifestCID returns the CID of the builtin actors manifest for the given network version\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abinetwork.Version", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 22 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3459" + } + }, + { + "name": "Filecoin.StateAllMinerFaults", + "description": "```go\nfunc (s *FullNodeStruct) StateAllMinerFaults(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) ([]*Fault, error) {\n\tif s.Internal.StateAllMinerFaults == nil {\n\t\treturn *new([]*Fault), ErrNotSupported\n\t}\n\treturn s.Internal.StateAllMinerFaults(p0, p1, p2)\n}\n```", + "summary": "StateAllMinerFaults returns all non-expired Faults that occur within lookback epochs of the given tipset\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*Fault", + "description": "[]*Fault", + "summary": "", + "schema": { + "examples": [ + [ + { + "Miner": "f01234", + "Epoch": 10101 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Epoch": { + "title": "number", + "type": "number" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3470" + } + }, + { + "name": "Filecoin.StateCall", + "description": "```go\nfunc (s *FullNodeStruct) StateCall(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (*InvocResult, error) {\n\tif s.Internal.StateCall == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateCall(p0, p1, p2)\n}\n```", + "summary": "StateCall runs the given message and returns its result without any persisted changes.\n\nStateCall applies the message to the tipset's parent state. The\nmessage is not applied on-top-of the messages in the passed-in\ntipset.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*InvocResult", + "description": "*InvocResult", + "summary": "", + "schema": { + "examples": [ + { + "MsgCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Msg": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "GasCost": { + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "GasUsed": "0", + "BaseFeeBurn": "0", + "OverEstimationBurn": "0", + "MinerPenalty": "0", + "MinerTip": "0", + "Refund": "0", + "TotalCost": "0" + }, + "ExecutionTrace": { + "Msg": { + "From": "f01234", + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "ParamsCodec": 42, + "GasLimit": 42, + "ReadOnly": true + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "ReturnCodec": 42 + }, + "InvokedActor": { + "Id": 1000, + "State": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + }, + "GasCharges": [ + { + "Name": "string value", + "tg": 9, + "cg": 9, + "sg": 9, + "tt": 60000000000 + } + ], + "Subcalls": [ + { + "Msg": { + "From": "f01234", + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "ParamsCodec": 42, + "GasLimit": 42, + "ReadOnly": true + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "ReturnCodec": 42 + }, + "InvokedActor": { + "Id": 1000, + "State": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + }, + "GasCharges": [ + { + "Name": "string value", + "tg": 9, + "cg": 9, + "sg": 9, + "tt": 60000000000 + } + ], + "Subcalls": null + } + ] + }, + "Error": "string value", + "Duration": 60000000000 + } + ], + "additionalProperties": false, + "properties": { + "Duration": { + "title": "number", + "type": "number" + }, + "Error": { + "type": "string" + }, + "ExecutionTrace": { + "additionalProperties": false, + "properties": { + "GasCharges": { + "items": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "cg": { + "title": "number", + "type": "number" + }, + "sg": { + "title": "number", + "type": "number" + }, + "tg": { + "title": "number", + "type": "number" + }, + "tt": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "InvokedActor": { + "additionalProperties": false, + "properties": { + "Id": { + "title": "number", + "type": "number" + }, + "State": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Balance": { + "additionalProperties": false, + "type": "object" + }, + "Code": { + "title": "Content Identifier", + "type": "string" + }, + "Head": { + "title": "Content Identifier", + "type": "string" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Msg": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ParamsCodec": { + "title": "number", + "type": "number" + }, + "ReadOnly": { + "type": "boolean" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "MsgRct": { + "additionalProperties": false, + "properties": { + "ExitCode": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ReturnCodec": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Subcalls": { + "items": {}, + "type": "array" + } + }, + "type": "object" + }, + "GasCost": { + "additionalProperties": false, + "properties": { + "BaseFeeBurn": { + "additionalProperties": false, + "type": "object" + }, + "GasUsed": { + "additionalProperties": false, + "type": "object" + }, + "Message": { + "title": "Content Identifier", + "type": "string" + }, + "MinerPenalty": { + "additionalProperties": false, + "type": "object" + }, + "MinerTip": { + "additionalProperties": false, + "type": "object" + }, + "OverEstimationBurn": { + "additionalProperties": false, + "type": "object" + }, + "Refund": { + "additionalProperties": false, + "type": "object" + }, + "TotalCost": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "Msg": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "MsgCid": { + "title": "Content Identifier", + "type": "string" + }, + "MsgRct": { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3481" + } + }, + { + "name": "Filecoin.StateChangedActors", + "description": "```go\nfunc (s *FullNodeStruct) StateChangedActors(p0 context.Context, p1 cid.Cid, p2 cid.Cid) (map[string]types.Actor, error) {\n\tif s.Internal.StateChangedActors == nil {\n\t\treturn *new(map[string]types.Actor), ErrNotSupported\n\t}\n\treturn s.Internal.StateChangedActors(p0, p1, p2)\n}\n```", + "summary": "StateChangedActors returns all the actors whose states change between the two given state CIDs\nTODO: Should this take tipset keys instead?\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[string]types.Actor", + "description": "map[string]types.Actor", + "summary": "", + "schema": { + "examples": [ + { + "t01236": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + } + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Balance": { + "additionalProperties": false, + "type": "object" + }, + "Code": { + "title": "Content Identifier", + "type": "string" + }, + "Head": { + "title": "Content Identifier", + "type": "string" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3492" + } + }, + { + "name": "Filecoin.StateCirculatingSupply", + "description": "```go\nfunc (s *FullNodeStruct) StateCirculatingSupply(p0 context.Context, p1 types.TipSetKey) (abi.TokenAmount, error) {\n\tif s.Internal.StateCirculatingSupply == nil {\n\t\treturn *new(abi.TokenAmount), ErrNotSupported\n\t}\n\treturn s.Internal.StateCirculatingSupply(p0, p1)\n}\n```", + "summary": "StateCirculatingSupply returns the exact circulating supply of Filecoin at the given tipset.\nThis is not used anywhere in the protocol itself, and is only for external consumption.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "abi.TokenAmount", + "description": "abi.TokenAmount", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3503" + } + }, + { + "name": "Filecoin.StateCompute", + "description": "```go\nfunc (s *FullNodeStruct) StateCompute(p0 context.Context, p1 abi.ChainEpoch, p2 []*types.Message, p3 types.TipSetKey) (*ComputeStateOutput, error) {\n\tif s.Internal.StateCompute == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateCompute(p0, p1, p2, p3)\n}\n```", + "summary": "StateCompute is a flexible command that applies the given messages on the given tipset.\nThe messages are run as though the VM were at the provided height.\n\nWhen called, StateCompute will:\n- Load the provided tipset, or use the current chain head if not provided\n- Compute the tipset state of the provided tipset on top of the parent state\n - (note that this step runs before vmheight is applied to the execution)\n - Execute state upgrade if any were scheduled at the epoch, or in null\n blocks preceding the tipset\n - Call the cron actor on null blocks preceding the tipset\n - For each block in the tipset\n - Apply messages in blocks in the specified\n - Award block reward by calling the reward actor\n - Call the cron actor for the current epoch\n- If the specified vmheight is higher than the current epoch, apply any\n needed state upgrades to the state\n- Apply the specified messages to the state\n\nThe vmheight parameter sets VM execution epoch, and can be used to simulate\nmessage execution in different network versions. If the specified vmheight\nepoch is higher than the epoch of the specified tipset, any state upgrades\nuntil the vmheight will be executed on the state before applying messages\nspecified by the user.\n\nNote that the initial tipset state computation is not affected by the\nvmheight parameter - only the messages in the `apply` set are\n\nIf the caller wants to simply compute the state, vmheight should be set to\nthe epoch of the specified tipset.\n\nMessages in the `apply` parameter must have the correct nonces, and gas\nvalues set.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "[]*types.Message", + "summary": "", + "schema": { + "examples": [ + [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ComputeStateOutput", + "description": "*ComputeStateOutput", + "summary": "", + "schema": { + "examples": [ + { + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Trace": [ + { + "MsgCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Msg": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "GasCost": { + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "GasUsed": "0", + "BaseFeeBurn": "0", + "OverEstimationBurn": "0", + "MinerPenalty": "0", + "MinerTip": "0", + "Refund": "0", + "TotalCost": "0" + }, + "ExecutionTrace": { + "Msg": { + "From": "f01234", + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "ParamsCodec": 42, + "GasLimit": 42, + "ReadOnly": true + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "ReturnCodec": 42 + }, + "InvokedActor": { + "Id": 1000, + "State": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + }, + "GasCharges": [ + { + "Name": "string value", + "tg": 9, + "cg": 9, + "sg": 9, + "tt": 60000000000 + } + ], + "Subcalls": [ + { + "Msg": { + "From": "f01234", + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "ParamsCodec": 42, + "GasLimit": 42, + "ReadOnly": true + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "ReturnCodec": 42 + }, + "InvokedActor": { + "Id": 1000, + "State": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + }, + "GasCharges": [ + { + "Name": "string value", + "tg": 9, + "cg": 9, + "sg": 9, + "tt": 60000000000 + } + ], + "Subcalls": null + } + ] + }, + "Error": "string value", + "Duration": 60000000000 + } + ] + } + ], + "additionalProperties": false, + "properties": { + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "Trace": { + "items": { + "additionalProperties": false, + "properties": { + "Duration": { + "title": "number", + "type": "number" + }, + "Error": { + "type": "string" + }, + "ExecutionTrace": { + "additionalProperties": false, + "properties": { + "GasCharges": { + "items": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "cg": { + "title": "number", + "type": "number" + }, + "sg": { + "title": "number", + "type": "number" + }, + "tg": { + "title": "number", + "type": "number" + }, + "tt": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "InvokedActor": { + "additionalProperties": false, + "properties": { + "Id": { + "title": "number", + "type": "number" + }, + "State": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Balance": { + "additionalProperties": false, + "type": "object" + }, + "Code": { + "title": "Content Identifier", + "type": "string" + }, + "Head": { + "title": "Content Identifier", + "type": "string" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Msg": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ParamsCodec": { + "title": "number", + "type": "number" + }, + "ReadOnly": { + "type": "boolean" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "MsgRct": { + "additionalProperties": false, + "properties": { + "ExitCode": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ReturnCodec": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Subcalls": { + "items": {}, + "type": "array" + } + }, + "type": "object" + }, + "GasCost": { + "additionalProperties": false, + "properties": { + "BaseFeeBurn": { + "additionalProperties": false, + "type": "object" + }, + "GasUsed": { + "additionalProperties": false, + "type": "object" + }, + "Message": { + "title": "Content Identifier", + "type": "string" + }, + "MinerPenalty": { + "additionalProperties": false, + "type": "object" + }, + "MinerTip": { + "additionalProperties": false, + "type": "object" + }, + "OverEstimationBurn": { + "additionalProperties": false, + "type": "object" + }, + "Refund": { + "additionalProperties": false, + "type": "object" + }, + "TotalCost": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "Msg": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "MsgCid": { + "title": "Content Identifier", + "type": "string" + }, + "MsgRct": { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3514" + } + }, + { + "name": "Filecoin.StateComputeDataCID", + "description": "```go\nfunc (s *FullNodeStruct) StateComputeDataCID(p0 context.Context, p1 address.Address, p2 abi.RegisteredSealProof, p3 []abi.DealID, p4 types.TipSetKey) (cid.Cid, error) {\n\tif s.Internal.StateComputeDataCID == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.StateComputeDataCID(p0, p1, p2, p3, p4)\n}\n```", + "summary": "StateComputeDataCID computes DataCID from a set of on-chain deals\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.RegisteredSealProof", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 8 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]abi.DealID", + "summary": "", + "schema": { + "examples": [ + [ + 5432 + ] + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3525" + } + }, + { + "name": "Filecoin.StateDealProviderCollateralBounds", + "description": "```go\nfunc (s *FullNodeStruct) StateDealProviderCollateralBounds(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (DealCollateralBounds, error) {\n\tif s.Internal.StateDealProviderCollateralBounds == nil {\n\t\treturn *new(DealCollateralBounds), ErrNotSupported\n\t}\n\treturn s.Internal.StateDealProviderCollateralBounds(p0, p1, p2, p3)\n}\n```", + "summary": "StateDealProviderCollateralBounds returns the min and max collateral a storage provider\ncan issue. It takes the deal size and verified status as parameters.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.PaddedPieceSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1032 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "DealCollateralBounds", + "description": "DealCollateralBounds", + "summary": "", + "schema": { + "examples": [ + { + "Min": "0", + "Max": "0" + } + ], + "additionalProperties": false, + "properties": { + "Max": { + "additionalProperties": false, + "type": "object" + }, + "Min": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3536" + } + }, + { + "name": "Filecoin.StateDecodeParams", + "description": "```go\nfunc (s *FullNodeStruct) StateDecodeParams(p0 context.Context, p1 address.Address, p2 abi.MethodNum, p3 []byte, p4 types.TipSetKey) (interface{}, error) {\n\tif s.Internal.StateDecodeParams == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateDecodeParams(p0, p1, p2, p3, p4)\n}\n```", + "summary": "StateDecodeParams attempts to decode the provided params, based on the recipient actor address and method number.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.MethodNum", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "interface{}", + "description": "interface{}", + "summary": "", + "schema": { + "examples": [ + {} + ], + "additionalProperties": true, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3547" + } + }, + { + "name": "Filecoin.StateEncodeParams", + "description": "```go\nfunc (s *FullNodeStruct) StateEncodeParams(p0 context.Context, p1 cid.Cid, p2 abi.MethodNum, p3 json.RawMessage) ([]byte, error) {\n\tif s.Internal.StateEncodeParams == nil {\n\t\treturn *new([]byte), ErrNotSupported\n\t}\n\treturn s.Internal.StateEncodeParams(p0, p1, p2, p3)\n}\n```", + "summary": "StateEncodeParams attempts to encode the provided json params to the binary from\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.MethodNum", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "json.RawMessage", + "summary": "", + "schema": { + "examples": [ + "json raw message" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]byte", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3558" + } + }, + { + "name": "Filecoin.StateGetActor", + "description": "```go\nfunc (s *FullNodeStruct) StateGetActor(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) {\n\tif s.Internal.StateGetActor == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateGetActor(p0, p1, p2)\n}\n```", + "summary": "StateGetActor returns the indicated actor's nonce and balance.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.Actor", + "description": "*types.Actor", + "summary": "", + "schema": { + "examples": [ + { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + ], + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Balance": { + "additionalProperties": false, + "type": "object" + }, + "Code": { + "title": "Content Identifier", + "type": "string" + }, + "Head": { + "title": "Content Identifier", + "type": "string" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3569" + } + }, + { + "name": "Filecoin.StateGetAllAllocations", + "description": "```go\nfunc (s *FullNodeStruct) StateGetAllAllocations(p0 context.Context, p1 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) {\n\tif s.Internal.StateGetAllAllocations == nil {\n\t\treturn *new(map[verifregtypes.AllocationId]verifregtypes.Allocation), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetAllAllocations(p0, p1)\n}\n```", + "summary": "StateGetAllAllocations returns the all the allocations available in verified registry actor.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[verifregtypes.AllocationId]verifregtypes.Allocation", + "description": "map[verifregtypes.AllocationId]verifregtypes.Allocation", + "summary": "", + "schema": { + "examples": [ + {} + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3580" + } + }, + { + "name": "Filecoin.StateGetAllClaims", + "description": "```go\nfunc (s *FullNodeStruct) StateGetAllClaims(p0 context.Context, p1 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) {\n\tif s.Internal.StateGetAllClaims == nil {\n\t\treturn *new(map[verifregtypes.ClaimId]verifregtypes.Claim), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetAllClaims(p0, p1)\n}\n```", + "summary": "StateGetAllClaims returns the all the claims available in verified registry actor.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[verifregtypes.ClaimId]verifregtypes.Claim", + "description": "map[verifregtypes.ClaimId]verifregtypes.Claim", + "summary": "", + "schema": { + "examples": [ + {} + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Sector": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + }, + "TermStart": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3591" + } + }, + { + "name": "Filecoin.StateGetAllocation", + "description": "```go\nfunc (s *FullNodeStruct) StateGetAllocation(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) {\n\tif s.Internal.StateGetAllocation == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateGetAllocation(p0, p1, p2, p3)\n}\n```", + "summary": "StateGetAllocation returns the allocation for a given address and allocation ID.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "verifregtypes.AllocationId", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 0 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*verifregtypes.Allocation", + "description": "*verifregtypes.Allocation", + "summary": "", + "schema": { + "examples": [ + { + "Client": 1000, + "Provider": 1000, + "Data": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 1032, + "TermMin": 10101, + "TermMax": 10101, + "Expiration": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3602" + } + }, + { + "name": "Filecoin.StateGetAllocationForPendingDeal", + "description": "```go\nfunc (s *FullNodeStruct) StateGetAllocationForPendingDeal(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) {\n\tif s.Internal.StateGetAllocationForPendingDeal == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateGetAllocationForPendingDeal(p0, p1, p2)\n}\n```", + "summary": "StateGetAllocationForPendingDeal returns the allocation for a given deal ID of a pending deal. Returns nil if\npending allocation is not found.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.DealID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 5432 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*verifregtypes.Allocation", + "description": "*verifregtypes.Allocation", + "summary": "", + "schema": { + "examples": [ + { + "Client": 1000, + "Provider": 1000, + "Data": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 1032, + "TermMin": 10101, + "TermMax": 10101, + "Expiration": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3613" + } + }, + { + "name": "Filecoin.StateGetAllocationIdForPendingDeal", + "description": "```go\nfunc (s *FullNodeStruct) StateGetAllocationIdForPendingDeal(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (verifreg.AllocationId, error) {\n\tif s.Internal.StateGetAllocationIdForPendingDeal == nil {\n\t\treturn *new(verifreg.AllocationId), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetAllocationIdForPendingDeal(p0, p1, p2)\n}\n```", + "summary": "StateGetAllocationIdForPendingDeal is like StateGetAllocationForPendingDeal except it returns the allocation ID\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.DealID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 5432 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "verifreg.AllocationId", + "description": "verifreg.AllocationId", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 0 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3624" + } + }, + { + "name": "Filecoin.StateGetAllocations", + "description": "```go\nfunc (s *FullNodeStruct) StateGetAllocations(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) {\n\tif s.Internal.StateGetAllocations == nil {\n\t\treturn *new(map[verifregtypes.AllocationId]verifregtypes.Allocation), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetAllocations(p0, p1, p2)\n}\n```", + "summary": "StateGetAllocations returns the all the allocations for a given client.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[verifregtypes.AllocationId]verifregtypes.Allocation", + "description": "map[verifregtypes.AllocationId]verifregtypes.Allocation", + "summary": "", + "schema": { + "examples": [ + {} + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3635" + } + }, + { + "name": "Filecoin.StateGetBeaconEntry", + "description": "```go\nfunc (s *FullNodeStruct) StateGetBeaconEntry(p0 context.Context, p1 abi.ChainEpoch) (*types.BeaconEntry, error) {\n\tif s.Internal.StateGetBeaconEntry == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateGetBeaconEntry(p0, p1)\n}\n```", + "summary": "StateGetBeaconEntry returns the beacon entry for the given filecoin epoch. If\nthe entry has not yet been produced, the call will block until the entry\nbecomes available\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.BeaconEntry", + "description": "*types.BeaconEntry", + "summary": "", + "schema": { + "examples": [ + { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + } + ], + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Round": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3646" + } + }, + { + "name": "Filecoin.StateGetClaim", + "description": "```go\nfunc (s *FullNodeStruct) StateGetClaim(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) {\n\tif s.Internal.StateGetClaim == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateGetClaim(p0, p1, p2, p3)\n}\n```", + "summary": "StateGetClaim returns the claim for a given address and claim ID.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "verifregtypes.ClaimId", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 0 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*verifregtypes.Claim", + "description": "*verifregtypes.Claim", + "summary": "", + "schema": { + "examples": [ + { + "Provider": 1000, + "Client": 1000, + "Data": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 1032, + "TermMin": 10101, + "TermMax": 10101, + "TermStart": 10101, + "Sector": 9 + } + ], + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Sector": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + }, + "TermStart": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3657" + } + }, + { + "name": "Filecoin.StateGetClaims", + "description": "```go\nfunc (s *FullNodeStruct) StateGetClaims(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) {\n\tif s.Internal.StateGetClaims == nil {\n\t\treturn *new(map[verifregtypes.ClaimId]verifregtypes.Claim), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetClaims(p0, p1, p2)\n}\n```", + "summary": "StateGetClaims returns the all the claims for a given provider.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[verifregtypes.ClaimId]verifregtypes.Claim", + "description": "map[verifregtypes.ClaimId]verifregtypes.Claim", + "summary": "", + "schema": { + "examples": [ + {} + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Sector": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + }, + "TermStart": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3668" + } + }, + { + "name": "Filecoin.StateGetNetworkParams", + "description": "```go\nfunc (s *FullNodeStruct) StateGetNetworkParams(p0 context.Context) (*NetworkParams, error) {\n\tif s.Internal.StateGetNetworkParams == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateGetNetworkParams(p0)\n}\n```", + "summary": "StateGetNetworkParams return current network params\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*NetworkParams", + "description": "*NetworkParams", + "summary": "", + "schema": { + "examples": [ + { + "NetworkName": "lotus", + "BlockDelaySecs": 42, + "ConsensusMinerMinPower": "0", + "SupportedProofTypes": [ + 8 + ], + "PreCommitChallengeDelay": 10101, + "ForkUpgradeParams": { + "UpgradeSmokeHeight": 10101, + "UpgradeBreezeHeight": 10101, + "UpgradeIgnitionHeight": 10101, + "UpgradeLiftoffHeight": 10101, + "UpgradeAssemblyHeight": 10101, + "UpgradeRefuelHeight": 10101, + "UpgradeTapeHeight": 10101, + "UpgradeKumquatHeight": 10101, + "BreezeGasTampingDuration": 10101, + "UpgradeCalicoHeight": 10101, + "UpgradePersianHeight": 10101, + "UpgradeOrangeHeight": 10101, + "UpgradeClausHeight": 10101, + "UpgradeTrustHeight": 10101, + "UpgradeNorwegianHeight": 10101, + "UpgradeTurboHeight": 10101, + "UpgradeHyperdriveHeight": 10101, + "UpgradeChocolateHeight": 10101, + "UpgradeOhSnapHeight": 10101, + "UpgradeSkyrHeight": 10101, + "UpgradeSharkHeight": 10101, + "UpgradeHyggeHeight": 10101, + "UpgradeLightningHeight": 10101, + "UpgradeThunderHeight": 10101, + "UpgradeWatermelonHeight": 10101, + "UpgradeDragonHeight": 10101, + "UpgradePhoenixHeight": 10101 + }, + "Eip155ChainID": 123 + } + ], + "additionalProperties": false, + "properties": { + "BlockDelaySecs": { + "title": "number", + "type": "number" + }, + "ConsensusMinerMinPower": { + "additionalProperties": false, + "type": "object" + }, + "Eip155ChainID": { + "title": "number", + "type": "number" + }, + "ForkUpgradeParams": { + "additionalProperties": false, + "properties": { + "BreezeGasTampingDuration": { + "title": "number", + "type": "number" + }, + "UpgradeAssemblyHeight": { + "title": "number", + "type": "number" + }, + "UpgradeBreezeHeight": { + "title": "number", + "type": "number" + }, + "UpgradeCalicoHeight": { + "title": "number", + "type": "number" + }, + "UpgradeChocolateHeight": { + "title": "number", + "type": "number" + }, + "UpgradeClausHeight": { + "title": "number", + "type": "number" + }, + "UpgradeDragonHeight": { + "title": "number", + "type": "number" + }, + "UpgradeHyggeHeight": { + "title": "number", + "type": "number" + }, + "UpgradeHyperdriveHeight": { + "title": "number", + "type": "number" + }, + "UpgradeIgnitionHeight": { + "title": "number", + "type": "number" + }, + "UpgradeKumquatHeight": { + "title": "number", + "type": "number" + }, + "UpgradeLiftoffHeight": { + "title": "number", + "type": "number" + }, + "UpgradeLightningHeight": { + "title": "number", + "type": "number" + }, + "UpgradeNorwegianHeight": { + "title": "number", + "type": "number" + }, + "UpgradeOhSnapHeight": { + "title": "number", + "type": "number" + }, + "UpgradeOrangeHeight": { + "title": "number", + "type": "number" + }, + "UpgradePersianHeight": { + "title": "number", + "type": "number" + }, + "UpgradePhoenixHeight": { + "title": "number", + "type": "number" + }, + "UpgradeRefuelHeight": { + "title": "number", + "type": "number" + }, + "UpgradeSharkHeight": { + "title": "number", + "type": "number" + }, + "UpgradeSkyrHeight": { + "title": "number", + "type": "number" + }, + "UpgradeSmokeHeight": { + "title": "number", + "type": "number" + }, + "UpgradeTapeHeight": { + "title": "number", + "type": "number" + }, + "UpgradeThunderHeight": { + "title": "number", + "type": "number" + }, + "UpgradeTrustHeight": { + "title": "number", + "type": "number" + }, + "UpgradeTurboHeight": { + "title": "number", + "type": "number" + }, + "UpgradeWatermelonHeight": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "NetworkName": { + "type": "string" + }, + "PreCommitChallengeDelay": { + "title": "number", + "type": "number" + }, + "SupportedProofTypes": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3679" + } + }, + { + "name": "Filecoin.StateGetRandomnessDigestFromBeacon", + "description": "```go\nfunc (s *FullNodeStruct) StateGetRandomnessDigestFromBeacon(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (abi.Randomness, error) {\n\tif s.Internal.StateGetRandomnessDigestFromBeacon == nil {\n\t\treturn *new(abi.Randomness), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetRandomnessDigestFromBeacon(p0, p1, p2)\n}\n```", + "summary": "StateGetRandomnessDigestFromBeacon is used to sample the beacon for randomness.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "abi.Randomness", + "description": "abi.Randomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3690" + } + }, + { + "name": "Filecoin.StateGetRandomnessDigestFromTickets", + "description": "```go\nfunc (s *FullNodeStruct) StateGetRandomnessDigestFromTickets(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (abi.Randomness, error) {\n\tif s.Internal.StateGetRandomnessDigestFromTickets == nil {\n\t\treturn *new(abi.Randomness), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetRandomnessDigestFromTickets(p0, p1, p2)\n}\n```", + "summary": "StateGetRandomnessDigestFromTickets. is used to sample the chain for randomness.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "abi.Randomness", + "description": "abi.Randomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3701" + } + }, + { + "name": "Filecoin.StateGetRandomnessFromBeacon", + "description": "```go\nfunc (s *FullNodeStruct) StateGetRandomnessFromBeacon(p0 context.Context, p1 crypto.DomainSeparationTag, p2 abi.ChainEpoch, p3 []byte, p4 types.TipSetKey) (abi.Randomness, error) {\n\tif s.Internal.StateGetRandomnessFromBeacon == nil {\n\t\treturn *new(abi.Randomness), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetRandomnessFromBeacon(p0, p1, p2, p3, p4)\n}\n```", + "summary": "StateGetRandomnessFromBeacon is used to sample the beacon for randomness.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "crypto.DomainSeparationTag", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 2 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "abi.Randomness", + "description": "abi.Randomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3712" + } + }, + { + "name": "Filecoin.StateGetRandomnessFromTickets", + "description": "```go\nfunc (s *FullNodeStruct) StateGetRandomnessFromTickets(p0 context.Context, p1 crypto.DomainSeparationTag, p2 abi.ChainEpoch, p3 []byte, p4 types.TipSetKey) (abi.Randomness, error) {\n\tif s.Internal.StateGetRandomnessFromTickets == nil {\n\t\treturn *new(abi.Randomness), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetRandomnessFromTickets(p0, p1, p2, p3, p4)\n}\n```", + "summary": "StateGetRandomnessFromTickets is used to sample the chain for randomness.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "crypto.DomainSeparationTag", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 2 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "abi.Randomness", + "description": "abi.Randomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3723" + } + }, + { + "name": "Filecoin.StateListActors", + "description": "```go\nfunc (s *FullNodeStruct) StateListActors(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) {\n\tif s.Internal.StateListActors == nil {\n\t\treturn *new([]address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.StateListActors(p0, p1)\n}\n```", + "summary": "StateListActors returns the addresses of every actor in the state\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]address.Address", + "description": "[]address.Address", + "summary": "", + "schema": { + "examples": [ + [ + "f01234" + ] + ], + "items": [ + { + "additionalProperties": false, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3734" + } + }, + { + "name": "Filecoin.StateListMessages", + "description": "```go\nfunc (s *FullNodeStruct) StateListMessages(p0 context.Context, p1 *MessageMatch, p2 types.TipSetKey, p3 abi.ChainEpoch) ([]cid.Cid, error) {\n\tif s.Internal.StateListMessages == nil {\n\t\treturn *new([]cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.StateListMessages(p0, p1, p2, p3)\n}\n```", + "summary": "StateListMessages looks back and returns all messages with a matching to or from address, stopping at the given height.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*MessageMatch", + "summary": "", + "schema": { + "examples": [ + { + "To": "f01234", + "From": "f01234" + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "To": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]cid.Cid", + "description": "[]cid.Cid", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + ], + "items": [ + { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3745" + } + }, + { + "name": "Filecoin.StateListMiners", + "description": "```go\nfunc (s *FullNodeStruct) StateListMiners(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) {\n\tif s.Internal.StateListMiners == nil {\n\t\treturn *new([]address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.StateListMiners(p0, p1)\n}\n```", + "summary": "StateListMiners returns the addresses of every miner that has claimed power in the Power Actor\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]address.Address", + "description": "[]address.Address", + "summary": "", + "schema": { + "examples": [ + [ + "f01234" + ] + ], + "items": [ + { + "additionalProperties": false, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3756" + } + }, + { + "name": "Filecoin.StateLookupID", + "description": "```go\nfunc (s *FullNodeStruct) StateLookupID(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) {\n\tif s.Internal.StateLookupID == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.StateLookupID(p0, p1, p2)\n}\n```", + "summary": "StateLookupID retrieves the ID address of the given address\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3767" + } + }, + { + "name": "Filecoin.StateLookupRobustAddress", + "description": "```go\nfunc (s *FullNodeStruct) StateLookupRobustAddress(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) {\n\tif s.Internal.StateLookupRobustAddress == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.StateLookupRobustAddress(p0, p1, p2)\n}\n```", + "summary": "StateLookupRobustAddress returns the public key address of the given ID address for non-account addresses (multisig, miners etc)\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3778" + } + }, + { + "name": "Filecoin.StateMarketBalance", + "description": "```go\nfunc (s *FullNodeStruct) StateMarketBalance(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MarketBalance, error) {\n\tif s.Internal.StateMarketBalance == nil {\n\t\treturn *new(MarketBalance), ErrNotSupported\n\t}\n\treturn s.Internal.StateMarketBalance(p0, p1, p2)\n}\n```", + "summary": "StateMarketBalance looks up the Escrow and Locked balances of the given address in the Storage Market\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "MarketBalance", + "description": "MarketBalance", + "summary": "", + "schema": { + "examples": [ + { + "Escrow": "0", + "Locked": "0" + } + ], + "additionalProperties": false, + "properties": { + "Escrow": { + "additionalProperties": false, + "type": "object" + }, + "Locked": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3789" + } + }, + { + "name": "Filecoin.StateMarketDeals", + "description": "```go\nfunc (s *FullNodeStruct) StateMarketDeals(p0 context.Context, p1 types.TipSetKey) (map[string]*MarketDeal, error) {\n\tif s.Internal.StateMarketDeals == nil {\n\t\treturn *new(map[string]*MarketDeal), ErrNotSupported\n\t}\n\treturn s.Internal.StateMarketDeals(p0, p1)\n}\n```", + "summary": "StateMarketDeals returns information about every deal in the Storage Market\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[string]*MarketDeal", + "description": "map[string]*MarketDeal", + "summary": "", + "schema": { + "examples": [ + { + "t026363": { + "Proposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "State": { + "SectorStartEpoch": 10101, + "LastUpdatedEpoch": 10101, + "SlashEpoch": 10101 + } + } + } + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "Proposal": { + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "ClientCollateral": { + "additionalProperties": false, + "type": "object" + }, + "EndEpoch": { + "title": "number", + "type": "number" + }, + "Label": { + "additionalProperties": false, + "type": "object" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "StoragePricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + } + }, + "type": "object" + }, + "State": { + "additionalProperties": false, + "properties": { + "LastUpdatedEpoch": { + "title": "number", + "type": "number" + }, + "SectorStartEpoch": { + "title": "number", + "type": "number" + }, + "SlashEpoch": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3800" + } + }, + { + "name": "Filecoin.StateMarketParticipants", + "description": "```go\nfunc (s *FullNodeStruct) StateMarketParticipants(p0 context.Context, p1 types.TipSetKey) (map[string]MarketBalance, error) {\n\tif s.Internal.StateMarketParticipants == nil {\n\t\treturn *new(map[string]MarketBalance), ErrNotSupported\n\t}\n\treturn s.Internal.StateMarketParticipants(p0, p1)\n}\n```", + "summary": "StateMarketParticipants returns the Escrow and Locked balances of every participant in the Storage Market\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[string]MarketBalance", + "description": "map[string]MarketBalance", + "summary": "", + "schema": { + "examples": [ + { + "t026363": { + "Escrow": "0", + "Locked": "0" + } + } + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "Escrow": { + "additionalProperties": false, + "type": "object" + }, + "Locked": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3811" + } + }, + { + "name": "Filecoin.StateMarketStorageDeal", + "description": "```go\nfunc (s *FullNodeStruct) StateMarketStorageDeal(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*MarketDeal, error) {\n\tif s.Internal.StateMarketStorageDeal == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateMarketStorageDeal(p0, p1, p2)\n}\n```", + "summary": "StateMarketStorageDeal returns information about the indicated deal\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.DealID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 5432 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MarketDeal", + "description": "*MarketDeal", + "summary": "", + "schema": { + "examples": [ + { + "Proposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "State": { + "SectorStartEpoch": 10101, + "LastUpdatedEpoch": 10101, + "SlashEpoch": 10101 + } + } + ], + "additionalProperties": false, + "properties": { + "Proposal": { + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "ClientCollateral": { + "additionalProperties": false, + "type": "object" + }, + "EndEpoch": { + "title": "number", + "type": "number" + }, + "Label": { + "additionalProperties": false, + "type": "object" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "StoragePricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + } + }, + "type": "object" + }, + "State": { + "additionalProperties": false, + "properties": { + "LastUpdatedEpoch": { + "title": "number", + "type": "number" + }, + "SectorStartEpoch": { + "title": "number", + "type": "number" + }, + "SlashEpoch": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3822" + } + }, + { + "name": "Filecoin.StateMinerActiveSectors", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerActiveSectors(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*miner.SectorOnChainInfo, error) {\n\tif s.Internal.StateMinerActiveSectors == nil {\n\t\treturn *new([]*miner.SectorOnChainInfo), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerActiveSectors(p0, p1, p2)\n}\n```", + "summary": "StateMinerActiveSectors returns info about sectors that a given miner is actively proving.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*miner.SectorOnChainInfo", + "description": "[]*miner.SectorOnChainInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "SectorNumber": 9, + "SealProof": 8, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DealIDs": [ + 5432 + ], + "Activation": 10101, + "Expiration": 10101, + "DealWeight": "0", + "VerifiedDealWeight": "0", + "InitialPledge": "0", + "ExpectedDayReward": "0", + "ExpectedStoragePledge": "0", + "PowerBaseEpoch": 10101, + "ReplacedDayReward": "0", + "SectorKeyCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Flags": 0 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Activation": { + "title": "number", + "type": "number" + }, + "DealIDs": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "DealWeight": { + "additionalProperties": false, + "type": "object" + }, + "ExpectedDayReward": { + "additionalProperties": false, + "type": "object" + }, + "ExpectedStoragePledge": { + "additionalProperties": false, + "type": "object" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Flags": { + "title": "number", + "type": "number" + }, + "InitialPledge": { + "additionalProperties": false, + "type": "object" + }, + "PowerBaseEpoch": { + "title": "number", + "type": "number" + }, + "ReplacedDayReward": { + "additionalProperties": false, + "type": "object" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorKeyCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "VerifiedDealWeight": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3833" + } + }, + { + "name": "Filecoin.StateMinerAllocated", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerAllocated(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*bitfield.BitField, error) {\n\tif s.Internal.StateMinerAllocated == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerAllocated(p0, p1, p2)\n}\n```", + "summary": "StateMinerAllocated returns a bitfield containing all sector numbers marked as allocated in miner state\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*bitfield.BitField", + "description": "*bitfield.BitField", + "summary": "", + "schema": { + "examples": [ + [ + 0 + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3844" + } + }, + { + "name": "Filecoin.StateMinerAvailableBalance", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerAvailableBalance(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.StateMinerAvailableBalance == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerAvailableBalance(p0, p1, p2)\n}\n```", + "summary": "StateMinerAvailableBalance returns the portion of a miner's balance that can be withdrawn or spent\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3855" + } + }, + { + "name": "Filecoin.StateMinerDeadlines", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerDeadlines(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]Deadline, error) {\n\tif s.Internal.StateMinerDeadlines == nil {\n\t\treturn *new([]Deadline), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerDeadlines(p0, p1, p2)\n}\n```", + "summary": "StateMinerDeadlines returns all the proving deadlines for the given miner\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]Deadline", + "description": "[]Deadline", + "summary": "", + "schema": { + "examples": [ + [ + { + "PostSubmissions": [ + 5, + 1 + ], + "DisputableProofCount": 42 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "DisputableProofCount": { + "title": "number", + "type": "number" + }, + "PostSubmissions": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3866" + } + }, + { + "name": "Filecoin.StateMinerFaults", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerFaults(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (bitfield.BitField, error) {\n\tif s.Internal.StateMinerFaults == nil {\n\t\treturn *new(bitfield.BitField), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerFaults(p0, p1, p2)\n}\n```", + "summary": "StateMinerFaults returns a bitfield indicating the faulty sectors of the given miner\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bitfield.BitField", + "description": "bitfield.BitField", + "summary": "", + "schema": { + "examples": [ + [ + 5, + 1 + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3877" + } + }, + { + "name": "Filecoin.StateMinerInfo", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerInfo(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerInfo, error) {\n\tif s.Internal.StateMinerInfo == nil {\n\t\treturn *new(MinerInfo), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerInfo(p0, p1, p2)\n}\n```", + "summary": "StateMinerInfo returns info about the indicated miner\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "MinerInfo", + "description": "MinerInfo", + "summary": "", + "schema": { + "examples": [ + { + "Owner": "f01234", + "Worker": "f01234", + "NewWorker": "f01234", + "ControlAddresses": [ + "f01234" + ], + "WorkerChangeEpoch": 10101, + "PeerId": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Multiaddrs": [ + "Ynl0ZSBhcnJheQ==" + ], + "WindowPoStProofType": 8, + "SectorSize": 34359738368, + "WindowPoStPartitionSectors": 42, + "ConsensusFaultElapsed": 10101, + "PendingOwnerAddress": "f01234", + "Beneficiary": "f01234", + "BeneficiaryTerm": { + "Quota": "0", + "UsedQuota": "0", + "Expiration": 10101 + }, + "PendingBeneficiaryTerm": { + "NewBeneficiary": "f01234", + "NewQuota": "0", + "NewExpiration": 10101, + "ApprovedByBeneficiary": true, + "ApprovedByNominee": true + } + } + ], + "additionalProperties": false, + "properties": { + "Beneficiary": { + "additionalProperties": false, + "type": "object" + }, + "BeneficiaryTerm": { + "additionalProperties": false, + "properties": { + "Expiration": { + "title": "number", + "type": "number" + }, + "Quota": { + "additionalProperties": false, + "type": "object" + }, + "UsedQuota": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "ConsensusFaultElapsed": { + "title": "number", + "type": "number" + }, + "ControlAddresses": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "Multiaddrs": { + "items": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "type": "array" + }, + "NewWorker": { + "additionalProperties": false, + "type": "object" + }, + "Owner": { + "additionalProperties": false, + "type": "object" + }, + "PeerId": { + "type": "string" + }, + "PendingBeneficiaryTerm": { + "additionalProperties": false, + "properties": { + "ApprovedByBeneficiary": { + "type": "boolean" + }, + "ApprovedByNominee": { + "type": "boolean" + }, + "NewBeneficiary": { + "additionalProperties": false, + "type": "object" + }, + "NewExpiration": { + "title": "number", + "type": "number" + }, + "NewQuota": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "PendingOwnerAddress": { + "additionalProperties": false, + "type": "object" + }, + "SectorSize": { + "title": "number", + "type": "number" + }, + "WindowPoStPartitionSectors": { + "title": "number", + "type": "number" + }, + "WindowPoStProofType": { + "title": "number", + "type": "number" + }, + "Worker": { + "additionalProperties": false, + "type": "object" + }, + "WorkerChangeEpoch": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3888" + } + }, + { + "name": "Filecoin.StateMinerInitialPledgeCollateral", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerInitialPledgeCollateral(p0 context.Context, p1 address.Address, p2 miner.SectorPreCommitInfo, p3 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.StateMinerInitialPledgeCollateral == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerInitialPledgeCollateral(p0, p1, p2, p3)\n}\n```", + "summary": "StateMinerInitialPledgeCollateral returns the initial pledge collateral for the specified miner's sector\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "miner.SectorPreCommitInfo", + "summary": "", + "schema": { + "examples": [ + { + "SealProof": 8, + "SectorNumber": 9, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "SealRandEpoch": 10101, + "DealIDs": [ + 5432 + ], + "Expiration": 10101, + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "DealIDs": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SealRandEpoch": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "UnsealedCid": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3899" + } + }, + { + "name": "Filecoin.StateMinerPartitions", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerPartitions(p0 context.Context, p1 address.Address, p2 uint64, p3 types.TipSetKey) ([]Partition, error) {\n\tif s.Internal.StateMinerPartitions == nil {\n\t\treturn *new([]Partition), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerPartitions(p0, p1, p2, p3)\n}\n```", + "summary": "StateMinerPartitions returns all partitions in the specified deadline\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]Partition", + "description": "[]Partition", + "summary": "", + "schema": { + "examples": [ + [ + { + "AllSectors": [ + 5, + 1 + ], + "FaultySectors": [ + 5, + 1 + ], + "RecoveringSectors": [ + 5, + 1 + ], + "LiveSectors": [ + 5, + 1 + ], + "ActiveSectors": [ + 5, + 1 + ] + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "ActiveSectors": { + "additionalProperties": false, + "type": "object" + }, + "AllSectors": { + "additionalProperties": false, + "type": "object" + }, + "FaultySectors": { + "additionalProperties": false, + "type": "object" + }, + "LiveSectors": { + "additionalProperties": false, + "type": "object" + }, + "RecoveringSectors": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3910" + } + }, + { + "name": "Filecoin.StateMinerPower", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerPower(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*MinerPower, error) {\n\tif s.Internal.StateMinerPower == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerPower(p0, p1, p2)\n}\n```", + "summary": "StateMinerPower returns the power of the indicated miner\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MinerPower", + "description": "*MinerPower", + "summary": "", + "schema": { + "examples": [ + { + "MinerPower": { + "RawBytePower": "0", + "QualityAdjPower": "0" + }, + "TotalPower": { + "RawBytePower": "0", + "QualityAdjPower": "0" + }, + "HasMinPower": true + } + ], + "additionalProperties": false, + "properties": { + "HasMinPower": { + "type": "boolean" + }, + "MinerPower": { + "additionalProperties": false, + "properties": { + "QualityAdjPower": { + "additionalProperties": false, + "type": "object" + }, + "RawBytePower": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "TotalPower": { + "additionalProperties": false, + "properties": { + "QualityAdjPower": { + "additionalProperties": false, + "type": "object" + }, + "RawBytePower": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3921" + } + }, + { + "name": "Filecoin.StateMinerPreCommitDepositForPower", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerPreCommitDepositForPower(p0 context.Context, p1 address.Address, p2 miner.SectorPreCommitInfo, p3 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.StateMinerPreCommitDepositForPower == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerPreCommitDepositForPower(p0, p1, p2, p3)\n}\n```", + "summary": "StateMinerInitialPledgeCollateral returns the precommit deposit for the specified miner's sector\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "miner.SectorPreCommitInfo", + "summary": "", + "schema": { + "examples": [ + { + "SealProof": 8, + "SectorNumber": 9, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "SealRandEpoch": 10101, + "DealIDs": [ + 5432 + ], + "Expiration": 10101, + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "DealIDs": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SealRandEpoch": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "UnsealedCid": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3932" + } + }, + { + "name": "Filecoin.StateMinerProvingDeadline", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerProvingDeadline(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*dline.Info, error) {\n\tif s.Internal.StateMinerProvingDeadline == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerProvingDeadline(p0, p1, p2)\n}\n```", + "summary": "StateMinerProvingDeadline calculates the deadline at some epoch for a proving period\nand returns the deadline-related calculations.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*dline.Info", + "description": "*dline.Info", + "summary": "", + "schema": { + "examples": [ + { + "CurrentEpoch": 10101, + "PeriodStart": 10101, + "Index": 42, + "Open": 10101, + "Close": 10101, + "Challenge": 10101, + "FaultCutoff": 10101, + "WPoStPeriodDeadlines": 42, + "WPoStProvingPeriod": 10101, + "WPoStChallengeWindow": 10101, + "WPoStChallengeLookback": 10101, + "FaultDeclarationCutoff": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Challenge": { + "title": "number", + "type": "number" + }, + "Close": { + "title": "number", + "type": "number" + }, + "CurrentEpoch": { + "title": "number", + "type": "number" + }, + "FaultCutoff": { + "title": "number", + "type": "number" + }, + "FaultDeclarationCutoff": { + "title": "number", + "type": "number" + }, + "Index": { + "title": "number", + "type": "number" + }, + "Open": { + "title": "number", + "type": "number" + }, + "PeriodStart": { + "title": "number", + "type": "number" + }, + "WPoStChallengeLookback": { + "title": "number", + "type": "number" + }, + "WPoStChallengeWindow": { + "title": "number", + "type": "number" + }, + "WPoStPeriodDeadlines": { + "title": "number", + "type": "number" + }, + "WPoStProvingPeriod": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3943" + } + }, + { + "name": "Filecoin.StateMinerRecoveries", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerRecoveries(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (bitfield.BitField, error) {\n\tif s.Internal.StateMinerRecoveries == nil {\n\t\treturn *new(bitfield.BitField), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerRecoveries(p0, p1, p2)\n}\n```", + "summary": "StateMinerRecoveries returns a bitfield indicating the recovering sectors of the given miner\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bitfield.BitField", + "description": "bitfield.BitField", + "summary": "", + "schema": { + "examples": [ + [ + 5, + 1 + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3954" + } + }, + { + "name": "Filecoin.StateMinerSectorAllocated", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerSectorAllocated(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (bool, error) {\n\tif s.Internal.StateMinerSectorAllocated == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerSectorAllocated(p0, p1, p2, p3)\n}\n```", + "summary": "StateMinerSectorAllocated checks if a sector number is marked as allocated.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3965" + } + }, + { + "name": "Filecoin.StateMinerSectorCount", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerSectorCount(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerSectors, error) {\n\tif s.Internal.StateMinerSectorCount == nil {\n\t\treturn *new(MinerSectors), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerSectorCount(p0, p1, p2)\n}\n```", + "summary": "StateMinerSectorCount returns the number of sectors in a miner's sector set and proving set\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "MinerSectors", + "description": "MinerSectors", + "summary": "", + "schema": { + "examples": [ + { + "Live": 42, + "Active": 42, + "Faulty": 42 + } + ], + "additionalProperties": false, + "properties": { + "Active": { + "title": "number", + "type": "number" + }, + "Faulty": { + "title": "number", + "type": "number" + }, + "Live": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3976" + } + }, + { + "name": "Filecoin.StateMinerSectors", + "description": "```go\nfunc (s *FullNodeStruct) StateMinerSectors(p0 context.Context, p1 address.Address, p2 *bitfield.BitField, p3 types.TipSetKey) ([]*miner.SectorOnChainInfo, error) {\n\tif s.Internal.StateMinerSectors == nil {\n\t\treturn *new([]*miner.SectorOnChainInfo), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerSectors(p0, p1, p2, p3)\n}\n```", + "summary": "StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*bitfield.BitField", + "summary": "", + "schema": { + "examples": [ + [ + 0 + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*miner.SectorOnChainInfo", + "description": "[]*miner.SectorOnChainInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "SectorNumber": 9, + "SealProof": 8, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DealIDs": [ + 5432 + ], + "Activation": 10101, + "Expiration": 10101, + "DealWeight": "0", + "VerifiedDealWeight": "0", + "InitialPledge": "0", + "ExpectedDayReward": "0", + "ExpectedStoragePledge": "0", + "PowerBaseEpoch": 10101, + "ReplacedDayReward": "0", + "SectorKeyCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Flags": 0 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Activation": { + "title": "number", + "type": "number" + }, + "DealIDs": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "DealWeight": { + "additionalProperties": false, + "type": "object" + }, + "ExpectedDayReward": { + "additionalProperties": false, + "type": "object" + }, + "ExpectedStoragePledge": { + "additionalProperties": false, + "type": "object" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Flags": { + "title": "number", + "type": "number" + }, + "InitialPledge": { + "additionalProperties": false, + "type": "object" + }, + "PowerBaseEpoch": { + "title": "number", + "type": "number" + }, + "ReplacedDayReward": { + "additionalProperties": false, + "type": "object" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorKeyCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "VerifiedDealWeight": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3987" + } + }, + { + "name": "Filecoin.StateNetworkName", + "description": "```go\nfunc (s *FullNodeStruct) StateNetworkName(p0 context.Context) (dtypes.NetworkName, error) {\n\tif s.Internal.StateNetworkName == nil {\n\t\treturn *new(dtypes.NetworkName), ErrNotSupported\n\t}\n\treturn s.Internal.StateNetworkName(p0)\n}\n```", + "summary": "StateNetworkName returns the name of the network the node is synced to\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "dtypes.NetworkName", + "description": "dtypes.NetworkName", + "summary": "", + "schema": { + "examples": [ + "lotus" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L3998" + } + }, + { + "name": "Filecoin.StateNetworkVersion", + "description": "```go\nfunc (s *FullNodeStruct) StateNetworkVersion(p0 context.Context, p1 types.TipSetKey) (apitypes.NetworkVersion, error) {\n\tif s.Internal.StateNetworkVersion == nil {\n\t\treturn *new(apitypes.NetworkVersion), ErrNotSupported\n\t}\n\treturn s.Internal.StateNetworkVersion(p0, p1)\n}\n```", + "summary": "StateNetworkVersion returns the network version at the given tipset\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "apitypes.NetworkVersion", + "description": "apitypes.NetworkVersion", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 22 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4009" + } + }, + { + "name": "Filecoin.StateReadState", + "description": "```go\nfunc (s *FullNodeStruct) StateReadState(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*ActorState, error) {\n\tif s.Internal.StateReadState == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateReadState(p0, p1, p2)\n}\n```", + "summary": "StateReadState returns the indicated actor's state.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ActorState", + "description": "*ActorState", + "summary": "", + "schema": { + "examples": [ + { + "Balance": "0", + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "State": {} + } + ], + "additionalProperties": false, + "properties": { + "Balance": { + "additionalProperties": false, + "type": "object" + }, + "Code": { + "title": "Content Identifier", + "type": "string" + }, + "State": { + "additionalProperties": true, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4020" + } + }, + { + "name": "Filecoin.StateReplay", + "description": "```go\nfunc (s *FullNodeStruct) StateReplay(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid) (*InvocResult, error) {\n\tif s.Internal.StateReplay == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateReplay(p0, p1, p2)\n}\n```", + "summary": "StateReplay replays a given message, assuming it was included in a block in the specified tipset.\n\nIf a tipset key is provided, and a replacing message is not found on chain,\nthe method will return an error saying that the message wasn't found\n\nIf no tipset key is provided, the appropriate tipset is looked up, and if\nthe message was gas-repriced, the on-chain message will be replayed - in\nthat case the returned InvocResult.MsgCid will not match the Cid param\n\nIf the caller wants to ensure that exactly the requested message was executed,\nthey MUST check that InvocResult.MsgCid is equal to the provided Cid.\nWithout this check both the requested and original message may appear as\nsuccessfully executed on-chain, which may look like a double-spend.\n\nA replacing message is a message with a different CID, any of Gas values, and\ndifferent signature, but with all other parameters matching (source/destination,\nnonce, params, etc.)\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*InvocResult", + "description": "*InvocResult", + "summary": "", + "schema": { + "examples": [ + { + "MsgCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Msg": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "GasCost": { + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "GasUsed": "0", + "BaseFeeBurn": "0", + "OverEstimationBurn": "0", + "MinerPenalty": "0", + "MinerTip": "0", + "Refund": "0", + "TotalCost": "0" + }, + "ExecutionTrace": { + "Msg": { + "From": "f01234", + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "ParamsCodec": 42, + "GasLimit": 42, + "ReadOnly": true + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "ReturnCodec": 42 + }, + "InvokedActor": { + "Id": 1000, + "State": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + }, + "GasCharges": [ + { + "Name": "string value", + "tg": 9, + "cg": 9, + "sg": 9, + "tt": 60000000000 + } + ], + "Subcalls": [ + { + "Msg": { + "From": "f01234", + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "ParamsCodec": 42, + "GasLimit": 42, + "ReadOnly": true + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "ReturnCodec": 42 + }, + "InvokedActor": { + "Id": 1000, + "State": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + }, + "GasCharges": [ + { + "Name": "string value", + "tg": 9, + "cg": 9, + "sg": 9, + "tt": 60000000000 + } + ], + "Subcalls": null + } + ] + }, + "Error": "string value", + "Duration": 60000000000 + } + ], + "additionalProperties": false, + "properties": { + "Duration": { + "title": "number", + "type": "number" + }, + "Error": { + "type": "string" + }, + "ExecutionTrace": { + "additionalProperties": false, + "properties": { + "GasCharges": { + "items": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "cg": { + "title": "number", + "type": "number" + }, + "sg": { + "title": "number", + "type": "number" + }, + "tg": { + "title": "number", + "type": "number" + }, + "tt": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "InvokedActor": { + "additionalProperties": false, + "properties": { + "Id": { + "title": "number", + "type": "number" + }, + "State": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Balance": { + "additionalProperties": false, + "type": "object" + }, + "Code": { + "title": "Content Identifier", + "type": "string" + }, + "Head": { + "title": "Content Identifier", + "type": "string" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Msg": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ParamsCodec": { + "title": "number", + "type": "number" + }, + "ReadOnly": { + "type": "boolean" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "MsgRct": { + "additionalProperties": false, + "properties": { + "ExitCode": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ReturnCodec": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Subcalls": { + "items": {}, + "type": "array" + } + }, + "type": "object" + }, + "GasCost": { + "additionalProperties": false, + "properties": { + "BaseFeeBurn": { + "additionalProperties": false, + "type": "object" + }, + "GasUsed": { + "additionalProperties": false, + "type": "object" + }, + "Message": { + "title": "Content Identifier", + "type": "string" + }, + "MinerPenalty": { + "additionalProperties": false, + "type": "object" + }, + "MinerTip": { + "additionalProperties": false, + "type": "object" + }, + "OverEstimationBurn": { + "additionalProperties": false, + "type": "object" + }, + "Refund": { + "additionalProperties": false, + "type": "object" + }, + "TotalCost": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "Msg": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "MsgCid": { + "title": "Content Identifier", + "type": "string" + }, + "MsgRct": { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4031" + } + }, + { + "name": "Filecoin.StateSearchMsg", + "description": "```go\nfunc (s *FullNodeStruct) StateSearchMsg(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) {\n\tif s.Internal.StateSearchMsg == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateSearchMsg(p0, p1, p2, p3, p4)\n}\n```", + "summary": "StateSearchMsg looks back up to limit epochs in the chain for a message, and returns its receipt and the tipset where it was executed\n\nNOTE: If a replacing message is found on chain, this method will return\na MsgLookup for the replacing message - the MsgLookup.Message will be a different\nCID than the one provided in the 'cid' param, MsgLookup.Receipt will contain the\nresult of the execution of the replacing message.\n\nIf the caller wants to ensure that exactly the requested message was executed,\nthey must check that MsgLookup.Message is equal to the provided 'cid', or set the\n`allowReplaced` parameter to false. Without this check, and with `allowReplaced`\nset to true, both the requested and original message may appear as\nsuccessfully executed on-chain, which may look like a double-spend.\n\nA replacing message is a message with a different CID, any of Gas values, and\ndifferent signature, but with all other parameters matching (source/destination,\nnonce, params, etc.)\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MsgLookup", + "description": "*MsgLookup", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Receipt": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "ReturnDec": {}, + "TipSet": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "Height": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Height": { + "title": "number", + "type": "number" + }, + "Message": { + "title": "Content Identifier", + "type": "string" + }, + "Receipt": { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "ReturnDec": { + "additionalProperties": true, + "type": "object" + }, + "TipSet": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4042" + } + }, + { + "name": "Filecoin.StateSectorExpiration", + "description": "```go\nfunc (s *FullNodeStruct) StateSectorExpiration(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorExpiration, error) {\n\tif s.Internal.StateSectorExpiration == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateSectorExpiration(p0, p1, p2, p3)\n}\n```", + "summary": "StateSectorExpiration returns epoch at which given sector will expire\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*miner.SectorExpiration", + "description": "*miner.SectorExpiration", + "summary": "", + "schema": { + "examples": [ + { + "OnTime": 10101, + "Early": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Early": { + "title": "number", + "type": "number" + }, + "OnTime": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4053" + } + }, + { + "name": "Filecoin.StateSectorGetInfo", + "description": "```go\nfunc (s *FullNodeStruct) StateSectorGetInfo(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorOnChainInfo, error) {\n\tif s.Internal.StateSectorGetInfo == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateSectorGetInfo(p0, p1, p2, p3)\n}\n```", + "summary": "StateSectorGetInfo returns the on-chain info for the specified miner's sector. Returns null in case the sector info isn't found\nNOTE: returned info.Expiration may not be accurate in some cases, use StateSectorExpiration to get accurate\nexpiration epoch\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*miner.SectorOnChainInfo", + "description": "*miner.SectorOnChainInfo", + "summary": "", + "schema": { + "examples": [ + { + "SectorNumber": 9, + "SealProof": 8, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DealIDs": [ + 5432 + ], + "Activation": 10101, + "Expiration": 10101, + "DealWeight": "0", + "VerifiedDealWeight": "0", + "InitialPledge": "0", + "ExpectedDayReward": "0", + "ExpectedStoragePledge": "0", + "PowerBaseEpoch": 10101, + "ReplacedDayReward": "0", + "SectorKeyCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Flags": 0 + } + ], + "additionalProperties": false, + "properties": { + "Activation": { + "title": "number", + "type": "number" + }, + "DealIDs": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "DealWeight": { + "additionalProperties": false, + "type": "object" + }, + "ExpectedDayReward": { + "additionalProperties": false, + "type": "object" + }, + "ExpectedStoragePledge": { + "additionalProperties": false, + "type": "object" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Flags": { + "title": "number", + "type": "number" + }, + "InitialPledge": { + "additionalProperties": false, + "type": "object" + }, + "PowerBaseEpoch": { + "title": "number", + "type": "number" + }, + "ReplacedDayReward": { + "additionalProperties": false, + "type": "object" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorKeyCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "VerifiedDealWeight": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4064" + } + }, + { + "name": "Filecoin.StateSectorPartition", + "description": "```go\nfunc (s *FullNodeStruct) StateSectorPartition(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorLocation, error) {\n\tif s.Internal.StateSectorPartition == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateSectorPartition(p0, p1, p2, p3)\n}\n```", + "summary": "StateSectorPartition finds deadline/partition with the specified sector\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*miner.SectorLocation", + "description": "*miner.SectorLocation", + "summary": "", + "schema": { + "examples": [ + { + "Deadline": 42, + "Partition": 42 + } + ], + "additionalProperties": false, + "properties": { + "Deadline": { + "title": "number", + "type": "number" + }, + "Partition": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4075" + } + }, + { + "name": "Filecoin.StateSectorPreCommitInfo", + "description": "```go\nfunc (s *FullNodeStruct) StateSectorPreCommitInfo(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) {\n\tif s.Internal.StateSectorPreCommitInfo == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateSectorPreCommitInfo(p0, p1, p2, p3)\n}\n```", + "summary": "StateSectorPreCommitInfo returns the PreCommit info for the specified miner's sector.\nReturns nil and no error if the sector isn't precommitted.\n\nNote that the sector number may be allocated while PreCommitInfo is nil. This means that either allocated sector\nnumbers were compacted, and the sector number was marked as allocated in order to reduce size of the allocated\nsectors bitfield, or that the sector was precommitted, but the precommit has expired.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*miner.SectorPreCommitOnChainInfo", + "description": "*miner.SectorPreCommitOnChainInfo", + "summary": "", + "schema": { + "examples": [ + { + "Info": { + "SealProof": 8, + "SectorNumber": 9, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "SealRandEpoch": 10101, + "DealIDs": [ + 5432 + ], + "Expiration": 10101, + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "PreCommitDeposit": "0", + "PreCommitEpoch": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Info": { + "additionalProperties": false, + "properties": { + "DealIDs": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SealRandEpoch": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "UnsealedCid": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": "object" + }, + "PreCommitDeposit": { + "additionalProperties": false, + "type": "object" + }, + "PreCommitEpoch": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4086" + } + }, + { + "name": "Filecoin.StateVMCirculatingSupplyInternal", + "description": "```go\nfunc (s *FullNodeStruct) StateVMCirculatingSupplyInternal(p0 context.Context, p1 types.TipSetKey) (CirculatingSupply, error) {\n\tif s.Internal.StateVMCirculatingSupplyInternal == nil {\n\t\treturn *new(CirculatingSupply), ErrNotSupported\n\t}\n\treturn s.Internal.StateVMCirculatingSupplyInternal(p0, p1)\n}\n```", + "summary": "StateVMCirculatingSupplyInternal returns an approximation of the circulating supply of Filecoin at the given tipset.\nThis is the value reported by the runtime interface to actors code.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "CirculatingSupply", + "description": "CirculatingSupply", + "summary": "", + "schema": { + "examples": [ + { + "FilVested": "0", + "FilMined": "0", + "FilBurnt": "0", + "FilLocked": "0", + "FilCirculating": "0", + "FilReserveDisbursed": "0" + } + ], + "additionalProperties": false, + "properties": { + "FilBurnt": { + "additionalProperties": false, + "type": "object" + }, + "FilCirculating": { + "additionalProperties": false, + "type": "object" + }, + "FilLocked": { + "additionalProperties": false, + "type": "object" + }, + "FilMined": { + "additionalProperties": false, + "type": "object" + }, + "FilReserveDisbursed": { + "additionalProperties": false, + "type": "object" + }, + "FilVested": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4097" + } + }, + { + "name": "Filecoin.StateVerifiedClientStatus", + "description": "```go\nfunc (s *FullNodeStruct) StateVerifiedClientStatus(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) {\n\tif s.Internal.StateVerifiedClientStatus == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateVerifiedClientStatus(p0, p1, p2)\n}\n```", + "summary": "StateVerifiedClientStatus returns the data cap for the given address.\nReturns nil if there is no entry in the data cap table for the\naddress.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*abi.StoragePower", + "description": "*abi.StoragePower", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4108" + } + }, + { + "name": "Filecoin.StateVerifiedRegistryRootKey", + "description": "```go\nfunc (s *FullNodeStruct) StateVerifiedRegistryRootKey(p0 context.Context, p1 types.TipSetKey) (address.Address, error) {\n\tif s.Internal.StateVerifiedRegistryRootKey == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.StateVerifiedRegistryRootKey(p0, p1)\n}\n```", + "summary": "StateVerifiedRegistryRootKey returns the address of the Verified Registry's root key\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4119" + } + }, + { + "name": "Filecoin.StateVerifierStatus", + "description": "```go\nfunc (s *FullNodeStruct) StateVerifierStatus(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) {\n\tif s.Internal.StateVerifierStatus == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateVerifierStatus(p0, p1, p2)\n}\n```", + "summary": "StateVerifierStatus returns the data cap for the given address.\nReturns nil if there is no entry in the data cap table for the\naddress.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*abi.StoragePower", + "description": "*abi.StoragePower", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4130" + } + }, + { + "name": "Filecoin.StateWaitMsg", + "description": "```go\nfunc (s *FullNodeStruct) StateWaitMsg(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) {\n\tif s.Internal.StateWaitMsg == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateWaitMsg(p0, p1, p2, p3, p4)\n}\n```", + "summary": "StateWaitMsg looks back up to limit epochs in the chain for a message.\nIf not found, it blocks until the message arrives on chain, and gets to the\nindicated confidence depth.\n\nNOTE: If a replacing message is found on chain, this method will return\na MsgLookup for the replacing message - the MsgLookup.Message will be a different\nCID than the one provided in the 'cid' param, MsgLookup.Receipt will contain the\nresult of the execution of the replacing message.\n\nIf the caller wants to ensure that exactly the requested message was executed,\nthey must check that MsgLookup.Message is equal to the provided 'cid', or set the\n`allowReplaced` parameter to false. Without this check, and with `allowReplaced`\nset to true, both the requested and original message may appear as\nsuccessfully executed on-chain, which may look like a double-spend.\n\nA replacing message is a message with a different CID, any of Gas values, and\ndifferent signature, but with all other parameters matching (source/destination,\nnonce, params, etc.)\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MsgLookup", + "description": "*MsgLookup", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Receipt": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "ReturnDec": {}, + "TipSet": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "Height": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Height": { + "title": "number", + "type": "number" + }, + "Message": { + "title": "Content Identifier", + "type": "string" + }, + "Receipt": { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "ReturnDec": { + "additionalProperties": true, + "type": "object" + }, + "TipSet": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4141" + } + }, + { + "name": "Filecoin.SyncCheckBad", + "description": "```go\nfunc (s *FullNodeStruct) SyncCheckBad(p0 context.Context, p1 cid.Cid) (string, error) {\n\tif s.Internal.SyncCheckBad == nil {\n\t\treturn \"\", ErrNotSupported\n\t}\n\treturn s.Internal.SyncCheckBad(p0, p1)\n}\n```", + "summary": "SyncCheckBad checks if a block was marked as bad, and if it was, returns\nthe reason.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "string", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4163" + } + }, + { + "name": "Filecoin.SyncCheckpoint", + "description": "```go\nfunc (s *FullNodeStruct) SyncCheckpoint(p0 context.Context, p1 types.TipSetKey) error {\n\tif s.Internal.SyncCheckpoint == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SyncCheckpoint(p0, p1)\n}\n```", + "summary": "SyncCheckpoint marks a blocks as checkpointed, meaning that it won't ever fork away from it.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4174" + } + }, + { + "name": "Filecoin.SyncMarkBad", + "description": "```go\nfunc (s *FullNodeStruct) SyncMarkBad(p0 context.Context, p1 cid.Cid) error {\n\tif s.Internal.SyncMarkBad == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SyncMarkBad(p0, p1)\n}\n```", + "summary": "SyncMarkBad marks a blocks as bad, meaning that it won't ever by synced.\nUse with extreme caution.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4196" + } + }, + { + "name": "Filecoin.SyncState", + "description": "```go\nfunc (s *FullNodeStruct) SyncState(p0 context.Context) (*SyncState, error) {\n\tif s.Internal.SyncState == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.SyncState(p0)\n}\n```", + "summary": "SyncState returns the current status of the lotus sync system.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*SyncState", + "description": "*SyncState", + "summary": "", + "schema": { + "examples": [ + { + "ActiveSyncs": [ + { + "WorkerID": 42, + "Base": { + "Cids": null, + "Blocks": null, + "Height": 0 + }, + "Target": { + "Cids": null, + "Blocks": null, + "Height": 0 + }, + "Stage": 1, + "Height": 10101, + "Start": "0001-01-01T00:00:00Z", + "End": "0001-01-01T00:00:00Z", + "Message": "string value" + } + ], + "VMApplied": 42 + } + ], + "additionalProperties": false, + "properties": { + "ActiveSyncs": { + "items": { + "additionalProperties": false, + "properties": { + "Base": { + "additionalProperties": false, + "type": "object" + }, + "End": { + "format": "date-time", + "type": "string" + }, + "Height": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + }, + "Stage": { + "title": "number", + "type": "number" + }, + "Start": { + "format": "date-time", + "type": "string" + }, + "Target": { + "additionalProperties": false, + "type": "object" + }, + "WorkerID": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "VMApplied": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4207" + } + }, + { + "name": "Filecoin.SyncSubmitBlock", + "description": "```go\nfunc (s *FullNodeStruct) SyncSubmitBlock(p0 context.Context, p1 *types.BlockMsg) error {\n\tif s.Internal.SyncSubmitBlock == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SyncSubmitBlock(p0, p1)\n}\n```", + "summary": "SyncSubmitBlock can be used to submit a newly created block to the.\nnetwork through this node\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.BlockMsg", + "summary": "", + "schema": { + "examples": [ + { + "Header": { + "Miner": "f01234", + "Ticket": { + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "ElectionProof": { + "WinCount": 9, + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": [ + { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + } + ], + "WinPoStProof": [ + { + "PoStProof": 8, + "ProofBytes": "Ynl0ZSBhcnJheQ==" + } + ], + "Parents": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "ParentWeight": "0", + "Height": 10101, + "ParentStateRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Messages": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "BLSAggregate": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Timestamp": 42, + "BlockSig": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "ForkSignaling": 42, + "ParentBaseFee": "0" + }, + "BlsMessages": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "SecpkMessages": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + } + ], + "additionalProperties": false, + "properties": { + "BlsMessages": { + "items": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + }, + "type": "array" + }, + "Header": { + "additionalProperties": false, + "properties": { + "BLSAggregate": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "BeaconEntries": { + "items": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Round": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "BlockSig": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ElectionProof": { + "additionalProperties": false, + "properties": { + "VRFProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "WinCount": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ForkSignaling": { + "title": "number", + "type": "number" + }, + "Height": { + "title": "number", + "type": "number" + }, + "Messages": { + "title": "Content Identifier", + "type": "string" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "ParentBaseFee": { + "additionalProperties": false, + "type": "object" + }, + "ParentMessageReceipts": { + "title": "Content Identifier", + "type": "string" + }, + "ParentStateRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ParentWeight": { + "additionalProperties": false, + "type": "object" + }, + "Parents": { + "items": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + }, + "type": "array" + }, + "Ticket": { + "additionalProperties": false, + "properties": { + "VRFProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "Timestamp": { + "title": "number", + "type": "number" + }, + "WinPoStProof": { + "items": { + "additionalProperties": false, + "properties": { + "PoStProof": { + "title": "number", + "type": "number" + }, + "ProofBytes": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "SecpkMessages": { + "items": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4218" + } + }, + { + "name": "Filecoin.SyncUnmarkAllBad", + "description": "```go\nfunc (s *FullNodeStruct) SyncUnmarkAllBad(p0 context.Context) error {\n\tif s.Internal.SyncUnmarkAllBad == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SyncUnmarkAllBad(p0)\n}\n```", + "summary": "SyncUnmarkAllBad purges bad block cache, making it possible to sync to chains previously marked as bad\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4229" + } + }, + { + "name": "Filecoin.SyncUnmarkBad", + "description": "```go\nfunc (s *FullNodeStruct) SyncUnmarkBad(p0 context.Context, p1 cid.Cid) error {\n\tif s.Internal.SyncUnmarkBad == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SyncUnmarkBad(p0, p1)\n}\n```", + "summary": "SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4240" + } + }, + { + "name": "Filecoin.SyncValidateTipset", + "description": "```go\nfunc (s *FullNodeStruct) SyncValidateTipset(p0 context.Context, p1 types.TipSetKey) (bool, error) {\n\tif s.Internal.SyncValidateTipset == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.SyncValidateTipset(p0, p1)\n}\n```", + "summary": "SyncValidateTipset indicates whether the provided tipset is valid or not\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4251" + } + }, + { + "name": "Filecoin.WalletBalance", + "description": "```go\nfunc (s *FullNodeStruct) WalletBalance(p0 context.Context, p1 address.Address) (types.BigInt, error) {\n\tif s.Internal.WalletBalance == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.WalletBalance(p0, p1)\n}\n```", + "summary": "WalletBalance returns the balance of the given address at the current head of the chain.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4262" + } + }, + { + "name": "Filecoin.WalletDefaultAddress", + "description": "```go\nfunc (s *FullNodeStruct) WalletDefaultAddress(p0 context.Context) (address.Address, error) {\n\tif s.Internal.WalletDefaultAddress == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.WalletDefaultAddress(p0)\n}\n```", + "summary": "WalletDefaultAddress returns the address marked as default in the wallet.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4273" + } + }, + { + "name": "Filecoin.WalletDelete", + "description": "```go\nfunc (s *FullNodeStruct) WalletDelete(p0 context.Context, p1 address.Address) error {\n\tif s.Internal.WalletDelete == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.WalletDelete(p0, p1)\n}\n```", + "summary": "WalletDelete deletes an address from the wallet.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4284" + } + }, + { + "name": "Filecoin.WalletExport", + "description": "```go\nfunc (s *FullNodeStruct) WalletExport(p0 context.Context, p1 address.Address) (*types.KeyInfo, error) {\n\tif s.Internal.WalletExport == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.WalletExport(p0, p1)\n}\n```", + "summary": "WalletExport returns the private key of an address in the wallet.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.KeyInfo", + "description": "*types.KeyInfo", + "summary": "", + "schema": { + "examples": [ + { + "Type": "bls", + "PrivateKey": "Ynl0ZSBhcnJheQ==" + } + ], + "additionalProperties": false, + "properties": { + "PrivateKey": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4295" + } + }, + { + "name": "Filecoin.WalletHas", + "description": "```go\nfunc (s *FullNodeStruct) WalletHas(p0 context.Context, p1 address.Address) (bool, error) {\n\tif s.Internal.WalletHas == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.WalletHas(p0, p1)\n}\n```", + "summary": "WalletHas indicates whether the given address is in the wallet.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4306" + } + }, + { + "name": "Filecoin.WalletImport", + "description": "```go\nfunc (s *FullNodeStruct) WalletImport(p0 context.Context, p1 *types.KeyInfo) (address.Address, error) {\n\tif s.Internal.WalletImport == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.WalletImport(p0, p1)\n}\n```", + "summary": "WalletImport receives a KeyInfo, which includes a private key, and imports it into the wallet.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.KeyInfo", + "summary": "", + "schema": { + "examples": [ + { + "Type": "bls", + "PrivateKey": "Ynl0ZSBhcnJheQ==" + } + ], + "additionalProperties": false, + "properties": { + "PrivateKey": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4317" + } + }, + { + "name": "Filecoin.WalletList", + "description": "```go\nfunc (s *FullNodeStruct) WalletList(p0 context.Context) ([]address.Address, error) {\n\tif s.Internal.WalletList == nil {\n\t\treturn *new([]address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.WalletList(p0)\n}\n```", + "summary": "WalletList lists all the addresses in the wallet.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]address.Address", + "description": "[]address.Address", + "summary": "", + "schema": { + "examples": [ + [ + "f01234" + ] + ], + "items": [ + { + "additionalProperties": false, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4328" + } + }, + { + "name": "Filecoin.WalletNew", + "description": "```go\nfunc (s *FullNodeStruct) WalletNew(p0 context.Context, p1 types.KeyType) (address.Address, error) {\n\tif s.Internal.WalletNew == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.WalletNew(p0, p1)\n}\n```", + "summary": "WalletNew creates a new address in the wallet with the given sigType.\nAvailable key types: bls, secp256k1, secp256k1-ledger\nSupport for numerical types: 1 - secp256k1, 2 - BLS is deprecated\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.KeyType", + "summary": "", + "schema": { + "examples": [ + "bls" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4339" + } + }, + { + "name": "Filecoin.WalletSetDefault", + "description": "```go\nfunc (s *FullNodeStruct) WalletSetDefault(p0 context.Context, p1 address.Address) error {\n\tif s.Internal.WalletSetDefault == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.WalletSetDefault(p0, p1)\n}\n```", + "summary": "WalletSetDefault marks the given address as the default one.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4350" + } + }, + { + "name": "Filecoin.WalletSign", + "description": "```go\nfunc (s *FullNodeStruct) WalletSign(p0 context.Context, p1 address.Address, p2 []byte) (*crypto.Signature, error) {\n\tif s.Internal.WalletSign == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.WalletSign(p0, p1, p2)\n}\n```", + "summary": "WalletSign signs the given bytes using the given address.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*crypto.Signature", + "description": "*crypto.Signature", + "summary": "", + "schema": { + "examples": [ + { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + ], + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4361" + } + }, + { + "name": "Filecoin.WalletSignMessage", + "description": "```go\nfunc (s *FullNodeStruct) WalletSignMessage(p0 context.Context, p1 address.Address, p2 *types.Message) (*types.SignedMessage, error) {\n\tif s.Internal.WalletSignMessage == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.WalletSignMessage(p0, p1, p2)\n}\n```", + "summary": "WalletSignMessage signs the given message using the given address.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.SignedMessage", + "description": "*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4372" + } + }, + { + "name": "Filecoin.WalletValidateAddress", + "description": "```go\nfunc (s *FullNodeStruct) WalletValidateAddress(p0 context.Context, p1 string) (address.Address, error) {\n\tif s.Internal.WalletValidateAddress == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.WalletValidateAddress(p0, p1)\n}\n```", + "summary": "WalletValidateAddress validates whether a given string can be decoded as a well-formed address\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4383" + } + }, + { + "name": "Filecoin.WalletVerify", + "description": "```go\nfunc (s *FullNodeStruct) WalletVerify(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) {\n\tif s.Internal.WalletVerify == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.WalletVerify(p0, p1, p2, p3)\n}\n```", + "summary": "WalletVerify takes an address, a signature, and some bytes, and indicates whether the signature is valid.\nThe address does not have to be in the wallet.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*crypto.Signature", + "summary": "", + "schema": { + "examples": [ + { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + ], + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4394" + } + }, + { + "name": "Filecoin.Web3ClientVersion", + "description": "```go\nfunc (s *FullNodeStruct) Web3ClientVersion(p0 context.Context) (string, error) {\n\tif s.Internal.Web3ClientVersion == nil {\n\t\treturn \"\", ErrNotSupported\n\t}\n\treturn s.Internal.Web3ClientVersion(p0)\n}\n```", + "summary": "Returns the client version\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "string", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4405" + } + } + ] +} \ No newline at end of file diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index baaf830238c..08dda7784c6 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/gateway.json b/build/openrpc/gateway.json new file mode 100644 index 00000000000..3538f25cf5a --- /dev/null +++ b/build/openrpc/gateway.json @@ -0,0 +1,10267 @@ +{ + "openrpc": "1.2.6", + "info": { + "title": "Lotus RPC API", + "version": "1.27.0" + }, + "methods": [ + { + "name": "Filecoin.ChainGetBlock", + "description": "```go\nfunc (s *GatewayStruct) ChainGetBlock(p0 context.Context, p1 cid.Cid) (*types.BlockHeader, error) {\n\tif s.Internal.ChainGetBlock == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetBlock(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.BlockHeader", + "description": "*types.BlockHeader", + "summary": "", + "schema": { + "examples": [ + { + "Miner": "f01234", + "Ticket": { + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "ElectionProof": { + "WinCount": 9, + "VRFProof": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": [ + { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + } + ], + "WinPoStProof": [ + { + "PoStProof": 8, + "ProofBytes": "Ynl0ZSBhcnJheQ==" + } + ], + "Parents": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "ParentWeight": "0", + "Height": 10101, + "ParentStateRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "ParentMessageReceipts": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Messages": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "BLSAggregate": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "Timestamp": 42, + "BlockSig": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "ForkSignaling": 42, + "ParentBaseFee": "0" + } + ], + "additionalProperties": false, + "properties": { + "BLSAggregate": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "BeaconEntries": { + "items": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Round": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "BlockSig": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ElectionProof": { + "additionalProperties": false, + "properties": { + "VRFProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "WinCount": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ForkSignaling": { + "title": "number", + "type": "number" + }, + "Height": { + "title": "number", + "type": "number" + }, + "Messages": { + "title": "Content Identifier", + "type": "string" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "ParentBaseFee": { + "additionalProperties": false, + "type": "object" + }, + "ParentMessageReceipts": { + "title": "Content Identifier", + "type": "string" + }, + "ParentStateRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ParentWeight": { + "additionalProperties": false, + "type": "object" + }, + "Parents": { + "items": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + }, + "type": "array" + }, + "Ticket": { + "additionalProperties": false, + "properties": { + "VRFProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "Timestamp": { + "title": "number", + "type": "number" + }, + "WinPoStProof": { + "items": { + "additionalProperties": false, + "properties": { + "PoStProof": { + "title": "number", + "type": "number" + }, + "ProofBytes": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4416" + } + }, + { + "name": "Filecoin.ChainGetBlockMessages", + "description": "```go\nfunc (s *GatewayStruct) ChainGetBlockMessages(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) {\n\tif s.Internal.ChainGetBlockMessages == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetBlockMessages(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*BlockMessages", + "description": "*BlockMessages", + "summary": "", + "schema": { + "examples": [ + { + "BlsMessages": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "SecpkMessages": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "Cids": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + } + ], + "additionalProperties": false, + "properties": { + "BlsMessages": { + "items": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "Cids": { + "items": { + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "title": "Content Identifier", + "type": "string" + }, + "type": "array" + }, + "SecpkMessages": { + "items": { + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4427" + } + }, + { + "name": "Filecoin.ChainGetEvents", + "description": "```go\nfunc (s *GatewayStruct) ChainGetEvents(p0 context.Context, p1 cid.Cid) ([]types.Event, error) {\n\tif s.Internal.ChainGetEvents == nil {\n\t\treturn *new([]types.Event), ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetEvents(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]types.Event", + "description": "[]types.Event", + "summary": "", + "schema": { + "examples": [ + [ + { + "Emitter": 1000, + "Entries": [ + { + "Flags": 7, + "Key": "string value", + "Codec": 42, + "Value": "Ynl0ZSBhcnJheQ==" + } + ] + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Emitter": { + "title": "number", + "type": "number" + }, + "Entries": { + "items": { + "additionalProperties": false, + "properties": { + "Codec": { + "title": "number", + "type": "number" + }, + "Flags": { + "title": "number", + "type": "number" + }, + "Key": { + "type": "string" + }, + "Value": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4438" + } + }, + { + "name": "Filecoin.ChainGetGenesis", + "description": "```go\nfunc (s *GatewayStruct) ChainGetGenesis(p0 context.Context) (*types.TipSet, error) {\n\tif s.Internal.ChainGetGenesis == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetGenesis(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4449" + } + }, + { + "name": "Filecoin.ChainGetMessage", + "description": "```go\nfunc (s *GatewayStruct) ChainGetMessage(p0 context.Context, p1 cid.Cid) (*types.Message, error) {\n\tif s.Internal.ChainGetMessage == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetMessage(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.Message", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4460" + } + }, + { + "name": "Filecoin.ChainGetParentMessages", + "description": "```go\nfunc (s *GatewayStruct) ChainGetParentMessages(p0 context.Context, p1 cid.Cid) ([]Message, error) {\n\tif s.Internal.ChainGetParentMessages == nil {\n\t\treturn *new([]Message), ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetParentMessages(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]Message", + "description": "[]Message", + "summary": "", + "schema": { + "examples": [ + [ + { + "Cid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Cid": { + "title": "Content Identifier", + "type": "string" + }, + "Message": { + "additionalProperties": false, + "properties": { + "Cid": { + "title": "Content Identifier", + "type": "string" + }, + "Message": {} + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4471" + } + }, + { + "name": "Filecoin.ChainGetParentReceipts", + "description": "```go\nfunc (s *GatewayStruct) ChainGetParentReceipts(p0 context.Context, p1 cid.Cid) ([]*types.MessageReceipt, error) {\n\tif s.Internal.ChainGetParentReceipts == nil {\n\t\treturn *new([]*types.MessageReceipt), ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetParentReceipts(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*types.MessageReceipt", + "description": "[]*types.MessageReceipt", + "summary": "", + "schema": { + "examples": [ + [ + { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4482" + } + }, + { + "name": "Filecoin.ChainGetPath", + "description": "```go\nfunc (s *GatewayStruct) ChainGetPath(p0 context.Context, p1 types.TipSetKey, p2 types.TipSetKey) ([]*HeadChange, error) {\n\tif s.Internal.ChainGetPath == nil {\n\t\treturn *new([]*HeadChange), ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetPath(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*HeadChange", + "description": "[]*HeadChange", + "summary": "", + "schema": { + "examples": [ + [ + { + "Type": "string value", + "Val": { + "Cids": null, + "Blocks": null, + "Height": 0 + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Type": { + "type": "string" + }, + "Val": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4493" + } + }, + { + "name": "Filecoin.ChainGetTipSet", + "description": "```go\nfunc (s *GatewayStruct) ChainGetTipSet(p0 context.Context, p1 types.TipSetKey) (*types.TipSet, error) {\n\tif s.Internal.ChainGetTipSet == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetTipSet(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4504" + } + }, + { + "name": "Filecoin.ChainGetTipSetAfterHeight", + "description": "```go\nfunc (s *GatewayStruct) ChainGetTipSetAfterHeight(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) {\n\tif s.Internal.ChainGetTipSetAfterHeight == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetTipSetAfterHeight(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4515" + } + }, + { + "name": "Filecoin.ChainGetTipSetByHeight", + "description": "```go\nfunc (s *GatewayStruct) ChainGetTipSetByHeight(p0 context.Context, p1 abi.ChainEpoch, p2 types.TipSetKey) (*types.TipSet, error) {\n\tif s.Internal.ChainGetTipSetByHeight == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainGetTipSetByHeight(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4526" + } + }, + { + "name": "Filecoin.ChainHasObj", + "description": "```go\nfunc (s *GatewayStruct) ChainHasObj(p0 context.Context, p1 cid.Cid) (bool, error) {\n\tif s.Internal.ChainHasObj == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.ChainHasObj(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4537" + } + }, + { + "name": "Filecoin.ChainHead", + "description": "```go\nfunc (s *GatewayStruct) ChainHead(p0 context.Context) (*types.TipSet, error) {\n\tif s.Internal.ChainHead == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.ChainHead(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4548" + } + }, + { + "name": "Filecoin.ChainPutObj", + "description": "```go\nfunc (s *GatewayStruct) ChainPutObj(p0 context.Context, p1 blocks.Block) error {\n\tif s.Internal.ChainPutObj == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ChainPutObj(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "blocks.Block", + "summary": "", + "schema": { + "examples": [ + {} + ], + "additionalProperties": true + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4570" + } + }, + { + "name": "Filecoin.ChainReadObj", + "description": "```go\nfunc (s *GatewayStruct) ChainReadObj(p0 context.Context, p1 cid.Cid) ([]byte, error) {\n\tif s.Internal.ChainReadObj == nil {\n\t\treturn *new([]byte), ErrNotSupported\n\t}\n\treturn s.Internal.ChainReadObj(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]byte", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4581" + } + }, + { + "name": "Filecoin.Discover", + "description": "```go\nfunc (s *GatewayStruct) Discover(p0 context.Context) (apitypes.OpenRPCDocument, error) {\n\tif s.Internal.Discover == nil {\n\t\treturn *new(apitypes.OpenRPCDocument), ErrNotSupported\n\t}\n\treturn s.Internal.Discover(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "apitypes.OpenRPCDocument", + "description": "apitypes.OpenRPCDocument", + "summary": "", + "schema": { + "examples": [ + { + "info": { + "title": "Lotus RPC API", + "version": "1.2.1/generated=2020-11-22T08:22:42-06:00" + }, + "methods": [], + "openrpc": "1.2.6" + } + ], + "patternProperties": { + ".*": { + "additionalProperties": true, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4592" + } + }, + { + "name": "Filecoin.EthAccounts", + "description": "```go\nfunc (s *GatewayStruct) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, error) {\n\tif s.Internal.EthAccounts == nil {\n\t\treturn *new([]ethtypes.EthAddress), ErrNotSupported\n\t}\n\treturn s.Internal.EthAccounts(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]ethtypes.EthAddress", + "description": "[]ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ] + ], + "items": [ + { + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4603" + } + }, + { + "name": "Filecoin.EthAddressToFilecoinAddress", + "description": "```go\nfunc (s *GatewayStruct) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) {\n\tif s.Internal.EthAddressToFilecoinAddress == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.EthAddressToFilecoinAddress(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4614" + } + }, + { + "name": "Filecoin.EthBlockNumber", + "description": "```go\nfunc (s *GatewayStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthBlockNumber == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthBlockNumber(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4625" + } + }, + { + "name": "Filecoin.EthCall", + "description": "```go\nfunc (s *GatewayStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) {\n\tif s.Internal.EthCall == nil {\n\t\treturn *new(ethtypes.EthBytes), ErrNotSupported\n\t}\n\treturn s.Internal.EthCall(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthCall", + "summary": "", + "schema": { + "examples": [ + { + "from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", + "gas": "0x5", + "gasPrice": "0x0", + "value": "0x0", + "data": "0x07" + } + ], + "additionalProperties": false, + "properties": { + "data": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gas": { + "title": "number", + "type": "number" + }, + "gasPrice": { + "additionalProperties": false, + "type": "object" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthBlockNumberOrHash", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "requireCanonical": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBytes", + "description": "ethtypes.EthBytes", + "summary": "", + "schema": { + "examples": [ + "0x07" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4636" + } + }, + { + "name": "Filecoin.EthChainId", + "description": "```go\nfunc (s *GatewayStruct) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthChainId == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthChainId(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4647" + } + }, + { + "name": "Filecoin.EthEstimateGas", + "description": "```go\nfunc (s *GatewayStruct) EthEstimateGas(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthEstimateGas == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthEstimateGas(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "jsonrpc.RawParams", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4658" + } + }, + { + "name": "Filecoin.EthFeeHistory", + "description": "```go\nfunc (s *GatewayStruct) EthFeeHistory(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) {\n\tif s.Internal.EthFeeHistory == nil {\n\t\treturn *new(ethtypes.EthFeeHistory), ErrNotSupported\n\t}\n\treturn s.Internal.EthFeeHistory(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "jsonrpc.RawParams", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthFeeHistory", + "description": "ethtypes.EthFeeHistory", + "summary": "", + "schema": { + "examples": [ + { + "oldestBlock": "0x5", + "baseFeePerGas": [ + "0x0" + ], + "gasUsedRatio": [ + 12.3 + ], + "reward": [] + } + ], + "additionalProperties": false, + "properties": { + "baseFeePerGas": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "gasUsedRatio": { + "items": { + "type": "number" + }, + "type": "array" + }, + "oldestBlock": { + "title": "number", + "type": "number" + }, + "reward": { + "items": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4669" + } + }, + { + "name": "Filecoin.EthGasPrice", + "description": "```go\nfunc (s *GatewayStruct) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error) {\n\tif s.Internal.EthGasPrice == nil {\n\t\treturn *new(ethtypes.EthBigInt), ErrNotSupported\n\t}\n\treturn s.Internal.EthGasPrice(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthBigInt", + "description": "ethtypes.EthBigInt", + "summary": "", + "schema": { + "examples": [ + "0x0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4680" + } + }, + { + "name": "Filecoin.EthGetBalance", + "description": "```go\nfunc (s *GatewayStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) {\n\tif s.Internal.EthGetBalance == nil {\n\t\treturn *new(ethtypes.EthBigInt), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetBalance(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthBlockNumberOrHash", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "requireCanonical": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBigInt", + "description": "ethtypes.EthBigInt", + "summary": "", + "schema": { + "examples": [ + "0x0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4691" + } + }, + { + "name": "Filecoin.EthGetBlockByHash", + "description": "```go\nfunc (s *GatewayStruct) EthGetBlockByHash(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) {\n\tif s.Internal.EthGetBlockByHash == nil {\n\t\treturn *new(ethtypes.EthBlock), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetBlockByHash(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBlock", + "description": "ethtypes.EthBlock", + "summary": "", + "schema": { + "examples": [ + { + "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" + ] + } + ], + "additionalProperties": false, + "properties": { + "baseFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "difficulty": { + "title": "number", + "type": "number" + }, + "extraData": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "gasLimit": { + "title": "number", + "type": "number" + }, + "gasUsed": { + "title": "number", + "type": "number" + }, + "hash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "logsBloom": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "miner": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "mixHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "nonce": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 8, + "minItems": 8, + "type": "array" + }, + "number": { + "title": "number", + "type": "number" + }, + "parentHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "receiptsRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "sha3Uncles": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "size": { + "title": "number", + "type": "number" + }, + "stateRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "timestamp": { + "title": "number", + "type": "number" + }, + "totalDifficulty": { + "title": "number", + "type": "number" + }, + "transactions": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + }, + "transactionsRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "uncles": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4702" + } + }, + { + "name": "Filecoin.EthGetBlockByNumber", + "description": "```go\nfunc (s *GatewayStruct) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) {\n\tif s.Internal.EthGetBlockByNumber == nil {\n\t\treturn *new(ethtypes.EthBlock), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetBlockByNumber(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBlock", + "description": "ethtypes.EthBlock", + "summary": "", + "schema": { + "examples": [ + { + "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" + ] + } + ], + "additionalProperties": false, + "properties": { + "baseFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "difficulty": { + "title": "number", + "type": "number" + }, + "extraData": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "gasLimit": { + "title": "number", + "type": "number" + }, + "gasUsed": { + "title": "number", + "type": "number" + }, + "hash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "logsBloom": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "miner": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "mixHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "nonce": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 8, + "minItems": 8, + "type": "array" + }, + "number": { + "title": "number", + "type": "number" + }, + "parentHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "receiptsRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "sha3Uncles": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "size": { + "title": "number", + "type": "number" + }, + "stateRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "timestamp": { + "title": "number", + "type": "number" + }, + "totalDifficulty": { + "title": "number", + "type": "number" + }, + "transactions": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + }, + "transactionsRoot": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "uncles": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4713" + } + }, + { + "name": "Filecoin.EthGetBlockTransactionCountByHash", + "description": "```go\nfunc (s *GatewayStruct) EthGetBlockTransactionCountByHash(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthGetBlockTransactionCountByHash == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetBlockTransactionCountByHash(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4724" + } + }, + { + "name": "Filecoin.EthGetBlockTransactionCountByNumber", + "description": "```go\nfunc (s *GatewayStruct) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthGetBlockTransactionCountByNumber == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetBlockTransactionCountByNumber(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4735" + } + }, + { + "name": "Filecoin.EthGetCode", + "description": "```go\nfunc (s *GatewayStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) {\n\tif s.Internal.EthGetCode == nil {\n\t\treturn *new(ethtypes.EthBytes), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetCode(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthBlockNumberOrHash", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "requireCanonical": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBytes", + "description": "ethtypes.EthBytes", + "summary": "", + "schema": { + "examples": [ + "0x07" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4746" + } + }, + { + "name": "Filecoin.EthGetFilterChanges", + "description": "```go\nfunc (s *GatewayStruct) EthGetFilterChanges(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {\n\tif s.Internal.EthGetFilterChanges == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetFilterChanges(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthFilterResult", + "description": "*ethtypes.EthFilterResult", + "summary": "", + "schema": { + "examples": [ + [ + {} + ] + ], + "additionalProperties": false, + "properties": { + "Results": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4757" + } + }, + { + "name": "Filecoin.EthGetFilterLogs", + "description": "```go\nfunc (s *GatewayStruct) EthGetFilterLogs(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {\n\tif s.Internal.EthGetFilterLogs == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetFilterLogs(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthFilterResult", + "description": "*ethtypes.EthFilterResult", + "summary": "", + "schema": { + "examples": [ + [ + {} + ] + ], + "additionalProperties": false, + "properties": { + "Results": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4768" + } + }, + { + "name": "Filecoin.EthGetLogs", + "description": "```go\nfunc (s *GatewayStruct) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) {\n\tif s.Internal.EthGetLogs == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetLogs(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*ethtypes.EthFilterSpec", + "summary": "", + "schema": { + "examples": [ + { + "fromBlock": "2301220", + "address": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "topics": null + } + ], + "additionalProperties": false, + "properties": { + "address": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "fromBlock": { + "type": "string" + }, + "toBlock": { + "type": "string" + }, + "topics": { + "items": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthFilterResult", + "description": "*ethtypes.EthFilterResult", + "summary": "", + "schema": { + "examples": [ + [ + {} + ] + ], + "additionalProperties": false, + "properties": { + "Results": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4779" + } + }, + { + "name": "Filecoin.EthGetMessageCidByTransactionHash", + "description": "```go\nfunc (s *GatewayStruct) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) {\n\tif s.Internal.EthGetMessageCidByTransactionHash == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetMessageCidByTransactionHash(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*cid.Cid", + "description": "*cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4790" + } + }, + { + "name": "Filecoin.EthGetStorageAt", + "description": "```go\nfunc (s *GatewayStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) {\n\tif s.Internal.EthGetStorageAt == nil {\n\t\treturn *new(ethtypes.EthBytes), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetStorageAt(p0, p1, p2, p3)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthBytes", + "summary": "", + "schema": { + "examples": [ + "0x07" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "ethtypes.EthBlockNumberOrHash", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "requireCanonical": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthBytes", + "description": "ethtypes.EthBytes", + "summary": "", + "schema": { + "examples": [ + "0x07" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4801" + } + }, + { + "name": "Filecoin.EthGetTransactionByHash", + "description": "```go\nfunc (s *GatewayStruct) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) {\n\tif s.Internal.EthGetTransactionByHash == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionByHash(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthTx", + "description": "*ethtypes.EthTx", + "summary": "", + "schema": { + "examples": [ + { + "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" + } + ], + "additionalProperties": false, + "properties": { + "accessList": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "chainId": { + "title": "number", + "type": "number" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gas": { + "title": "number", + "type": "number" + }, + "hash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "input": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "maxFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "maxPriorityFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "nonce": { + "title": "number", + "type": "number" + }, + "r": { + "additionalProperties": false, + "type": "object" + }, + "s": { + "additionalProperties": false, + "type": "object" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + }, + "type": { + "title": "number", + "type": "number" + }, + "v": { + "additionalProperties": false, + "type": "object" + }, + "value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4812" + } + }, + { + "name": "Filecoin.EthGetTransactionByHashLimited", + "description": "```go\nfunc (s *GatewayStruct) EthGetTransactionByHashLimited(p0 context.Context, p1 *ethtypes.EthHash, p2 abi.ChainEpoch) (*ethtypes.EthTx, error) {\n\tif s.Internal.EthGetTransactionByHashLimited == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionByHashLimited(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthTx", + "description": "*ethtypes.EthTx", + "summary": "", + "schema": { + "examples": [ + { + "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" + } + ], + "additionalProperties": false, + "properties": { + "accessList": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "chainId": { + "title": "number", + "type": "number" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gas": { + "title": "number", + "type": "number" + }, + "hash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "input": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "maxFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "maxPriorityFeePerGas": { + "additionalProperties": false, + "type": "object" + }, + "nonce": { + "title": "number", + "type": "number" + }, + "r": { + "additionalProperties": false, + "type": "object" + }, + "s": { + "additionalProperties": false, + "type": "object" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + }, + "type": { + "title": "number", + "type": "number" + }, + "v": { + "additionalProperties": false, + "type": "object" + }, + "value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4823" + } + }, + { + "name": "Filecoin.EthGetTransactionCount", + "description": "```go\nfunc (s *GatewayStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthGetTransactionCount == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionCount(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "ethtypes.EthBlockNumberOrHash", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "requireCanonical": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4834" + } + }, + { + "name": "Filecoin.EthGetTransactionHashByCid", + "description": "```go\nfunc (s *GatewayStruct) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) {\n\tif s.Internal.EthGetTransactionHashByCid == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionHashByCid(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ethtypes.EthHash", + "description": "*ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4845" + } + }, + { + "name": "Filecoin.EthGetTransactionReceipt", + "description": "```go\nfunc (s *GatewayStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) {\n\tif s.Internal.EthGetTransactionReceipt == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionReceipt(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*EthTxReceipt", + "description": "*EthTxReceipt", + "summary": "", + "schema": { + "examples": [ + { + "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" + } + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "contractAddress": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "cumulativeGasUsed": { + "title": "number", + "type": "number" + }, + "effectiveGasPrice": { + "additionalProperties": false, + "type": "object" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gasUsed": { + "title": "number", + "type": "number" + }, + "logs": { + "items": { + "additionalProperties": false, + "properties": { + "address": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "data": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "logIndex": { + "title": "number", + "type": "number" + }, + "removed": { + "type": "boolean" + }, + "topics": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "logsBloom": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "root": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "status": { + "title": "number", + "type": "number" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + }, + "type": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4856" + } + }, + { + "name": "Filecoin.EthGetTransactionReceiptLimited", + "description": "```go\nfunc (s *GatewayStruct) EthGetTransactionReceiptLimited(p0 context.Context, p1 ethtypes.EthHash, p2 abi.ChainEpoch) (*EthTxReceipt, error) {\n\tif s.Internal.EthGetTransactionReceiptLimited == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.EthGetTransactionReceiptLimited(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*EthTxReceipt", + "description": "*EthTxReceipt", + "summary": "", + "schema": { + "examples": [ + { + "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" + } + ], + "additionalProperties": false, + "properties": { + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "contractAddress": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "cumulativeGasUsed": { + "title": "number", + "type": "number" + }, + "effectiveGasPrice": { + "additionalProperties": false, + "type": "object" + }, + "from": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "gasUsed": { + "title": "number", + "type": "number" + }, + "logs": { + "items": { + "additionalProperties": false, + "properties": { + "address": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "data": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "logIndex": { + "title": "number", + "type": "number" + }, + "removed": { + "type": "boolean" + }, + "topics": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "logsBloom": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "root": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "status": { + "title": "number", + "type": "number" + }, + "to": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "transactionIndex": { + "title": "number", + "type": "number" + }, + "type": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4867" + } + }, + { + "name": "Filecoin.EthMaxPriorityFeePerGas", + "description": "```go\nfunc (s *GatewayStruct) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) {\n\tif s.Internal.EthMaxPriorityFeePerGas == nil {\n\t\treturn *new(ethtypes.EthBigInt), ErrNotSupported\n\t}\n\treturn s.Internal.EthMaxPriorityFeePerGas(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthBigInt", + "description": "ethtypes.EthBigInt", + "summary": "", + "schema": { + "examples": [ + "0x0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4878" + } + }, + { + "name": "Filecoin.EthNewBlockFilter", + "description": "```go\nfunc (s *GatewayStruct) EthNewBlockFilter(p0 context.Context) (ethtypes.EthFilterID, error) {\n\tif s.Internal.EthNewBlockFilter == nil {\n\t\treturn *new(ethtypes.EthFilterID), ErrNotSupported\n\t}\n\treturn s.Internal.EthNewBlockFilter(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthFilterID", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4889" + } + }, + { + "name": "Filecoin.EthNewFilter", + "description": "```go\nfunc (s *GatewayStruct) EthNewFilter(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) {\n\tif s.Internal.EthNewFilter == nil {\n\t\treturn *new(ethtypes.EthFilterID), ErrNotSupported\n\t}\n\treturn s.Internal.EthNewFilter(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*ethtypes.EthFilterSpec", + "summary": "", + "schema": { + "examples": [ + { + "fromBlock": "2301220", + "address": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "topics": null + } + ], + "additionalProperties": false, + "properties": { + "address": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 20, + "minItems": 20, + "type": "array" + }, + "type": "array" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "fromBlock": { + "type": "string" + }, + "toBlock": { + "type": "string" + }, + "topics": { + "items": { + "items": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "type": "array" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthFilterID", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4900" + } + }, + { + "name": "Filecoin.EthNewPendingTransactionFilter", + "description": "```go\nfunc (s *GatewayStruct) EthNewPendingTransactionFilter(p0 context.Context) (ethtypes.EthFilterID, error) {\n\tif s.Internal.EthNewPendingTransactionFilter == nil {\n\t\treturn *new(ethtypes.EthFilterID), ErrNotSupported\n\t}\n\treturn s.Internal.EthNewPendingTransactionFilter(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthFilterID", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4911" + } + }, + { + "name": "Filecoin.EthProtocolVersion", + "description": "```go\nfunc (s *GatewayStruct) EthProtocolVersion(p0 context.Context) (ethtypes.EthUint64, error) {\n\tif s.Internal.EthProtocolVersion == nil {\n\t\treturn *new(ethtypes.EthUint64), ErrNotSupported\n\t}\n\treturn s.Internal.EthProtocolVersion(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthUint64", + "description": "ethtypes.EthUint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + "0x5" + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4922" + } + }, + { + "name": "Filecoin.EthSendRawTransaction", + "description": "```go\nfunc (s *GatewayStruct) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) {\n\tif s.Internal.EthSendRawTransaction == nil {\n\t\treturn *new(ethtypes.EthHash), ErrNotSupported\n\t}\n\treturn s.Internal.EthSendRawTransaction(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthBytes", + "summary": "", + "schema": { + "examples": [ + "0x07" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthHash", + "description": "ethtypes.EthHash", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4933" + } + }, + { + "name": "Filecoin.EthSubscribe", + "description": "```go\nfunc (s *GatewayStruct) EthSubscribe(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {\n\tif s.Internal.EthSubscribe == nil {\n\t\treturn *new(ethtypes.EthSubscriptionID), ErrNotSupported\n\t}\n\treturn s.Internal.EthSubscribe(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "jsonrpc.RawParams", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthSubscriptionID", + "description": "ethtypes.EthSubscriptionID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4944" + } + }, + { + "name": "Filecoin.EthSyncing", + "description": "```go\nfunc (s *GatewayStruct) EthSyncing(p0 context.Context) (ethtypes.EthSyncingResult, error) {\n\tif s.Internal.EthSyncing == nil {\n\t\treturn *new(ethtypes.EthSyncingResult), ErrNotSupported\n\t}\n\treturn s.Internal.EthSyncing(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "ethtypes.EthSyncingResult", + "description": "ethtypes.EthSyncingResult", + "summary": "", + "schema": { + "examples": [ + false + ], + "additionalProperties": false, + "properties": { + "CurrentBlock": { + "title": "number", + "type": "number" + }, + "DoneSync": { + "type": "boolean" + }, + "HighestBlock": { + "title": "number", + "type": "number" + }, + "StartingBlock": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4955" + } + }, + { + "name": "Filecoin.EthTraceBlock", + "description": "```go\nfunc (s *GatewayStruct) EthTraceBlock(p0 context.Context, p1 string) ([]*ethtypes.EthTraceBlock, error) {\n\tif s.Internal.EthTraceBlock == nil {\n\t\treturn *new([]*ethtypes.EthTraceBlock), ErrNotSupported\n\t}\n\treturn s.Internal.EthTraceBlock(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*ethtypes.EthTraceBlock", + "description": "[]*ethtypes.EthTraceBlock", + "summary": "", + "schema": { + "examples": [ + [ + { + "type": "string value", + "error": "string value", + "subtraces": 123, + "traceAddress": [ + 123 + ], + "action": {}, + "result": {}, + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "blockNumber": 9, + "transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "transactionPosition": 123 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "action": { + "additionalProperties": true, + "type": "object" + }, + "blockHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "blockNumber": { + "title": "number", + "type": "number" + }, + "error": { + "type": "string" + }, + "result": { + "additionalProperties": true, + "type": "object" + }, + "subtraces": { + "title": "number", + "type": "number" + }, + "traceAddress": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "transactionPosition": { + "title": "number", + "type": "number" + }, + "type": { + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4966" + } + }, + { + "name": "Filecoin.EthTraceReplayBlockTransactions", + "description": "```go\nfunc (s *GatewayStruct) EthTraceReplayBlockTransactions(p0 context.Context, p1 string, p2 []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error) {\n\tif s.Internal.EthTraceReplayBlockTransactions == nil {\n\t\treturn *new([]*ethtypes.EthTraceReplayBlockTransaction), ErrNotSupported\n\t}\n\treturn s.Internal.EthTraceReplayBlockTransactions(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "[]string", + "summary": "", + "schema": { + "examples": [ + [ + "string value" + ] + ], + "items": [ + { + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*ethtypes.EthTraceReplayBlockTransaction", + "description": "[]*ethtypes.EthTraceReplayBlockTransaction", + "summary": "", + "schema": { + "examples": [ + [ + { + "output": "0x07", + "stateDiff": "string value", + "trace": [ + { + "type": "string value", + "error": "string value", + "subtraces": 123, + "traceAddress": [ + 123 + ], + "action": {}, + "result": {} + } + ], + "transactionHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "vmTrace": "string value" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "output": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "stateDiff": { + "type": "string" + }, + "trace": { + "items": { + "additionalProperties": false, + "properties": { + "action": { + "additionalProperties": true, + "type": "object" + }, + "error": { + "type": "string" + }, + "result": { + "additionalProperties": true, + "type": "object" + }, + "subtraces": { + "title": "number", + "type": "number" + }, + "traceAddress": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "type": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "transactionHash": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 32, + "minItems": 32, + "type": "array" + }, + "vmTrace": { + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4977" + } + }, + { + "name": "Filecoin.EthUninstallFilter", + "description": "```go\nfunc (s *GatewayStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) {\n\tif s.Internal.EthUninstallFilter == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.EthUninstallFilter(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthFilterID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4988" + } + }, + { + "name": "Filecoin.EthUnsubscribe", + "description": "```go\nfunc (s *GatewayStruct) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) {\n\tif s.Internal.EthUnsubscribe == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.EthUnsubscribe(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "ethtypes.EthSubscriptionID", + "summary": "", + "schema": { + "examples": [ + "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 32, + "minItems": 32, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L4999" + } + }, + { + "name": "Filecoin.FilecoinAddressToEthAddress", + "description": "```go\nfunc (s *GatewayStruct) FilecoinAddressToEthAddress(p0 context.Context, p1 address.Address) (ethtypes.EthAddress, error) {\n\tif s.Internal.FilecoinAddressToEthAddress == nil {\n\t\treturn *new(ethtypes.EthAddress), ErrNotSupported\n\t}\n\treturn s.Internal.FilecoinAddressToEthAddress(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "ethtypes.EthAddress", + "description": "ethtypes.EthAddress", + "summary": "", + "schema": { + "examples": [ + "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 20, + "minItems": 20, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5010" + } + }, + { + "name": "Filecoin.GasEstimateGasPremium", + "description": "```go\nfunc (s *GatewayStruct) GasEstimateGasPremium(p0 context.Context, p1 uint64, p2 address.Address, p3 int64, p4 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.GasEstimateGasPremium == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.GasEstimateGasPremium(p0, p1, p2, p3, p4)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "int64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5021" + } + }, + { + "name": "Filecoin.GasEstimateMessageGas", + "description": "```go\nfunc (s *GatewayStruct) GasEstimateMessageGas(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) {\n\tif s.Internal.GasEstimateMessageGas == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.GasEstimateMessageGas(p0, p1, p2, p3)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*MessageSendSpec", + "summary": "", + "schema": { + "examples": [ + { + "MaxFee": "0", + "MsgUuid": "07070707-0707-0707-0707-070707070707", + "MaximizeFeeCap": true + } + ], + "additionalProperties": false, + "properties": { + "MaxFee": { + "additionalProperties": false, + "type": "object" + }, + "MaximizeFeeCap": { + "type": "boolean" + }, + "MsgUuid": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.Message", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5032" + } + }, + { + "name": "Filecoin.GetActorEventsRaw", + "description": "```go\nfunc (s *GatewayStruct) GetActorEventsRaw(p0 context.Context, p1 *types.ActorEventFilter) ([]*types.ActorEvent, error) {\n\tif s.Internal.GetActorEventsRaw == nil {\n\t\treturn *new([]*types.ActorEvent), ErrNotSupported\n\t}\n\treturn s.Internal.GetActorEventsRaw(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.ActorEventFilter", + "summary": "", + "schema": { + "examples": [ + { + "addresses": [ + "f01234" + ], + "fields": { + "abc": [ + { + "codec": 81, + "value": "ZGRhdGE=" + } + ] + }, + "fromHeight": 1010, + "toHeight": 1020 + } + ], + "additionalProperties": false, + "properties": { + "addresses": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "fields": { + "patternProperties": { + ".*": { + "items": { + "additionalProperties": false, + "properties": { + "codec": { + "title": "number", + "type": "number" + }, + "value": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "fromHeight": { + "title": "number", + "type": "number" + }, + "tipsetKey": { + "additionalProperties": false, + "type": "object" + }, + "toHeight": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*types.ActorEvent", + "description": "[]*types.ActorEvent", + "summary": "", + "schema": { + "examples": [ + [ + { + "entries": [ + { + "Flags": 7, + "Key": "string value", + "Codec": 42, + "Value": "Ynl0ZSBhcnJheQ==" + } + ], + "emitter": "f01234", + "reverted": true, + "height": 10101, + "tipsetKey": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "msgCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "emitter": { + "additionalProperties": false, + "type": "object" + }, + "entries": { + "items": { + "additionalProperties": false, + "properties": { + "Codec": { + "title": "number", + "type": "number" + }, + "Flags": { + "title": "number", + "type": "number" + }, + "Key": { + "type": "string" + }, + "Value": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "height": { + "title": "number", + "type": "number" + }, + "msgCid": { + "title": "Content Identifier", + "type": "string" + }, + "reverted": { + "type": "boolean" + }, + "tipsetKey": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5043" + } + }, + { + "name": "Filecoin.MinerGetBaseInfo", + "description": "```go\nfunc (s *GatewayStruct) MinerGetBaseInfo(p0 context.Context, p1 address.Address, p2 abi.ChainEpoch, p3 types.TipSetKey) (*MiningBaseInfo, error) {\n\tif s.Internal.MinerGetBaseInfo == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MinerGetBaseInfo(p0, p1, p2, p3)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MiningBaseInfo", + "description": "*MiningBaseInfo", + "summary": "", + "schema": { + "examples": [ + { + "MinerPower": "0", + "NetworkPower": "0", + "Sectors": [ + { + "SealProof": 8, + "SectorNumber": 9, + "SectorKey": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "WorkerKey": "f01234", + "SectorSize": 34359738368, + "PrevBeaconEntry": { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "BeaconEntries": [ + { + "Round": 42, + "Data": "Ynl0ZSBhcnJheQ==" + } + ], + "EligibleForMining": true + } + ], + "additionalProperties": false, + "properties": { + "BeaconEntries": { + "items": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Round": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "EligibleForMining": { + "type": "boolean" + }, + "MinerPower": { + "additionalProperties": false, + "type": "object" + }, + "NetworkPower": { + "additionalProperties": false, + "type": "object" + }, + "PrevBeaconEntry": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Round": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "SectorSize": { + "title": "number", + "type": "number" + }, + "Sectors": { + "items": { + "additionalProperties": false, + "properties": { + "SealProof": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorKey": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "WorkerKey": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5054" + } + }, + { + "name": "Filecoin.MpoolGetNonce", + "description": "```go\nfunc (s *GatewayStruct) MpoolGetNonce(p0 context.Context, p1 address.Address) (uint64, error) {\n\tif s.Internal.MpoolGetNonce == nil {\n\t\treturn 0, ErrNotSupported\n\t}\n\treturn s.Internal.MpoolGetNonce(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "uint64", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5065" + } + }, + { + "name": "Filecoin.MpoolPending", + "description": "```go\nfunc (s *GatewayStruct) MpoolPending(p0 context.Context, p1 types.TipSetKey) ([]*types.SignedMessage, error) {\n\tif s.Internal.MpoolPending == nil {\n\t\treturn *new([]*types.SignedMessage), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolPending(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*types.SignedMessage", + "description": "[]*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5076" + } + }, + { + "name": "Filecoin.MpoolPush", + "description": "```go\nfunc (s *GatewayStruct) MpoolPush(p0 context.Context, p1 *types.SignedMessage) (cid.Cid, error) {\n\tif s.Internal.MpoolPush == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.MpoolPush(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.SignedMessage", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "Message": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5087" + } + }, + { + "name": "Filecoin.MsigGetAvailableBalance", + "description": "```go\nfunc (s *GatewayStruct) MsigGetAvailableBalance(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.MsigGetAvailableBalance == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.MsigGetAvailableBalance(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5098" + } + }, + { + "name": "Filecoin.MsigGetPending", + "description": "```go\nfunc (s *GatewayStruct) MsigGetPending(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]*MsigTransaction, error) {\n\tif s.Internal.MsigGetPending == nil {\n\t\treturn *new([]*MsigTransaction), ErrNotSupported\n\t}\n\treturn s.Internal.MsigGetPending(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]*MsigTransaction", + "description": "[]*MsigTransaction", + "summary": "", + "schema": { + "examples": [ + [ + { + "ID": 9, + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "Approved": [ + "f01234" + ] + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Approved": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "ID": { + "title": "number", + "type": "number" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5109" + } + }, + { + "name": "Filecoin.MsigGetVested", + "description": "```go\nfunc (s *GatewayStruct) MsigGetVested(p0 context.Context, p1 address.Address, p2 types.TipSetKey, p3 types.TipSetKey) (types.BigInt, error) {\n\tif s.Internal.MsigGetVested == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.MsigGetVested(p0, p1, p2, p3)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5120" + } + }, + { + "name": "Filecoin.MsigGetVestingSchedule", + "description": "```go\nfunc (s *GatewayStruct) MsigGetVestingSchedule(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MsigVesting, error) {\n\tif s.Internal.MsigGetVestingSchedule == nil {\n\t\treturn *new(MsigVesting), ErrNotSupported\n\t}\n\treturn s.Internal.MsigGetVestingSchedule(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "MsigVesting", + "description": "MsigVesting", + "summary": "", + "schema": { + "examples": [ + { + "InitialBalance": "0", + "StartEpoch": 10101, + "UnlockDuration": 10101 + } + ], + "additionalProperties": false, + "properties": { + "InitialBalance": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "UnlockDuration": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5131" + } + }, + { + "name": "Filecoin.NetListening", + "description": "```go\nfunc (s *GatewayStruct) NetListening(p0 context.Context) (bool, error) {\n\tif s.Internal.NetListening == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.NetListening(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5142" + } + }, + { + "name": "Filecoin.NetVersion", + "description": "```go\nfunc (s *GatewayStruct) NetVersion(p0 context.Context) (string, error) {\n\tif s.Internal.NetVersion == nil {\n\t\treturn \"\", ErrNotSupported\n\t}\n\treturn s.Internal.NetVersion(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "string", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5153" + } + }, + { + "name": "Filecoin.StateAccountKey", + "description": "```go\nfunc (s *GatewayStruct) StateAccountKey(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) {\n\tif s.Internal.StateAccountKey == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.StateAccountKey(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5164" + } + }, + { + "name": "Filecoin.StateCall", + "description": "```go\nfunc (s *GatewayStruct) StateCall(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (*InvocResult, error) {\n\tif s.Internal.StateCall == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateCall(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*types.Message", + "summary": "", + "schema": { + "examples": [ + { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + } + ], + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*InvocResult", + "description": "*InvocResult", + "summary": "", + "schema": { + "examples": [ + { + "MsgCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Msg": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "GasCost": { + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "GasUsed": "0", + "BaseFeeBurn": "0", + "OverEstimationBurn": "0", + "MinerPenalty": "0", + "MinerTip": "0", + "Refund": "0", + "TotalCost": "0" + }, + "ExecutionTrace": { + "Msg": { + "From": "f01234", + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "ParamsCodec": 42, + "GasLimit": 42, + "ReadOnly": true + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "ReturnCodec": 42 + }, + "InvokedActor": { + "Id": 1000, + "State": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + }, + "GasCharges": [ + { + "Name": "string value", + "tg": 9, + "cg": 9, + "sg": 9, + "tt": 60000000000 + } + ], + "Subcalls": [ + { + "Msg": { + "From": "f01234", + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "ParamsCodec": 42, + "GasLimit": 42, + "ReadOnly": true + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "ReturnCodec": 42 + }, + "InvokedActor": { + "Id": 1000, + "State": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + }, + "GasCharges": [ + { + "Name": "string value", + "tg": 9, + "cg": 9, + "sg": 9, + "tt": 60000000000 + } + ], + "Subcalls": null + } + ] + }, + "Error": "string value", + "Duration": 60000000000 + } + ], + "additionalProperties": false, + "properties": { + "Duration": { + "title": "number", + "type": "number" + }, + "Error": { + "type": "string" + }, + "ExecutionTrace": { + "additionalProperties": false, + "properties": { + "GasCharges": { + "items": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "cg": { + "title": "number", + "type": "number" + }, + "sg": { + "title": "number", + "type": "number" + }, + "tg": { + "title": "number", + "type": "number" + }, + "tt": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "InvokedActor": { + "additionalProperties": false, + "properties": { + "Id": { + "title": "number", + "type": "number" + }, + "State": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Balance": { + "additionalProperties": false, + "type": "object" + }, + "Code": { + "title": "Content Identifier", + "type": "string" + }, + "Head": { + "title": "Content Identifier", + "type": "string" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Msg": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ParamsCodec": { + "title": "number", + "type": "number" + }, + "ReadOnly": { + "type": "boolean" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "MsgRct": { + "additionalProperties": false, + "properties": { + "ExitCode": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ReturnCodec": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Subcalls": { + "items": {}, + "type": "array" + } + }, + "type": "object" + }, + "GasCost": { + "additionalProperties": false, + "properties": { + "BaseFeeBurn": { + "additionalProperties": false, + "type": "object" + }, + "GasUsed": { + "additionalProperties": false, + "type": "object" + }, + "Message": { + "title": "Content Identifier", + "type": "string" + }, + "MinerPenalty": { + "additionalProperties": false, + "type": "object" + }, + "MinerTip": { + "additionalProperties": false, + "type": "object" + }, + "OverEstimationBurn": { + "additionalProperties": false, + "type": "object" + }, + "Refund": { + "additionalProperties": false, + "type": "object" + }, + "TotalCost": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "Msg": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "MsgCid": { + "title": "Content Identifier", + "type": "string" + }, + "MsgRct": { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5175" + } + }, + { + "name": "Filecoin.StateDealProviderCollateralBounds", + "description": "```go\nfunc (s *GatewayStruct) StateDealProviderCollateralBounds(p0 context.Context, p1 abi.PaddedPieceSize, p2 bool, p3 types.TipSetKey) (DealCollateralBounds, error) {\n\tif s.Internal.StateDealProviderCollateralBounds == nil {\n\t\treturn *new(DealCollateralBounds), ErrNotSupported\n\t}\n\treturn s.Internal.StateDealProviderCollateralBounds(p0, p1, p2, p3)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.PaddedPieceSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1032 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "DealCollateralBounds", + "description": "DealCollateralBounds", + "summary": "", + "schema": { + "examples": [ + { + "Min": "0", + "Max": "0" + } + ], + "additionalProperties": false, + "properties": { + "Max": { + "additionalProperties": false, + "type": "object" + }, + "Min": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5186" + } + }, + { + "name": "Filecoin.StateDecodeParams", + "description": "```go\nfunc (s *GatewayStruct) StateDecodeParams(p0 context.Context, p1 address.Address, p2 abi.MethodNum, p3 []byte, p4 types.TipSetKey) (interface{}, error) {\n\tif s.Internal.StateDecodeParams == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateDecodeParams(p0, p1, p2, p3, p4)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.MethodNum", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]byte", + "summary": "", + "schema": { + "examples": [ + "Ynl0ZSBhcnJheQ==" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "interface{}", + "description": "interface{}", + "summary": "", + "schema": { + "examples": [ + {} + ], + "additionalProperties": true, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5197" + } + }, + { + "name": "Filecoin.StateGetActor", + "description": "```go\nfunc (s *GatewayStruct) StateGetActor(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*types.Actor, error) {\n\tif s.Internal.StateGetActor == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateGetActor(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*types.Actor", + "description": "*types.Actor", + "summary": "", + "schema": { + "examples": [ + { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + ], + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Balance": { + "additionalProperties": false, + "type": "object" + }, + "Code": { + "title": "Content Identifier", + "type": "string" + }, + "Head": { + "title": "Content Identifier", + "type": "string" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5208" + } + }, + { + "name": "Filecoin.StateGetAllocation", + "description": "```go\nfunc (s *GatewayStruct) StateGetAllocation(p0 context.Context, p1 address.Address, p2 verifregtypes.AllocationId, p3 types.TipSetKey) (*verifregtypes.Allocation, error) {\n\tif s.Internal.StateGetAllocation == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateGetAllocation(p0, p1, p2, p3)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "verifregtypes.AllocationId", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 0 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*verifregtypes.Allocation", + "description": "*verifregtypes.Allocation", + "summary": "", + "schema": { + "examples": [ + { + "Client": 1000, + "Provider": 1000, + "Data": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 1032, + "TermMin": 10101, + "TermMax": 10101, + "Expiration": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5219" + } + }, + { + "name": "Filecoin.StateGetAllocationForPendingDeal", + "description": "```go\nfunc (s *GatewayStruct) StateGetAllocationForPendingDeal(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*verifregtypes.Allocation, error) {\n\tif s.Internal.StateGetAllocationForPendingDeal == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateGetAllocationForPendingDeal(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.DealID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 5432 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*verifregtypes.Allocation", + "description": "*verifregtypes.Allocation", + "summary": "", + "schema": { + "examples": [ + { + "Client": 1000, + "Provider": 1000, + "Data": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 1032, + "TermMin": 10101, + "TermMax": 10101, + "Expiration": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5230" + } + }, + { + "name": "Filecoin.StateGetAllocations", + "description": "```go\nfunc (s *GatewayStruct) StateGetAllocations(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.AllocationId]verifregtypes.Allocation, error) {\n\tif s.Internal.StateGetAllocations == nil {\n\t\treturn *new(map[verifregtypes.AllocationId]verifregtypes.Allocation), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetAllocations(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[verifregtypes.AllocationId]verifregtypes.Allocation", + "description": "map[verifregtypes.AllocationId]verifregtypes.Allocation", + "summary": "", + "schema": { + "examples": [ + {} + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5241" + } + }, + { + "name": "Filecoin.StateGetClaim", + "description": "```go\nfunc (s *GatewayStruct) StateGetClaim(p0 context.Context, p1 address.Address, p2 verifregtypes.ClaimId, p3 types.TipSetKey) (*verifregtypes.Claim, error) {\n\tif s.Internal.StateGetClaim == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateGetClaim(p0, p1, p2, p3)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "verifregtypes.ClaimId", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 0 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*verifregtypes.Claim", + "description": "*verifregtypes.Claim", + "summary": "", + "schema": { + "examples": [ + { + "Provider": 1000, + "Client": 1000, + "Data": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 1032, + "TermMin": 10101, + "TermMax": 10101, + "TermStart": 10101, + "Sector": 9 + } + ], + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Sector": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + }, + "TermStart": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5252" + } + }, + { + "name": "Filecoin.StateGetClaims", + "description": "```go\nfunc (s *GatewayStruct) StateGetClaims(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (map[verifregtypes.ClaimId]verifregtypes.Claim, error) {\n\tif s.Internal.StateGetClaims == nil {\n\t\treturn *new(map[verifregtypes.ClaimId]verifregtypes.Claim), ErrNotSupported\n\t}\n\treturn s.Internal.StateGetClaims(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[verifregtypes.ClaimId]verifregtypes.Claim", + "description": "map[verifregtypes.ClaimId]verifregtypes.Claim", + "summary": "", + "schema": { + "examples": [ + {} + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "Data": { + "title": "Content Identifier", + "type": "string" + }, + "Provider": { + "title": "number", + "type": "number" + }, + "Sector": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + }, + "TermMax": { + "title": "number", + "type": "number" + }, + "TermMin": { + "title": "number", + "type": "number" + }, + "TermStart": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5263" + } + }, + { + "name": "Filecoin.StateListMiners", + "description": "```go\nfunc (s *GatewayStruct) StateListMiners(p0 context.Context, p1 types.TipSetKey) ([]address.Address, error) {\n\tif s.Internal.StateListMiners == nil {\n\t\treturn *new([]address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.StateListMiners(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]address.Address", + "description": "[]address.Address", + "summary": "", + "schema": { + "examples": [ + [ + "f01234" + ] + ], + "items": [ + { + "additionalProperties": false, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5274" + } + }, + { + "name": "Filecoin.StateLookupID", + "description": "```go\nfunc (s *GatewayStruct) StateLookupID(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (address.Address, error) {\n\tif s.Internal.StateLookupID == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.StateLookupID(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5285" + } + }, + { + "name": "Filecoin.StateMarketBalance", + "description": "```go\nfunc (s *GatewayStruct) StateMarketBalance(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MarketBalance, error) {\n\tif s.Internal.StateMarketBalance == nil {\n\t\treturn *new(MarketBalance), ErrNotSupported\n\t}\n\treturn s.Internal.StateMarketBalance(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "MarketBalance", + "description": "MarketBalance", + "summary": "", + "schema": { + "examples": [ + { + "Escrow": "0", + "Locked": "0" + } + ], + "additionalProperties": false, + "properties": { + "Escrow": { + "additionalProperties": false, + "type": "object" + }, + "Locked": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5296" + } + }, + { + "name": "Filecoin.StateMarketStorageDeal", + "description": "```go\nfunc (s *GatewayStruct) StateMarketStorageDeal(p0 context.Context, p1 abi.DealID, p2 types.TipSetKey) (*MarketDeal, error) {\n\tif s.Internal.StateMarketStorageDeal == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateMarketStorageDeal(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.DealID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 5432 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MarketDeal", + "description": "*MarketDeal", + "summary": "", + "schema": { + "examples": [ + { + "Proposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "State": { + "SectorStartEpoch": 10101, + "LastUpdatedEpoch": 10101, + "SlashEpoch": 10101 + } + } + ], + "additionalProperties": false, + "properties": { + "Proposal": { + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "ClientCollateral": { + "additionalProperties": false, + "type": "object" + }, + "EndEpoch": { + "title": "number", + "type": "number" + }, + "Label": { + "additionalProperties": false, + "type": "object" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "StoragePricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + } + }, + "type": "object" + }, + "State": { + "additionalProperties": false, + "properties": { + "LastUpdatedEpoch": { + "title": "number", + "type": "number" + }, + "SectorStartEpoch": { + "title": "number", + "type": "number" + }, + "SlashEpoch": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5307" + } + }, + { + "name": "Filecoin.StateMinerDeadlines", + "description": "```go\nfunc (s *GatewayStruct) StateMinerDeadlines(p0 context.Context, p1 address.Address, p2 types.TipSetKey) ([]Deadline, error) {\n\tif s.Internal.StateMinerDeadlines == nil {\n\t\treturn *new([]Deadline), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerDeadlines(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]Deadline", + "description": "[]Deadline", + "summary": "", + "schema": { + "examples": [ + [ + { + "PostSubmissions": [ + 5, + 1 + ], + "DisputableProofCount": 42 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "DisputableProofCount": { + "title": "number", + "type": "number" + }, + "PostSubmissions": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5318" + } + }, + { + "name": "Filecoin.StateMinerInfo", + "description": "```go\nfunc (s *GatewayStruct) StateMinerInfo(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerInfo, error) {\n\tif s.Internal.StateMinerInfo == nil {\n\t\treturn *new(MinerInfo), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerInfo(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "MinerInfo", + "description": "MinerInfo", + "summary": "", + "schema": { + "examples": [ + { + "Owner": "f01234", + "Worker": "f01234", + "NewWorker": "f01234", + "ControlAddresses": [ + "f01234" + ], + "WorkerChangeEpoch": 10101, + "PeerId": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Multiaddrs": [ + "Ynl0ZSBhcnJheQ==" + ], + "WindowPoStProofType": 8, + "SectorSize": 34359738368, + "WindowPoStPartitionSectors": 42, + "ConsensusFaultElapsed": 10101, + "PendingOwnerAddress": "f01234", + "Beneficiary": "f01234", + "BeneficiaryTerm": { + "Quota": "0", + "UsedQuota": "0", + "Expiration": 10101 + }, + "PendingBeneficiaryTerm": { + "NewBeneficiary": "f01234", + "NewQuota": "0", + "NewExpiration": 10101, + "ApprovedByBeneficiary": true, + "ApprovedByNominee": true + } + } + ], + "additionalProperties": false, + "properties": { + "Beneficiary": { + "additionalProperties": false, + "type": "object" + }, + "BeneficiaryTerm": { + "additionalProperties": false, + "properties": { + "Expiration": { + "title": "number", + "type": "number" + }, + "Quota": { + "additionalProperties": false, + "type": "object" + }, + "UsedQuota": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "ConsensusFaultElapsed": { + "title": "number", + "type": "number" + }, + "ControlAddresses": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "Multiaddrs": { + "items": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "type": "array" + }, + "NewWorker": { + "additionalProperties": false, + "type": "object" + }, + "Owner": { + "additionalProperties": false, + "type": "object" + }, + "PeerId": { + "type": "string" + }, + "PendingBeneficiaryTerm": { + "additionalProperties": false, + "properties": { + "ApprovedByBeneficiary": { + "type": "boolean" + }, + "ApprovedByNominee": { + "type": "boolean" + }, + "NewBeneficiary": { + "additionalProperties": false, + "type": "object" + }, + "NewExpiration": { + "title": "number", + "type": "number" + }, + "NewQuota": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "PendingOwnerAddress": { + "additionalProperties": false, + "type": "object" + }, + "SectorSize": { + "title": "number", + "type": "number" + }, + "WindowPoStPartitionSectors": { + "title": "number", + "type": "number" + }, + "WindowPoStProofType": { + "title": "number", + "type": "number" + }, + "Worker": { + "additionalProperties": false, + "type": "object" + }, + "WorkerChangeEpoch": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5329" + } + }, + { + "name": "Filecoin.StateMinerPower", + "description": "```go\nfunc (s *GatewayStruct) StateMinerPower(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*MinerPower, error) {\n\tif s.Internal.StateMinerPower == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerPower(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MinerPower", + "description": "*MinerPower", + "summary": "", + "schema": { + "examples": [ + { + "MinerPower": { + "RawBytePower": "0", + "QualityAdjPower": "0" + }, + "TotalPower": { + "RawBytePower": "0", + "QualityAdjPower": "0" + }, + "HasMinPower": true + } + ], + "additionalProperties": false, + "properties": { + "HasMinPower": { + "type": "boolean" + }, + "MinerPower": { + "additionalProperties": false, + "properties": { + "QualityAdjPower": { + "additionalProperties": false, + "type": "object" + }, + "RawBytePower": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "TotalPower": { + "additionalProperties": false, + "properties": { + "QualityAdjPower": { + "additionalProperties": false, + "type": "object" + }, + "RawBytePower": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5340" + } + }, + { + "name": "Filecoin.StateMinerProvingDeadline", + "description": "```go\nfunc (s *GatewayStruct) StateMinerProvingDeadline(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*dline.Info, error) {\n\tif s.Internal.StateMinerProvingDeadline == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerProvingDeadline(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*dline.Info", + "description": "*dline.Info", + "summary": "", + "schema": { + "examples": [ + { + "CurrentEpoch": 10101, + "PeriodStart": 10101, + "Index": 42, + "Open": 10101, + "Close": 10101, + "Challenge": 10101, + "FaultCutoff": 10101, + "WPoStPeriodDeadlines": 42, + "WPoStProvingPeriod": 10101, + "WPoStChallengeWindow": 10101, + "WPoStChallengeLookback": 10101, + "FaultDeclarationCutoff": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Challenge": { + "title": "number", + "type": "number" + }, + "Close": { + "title": "number", + "type": "number" + }, + "CurrentEpoch": { + "title": "number", + "type": "number" + }, + "FaultCutoff": { + "title": "number", + "type": "number" + }, + "FaultDeclarationCutoff": { + "title": "number", + "type": "number" + }, + "Index": { + "title": "number", + "type": "number" + }, + "Open": { + "title": "number", + "type": "number" + }, + "PeriodStart": { + "title": "number", + "type": "number" + }, + "WPoStChallengeLookback": { + "title": "number", + "type": "number" + }, + "WPoStChallengeWindow": { + "title": "number", + "type": "number" + }, + "WPoStPeriodDeadlines": { + "title": "number", + "type": "number" + }, + "WPoStProvingPeriod": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5351" + } + }, + { + "name": "Filecoin.StateMinerSectorCount", + "description": "```go\nfunc (s *GatewayStruct) StateMinerSectorCount(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (MinerSectors, error) {\n\tif s.Internal.StateMinerSectorCount == nil {\n\t\treturn *new(MinerSectors), ErrNotSupported\n\t}\n\treturn s.Internal.StateMinerSectorCount(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "MinerSectors", + "description": "MinerSectors", + "summary": "", + "schema": { + "examples": [ + { + "Live": 42, + "Active": 42, + "Faulty": 42 + } + ], + "additionalProperties": false, + "properties": { + "Active": { + "title": "number", + "type": "number" + }, + "Faulty": { + "title": "number", + "type": "number" + }, + "Live": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5362" + } + }, + { + "name": "Filecoin.StateNetworkName", + "description": "```go\nfunc (s *GatewayStruct) StateNetworkName(p0 context.Context) (dtypes.NetworkName, error) {\n\tif s.Internal.StateNetworkName == nil {\n\t\treturn *new(dtypes.NetworkName), ErrNotSupported\n\t}\n\treturn s.Internal.StateNetworkName(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "dtypes.NetworkName", + "description": "dtypes.NetworkName", + "summary": "", + "schema": { + "examples": [ + "lotus" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5373" + } + }, + { + "name": "Filecoin.StateNetworkVersion", + "description": "```go\nfunc (s *GatewayStruct) StateNetworkVersion(p0 context.Context, p1 types.TipSetKey) (apitypes.NetworkVersion, error) {\n\tif s.Internal.StateNetworkVersion == nil {\n\t\treturn *new(apitypes.NetworkVersion), ErrNotSupported\n\t}\n\treturn s.Internal.StateNetworkVersion(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "apitypes.NetworkVersion", + "description": "apitypes.NetworkVersion", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 22 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5384" + } + }, + { + "name": "Filecoin.StateReadState", + "description": "```go\nfunc (s *GatewayStruct) StateReadState(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*ActorState, error) {\n\tif s.Internal.StateReadState == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateReadState(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*ActorState", + "description": "*ActorState", + "summary": "", + "schema": { + "examples": [ + { + "Balance": "0", + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "State": {} + } + ], + "additionalProperties": false, + "properties": { + "Balance": { + "additionalProperties": false, + "type": "object" + }, + "Code": { + "title": "Content Identifier", + "type": "string" + }, + "State": { + "additionalProperties": true, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5395" + } + }, + { + "name": "Filecoin.StateReplay", + "description": "```go\nfunc (s *GatewayStruct) StateReplay(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid) (*InvocResult, error) {\n\tif s.Internal.StateReplay == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateReplay(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*InvocResult", + "description": "*InvocResult", + "summary": "", + "schema": { + "examples": [ + { + "MsgCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Msg": { + "Version": 42, + "To": "f01234", + "From": "f01234", + "Nonce": 42, + "Value": "0", + "GasLimit": 9, + "GasFeeCap": "0", + "GasPremium": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "CID": { + "/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s" + } + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "GasCost": { + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "GasUsed": "0", + "BaseFeeBurn": "0", + "OverEstimationBurn": "0", + "MinerPenalty": "0", + "MinerTip": "0", + "Refund": "0", + "TotalCost": "0" + }, + "ExecutionTrace": { + "Msg": { + "From": "f01234", + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "ParamsCodec": 42, + "GasLimit": 42, + "ReadOnly": true + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "ReturnCodec": 42 + }, + "InvokedActor": { + "Id": 1000, + "State": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + }, + "GasCharges": [ + { + "Name": "string value", + "tg": 9, + "cg": 9, + "sg": 9, + "tt": 60000000000 + } + ], + "Subcalls": [ + { + "Msg": { + "From": "f01234", + "To": "f01234", + "Value": "0", + "Method": 1, + "Params": "Ynl0ZSBhcnJheQ==", + "ParamsCodec": 42, + "GasLimit": 42, + "ReadOnly": true + }, + "MsgRct": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "ReturnCodec": 42 + }, + "InvokedActor": { + "Id": 1000, + "State": { + "Code": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Head": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Nonce": 42, + "Balance": "0", + "Address": "f01234" + } + }, + "GasCharges": [ + { + "Name": "string value", + "tg": 9, + "cg": 9, + "sg": 9, + "tt": 60000000000 + } + ], + "Subcalls": null + } + ] + }, + "Error": "string value", + "Duration": 60000000000 + } + ], + "additionalProperties": false, + "properties": { + "Duration": { + "title": "number", + "type": "number" + }, + "Error": { + "type": "string" + }, + "ExecutionTrace": { + "additionalProperties": false, + "properties": { + "GasCharges": { + "items": { + "additionalProperties": false, + "properties": { + "Name": { + "type": "string" + }, + "cg": { + "title": "number", + "type": "number" + }, + "sg": { + "title": "number", + "type": "number" + }, + "tg": { + "title": "number", + "type": "number" + }, + "tt": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "InvokedActor": { + "additionalProperties": false, + "properties": { + "Id": { + "title": "number", + "type": "number" + }, + "State": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Balance": { + "additionalProperties": false, + "type": "object" + }, + "Code": { + "title": "Content Identifier", + "type": "string" + }, + "Head": { + "title": "Content Identifier", + "type": "string" + }, + "Nonce": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Msg": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ParamsCodec": { + "title": "number", + "type": "number" + }, + "ReadOnly": { + "type": "boolean" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "MsgRct": { + "additionalProperties": false, + "properties": { + "ExitCode": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ReturnCodec": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Subcalls": { + "items": {}, + "type": "array" + } + }, + "type": "object" + }, + "GasCost": { + "additionalProperties": false, + "properties": { + "BaseFeeBurn": { + "additionalProperties": false, + "type": "object" + }, + "GasUsed": { + "additionalProperties": false, + "type": "object" + }, + "Message": { + "title": "Content Identifier", + "type": "string" + }, + "MinerPenalty": { + "additionalProperties": false, + "type": "object" + }, + "MinerTip": { + "additionalProperties": false, + "type": "object" + }, + "OverEstimationBurn": { + "additionalProperties": false, + "type": "object" + }, + "Refund": { + "additionalProperties": false, + "type": "object" + }, + "TotalCost": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "Msg": { + "additionalProperties": false, + "properties": { + "From": { + "additionalProperties": false, + "type": "object" + }, + "GasFeeCap": { + "additionalProperties": false, + "type": "object" + }, + "GasLimit": { + "title": "number", + "type": "number" + }, + "GasPremium": { + "additionalProperties": false, + "type": "object" + }, + "Method": { + "title": "number", + "type": "number" + }, + "Nonce": { + "title": "number", + "type": "number" + }, + "Params": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "To": { + "additionalProperties": false, + "type": "object" + }, + "Value": { + "additionalProperties": false, + "type": "object" + }, + "Version": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "MsgCid": { + "title": "Content Identifier", + "type": "string" + }, + "MsgRct": { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5406" + } + }, + { + "name": "Filecoin.StateSearchMsg", + "description": "```go\nfunc (s *GatewayStruct) StateSearchMsg(p0 context.Context, p1 types.TipSetKey, p2 cid.Cid, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) {\n\tif s.Internal.StateSearchMsg == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateSearchMsg(p0, p1, p2, p3, p4)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MsgLookup", + "description": "*MsgLookup", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Receipt": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "ReturnDec": {}, + "TipSet": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "Height": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Height": { + "title": "number", + "type": "number" + }, + "Message": { + "title": "Content Identifier", + "type": "string" + }, + "Receipt": { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "ReturnDec": { + "additionalProperties": true, + "type": "object" + }, + "TipSet": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5417" + } + }, + { + "name": "Filecoin.StateSectorGetInfo", + "description": "```go\nfunc (s *GatewayStruct) StateSectorGetInfo(p0 context.Context, p1 address.Address, p2 abi.SectorNumber, p3 types.TipSetKey) (*miner.SectorOnChainInfo, error) {\n\tif s.Internal.StateSectorGetInfo == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateSectorGetInfo(p0, p1, p2, p3)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*miner.SectorOnChainInfo", + "description": "*miner.SectorOnChainInfo", + "summary": "", + "schema": { + "examples": [ + { + "SectorNumber": 9, + "SealProof": 8, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DealIDs": [ + 5432 + ], + "Activation": 10101, + "Expiration": 10101, + "DealWeight": "0", + "VerifiedDealWeight": "0", + "InitialPledge": "0", + "ExpectedDayReward": "0", + "ExpectedStoragePledge": "0", + "PowerBaseEpoch": 10101, + "ReplacedDayReward": "0", + "SectorKeyCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Flags": 0 + } + ], + "additionalProperties": false, + "properties": { + "Activation": { + "title": "number", + "type": "number" + }, + "DealIDs": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "DealWeight": { + "additionalProperties": false, + "type": "object" + }, + "ExpectedDayReward": { + "additionalProperties": false, + "type": "object" + }, + "ExpectedStoragePledge": { + "additionalProperties": false, + "type": "object" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "Flags": { + "title": "number", + "type": "number" + }, + "InitialPledge": { + "additionalProperties": false, + "type": "object" + }, + "PowerBaseEpoch": { + "title": "number", + "type": "number" + }, + "ReplacedDayReward": { + "additionalProperties": false, + "type": "object" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorKeyCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "VerifiedDealWeight": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5428" + } + }, + { + "name": "Filecoin.StateVerifiedClientStatus", + "description": "```go\nfunc (s *GatewayStruct) StateVerifiedClientStatus(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) {\n\tif s.Internal.StateVerifiedClientStatus == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateVerifiedClientStatus(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*abi.StoragePower", + "description": "*abi.StoragePower", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5439" + } + }, + { + "name": "Filecoin.StateVerifierStatus", + "description": "```go\nfunc (s *GatewayStruct) StateVerifierStatus(p0 context.Context, p1 address.Address, p2 types.TipSetKey) (*abi.StoragePower, error) {\n\tif s.Internal.StateVerifierStatus == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateVerifierStatus(p0, p1, p2)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*abi.StoragePower", + "description": "*abi.StoragePower", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5450" + } + }, + { + "name": "Filecoin.StateWaitMsg", + "description": "```go\nfunc (s *GatewayStruct) StateWaitMsg(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) {\n\tif s.Internal.StateWaitMsg == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.StateWaitMsg(p0, p1, p2, p3, p4)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*MsgLookup", + "description": "*MsgLookup", + "summary": "", + "schema": { + "examples": [ + { + "Message": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Receipt": { + "ExitCode": 0, + "Return": "Ynl0ZSBhcnJheQ==", + "GasUsed": 9, + "EventsRoot": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "ReturnDec": {}, + "TipSet": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "Height": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Height": { + "title": "number", + "type": "number" + }, + "Message": { + "title": "Content Identifier", + "type": "string" + }, + "Receipt": { + "additionalProperties": false, + "properties": { + "EventsRoot": { + "title": "Content Identifier", + "type": "string" + }, + "ExitCode": { + "title": "number", + "type": "number" + }, + "GasUsed": { + "title": "number", + "type": "number" + }, + "Return": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "ReturnDec": { + "additionalProperties": true, + "type": "object" + }, + "TipSet": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5461" + } + }, + { + "name": "Filecoin.Version", + "description": "```go\nfunc (s *GatewayStruct) Version(p0 context.Context) (APIVersion, error) {\n\tif s.Internal.Version == nil {\n\t\treturn *new(APIVersion), ErrNotSupported\n\t}\n\treturn s.Internal.Version(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "APIVersion", + "description": "APIVersion", + "summary": "", + "schema": { + "examples": [ + { + "Version": "string value", + "APIVersion": 131840, + "BlockDelay": 42 + } + ], + "additionalProperties": false, + "properties": { + "APIVersion": { + "title": "number", + "type": "number" + }, + "BlockDelay": { + "title": "number", + "type": "number" + }, + "Version": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5483" + } + }, + { + "name": "Filecoin.WalletBalance", + "description": "```go\nfunc (s *GatewayStruct) WalletBalance(p0 context.Context, p1 address.Address) (types.BigInt, error) {\n\tif s.Internal.WalletBalance == nil {\n\t\treturn *new(types.BigInt), ErrNotSupported\n\t}\n\treturn s.Internal.WalletBalance(p0, p1)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "types.BigInt", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5494" + } + }, + { + "name": "Filecoin.Web3ClientVersion", + "description": "```go\nfunc (s *GatewayStruct) Web3ClientVersion(p0 context.Context) (string, error) {\n\tif s.Internal.Web3ClientVersion == nil {\n\t\treturn \"\", ErrNotSupported\n\t}\n\treturn s.Internal.Web3ClientVersion(p0)\n}\n```", + "summary": "There are not yet any comments for this method.", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "string", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5505" + } + } + ] +} \ No newline at end of file diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index 9c2dfbcf2a2..9f5dc38ee68 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/build/openrpc/miner.json b/build/openrpc/miner.json new file mode 100644 index 00000000000..d9f2f514548 --- /dev/null +++ b/build/openrpc/miner.json @@ -0,0 +1,12744 @@ +{ + "openrpc": "1.2.6", + "info": { + "title": "Lotus RPC API", + "version": "1.27.0" + }, + "methods": [ + { + "name": "Filecoin.ActorAddress", + "description": "```go\nfunc (s *StorageMinerStruct) ActorAddress(p0 context.Context) (address.Address, error) {\n\tif s.Internal.ActorAddress == nil {\n\t\treturn *new(address.Address), ErrNotSupported\n\t}\n\treturn s.Internal.ActorAddress(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "address.Address", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5791" + } + }, + { + "name": "Filecoin.ActorAddressConfig", + "description": "```go\nfunc (s *StorageMinerStruct) ActorAddressConfig(p0 context.Context) (AddressConfig, error) {\n\tif s.Internal.ActorAddressConfig == nil {\n\t\treturn *new(AddressConfig), ErrNotSupported\n\t}\n\treturn s.Internal.ActorAddressConfig(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "AddressConfig", + "description": "AddressConfig", + "summary": "", + "schema": { + "examples": [ + { + "PreCommitControl": [ + "f01234" + ], + "CommitControl": [ + "f01234" + ], + "TerminateControl": [ + "f01234" + ], + "DealPublishControl": [ + "f01234" + ], + "DisableOwnerFallback": true, + "DisableWorkerFallback": true + } + ], + "additionalProperties": false, + "properties": { + "CommitControl": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "DealPublishControl": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "DisableOwnerFallback": { + "type": "boolean" + }, + "DisableWorkerFallback": { + "type": "boolean" + }, + "PreCommitControl": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + }, + "TerminateControl": { + "items": { + "additionalProperties": false, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5802" + } + }, + { + "name": "Filecoin.ActorSectorSize", + "description": "```go\nfunc (s *StorageMinerStruct) ActorSectorSize(p0 context.Context, p1 address.Address) (abi.SectorSize, error) {\n\tif s.Internal.ActorSectorSize == nil {\n\t\treturn *new(abi.SectorSize), ErrNotSupported\n\t}\n\treturn s.Internal.ActorSectorSize(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "address.Address", + "summary": "", + "schema": { + "examples": [ + "f01234" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "abi.SectorSize", + "description": "abi.SectorSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 34359738368 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5813" + } + }, + { + "name": "Filecoin.ActorWithdrawBalance", + "description": "```go\nfunc (s *StorageMinerStruct) ActorWithdrawBalance(p0 context.Context, p1 abi.TokenAmount) (cid.Cid, error) {\n\tif s.Internal.ActorWithdrawBalance == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.ActorWithdrawBalance(p0, p1)\n}\n```", + "summary": "WithdrawBalance allows to withdraw balance from miner actor to owner address\nSpecify amount as \"0\" to withdraw full balance. This method returns a message CID\nand does not wait for message execution\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.TokenAmount", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5824" + } + }, + { + "name": "Filecoin.BeneficiaryWithdrawBalance", + "description": "```go\nfunc (s *StorageMinerStruct) BeneficiaryWithdrawBalance(p0 context.Context, p1 abi.TokenAmount) (cid.Cid, error) {\n\tif s.Internal.BeneficiaryWithdrawBalance == nil {\n\t\treturn *new(cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.BeneficiaryWithdrawBalance(p0, p1)\n}\n```", + "summary": "BeneficiaryWithdrawBalance allows the beneficiary of a miner to withdraw balance from miner actor\nSpecify amount as \"0\" to withdraw full balance. This method returns a message CID\nand does not wait for message execution\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.TokenAmount", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "cid.Cid", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5835" + } + }, + { + "name": "Filecoin.CheckProvable", + "description": "```go\nfunc (s *StorageMinerStruct) CheckProvable(p0 context.Context, p1 abi.RegisteredPoStProof, p2 []storiface.SectorRef) (map[abi.SectorNumber]string, error) {\n\tif s.Internal.CheckProvable == nil {\n\t\treturn *new(map[abi.SectorNumber]string), ErrNotSupported\n\t}\n\treturn s.Internal.CheckProvable(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.RegisteredPoStProof", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 8 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "[]storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "map[abi.SectorNumber]string", + "description": "map[abi.SectorNumber]string", + "summary": "", + "schema": { + "examples": [ + { + "123": "can't acquire read lock" + } + ], + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5846" + } + }, + { + "name": "Filecoin.ComputeDataCid", + "description": "```go\nfunc (s *StorageMinerStruct) ComputeDataCid(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data) (abi.PieceInfo, error) {\n\tif s.Internal.ComputeDataCid == nil {\n\t\treturn *new(abi.PieceInfo), ErrNotSupported\n\t}\n\treturn s.Internal.ComputeDataCid(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.UnpaddedPieceSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1024 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.Data", + "summary": "", + "schema": { + "examples": [ + {} + ], + "additionalProperties": true + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "abi.PieceInfo", + "description": "abi.PieceInfo", + "summary": "", + "schema": { + "examples": [ + { + "Size": 1032, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5857" + } + }, + { + "name": "Filecoin.ComputeProof", + "description": "```go\nfunc (s *StorageMinerStruct) ComputeProof(p0 context.Context, p1 []builtinactors.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtinactors.PoStProof, error) {\n\tif s.Internal.ComputeProof == nil {\n\t\treturn *new([]builtinactors.PoStProof), ErrNotSupported\n\t}\n\treturn s.Internal.ComputeProof(p0, p1, p2, p3, p4)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "[]builtinactors.ExtendedSectorInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "SealProof": 8, + "SectorNumber": 9, + "SectorKey": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "SealProof": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorKey": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.PoStRandomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "abinetwork.Version", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 22 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]builtinactors.PoStProof", + "description": "[]builtinactors.PoStProof", + "summary": "", + "schema": { + "examples": [ + [ + { + "PoStProof": 8, + "ProofBytes": "Ynl0ZSBhcnJheQ==" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "PoStProof": { + "title": "number", + "type": "number" + }, + "ProofBytes": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5868" + } + }, + { + "name": "Filecoin.ComputeWindowPoSt", + "description": "```go\nfunc (s *StorageMinerStruct) ComputeWindowPoSt(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) {\n\tif s.Internal.ComputeWindowPoSt == nil {\n\t\treturn *new([]miner.SubmitWindowedPoStParams), ErrNotSupported\n\t}\n\treturn s.Internal.ComputeWindowPoSt(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.TipSetKey", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]miner.SubmitWindowedPoStParams", + "description": "[]miner.SubmitWindowedPoStParams", + "summary": "", + "schema": { + "examples": [ + [ + { + "Deadline": 42, + "Partitions": [ + { + "Index": 42, + "Skipped": [ + 5, + 1 + ] + } + ], + "Proofs": [ + { + "PoStProof": 8, + "ProofBytes": "Ynl0ZSBhcnJheQ==" + } + ], + "ChainCommitEpoch": 10101, + "ChainCommitRand": "Bw==" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "ChainCommitEpoch": { + "title": "number", + "type": "number" + }, + "ChainCommitRand": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "Deadline": { + "title": "number", + "type": "number" + }, + "Partitions": { + "items": { + "additionalProperties": false, + "properties": { + "Index": { + "title": "number", + "type": "number" + }, + "Skipped": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Proofs": { + "items": { + "additionalProperties": false, + "properties": { + "PoStProof": { + "title": "number", + "type": "number" + }, + "ProofBytes": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5879" + } + }, + { + "name": "Filecoin.CreateBackup", + "description": "```go\nfunc (s *StorageMinerStruct) CreateBackup(p0 context.Context, p1 string) error {\n\tif s.Internal.CreateBackup == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.CreateBackup(p0, p1)\n}\n```", + "summary": "CreateBackup creates node backup onder the specified file name. The\nmethod requires that the lotus-miner is running with the\nLOTUS_BACKUP_BASE_PATH environment variable set to some path, and that\nthe path specified when calling CreateBackup is within the base path\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5890" + } + }, + { + "name": "Filecoin.DagstoreGC", + "description": "```go\nfunc (s *StorageMinerStruct) DagstoreGC(p0 context.Context) ([]DagstoreShardResult, error) {\n\tif s.Internal.DagstoreGC == nil {\n\t\treturn *new([]DagstoreShardResult), ErrNotSupported\n\t}\n\treturn s.Internal.DagstoreGC(p0)\n}\n```", + "summary": "DagstoreGC runs garbage collection on the DAG store.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]DagstoreShardResult", + "description": "[]DagstoreShardResult", + "summary": "", + "schema": { + "examples": [ + [ + { + "Key": "baga6ea4seaqecmtz7iak33dsfshi627abz4i4665dfuzr3qfs4bmad6dx3iigdq", + "Success": false, + "Error": "\u003cerror\u003e" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Error": { + "type": "string" + }, + "Key": { + "type": "string" + }, + "Success": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5901" + } + }, + { + "name": "Filecoin.DagstoreInitializeShard", + "description": "```go\nfunc (s *StorageMinerStruct) DagstoreInitializeShard(p0 context.Context, p1 string) error {\n\tif s.Internal.DagstoreInitializeShard == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DagstoreInitializeShard(p0, p1)\n}\n```", + "summary": "DagstoreInitializeShard initializes an uninitialized shard.\n\nInitialization consists of fetching the shard's data (deal payload) from\nthe storage subsystem, generating an index, and persisting the index\nto facilitate later retrievals, and/or to publish to external sources.\n\nThis operation is intended to complement the initial migration. The\nmigration registers a shard for every unique piece CID, with lazy\ninitialization. Thus, shards are not initialized immediately to avoid\nIO activity competing with proving. Instead, shard are initialized\nwhen first accessed. This method forces the initialization of a shard by\naccessing it and immediately releasing it. This is useful to warm up the\ncache to facilitate subsequent retrievals, and to generate the indexes\nto publish them externally.\n\nThis operation fails if the shard is not in ShardStateNew state.\nIt blocks until initialization finishes.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5923" + } + }, + { + "name": "Filecoin.DagstoreListShards", + "description": "```go\nfunc (s *StorageMinerStruct) DagstoreListShards(p0 context.Context) ([]DagstoreShardInfo, error) {\n\tif s.Internal.DagstoreListShards == nil {\n\t\treturn *new([]DagstoreShardInfo), ErrNotSupported\n\t}\n\treturn s.Internal.DagstoreListShards(p0)\n}\n```", + "summary": "DagstoreListShards returns information about all shards known to the\nDAG store. Only available on nodes running the markets subsystem.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]DagstoreShardInfo", + "description": "[]DagstoreShardInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "Key": "baga6ea4seaqecmtz7iak33dsfshi627abz4i4665dfuzr3qfs4bmad6dx3iigdq", + "State": "ShardStateAvailable", + "Error": "\u003cerror\u003e" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Error": { + "type": "string" + }, + "Key": { + "type": "string" + }, + "State": { + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5934" + } + }, + { + "name": "Filecoin.DagstoreLookupPieces", + "description": "```go\nfunc (s *StorageMinerStruct) DagstoreLookupPieces(p0 context.Context, p1 cid.Cid) ([]DagstoreShardInfo, error) {\n\tif s.Internal.DagstoreLookupPieces == nil {\n\t\treturn *new([]DagstoreShardInfo), ErrNotSupported\n\t}\n\treturn s.Internal.DagstoreLookupPieces(p0, p1)\n}\n```", + "summary": "DagstoreLookupPieces returns information about shards that contain the given CID.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]DagstoreShardInfo", + "description": "[]DagstoreShardInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "Key": "baga6ea4seaqecmtz7iak33dsfshi627abz4i4665dfuzr3qfs4bmad6dx3iigdq", + "State": "ShardStateAvailable", + "Error": "\u003cerror\u003e" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Error": { + "type": "string" + }, + "Key": { + "type": "string" + }, + "State": { + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5945" + } + }, + { + "name": "Filecoin.DagstoreRecoverShard", + "description": "```go\nfunc (s *StorageMinerStruct) DagstoreRecoverShard(p0 context.Context, p1 string) error {\n\tif s.Internal.DagstoreRecoverShard == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DagstoreRecoverShard(p0, p1)\n}\n```", + "summary": "DagstoreRecoverShard attempts to recover a failed shard.\n\nThis operation fails if the shard is not in ShardStateErrored state.\nIt blocks until recovery finishes. If recovery failed, it returns the\nerror.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5956" + } + }, + { + "name": "Filecoin.DagstoreRegisterShard", + "description": "```go\nfunc (s *StorageMinerStruct) DagstoreRegisterShard(p0 context.Context, p1 string) error {\n\tif s.Internal.DagstoreRegisterShard == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DagstoreRegisterShard(p0, p1)\n}\n```", + "summary": "DagstoreRegisterShard registers a shard manually with dagstore with given pieceCID\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5967" + } + }, + { + "name": "Filecoin.DealsConsiderOfflineRetrievalDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsConsiderOfflineRetrievalDeals(p0 context.Context) (bool, error) {\n\tif s.Internal.DealsConsiderOfflineRetrievalDeals == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.DealsConsiderOfflineRetrievalDeals(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5978" + } + }, + { + "name": "Filecoin.DealsConsiderOfflineStorageDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsConsiderOfflineStorageDeals(p0 context.Context) (bool, error) {\n\tif s.Internal.DealsConsiderOfflineStorageDeals == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.DealsConsiderOfflineStorageDeals(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L5989" + } + }, + { + "name": "Filecoin.DealsConsiderOnlineRetrievalDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsConsiderOnlineRetrievalDeals(p0 context.Context) (bool, error) {\n\tif s.Internal.DealsConsiderOnlineRetrievalDeals == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.DealsConsiderOnlineRetrievalDeals(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6000" + } + }, + { + "name": "Filecoin.DealsConsiderOnlineStorageDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsConsiderOnlineStorageDeals(p0 context.Context) (bool, error) {\n\tif s.Internal.DealsConsiderOnlineStorageDeals == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.DealsConsiderOnlineStorageDeals(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6011" + } + }, + { + "name": "Filecoin.DealsConsiderUnverifiedStorageDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsConsiderUnverifiedStorageDeals(p0 context.Context) (bool, error) {\n\tif s.Internal.DealsConsiderUnverifiedStorageDeals == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.DealsConsiderUnverifiedStorageDeals(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6022" + } + }, + { + "name": "Filecoin.DealsConsiderVerifiedStorageDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsConsiderVerifiedStorageDeals(p0 context.Context) (bool, error) {\n\tif s.Internal.DealsConsiderVerifiedStorageDeals == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.DealsConsiderVerifiedStorageDeals(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6033" + } + }, + { + "name": "Filecoin.DealsImportData", + "description": "```go\nfunc (s *StorageMinerStruct) DealsImportData(p0 context.Context, p1 cid.Cid, p2 string) error {\n\tif s.Internal.DealsImportData == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DealsImportData(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6044" + } + }, + { + "name": "Filecoin.DealsList", + "description": "```go\nfunc (s *StorageMinerStruct) DealsList(p0 context.Context) ([]*MarketDeal, error) {\n\tif s.Internal.DealsList == nil {\n\t\treturn *new([]*MarketDeal), ErrNotSupported\n\t}\n\treturn s.Internal.DealsList(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]*MarketDeal", + "description": "[]*MarketDeal", + "summary": "", + "schema": { + "examples": [ + [ + { + "Proposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "State": { + "SectorStartEpoch": 10101, + "LastUpdatedEpoch": 10101, + "SlashEpoch": 10101 + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Proposal": { + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "ClientCollateral": { + "additionalProperties": false, + "type": "object" + }, + "EndEpoch": { + "title": "number", + "type": "number" + }, + "Label": { + "additionalProperties": false, + "type": "object" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "StoragePricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + } + }, + "type": "object" + }, + "State": { + "additionalProperties": false, + "properties": { + "LastUpdatedEpoch": { + "title": "number", + "type": "number" + }, + "SectorStartEpoch": { + "title": "number", + "type": "number" + }, + "SlashEpoch": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6055" + } + }, + { + "name": "Filecoin.DealsPieceCidBlocklist", + "description": "```go\nfunc (s *StorageMinerStruct) DealsPieceCidBlocklist(p0 context.Context) ([]cid.Cid, error) {\n\tif s.Internal.DealsPieceCidBlocklist == nil {\n\t\treturn *new([]cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.DealsPieceCidBlocklist(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]cid.Cid", + "description": "[]cid.Cid", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + ], + "items": [ + { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6066" + } + }, + { + "name": "Filecoin.DealsSetConsiderOfflineRetrievalDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsSetConsiderOfflineRetrievalDeals(p0 context.Context, p1 bool) error {\n\tif s.Internal.DealsSetConsiderOfflineRetrievalDeals == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DealsSetConsiderOfflineRetrievalDeals(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6077" + } + }, + { + "name": "Filecoin.DealsSetConsiderOfflineStorageDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsSetConsiderOfflineStorageDeals(p0 context.Context, p1 bool) error {\n\tif s.Internal.DealsSetConsiderOfflineStorageDeals == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DealsSetConsiderOfflineStorageDeals(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6088" + } + }, + { + "name": "Filecoin.DealsSetConsiderOnlineRetrievalDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsSetConsiderOnlineRetrievalDeals(p0 context.Context, p1 bool) error {\n\tif s.Internal.DealsSetConsiderOnlineRetrievalDeals == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DealsSetConsiderOnlineRetrievalDeals(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6099" + } + }, + { + "name": "Filecoin.DealsSetConsiderOnlineStorageDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsSetConsiderOnlineStorageDeals(p0 context.Context, p1 bool) error {\n\tif s.Internal.DealsSetConsiderOnlineStorageDeals == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DealsSetConsiderOnlineStorageDeals(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6110" + } + }, + { + "name": "Filecoin.DealsSetConsiderUnverifiedStorageDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsSetConsiderUnverifiedStorageDeals(p0 context.Context, p1 bool) error {\n\tif s.Internal.DealsSetConsiderUnverifiedStorageDeals == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DealsSetConsiderUnverifiedStorageDeals(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6121" + } + }, + { + "name": "Filecoin.DealsSetConsiderVerifiedStorageDeals", + "description": "```go\nfunc (s *StorageMinerStruct) DealsSetConsiderVerifiedStorageDeals(p0 context.Context, p1 bool) error {\n\tif s.Internal.DealsSetConsiderVerifiedStorageDeals == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DealsSetConsiderVerifiedStorageDeals(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6132" + } + }, + { + "name": "Filecoin.DealsSetPieceCidBlocklist", + "description": "```go\nfunc (s *StorageMinerStruct) DealsSetPieceCidBlocklist(p0 context.Context, p1 []cid.Cid) error {\n\tif s.Internal.DealsSetPieceCidBlocklist == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.DealsSetPieceCidBlocklist(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "[]cid.Cid", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + ], + "items": [ + { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6143" + } + }, + { + "name": "Filecoin.IndexerAnnounceAllDeals", + "description": "```go\nfunc (s *StorageMinerStruct) IndexerAnnounceAllDeals(p0 context.Context) error {\n\tif s.Internal.IndexerAnnounceAllDeals == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.IndexerAnnounceAllDeals(p0)\n}\n```", + "summary": "IndexerAnnounceAllDeals informs the indexer nodes aboutall active deals.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6154" + } + }, + { + "name": "Filecoin.IndexerAnnounceDeal", + "description": "```go\nfunc (s *StorageMinerStruct) IndexerAnnounceDeal(p0 context.Context, p1 cid.Cid) error {\n\tif s.Internal.IndexerAnnounceDeal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.IndexerAnnounceDeal(p0, p1)\n}\n```", + "summary": "IndexerAnnounceDeal informs indexer nodes that a new deal was received,\nso they can download its index\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6165" + } + }, + { + "name": "Filecoin.MarketCancelDataTransfer", + "description": "```go\nfunc (s *StorageMinerStruct) MarketCancelDataTransfer(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error {\n\tif s.Internal.MarketCancelDataTransfer == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.MarketCancelDataTransfer(p0, p1, p2, p3)\n}\n```", + "summary": "MarketCancelDataTransfer cancels a data transfer with the given transfer ID and other peer\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "datatransfer.TransferID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 3 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "peer.ID", + "summary": "", + "schema": { + "examples": [ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6176" + } + }, + { + "name": "Filecoin.MarketDataTransferDiagnostics", + "description": "```go\nfunc (s *StorageMinerStruct) MarketDataTransferDiagnostics(p0 context.Context, p1 peer.ID) (*TransferDiagnostics, error) {\n\tif s.Internal.MarketDataTransferDiagnostics == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MarketDataTransferDiagnostics(p0, p1)\n}\n```", + "summary": "MarketDataTransferDiagnostics generates debugging information about current data transfers over graphsync\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "peer.ID", + "summary": "", + "schema": { + "examples": [ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*TransferDiagnostics", + "description": "*TransferDiagnostics", + "summary": "", + "schema": { + "examples": [ + { + "ReceivingTransfers": [ + { + "RequestID": {}, + "RequestState": "string value", + "IsCurrentChannelRequest": true, + "ChannelID": { + "Initiator": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Responder": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "ID": 3 + }, + "ChannelState": { + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42, + "Stages": { + "Stages": [ + { + "Name": "string value", + "Description": "string value", + "CreatedTime": "0001-01-01T00:00:00Z", + "UpdatedTime": "0001-01-01T00:00:00Z", + "Logs": [ + { + "Log": "string value", + "UpdatedTime": "0001-01-01T00:00:00Z" + } + ] + } + ] + } + }, + "Diagnostics": [ + "string value" + ] + } + ], + "SendingTransfers": [ + { + "RequestID": {}, + "RequestState": "string value", + "IsCurrentChannelRequest": true, + "ChannelID": { + "Initiator": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Responder": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "ID": 3 + }, + "ChannelState": { + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42, + "Stages": { + "Stages": [ + { + "Name": "string value", + "Description": "string value", + "CreatedTime": "0001-01-01T00:00:00Z", + "UpdatedTime": "0001-01-01T00:00:00Z", + "Logs": [ + { + "Log": "string value", + "UpdatedTime": "0001-01-01T00:00:00Z" + } + ] + } + ] + } + }, + "Diagnostics": [ + "string value" + ] + } + ] + } + ], + "additionalProperties": false, + "properties": { + "ReceivingTransfers": { + "items": { + "additionalProperties": false, + "properties": { + "ChannelID": { + "additionalProperties": false, + "properties": { + "ID": { + "title": "number", + "type": "number" + }, + "Initiator": { + "type": "string" + }, + "Responder": { + "type": "string" + } + }, + "type": "object" + }, + "ChannelState": { + "additionalProperties": false, + "properties": { + "BaseCID": { + "title": "Content Identifier", + "type": "string" + }, + "IsInitiator": { + "type": "boolean" + }, + "IsSender": { + "type": "boolean" + }, + "Message": { + "type": "string" + }, + "OtherPeer": { + "type": "string" + }, + "Stages": { + "additionalProperties": false, + "properties": { + "Stages": { + "items": { + "additionalProperties": false, + "properties": { + "CreatedTime": { + "additionalProperties": false, + "type": "object" + }, + "Description": { + "type": "string" + }, + "Logs": { + "items": { + "additionalProperties": false, + "properties": { + "Log": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Name": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "Status": { + "title": "number", + "type": "number" + }, + "TransferID": { + "title": "number", + "type": "number" + }, + "Transferred": { + "title": "number", + "type": "number" + }, + "Voucher": { + "type": "string" + } + }, + "type": "object" + }, + "Diagnostics": { + "items": { + "type": "string" + }, + "type": "array" + }, + "IsCurrentChannelRequest": { + "type": "boolean" + }, + "RequestID": { + "additionalProperties": false, + "type": "object" + }, + "RequestState": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "SendingTransfers": { + "items": { + "additionalProperties": false, + "properties": { + "ChannelID": { + "additionalProperties": false, + "properties": { + "ID": { + "title": "number", + "type": "number" + }, + "Initiator": { + "type": "string" + }, + "Responder": { + "type": "string" + } + }, + "type": "object" + }, + "ChannelState": { + "additionalProperties": false, + "properties": { + "BaseCID": { + "title": "Content Identifier", + "type": "string" + }, + "IsInitiator": { + "type": "boolean" + }, + "IsSender": { + "type": "boolean" + }, + "Message": { + "type": "string" + }, + "OtherPeer": { + "type": "string" + }, + "Stages": { + "additionalProperties": false, + "properties": { + "Stages": { + "items": { + "additionalProperties": false, + "properties": { + "CreatedTime": { + "additionalProperties": false, + "type": "object" + }, + "Description": { + "type": "string" + }, + "Logs": { + "items": { + "additionalProperties": false, + "properties": { + "Log": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Name": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "Status": { + "title": "number", + "type": "number" + }, + "TransferID": { + "title": "number", + "type": "number" + }, + "Transferred": { + "title": "number", + "type": "number" + }, + "Voucher": { + "type": "string" + } + }, + "type": "object" + }, + "Diagnostics": { + "items": { + "type": "string" + }, + "type": "array" + }, + "IsCurrentChannelRequest": { + "type": "boolean" + }, + "RequestID": { + "additionalProperties": false, + "type": "object" + }, + "RequestState": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6187" + } + }, + { + "name": "Filecoin.MarketGetAsk", + "description": "```go\nfunc (s *StorageMinerStruct) MarketGetAsk(p0 context.Context) (*storagemarket.SignedStorageAsk, error) {\n\tif s.Internal.MarketGetAsk == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MarketGetAsk(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*storagemarket.SignedStorageAsk", + "description": "*storagemarket.SignedStorageAsk", + "summary": "", + "schema": { + "examples": [ + { + "Ask": { + "Price": "0", + "VerifiedPrice": "0", + "MinPieceSize": 1032, + "MaxPieceSize": 1032, + "Miner": "f01234", + "Timestamp": 10101, + "Expiry": 10101, + "SeqNo": 42 + }, + "Signature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } + ], + "additionalProperties": false, + "properties": { + "Ask": { + "additionalProperties": false, + "properties": { + "Expiry": { + "title": "number", + "type": "number" + }, + "MaxPieceSize": { + "title": "number", + "type": "number" + }, + "MinPieceSize": { + "title": "number", + "type": "number" + }, + "Miner": { + "additionalProperties": false, + "type": "object" + }, + "Price": { + "additionalProperties": false, + "type": "object" + }, + "SeqNo": { + "title": "number", + "type": "number" + }, + "Timestamp": { + "title": "number", + "type": "number" + }, + "VerifiedPrice": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "Signature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6209" + } + }, + { + "name": "Filecoin.MarketGetRetrievalAsk", + "description": "```go\nfunc (s *StorageMinerStruct) MarketGetRetrievalAsk(p0 context.Context) (*retrievalmarket.Ask, error) {\n\tif s.Internal.MarketGetRetrievalAsk == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MarketGetRetrievalAsk(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*retrievalmarket.Ask", + "description": "*retrievalmarket.Ask", + "summary": "", + "schema": { + "examples": [ + { + "PricePerByte": "0", + "UnsealPrice": "0", + "PaymentInterval": 42, + "PaymentIntervalIncrease": 42 + } + ], + "additionalProperties": false, + "properties": { + "PaymentInterval": { + "title": "number", + "type": "number" + }, + "PaymentIntervalIncrease": { + "title": "number", + "type": "number" + }, + "PricePerByte": { + "additionalProperties": false, + "type": "object" + }, + "UnsealPrice": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6231" + } + }, + { + "name": "Filecoin.MarketImportDealData", + "description": "```go\nfunc (s *StorageMinerStruct) MarketImportDealData(p0 context.Context, p1 cid.Cid, p2 string) error {\n\tif s.Internal.MarketImportDealData == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.MarketImportDealData(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6242" + } + }, + { + "name": "Filecoin.MarketListDataTransfers", + "description": "```go\nfunc (s *StorageMinerStruct) MarketListDataTransfers(p0 context.Context) ([]DataTransferChannel, error) {\n\tif s.Internal.MarketListDataTransfers == nil {\n\t\treturn *new([]DataTransferChannel), ErrNotSupported\n\t}\n\treturn s.Internal.MarketListDataTransfers(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]DataTransferChannel", + "description": "[]DataTransferChannel", + "summary": "", + "schema": { + "examples": [ + [ + { + "TransferID": 3, + "Status": 1, + "BaseCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "IsInitiator": true, + "IsSender": true, + "Voucher": "string value", + "Message": "string value", + "OtherPeer": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Transferred": 42, + "Stages": { + "Stages": [ + { + "Name": "string value", + "Description": "string value", + "CreatedTime": "0001-01-01T00:00:00Z", + "UpdatedTime": "0001-01-01T00:00:00Z", + "Logs": [ + { + "Log": "string value", + "UpdatedTime": "0001-01-01T00:00:00Z" + } + ] + } + ] + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "BaseCID": { + "title": "Content Identifier", + "type": "string" + }, + "IsInitiator": { + "type": "boolean" + }, + "IsSender": { + "type": "boolean" + }, + "Message": { + "type": "string" + }, + "OtherPeer": { + "type": "string" + }, + "Stages": { + "additionalProperties": false, + "properties": { + "Stages": { + "items": { + "additionalProperties": false, + "properties": { + "CreatedTime": { + "additionalProperties": false, + "type": "object" + }, + "Description": { + "type": "string" + }, + "Logs": { + "items": { + "additionalProperties": false, + "properties": { + "Log": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "Name": { + "type": "string" + }, + "UpdatedTime": { + "additionalProperties": false, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "Status": { + "title": "number", + "type": "number" + }, + "TransferID": { + "title": "number", + "type": "number" + }, + "Transferred": { + "title": "number", + "type": "number" + }, + "Voucher": { + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6253" + } + }, + { + "name": "Filecoin.MarketListDeals", + "description": "```go\nfunc (s *StorageMinerStruct) MarketListDeals(p0 context.Context) ([]*MarketDeal, error) {\n\tif s.Internal.MarketListDeals == nil {\n\t\treturn *new([]*MarketDeal), ErrNotSupported\n\t}\n\treturn s.Internal.MarketListDeals(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]*MarketDeal", + "description": "[]*MarketDeal", + "summary": "", + "schema": { + "examples": [ + [ + { + "Proposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "State": { + "SectorStartEpoch": 10101, + "LastUpdatedEpoch": 10101, + "SlashEpoch": 10101 + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Proposal": { + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "ClientCollateral": { + "additionalProperties": false, + "type": "object" + }, + "EndEpoch": { + "title": "number", + "type": "number" + }, + "Label": { + "additionalProperties": false, + "type": "object" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "StoragePricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + } + }, + "type": "object" + }, + "State": { + "additionalProperties": false, + "properties": { + "LastUpdatedEpoch": { + "title": "number", + "type": "number" + }, + "SectorStartEpoch": { + "title": "number", + "type": "number" + }, + "SlashEpoch": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6264" + } + }, + { + "name": "Filecoin.MarketListIncompleteDeals", + "description": "```go\nfunc (s *StorageMinerStruct) MarketListIncompleteDeals(p0 context.Context) ([]storagemarket.MinerDeal, error) {\n\tif s.Internal.MarketListIncompleteDeals == nil {\n\t\treturn *new([]storagemarket.MinerDeal), ErrNotSupported\n\t}\n\treturn s.Internal.MarketListIncompleteDeals(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]storagemarket.MinerDeal", + "description": "[]storagemarket.MinerDeal", + "summary": "", + "schema": { + "examples": [ + [ + { + "Proposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "ClientSignature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + }, + "ProposalCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "AddFundsCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PublishCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Miner": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Client": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "State": 42, + "PiecePath": ".lotusminer/fstmp123", + "MetadataPath": ".lotusminer/fstmp123", + "SlashEpoch": 10101, + "FastRetrieval": true, + "Message": "string value", + "FundsReserved": "0", + "Ref": { + "TransferType": "string value", + "Root": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1024, + "RawBlockSize": 42 + }, + "AvailableForRetrieval": true, + "DealID": 5432, + "CreationTime": "0001-01-01T00:00:00Z", + "TransferChannelId": { + "Initiator": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "Responder": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", + "ID": 3 + }, + "SectorNumber": 9, + "InboundCAR": "string value" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "AddFundsCid": { + "title": "Content Identifier", + "type": "string" + }, + "AvailableForRetrieval": { + "type": "boolean" + }, + "Client": { + "type": "string" + }, + "ClientSignature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "CreationTime": { + "additionalProperties": false, + "type": "object" + }, + "DealID": { + "title": "number", + "type": "number" + }, + "FastRetrieval": { + "type": "boolean" + }, + "FundsReserved": { + "additionalProperties": false, + "type": "object" + }, + "InboundCAR": { + "type": "string" + }, + "Message": { + "type": "string" + }, + "MetadataPath": { + "type": "string" + }, + "Miner": { + "type": "string" + }, + "PiecePath": { + "type": "string" + }, + "Proposal": { + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "ClientCollateral": { + "additionalProperties": false, + "type": "object" + }, + "EndEpoch": { + "title": "number", + "type": "number" + }, + "Label": { + "additionalProperties": false, + "type": "object" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "StoragePricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + } + }, + "type": "object" + }, + "ProposalCid": { + "title": "Content Identifier", + "type": "string" + }, + "PublishCid": { + "title": "Content Identifier", + "type": "string" + }, + "Ref": { + "additionalProperties": false, + "properties": { + "PieceCid": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "RawBlockSize": { + "title": "number", + "type": "number" + }, + "Root": { + "title": "Content Identifier", + "type": "string" + }, + "TransferType": { + "type": "string" + } + }, + "type": "object" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "SlashEpoch": { + "title": "number", + "type": "number" + }, + "State": { + "title": "number", + "type": "number" + }, + "TransferChannelId": { + "additionalProperties": false, + "properties": { + "ID": { + "title": "number", + "type": "number" + }, + "Initiator": { + "type": "string" + }, + "Responder": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6275" + } + }, + { + "name": "Filecoin.MarketListRetrievalDeals", + "description": "```go\nfunc (s *StorageMinerStruct) MarketListRetrievalDeals(p0 context.Context) ([]struct{}, error) {\n\tif s.Internal.MarketListRetrievalDeals == nil {\n\t\treturn *new([]struct{}), ErrNotSupported\n\t}\n\treturn s.Internal.MarketListRetrievalDeals(p0)\n}\n```", + "summary": "MarketListRetrievalDeals is deprecated, returns empty list\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]struct{}", + "description": "[]struct{}", + "summary": "", + "schema": { + "examples": [ + [ + {} + ] + ], + "items": [ + { + "additionalProperties": false, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6286" + } + }, + { + "name": "Filecoin.MarketPendingDeals", + "description": "```go\nfunc (s *StorageMinerStruct) MarketPendingDeals(p0 context.Context) (PendingDealInfo, error) {\n\tif s.Internal.MarketPendingDeals == nil {\n\t\treturn *new(PendingDealInfo), ErrNotSupported\n\t}\n\treturn s.Internal.MarketPendingDeals(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "PendingDealInfo", + "description": "PendingDealInfo", + "summary": "", + "schema": { + "examples": [ + { + "Deals": [ + { + "Proposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "ClientSignature": { + "Type": 2, + "Data": "Ynl0ZSBhcnJheQ==" + } + } + ], + "PublishPeriodStart": "0001-01-01T00:00:00Z", + "PublishPeriod": 60000000000 + } + ], + "additionalProperties": false, + "properties": { + "Deals": { + "items": { + "additionalProperties": false, + "properties": { + "ClientSignature": { + "additionalProperties": false, + "properties": { + "Data": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Proposal": { + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "ClientCollateral": { + "additionalProperties": false, + "type": "object" + }, + "EndEpoch": { + "title": "number", + "type": "number" + }, + "Label": { + "additionalProperties": false, + "type": "object" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "StoragePricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "PublishPeriod": { + "title": "number", + "type": "number" + }, + "PublishPeriodStart": { + "format": "date-time", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6297" + } + }, + { + "name": "Filecoin.MarketPublishPendingDeals", + "description": "```go\nfunc (s *StorageMinerStruct) MarketPublishPendingDeals(p0 context.Context) error {\n\tif s.Internal.MarketPublishPendingDeals == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.MarketPublishPendingDeals(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6308" + } + }, + { + "name": "Filecoin.MarketRestartDataTransfer", + "description": "```go\nfunc (s *StorageMinerStruct) MarketRestartDataTransfer(p0 context.Context, p1 datatransfer.TransferID, p2 peer.ID, p3 bool) error {\n\tif s.Internal.MarketRestartDataTransfer == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.MarketRestartDataTransfer(p0, p1, p2, p3)\n}\n```", + "summary": "MarketRestartDataTransfer attempts to restart a data transfer with the given transfer ID and other peer\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "datatransfer.TransferID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 3 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "peer.ID", + "summary": "", + "schema": { + "examples": [ + "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6319" + } + }, + { + "name": "Filecoin.MarketRetryPublishDeal", + "description": "```go\nfunc (s *StorageMinerStruct) MarketRetryPublishDeal(p0 context.Context, p1 cid.Cid) error {\n\tif s.Internal.MarketRetryPublishDeal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.MarketRetryPublishDeal(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6330" + } + }, + { + "name": "Filecoin.MarketSetAsk", + "description": "```go\nfunc (s *StorageMinerStruct) MarketSetAsk(p0 context.Context, p1 types.BigInt, p2 types.BigInt, p3 abi.ChainEpoch, p4 abi.PaddedPieceSize, p5 abi.PaddedPieceSize) error {\n\tif s.Internal.MarketSetAsk == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.MarketSetAsk(p0, p1, p2, p3, p4, p5)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "types.BigInt", + "summary": "", + "schema": { + "examples": [ + "0" + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.ChainEpoch", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 10101 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "abi.PaddedPieceSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1032 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "abi.PaddedPieceSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1032 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6341" + } + }, + { + "name": "Filecoin.MarketSetRetrievalAsk", + "description": "```go\nfunc (s *StorageMinerStruct) MarketSetRetrievalAsk(p0 context.Context, p1 *retrievalmarket.Ask) error {\n\tif s.Internal.MarketSetRetrievalAsk == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.MarketSetRetrievalAsk(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*retrievalmarket.Ask", + "summary": "", + "schema": { + "examples": [ + { + "PricePerByte": "0", + "UnsealPrice": "0", + "PaymentInterval": 42, + "PaymentIntervalIncrease": 42 + } + ], + "additionalProperties": false, + "properties": { + "PaymentInterval": { + "title": "number", + "type": "number" + }, + "PaymentIntervalIncrease": { + "title": "number", + "type": "number" + }, + "PricePerByte": { + "additionalProperties": false, + "type": "object" + }, + "UnsealPrice": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6352" + } + }, + { + "name": "Filecoin.MiningBase", + "description": "```go\nfunc (s *StorageMinerStruct) MiningBase(p0 context.Context) (*types.TipSet, error) {\n\tif s.Internal.MiningBase == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.MiningBase(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*types.TipSet", + "description": "*types.TipSet", + "summary": "", + "schema": { + "examples": [ + { + "Cids": null, + "Blocks": null, + "Height": 0 + } + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6363" + } + }, + { + "name": "Filecoin.PiecesGetCIDInfo", + "description": "```go\nfunc (s *StorageMinerStruct) PiecesGetCIDInfo(p0 context.Context, p1 cid.Cid) (*piecestore.CIDInfo, error) {\n\tif s.Internal.PiecesGetCIDInfo == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.PiecesGetCIDInfo(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*piecestore.CIDInfo", + "description": "*piecestore.CIDInfo", + "summary": "", + "schema": { + "examples": [ + { + "CID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceBlockLocations": [ + { + "RelOffset": 42, + "BlockSize": 42, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ] + } + ], + "additionalProperties": false, + "properties": { + "CID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceBlockLocations": { + "items": { + "additionalProperties": false, + "properties": { + "BlockSize": { + "title": "number", + "type": "number" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "RelOffset": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6374" + } + }, + { + "name": "Filecoin.PiecesGetPieceInfo", + "description": "```go\nfunc (s *StorageMinerStruct) PiecesGetPieceInfo(p0 context.Context, p1 cid.Cid) (*piecestore.PieceInfo, error) {\n\tif s.Internal.PiecesGetPieceInfo == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.PiecesGetPieceInfo(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "*piecestore.PieceInfo", + "description": "*piecestore.PieceInfo", + "summary": "", + "schema": { + "examples": [ + { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Deals": [ + { + "DealID": 5432, + "SectorID": 9, + "Offset": 1032, + "Length": 1032 + } + ] + } + ], + "additionalProperties": false, + "properties": { + "Deals": { + "items": { + "additionalProperties": false, + "properties": { + "DealID": { + "title": "number", + "type": "number" + }, + "Length": { + "title": "number", + "type": "number" + }, + "Offset": { + "title": "number", + "type": "number" + }, + "SectorID": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6385" + } + }, + { + "name": "Filecoin.PiecesListCidInfos", + "description": "```go\nfunc (s *StorageMinerStruct) PiecesListCidInfos(p0 context.Context) ([]cid.Cid, error) {\n\tif s.Internal.PiecesListCidInfos == nil {\n\t\treturn *new([]cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.PiecesListCidInfos(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]cid.Cid", + "description": "[]cid.Cid", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + ], + "items": [ + { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6396" + } + }, + { + "name": "Filecoin.PiecesListPieces", + "description": "```go\nfunc (s *StorageMinerStruct) PiecesListPieces(p0 context.Context) ([]cid.Cid, error) {\n\tif s.Internal.PiecesListPieces == nil {\n\t\treturn *new([]cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.PiecesListPieces(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]cid.Cid", + "description": "[]cid.Cid", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + ], + "items": [ + { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6407" + } + }, + { + "name": "Filecoin.PledgeSector", + "description": "```go\nfunc (s *StorageMinerStruct) PledgeSector(p0 context.Context) (abi.SectorID, error) {\n\tif s.Internal.PledgeSector == nil {\n\t\treturn *new(abi.SectorID), ErrNotSupported\n\t}\n\treturn s.Internal.PledgeSector(p0)\n}\n```", + "summary": "Temp api for testing\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "abi.SectorID", + "description": "abi.SectorID", + "summary": "", + "schema": { + "examples": [ + { + "Miner": 1000, + "Number": 9 + } + ], + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6418" + } + }, + { + "name": "Filecoin.RecoverFault", + "description": "```go\nfunc (s *StorageMinerStruct) RecoverFault(p0 context.Context, p1 []abi.SectorNumber) ([]cid.Cid, error) {\n\tif s.Internal.RecoverFault == nil {\n\t\treturn *new([]cid.Cid), ErrNotSupported\n\t}\n\treturn s.Internal.RecoverFault(p0, p1)\n}\n```", + "summary": "RecoverFault can be used to declare recoveries manually. It sends messages\nto the miner actor with details of recovered sectors and returns the CID of messages. It honors the\nmaxPartitionsPerRecoveryMessage from the config\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "[]abi.SectorNumber", + "summary": "", + "schema": { + "examples": [ + [ + 123, + 124 + ] + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]cid.Cid", + "description": "[]cid.Cid", + "summary": "", + "schema": { + "examples": [ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ] + ], + "items": [ + { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6429" + } + }, + { + "name": "Filecoin.ReturnAddPiece", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnAddPiece(p0 context.Context, p1 storiface.CallID, p2 abi.PieceInfo, p3 *storiface.CallError) error {\n\tif s.Internal.ReturnAddPiece == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnAddPiece(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.PieceInfo", + "summary": "", + "schema": { + "examples": [ + { + "Size": 1032, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6440" + } + }, + { + "name": "Filecoin.ReturnDataCid", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnDataCid(p0 context.Context, p1 storiface.CallID, p2 abi.PieceInfo, p3 *storiface.CallError) error {\n\tif s.Internal.ReturnDataCid == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnDataCid(p0, p1, p2, p3)\n}\n```", + "summary": "storiface.WorkerReturn\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.PieceInfo", + "summary": "", + "schema": { + "examples": [ + { + "Size": 1032, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6451" + } + }, + { + "name": "Filecoin.ReturnDownloadSector", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnDownloadSector(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error {\n\tif s.Internal.ReturnDownloadSector == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnDownloadSector(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6462" + } + }, + { + "name": "Filecoin.ReturnFetch", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnFetch(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error {\n\tif s.Internal.ReturnFetch == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnFetch(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6473" + } + }, + { + "name": "Filecoin.ReturnFinalizeReplicaUpdate", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnFinalizeReplicaUpdate(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error {\n\tif s.Internal.ReturnFinalizeReplicaUpdate == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnFinalizeReplicaUpdate(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6484" + } + }, + { + "name": "Filecoin.ReturnFinalizeSector", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnFinalizeSector(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error {\n\tif s.Internal.ReturnFinalizeSector == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnFinalizeSector(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6495" + } + }, + { + "name": "Filecoin.ReturnGenerateSectorKeyFromData", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnGenerateSectorKeyFromData(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error {\n\tif s.Internal.ReturnGenerateSectorKeyFromData == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnGenerateSectorKeyFromData(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6506" + } + }, + { + "name": "Filecoin.ReturnMoveStorage", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnMoveStorage(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error {\n\tif s.Internal.ReturnMoveStorage == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnMoveStorage(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6517" + } + }, + { + "name": "Filecoin.ReturnProveReplicaUpdate1", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnProveReplicaUpdate1(p0 context.Context, p1 storiface.CallID, p2 storiface.ReplicaVanillaProofs, p3 *storiface.CallError) error {\n\tif s.Internal.ReturnProveReplicaUpdate1 == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnProveReplicaUpdate1(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.ReplicaVanillaProofs", + "summary": "", + "schema": { + "examples": [ + [ + "Ynl0ZSBhcnJheQ==" + ] + ], + "items": [ + { + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6528" + } + }, + { + "name": "Filecoin.ReturnProveReplicaUpdate2", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnProveReplicaUpdate2(p0 context.Context, p1 storiface.CallID, p2 storiface.ReplicaUpdateProof, p3 *storiface.CallError) error {\n\tif s.Internal.ReturnProveReplicaUpdate2 == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnProveReplicaUpdate2(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.ReplicaUpdateProof", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6539" + } + }, + { + "name": "Filecoin.ReturnReadPiece", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnReadPiece(p0 context.Context, p1 storiface.CallID, p2 bool, p3 *storiface.CallError) error {\n\tif s.Internal.ReturnReadPiece == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnReadPiece(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6550" + } + }, + { + "name": "Filecoin.ReturnReleaseUnsealed", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnReleaseUnsealed(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error {\n\tif s.Internal.ReturnReleaseUnsealed == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnReleaseUnsealed(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6561" + } + }, + { + "name": "Filecoin.ReturnReplicaUpdate", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnReplicaUpdate(p0 context.Context, p1 storiface.CallID, p2 storiface.ReplicaUpdateOut, p3 *storiface.CallError) error {\n\tif s.Internal.ReturnReplicaUpdate == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnReplicaUpdate(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.ReplicaUpdateOut", + "summary": "", + "schema": { + "examples": [ + { + "NewSealed": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "NewUnsealed": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "NewSealed": { + "title": "Content Identifier", + "type": "string" + }, + "NewUnsealed": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6572" + } + }, + { + "name": "Filecoin.ReturnSealCommit1", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnSealCommit1(p0 context.Context, p1 storiface.CallID, p2 storiface.Commit1Out, p3 *storiface.CallError) error {\n\tif s.Internal.ReturnSealCommit1 == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnSealCommit1(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.Commit1Out", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6583" + } + }, + { + "name": "Filecoin.ReturnSealCommit2", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnSealCommit2(p0 context.Context, p1 storiface.CallID, p2 storiface.Proof, p3 *storiface.CallError) error {\n\tif s.Internal.ReturnSealCommit2 == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnSealCommit2(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.Proof", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6594" + } + }, + { + "name": "Filecoin.ReturnSealPreCommit1", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnSealPreCommit1(p0 context.Context, p1 storiface.CallID, p2 storiface.PreCommit1Out, p3 *storiface.CallError) error {\n\tif s.Internal.ReturnSealPreCommit1 == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnSealPreCommit1(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.PreCommit1Out", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6605" + } + }, + { + "name": "Filecoin.ReturnSealPreCommit2", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnSealPreCommit2(p0 context.Context, p1 storiface.CallID, p2 storiface.SectorCids, p3 *storiface.CallError) error {\n\tif s.Internal.ReturnSealPreCommit2 == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnSealPreCommit2(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.SectorCids", + "summary": "", + "schema": { + "examples": [ + { + "Unsealed": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Sealed": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "Sealed": { + "title": "Content Identifier", + "type": "string" + }, + "Unsealed": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6616" + } + }, + { + "name": "Filecoin.ReturnUnsealPiece", + "description": "```go\nfunc (s *StorageMinerStruct) ReturnUnsealPiece(p0 context.Context, p1 storiface.CallID, p2 *storiface.CallError) error {\n\tif s.Internal.ReturnUnsealPiece == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.ReturnUnsealPiece(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "*storiface.CallError", + "summary": "", + "schema": { + "examples": [ + { + "Code": 0, + "Message": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Code": { + "title": "number", + "type": "number" + }, + "Message": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6627" + } + }, + { + "name": "Filecoin.RuntimeSubsystems", + "description": "```go\nfunc (s *StorageMinerStruct) RuntimeSubsystems(p0 context.Context) (MinerSubsystems, error) {\n\tif s.Internal.RuntimeSubsystems == nil {\n\t\treturn *new(MinerSubsystems), ErrNotSupported\n\t}\n\treturn s.Internal.RuntimeSubsystems(p0)\n}\n```", + "summary": "RuntimeSubsystems returns the subsystems that are enabled\nin this instance.\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "MinerSubsystems", + "description": "MinerSubsystems", + "summary": "", + "schema": { + "examples": [ + [ + "Mining", + "Sealing", + "SectorStorage", + "Markets" + ] + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6638" + } + }, + { + "name": "Filecoin.SealingAbort", + "description": "```go\nfunc (s *StorageMinerStruct) SealingAbort(p0 context.Context, p1 storiface.CallID) error {\n\tif s.Internal.SealingAbort == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SealingAbort(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6649" + } + }, + { + "name": "Filecoin.SealingRemoveRequest", + "description": "```go\nfunc (s *StorageMinerStruct) SealingRemoveRequest(p0 context.Context, p1 uuid.UUID) error {\n\tif s.Internal.SealingRemoveRequest == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SealingRemoveRequest(p0, p1)\n}\n```", + "summary": "SealingSchedRemove removes a request from sealing pipeline\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "uuid.UUID", + "summary": "", + "schema": { + "examples": [ + "07070707-0707-0707-0707-070707070707" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 16, + "minItems": 16, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6660" + } + }, + { + "name": "Filecoin.SealingSchedDiag", + "description": "```go\nfunc (s *StorageMinerStruct) SealingSchedDiag(p0 context.Context, p1 bool) (interface{}, error) {\n\tif s.Internal.SealingSchedDiag == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.SealingSchedDiag(p0, p1)\n}\n```", + "summary": "SealingSchedDiag dumps internal sealing scheduler state\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "interface{}", + "description": "interface{}", + "summary": "", + "schema": { + "examples": [ + {} + ], + "additionalProperties": true, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6671" + } + }, + { + "name": "Filecoin.SectorAbortUpgrade", + "description": "```go\nfunc (s *StorageMinerStruct) SectorAbortUpgrade(p0 context.Context, p1 abi.SectorNumber) error {\n\tif s.Internal.SectorAbortUpgrade == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorAbortUpgrade(p0, p1)\n}\n```", + "summary": "SectorAbortUpgrade can be called on sectors that are in the process of being upgraded to abort it\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6682" + } + }, + { + "name": "Filecoin.SectorAddPieceToAny", + "description": "```go\nfunc (s *StorageMinerStruct) SectorAddPieceToAny(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data, p3 piece.PieceDealInfo) (SectorOffset, error) {\n\tif s.Internal.SectorAddPieceToAny == nil {\n\t\treturn *new(SectorOffset), ErrNotSupported\n\t}\n\treturn s.Internal.SectorAddPieceToAny(p0, p1, p2, p3)\n}\n```", + "summary": "Add piece to an open sector. If no sectors with enough space are open,\neither a new sector will be created, or this call will block until more\nsectors can be created.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.UnpaddedPieceSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1024 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.Data", + "summary": "", + "schema": { + "examples": [ + {} + ], + "additionalProperties": true + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "piece.PieceDealInfo", + "summary": "", + "schema": { + "examples": [ + { + "PublishCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DealID": 5432, + "DealProposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "DealSchedule": { + "StartEpoch": 10101, + "EndEpoch": 10101 + }, + "PieceActivationManifest": { + "CID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 2032, + "VerifiedAllocationKey": null, + "Notify": null + }, + "KeepUnsealed": true + } + ], + "additionalProperties": false, + "properties": { + "DealID": { + "title": "number", + "type": "number" + }, + "DealProposal": { + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "ClientCollateral": { + "additionalProperties": false, + "type": "object" + }, + "EndEpoch": { + "title": "number", + "type": "number" + }, + "Label": { + "additionalProperties": false, + "type": "object" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "StoragePricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + } + }, + "type": "object" + }, + "DealSchedule": { + "additionalProperties": false, + "properties": { + "EndEpoch": { + "title": "number", + "type": "number" + }, + "StartEpoch": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "KeepUnsealed": { + "type": "boolean" + }, + "PieceActivationManifest": { + "additionalProperties": false, + "properties": { + "CID": { + "title": "Content Identifier", + "type": "string" + }, + "Notify": { + "items": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Payload": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "Size": { + "title": "number", + "type": "number" + }, + "VerifiedAllocationKey": { + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "ID": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "PublishCid": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "SectorOffset", + "description": "SectorOffset", + "summary": "", + "schema": { + "examples": [ + { + "Sector": 9, + "Offset": 1032 + } + ], + "additionalProperties": false, + "properties": { + "Offset": { + "title": "number", + "type": "number" + }, + "Sector": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6693" + } + }, + { + "name": "Filecoin.SectorCommitFlush", + "description": "```go\nfunc (s *StorageMinerStruct) SectorCommitFlush(p0 context.Context) ([]sealiface.CommitBatchRes, error) {\n\tif s.Internal.SectorCommitFlush == nil {\n\t\treturn *new([]sealiface.CommitBatchRes), ErrNotSupported\n\t}\n\treturn s.Internal.SectorCommitFlush(p0)\n}\n```", + "summary": "SectorCommitFlush immediately sends a Commit message with sectors aggregated for Commit.\nReturns null if message wasn't sent\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]sealiface.CommitBatchRes", + "description": "[]sealiface.CommitBatchRes", + "summary": "", + "schema": { + "examples": [ + [ + { + "Sectors": [ + 123, + 124 + ], + "FailedSectors": { + "123": "can't acquire read lock" + }, + "Msg": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Error": "string value" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Error": { + "type": "string" + }, + "FailedSectors": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "Msg": { + "title": "Content Identifier", + "type": "string" + }, + "Sectors": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6704" + } + }, + { + "name": "Filecoin.SectorCommitPending", + "description": "```go\nfunc (s *StorageMinerStruct) SectorCommitPending(p0 context.Context) ([]abi.SectorID, error) {\n\tif s.Internal.SectorCommitPending == nil {\n\t\treturn *new([]abi.SectorID), ErrNotSupported\n\t}\n\treturn s.Internal.SectorCommitPending(p0)\n}\n```", + "summary": "SectorCommitPending returns a list of pending Commit sectors to be sent in the next aggregate message\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]abi.SectorID", + "description": "[]abi.SectorID", + "summary": "", + "schema": { + "examples": [ + [ + { + "Miner": 1000, + "Number": 9 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6715" + } + }, + { + "name": "Filecoin.SectorGetExpectedSealDuration", + "description": "```go\nfunc (s *StorageMinerStruct) SectorGetExpectedSealDuration(p0 context.Context) (time.Duration, error) {\n\tif s.Internal.SectorGetExpectedSealDuration == nil {\n\t\treturn *new(time.Duration), ErrNotSupported\n\t}\n\treturn s.Internal.SectorGetExpectedSealDuration(p0)\n}\n```", + "summary": "SectorGetExpectedSealDuration gets the expected time for a sector to seal\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "time.Duration", + "description": "time.Duration", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 60000000000 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6726" + } + }, + { + "name": "Filecoin.SectorGetSealDelay", + "description": "```go\nfunc (s *StorageMinerStruct) SectorGetSealDelay(p0 context.Context) (time.Duration, error) {\n\tif s.Internal.SectorGetSealDelay == nil {\n\t\treturn *new(time.Duration), ErrNotSupported\n\t}\n\treturn s.Internal.SectorGetSealDelay(p0)\n}\n```", + "summary": "SectorGetSealDelay gets the time that a newly-created sector\nwaits for more deals before it starts sealing\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "time.Duration", + "description": "time.Duration", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 60000000000 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6737" + } + }, + { + "name": "Filecoin.SectorMarkForUpgrade", + "description": "```go\nfunc (s *StorageMinerStruct) SectorMarkForUpgrade(p0 context.Context, p1 abi.SectorNumber, p2 bool) error {\n\tif s.Internal.SectorMarkForUpgrade == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorMarkForUpgrade(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6748" + } + }, + { + "name": "Filecoin.SectorMatchPendingPiecesToOpenSectors", + "description": "```go\nfunc (s *StorageMinerStruct) SectorMatchPendingPiecesToOpenSectors(p0 context.Context) error {\n\tif s.Internal.SectorMatchPendingPiecesToOpenSectors == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorMatchPendingPiecesToOpenSectors(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6759" + } + }, + { + "name": "Filecoin.SectorNumAssignerMeta", + "description": "```go\nfunc (s *StorageMinerStruct) SectorNumAssignerMeta(p0 context.Context) (NumAssignerMeta, error) {\n\tif s.Internal.SectorNumAssignerMeta == nil {\n\t\treturn *new(NumAssignerMeta), ErrNotSupported\n\t}\n\treturn s.Internal.SectorNumAssignerMeta(p0)\n}\n```", + "summary": "SectorNumAssignerMeta returns sector number assigner metadata - reserved/allocated\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "NumAssignerMeta", + "description": "NumAssignerMeta", + "summary": "", + "schema": { + "examples": [ + { + "Reserved": [ + 5, + 1 + ], + "Allocated": [ + 5, + 1 + ], + "InUse": [ + 5, + 1 + ], + "Next": 9 + } + ], + "additionalProperties": false, + "properties": { + "Allocated": { + "additionalProperties": false, + "type": "object" + }, + "InUse": { + "additionalProperties": false, + "type": "object" + }, + "Next": { + "title": "number", + "type": "number" + }, + "Reserved": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6770" + } + }, + { + "name": "Filecoin.SectorNumFree", + "description": "```go\nfunc (s *StorageMinerStruct) SectorNumFree(p0 context.Context, p1 string) error {\n\tif s.Internal.SectorNumFree == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorNumFree(p0, p1)\n}\n```", + "summary": "SectorNumFree drops a sector reservation\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6781" + } + }, + { + "name": "Filecoin.SectorNumReservations", + "description": "```go\nfunc (s *StorageMinerStruct) SectorNumReservations(p0 context.Context) (map[string]bitfield.BitField, error) {\n\tif s.Internal.SectorNumReservations == nil {\n\t\treturn *new(map[string]bitfield.BitField), ErrNotSupported\n\t}\n\treturn s.Internal.SectorNumReservations(p0)\n}\n```", + "summary": "SectorNumReservations returns a list of sector number reservations\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "map[string]bitfield.BitField", + "description": "map[string]bitfield.BitField", + "summary": "", + "schema": { + "examples": [ + { + "": [ + 5, + 3, + 2, + 1 + ] + } + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6792" + } + }, + { + "name": "Filecoin.SectorNumReserve", + "description": "```go\nfunc (s *StorageMinerStruct) SectorNumReserve(p0 context.Context, p1 string, p2 bitfield.BitField, p3 bool) error {\n\tif s.Internal.SectorNumReserve == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorNumReserve(p0, p1, p2, p3)\n}\n```", + "summary": "SectorNumReserve creates a new sector number reservation. Will fail if any other reservation has colliding\nnumbers or name. Set force to true to override safety checks.\nValid characters for name: a-z, A-Z, 0-9, _, -\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bitfield.BitField", + "summary": "", + "schema": { + "examples": [ + [ + 5, + 1 + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6803" + } + }, + { + "name": "Filecoin.SectorNumReserveCount", + "description": "```go\nfunc (s *StorageMinerStruct) SectorNumReserveCount(p0 context.Context, p1 string, p2 uint64) (bitfield.BitField, error) {\n\tif s.Internal.SectorNumReserveCount == nil {\n\t\treturn *new(bitfield.BitField), ErrNotSupported\n\t}\n\treturn s.Internal.SectorNumReserveCount(p0, p1, p2)\n}\n```", + "summary": "SectorNumReserveCount creates a new sector number reservation for `count` sector numbers.\nby default lotus will allocate lowest-available sector numbers to the reservation.\nFor restrictions on `name` see SectorNumReserve\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "uint64", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 42 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bitfield.BitField", + "description": "bitfield.BitField", + "summary": "", + "schema": { + "examples": [ + [ + 5, + 1 + ] + ], + "additionalProperties": false, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6814" + } + }, + { + "name": "Filecoin.SectorPreCommitFlush", + "description": "```go\nfunc (s *StorageMinerStruct) SectorPreCommitFlush(p0 context.Context) ([]sealiface.PreCommitBatchRes, error) {\n\tif s.Internal.SectorPreCommitFlush == nil {\n\t\treturn *new([]sealiface.PreCommitBatchRes), ErrNotSupported\n\t}\n\treturn s.Internal.SectorPreCommitFlush(p0)\n}\n```", + "summary": "SectorPreCommitFlush immediately sends a PreCommit message with sectors batched for PreCommit.\nReturns null if message wasn't sent\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]sealiface.PreCommitBatchRes", + "description": "[]sealiface.PreCommitBatchRes", + "summary": "", + "schema": { + "examples": [ + [ + { + "Sectors": [ + 123, + 124 + ], + "Msg": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Error": "string value" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Error": { + "type": "string" + }, + "Msg": { + "title": "Content Identifier", + "type": "string" + }, + "Sectors": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6825" + } + }, + { + "name": "Filecoin.SectorPreCommitPending", + "description": "```go\nfunc (s *StorageMinerStruct) SectorPreCommitPending(p0 context.Context) ([]abi.SectorID, error) {\n\tif s.Internal.SectorPreCommitPending == nil {\n\t\treturn *new([]abi.SectorID), ErrNotSupported\n\t}\n\treturn s.Internal.SectorPreCommitPending(p0)\n}\n```", + "summary": "SectorPreCommitPending returns a list of pending PreCommit sectors to be sent in the next batch message\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]abi.SectorID", + "description": "[]abi.SectorID", + "summary": "", + "schema": { + "examples": [ + [ + { + "Miner": 1000, + "Number": 9 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6836" + } + }, + { + "name": "Filecoin.SectorReceive", + "description": "```go\nfunc (s *StorageMinerStruct) SectorReceive(p0 context.Context, p1 RemoteSectorMeta) error {\n\tif s.Internal.SectorReceive == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorReceive(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "RemoteSectorMeta", + "summary": "", + "schema": { + "examples": [ + { + "State": "Proving", + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "Type": 8, + "Pieces": [ + { + "Piece": { + "Size": 1032, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "DealInfo": { + "PublishCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DealID": 5432, + "DealProposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "DealSchedule": { + "StartEpoch": 10101, + "EndEpoch": 10101 + }, + "PieceActivationManifest": { + "CID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 2032, + "VerifiedAllocationKey": null, + "Notify": null + }, + "KeepUnsealed": true + } + } + ], + "TicketValue": "Bw==", + "TicketEpoch": 10101, + "PreCommit1Out": "Bw==", + "CommD": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "CommR": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PreCommitInfo": { + "SealProof": 8, + "SectorNumber": 9, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "SealRandEpoch": 10101, + "DealIDs": [ + 5432 + ], + "Expiration": 10101, + "UnsealedCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "PreCommitDeposit": "0", + "PreCommitMessage": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PreCommitTipSet": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + "SeedValue": "Bw==", + "SeedEpoch": 10101, + "CommitProof": "Ynl0ZSBhcnJheQ==", + "CommitMessage": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Log": [ + { + "Kind": "string value", + "Timestamp": 42, + "Trace": "string value", + "Message": "string value" + } + ], + "DataUnsealed": { + "Local": true, + "URL": "string value", + "Headers": [ + { + "Key": "string value", + "Value": "string value" + } + ] + }, + "DataSealed": { + "Local": true, + "URL": "string value", + "Headers": [ + { + "Key": "string value", + "Value": "string value" + } + ] + }, + "DataCache": { + "Local": true, + "URL": "string value", + "Headers": [ + { + "Key": "string value", + "Value": "string value" + } + ] + }, + "RemoteCommit1Endpoint": "string value", + "RemoteCommit2Endpoint": "string value", + "RemoteSealingDoneEndpoint": "string value" + } + ], + "additionalProperties": false, + "properties": { + "CommD": { + "title": "Content Identifier", + "type": "string" + }, + "CommR": { + "title": "Content Identifier", + "type": "string" + }, + "CommitMessage": { + "title": "Content Identifier", + "type": "string" + }, + "CommitProof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "DataCache": { + "additionalProperties": false, + "properties": { + "Headers": { + "items": { + "additionalProperties": false, + "properties": { + "Key": { + "type": "string" + }, + "Value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "Local": { + "type": "boolean" + }, + "URL": { + "type": "string" + } + }, + "type": "object" + }, + "DataSealed": { + "additionalProperties": false, + "properties": { + "Headers": { + "items": { + "additionalProperties": false, + "properties": { + "Key": { + "type": "string" + }, + "Value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "Local": { + "type": "boolean" + }, + "URL": { + "type": "string" + } + }, + "type": "object" + }, + "DataUnsealed": { + "additionalProperties": false, + "properties": { + "Headers": { + "items": { + "additionalProperties": false, + "properties": { + "Key": { + "type": "string" + }, + "Value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "Local": { + "type": "boolean" + }, + "URL": { + "type": "string" + } + }, + "type": "object" + }, + "Log": { + "items": { + "additionalProperties": false, + "properties": { + "Kind": { + "type": "string" + }, + "Message": { + "type": "string" + }, + "Timestamp": { + "title": "number", + "type": "number" + }, + "Trace": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "Pieces": { + "items": { + "additionalProperties": false, + "properties": { + "DealInfo": { + "additionalProperties": false, + "properties": { + "DealID": { + "title": "number", + "type": "number" + }, + "DealProposal": { + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "ClientCollateral": { + "additionalProperties": false, + "type": "object" + }, + "EndEpoch": { + "title": "number", + "type": "number" + }, + "Label": { + "additionalProperties": false, + "type": "object" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "StoragePricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + } + }, + "type": "object" + }, + "DealSchedule": { + "additionalProperties": false, + "properties": { + "EndEpoch": { + "title": "number", + "type": "number" + }, + "StartEpoch": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "KeepUnsealed": { + "type": "boolean" + }, + "PieceActivationManifest": { + "additionalProperties": false, + "properties": { + "CID": { + "title": "Content Identifier", + "type": "string" + }, + "Notify": { + "items": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Payload": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "Size": { + "title": "number", + "type": "number" + }, + "VerifiedAllocationKey": { + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "ID": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "PublishCid": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": "object" + }, + "Piece": { + "additionalProperties": false, + "properties": { + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "PreCommit1Out": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "PreCommitDeposit": { + "additionalProperties": false, + "type": "object" + }, + "PreCommitInfo": { + "additionalProperties": false, + "properties": { + "DealIDs": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SealRandEpoch": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "UnsealedCid": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": "object" + }, + "PreCommitMessage": { + "title": "Content Identifier", + "type": "string" + }, + "PreCommitTipSet": { + "additionalProperties": false, + "type": "object" + }, + "RemoteCommit1Endpoint": { + "type": "string" + }, + "RemoteCommit2Endpoint": { + "type": "string" + }, + "RemoteSealingDoneEndpoint": { + "type": "string" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "SeedEpoch": { + "title": "number", + "type": "number" + }, + "SeedValue": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "State": { + "type": "string" + }, + "TicketEpoch": { + "title": "number", + "type": "number" + }, + "TicketValue": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "Type": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6847" + } + }, + { + "name": "Filecoin.SectorRemove", + "description": "```go\nfunc (s *StorageMinerStruct) SectorRemove(p0 context.Context, p1 abi.SectorNumber) error {\n\tif s.Internal.SectorRemove == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorRemove(p0, p1)\n}\n```", + "summary": "SectorRemove removes the sector from storage. It doesn't terminate it on-chain, which can\nbe done with SectorTerminate. Removing and not terminating live sectors will cause additional penalties.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6858" + } + }, + { + "name": "Filecoin.SectorSetExpectedSealDuration", + "description": "```go\nfunc (s *StorageMinerStruct) SectorSetExpectedSealDuration(p0 context.Context, p1 time.Duration) error {\n\tif s.Internal.SectorSetExpectedSealDuration == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorSetExpectedSealDuration(p0, p1)\n}\n```", + "summary": "SectorSetExpectedSealDuration sets the expected time for a sector to seal\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "time.Duration", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 60000000000 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6869" + } + }, + { + "name": "Filecoin.SectorSetSealDelay", + "description": "```go\nfunc (s *StorageMinerStruct) SectorSetSealDelay(p0 context.Context, p1 time.Duration) error {\n\tif s.Internal.SectorSetSealDelay == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorSetSealDelay(p0, p1)\n}\n```", + "summary": "SectorSetSealDelay sets the time that a newly-created sector\nwaits for more deals before it starts sealing\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "time.Duration", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 60000000000 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6880" + } + }, + { + "name": "Filecoin.SectorStartSealing", + "description": "```go\nfunc (s *StorageMinerStruct) SectorStartSealing(p0 context.Context, p1 abi.SectorNumber) error {\n\tif s.Internal.SectorStartSealing == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorStartSealing(p0, p1)\n}\n```", + "summary": "SectorStartSealing can be called on sectors in Empty or WaitDeals states\nto trigger sealing early\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6891" + } + }, + { + "name": "Filecoin.SectorTerminate", + "description": "```go\nfunc (s *StorageMinerStruct) SectorTerminate(p0 context.Context, p1 abi.SectorNumber) error {\n\tif s.Internal.SectorTerminate == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorTerminate(p0, p1)\n}\n```", + "summary": "SectorTerminate terminates the sector on-chain (adding it to a termination batch first), then\nautomatically removes it from storage\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6902" + } + }, + { + "name": "Filecoin.SectorTerminateFlush", + "description": "```go\nfunc (s *StorageMinerStruct) SectorTerminateFlush(p0 context.Context) (*cid.Cid, error) {\n\tif s.Internal.SectorTerminateFlush == nil {\n\t\treturn nil, ErrNotSupported\n\t}\n\treturn s.Internal.SectorTerminateFlush(p0)\n}\n```", + "summary": "SectorTerminateFlush immediately sends a terminate message with sectors batched for termination.\nReturns null if message wasn't sent\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "*cid.Cid", + "description": "*cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6913" + } + }, + { + "name": "Filecoin.SectorTerminatePending", + "description": "```go\nfunc (s *StorageMinerStruct) SectorTerminatePending(p0 context.Context) ([]abi.SectorID, error) {\n\tif s.Internal.SectorTerminatePending == nil {\n\t\treturn *new([]abi.SectorID), ErrNotSupported\n\t}\n\treturn s.Internal.SectorTerminatePending(p0)\n}\n```", + "summary": "SectorTerminatePending returns a list of pending sector terminations to be sent in the next batch message\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]abi.SectorID", + "description": "[]abi.SectorID", + "summary": "", + "schema": { + "examples": [ + [ + { + "Miner": 1000, + "Number": 9 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6924" + } + }, + { + "name": "Filecoin.SectorUnseal", + "description": "```go\nfunc (s *StorageMinerStruct) SectorUnseal(p0 context.Context, p1 abi.SectorNumber) error {\n\tif s.Internal.SectorUnseal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorUnseal(p0, p1)\n}\n```", + "summary": "SectorUnseal unseals the provided sector\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6935" + } + }, + { + "name": "Filecoin.SectorsList", + "description": "```go\nfunc (s *StorageMinerStruct) SectorsList(p0 context.Context) ([]abi.SectorNumber, error) {\n\tif s.Internal.SectorsList == nil {\n\t\treturn *new([]abi.SectorNumber), ErrNotSupported\n\t}\n\treturn s.Internal.SectorsList(p0)\n}\n```", + "summary": "List all staged sectors\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]abi.SectorNumber", + "description": "[]abi.SectorNumber", + "summary": "", + "schema": { + "examples": [ + [ + 123, + 124 + ] + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6946" + } + }, + { + "name": "Filecoin.SectorsListInStates", + "description": "```go\nfunc (s *StorageMinerStruct) SectorsListInStates(p0 context.Context, p1 []SectorState) ([]abi.SectorNumber, error) {\n\tif s.Internal.SectorsListInStates == nil {\n\t\treturn *new([]abi.SectorNumber), ErrNotSupported\n\t}\n\treturn s.Internal.SectorsListInStates(p0, p1)\n}\n```", + "summary": "List sectors in particular states\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "[]SectorState", + "summary": "", + "schema": { + "examples": [ + [ + "Proving" + ] + ], + "items": [ + { + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]abi.SectorNumber", + "description": "[]abi.SectorNumber", + "summary": "", + "schema": { + "examples": [ + [ + 123, + 124 + ] + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6957" + } + }, + { + "name": "Filecoin.SectorsRefs", + "description": "```go\nfunc (s *StorageMinerStruct) SectorsRefs(p0 context.Context) (map[string][]SealedRef, error) {\n\tif s.Internal.SectorsRefs == nil {\n\t\treturn *new(map[string][]SealedRef), ErrNotSupported\n\t}\n\treturn s.Internal.SectorsRefs(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "map[string][]SealedRef", + "description": "map[string][]SealedRef", + "summary": "", + "schema": { + "examples": [ + { + "98000": [ + { + "SectorID": 100, + "Offset": 10485760, + "Size": 1048576 + } + ] + } + ], + "patternProperties": { + ".*": { + "items": { + "additionalProperties": false, + "properties": { + "Offset": { + "title": "number", + "type": "number" + }, + "SectorID": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6968" + } + }, + { + "name": "Filecoin.SectorsStatus", + "description": "```go\nfunc (s *StorageMinerStruct) SectorsStatus(p0 context.Context, p1 abi.SectorNumber, p2 bool) (SectorInfo, error) {\n\tif s.Internal.SectorsStatus == nil {\n\t\treturn *new(SectorInfo), ErrNotSupported\n\t}\n\treturn s.Internal.SectorsStatus(p0, p1, p2)\n}\n```", + "summary": "Get the status of a given sector by ID\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "SectorInfo", + "description": "SectorInfo", + "summary": "", + "schema": { + "examples": [ + { + "SectorID": 9, + "State": "Proving", + "CommD": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "CommR": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Proof": "Ynl0ZSBhcnJheQ==", + "Deals": [ + 5432 + ], + "Pieces": [ + { + "Piece": { + "Size": 1032, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + }, + "DealInfo": { + "PublishCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DealID": 5432, + "DealProposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "DealSchedule": { + "StartEpoch": 10101, + "EndEpoch": 10101 + }, + "PieceActivationManifest": { + "CID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 2032, + "VerifiedAllocationKey": null, + "Notify": null + }, + "KeepUnsealed": true + } + } + ], + "Ticket": { + "Value": "Bw==", + "Epoch": 10101 + }, + "Seed": { + "Value": "Bw==", + "Epoch": 10101 + }, + "PreCommitMsg": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "CommitMsg": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Retries": 42, + "ToUpgrade": true, + "ReplicaUpdateMessage": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "LastErr": "string value", + "Log": [ + { + "Kind": "string value", + "Timestamp": 42, + "Trace": "string value", + "Message": "string value" + } + ], + "SealProof": 8, + "Activation": 10101, + "Expiration": 10101, + "DealWeight": "0", + "VerifiedDealWeight": "0", + "InitialPledge": "0", + "OnTime": 10101, + "Early": 10101 + } + ], + "additionalProperties": false, + "properties": { + "Activation": { + "title": "number", + "type": "number" + }, + "CommD": { + "title": "Content Identifier", + "type": "string" + }, + "CommR": { + "title": "Content Identifier", + "type": "string" + }, + "CommitMsg": { + "title": "Content Identifier", + "type": "string" + }, + "DealWeight": { + "additionalProperties": false, + "type": "object" + }, + "Deals": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "Early": { + "title": "number", + "type": "number" + }, + "Expiration": { + "title": "number", + "type": "number" + }, + "InitialPledge": { + "additionalProperties": false, + "type": "object" + }, + "LastErr": { + "type": "string" + }, + "Log": { + "items": { + "additionalProperties": false, + "properties": { + "Kind": { + "type": "string" + }, + "Message": { + "type": "string" + }, + "Timestamp": { + "title": "number", + "type": "number" + }, + "Trace": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "OnTime": { + "title": "number", + "type": "number" + }, + "Pieces": { + "items": { + "additionalProperties": false, + "properties": { + "DealInfo": { + "additionalProperties": false, + "properties": { + "DealID": { + "title": "number", + "type": "number" + }, + "DealProposal": { + "additionalProperties": false, + "properties": { + "Client": { + "additionalProperties": false, + "type": "object" + }, + "ClientCollateral": { + "additionalProperties": false, + "type": "object" + }, + "EndEpoch": { + "title": "number", + "type": "number" + }, + "Label": { + "additionalProperties": false, + "type": "object" + }, + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "PieceSize": { + "title": "number", + "type": "number" + }, + "Provider": { + "additionalProperties": false, + "type": "object" + }, + "ProviderCollateral": { + "additionalProperties": false, + "type": "object" + }, + "StartEpoch": { + "title": "number", + "type": "number" + }, + "StoragePricePerEpoch": { + "additionalProperties": false, + "type": "object" + }, + "VerifiedDeal": { + "type": "boolean" + } + }, + "type": "object" + }, + "DealSchedule": { + "additionalProperties": false, + "properties": { + "EndEpoch": { + "title": "number", + "type": "number" + }, + "StartEpoch": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "KeepUnsealed": { + "type": "boolean" + }, + "PieceActivationManifest": { + "additionalProperties": false, + "properties": { + "CID": { + "title": "Content Identifier", + "type": "string" + }, + "Notify": { + "items": { + "additionalProperties": false, + "properties": { + "Address": { + "additionalProperties": false, + "type": "object" + }, + "Payload": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "Size": { + "title": "number", + "type": "number" + }, + "VerifiedAllocationKey": { + "additionalProperties": false, + "properties": { + "Client": { + "title": "number", + "type": "number" + }, + "ID": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "PublishCid": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": "object" + }, + "Piece": { + "additionalProperties": false, + "properties": { + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "PreCommitMsg": { + "title": "Content Identifier", + "type": "string" + }, + "Proof": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + }, + "ReplicaUpdateMessage": { + "title": "Content Identifier", + "type": "string" + }, + "Retries": { + "title": "number", + "type": "number" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SectorID": { + "title": "number", + "type": "number" + }, + "Seed": { + "additionalProperties": false, + "properties": { + "Epoch": { + "title": "number", + "type": "number" + }, + "Value": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + } + }, + "type": "object" + }, + "State": { + "type": "string" + }, + "Ticket": { + "additionalProperties": false, + "properties": { + "Epoch": { + "title": "number", + "type": "number" + }, + "Value": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + } + }, + "type": "object" + }, + "ToUpgrade": { + "type": "boolean" + }, + "VerifiedDealWeight": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6979" + } + }, + { + "name": "Filecoin.SectorsSummary", + "description": "```go\nfunc (s *StorageMinerStruct) SectorsSummary(p0 context.Context) (map[SectorState]int, error) {\n\tif s.Internal.SectorsSummary == nil {\n\t\treturn *new(map[SectorState]int), ErrNotSupported\n\t}\n\treturn s.Internal.SectorsSummary(p0)\n}\n```", + "summary": "Get summary info of sectors\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "map[SectorState]int", + "description": "map[SectorState]int", + "summary": "", + "schema": { + "examples": [ + { + "Proving": 120 + } + ], + "patternProperties": { + ".*": { + "description": "Number is a number", + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L6990" + } + }, + { + "name": "Filecoin.SectorsUnsealPiece", + "description": "```go\nfunc (s *StorageMinerStruct) SectorsUnsealPiece(p0 context.Context, p1 storiface.SectorRef, p2 storiface.UnpaddedByteIndex, p3 abi.UnpaddedPieceSize, p4 abi.SealRandomness, p5 *cid.Cid) error {\n\tif s.Internal.SectorsUnsealPiece == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorsUnsealPiece(p0, p1, p2, p3, p4, p5)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.UnpaddedByteIndex", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1040384 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.UnpaddedPieceSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1024 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "abi.SealRandomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "*cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7001" + } + }, + { + "name": "Filecoin.SectorsUpdate", + "description": "```go\nfunc (s *StorageMinerStruct) SectorsUpdate(p0 context.Context, p1 abi.SectorNumber, p2 SectorState) error {\n\tif s.Internal.SectorsUpdate == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SectorsUpdate(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorNumber", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 9 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "SectorState", + "summary": "", + "schema": { + "examples": [ + "Proving" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7012" + } + }, + { + "name": "Filecoin.StorageAddLocal", + "description": "```go\nfunc (s *StorageMinerStruct) StorageAddLocal(p0 context.Context, p1 string) error {\n\tif s.Internal.StorageAddLocal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageAddLocal(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7023" + } + }, + { + "name": "Filecoin.StorageAttach", + "description": "```go\nfunc (s *StorageMinerStruct) StorageAttach(p0 context.Context, p1 storiface.StorageInfo, p2 fsutil.FsStat) error {\n\tif s.Internal.StorageAttach == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageAttach(p0, p1, p2)\n}\n```", + "summary": "paths.SectorIndex\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.StorageInfo", + "summary": "", + "schema": { + "examples": [ + { + "ID": "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + "URLs": [ + "string value" + ], + "Weight": 42, + "MaxStorage": 42, + "CanSeal": true, + "CanStore": true, + "Groups": [ + "string value" + ], + "AllowTo": [ + "string value" + ], + "AllowTypes": [ + "string value" + ], + "DenyTypes": [ + "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" + ] + } + ], + "additionalProperties": false, + "properties": { + "AllowMiners": { + "items": { + "type": "string" + }, + "type": "array" + }, + "AllowTo": { + "items": { + "type": "string" + }, + "type": "array" + }, + "AllowTypes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "CanSeal": { + "type": "boolean" + }, + "CanStore": { + "type": "boolean" + }, + "DenyMiners": { + "items": { + "type": "string" + }, + "type": "array" + }, + "DenyTypes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Groups": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ID": { + "type": "string" + }, + "MaxStorage": { + "title": "number", + "type": "number" + }, + "URLs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Weight": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "fsutil.FsStat", + "summary": "", + "schema": { + "examples": [ + { + "Capacity": 9, + "Available": 9, + "FSAvailable": 9, + "Reserved": 9, + "Max": 9, + "Used": 9 + } + ], + "additionalProperties": false, + "properties": { + "Available": { + "title": "number", + "type": "number" + }, + "Capacity": { + "title": "number", + "type": "number" + }, + "FSAvailable": { + "title": "number", + "type": "number" + }, + "Max": { + "title": "number", + "type": "number" + }, + "Reserved": { + "title": "number", + "type": "number" + }, + "Used": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7034" + } + }, + { + "name": "Filecoin.StorageAuthVerify", + "description": "```go\nfunc (s *StorageMinerStruct) StorageAuthVerify(p0 context.Context, p1 string) ([]auth.Permission, error) {\n\tif s.Internal.StorageAuthVerify == nil {\n\t\treturn *new([]auth.Permission), ErrNotSupported\n\t}\n\treturn s.Internal.StorageAuthVerify(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]auth.Permission", + "description": "[]auth.Permission", + "summary": "", + "schema": { + "examples": [ + [ + "write" + ] + ], + "items": [ + { + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7045" + } + }, + { + "name": "Filecoin.StorageBestAlloc", + "description": "```go\nfunc (s *StorageMinerStruct) StorageBestAlloc(p0 context.Context, p1 storiface.SectorFileType, p2 abi.SectorSize, p3 storiface.PathType, p4 abi.ActorID) ([]storiface.StorageInfo, error) {\n\tif s.Internal.StorageBestAlloc == nil {\n\t\treturn *new([]storiface.StorageInfo), ErrNotSupported\n\t}\n\treturn s.Internal.StorageBestAlloc(p0, p1, p2, p3, p4)\n}\n```", + "summary": "StorageBestAlloc returns list of paths where sector files of the specified type can be allocated, ordered by preference.\nPaths with more weight and more % of free space are preferred.\nNote: This method doesn't filter paths based on AllowTypes/DenyTypes.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorFileType", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SectorSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 34359738368 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "storiface.PathType", + "summary": "", + "schema": { + "examples": [ + "sealing" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "abi.ActorID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1000 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]storiface.StorageInfo", + "description": "[]storiface.StorageInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "ID": "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + "URLs": [ + "string value" + ], + "Weight": 42, + "MaxStorage": 42, + "CanSeal": true, + "CanStore": true, + "Groups": [ + "string value" + ], + "AllowTo": [ + "string value" + ], + "AllowTypes": [ + "string value" + ], + "DenyTypes": [ + "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" + ] + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "AllowMiners": { + "items": { + "type": "string" + }, + "type": "array" + }, + "AllowTo": { + "items": { + "type": "string" + }, + "type": "array" + }, + "AllowTypes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "CanSeal": { + "type": "boolean" + }, + "CanStore": { + "type": "boolean" + }, + "DenyMiners": { + "items": { + "type": "string" + }, + "type": "array" + }, + "DenyTypes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Groups": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ID": { + "type": "string" + }, + "MaxStorage": { + "title": "number", + "type": "number" + }, + "URLs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Weight": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7056" + } + }, + { + "name": "Filecoin.StorageDeclareSector", + "description": "```go\nfunc (s *StorageMinerStruct) StorageDeclareSector(p0 context.Context, p1 storiface.ID, p2 abi.SectorID, p3 storiface.SectorFileType, p4 bool) error {\n\tif s.Internal.StorageDeclareSector == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageDeclareSector(p0, p1, p2, p3, p4)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.ID", + "summary": "", + "schema": { + "examples": [ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SectorID", + "summary": "", + "schema": { + "examples": [ + { + "Miner": 1000, + "Number": 9 + } + ], + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "storiface.SectorFileType", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7067" + } + }, + { + "name": "Filecoin.StorageDetach", + "description": "```go\nfunc (s *StorageMinerStruct) StorageDetach(p0 context.Context, p1 storiface.ID, p2 string) error {\n\tif s.Internal.StorageDetach == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageDetach(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.ID", + "summary": "", + "schema": { + "examples": [ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7078" + } + }, + { + "name": "Filecoin.StorageDetachLocal", + "description": "```go\nfunc (s *StorageMinerStruct) StorageDetachLocal(p0 context.Context, p1 string) error {\n\tif s.Internal.StorageDetachLocal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageDetachLocal(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7089" + } + }, + { + "name": "Filecoin.StorageDropSector", + "description": "```go\nfunc (s *StorageMinerStruct) StorageDropSector(p0 context.Context, p1 storiface.ID, p2 abi.SectorID, p3 storiface.SectorFileType) error {\n\tif s.Internal.StorageDropSector == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageDropSector(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.ID", + "summary": "", + "schema": { + "examples": [ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SectorID", + "summary": "", + "schema": { + "examples": [ + { + "Miner": 1000, + "Number": 9 + } + ], + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "storiface.SectorFileType", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7100" + } + }, + { + "name": "Filecoin.StorageFindSector", + "description": "```go\nfunc (s *StorageMinerStruct) StorageFindSector(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 abi.SectorSize, p4 bool) ([]storiface.SectorStorageInfo, error) {\n\tif s.Internal.StorageFindSector == nil {\n\t\treturn *new([]storiface.SectorStorageInfo), ErrNotSupported\n\t}\n\treturn s.Internal.StorageFindSector(p0, p1, p2, p3, p4)\n}\n```", + "summary": "StorageFindSector returns list of paths where the specified sector files exist.\n\nIf allowFetch is set, list of paths to which the sector can be fetched will also be returned.\n- Paths which have sector files locally (don't require fetching) will be listed first.\n- Paths which have sector files locally will not be filtered based on based on AllowTypes/DenyTypes.\n- Paths which require fetching will be filtered based on AllowTypes/DenyTypes. If multiple\n file types are specified, each type will be considered individually, and a union of all paths\n which can accommodate each file type will be returned.\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorID", + "summary": "", + "schema": { + "examples": [ + { + "Miner": 1000, + "Number": 9 + } + ], + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.SectorFileType", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.SectorSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 34359738368 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]storiface.SectorStorageInfo", + "description": "[]storiface.SectorStorageInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "ID": "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + "URLs": [ + "string value" + ], + "BaseURLs": [ + "string value" + ], + "Weight": 42, + "CanSeal": true, + "CanStore": true, + "Primary": true, + "AllowTypes": [ + "string value" + ], + "DenyTypes": [ + "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" + ] + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "AllowMiners": { + "items": { + "type": "string" + }, + "type": "array" + }, + "AllowTypes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "BaseURLs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "CanSeal": { + "type": "boolean" + }, + "CanStore": { + "type": "boolean" + }, + "DenyMiners": { + "items": { + "type": "string" + }, + "type": "array" + }, + "DenyTypes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ID": { + "type": "string" + }, + "Primary": { + "type": "boolean" + }, + "URLs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Weight": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7111" + } + }, + { + "name": "Filecoin.StorageGetLocks", + "description": "```go\nfunc (s *StorageMinerStruct) StorageGetLocks(p0 context.Context) (storiface.SectorLocks, error) {\n\tif s.Internal.StorageGetLocks == nil {\n\t\treturn *new(storiface.SectorLocks), ErrNotSupported\n\t}\n\treturn s.Internal.StorageGetLocks(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "storiface.SectorLocks", + "description": "storiface.SectorLocks", + "summary": "", + "schema": { + "examples": [ + { + "Locks": [ + { + "Sector": { + "Miner": 1000, + "Number": 123 + }, + "Write": [ + 0, + 0, + 1, + 0, + 0, + 0 + ], + "Read": [ + 2, + 3, + 0, + 0, + 0, + 0 + ] + } + ] + } + ], + "additionalProperties": false, + "properties": { + "Locks": { + "items": { + "additionalProperties": false, + "properties": { + "Read": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 6, + "minItems": 6, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Write": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 6, + "minItems": 6, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7122" + } + }, + { + "name": "Filecoin.StorageInfo", + "description": "```go\nfunc (s *StorageMinerStruct) StorageInfo(p0 context.Context, p1 storiface.ID) (storiface.StorageInfo, error) {\n\tif s.Internal.StorageInfo == nil {\n\t\treturn *new(storiface.StorageInfo), ErrNotSupported\n\t}\n\treturn s.Internal.StorageInfo(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.ID", + "summary": "", + "schema": { + "examples": [ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.StorageInfo", + "description": "storiface.StorageInfo", + "summary": "", + "schema": { + "examples": [ + { + "ID": "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + "URLs": [ + "string value" + ], + "Weight": 42, + "MaxStorage": 42, + "CanSeal": true, + "CanStore": true, + "Groups": [ + "string value" + ], + "AllowTo": [ + "string value" + ], + "AllowTypes": [ + "string value" + ], + "DenyTypes": [ + "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" + ] + } + ], + "additionalProperties": false, + "properties": { + "AllowMiners": { + "items": { + "type": "string" + }, + "type": "array" + }, + "AllowTo": { + "items": { + "type": "string" + }, + "type": "array" + }, + "AllowTypes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "CanSeal": { + "type": "boolean" + }, + "CanStore": { + "type": "boolean" + }, + "DenyMiners": { + "items": { + "type": "string" + }, + "type": "array" + }, + "DenyTypes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Groups": { + "items": { + "type": "string" + }, + "type": "array" + }, + "ID": { + "type": "string" + }, + "MaxStorage": { + "title": "number", + "type": "number" + }, + "URLs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "Weight": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7133" + } + }, + { + "name": "Filecoin.StorageList", + "description": "```go\nfunc (s *StorageMinerStruct) StorageList(p0 context.Context) (map[storiface.ID][]storiface.Decl, error) {\n\tif s.Internal.StorageList == nil {\n\t\treturn *new(map[storiface.ID][]storiface.Decl), ErrNotSupported\n\t}\n\treturn s.Internal.StorageList(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "map[storiface.ID][]storiface.Decl", + "description": "map[storiface.ID][]storiface.Decl", + "summary": "", + "schema": { + "examples": [ + { + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8": [ + { + "Miner": 1000, + "Number": 100, + "SectorFileType": 2 + } + ] + } + ], + "patternProperties": { + ".*": { + "items": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7144" + } + }, + { + "name": "Filecoin.StorageLocal", + "description": "```go\nfunc (s *StorageMinerStruct) StorageLocal(p0 context.Context) (map[storiface.ID]string, error) {\n\tif s.Internal.StorageLocal == nil {\n\t\treturn *new(map[storiface.ID]string), ErrNotSupported\n\t}\n\treturn s.Internal.StorageLocal(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "map[storiface.ID]string", + "description": "map[storiface.ID]string", + "summary": "", + "schema": { + "examples": [ + { + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8": "/data/path" + } + ], + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7155" + } + }, + { + "name": "Filecoin.StorageLock", + "description": "```go\nfunc (s *StorageMinerStruct) StorageLock(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 storiface.SectorFileType) error {\n\tif s.Internal.StorageLock == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageLock(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorID", + "summary": "", + "schema": { + "examples": [ + { + "Miner": 1000, + "Number": 9 + } + ], + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.SectorFileType", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "storiface.SectorFileType", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7166" + } + }, + { + "name": "Filecoin.StorageRedeclareLocal", + "description": "```go\nfunc (s *StorageMinerStruct) StorageRedeclareLocal(p0 context.Context, p1 *storiface.ID, p2 bool) error {\n\tif s.Internal.StorageRedeclareLocal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageRedeclareLocal(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*storiface.ID", + "summary": "", + "schema": { + "examples": [ + "1399aa04-2625-44b1-bad4-bd07b59b22c4" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7177" + } + }, + { + "name": "Filecoin.StorageReportHealth", + "description": "```go\nfunc (s *StorageMinerStruct) StorageReportHealth(p0 context.Context, p1 storiface.ID, p2 storiface.HealthReport) error {\n\tif s.Internal.StorageReportHealth == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageReportHealth(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.ID", + "summary": "", + "schema": { + "examples": [ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.HealthReport", + "summary": "", + "schema": { + "examples": [ + { + "Stat": { + "Capacity": 9, + "Available": 9, + "FSAvailable": 9, + "Reserved": 9, + "Max": 9, + "Used": 9 + }, + "Err": "string value" + } + ], + "additionalProperties": false, + "properties": { + "Err": { + "type": "string" + }, + "Stat": { + "additionalProperties": false, + "properties": { + "Available": { + "title": "number", + "type": "number" + }, + "Capacity": { + "title": "number", + "type": "number" + }, + "FSAvailable": { + "title": "number", + "type": "number" + }, + "Max": { + "title": "number", + "type": "number" + }, + "Reserved": { + "title": "number", + "type": "number" + }, + "Used": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7188" + } + }, + { + "name": "Filecoin.StorageStat", + "description": "```go\nfunc (s *StorageMinerStruct) StorageStat(p0 context.Context, p1 storiface.ID) (fsutil.FsStat, error) {\n\tif s.Internal.StorageStat == nil {\n\t\treturn *new(fsutil.FsStat), ErrNotSupported\n\t}\n\treturn s.Internal.StorageStat(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.ID", + "summary": "", + "schema": { + "examples": [ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "fsutil.FsStat", + "description": "fsutil.FsStat", + "summary": "", + "schema": { + "examples": [ + { + "Capacity": 9, + "Available": 9, + "FSAvailable": 9, + "Reserved": 9, + "Max": 9, + "Used": 9 + } + ], + "additionalProperties": false, + "properties": { + "Available": { + "title": "number", + "type": "number" + }, + "Capacity": { + "title": "number", + "type": "number" + }, + "FSAvailable": { + "title": "number", + "type": "number" + }, + "Max": { + "title": "number", + "type": "number" + }, + "Reserved": { + "title": "number", + "type": "number" + }, + "Used": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7199" + } + }, + { + "name": "Filecoin.StorageTryLock", + "description": "```go\nfunc (s *StorageMinerStruct) StorageTryLock(p0 context.Context, p1 abi.SectorID, p2 storiface.SectorFileType, p3 storiface.SectorFileType) (bool, error) {\n\tif s.Internal.StorageTryLock == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.StorageTryLock(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorID", + "summary": "", + "schema": { + "examples": [ + { + "Miner": 1000, + "Number": 9 + } + ], + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.SectorFileType", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "storiface.SectorFileType", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7210" + } + }, + { + "name": "Filecoin.WorkerConnect", + "description": "```go\nfunc (s *StorageMinerStruct) WorkerConnect(p0 context.Context, p1 string) error {\n\tif s.Internal.WorkerConnect == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.WorkerConnect(p0, p1)\n}\n```", + "summary": "WorkerConnect tells the node to connect to workers RPC\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7221" + } + }, + { + "name": "Filecoin.WorkerJobs", + "description": "```go\nfunc (s *StorageMinerStruct) WorkerJobs(p0 context.Context) (map[uuid.UUID][]storiface.WorkerJob, error) {\n\tif s.Internal.WorkerJobs == nil {\n\t\treturn *new(map[uuid.UUID][]storiface.WorkerJob), ErrNotSupported\n\t}\n\treturn s.Internal.WorkerJobs(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "map[uuid.UUID][]storiface.WorkerJob", + "description": "map[uuid.UUID][]storiface.WorkerJob", + "summary": "", + "schema": { + "examples": [ + { + "ef8d99a2-6865-4189-8ffa-9fef0f806eee": [ + { + "ID": { + "Sector": { + "Miner": 1000, + "Number": 100 + }, + "ID": "76081ba0-61bd-45a5-bc08-af05f1c26e5d" + }, + "Sector": { + "Miner": 1000, + "Number": 100 + }, + "Task": "seal/v0/precommit/2", + "RunWait": 0, + "Start": "2020-11-12T09:22:07Z", + "Hostname": "host" + } + ] + } + ], + "patternProperties": { + ".*": { + "items": { + "additionalProperties": false, + "properties": { + "Hostname": { + "type": "string" + }, + "ID": { + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "RunWait": { + "title": "number", + "type": "number" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Start": { + "format": "date-time", + "type": "string" + }, + "Task": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7232" + } + }, + { + "name": "Filecoin.WorkerStats", + "description": "```go\nfunc (s *StorageMinerStruct) WorkerStats(p0 context.Context) (map[uuid.UUID]storiface.WorkerStats, error) {\n\tif s.Internal.WorkerStats == nil {\n\t\treturn *new(map[uuid.UUID]storiface.WorkerStats), ErrNotSupported\n\t}\n\treturn s.Internal.WorkerStats(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "map[uuid.UUID]storiface.WorkerStats", + "description": "map[uuid.UUID]storiface.WorkerStats", + "summary": "", + "schema": { + "examples": [ + { + "ef8d99a2-6865-4189-8ffa-9fef0f806eee": { + "Info": { + "Hostname": "host", + "IgnoreResources": false, + "Resources": { + "MemPhysical": 274877906944, + "MemUsed": 2147483648, + "MemSwap": 128849018880, + "MemSwapUsed": 2147483648, + "CPUs": 64, + "GPUs": [ + "aGPU 1337" + ], + "Resources": { + "post/v0/windowproof": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 32212254720, + "MaxMemory": 103079215104, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 64424509440, + "MaxMemory": 128849018880, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 32212254720, + "MaxMemory": 103079215104, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 64424509440, + "MaxMemory": 128849018880, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 32212254720, + "MaxMemory": 103079215104, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 64424509440, + "MaxMemory": 128849018880, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + } + }, + "post/v0/winningproof": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + } + }, + "seal/v0/addpiece": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/commit/1": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/commit/2": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + } + }, + "seal/v0/datacid": { + "0": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/fetch": { + "0": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + } + }, + "seal/v0/precommit/1": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + } + }, + "seal/v0/precommit/2": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 16106127360, + "MaxMemory": 16106127360, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 32212254720, + "MaxMemory": 32212254720, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 16106127360, + "MaxMemory": 16106127360, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 32212254720, + "MaxMemory": 32212254720, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 16106127360, + "MaxMemory": 16106127360, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 32212254720, + "MaxMemory": 32212254720, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/provereplicaupdate/1": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/provereplicaupdate/2": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + } + }, + "seal/v0/regensectorkey": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/replicaupdate": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/unseal": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + } + } + } + } + }, + "Tasks": null, + "Enabled": true, + "MemUsedMin": 0, + "MemUsedMax": 0, + "GpuUsed": 0, + "CpuUse": 0, + "TaskCounts": null + } + } + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "CpuUse": { + "title": "number", + "type": "number" + }, + "Enabled": { + "type": "boolean" + }, + "GpuUsed": { + "type": "number" + }, + "Info": { + "additionalProperties": false, + "properties": { + "Hostname": { + "type": "string" + }, + "IgnoreResources": { + "type": "boolean" + }, + "Resources": { + "additionalProperties": false, + "properties": { + "CPUs": { + "title": "number", + "type": "number" + }, + "GPUs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "MemPhysical": { + "title": "number", + "type": "number" + }, + "MemSwap": { + "title": "number", + "type": "number" + }, + "MemSwapUsed": { + "title": "number", + "type": "number" + }, + "MemUsed": { + "title": "number", + "type": "number" + }, + "Resources": { + "patternProperties": { + ".*": { + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "BaseMinMemory": { + "title": "number", + "type": "number" + }, + "GPUUtilization": { + "type": "number" + }, + "MaxConcurrent": { + "title": "number", + "type": "number" + }, + "MaxMemory": { + "title": "number", + "type": "number" + }, + "MaxParallelism": { + "title": "number", + "type": "number" + }, + "MaxParallelismGPU": { + "title": "number", + "type": "number" + }, + "MinMemory": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "MemUsedMax": { + "title": "number", + "type": "number" + }, + "MemUsedMin": { + "title": "number", + "type": "number" + }, + "TaskCounts": { + "patternProperties": { + ".*": { + "description": "Number is a number", + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "Tasks": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7243" + } + } + ] +} \ No newline at end of file diff --git a/build/openrpc/miner.json.gz b/build/openrpc/miner.json.gz index ba135c01577..5fbd42c3db8 100644 Binary files a/build/openrpc/miner.json.gz and b/build/openrpc/miner.json.gz differ diff --git a/build/openrpc/worker.json b/build/openrpc/worker.json new file mode 100644 index 00000000000..889853b5f00 --- /dev/null +++ b/build/openrpc/worker.json @@ -0,0 +1,5536 @@ +{ + "openrpc": "1.2.6", + "info": { + "title": "Lotus RPC API", + "version": "1.27.0" + }, + "methods": [ + { + "name": "Filecoin.AddPiece", + "description": "```go\nfunc (s *WorkerStruct) AddPiece(p0 context.Context, p1 storiface.SectorRef, p2 []abi.UnpaddedPieceSize, p3 abi.UnpaddedPieceSize, p4 storiface.Data) (storiface.CallID, error) {\n\tif s.Internal.AddPiece == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.AddPiece(p0, p1, p2, p3, p4)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "[]abi.UnpaddedPieceSize", + "summary": "", + "schema": { + "examples": [ + [ + 1024 + ] + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.UnpaddedPieceSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1024 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "storiface.Data", + "summary": "", + "schema": { + "examples": [ + {} + ], + "additionalProperties": true + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7331" + } + }, + { + "name": "Filecoin.DataCid", + "description": "```go\nfunc (s *WorkerStruct) DataCid(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data) (storiface.CallID, error) {\n\tif s.Internal.DataCid == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.DataCid(p0, p1, p2)\n}\n```", + "summary": "storiface.WorkerCalls\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.UnpaddedPieceSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1024 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.Data", + "summary": "", + "schema": { + "examples": [ + {} + ], + "additionalProperties": true + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7342" + } + }, + { + "name": "Filecoin.DownloadSectorData", + "description": "```go\nfunc (s *WorkerStruct) DownloadSectorData(p0 context.Context, p1 storiface.SectorRef, p2 bool, p3 map[storiface.SectorFileType]storiface.SectorLocation) (storiface.CallID, error) {\n\tif s.Internal.DownloadSectorData == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.DownloadSectorData(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "map[storiface.SectorFileType]storiface.SectorLocation", + "summary": "", + "schema": { + "examples": [ + { + "2": { + "Local": false, + "URL": "https://example.com/sealingservice/sectors/s-f0123-12345", + "Headers": null + } + } + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "Headers": { + "items": { + "additionalProperties": false, + "properties": { + "Key": { + "type": "string" + }, + "Value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "Local": { + "type": "boolean" + }, + "URL": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7353" + } + }, + { + "name": "Filecoin.Enabled", + "description": "```go\nfunc (s *WorkerStruct) Enabled(p0 context.Context) (bool, error) {\n\tif s.Internal.Enabled == nil {\n\t\treturn false, ErrNotSupported\n\t}\n\treturn s.Internal.Enabled(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "bool", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7364" + } + }, + { + "name": "Filecoin.Fetch", + "description": "```go\nfunc (s *WorkerStruct) Fetch(p0 context.Context, p1 storiface.SectorRef, p2 storiface.SectorFileType, p3 storiface.PathType, p4 storiface.AcquireMode) (storiface.CallID, error) {\n\tif s.Internal.Fetch == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.Fetch(p0, p1, p2, p3, p4)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.SectorFileType", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "storiface.PathType", + "summary": "", + "schema": { + "examples": [ + "sealing" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "storiface.AcquireMode", + "summary": "", + "schema": { + "examples": [ + "move" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7375" + } + }, + { + "name": "Filecoin.FinalizeReplicaUpdate", + "description": "```go\nfunc (s *WorkerStruct) FinalizeReplicaUpdate(p0 context.Context, p1 storiface.SectorRef) (storiface.CallID, error) {\n\tif s.Internal.FinalizeReplicaUpdate == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.FinalizeReplicaUpdate(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7386" + } + }, + { + "name": "Filecoin.FinalizeSector", + "description": "```go\nfunc (s *WorkerStruct) FinalizeSector(p0 context.Context, p1 storiface.SectorRef) (storiface.CallID, error) {\n\tif s.Internal.FinalizeSector == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.FinalizeSector(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7397" + } + }, + { + "name": "Filecoin.GenerateSectorKeyFromData", + "description": "```go\nfunc (s *WorkerStruct) GenerateSectorKeyFromData(p0 context.Context, p1 storiface.SectorRef, p2 cid.Cid) (storiface.CallID, error) {\n\tif s.Internal.GenerateSectorKeyFromData == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.GenerateSectorKeyFromData(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7408" + } + }, + { + "name": "Filecoin.GenerateWindowPoSt", + "description": "```go\nfunc (s *WorkerStruct) GenerateWindowPoSt(p0 context.Context, p1 abi.RegisteredPoStProof, p2 abi.ActorID, p3 []storiface.PostSectorChallenge, p4 int, p5 abi.PoStRandomness) (storiface.WindowPoStResult, error) {\n\tif s.Internal.GenerateWindowPoSt == nil {\n\t\treturn *new(storiface.WindowPoStResult), ErrNotSupported\n\t}\n\treturn s.Internal.GenerateWindowPoSt(p0, p1, p2, p3, p4, p5)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.RegisteredPoStProof", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 8 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.ActorID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1000 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]storiface.PostSectorChallenge", + "summary": "", + "schema": { + "examples": [ + [ + { + "SealProof": 8, + "SectorNumber": 9, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Challenge": [ + 42 + ], + "Update": true + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Challenge": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "Update": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "int", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 123 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "abi.PoStRandomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.WindowPoStResult", + "description": "storiface.WindowPoStResult", + "summary": "", + "schema": { + "examples": [ + { + "PoStProofs": { + "PoStProof": 8, + "ProofBytes": "Ynl0ZSBhcnJheQ==" + }, + "Skipped": [ + { + "Miner": 1000, + "Number": 9 + } + ] + } + ], + "additionalProperties": false, + "properties": { + "PoStProofs": { + "additionalProperties": false, + "properties": { + "PoStProof": { + "title": "number", + "type": "number" + }, + "ProofBytes": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": "object" + }, + "Skipped": { + "items": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7419" + } + }, + { + "name": "Filecoin.GenerateWinningPoSt", + "description": "```go\nfunc (s *WorkerStruct) GenerateWinningPoSt(p0 context.Context, p1 abi.RegisteredPoStProof, p2 abi.ActorID, p3 []storiface.PostSectorChallenge, p4 abi.PoStRandomness) ([]proof.PoStProof, error) {\n\tif s.Internal.GenerateWinningPoSt == nil {\n\t\treturn *new([]proof.PoStProof), ErrNotSupported\n\t}\n\treturn s.Internal.GenerateWinningPoSt(p0, p1, p2, p3, p4)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.RegisteredPoStProof", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 8 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.ActorID", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1000 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]storiface.PostSectorChallenge", + "summary": "", + "schema": { + "examples": [ + [ + { + "SealProof": 8, + "SectorNumber": 9, + "SealedCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Challenge": [ + 42 + ], + "Update": true + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Challenge": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "type": "array" + }, + "SealProof": { + "title": "number", + "type": "number" + }, + "SealedCID": { + "title": "Content Identifier", + "type": "string" + }, + "SectorNumber": { + "title": "number", + "type": "number" + }, + "Update": { + "type": "boolean" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "abi.PoStRandomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "[]proof.PoStProof", + "description": "[]proof.PoStProof", + "summary": "", + "schema": { + "examples": [ + [ + { + "PoStProof": 8, + "ProofBytes": "Ynl0ZSBhcnJheQ==" + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "PoStProof": { + "title": "number", + "type": "number" + }, + "ProofBytes": { + "media": { + "binaryEncoding": "base64" + }, + "type": "string" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7430" + } + }, + { + "name": "Filecoin.Info", + "description": "```go\nfunc (s *WorkerStruct) Info(p0 context.Context) (storiface.WorkerInfo, error) {\n\tif s.Internal.Info == nil {\n\t\treturn *new(storiface.WorkerInfo), ErrNotSupported\n\t}\n\treturn s.Internal.Info(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "storiface.WorkerInfo", + "description": "storiface.WorkerInfo", + "summary": "", + "schema": { + "examples": [ + { + "Hostname": "string value", + "IgnoreResources": true, + "Resources": { + "MemPhysical": 42, + "MemUsed": 42, + "MemSwap": 42, + "MemSwapUsed": 42, + "CPUs": 42, + "GPUs": [ + "string value" + ], + "Resources": { + "post/v0/windowproof": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 32212254720, + "MaxMemory": 103079215104, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 64424509440, + "MaxMemory": 128849018880, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 32212254720, + "MaxMemory": 103079215104, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 64424509440, + "MaxMemory": 128849018880, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 32212254720, + "MaxMemory": 103079215104, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 64424509440, + "MaxMemory": 128849018880, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + } + }, + "post/v0/winningproof": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + } + }, + "seal/v0/addpiece": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/commit/1": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/commit/2": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + } + }, + "seal/v0/datacid": { + "0": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/fetch": { + "0": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 1048576, + "MaxMemory": 1048576, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 0, + "MaxConcurrent": 0 + } + }, + "seal/v0/precommit/1": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + } + }, + "seal/v0/precommit/2": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 16106127360, + "MaxMemory": 16106127360, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 32212254720, + "MaxMemory": 32212254720, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 16106127360, + "MaxMemory": 16106127360, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 32212254720, + "MaxMemory": 32212254720, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 0, + "MaxParallelism": -1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 16106127360, + "MaxMemory": 16106127360, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 32212254720, + "MaxMemory": 32212254720, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/provereplicaupdate/1": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 0, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/provereplicaupdate/2": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1610612736, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10737418240, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 32212254720, + "MaxMemory": 161061273600, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 34359738368, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 64424509440, + "MaxMemory": 204010946560, + "GPUUtilization": 1, + "MaxParallelism": -1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 68719476736, + "MaxConcurrent": 0 + } + }, + "seal/v0/regensectorkey": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/replicaupdate": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 1073741824, + "MaxMemory": 1073741824, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 4294967296, + "MaxMemory": 4294967296, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 8589934592, + "MaxMemory": 8589934592, + "GPUUtilization": 1, + "MaxParallelism": 1, + "MaxParallelismGPU": 6, + "BaseMinMemory": 1073741824, + "MaxConcurrent": 0 + } + }, + "seal/v0/unseal": { + "0": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "1": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "10": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "11": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "12": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "13": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "14": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "2": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "3": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "4": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "5": { + "MinMemory": 2048, + "MaxMemory": 2048, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 2048, + "MaxConcurrent": 0 + }, + "6": { + "MinMemory": 8388608, + "MaxMemory": 8388608, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 8388608, + "MaxConcurrent": 0 + }, + "7": { + "MinMemory": 805306368, + "MaxMemory": 1073741824, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 1048576, + "MaxConcurrent": 0 + }, + "8": { + "MinMemory": 60129542144, + "MaxMemory": 68719476736, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + }, + "9": { + "MinMemory": 120259084288, + "MaxMemory": 137438953472, + "GPUUtilization": 0, + "MaxParallelism": 1, + "MaxParallelismGPU": 0, + "BaseMinMemory": 10485760, + "MaxConcurrent": 0 + } + } + } + } + } + ], + "additionalProperties": false, + "properties": { + "Hostname": { + "type": "string" + }, + "IgnoreResources": { + "type": "boolean" + }, + "Resources": { + "additionalProperties": false, + "properties": { + "CPUs": { + "title": "number", + "type": "number" + }, + "GPUs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "MemPhysical": { + "title": "number", + "type": "number" + }, + "MemSwap": { + "title": "number", + "type": "number" + }, + "MemSwapUsed": { + "title": "number", + "type": "number" + }, + "MemUsed": { + "title": "number", + "type": "number" + }, + "Resources": { + "patternProperties": { + ".*": { + "patternProperties": { + ".*": { + "additionalProperties": false, + "properties": { + "BaseMinMemory": { + "title": "number", + "type": "number" + }, + "GPUUtilization": { + "type": "number" + }, + "MaxConcurrent": { + "title": "number", + "type": "number" + }, + "MaxMemory": { + "title": "number", + "type": "number" + }, + "MaxParallelism": { + "title": "number", + "type": "number" + }, + "MaxParallelismGPU": { + "title": "number", + "type": "number" + }, + "MinMemory": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7441" + } + }, + { + "name": "Filecoin.MoveStorage", + "description": "```go\nfunc (s *WorkerStruct) MoveStorage(p0 context.Context, p1 storiface.SectorRef, p2 storiface.SectorFileType) (storiface.CallID, error) {\n\tif s.Internal.MoveStorage == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.MoveStorage(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.SectorFileType", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7452" + } + }, + { + "name": "Filecoin.Paths", + "description": "```go\nfunc (s *WorkerStruct) Paths(p0 context.Context) ([]storiface.StoragePath, error) {\n\tif s.Internal.Paths == nil {\n\t\treturn *new([]storiface.StoragePath), ErrNotSupported\n\t}\n\treturn s.Internal.Paths(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "[]storiface.StoragePath", + "description": "[]storiface.StoragePath", + "summary": "", + "schema": { + "examples": [ + [ + { + "ID": "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + "Weight": 42, + "LocalPath": "string value", + "CanSeal": true, + "CanStore": true + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "CanSeal": { + "type": "boolean" + }, + "CanStore": { + "type": "boolean" + }, + "ID": { + "type": "string" + }, + "LocalPath": { + "type": "string" + }, + "Weight": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7463" + } + }, + { + "name": "Filecoin.ProcessSession", + "description": "```go\nfunc (s *WorkerStruct) ProcessSession(p0 context.Context) (uuid.UUID, error) {\n\tif s.Internal.ProcessSession == nil {\n\t\treturn *new(uuid.UUID), ErrNotSupported\n\t}\n\treturn s.Internal.ProcessSession(p0)\n}\n```", + "summary": "returns a random UUID of worker session, generated randomly when worker\nprocess starts\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "uuid.UUID", + "description": "uuid.UUID", + "summary": "", + "schema": { + "examples": [ + "07070707-0707-0707-0707-070707070707" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 16, + "minItems": 16, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7474" + } + }, + { + "name": "Filecoin.ProveReplicaUpdate1", + "description": "```go\nfunc (s *WorkerStruct) ProveReplicaUpdate1(p0 context.Context, p1 storiface.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid) (storiface.CallID, error) {\n\tif s.Internal.ProveReplicaUpdate1 == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.ProveReplicaUpdate1(p0, p1, p2, p3, p4)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7485" + } + }, + { + "name": "Filecoin.ProveReplicaUpdate2", + "description": "```go\nfunc (s *WorkerStruct) ProveReplicaUpdate2(p0 context.Context, p1 storiface.SectorRef, p2 cid.Cid, p3 cid.Cid, p4 cid.Cid, p5 storiface.ReplicaVanillaProofs) (storiface.CallID, error) {\n\tif s.Internal.ProveReplicaUpdate2 == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.ProveReplicaUpdate2(p0, p1, p2, p3, p4, p5)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "storiface.ReplicaVanillaProofs", + "summary": "", + "schema": { + "examples": [ + [ + "Ynl0ZSBhcnJheQ==" + ] + ], + "items": [ + { + "type": [ + "string" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7496" + } + }, + { + "name": "Filecoin.ReleaseUnsealed", + "description": "```go\nfunc (s *WorkerStruct) ReleaseUnsealed(p0 context.Context, p1 storiface.SectorRef, p2 []storiface.Range) (storiface.CallID, error) {\n\tif s.Internal.ReleaseUnsealed == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.ReleaseUnsealed(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "[]storiface.Range", + "summary": "", + "schema": { + "examples": [ + [ + { + "Offset": 1024, + "Size": 1024 + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "Offset": { + "title": "number", + "type": "number" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7507" + } + }, + { + "name": "Filecoin.Remove", + "description": "```go\nfunc (s *WorkerStruct) Remove(p0 context.Context, p1 abi.SectorID) error {\n\tif s.Internal.Remove == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.Remove(p0, p1)\n}\n```", + "summary": "Storage / Other\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "abi.SectorID", + "summary": "", + "schema": { + "examples": [ + { + "Miner": 1000, + "Number": 9 + } + ], + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7518" + } + }, + { + "name": "Filecoin.ReplicaUpdate", + "description": "```go\nfunc (s *WorkerStruct) ReplicaUpdate(p0 context.Context, p1 storiface.SectorRef, p2 []abi.PieceInfo) (storiface.CallID, error) {\n\tif s.Internal.ReplicaUpdate == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.ReplicaUpdate(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "[]abi.PieceInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "Size": 1032, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7529" + } + }, + { + "name": "Filecoin.SealCommit1", + "description": "```go\nfunc (s *WorkerStruct) SealCommit1(p0 context.Context, p1 storiface.SectorRef, p2 abi.SealRandomness, p3 abi.InteractiveSealRandomness, p4 []abi.PieceInfo, p5 storiface.SectorCids) (storiface.CallID, error) {\n\tif s.Internal.SealCommit1 == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.SealCommit1(p0, p1, p2, p3, p4, p5)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SealRandomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.InteractiveSealRandomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "[]abi.PieceInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "Size": 1032, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "storiface.SectorCids", + "summary": "", + "schema": { + "examples": [ + { + "Unsealed": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Sealed": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ], + "additionalProperties": false, + "properties": { + "Sealed": { + "title": "Content Identifier", + "type": "string" + }, + "Unsealed": { + "title": "Content Identifier", + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7540" + } + }, + { + "name": "Filecoin.SealCommit2", + "description": "```go\nfunc (s *WorkerStruct) SealCommit2(p0 context.Context, p1 storiface.SectorRef, p2 storiface.Commit1Out) (storiface.CallID, error) {\n\tif s.Internal.SealCommit2 == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.SealCommit2(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.Commit1Out", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7551" + } + }, + { + "name": "Filecoin.SealPreCommit1", + "description": "```go\nfunc (s *WorkerStruct) SealPreCommit1(p0 context.Context, p1 storiface.SectorRef, p2 abi.SealRandomness, p3 []abi.PieceInfo) (storiface.CallID, error) {\n\tif s.Internal.SealPreCommit1 == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.SealPreCommit1(p0, p1, p2, p3)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "abi.SealRandomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "[]abi.PieceInfo", + "summary": "", + "schema": { + "examples": [ + [ + { + "Size": 1032, + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + } + ] + ], + "items": [ + { + "additionalProperties": false, + "properties": { + "PieceCID": { + "title": "Content Identifier", + "type": "string" + }, + "Size": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7562" + } + }, + { + "name": "Filecoin.SealPreCommit2", + "description": "```go\nfunc (s *WorkerStruct) SealPreCommit2(p0 context.Context, p1 storiface.SectorRef, p2 storiface.PreCommit1Out) (storiface.CallID, error) {\n\tif s.Internal.SealPreCommit2 == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.SealPreCommit2(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.PreCommit1Out", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7573" + } + }, + { + "name": "Filecoin.Session", + "description": "```go\nfunc (s *WorkerStruct) Session(p0 context.Context) (uuid.UUID, error) {\n\tif s.Internal.Session == nil {\n\t\treturn *new(uuid.UUID), ErrNotSupported\n\t}\n\treturn s.Internal.Session(p0)\n}\n```", + "summary": "Like ProcessSession, but returns an error when worker is disabled\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "uuid.UUID", + "description": "uuid.UUID", + "summary": "", + "schema": { + "examples": [ + "07070707-0707-0707-0707-070707070707" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "maxItems": 16, + "minItems": 16, + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7584" + } + }, + { + "name": "Filecoin.SetEnabled", + "description": "```go\nfunc (s *WorkerStruct) SetEnabled(p0 context.Context, p1 bool) error {\n\tif s.Internal.SetEnabled == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.SetEnabled(p0, p1)\n}\n```", + "summary": "SetEnabled marks the worker as enabled/disabled. Not that this setting\nmay take a few seconds to propagate to task scheduler\n", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7595" + } + }, + { + "name": "Filecoin.Shutdown", + "description": "```go\nfunc (s *WorkerStruct) Shutdown(p0 context.Context) error {\n\tif s.Internal.Shutdown == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.Shutdown(p0)\n}\n```", + "summary": "Trigger shutdown\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7606" + } + }, + { + "name": "Filecoin.StorageAddLocal", + "description": "```go\nfunc (s *WorkerStruct) StorageAddLocal(p0 context.Context, p1 string) error {\n\tif s.Internal.StorageAddLocal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageAddLocal(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7617" + } + }, + { + "name": "Filecoin.StorageDetachAll", + "description": "```go\nfunc (s *WorkerStruct) StorageDetachAll(p0 context.Context) error {\n\tif s.Internal.StorageDetachAll == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageDetachAll(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7628" + } + }, + { + "name": "Filecoin.StorageDetachLocal", + "description": "```go\nfunc (s *WorkerStruct) StorageDetachLocal(p0 context.Context, p1 string) error {\n\tif s.Internal.StorageDetachLocal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageDetachLocal(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "string", + "summary": "", + "schema": { + "examples": [ + "string value" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7639" + } + }, + { + "name": "Filecoin.StorageLocal", + "description": "```go\nfunc (s *WorkerStruct) StorageLocal(p0 context.Context) (map[storiface.ID]string, error) {\n\tif s.Internal.StorageLocal == nil {\n\t\treturn *new(map[storiface.ID]string), ErrNotSupported\n\t}\n\treturn s.Internal.StorageLocal(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "map[storiface.ID]string", + "description": "map[storiface.ID]string", + "summary": "", + "schema": { + "examples": [ + { + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8": "/data/path" + } + ], + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7650" + } + }, + { + "name": "Filecoin.StorageRedeclareLocal", + "description": "```go\nfunc (s *WorkerStruct) StorageRedeclareLocal(p0 context.Context, p1 *storiface.ID, p2 bool) error {\n\tif s.Internal.StorageRedeclareLocal == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.StorageRedeclareLocal(p0, p1, p2)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "*storiface.ID", + "summary": "", + "schema": { + "examples": [ + "1399aa04-2625-44b1-bad4-bd07b59b22c4" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "bool", + "summary": "", + "schema": { + "examples": [ + true + ], + "type": [ + "boolean" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7661" + } + }, + { + "name": "Filecoin.TaskDisable", + "description": "```go\nfunc (s *WorkerStruct) TaskDisable(p0 context.Context, p1 sealtasks.TaskType) error {\n\tif s.Internal.TaskDisable == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.TaskDisable(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "sealtasks.TaskType", + "summary": "", + "schema": { + "examples": [ + "seal/v0/commit/2" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7672" + } + }, + { + "name": "Filecoin.TaskEnable", + "description": "```go\nfunc (s *WorkerStruct) TaskEnable(p0 context.Context, p1 sealtasks.TaskType) error {\n\tif s.Internal.TaskEnable == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.TaskEnable(p0, p1)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "sealtasks.TaskType", + "summary": "", + "schema": { + "examples": [ + "seal/v0/commit/2" + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7683" + } + }, + { + "name": "Filecoin.TaskTypes", + "description": "```go\nfunc (s *WorkerStruct) TaskTypes(p0 context.Context) (map[sealtasks.TaskType]struct{}, error) {\n\tif s.Internal.TaskTypes == nil {\n\t\treturn *new(map[sealtasks.TaskType]struct{}), ErrNotSupported\n\t}\n\treturn s.Internal.TaskTypes(p0)\n}\n```", + "summary": "TaskType -\u003e Weight\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "map[sealtasks.TaskType]struct{}", + "description": "map[sealtasks.TaskType]struct{}", + "summary": "", + "schema": { + "examples": [ + { + "seal/v0/precommit/2": {} + } + ], + "patternProperties": { + ".*": { + "additionalProperties": false, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7694" + } + }, + { + "name": "Filecoin.UnsealPiece", + "description": "```go\nfunc (s *WorkerStruct) UnsealPiece(p0 context.Context, p1 storiface.SectorRef, p2 storiface.UnpaddedByteIndex, p3 abi.UnpaddedPieceSize, p4 abi.SealRandomness, p5 cid.Cid) (storiface.CallID, error) {\n\tif s.Internal.UnsealPiece == nil {\n\t\treturn *new(storiface.CallID), ErrNotSupported\n\t}\n\treturn s.Internal.UnsealPiece(p0, p1, p2, p3, p4, p5)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [ + { + "name": "p1", + "description": "storiface.SectorRef", + "summary": "", + "schema": { + "examples": [ + { + "ID": { + "Miner": 1000, + "Number": 9 + }, + "ProofType": 8 + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + }, + "ProofType": { + "title": "number", + "type": "number" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p2", + "description": "storiface.UnpaddedByteIndex", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1040384 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p3", + "description": "abi.UnpaddedPieceSize", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 1024 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p4", + "description": "abi.SealRandomness", + "summary": "", + "schema": { + "examples": [ + "Bw==" + ], + "items": [ + { + "title": "number", + "description": "Number is a number", + "type": [ + "number" + ] + } + ], + "type": [ + "array" + ] + }, + "required": true, + "deprecated": false + }, + { + "name": "p5", + "description": "cid.Cid", + "summary": "", + "schema": { + "title": "Content Identifier", + "description": "Cid represents a self-describing content addressed identifier. It is formed by a Version, a Codec (which indicates a multicodec-packed content type) and a Multihash.", + "examples": [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } + ], + "type": [ + "string" + ] + }, + "required": true, + "deprecated": false + } + ], + "result": { + "name": "storiface.CallID", + "description": "storiface.CallID", + "summary": "", + "schema": { + "examples": [ + { + "Sector": { + "Miner": 1000, + "Number": 9 + }, + "ID": "07070707-0707-0707-0707-070707070707" + } + ], + "additionalProperties": false, + "properties": { + "ID": { + "items": { + "description": "Number is a number", + "title": "number", + "type": "number" + }, + "maxItems": 16, + "minItems": 16, + "type": "array" + }, + "Sector": { + "additionalProperties": false, + "properties": { + "Miner": { + "title": "number", + "type": "number" + }, + "Number": { + "title": "number", + "type": "number" + } + }, + "type": "object" + } + }, + "type": [ + "object" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7705" + } + }, + { + "name": "Filecoin.Version", + "description": "```go\nfunc (s *WorkerStruct) Version(p0 context.Context) (Version, error) {\n\tif s.Internal.Version == nil {\n\t\treturn *new(Version), ErrNotSupported\n\t}\n\treturn s.Internal.Version(p0)\n}\n```", + "summary": "", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "Version", + "description": "Version", + "summary": "", + "schema": { + "title": "number", + "description": "Number is a number", + "examples": [ + 131840 + ], + "type": [ + "number" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7716" + } + }, + { + "name": "Filecoin.WaitQuiet", + "description": "```go\nfunc (s *WorkerStruct) WaitQuiet(p0 context.Context) error {\n\tif s.Internal.WaitQuiet == nil {\n\t\treturn ErrNotSupported\n\t}\n\treturn s.Internal.WaitQuiet(p0)\n}\n```", + "summary": "WaitQuiet blocks until there are no tasks running\n", + "paramStructure": "by-position", + "params": [], + "result": { + "name": "Null", + "description": "Null", + "schema": { + "type": [ + "null" + ] + }, + "required": true, + "deprecated": false + }, + "deprecated": false, + "externalDocs": { + "description": "Github remote link", + "url": "https://github.com/filecoin-project/lotus/blob/master/api/proxy_gen.go#L7727" + } + } + ] +} \ No newline at end of file diff --git a/build/openrpc/worker.json.gz b/build/openrpc/worker.json.gz index 58231030637..0f3cb11c7a3 100644 Binary files a/build/openrpc/worker.json.gz and b/build/openrpc/worker.json.gz differ diff --git a/build/params_mainnet.go b/build/params_mainnet.go index 5831e513782..91a9b849759 100644 --- a/build/params_mainnet.go +++ b/build/params_mainnet.go @@ -165,5 +165,5 @@ const BootstrapPeerThreshold = 4 // 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 +// WhitelistedBlock skips 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 8a3f6550124..798a9f2a01d 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -124,6 +124,7 @@ const MinimumBaseFee = 100 const PackingEfficiencyNum = 4 const PackingEfficiencyDenom = 5 +// revive:disable-next-line:exported // Actor consts // TODO: pieceSize unused from actors var MinDealDuration, MaxDealDuration = policy.DealDurationBounds(0) diff --git a/build/version.go b/build/version.go index 506b25b3f2a..8fdaaafce98 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.26.2" +const BuildVersion = "1.27.0" func UserVersion() string { if os.Getenv("LOTUS_VERSION_IGNORE_COMMIT") == "1" { diff --git a/chain/actors/builtin/miner/actor.go.template b/chain/actors/builtin/miner/actor.go.template index 089e3dc68e1..c29590bba28 100644 --- a/chain/actors/builtin/miner/actor.go.template +++ b/chain/actors/builtin/miner/actor.go.template @@ -153,7 +153,7 @@ type Partition interface { UnprovenSectors() (bitfield.BitField, error) } -type SectorOnChainInfo = minertypes.SectorOnChainInfo +type SectorOnChainInfo = minertypes13.SectorOnChainInfo func PreferredSealProofTypeFromWindowPoStType(nver network.Version, proof abi.RegisteredPoStProof, configWantSynthetic bool) (abi.RegisteredSealProof, error) { // We added support for the new proofs in network version 7, and removed support for the old @@ -256,6 +256,7 @@ type ProveCommitSectors3Params = minertypes13.ProveCommitSectors3Params type SectorActivationManifest = minertypes13.SectorActivationManifest type ProveReplicaUpdates3Params = minertypes13.ProveReplicaUpdates3Params type SectorUpdateManifest = minertypes13.SectorUpdateManifest +type SectorOnChainInfoFlags = minertypes13.SectorOnChainInfoFlags var QAPowerMax = minertypes.QAPowerMax diff --git a/chain/actors/builtin/miner/miner.go b/chain/actors/builtin/miner/miner.go index 6bb1028f377..cdf0046f587 100644 --- a/chain/actors/builtin/miner/miner.go +++ b/chain/actors/builtin/miner/miner.go @@ -219,7 +219,7 @@ type Partition interface { UnprovenSectors() (bitfield.BitField, error) } -type SectorOnChainInfo = minertypes.SectorOnChainInfo +type SectorOnChainInfo = minertypes13.SectorOnChainInfo func PreferredSealProofTypeFromWindowPoStType(nver network.Version, proof abi.RegisteredPoStProof, configWantSynthetic bool) (abi.RegisteredSealProof, error) { // We added support for the new proofs in network version 7, and removed support for the old @@ -322,6 +322,7 @@ type ProveCommitSectors3Params = minertypes13.ProveCommitSectors3Params type SectorActivationManifest = minertypes13.SectorActivationManifest type ProveReplicaUpdates3Params = minertypes13.ProveReplicaUpdates3Params type SectorUpdateManifest = minertypes13.SectorUpdateManifest +type SectorOnChainInfoFlags = minertypes13.SectorOnChainInfoFlags var QAPowerMax = minertypes.QAPowerMax diff --git a/chain/actors/builtin/miner/state.go.template b/chain/actors/builtin/miner/state.go.template index 3c7f05d9af5..a940dd9ea53 100644 --- a/chain/actors/builtin/miner/state.go.template +++ b/chain/actors/builtin/miner/state.go.template @@ -583,7 +583,12 @@ func fromV{{.v}}SectorOnChainInfo(v{{.v}} miner{{.v}}.SectorOnChainInfo) SectorO ExpectedStoragePledge: v{{.v}}.ExpectedStoragePledge, {{if (ge .v 7)}} SectorKeyCID: v{{.v}}.SectorKeyCID, - {{end}} + {{end}} + {{if (ge .v 12)}} + PowerBaseEpoch: v{{.v}}.PowerBaseEpoch, + ReplacedDayReward: v{{.v}}.ReplacedDayReward, + Flags: SectorOnChainInfoFlags(v{{.v}}.Flags), + {{end}} } return info } diff --git a/chain/actors/builtin/miner/v12.go b/chain/actors/builtin/miner/v12.go index 90ecc97fd3d..a26d78d3204 100644 --- a/chain/actors/builtin/miner/v12.go +++ b/chain/actors/builtin/miner/v12.go @@ -545,6 +545,10 @@ func fromV12SectorOnChainInfo(v12 miner12.SectorOnChainInfo) SectorOnChainInfo { ExpectedStoragePledge: v12.ExpectedStoragePledge, SectorKeyCID: v12.SectorKeyCID, + + PowerBaseEpoch: v12.PowerBaseEpoch, + ReplacedDayReward: v12.ReplacedDayReward, + Flags: SectorOnChainInfoFlags(v12.Flags), } return info } diff --git a/chain/actors/builtin/miner/v13.go b/chain/actors/builtin/miner/v13.go index bbd95f8187d..c033a9907c8 100644 --- a/chain/actors/builtin/miner/v13.go +++ b/chain/actors/builtin/miner/v13.go @@ -545,6 +545,10 @@ func fromV13SectorOnChainInfo(v13 miner13.SectorOnChainInfo) SectorOnChainInfo { ExpectedStoragePledge: v13.ExpectedStoragePledge, SectorKeyCID: v13.SectorKeyCID, + + PowerBaseEpoch: v13.PowerBaseEpoch, + ReplacedDayReward: v13.ReplacedDayReward, + Flags: SectorOnChainInfoFlags(v13.Flags), } return info } diff --git a/chain/beacon/drand/drand.go b/chain/beacon/drand/drand.go index b5f5917ef74..852a1a31ce5 100644 --- a/chain/beacon/drand/drand.go +++ b/chain/beacon/drand/drand.go @@ -203,7 +203,6 @@ func (db *DrandBeacon) VerifyEntry(entry types.BeaconEntry, prevEntrySig []byte) } db.cacheValue(entry) - return nil } diff --git a/chain/beacon/drand/drand_test.go b/chain/beacon/drand/drand_test.go index 339aaeaad75..c35c0da18f5 100644 --- a/chain/beacon/drand/drand_test.go +++ b/chain/beacon/drand/drand_test.go @@ -3,6 +3,7 @@ package drand import ( + "bytes" "context" "os" "testing" @@ -18,7 +19,12 @@ import ( func TestPrintGroupInfo(t *testing.T) { server := build.DrandConfigs[build.DrandTestnet].Servers[0] - c, err := hclient.New(server, nil, nil) + chainInfo := build.DrandConfigs[build.DrandTestnet].ChainInfoJSON + + drandChain, err := dchain.InfoFromJSON(bytes.NewReader([]byte(chainInfo))) + assert.NoError(t, err) + c, err := hclient.NewWithInfo(server, drandChain, nil) + assert.NoError(t, err) cg := c.(interface { FetchChainInfo(ctx context.Context, groupHash []byte) (*dchain.Info, error) diff --git a/chain/checkpoint.go b/chain/checkpoint.go index f9b0bb4ebe1..766af95b42c 100644 --- a/chain/checkpoint.go +++ b/chain/checkpoint.go @@ -24,9 +24,16 @@ func (syncer *Syncer) SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) e ts = tss[0] } - if err := syncer.switchChain(ctx, ts); err != nil { - return xerrors.Errorf("failed to switch chain when syncing checkpoint: %w", err) - } + hts := syncer.ChainStore().GetHeaviestTipSet() + if !hts.Equals(ts) { + if anc, err := syncer.store.IsAncestorOf(ctx, ts, hts); err != nil { + return xerrors.Errorf("failed to walk the chain when checkpointing: %w", err) + } else if !anc { + if err := syncer.collectChain(ctx, ts, hts, true); err != nil { + return xerrors.Errorf("failed to collect chain for checkpoint: %w", err) + } + } // else new checkpoint is on the current chain, we definitely have the tipsets. + } // else current head, no need to switch. if err := syncer.ChainStore().SetCheckpoint(ctx, ts); err != nil { return xerrors.Errorf("failed to set the chain checkpoint: %w", err) @@ -34,24 +41,3 @@ func (syncer *Syncer) SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) e return nil } - -func (syncer *Syncer) switchChain(ctx context.Context, ts *types.TipSet) error { - hts := syncer.ChainStore().GetHeaviestTipSet() - if hts.Equals(ts) { - return nil - } - - if anc, err := syncer.store.IsAncestorOf(ctx, ts, hts); err == nil && anc { - return nil - } - - // Otherwise, sync the chain and set the head. - if err := syncer.collectChain(ctx, ts, hts, true); err != nil { - return xerrors.Errorf("failed to collect chain for checkpoint: %w", err) - } - - if err := syncer.ChainStore().SetHead(ctx, ts); err != nil { - return xerrors.Errorf("failed to set the chain head: %w", err) - } - return nil -} diff --git a/chain/consensus/common.go b/chain/consensus/common.go index a7e5c40d2b9..8fee0d4c2f1 100644 --- a/chain/consensus/common.go +++ b/chain/consensus/common.go @@ -220,7 +220,7 @@ func checkBlockMessages(ctx context.Context, sm *stmgr.StateManager, cs *store.C // the sender exists and is an account actor, and the nonces make sense var sender address.Address if nv >= network.Version13 { - sender, err = st.LookupID(m.From) + sender, err = st.LookupIDAddress(m.From) if err != nil { return xerrors.Errorf("failed to lookup sender %s: %w", m.From, err) } diff --git a/chain/consensus/filcns/filecoin.go b/chain/consensus/filcns/filecoin.go index 327c33c3558..8565f361358 100644 --- a/chain/consensus/filcns/filecoin.go +++ b/chain/consensus/filcns/filecoin.go @@ -150,7 +150,7 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock) return xerrors.Errorf("block was from the future (now=%d, blk=%d): %w", now, h.Timestamp, consensus.ErrTemporal) } if h.Timestamp > now { - log.Warn("Got block from the future, but within threshold", h.Timestamp, build.Clock.Now().Unix()) + log.Warnf("Got block from the future, but within threshold (%d > %d)", h.Timestamp, now) } minerCheck := async.Err(func() error { @@ -166,7 +166,7 @@ func (filec *FilecoinEC) ValidateBlock(ctx context.Context, b *types.FullBlock) } if types.BigCmp(pweight, b.Header.ParentWeight) != 0 { - return xerrors.Errorf("parrent weight different: %s (header) != %s (computed)", + return xerrors.Errorf("parent weight different: %s (header) != %s (computed)", b.Header.ParentWeight, pweight) } diff --git a/chain/consensus/filcns/upgrades.go b/chain/consensus/filcns/upgrades.go index 26c93a0f37e..eaa4f3b200d 100644 --- a/chain/consensus/filcns/upgrades.go +++ b/chain/consensus/filcns/upgrades.go @@ -81,7 +81,7 @@ func init() { return } // use value from environment - log.Infof("migration worker cound set from %s (%d)", EnvMigrationMaxWorkerCount, mwc) + log.Infof("migration worker count set from %s (%d)", EnvMigrationMaxWorkerCount, mwc) MigrationMaxWorkerCount = int(mwc) return } @@ -1712,14 +1712,14 @@ func upgradeActorsV10Common( if stateRoot.Version != types.StateTreeVersion4 { return cid.Undef, xerrors.Errorf( - "expected state root version 4 for actors v9 upgrade, got %d", + "expected state root version 4 for actors v10 upgrade, got %d", stateRoot.Version, ) } manifest, ok := actors.GetManifest(actorstypes.Version10) if !ok { - return cid.Undef, xerrors.Errorf("no manifest CID for v9 upgrade") + return cid.Undef, xerrors.Errorf("no manifest CID for v10 upgrade") } // Perform the migration @@ -1893,7 +1893,7 @@ func UpgradeActorsV12(ctx context.Context, sm *stmgr.StateManager, cache stmgr.M } newRoot, err := upgradeActorsV12Common(ctx, sm, cache, root, epoch, ts, config) if err != nil { - return cid.Undef, xerrors.Errorf("migrating actors v11 state: %w", err) + return cid.Undef, xerrors.Errorf("migrating actors v12 state: %w", err) } return newRoot, nil } @@ -2210,7 +2210,7 @@ func UpgradeActorsV13(ctx context.Context, sm *stmgr.StateManager, cache stmgr.M } newRoot, err := upgradeActorsV13Common(ctx, sm, cache, root, epoch, ts, config) if err != nil { - return cid.Undef, xerrors.Errorf("migrating actors v11 state: %w", err) + return cid.Undef, xerrors.Errorf("migrating actors v13 state: %w", err) } return newRoot, nil } diff --git a/chain/events/filter/event.go b/chain/events/filter/event.go index 1669d840eec..0accc551ab4 100644 --- a/chain/events/filter/event.go +++ b/chain/events/filter/event.go @@ -375,6 +375,10 @@ func (m *EventFilterManager) Revert(ctx context.Context, from, to *types.TipSet) func (m *EventFilterManager) Install(ctx context.Context, minHeight, maxHeight abi.ChainEpoch, tipsetCid cid.Cid, addresses []address.Address, keysWithCodec map[string][]types.ActorEventBlock, excludeReverted bool) (EventFilter, error) { m.mu.Lock() + if m.currentHeight == 0 { + // sync in progress, we haven't had an Apply + m.currentHeight = m.ChainStore.GetHeaviestTipSet().Height() + } currentHeight := m.currentHeight m.mu.Unlock() diff --git a/chain/events/filter/index.go b/chain/events/filter/index.go index 1ff8bb2c2f1..9a8f8bca4c5 100644 --- a/chain/events/filter/index.go +++ b/chain/events/filter/index.go @@ -26,7 +26,7 @@ var pragmas = []string{ "PRAGMA temp_store = memory", "PRAGMA mmap_size = 30000000000", "PRAGMA page_size = 32768", - "PRAGMA auto_vacuum = NONE", + "PRAGMA auto_vacuum = NONE", // not useful until we implement GC "PRAGMA automatic_index = OFF", "PRAGMA journal_mode = WAL", "PRAGMA read_uncommitted = ON", @@ -45,7 +45,10 @@ var ddls = []string{ reverted INTEGER NOT NULL )`, - `CREATE INDEX IF NOT EXISTS height_tipset_key ON event (height,tipset_key)`, + createIndexEventEmitterAddr, + createIndexEventTipsetKeyCid, + createIndexEventHeight, + createIndexEventReverted, `CREATE TABLE IF NOT EXISTS event_entry ( event_id INTEGER, @@ -56,13 +59,19 @@ var ddls = []string{ value BLOB NOT NULL )`, + createIndexEventEntryIndexedKey, + createIndexEventEntryCodecValue, + createIndexEventEntryEventId, + // metadata containing version of schema `CREATE TABLE IF NOT EXISTS _meta ( - version UINT64 NOT NULL UNIQUE + version UINT64 NOT NULL UNIQUE )`, `INSERT OR IGNORE INTO _meta (version) VALUES (1)`, `INSERT OR IGNORE INTO _meta (version) VALUES (2)`, + `INSERT OR IGNORE INTO _meta (version) VALUES (3)`, + `INSERT OR IGNORE INTO _meta (version) VALUES (4)`, } var ( @@ -70,13 +79,22 @@ var ( ) const ( - schemaVersion = 2 + schemaVersion = 4 eventExists = `SELECT MAX(id) FROM event WHERE height=? AND tipset_key=? AND tipset_key_cid=? AND emitter_addr=? AND event_index=? AND message_cid=? AND message_index=?` 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(?, ?, ?, ?, ?, ?)` revertEventsInTipset = `UPDATE event SET reverted=true WHERE height=? AND tipset_key=?` restoreEvent = `UPDATE event SET reverted=false WHERE height=? AND tipset_key=? AND tipset_key_cid=? AND emitter_addr=? AND event_index=? AND message_cid=? AND message_index=?` + + createIndexEventEmitterAddr = `CREATE INDEX IF NOT EXISTS event_emitter_addr ON event (emitter_addr)` + createIndexEventTipsetKeyCid = `CREATE INDEX IF NOT EXISTS event_tipset_key_cid ON event (tipset_key_cid);` + createIndexEventHeight = `CREATE INDEX IF NOT EXISTS event_height ON event (height);` + createIndexEventReverted = `CREATE INDEX IF NOT EXISTS event_reverted ON event (reverted);` + + createIndexEventEntryIndexedKey = `CREATE INDEX IF NOT EXISTS event_entry_indexed_key ON event_entry (indexed, key);` + createIndexEventEntryCodecValue = `CREATE INDEX IF NOT EXISTS event_entry_codec_value ON event_entry (codec, value);` + createIndexEventEntryEventId = `CREATE INDEX IF NOT EXISTS event_entry_event_id ON event_entry(event_id);` ) type EventIndex struct { @@ -121,43 +139,43 @@ func (ei *EventIndex) initStatements() (err error) { func (ei *EventIndex) migrateToVersion2(ctx context.Context, chainStore *store.ChainStore) error { now := time.Now() - tx, err := ei.db.Begin() + tx, err := ei.db.BeginTx(ctx, nil) if err != nil { return xerrors.Errorf("begin transaction: %w", err) } // rollback the transaction (a no-op if the transaction was already committed) - defer tx.Rollback() //nolint:errcheck + defer func() { _ = tx.Rollback() }() // create some temporary indices to help speed up the migration - _, err = tx.Exec("CREATE INDEX IF NOT EXISTS tmp_height_tipset_key_cid ON event (height,tipset_key_cid)") + _, err = tx.ExecContext(ctx, "CREATE INDEX IF NOT EXISTS tmp_height_tipset_key_cid ON event (height,tipset_key_cid)") if err != nil { return xerrors.Errorf("create index tmp_height_tipset_key_cid: %w", err) } - _, err = tx.Exec("CREATE INDEX IF NOT EXISTS tmp_tipset_key_cid ON event (tipset_key_cid)") + _, err = tx.ExecContext(ctx, "CREATE INDEX IF NOT EXISTS tmp_tipset_key_cid ON event (tipset_key_cid)") if err != nil { return xerrors.Errorf("create index tmp_tipset_key_cid: %w", err) } - stmtDeleteOffChainEvent, err := tx.Prepare("DELETE FROM event WHERE tipset_key_cid!=? and height=?") + stmtDeleteOffChainEvent, err := tx.PrepareContext(ctx, "DELETE FROM event WHERE tipset_key_cid!=? and height=?") if err != nil { return xerrors.Errorf("prepare stmtDeleteOffChainEvent: %w", err) } - stmtSelectEvent, err := tx.Prepare("SELECT id FROM event WHERE tipset_key_cid=? ORDER BY message_index ASC, event_index ASC, id DESC LIMIT 1") + stmtSelectEvent, err := tx.PrepareContext(ctx, "SELECT id FROM event WHERE tipset_key_cid=? ORDER BY message_index ASC, event_index ASC, id DESC LIMIT 1") if err != nil { return xerrors.Errorf("prepare stmtSelectEvent: %w", err) } - stmtDeleteEvent, err := tx.Prepare("DELETE FROM event WHERE tipset_key_cid=? AND id 0 { - subclauses := []string{} + subclauses := make([]string, 0, len(f.addresses)) for _, addr := range f.addresses { subclauses = append(subclauses, "emitter_addr=?") values = append(values, addr.Bytes()) @@ -523,7 +654,7 @@ func (ei *EventIndex) prefillFilter(ctx context.Context, f *eventFilter, exclude 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{} + subclauses := make([]string, 0, len(vals)) for _, val := range vals { subclauses = append(subclauses, fmt.Sprintf("(%s.value=? AND %[1]s.codec=?)", joinAlias)) values = append(values, val.Value, val.Codec) diff --git a/chain/events/state/predicates.go b/chain/events/state/predicates.go index e4e8b8f7e41..298f787ff93 100644 --- a/chain/events/state/predicates.go +++ b/chain/events/state/predicates.go @@ -369,7 +369,7 @@ func (sp *StatePredicates) OnMinerPreCommitChange() DiffMinerActorStateFunc { // DiffPaymentChannelStateFunc is function that compares two states for the payment channel type DiffPaymentChannelStateFunc func(ctx context.Context, oldState paych.State, newState paych.State) (changed bool, user UserData, err error) -// OnPaymentChannelActorChanged calls diffPaymentChannelState when the state changes for the the payment channel actor +// OnPaymentChannelActorChanged calls diffPaymentChannelState when the state changes for the payment channel actor func (sp *StatePredicates) OnPaymentChannelActorChanged(paychAddr address.Address, diffPaymentChannelState DiffPaymentChannelStateFunc) DiffTipSetKeyFunc { return sp.OnActorStateChanged(paychAddr, func(ctx context.Context, oldActorState, newActorState *types.Actor) (changed bool, user UserData, err error) { oldState, err := paych.Load(adt.WrapStore(ctx, sp.cst), oldActorState) diff --git a/chain/exchange/protocol.go b/chain/exchange/protocol.go index cd25f4a4350..7a22de8a3fa 100644 --- a/chain/exchange/protocol.go +++ b/chain/exchange/protocol.go @@ -38,6 +38,7 @@ const ( ReadResMinSpeed = 50 << 10 ShufflePeersPrefix = 16 WriteResDeadline = 60 * time.Second + streamReadDeadline = 10 * time.Second ) // FIXME: Rename. Make private. diff --git a/chain/exchange/server.go b/chain/exchange/server.go index 03dcf0ed79f..e8b2a414e69 100644 --- a/chain/exchange/server.go +++ b/chain/exchange/server.go @@ -40,11 +40,15 @@ func (s *server) HandleStream(stream inet.Stream) { defer stream.Close() //nolint:errcheck + _ = stream.SetReadDeadline(time.Now().Add(streamReadDeadline)) var req Request if err := cborutil.ReadCborRPC(bufio.NewReader(stream), &req); err != nil { + _ = stream.SetReadDeadline(time.Time{}) log.Warnf("failed to read block sync request: %s", err) return } + _ = stream.SetReadDeadline(time.Time{}) + log.Debugw("block sync request", "start", req.Head, "len", req.Length) @@ -137,7 +141,7 @@ func (s *server) serviceRequest(ctx context.Context, req *validatedRequest) (*Re chain, err := collectChainSegment(ctx, s.cs, req) if err != nil { - log.Warn("block sync request: collectChainSegment failed: ", err) + log.Info("block sync request: collectChainSegment failed: ", err) return &Response{ Status: InternalError, ErrorMessage: err.Error(), @@ -171,17 +175,11 @@ func collectChainSegment(ctx context.Context, cs *store.ChainStore, req *validat } if req.options.IncludeMessages { - bmsgs, bmincl, smsgs, smincl, err := gatherMessages(ctx, cs, ts) + bst.Messages, err = gatherMessages(ctx, cs, ts) if err != nil { return nil, xerrors.Errorf("gather messages failed: %w", err) } - // FIXME: Pass the response to `gatherMessages()` and set all this there. - bst.Messages = &CompactedMessages{} - bst.Messages.Bls = bmsgs - bst.Messages.BlsIncludes = bmincl - bst.Messages.Secpk = smsgs - bst.Messages.SecpkIncludes = smincl } bstips = append(bstips, &bst) @@ -196,16 +194,16 @@ func collectChainSegment(ctx context.Context, cs *store.ChainStore, req *validat } } -func gatherMessages(ctx context.Context, cs *store.ChainStore, ts *types.TipSet) ([]*types.Message, [][]uint64, []*types.SignedMessage, [][]uint64, error) { +func gatherMessages(ctx context.Context, cs *store.ChainStore, ts *types.TipSet) (*CompactedMessages, error) { + msgs := new(CompactedMessages) blsmsgmap := make(map[cid.Cid]uint64) secpkmsgmap := make(map[cid.Cid]uint64) - var secpkincl, blsincl [][]uint64 var blscids, secpkcids []cid.Cid for _, block := range ts.Blocks() { bc, sc, err := cs.ReadMsgMetaCids(ctx, block.Messages) if err != nil { - return nil, nil, nil, nil, err + return nil, err } // FIXME: DRY. Use `chain.Message` interface. @@ -220,7 +218,7 @@ func gatherMessages(ctx context.Context, cs *store.ChainStore, ts *types.TipSet) bmi = append(bmi, i) } - blsincl = append(blsincl, bmi) + msgs.BlsIncludes = append(msgs.BlsIncludes, bmi) smi := make([]uint64, 0, len(sc)) for _, m := range sc { @@ -233,18 +231,19 @@ func gatherMessages(ctx context.Context, cs *store.ChainStore, ts *types.TipSet) smi = append(smi, i) } - secpkincl = append(secpkincl, smi) + msgs.SecpkIncludes = append(msgs.SecpkIncludes, smi) } - blsmsgs, err := cs.LoadMessagesFromCids(ctx, blscids) + var err error + msgs.Bls, err = cs.LoadMessagesFromCids(ctx, blscids) if err != nil { - return nil, nil, nil, nil, err + return nil, err } - secpkmsgs, err := cs.LoadSignedMessagesFromCids(ctx, secpkcids) + msgs.Secpk, err = cs.LoadSignedMessagesFromCids(ctx, secpkcids) if err != nil { - return nil, nil, nil, nil, err + return nil, err } - return blsmsgs, blsincl, secpkmsgs, secpkincl, nil + return msgs, nil } diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 7d55b0b16f5..c8a2493faa6 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -778,9 +778,7 @@ func (mp *MessagePool) Add(ctx context.Context, m *types.SignedMessage) error { _, _ = mp.getStateNonce(ctx, m.Message.From, tmpCurTs) mp.curTsLk.Lock() - if tmpCurTs == mp.curTs { - //with the lock enabled, mp.curTs is the same Ts as we just had, so we know that our computations are cached - } else { + if tmpCurTs != mp.curTs { //curTs has been updated so we want to cache the new one: tmpCurTs = mp.curTs //we want to release the lock, cache the computations then grab it again @@ -789,7 +787,7 @@ func (mp *MessagePool) Add(ctx context.Context, m *types.SignedMessage) error { _, _ = mp.getStateNonce(ctx, m.Message.From, tmpCurTs) mp.curTsLk.Lock() //now that we have the lock, we continue, we could do this as a loop forever, but that's bad to loop forever, and this was added as an optimization and it seems once is enough because the computation < block time - } + } // else with the lock enabled, mp.curTs is the same Ts as we just had, so we know that our computations are cached defer mp.curTsLk.Unlock() diff --git a/chain/messagepool/provider.go b/chain/messagepool/provider.go index 764e6c13a92..8d1a971539a 100644 --- a/chain/messagepool/provider.go +++ b/chain/messagepool/provider.go @@ -5,6 +5,7 @@ import ( "errors" "time" + lru "github.com/hashicorp/golang-lru/v2" "github.com/ipfs/go-cid" pubsub "github.com/libp2p/go-libp2p-pubsub" "golang.org/x/xerrors" @@ -16,6 +17,8 @@ import ( "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/lib/must" + "github.com/filecoin-project/lotus/lib/result" ) var ( @@ -39,10 +42,19 @@ type Provider interface { IsLite() bool } +type actorCacheKey struct { + types.TipSetKey + address.Address +} + +var nonceCacheSize = 128 + type mpoolProvider struct { sm *stmgr.StateManager ps *pubsub.PubSub + liteActorCache *lru.Cache[actorCacheKey, result.Result[*types.Actor]] + lite MpoolNonceAPI } @@ -53,18 +65,31 @@ func NewProvider(sm *stmgr.StateManager, ps *pubsub.PubSub) Provider { } func NewProviderLite(sm *stmgr.StateManager, ps *pubsub.PubSub, noncer MpoolNonceAPI) Provider { - return &mpoolProvider{sm: sm, ps: ps, lite: noncer} + return &mpoolProvider{ + sm: sm, + ps: ps, + lite: noncer, + liteActorCache: must.One(lru.New[actorCacheKey, result.Result[*types.Actor]](nonceCacheSize)), + } } func (mpp *mpoolProvider) IsLite() bool { return mpp.lite != nil } -func (mpp *mpoolProvider) getActorLite(addr address.Address, ts *types.TipSet) (*types.Actor, error) { +func (mpp *mpoolProvider) getActorLite(addr address.Address, ts *types.TipSet) (act *types.Actor, err error) { if !mpp.IsLite() { return nil, errors.New("should not use getActorLite on non lite Provider") } + if c, ok := mpp.liteActorCache.Get(actorCacheKey{ts.Key(), addr}); ok { + return c.Unwrap() + } + + defer func() { + mpp.liteActorCache.Add(actorCacheKey{ts.Key(), addr}, result.Wrap(act, err)) + }() + n, err := mpp.lite.GetNonce(context.TODO(), addr, ts.Key()) if err != nil { return nil, xerrors.Errorf("getting nonce over lite: %w", err) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 163bd76f985..0d0ed3cbab2 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -400,7 +400,7 @@ tailLoop: continue tailLoop } - // the merge loop ended after processing all the chains and we we probably have still + // the merge loop ended after processing all the chains and we probably have still // gas to spare; end the loop. break } diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 17e0f34f4e0..5b46fadfbc6 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -1191,7 +1191,7 @@ func TestOptimalMessageSelection2(t *testing.T) { func TestOptimalMessageSelection3(t *testing.T) { //stm: @TOKEN_WALLET_NEW_001, @CHAIN_MEMPOOL_SELECT_001 - // this test uses 10 actors sending a block of messages to each other, with the the first + // this test uses 10 actors sending a block of messages to each other, with the first // actors paying higher gas premium than the subsequent actors. // We select with a low ticket quality; the chain dependent merging algorithm should pick // messages from the median actor from the start @@ -1321,7 +1321,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu mustAdd(t, mp, m) } - logging.SetLogLevel("messagepool", "error") + _ = logging.SetLogLevel("messagepool", "error") // 1. greedy selection gm, err := mp.selectMessagesGreedy(context.Background(), ts, ts) @@ -1414,7 +1414,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand, getPremium fu t.Logf("Average reward boost: %f", rewardBoost) t.Logf("Average best tq reward: %f", totalBestTQReward/runs/1e12) - logging.SetLogLevel("messagepool", "info") + _ = logging.SetLogLevel("messagepool", "info") return capacityBoost, rewardBoost, totalBestTQReward / runs / 1e12 } diff --git a/chain/messagesigner/messagesigner_consensus.go b/chain/messagesigner/messagesigner_consensus.go deleted file mode 100644 index 905bb71997a..00000000000 --- a/chain/messagesigner/messagesigner_consensus.go +++ /dev/null @@ -1,98 +0,0 @@ -package messagesigner - -import ( - "context" - - "github.com/google/uuid" - "github.com/ipfs/go-datastore" - "github.com/ipfs/go-datastore/namespace" - "github.com/libp2p/go-libp2p/core/peer" - "golang.org/x/xerrors" - - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/messagepool" - "github.com/filecoin-project/lotus/chain/types" - consensus "github.com/filecoin-project/lotus/lib/consensus/raft" - "github.com/filecoin-project/lotus/node/modules/dtypes" -) - -type MessageSignerConsensus struct { - MsgSigner - Consensus *consensus.Consensus -} - -func NewMessageSignerConsensus( - wallet api.Wallet, - mpool messagepool.MpoolNonceAPI, - ds dtypes.MetadataDS, - consensus *consensus.Consensus) *MessageSignerConsensus { - - ds = namespace.Wrap(ds, datastore.NewKey("/message-signer-consensus/")) - return &MessageSignerConsensus{ - MsgSigner: &MessageSigner{ - wallet: wallet, - mpool: mpool, - ds: ds, - }, - Consensus: consensus, - } -} - -func (ms *MessageSignerConsensus) IsLeader(ctx context.Context) bool { - return ms.Consensus.IsLeader(ctx) -} - -func (ms *MessageSignerConsensus) RedirectToLeader(ctx context.Context, method string, arg interface{}, ret interface{}) (bool, error) { - ok, err := ms.Consensus.RedirectToLeader(method, arg, ret.(*types.SignedMessage)) - if err != nil { - return ok, err - } - return ok, nil -} - -func (ms *MessageSignerConsensus) SignMessage( - ctx context.Context, - msg *types.Message, - spec *api.MessageSendSpec, - cb func(*types.SignedMessage) error) (*types.SignedMessage, error) { - - signedMsg, err := ms.MsgSigner.SignMessage(ctx, msg, spec, cb) - if err != nil { - return nil, err - } - - op := &consensus.ConsensusOp{ - Nonce: signedMsg.Message.Nonce, - Uuid: spec.MsgUuid, - Addr: signedMsg.Message.From, - SignedMsg: signedMsg, - } - err = ms.Consensus.Commit(ctx, op) - if err != nil { - return nil, err - } - - return signedMsg, nil -} - -func (ms *MessageSignerConsensus) GetSignedMessage(ctx context.Context, uuid uuid.UUID) (*types.SignedMessage, error) { - cstate, err := ms.Consensus.State(ctx) - if err != nil { - return nil, err - } - - //cstate := state.(Consensus.RaftState) - msg, ok := cstate.MsgUuids[uuid] - if !ok { - return nil, xerrors.Errorf("Msg with Uuid %s not available", uuid) - } - return msg, nil -} - -func (ms *MessageSignerConsensus) GetRaftState(ctx context.Context) (*consensus.RaftState, error) { - return ms.Consensus.State(ctx) -} - -func (ms *MessageSignerConsensus) Leader(ctx context.Context) (peer.ID, error) { - return ms.Consensus.Leader(ctx) -} diff --git a/chain/rand/rand.go b/chain/rand/rand.go index 40f9f593a03..f892d2aae1c 100644 --- a/chain/rand/rand.go +++ b/chain/rand/rand.go @@ -184,9 +184,8 @@ func (sr *stateRand) GetBeaconRandomness(ctx context.Context, filecoinEpoch abi. return sr.getBeaconRandomnessV3(ctx, filecoinEpoch) } else if nv == network.Version13 { return sr.getBeaconRandomnessV2(ctx, filecoinEpoch) - } else { - return sr.getBeaconRandomnessV1(ctx, filecoinEpoch) } + return sr.getBeaconRandomnessV1(ctx, filecoinEpoch) } func (sr *stateRand) DrawChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, filecoinEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) { diff --git a/chain/state/statetree.go b/chain/state/statetree.go index 1a6497d04b9..03cd98d95ad 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -230,7 +230,7 @@ func NewStateTree(cst cbor.IpldStore, ver types.StateTreeVersion) (*StateTree, e Store: cst, snaps: newStateSnaps(), } - s.lookupIDFun = s.lookupIDinternal + s.lookupIDFun = s.lookupInternalIDAddress return s, nil } @@ -302,13 +302,13 @@ func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) { Store: cst, snaps: newStateSnaps(), } - s.lookupIDFun = s.lookupIDinternal + s.lookupIDFun = s.lookupInternalIDAddress return s, nil } func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error { - iaddr, err := st.LookupID(addr) + iaddr, err := st.LookupIDAddress(addr) if err != nil { return xerrors.Errorf("ID lookup failed: %w", err) } @@ -318,7 +318,7 @@ func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error { return nil } -func (st *StateTree) lookupIDinternal(addr address.Address) (address.Address, error) { +func (st *StateTree) lookupInternalIDAddress(addr address.Address) (address.Address, error) { act, err := st.GetActor(init_.Address) if err != nil { return address.Undef, xerrors.Errorf("getting init actor: %w", err) @@ -339,8 +339,8 @@ func (st *StateTree) lookupIDinternal(addr address.Address) (address.Address, er return a, err } -// LookupID gets the ID address of this actor's `addr` stored in the `InitActor`. -func (st *StateTree) LookupID(addr address.Address) (address.Address, error) { +// LookupIDAddress gets the ID address of this actor's `addr` stored in the `InitActor`. +func (st *StateTree) LookupIDAddress(addr address.Address) (address.Address, error) { if addr.Protocol() == address.ID { return addr, nil } @@ -366,7 +366,7 @@ func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) { } // Transform `addr` to its ID format. - iaddr, err := st.LookupID(addr) + iaddr, err := st.LookupIDAddress(addr) if err != nil { if xerrors.Is(err, types.ErrActorNotFound) { return nil, xerrors.Errorf("resolution lookup failed (%s): %w", addr, err) @@ -411,7 +411,7 @@ func (st *StateTree) DeleteActor(addr address.Address) error { return xerrors.Errorf("DeleteActor called on undefined address") } - iaddr, err := st.LookupID(addr) + iaddr, err := st.LookupIDAddress(addr) if err != nil { if xerrors.Is(err, types.ErrActorNotFound) { return xerrors.Errorf("resolution lookup failed (%s): %w", addr, err) diff --git a/chain/stmgr/actors.go b/chain/stmgr/actors.go index f1d615e8d4f..0dce2c3cdf3 100644 --- a/chain/stmgr/actors.go +++ b/chain/stmgr/actors.go @@ -542,7 +542,7 @@ func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address, return api.MarketBalance{}, err } - addr, err = sm.LookupID(ctx, addr, ts) + addr, err = sm.LookupIDAddress(ctx, addr, ts) if err != nil { return api.MarketBalance{}, err } diff --git a/chain/stmgr/execute.go b/chain/stmgr/execute.go index bed8578338b..e716ed198df 100644 --- a/chain/stmgr/execute.go +++ b/chain/stmgr/execute.go @@ -13,6 +13,16 @@ import ( ) func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st cid.Cid, rec cid.Cid, err error) { + return sm.tipSetState(ctx, ts, false) +} + +// Recompute the tipset state without trying to lookup a pre-computed result in the chainstore. +// Useful if we know that our local chain-state isn't complete (e.g., we've discarded the events). +func (sm *StateManager) RecomputeTipSetState(ctx context.Context, ts *types.TipSet) (st cid.Cid, rec cid.Cid, err error) { + return sm.tipSetState(ctx, ts, true) +} + +func (sm *StateManager) tipSetState(ctx context.Context, ts *types.TipSet, recompute bool) (st cid.Cid, rec cid.Cid, err error) { ctx, span := trace.StartSpan(ctx, "tipSetState") defer span.End() if span.IsRecordingEvents() { @@ -65,8 +75,10 @@ func (sm *StateManager) TipSetState(ctx context.Context, ts *types.TipSet) (st c // First, try to find the tipset in the current chain. If found, we can avoid re-executing // it. - if st, rec, found := tryLookupTipsetState(ctx, sm.cs, ts); found { - return st, rec, nil + if !recompute { + if st, rec, found := tryLookupTipsetState(ctx, sm.cs, ts); found { + return st, rec, nil + } } st, rec, err = sm.tsExec.ExecuteTipSet(ctx, sm, ts, sm.tsExecMonitor, false) diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index 93f53c63ff0..9a236196187 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -178,18 +178,24 @@ func (sm *StateManager) HandleStateForks(ctx context.Context, root cid.Cid, heig retCid := root u := sm.stateMigrations[height] if u != nil && u.upgrade != nil { - if height != build.UpgradeWatermelonFixHeight { - migCid, ok, err := u.migrationResultCache.Get(ctx, root) - if err == nil { - if ok { - log.Infow("CACHED migration", "height", height, "from", root, "to", migCid) + migCid, ok, err := u.migrationResultCache.Get(ctx, root) + if err == nil { + if ok { + log.Infow("CACHED migration", "height", height, "from", root, "to", migCid) + foundMigratedRoot, err := sm.ChainStore().StateBlockstore().Has(ctx, migCid) + if err != nil { + log.Errorw("failed to check whether previous migration result is present", "err", err) + } else if !foundMigratedRoot { + log.Errorw("cached migration result not found in blockstore, running migration again") + u.migrationResultCache.Delete(ctx, root) + } else { return migCid, nil } - } else if !errors.Is(err, datastore.ErrNotFound) { - log.Errorw("failed to lookup previous migration result", "err", err) - } else { - log.Debug("no cached migration found, migrating from scratch") } + } else if !errors.Is(err, datastore.ErrNotFound) { + log.Errorw("failed to lookup previous migration result", "err", err) + } else { + log.Debug("no cached migration found, migrating from scratch") } startTime := time.Now() @@ -197,7 +203,6 @@ func (sm *StateManager) HandleStateForks(ctx context.Context, root cid.Cid, heig // Yes, we clone the cache, even for the final upgrade epoch. Why? Reverts. We may // have to migrate multiple times. tmpCache := u.cache.Clone() - var err error retCid, err = u.upgrade(ctx, sm, tmpCache, cb, root, height, ts) if err != nil { log.Errorw("FAILED migration", "height", height, "from", root, "error", err) diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index bf8793488b6..8c022755371 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -375,6 +375,20 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) { } func TestForkPreMigration(t *testing.T) { + // Backup the original value of the DISABLE_PRE_MIGRATIONS environment variable + originalValue, _ := os.LookupEnv("LOTUS_DISABLE_PRE_MIGRATIONS") + + // Unset the DISABLE_PRE_MIGRATIONS environment variable for the test + if err := os.Unsetenv("LOTUS_DISABLE_PRE_MIGRATIONS"); err != nil { + t.Fatalf("failed to unset LOTUS_DISABLE_PRE_MIGRATIONS: %v", err) + } + + // Restore the original DISABLE_PRE_MIGRATIONS environment variable at the end of the test + defer func() { + if err := os.Setenv("LOTUS_DISABLE_PRE_MIGRATIONS", originalValue); err != nil { + t.Fatalf("failed to restore LOTUS_DISABLE_PRE_MIGRATIONS: %v", err) + } + }() //stm: @CHAIN_GEN_NEXT_TIPSET_001, //stm: @CHAIN_STATE_RESOLVE_TO_KEY_ADDR_001, @CHAIN_STATE_SET_VM_CONSTRUCTOR_001 logging.SetAllLoggers(logging.LevelInfo) diff --git a/chain/stmgr/rpc/rpcstatemanager.go b/chain/stmgr/rpc/rpcstatemanager.go index 9186501eab9..fa311e1d4b9 100644 --- a/chain/stmgr/rpc/rpcstatemanager.go +++ b/chain/stmgr/rpc/rpcstatemanager.go @@ -44,7 +44,7 @@ func (s *RPCStateManager) LoadActorTsk(ctx context.Context, addr address.Address return s.gapi.StateGetActor(ctx, addr, tsk) } -func (s *RPCStateManager) LookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { +func (s *RPCStateManager) LookupIDAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { return s.gapi.StateLookupID(ctx, addr, ts.Key()) } diff --git a/chain/stmgr/searchwait.go b/chain/stmgr/searchwait.go index 356ace23c45..3377389b9b6 100644 --- a/chain/stmgr/searchwait.go +++ b/chain/stmgr/searchwait.go @@ -243,7 +243,7 @@ func (sm *StateManager) searchBackForMsg(ctx context.Context, from *types.TipSet return nil, nil, cid.Undef, xerrors.Errorf("failed to load initital tipset") } - mFromId, err := sm.LookupID(ctx, m.VMMessage().From, from) + mFromId, err := sm.LookupIDAddress(ctx, m.VMMessage().From, from) if err != nil { return nil, nil, cid.Undef, xerrors.Errorf("looking up From id address: %w", err) } diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 49913e442d1..d88d7dfd154 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -49,7 +49,7 @@ type StateManagerAPI interface { Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) 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) + LookupIDAddress(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) } @@ -113,6 +113,10 @@ func (m *migrationResultCache) Store(ctx context.Context, root cid.Cid, resultCi return nil } +func (m *migrationResultCache) Delete(ctx context.Context, root cid.Cid) { + _ = m.ds.Delete(ctx, m.keyForMigration(root)) +} + type Executor interface { NewActorRegistry() *vm.ActorRegistry ExecuteTipSet(ctx context.Context, sm *StateManager, ts *types.TipSet, em ExecMonitor, vmTracing bool) (stateroot cid.Cid, rectsroot cid.Cid, err error) @@ -396,13 +400,30 @@ func (sm *StateManager) GetBlsPublicKey(ctx context.Context, addr address.Addres return kaddr.Payload(), nil } -func (sm *StateManager) LookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { +func (sm *StateManager) LookupIDAddress(_ context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { + // Check for the fast route first to avoid unnecessary CBOR store instantiation and state tree load. + if addr.Protocol() == address.ID { + return addr, nil + } + cst := cbor.NewCborStore(sm.cs.StateBlockstore()) state, err := state.LoadStateTree(cst, sm.parentState(ts)) if err != nil { return address.Undef, xerrors.Errorf("load state tree: %w", err) } - return state.LookupID(addr) + return state.LookupIDAddress(addr) +} + +func (sm *StateManager) LookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (abi.ActorID, error) { + idAddr, err := sm.LookupIDAddress(ctx, addr, ts) + if err != nil { + return 0, xerrors.Errorf("state manager lookup id: %w", err) + } + id, err := address.IDFromAddress(idAddr) + if err != nil { + return 0, xerrors.Errorf("resolve actor id: id from addr: %w", err) + } + return abi.ActorID(id), nil } func (sm *StateManager) LookupRobustAddress(ctx context.Context, idAddr address.Address, ts *types.TipSet) (address.Address, error) { diff --git a/chain/stmgr/supply.go b/chain/stmgr/supply.go index 9486cb93622..1aea5cc65a4 100644 --- a/chain/stmgr/supply.go +++ b/chain/stmgr/supply.go @@ -193,7 +193,7 @@ func (sm *StateManager) setupPostCalicoVesting(ctx context.Context) error { return nil } -// GetVestedFunds returns all funds that have "left" actors that are in the genesis state: +// GetFilVested returns all funds that have "left" actors that are in the genesis state: // - For Multisigs, it counts the actual amounts that have vested at the given epoch // - For Accounts, it counts max(currentBalance - genesisBalance, 0). func (sm *StateManager) GetFilVested(ctx context.Context, height abi.ChainEpoch) (abi.TokenAmount, error) { diff --git a/chain/store/checkpoint_test.go b/chain/store/checkpoint_test.go index c5dff94a831..8b775d334a0 100644 --- a/chain/store/checkpoint_test.go +++ b/chain/store/checkpoint_test.go @@ -44,23 +44,15 @@ func TestChainCheckpoint(t *testing.T) { head := cs.GetHeaviestTipSet() require.True(t, head.Equals(checkpointParents)) - // Try to set the checkpoint in the future, it should fail. + // Checkpoint into the future. err = cs.SetCheckpoint(ctx, checkpoint) - require.Error(t, err) - - // Then move the head back. - err = cs.SetHead(ctx, checkpoint) require.NoError(t, err) - // Verify it worked. + // And verify that it worked. head = cs.GetHeaviestTipSet() require.True(t, head.Equals(checkpoint)) - // And checkpoint it. - err = cs.SetCheckpoint(ctx, checkpoint) - require.NoError(t, err) - - // Let the second miner miner mine a fork + // Let the second miner mine a fork last = checkpointParents for i := 0; i < 4; i++ { ts, err := cg.NextTipSetFromMiners(last, cg.Miners[1:], 0) @@ -85,11 +77,10 @@ func TestChainCheckpoint(t *testing.T) { head = cs.GetHeaviestTipSet() require.True(t, head.Equals(last)) - // Setting a checkpoint on the other fork should fail. + // We should switch back if we checkpoint again. err = cs.SetCheckpoint(ctx, checkpoint) - require.Error(t, err) - - // Setting a checkpoint on this fork should succeed. - err = cs.SetCheckpoint(ctx, checkpointParents) require.NoError(t, err) + + head = cs.GetHeaviestTipSet() + require.True(t, head.Equals(checkpoint)) } diff --git a/chain/store/messages.go b/chain/store/messages.go index c23f900d7cb..4129a9199a5 100644 --- a/chain/store/messages.go +++ b/chain/store/messages.go @@ -119,7 +119,7 @@ func (cs *ChainStore) BlockMsgsForTipset(ctx context.Context, ts *types.TipSet) var sender address.Address if ts.Height() >= build.UpgradeHyperdriveHeight { if useIds { - sender, err = st.LookupID(m.From) + sender, err = st.LookupIDAddress(m.From) if err != nil { return false, xerrors.Errorf("failed to resolve sender: %w", err) } @@ -131,14 +131,14 @@ func (cs *ChainStore) BlockMsgsForTipset(ctx context.Context, ts *types.TipSet) // uh-oh, we actually have an ID-sender! useIds = true for robust, nonce := range applied { - resolved, err := st.LookupID(robust) + resolved, err := st.LookupIDAddress(robust) if err != nil { return false, xerrors.Errorf("failed to resolve sender: %w", err) } applied[resolved] = nonce } - sender, err = st.LookupID(m.From) + sender, err = st.LookupIDAddress(m.From) if err != nil { return false, xerrors.Errorf("failed to resolve sender: %w", err) } diff --git a/chain/store/snapshot.go b/chain/store/snapshot.go index de2190c5d7a..ca483c2ef17 100644 --- a/chain/store/snapshot.go +++ b/chain/store/snapshot.go @@ -392,7 +392,7 @@ func (s *walkScheduler) Wait() error { log.Errorw("error writing to CAR file", "error", err) return errWrite } - s.workerTasks.Close() //nolint:errcheck + _ = s.workerTasks.Close() return err } diff --git a/chain/store/store.go b/chain/store/store.go index f2826fc2ff0..9c8c2b2a1e3 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -305,6 +305,7 @@ func (cs *ChainStore) SubHeadChanges(ctx context.Context) chan []*api.HeadChange // Unsubscribe. cs.bestTips.Unsub(subch) + // revive:disable-next-line:empty-block // Drain the channel. for range subch { } @@ -752,7 +753,7 @@ func FlushValidationCache(ctx context.Context, ds dstore.Batching) error { for _, k := range allKeys { if strings.HasPrefix(k.Key, blockValidationCacheKeyPrefix.String()) { delCnt++ - batch.Delete(ctx, dstore.RawKey(k.Key)) // nolint:errcheck + _ = batch.Delete(ctx, dstore.RawKey(k.Key)) } } @@ -793,9 +794,12 @@ func (cs *ChainStore) removeCheckpoint(ctx context.Context) error { return nil } -// SetCheckpoint will set a checkpoint past which the chainstore will not allow forks. +// SetCheckpoint will set a checkpoint past which the chainstore will not allow forks. If the new +// checkpoint is not an ancestor of the current head, head will be set to the new checkpoint. // -// NOTE: Checkpoints cannot be set beyond ForkLengthThreshold epochs in the past. +// NOTE: Checkpoints cannot be set beyond ForkLengthThreshold epochs in the past, but can be set +// arbitrarily far into the future. +// NOTE: The new checkpoint must already be synced. func (cs *ChainStore) SetCheckpoint(ctx context.Context, ts *types.TipSet) error { tskBytes, err := json.Marshal(ts.Key()) if err != nil { @@ -805,10 +809,6 @@ func (cs *ChainStore) SetCheckpoint(ctx context.Context, ts *types.TipSet) error cs.heaviestLk.Lock() defer cs.heaviestLk.Unlock() - if ts.Height() > cs.heaviest.Height() { - return xerrors.Errorf("cannot set a checkpoint in the future") - } - // Otherwise, this operation could get _very_ expensive. if cs.heaviest.Height()-ts.Height() > build.ForkLengthThreshold { return xerrors.Errorf("cannot set a checkpoint before the fork threshold") @@ -821,7 +821,9 @@ func (cs *ChainStore) SetCheckpoint(ctx context.Context, ts *types.TipSet) error } if !anc { - return xerrors.Errorf("cannot mark tipset as checkpoint, since it isn't in the main-chain: %w", err) + if err := cs.takeHeaviestTipSet(ctx, ts); err != nil { + return xerrors.Errorf("failed to switch chains when setting checkpoint: %w", err) + } } } err = cs.metadataDs.Put(ctx, checkpointKey, tskBytes) diff --git a/chain/sub/ratelimit/window.go b/chain/sub/ratelimit/window.go index 0756e8998bb..8350b109eb1 100644 --- a/chain/sub/ratelimit/window.go +++ b/chain/sub/ratelimit/window.go @@ -24,7 +24,7 @@ func NewWindow(capacity int, size time.Duration) *Window { } // Add attempts to append a new timestamp into the current window. Previously -// added values that are not not within `size` difference from the value being +// added values that are not within `size` difference from the value being // added are first removed. Add fails if adding the value would cause the // window to exceed capacity. func (w *Window) Add() error { diff --git a/chain/sync_manager.go b/chain/sync_manager.go index 3369c3b5a0d..2f54ac8bb7e 100644 --- a/chain/sync_manager.go +++ b/chain/sync_manager.go @@ -357,7 +357,7 @@ func (sm *syncManager) selectInitialSyncTarget() (*types.TipSet, error) { return buckets.Heaviest(), nil } -// adds a tipset to the potential sync targets; returns true if there is a a tipset to work on. +// adds a tipset to the potential sync targets; returns true if there is a tipset to work on. // this could be either a restart, eg because there is no currently scheduled sync work or a worker // failed or a potential fork. func (sm *syncManager) addSyncTarget(ts *types.TipSet) (*types.TipSet, bool, error) { diff --git a/chain/sync_test.go b/chain/sync_test.go index be775960319..1b556f87952 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -85,7 +85,7 @@ type syncTestUtil struct { } func prepSyncTest(t testing.TB, h int) *syncTestUtil { - logging.SetLogLevel("*", "INFO") + _ = logging.SetLogLevel("*", "INFO") g, err := gen.NewGenerator() if err != nil { @@ -115,7 +115,7 @@ func prepSyncTest(t testing.TB, h int) *syncTestUtil { } func prepSyncTestWithV5Height(t testing.TB, h int, v5height abi.ChainEpoch) *syncTestUtil { - logging.SetLogLevel("*", "INFO") + _ = logging.SetLogLevel("*", "INFO") sched := stmgr.UpgradeSchedule{{ // prepare for upgrade. @@ -1204,7 +1204,7 @@ func TestSyncManualBadTS(t *testing.T) { tu.compareSourceState(client) } -// TestState tests fetching the sync worker state before, during & after the sync +// TestSyncState tests fetching the sync worker state before, during & after the sync func TestSyncState(t *testing.T) { H := 50 tu := prepSyncTest(t, H) diff --git a/chain/types/ethtypes/eth_types.go b/chain/types/ethtypes/eth_types.go index b658b885620..893c0721c85 100644 --- a/chain/types/ethtypes/eth_types.go +++ b/chain/types/ethtypes/eth_types.go @@ -197,7 +197,7 @@ func init() { } } -func NewEthBlock(hasTransactions bool) EthBlock { +func NewEthBlock(hasTransactions bool, tipsetLen int) 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, @@ -208,7 +208,7 @@ func NewEthBlock(hasTransactions bool) EthBlock { Extradata: []byte{}, MixHash: EmptyEthHash, Nonce: EmptyEthNonce, - GasLimit: EthUint64(build.BlockGasLimit), // TODO we map Ethereum blocks to Filecoin tipsets; this is inconsistent. + GasLimit: EthUint64(build.BlockGasLimit * int64(tipsetLen)), Uncles: []EthHash{}, Transactions: []interface{}{}, } @@ -229,13 +229,25 @@ type EthCall struct { } func (c *EthCall) UnmarshalJSON(b []byte) error { - type TempEthCall EthCall - var params TempEthCall + type EthCallRaw EthCall // Avoid a recursive call. + type EthCallDecode struct { + // The field should be "input" by spec, but many clients use "data" so we support + // both, but prefer "input". + Input *EthBytes `json:"input"` + EthCallRaw + } + var params EthCallDecode if err := json.Unmarshal(b, ¶ms); err != nil { return err } - *c = EthCall(params) + + // If input is specified, prefer it. + if params.Input != nil { + params.Data = *params.Input + } + + *c = EthCall(params.EthCallRaw) return nil } @@ -915,7 +927,7 @@ func NewEthBlockNumberOrHashFromNumber(number EthUint64) EthBlockNumberOrHash { func NewEthBlockNumberOrHashFromHexString(str string) (EthBlockNumberOrHash, error) { // check if block param is a number (decimal or hex) - var num EthUint64 = 0 + var num EthUint64 err := num.UnmarshalJSON([]byte(str)) if err != nil { return NewEthBlockNumberOrHashFromNumber(0), err diff --git a/chain/types/ethtypes/eth_types_test.go b/chain/types/ethtypes/eth_types_test.go index 4a73184c2a9..2a1b2df55e2 100644 --- a/chain/types/ethtypes/eth_types_test.go +++ b/chain/types/ethtypes/eth_types_test.go @@ -194,11 +194,40 @@ func TestMaskedIDInF4(t *testing.T) { } func TestUnmarshalEthCall(t *testing.T) { - data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":""}` + data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":"0xFF"}` var c EthCall err := c.UnmarshalJSON([]byte(data)) require.Nil(t, err) + require.EqualValues(t, []byte{0xff}, c.Data) +} + +func TestUnmarshalEthCallInput(t *testing.T) { + data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","input":"0xFF"}` + + var c EthCall + err := c.UnmarshalJSON([]byte(data)) + require.Nil(t, err) + require.EqualValues(t, []byte{0xff}, c.Data) +} + +func TestUnmarshalEthCallInputAndData(t *testing.T) { + data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":"0xFE","input":"0xFF"}` + + var c EthCall + err := c.UnmarshalJSON([]byte(data)) + require.Nil(t, err) + require.EqualValues(t, []byte{0xff}, c.Data) +} + +func TestUnmarshalEthCallInputAndDataEmpty(t *testing.T) { + // Even if the input is empty, it should be used when specified. + data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":"0xFE","input":""}` + + var c EthCall + err := c.UnmarshalJSON([]byte(data)) + require.Nil(t, err) + require.EqualValues(t, []byte{}, c.Data) } func TestUnmarshalEthBytes(t *testing.T) { diff --git a/chain/types/fil.go b/chain/types/fil.go index 2a0ccb46004..960a42f2879 100644 --- a/chain/types/fil.go +++ b/chain/types/fil.go @@ -6,6 +6,8 @@ import ( "math/big" "strings" + "github.com/invopop/jsonschema" + "github.com/filecoin-project/lotus/build" ) @@ -77,6 +79,10 @@ func (f FIL) MarshalText() (text []byte, err error) { } func (f FIL) UnmarshalText(text []byte) error { + if f.Int == nil { + return fmt.Errorf("cannot unmarshal into nil BigInt (text:%s)", string(text)) + } + p, err := ParseFIL(string(text)) if err != nil { return err @@ -134,5 +140,12 @@ func MustParseFIL(s string) FIL { return n } +func (f FIL) JSONSchema() *jsonschema.Schema { + return &jsonschema.Schema{ + Type: "string", + Pattern: `^((\d+(\.\d+)?|0x[0-9a-fA-F]+))( ([aA]([tT][tT][oO])?)?[fF][iI][lL])?$`, + } +} + var _ encoding.TextMarshaler = (*FIL)(nil) var _ encoding.TextUnmarshaler = (*FIL)(nil) diff --git a/chain/types/tipset_key_test.go b/chain/types/tipset_key_test.go index 5fbecb3ea7d..d7a933b54a2 100644 --- a/chain/types/tipset_key_test.go +++ b/chain/types/tipset_key_test.go @@ -18,10 +18,10 @@ import ( func TestTipSetKey(t *testing.T) { //stm: @TYPES_TIPSETKEY_FROM_BYTES_001, @TYPES_TIPSETKEY_NEW_001 cb := cid.V1Builder{Codec: cid.DagCBOR, MhType: multihash.BLAKE2B_MIN + 31} + // distinct, but arbitrary CIDs, pretending dag-cbor encoding but they are just a multihash over bytes c1, _ := cb.Sum([]byte("a")) c2, _ := cb.Sum([]byte("b")) c3, _ := cb.Sum([]byte("c")) - fmt.Println(len(c1.Bytes())) t.Run("zero value", func(t *testing.T) { assert.Equal(t, EmptyTSK, NewTipSetKey()) @@ -36,6 +36,22 @@ func TestTipSetKey(t *testing.T) { assert.Equal(t, []cid.Cid{c1, c1}, NewTipSetKey(c1, c1).Cids()) }) + t.Run("derived CID", func(t *testing.T) { + assert.Equal(t, "bafy2bzacecesrkxghscnq7vatble2hqdvwat6ed23vdu4vvo3uuggsoaya7ki", c1.String()) // sanity check + actualCid, err := NewTipSetKey().Cid() + require.NoError(t, err) + assert.Equal(t, "bafy2bzacea456askyutsf7uk4ta2q5aojrlcji4mhaqokbfalgvoq4ueeh4l2", actualCid.String(), "empty TSK") + actualCid, err = NewTipSetKey(c1).Cid() + require.NoError(t, err) + assert.Equal(t, "bafy2bzacealem6larzxhf7aggj3cozcefqez3jlksx2tuxehwdil27otcmy4q", actualCid.String()) + actualCid, err = NewTipSetKey(c1, c2, c3).Cid() + require.NoError(t, err) + assert.Equal(t, "bafy2bzacecbnwngwfvxuciumcfudiaoqozisp3hus5im5lg4urrwlxbueissu", actualCid.String()) + + // The key doesn't check for duplicates. + assert.Equal(t, []cid.Cid{c1, c1}, NewTipSetKey(c1, c1).Cids()) + }) + t.Run("equality", func(t *testing.T) { assert.Equal(t, NewTipSetKey(), NewTipSetKey()) assert.Equal(t, NewTipSetKey(c1), NewTipSetKey(c1)) diff --git a/chain/vm/execution.go b/chain/vm/execution.go index ea3a9719341..4fb626f4390 100644 --- a/chain/vm/execution.go +++ b/chain/vm/execution.go @@ -41,14 +41,14 @@ func newVMExecutor(vmi Interface, lane ExecutionLane) Interface { } func (e *vmExecutor) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, error) { - token := execution.getToken(e.lane) + token := execution.getToken(ctx, e.lane) defer token.Done() return e.vmi.ApplyMessage(ctx, cmsg) } func (e *vmExecutor) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*ApplyRet, error) { - token := execution.getToken(e.lane) + token := execution.getToken(ctx, e.lane) defer token.Done() return e.vmi.ApplyImplicitMessage(ctx, msg) @@ -61,6 +61,7 @@ func (e *vmExecutor) Flush(ctx context.Context) (cid.Cid, error) { type executionToken struct { lane ExecutionLane reserved int + ctx context.Context } func (token *executionToken) Done() { @@ -77,78 +78,69 @@ type executionEnv struct { reserved int } -func (e *executionEnv) getToken(lane ExecutionLane) *executionToken { - metricsUp(metrics.VMExecutionWaiting, lane) - defer metricsDown(metrics.VMExecutionWaiting, lane) +func (e *executionEnv) getToken(ctx context.Context, lane ExecutionLane) *executionToken { + metricsUp(ctx, metrics.VMExecutionWaiting, lane) + defer metricsDown(ctx, metrics.VMExecutionWaiting, lane) e.mx.Lock() - defer e.mx.Unlock() - switch lane { - case ExecutionLaneDefault: + reserving := 0 + if lane == ExecutionLaneDefault { for e.available <= e.reserved { e.cond.Wait() } - e.available-- - - metricsUp(metrics.VMExecutionRunning, lane) - return &executionToken{lane: lane, reserved: 0} - - case ExecutionLanePriority: + } else { for e.available == 0 { e.cond.Wait() } - - e.available-- - - reserving := 0 if e.reserved > 0 { e.reserved-- reserving = 1 } + } - metricsUp(metrics.VMExecutionRunning, lane) - return &executionToken{lane: lane, reserved: reserving} + e.available-- + e.mx.Unlock() - default: - // already checked at interface boundary in NewVM, so this is appropriate - panic("bogus execution lane") - } + metricsUp(ctx, metrics.VMExecutionRunning, lane) + return &executionToken{lane: lane, reserved: reserving, ctx: ctx} } func (e *executionEnv) putToken(token *executionToken) { e.mx.Lock() - defer e.mx.Unlock() e.available++ e.reserved += token.reserved // Note: Signal is unsound, because a priority token could wake up a non-priority - // goroutnie and lead to deadlock. So Broadcast it must be. + // goroutine and lead to deadlock. So Broadcast it must be. e.cond.Broadcast() + e.mx.Unlock() - metricsDown(metrics.VMExecutionRunning, token.lane) + metricsDown(token.ctx, metrics.VMExecutionRunning, token.lane) } -func metricsUp(metric *stats.Int64Measure, lane ExecutionLane) { - metricsAdjust(metric, lane, 1) +func metricsUp(ctx context.Context, metric *stats.Int64Measure, lane ExecutionLane) { + metricsAdjust(ctx, metric, lane, 1) } -func metricsDown(metric *stats.Int64Measure, lane ExecutionLane) { - metricsAdjust(metric, lane, -1) +func metricsDown(ctx context.Context, metric *stats.Int64Measure, lane ExecutionLane) { + metricsAdjust(ctx, metric, lane, -1) } -func metricsAdjust(metric *stats.Int64Measure, lane ExecutionLane, delta int) { - laneName := "default" +var ( + defaultLaneTag = tag.Upsert(metrics.ExecutionLane, "default") + priorityLaneTag = tag.Upsert(metrics.ExecutionLane, "priority") +) + +func metricsAdjust(ctx context.Context, metric *stats.Int64Measure, lane ExecutionLane, delta int) { + laneTag := defaultLaneTag if lane > ExecutionLaneDefault { - laneName = "priority" + laneTag = priorityLaneTag } - ctx, _ := tag.New( - context.Background(), - tag.Upsert(metrics.ExecutionLane, laneName), - ) + ctx, _ = tag.New(ctx, laneTag) stats.Record(ctx, metric.M(int64(delta))) } diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 355fcea2b09..9ca4f55d065 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -111,7 +111,7 @@ func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount { } func (rt *Runtime) ResolveAddress(addr address.Address) (ret address.Address, ok bool) { - r, err := rt.state.LookupID(addr) + r, err := rt.state.LookupIDAddress(addr) if err != nil { if xerrors.Is(err, types.ErrActorNotFound) { return address.Undef, false diff --git a/chain/vm/vm.go b/chain/vm/vm.go index ba404ab1fa3..f8a0c389216 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -336,9 +336,7 @@ func (vm *LegacyVM) send(ctx context.Context, msg *types.Message, parent *Runtim return nil, aerrors.Wrapf(err, "could not create account") } toActor = a - if vm.networkVersion <= network.Version3 { - // Leave the rt.Message as is - } else { + if vm.networkVersion > network.Version3 { nmsg := Message{ msg: types.Message{ To: aid, @@ -346,9 +344,8 @@ func (vm *LegacyVM) send(ctx context.Context, msg *types.Message, parent *Runtim Value: rt.Message.ValueReceived(), }, } - rt.Message = &nmsg - } + } // else leave the rt.Message as is } else { return nil, aerrors.Escalate(err, "getting actor") } @@ -902,7 +899,7 @@ func (vm *LegacyVM) transfer(from, to address.Address, amt types.BigInt, network return aerrors.Newf(exitcode.SysErrForbidden, "attempted to transfer negative value: %s", amt) } - fromID, err = vm.cstate.LookupID(from) + fromID, err = vm.cstate.LookupIDAddress(from) if err != nil { return aerrors.Fatalf("transfer failed when resolving sender address: %s", err) } @@ -921,7 +918,7 @@ func (vm *LegacyVM) transfer(from, to address.Address, amt types.BigInt, network return nil } - toID, err = vm.cstate.LookupID(to) + toID, err = vm.cstate.LookupIDAddress(to) if err != nil { return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err) } @@ -935,12 +932,12 @@ func (vm *LegacyVM) transfer(from, to address.Address, amt types.BigInt, network return nil } - fromID, err = vm.cstate.LookupID(from) + fromID, err = vm.cstate.LookupIDAddress(from) if err != nil { return aerrors.Fatalf("transfer failed when resolving sender address: %s", err) } - toID, err = vm.cstate.LookupID(to) + toID, err = vm.cstate.LookupIDAddress(to) if err != nil { return aerrors.Fatalf("transfer failed when resolving receiver address: %s", err) } diff --git a/chain/wallet/ledger/ledger.go b/chain/wallet/ledger/ledger.go index 5279389de81..5bd218b501f 100644 --- a/chain/wallet/ledger/ledger.go +++ b/chain/wallet/ledger/ledger.go @@ -10,7 +10,7 @@ import ( "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/query" logging "github.com/ipfs/go-log/v2" - ledgerfil "github.com/whyrusleeping/ledger-filecoin-go" + ledgerfil "github.com/zondax/ledger-filecoin-go" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" diff --git a/cli/backup.go b/cli/backup.go index d2d8f25ff89..e0495678cfd 100644 --- a/cli/backup.go +++ b/cli/backup.go @@ -24,7 +24,7 @@ type BackupApiFn func(ctx *cli.Context) (BackupAPI, jsonrpc.ClientCloser, error) func BackupCmd(repoFlag string, rt repo.RepoType, getApi BackupApiFn) *cli.Command { var offlineBackup = func(cctx *cli.Context) error { - logging.SetLogLevel("badger", "ERROR") // nolint:errcheck + _ = logging.SetLogLevel("badger", "ERROR") repoPath := cctx.String(repoFlag) r, err := repo.NewFS(repoPath) diff --git a/cli/clicommands/cmd.go b/cli/clicommands/cmd.go new file mode 100644 index 00000000000..a37ce329acc --- /dev/null +++ b/cli/clicommands/cmd.go @@ -0,0 +1,30 @@ +package clicommands + +import ( + "github.com/urfave/cli/v2" + + lcli "github.com/filecoin-project/lotus/cli" +) + +var Commands = []*cli.Command{ + lcli.WithCategory("basic", lcli.SendCmd), + lcli.WithCategory("basic", lcli.WalletCmd), + lcli.WithCategory("basic", lcli.InfoCmd), + lcli.WithCategory("basic", lcli.ClientCmd), + lcli.WithCategory("basic", lcli.MultisigCmd), + lcli.WithCategory("basic", lcli.FilplusCmd), + lcli.WithCategory("basic", lcli.PaychCmd), + lcli.WithCategory("developer", lcli.AuthCmd), + lcli.WithCategory("developer", lcli.MpoolCmd), + lcli.WithCategory("developer", StateCmd), + lcli.WithCategory("developer", lcli.ChainCmd), + lcli.WithCategory("developer", lcli.LogCmd), + lcli.WithCategory("developer", lcli.WaitApiCmd), + lcli.WithCategory("developer", lcli.FetchParamCmd), + lcli.WithCategory("developer", lcli.EvmCmd), + lcli.WithCategory("network", lcli.NetCmd), + lcli.WithCategory("network", lcli.SyncCmd), + lcli.WithCategory("status", lcli.StatusCmd), + lcli.PprofCmd, + lcli.VersionCmd, +} diff --git a/cli/clicommands/state.go b/cli/clicommands/state.go new file mode 100644 index 00000000000..e990cceb0be --- /dev/null +++ b/cli/clicommands/state.go @@ -0,0 +1,70 @@ +// Package clicommands contains only the cli.Command definitions that are +// common to sptool and miner. These are here because they can't be referenced +// in cli/spcli or cli/ because of the import cycle with all the other cli functions. +package clicommands + +import ( + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-address" + + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/spcli" +) + +var StateCmd = &cli.Command{ + Name: "state", + Usage: "Interact with and query filecoin chain state", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "tipset", + Usage: "specify tipset to call method on (pass comma separated array of cids)", + }, + }, + Subcommands: []*cli.Command{ + lcli.StatePowerCmd, + lcli.StateSectorsCmd, + lcli.StateActiveSectorsCmd, + lcli.StateListActorsCmd, + lcli.StateListMinersCmd, + lcli.StateCircSupplyCmd, + lcli.StateSectorCmd, + lcli.StateGetActorCmd, + lcli.StateLookupIDCmd, + lcli.StateReplayCmd, + lcli.StateSectorSizeCmd, + lcli.StateReadStateCmd, + lcli.StateListMessagesCmd, + lcli.StateComputeStateCmd, + lcli.StateCallCmd, + lcli.StateGetDealSetCmd, + lcli.StateWaitMsgCmd, + lcli.StateSearchMsgCmd, + StateMinerInfo, + lcli.StateMarketCmd, + lcli.StateExecTraceCmd, + lcli.StateNtwkVersionCmd, + lcli.StateMinerProvingDeadlineCmd, + lcli.StateSysActorCIDsCmd, + }, +} + +var StateMinerInfo = &cli.Command{ + Name: "miner-info", + Usage: "Retrieve miner information", + ArgsUsage: "[minerAddress]", + Action: func(cctx *cli.Context) error { + addressGetter := func(_ *cli.Context) (address.Address, error) { + if cctx.NArg() != 1 { + return address.Address{}, lcli.IncorrectNumArgs(cctx) + } + + return address.NewFromString(cctx.Args().First()) + } + err := spcli.InfoCmd(addressGetter).Action(cctx) + if err != nil { + return err + } + return nil + }, +} diff --git a/cli/client.go b/cli/client.go index 81299b8fb3e..e40a6686679 100644 --- a/cli/client.go +++ b/cli/client.go @@ -74,7 +74,7 @@ func GetCidEncoder(cctx *cli.Context) (cidenc.Encoder, error) { return e, nil } -var clientCmd = &cli.Command{ +var ClientCmd = &cli.Command{ Name: "client", Usage: "Make deals, store data, retrieve data", Subcommands: []*cli.Command{ @@ -574,7 +574,7 @@ func interactiveDeal(cctx *cli.Context) error { cs := readline.NewCancelableStdin(afmt.Stdin) go func() { <-ctx.Done() - cs.Close() // nolint:errcheck + _ = cs.Close() }() rl := bufio.NewReader(cs) @@ -2327,7 +2327,7 @@ func OutputDataTransferChannels(out io.Writer, channels []lapi.DataTransferChann for _, channel := range sendingChannels { w.Write(toChannelOutput("Sending To", channel, verbose)) } - w.Flush(out) //nolint:errcheck + _ = w.Flush(out) fmt.Fprintf(out, "\nReceiving Channels\n\n") w = tablewriter.New(tablewriter.Col("ID"), @@ -2341,7 +2341,7 @@ func OutputDataTransferChannels(out io.Writer, channels []lapi.DataTransferChann for _, channel := range receivingChannels { w.Write(toChannelOutput("Receiving From", channel, verbose)) } - w.Flush(out) //nolint:errcheck + _ = w.Flush(out) } func channelStatusString(status datatransfer.Status) string { diff --git a/cli/cmd.go b/cli/cmd.go index 802df0c99ac..76c0ab300a6 100644 --- a/cli/cmd.go +++ b/cli/cmd.go @@ -66,29 +66,6 @@ var CommonCommands = []*cli.Command{ VersionCmd, } -var Commands = []*cli.Command{ - WithCategory("basic", sendCmd), - WithCategory("basic", walletCmd), - WithCategory("basic", infoCmd), - WithCategory("basic", clientCmd), - WithCategory("basic", multisigCmd), - WithCategory("basic", filplusCmd), - WithCategory("basic", paychCmd), - WithCategory("developer", AuthCmd), - WithCategory("developer", MpoolCmd), - WithCategory("developer", StateCmd), - WithCategory("developer", ChainCmd), - WithCategory("developer", LogCmd), - WithCategory("developer", WaitApiCmd), - WithCategory("developer", FetchParamCmd), - WithCategory("developer", EvmCmd), - WithCategory("network", NetCmd), - WithCategory("network", SyncCmd), - WithCategory("status", StatusCmd), - PprofCmd, - VersionCmd, -} - func WithCategory(cat string, cmd *cli.Command) *cli.Command { cmd.Category = strings.ToUpper(cat) return cmd diff --git a/cli/disputer.go b/cli/disputer.go index de3f5032468..f6680daec66 100644 --- a/cli/disputer.go +++ b/cli/disputer.go @@ -361,6 +361,15 @@ var disputerStartCmd = &cli.Command{ // for a given miner, index, and maxPostIndex, tries to dispute posts from 0...postsSnapshotted-1 // returns a list of DisputeWindowedPoSt msgs that are expected to succeed if sent func makeDisputeWindowedPosts(ctx context.Context, api v0api.FullNode, dl minerDeadline, postsSnapshotted uint64, sender address.Address) ([]*types.Message, error) { + // CHECK: if miner waller balance is zero then skip sending dispute message + walletBalance, err := api.WalletBalance(ctx, dl.miner) + if err != nil { + return nil, xerrors.Errorf("failed to get wallet balance while checking to send dispute messages to miner %w: %w", dl.miner, err) + } + if walletBalance.IsZero() { + disputeLog.Warnw("wallet balance is zero, skipping dispute message", "wallet", dl.miner) + return nil, nil + } disputes := make([]*types.Message, 0) for i := uint64(0); i < postsSnapshotted; i++ { diff --git a/cli/filplus.go b/cli/filplus.go index e86fe0372c3..cf37a10f331 100644 --- a/cli/filplus.go +++ b/cli/filplus.go @@ -4,23 +4,30 @@ import ( "bytes" "context" "encoding/hex" + "errors" "fmt" "os" "strconv" "strings" cbor "github.com/ipfs/go-ipld-cbor" + "github.com/manifoldco/promptui" "github.com/urfave/cli/v2" + "golang.org/x/sync/errgroup" "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" + "github.com/filecoin-project/go-state-types/builtin" + verifregtypes13 "github.com/filecoin-project/go-state-types/builtin/v13/verifreg" verifregtypes8 "github.com/filecoin-project/go-state-types/builtin/v8/verifreg" + datacap2 "github.com/filecoin-project/go-state-types/builtin/v9/datacap" verifregtypes9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/v0api" "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/build" @@ -32,7 +39,7 @@ import ( "github.com/filecoin-project/lotus/lib/tablewriter" ) -var filplusCmd = &cli.Command{ +var FilplusCmd = &cli.Command{ Name: "filplus", Usage: "Interact with the verified registry actor used by Filplus", Flags: []cli.Flag{}, @@ -47,6 +54,7 @@ var filplusCmd = &cli.Command{ filplusListClaimsCmd, filplusRemoveExpiredAllocationsCmd, filplusRemoveExpiredClaimsCmd, + filplusExtendClaimCmd, }, } @@ -322,7 +330,7 @@ var filplusListAllocationsCmd = &cli.Command{ tablewriter.Col(pieceSize), tablewriter.Col(tMin), tablewriter.Col(tMax), - tablewriter.NewLineCol(expr)) + tablewriter.Col(expr)) // populate it with content for _, alloc := range allocs { tw.Write(alloc) @@ -386,6 +394,11 @@ var filplusListClaimsCmd = &cli.Command{ Name: "expired", Usage: "list only expired claims", }, + &cli.BoolFlag{ + Name: "json", + Usage: "output results in json format", + Value: false, + }, }, Action: func(cctx *cli.Context) error { if cctx.NArg() > 1 { @@ -427,7 +440,7 @@ var filplusListClaimsCmd = &cli.Command{ var claimList []map[string]interface{} for key, val := range claims { - if tsHeight > val.TermMax || !expired { + if tsHeight > val.TermStart+val.TermMax || !expired { claim := map[string]interface{}{ claimID: key, provider: val.Provider, @@ -466,7 +479,7 @@ var filplusListClaimsCmd = &cli.Command{ tablewriter.Col(tMin), tablewriter.Col(tMax), tablewriter.Col(tStart), - tablewriter.NewLineCol(sector)) + tablewriter.Col(sector)) // populate it with content for _, alloc := range claimList { @@ -518,7 +531,6 @@ var filplusListClaimsCmd = &cli.Command{ } return writeOut(ts.Height(), claimsMap, cctx.Bool("json"), cctx.Bool("expired")) - }, } @@ -924,3 +936,485 @@ var filplusSignRemoveDataCapProposal = &cli.Command{ return nil }, } + +var filplusExtendClaimCmd = &cli.Command{ + Name: "extend-claim", + Usage: "extends claim expiration (TermMax)", + UsageText: `Extends claim expiration (TermMax). +If the client is original client then claim can be extended to maximum 5 years and no Datacap is required. +If the client id different then claim can be extended up to maximum 5 years from now and Datacap is required. +`, + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "term-max", + Usage: "The maximum period for which a provider can earn quality-adjusted power for the piece (epochs). Default is 5 years.", + Aliases: []string{"tmax"}, + Value: verifregtypes13.MaximumVerifiedAllocationTerm, + }, + &cli.StringFlag{ + Name: "client", + Usage: "the client address that will used to send the message", + Required: true, + }, + &cli.BoolFlag{ + Name: "all", + Usage: "automatically extend TermMax of all claims for specified miner[s] to --term-max (default: 5 years from claim start epoch)", + }, + &cli.StringSliceFlag{ + Name: "miner", + Usage: "storage provider address[es]", + Aliases: []string{"m", "provider", "p"}, + }, + &cli.BoolFlag{ + Name: "assume-yes", + Usage: "automatic yes to prompts; assume 'yes' as answer to all prompts and run non-interactively", + Aliases: []string{"y", "yes"}, + }, + &cli.IntFlag{ + Name: "confidence", + Usage: "number of block confirmations to wait for", + Value: int(build.MessageConfidence), + }, + &cli.IntFlag{ + Name: "batch-size", + Usage: "number of extend requests per batch. If set incorrectly, this will lead to out of gas error", + Value: 500, + }, + }, + ArgsUsage: " ... or ...", + Action: func(cctx *cli.Context) error { + + miners := cctx.StringSlice("miner") + all := cctx.Bool("all") + client := cctx.String("client") + tmax := cctx.Int64("term-max") + + // No miner IDs and no arguments + if len(miners) == 0 && cctx.Args().Len() == 0 { + return xerrors.Errorf("must specify at least one miner ID or argument[s]") + } + + // Single Miner with no claimID and no --all flag + if len(miners) == 1 && cctx.Args().Len() == 0 && !all { + return xerrors.Errorf("must specify either --all flag or claim IDs to extend in argument") + } + + // Multiple Miner with claimIDs + if len(miners) > 1 && cctx.Args().Len() > 0 { + return xerrors.Errorf("either specify multiple miner IDs or multiple arguments") + } + + // Multiple Miner with no claimID and no --all flag + if len(miners) > 1 && cctx.Args().Len() == 0 && !all { + return xerrors.Errorf("must specify --all flag with multiple miner IDs") + } + + // Tmax can't be more than policy max + if tmax > verifregtypes13.MaximumVerifiedAllocationTerm { + return xerrors.Errorf("specified term-max %d is larger than %d maximum allowed by verified regirty actor policy", tmax, verifregtypes13.MaximumVerifiedAllocationTerm) + } + + api, closer, err := GetFullNodeAPIV1(cctx) + if err != nil { + return xerrors.Errorf("failed to get full node api: %s", err) + } + defer closer() + ctx := ReqContext(cctx) + + clientAddr, err := address.NewFromString(client) + if err != nil { + return err + } + + claimMap := make(map[verifregtypes13.ClaimId]ProvInfo) + + // If no miners and arguments are present + if len(miners) == 0 && cctx.Args().Len() > 0 { + for _, arg := range cctx.Args().Slice() { + detail := strings.Split(arg, "=") + if len(detail) > 2 { + return xerrors.Errorf("incorrect argument format: %s", detail) + } + + n, err := strconv.ParseInt(detail[1], 10, 64) + if err != nil { + return xerrors.Errorf("failed to parse the claim ID for %s for argument %s: %s", detail[0], detail, err) + } + + maddr, err := address.NewFromString(detail[0]) + if err != nil { + return err + } + + // Verify that minerID exists + _, err = api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + mid, err := address.IDFromAddress(maddr) + if err != nil { + return err + } + + pi := ProvInfo{ + Addr: maddr, + ID: abi.ActorID(mid), + } + + claimMap[verifregtypes13.ClaimId(n)] = pi + } + } + + // If 1 miner ID and multiple arguments + if len(miners) == 1 && cctx.Args().Len() > 0 && !all { + for _, arg := range cctx.Args().Slice() { + detail := strings.Split(arg, "=") + if len(detail) > 1 { + return xerrors.Errorf("incorrect argument format %s. Must provide only claim IDs with single miner ID", detail) + } + + n, err := strconv.ParseInt(detail[0], 10, 64) + if err != nil { + return xerrors.Errorf("failed to parse the claim ID for %s for argument %s: %s", detail[0], detail, err) + } + + claimMap[verifregtypes13.ClaimId(n)] = ProvInfo{} + } + } + + msgs, err := CreateExtendClaimMsg(ctx, api, claimMap, miners, clientAddr, abi.ChainEpoch(tmax), all, cctx.Bool("assume-yes"), cctx.Int("batch-size")) + if err != nil { + return err + } + + // If not msgs are found then no claims can be extended + if msgs == nil { + fmt.Println("No eligible claims to extend") + return nil + } + + // MpoolBatchPushMessage method will take care of gas estimation and funds check + smsgs, err := api.MpoolBatchPushMessage(ctx, msgs, nil) + if err != nil { + return err + } + + // wait for msgs to get mined into a block + eg := errgroup.Group{} + eg.SetLimit(10) + for _, msg := range smsgs { + msg := msg + eg.Go(func() error { + wait, err := api.StateWaitMsg(ctx, msg.Cid(), uint64(cctx.Int("confidence")), 2000, true) + if err != nil { + return xerrors.Errorf("timeout waiting for message to land on chain %s", wait.Message) + + } + + if wait.Receipt.ExitCode.IsError() { + return xerrors.Errorf("failed to execute message %s: %s", wait.Message, wait.Receipt.ExitCode) + } + return nil + }) + } + return eg.Wait() + }, +} + +type ProvInfo struct { + Addr address.Address + ID abi.ActorID +} + +// CreateExtendClaimMsg creates extend message[s] based on the following conditions +// 1. Extend all claims for a miner ID +// 2. Extend all claims for multiple miner IDs +// 3. Extend specified claims for a miner ID +// 4. Extend specific claims for specific miner ID +// 5. Extend all claims for a miner ID with different client address (2 messages) +// 6. Extend all claims for multiple miner IDs with different client address (2 messages) +// 7. Extend specified claims for a miner ID with different client address (2 messages) +// 8. Extend specific claims for specific miner ID with different client address (2 messages) +func CreateExtendClaimMsg(ctx context.Context, api api.FullNode, pcm map[verifregtypes13.ClaimId]ProvInfo, miners []string, wallet address.Address, tmax abi.ChainEpoch, all, assumeYes bool, batchSize int) ([]*types.Message, error) { + + ac, err := api.StateLookupID(ctx, wallet, types.EmptyTSK) + if err != nil { + return nil, err + } + w, err := address.IDFromAddress(ac) + if err != nil { + return nil, xerrors.Errorf("converting wallet address to ID: %w", err) + } + + wid := abi.ActorID(w) + + head, err := api.ChainHead(ctx) + if err != nil { + return nil, err + } + + var terms []verifregtypes13.ClaimTerm + newClaims := make(map[verifregtypes13.ClaimExtensionRequest]big.Int) + rDataCap := big.NewInt(0) + + // If --all is set + if all { + for _, id := range miners { + maddr, err := address.NewFromString(id) + if err != nil { + return nil, xerrors.Errorf("parsing miner %s: %s", id, err) + } + mid, err := address.IDFromAddress(maddr) + if err != nil { + return nil, xerrors.Errorf("converting miner address to miner ID: %s", err) + } + claims, err := api.StateGetClaims(ctx, maddr, types.EmptyTSK) + if err != nil { + return nil, xerrors.Errorf("getting claims for miner %s: %s", maddr, err) + } + for claimID, claim := range claims { + claimID := claimID + claim := claim + // If the client is not the original client - burn datacap + if claim.Client != wid { + // The new duration should be greater than the original deal duration and claim should not already be expired + if head.Height()+tmax-claim.TermStart > claim.TermMax-claim.TermStart && claim.TermStart+claim.TermMax > head.Height() { + req := verifregtypes13.ClaimExtensionRequest{ + Claim: verifregtypes13.ClaimId(claimID), + Provider: abi.ActorID(mid), + TermMax: head.Height() + tmax - claim.TermStart, + } + newClaims[req] = big.NewInt(int64(claim.Size)) + rDataCap.Add(big.NewInt(int64(claim.Size)).Int, rDataCap.Int) + } + // If new duration shorter than the original duration then do nothing + continue + } + // For original client, compare duration(TermMax) and claim should not already be expired + if claim.TermMax < tmax && claim.TermStart+claim.TermMax > head.Height() { + terms = append(terms, verifregtypes13.ClaimTerm{ + ClaimId: verifregtypes13.ClaimId(claimID), + TermMax: tmax, + Provider: abi.ActorID(mid), + }) + } + } + } + } + + // Single miner and specific claims + if len(miners) == 1 && len(pcm) > 0 { + maddr, err := address.NewFromString(miners[0]) + if err != nil { + return nil, xerrors.Errorf("parsing miner %s: %s", miners[0], err) + } + mid, err := address.IDFromAddress(maddr) + if err != nil { + return nil, xerrors.Errorf("converting miner address to miner ID: %s", err) + } + claims, err := api.StateGetClaims(ctx, maddr, types.EmptyTSK) + if err != nil { + return nil, xerrors.Errorf("getting claims for miner %s: %s", maddr, err) + } + + for claimID := range pcm { + claimID := claimID + claim, ok := claims[verifregtypes9.ClaimId(claimID)] + if !ok { + return nil, xerrors.Errorf("claim %d not found for provider %s", claimID, miners[0]) + } + // If the client is not the original client - burn datacap + if claim.Client != wid { + // The new duration should be greater than the original deal duration and claim should not already be expired + if head.Height()+tmax-claim.TermStart > claim.TermMax-claim.TermStart && claim.TermStart+claim.TermMax > head.Height() { + req := verifregtypes13.ClaimExtensionRequest{ + Claim: claimID, + Provider: abi.ActorID(mid), + TermMax: head.Height() + tmax - claim.TermStart, + } + newClaims[req] = big.NewInt(int64(claim.Size)) + rDataCap.Add(big.NewInt(int64(claim.Size)).Int, rDataCap.Int) + } + // If new duration shorter than the original duration then do nothing + continue + } + // For original client, compare duration(TermMax) and claim should not already be expired + if claim.TermMax < tmax && claim.TermStart+claim.TermMax > head.Height() { + terms = append(terms, verifregtypes13.ClaimTerm{ + ClaimId: claimID, + TermMax: tmax, + Provider: abi.ActorID(mid), + }) + } + } + } + + if len(miners) == 0 && len(pcm) > 0 { + for claimID, prov := range pcm { + prov := prov + claimID := claimID + claim, err := api.StateGetClaim(ctx, prov.Addr, verifregtypes9.ClaimId(claimID), types.EmptyTSK) + if err != nil { + return nil, xerrors.Errorf("could not load the claim %d: %s", claimID, err) + } + if claim == nil { + return nil, xerrors.Errorf("claim %d not found in the actor state", claimID) + } + // If the client is not the original client - burn datacap + if claim.Client != wid { + // The new duration should be greater than the original deal duration and claim should not already be expired + if head.Height()+tmax-claim.TermStart > claim.TermMax-claim.TermStart && claim.TermStart+claim.TermMax > head.Height() { + req := verifregtypes13.ClaimExtensionRequest{ + Claim: claimID, + Provider: prov.ID, + TermMax: head.Height() + tmax - claim.TermStart, + } + newClaims[req] = big.NewInt(int64(claim.Size)) + rDataCap.Add(big.NewInt(int64(claim.Size)).Int, rDataCap.Int) + } + // If new duration shorter than the original duration then do nothing + continue + } + // For original client, compare duration(TermMax) and claim should not already be expired + if claim.TermMax < tmax && claim.TermStart+claim.TermMax > head.Height() { + terms = append(terms, verifregtypes13.ClaimTerm{ + ClaimId: claimID, + TermMax: tmax, + Provider: prov.ID, + }) + } + } + } + + var msgs []*types.Message + + if len(terms) > 0 { + // Batch in 500 to avoid running out of gas + for i := 0; i < len(terms); i += batchSize { + batchEnd := i + batchSize + if batchEnd > len(terms) { + batchEnd = len(terms) + } + + batch := terms[i:batchEnd] + + params, err := actors.SerializeParams(&verifregtypes13.ExtendClaimTermsParams{ + Terms: batch, + }) + if err != nil { + return nil, xerrors.Errorf("failed to searialise the parameters: %s", err) + } + oclaimMsg := &types.Message{ + To: verifreg.Address, + From: wallet, + Method: verifreg.Methods.ExtendClaimTerms, + Params: params, + } + msgs = append(msgs, oclaimMsg) + } + } + + if len(newClaims) > 0 { + if !assumeYes { + out := fmt.Sprintf("Some of the specified allocation have a different client address and will require %d Datacap to extend. Proceed? Yes [Y/y] / No [N/n], Ctrl+C (^C) to exit", rDataCap.Int) + validate := func(input string) error { + if strings.EqualFold(input, "y") || strings.EqualFold(input, "yes") { + return nil + } + if strings.EqualFold(input, "n") || strings.EqualFold(input, "no") { + return nil + } + return errors.New("incorrect input") + } + + templates := &promptui.PromptTemplates{ + Prompt: "{{ . }} ", + Valid: "{{ . | green }} ", + Invalid: "{{ . | red }} ", + Success: "{{ . | cyan | bold }} ", + } + + prompt := promptui.Prompt{ + Label: out, + Templates: templates, + Validate: validate, + } + + input, err := prompt.Run() + if err != nil { + return nil, err + } + if strings.Contains(strings.ToLower(input), "n") { + fmt.Println("Dropping the extension for claims that require Datacap") + return msgs, nil + } + } + + // Get datacap balance + aDataCap, err := api.StateVerifiedClientStatus(ctx, wallet, types.EmptyTSK) + if err != nil { + return nil, err + } + + if aDataCap == nil { + return nil, xerrors.Errorf("wallet %s does not have any datacap", wallet) + } + + // Check that we have enough data cap to make the allocation + if rDataCap.GreaterThan(big.NewInt(aDataCap.Int64())) { + return nil, xerrors.Errorf("requested datacap %s is greater then the available datacap %s", rDataCap, aDataCap) + } + + // Create a map of just keys, so we can easily batch based on the numeric keys + keys := make([]verifregtypes13.ClaimExtensionRequest, 0, len(newClaims)) + for k := range newClaims { + keys = append(keys, k) + } + + // Batch in 500 to avoid running out of gas + for i := 0; i < len(keys); i += batchSize { + batchEnd := i + batchSize + if batchEnd > len(newClaims) { + batchEnd = len(newClaims) + } + + batch := keys[i:batchEnd] + + // Calculate Datacap for this batch + dcap := big.NewInt(0) + for _, k := range batch { + dc := newClaims[k] + dcap.Add(dcap.Int, dc.Int) + } + + ncparams, err := actors.SerializeParams(&verifregtypes13.AllocationRequests{ + Extensions: batch, + }) + if err != nil { + return nil, xerrors.Errorf("failed to searialise the parameters: %s", err) + } + + transferParams, err := actors.SerializeParams(&datacap2.TransferParams{ + To: builtin.VerifiedRegistryActorAddr, + Amount: big.Mul(dcap, builtin.TokenPrecision), + OperatorData: ncparams, + }) + + if err != nil { + return nil, xerrors.Errorf("failed to serialize transfer parameters: %s", err) + } + + nclaimMsg := &types.Message{ + To: builtin.DatacapActorAddr, + From: wallet, + Method: datacap.Methods.TransferExported, + Params: transferParams, + Value: big.Zero(), + } + msgs = append(msgs, nclaimMsg) + } + } + + return msgs, nil +} diff --git a/cli/info.go b/cli/info.go index 8b36be4889b..01f64dee9b4 100644 --- a/cli/info.go +++ b/cli/info.go @@ -23,7 +23,7 @@ import ( "github.com/filecoin-project/lotus/journal/alerting" ) -var infoCmd = &cli.Command{ +var InfoCmd = &cli.Command{ Name: "info", Usage: "Print node info", Action: infoCmdAct, @@ -131,9 +131,8 @@ func infoCmdAct(cctx *cli.Context) error { if err != nil { if strings.Contains(err.Error(), "actor not found") { continue - } else { - return err } + return err } mbLockedSum = big.Add(mbLockedSum, mbal.Locked) mbAvailableSum = big.Add(mbAvailableSum, mbal.Escrow) diff --git a/cli/init_test.go b/cli/init_test.go index 8c343bcfabe..59914684ba2 100644 --- a/cli/init_test.go +++ b/cli/init_test.go @@ -5,5 +5,5 @@ import ( ) func init() { - logging.SetLogLevel("watchdog", "ERROR") + _ = logging.SetLogLevel("watchdog", "ERROR") } diff --git a/cli/mpool.go b/cli/mpool.go index c83fb4b614a..f38a900fb7b 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -491,7 +491,7 @@ var MpoolReplaceCmd = &cli.Command{ msg.GasFeeCap = big.Max(retm.GasFeeCap, msg.GasPremium) mff := func() (abi.TokenAmount, error) { - return abi.TokenAmount(config.DefaultDefaultMaxFee), nil + return abi.TokenAmount(config.DefaultDefaultMaxFee()), nil } messagepool.CapGasFee(mff, &msg, mss) diff --git a/cli/multisig.go b/cli/multisig.go index 1af2a4c9e4e..290cf6700e2 100644 --- a/cli/multisig.go +++ b/cli/multisig.go @@ -32,7 +32,7 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) -var multisigCmd = &cli.Command{ +var MultisigCmd = &cli.Command{ Name: "msig", Usage: "Interact with a multisig wallet", Flags: []cli.Flag{ diff --git a/cli/paych.go b/cli/paych.go index 1067d091376..46b043d6a6d 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -20,7 +20,7 @@ import ( "github.com/filecoin-project/lotus/paychmgr" ) -var paychCmd = &cli.Command{ +var PaychCmd = &cli.Command{ Name: "paych", Usage: "Manage payment channels", Subcommands: []*cli.Command{ diff --git a/cli/send.go b/cli/send.go index cfa2515c07b..89c79e109bd 100644 --- a/cli/send.go +++ b/cli/send.go @@ -19,7 +19,7 @@ import ( "github.com/filecoin-project/lotus/chain/types/ethtypes" ) -var sendCmd = &cli.Command{ +var SendCmd = &cli.Command{ Name: "send", Usage: "Send funds between accounts", ArgsUsage: "[targetAddress] [amount]", diff --git a/cli/send_test.go b/cli/send_test.go index 2c59a9641f6..59b8942f44b 100644 --- a/cli/send_test.go +++ b/cli/send_test.go @@ -45,7 +45,7 @@ func TestSendCLI(t *testing.T) { oneFil := abi.TokenAmount(types.MustParseFIL("1")) t.Run("simple", func(t *testing.T) { - app, mockSrvcs, buf, done := newMockApp(t, sendCmd) + app, mockSrvcs, buf, done := newMockApp(t, SendCmd) defer done() arbtProto := &api.MessagePrototype{ @@ -76,7 +76,7 @@ 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) + app, mockSrvcs, buf, done := newMockApp(t, SendCmd) defer done() testEthAddr, err := ethtypes.CastEthAddress(make([]byte, 20)) diff --git a/cli/sending_ui.go b/cli/sending_ui.go index d2d2ed3c110..c248feb3d3e 100644 --- a/cli/sending_ui.go +++ b/cli/sending_ui.go @@ -122,7 +122,7 @@ func printChecks(printer io.Writer, checkGroups [][]api.MessageCheckStatus, prot func askUser(printer io.Writer, q string, def bool) bool { var resp string fmt.Fprint(printer, q) - fmt.Scanln(&resp) + _, _ = fmt.Scanln(&resp) resp = strings.ToLower(resp) if len(resp) == 0 { return def diff --git a/cli/spcli/actor.go b/cli/spcli/actor.go new file mode 100644 index 00000000000..33590de50b6 --- /dev/null +++ b/cli/spcli/actor.go @@ -0,0 +1,1433 @@ +package spcli + +import ( + "bytes" + "context" + "fmt" + "strconv" + + "github.com/docker/go-units" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/libp2p/go-libp2p/core/peer" + ma "github.com/multiformats/go-multiaddr" + "github.com/urfave/cli/v2" + "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" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v9/miner" + "github.com/filecoin-project/go-state-types/network" + power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power" + power6 "github.com/filecoin-project/specs-actors/v6/actors/builtin/power" + + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/v1api" + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + 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" + lcli "github.com/filecoin-project/lotus/cli" + cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/node/impl" +) + +func ActorWithdrawCmd(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "withdraw", + Usage: "withdraw available balance to beneficiary", + ArgsUsage: "[amount (FIL)]", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "confidence", + Usage: "number of block confirmations to wait for", + Value: int(build.MessageConfidence), + }, + &cli.BoolFlag{ + Name: "beneficiary", + Usage: "send withdraw message from the beneficiary address", + }, + }, + Action: func(cctx *cli.Context) error { + amount := abi.NewTokenAmount(0) + + if cctx.Args().Present() { + f, err := types.ParseFIL(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("parsing 'amount' argument: %w", err) + } + + amount = abi.TokenAmount(f) + } + + api, acloser, err := lcli.GetFullNodeAPIV1(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + res, err := impl.WithdrawBalance(ctx, api, maddr, amount, !cctx.IsSet("beneficiary")) + if err != nil { + return err + } + + fmt.Printf("Requested withdrawal in message %s\nwaiting for it to be included in a block..\n", res) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, res, uint64(cctx.Int("confidence")), lapi.LookbackNoLimit, true) + if err != nil { + return xerrors.Errorf("Timeout waiting for withdrawal message %s", res) + } + + if wait.Receipt.ExitCode.IsError() { + return xerrors.Errorf("Failed to execute withdrawal message %s: %w", wait.Message, wait.Receipt.ExitCode.Error()) + } + + nv, err := api.StateNetworkVersion(ctx, wait.TipSet) + if err != nil { + return err + } + + if nv >= network.Version14 { + var withdrawn abi.TokenAmount + if err := withdrawn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { + return err + } + + fmt.Printf("Successfully withdrew %s \n", types.FIL(withdrawn)) + if withdrawn.LessThan(amount) { + fmt.Printf("Note that this is less than the requested amount of %s\n", types.FIL(amount)) + } + } + + return nil + }, + } +} + +func ActorSetAddrsCmd(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "set-addresses", + Aliases: []string{"set-addrs"}, + Usage: "set addresses that your miner can be publicly dialed on", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "optionally specify the account to send the message from", + }, + &cli.Int64Flag{ + Name: "gas-limit", + Usage: "set gas limit", + Value: 0, + }, + &cli.BoolFlag{ + Name: "unset", + Usage: "unset address", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + args := cctx.Args().Slice() + unset := cctx.Bool("unset") + if len(args) == 0 && !unset { + return cli.ShowSubcommandHelp(cctx) + } + if len(args) > 0 && unset { + return fmt.Errorf("unset can only be used with no arguments") + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + var addrs []abi.Multiaddrs + for _, a := range args { + maddr, err := ma.NewMultiaddr(a) + if err != nil { + return fmt.Errorf("failed to parse %q as a multiaddr: %w", a, err) + } + + maddrNop2p, strip := ma.SplitFunc(maddr, func(c ma.Component) bool { + return c.Protocol().Code == ma.P_P2P + }) + + if strip != nil { + fmt.Println("Stripping peerid ", strip, " from ", maddr) + } + addrs = append(addrs, maddrNop2p.Bytes()) + } + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + fromAddr := minfo.Worker + if from := cctx.String("from"); from != "" { + addr, err := address.NewFromString(from) + if err != nil { + return err + } + + fromAddr = addr + } + + fromId, err := api.StateLookupID(ctx, fromAddr, types.EmptyTSK) + if err != nil { + return err + } + + if !isController(minfo, fromId) { + return xerrors.Errorf("sender isn't a controller of miner: %s", fromId) + } + + params, err := actors.SerializeParams(&miner.ChangeMultiaddrsParams{NewMultiaddrs: addrs}) + if err != nil { + return err + } + + gasLimit := cctx.Int64("gas-limit") + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + To: maddr, + From: fromId, + Value: types.NewInt(0), + GasLimit: gasLimit, + Method: builtin.MethodsMiner.ChangeMultiaddrs, + Params: params, + }, nil) + if err != nil { + return err + } + + fmt.Printf("Requested multiaddrs change in message %s\n", smsg.Cid()) + return nil + + }, + } +} + +func ActorSetPeeridCmd(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "set-peer-id", + Usage: "set the peer id of your miner", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "gas-limit", + Usage: "set gas limit", + Value: 0, + }, + }, + Action: func(cctx *cli.Context) error { + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + pid, err := peer.Decode(cctx.Args().Get(0)) + if err != nil { + return fmt.Errorf("failed to parse input as a peerId: %w", err) + } + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + params, err := actors.SerializeParams(&miner.ChangePeerIDParams{NewID: abi.PeerID(pid)}) + if err != nil { + return err + } + + gasLimit := cctx.Int64("gas-limit") + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + To: maddr, + From: minfo.Worker, + Value: types.NewInt(0), + GasLimit: gasLimit, + Method: builtin.MethodsMiner.ChangePeerID, + Params: params, + }, nil) + if err != nil { + return err + } + + fmt.Printf("Requested peerid change in message %s\n", smsg.Cid()) + return nil + + }, + } +} + +func ActorRepayDebtCmd(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "repay-debt", + Usage: "pay down a miner's debt", + ArgsUsage: "[amount (FIL)]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "optionally specify the account to send funds from", + }, + }, + Action: func(cctx *cli.Context) error { + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + var amount abi.TokenAmount + if cctx.Args().Present() { + f, err := types.ParseFIL(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("parsing 'amount' argument: %w", err) + } + + amount = abi.TokenAmount(f) + } else { + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(api))) + + mst, err := lminer.Load(store, mact) + if err != nil { + return err + } + + amount, err = mst.FeeDebt() + if err != nil { + return err + } + + } + + fromAddr := mi.Worker + if from := cctx.String("from"); from != "" { + addr, err := address.NewFromString(from) + if err != nil { + return err + } + + fromAddr = addr + } + + fromId, err := api.StateLookupID(ctx, fromAddr, types.EmptyTSK) + if err != nil { + return err + } + + if !isController(mi, fromId) { + return xerrors.Errorf("sender isn't a controller of miner: %s", fromId) + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + To: maddr, + From: fromId, + Value: amount, + Method: builtin.MethodsMiner.RepayDebt, + Params: nil, + }, nil) + if err != nil { + return err + } + + fmt.Printf("Sent repay debt message %s\n", smsg.Cid()) + + return nil + }, + } +} + +func ActorControlCmd(getActor ActorAddressGetter, actorControlListCmd *cli.Command) *cli.Command { + return &cli.Command{ + Name: "control", + Usage: "Manage control addresses", + Subcommands: []*cli.Command{ + actorControlListCmd, + actorControlSet(getActor), + }, + } +} + +func actorControlSet(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "set", + Usage: "Set control address(-es)", + ArgsUsage: "[...address]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + del := map[address.Address]struct{}{} + existing := map[address.Address]struct{}{} + for _, controlAddress := range mi.ControlAddresses { + ka, err := api.StateAccountKey(ctx, controlAddress, types.EmptyTSK) + if err != nil { + return err + } + + del[ka] = struct{}{} + existing[ka] = struct{}{} + } + + var toSet []address.Address + + for i, as := range cctx.Args().Slice() { + a, err := address.NewFromString(as) + if err != nil { + return xerrors.Errorf("parsing address %d: %w", i, err) + } + + ka, err := api.StateAccountKey(ctx, a, types.EmptyTSK) + if err != nil { + return err + } + + // make sure the address exists on chain + _, err = api.StateLookupID(ctx, ka, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("looking up %s: %w", ka, err) + } + + delete(del, ka) + toSet = append(toSet, ka) + } + + for a := range del { + fmt.Println("Remove", a) + } + for _, a := range toSet { + if _, exists := existing[a]; !exists { + fmt.Println("Add", a) + } + } + + if !cctx.Bool("really-do-it") { + fmt.Println("Pass --really-do-it to actually execute this action") + return nil + } + + cwp := &miner.ChangeWorkerAddressParams{ + NewWorker: mi.Worker, + NewControlAddrs: toSet, + } + + sp, err := actors.SerializeParams(cwp) + if err != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + From: mi.Owner, + To: maddr, + Method: builtin.MethodsMiner.ChangeWorkerAddress, + + Value: big.Zero(), + Params: sp, + }, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + fmt.Println("Message CID:", smsg.Cid()) + + return nil + }, + } +} + +func ActorSetOwnerCmd(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "set-owner", + Usage: "Set owner address (this command should be invoked twice, first with the old owner as the senderAddress, and then with the new owner)", + ArgsUsage: "[newOwnerAddress senderAddress]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 2 { + return lcli.IncorrectNumArgs(cctx) + } + + if !cctx.Bool("really-do-it") { + fmt.Println("Pass --really-do-it to actually execute this action") + return nil + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + na, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + newAddrId, err := api.StateLookupID(ctx, na, types.EmptyTSK) + if err != nil { + return err + } + + fa, err := address.NewFromString(cctx.Args().Get(1)) + if err != nil { + return err + } + + fromAddrId, err := api.StateLookupID(ctx, fa, types.EmptyTSK) + if err != nil { + return err + } + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + if fromAddrId != mi.Owner && fromAddrId != newAddrId { + return xerrors.New("from address must either be the old owner or the new owner") + } + + sp, err := actors.SerializeParams(&newAddrId) + if err != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + From: fromAddrId, + To: maddr, + Method: builtin.MethodsMiner.ChangeOwnerAddress, + Value: big.Zero(), + Params: sp, + }, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + fmt.Println("Message CID:", smsg.Cid()) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return err + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + fmt.Println("owner change failed!") + return err + } + + fmt.Println("message succeeded!") + + return nil + }, + } +} + +func ActorProposeChangeWorkerCmd(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "propose-change-worker", + Usage: "Propose a worker address change", + ArgsUsage: "[address]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("must pass address of new worker address") + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + na, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK) + if err != nil { + return err + } + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + if mi.NewWorker.Empty() { + if mi.Worker == newAddr { + return fmt.Errorf("worker address already set to %s", na) + } + } else { + if mi.NewWorker == newAddr { + return fmt.Errorf("change to worker address %s already pending", na) + } + } + + if !cctx.Bool("really-do-it") { + fmt.Fprintln(cctx.App.Writer, "Pass --really-do-it to actually execute this action") + return nil + } + + cwp := &miner.ChangeWorkerAddressParams{ + NewWorker: newAddr, + NewControlAddrs: mi.ControlAddresses, + } + + sp, err := actors.SerializeParams(cwp) + if err != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + From: mi.Owner, + To: maddr, + Method: builtin.MethodsMiner.ChangeWorkerAddress, + Value: big.Zero(), + Params: sp, + }, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + fmt.Fprintln(cctx.App.Writer, "Propose Message CID:", smsg.Cid()) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return err + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + return fmt.Errorf("propose worker change failed") + } + + mi, err = api.StateMinerInfo(ctx, maddr, wait.TipSet) + if err != nil { + return err + } + if mi.NewWorker != newAddr { + return fmt.Errorf("Proposed worker address change not reflected on chain: expected '%s', found '%s'", na, mi.NewWorker) + } + + fmt.Fprintf(cctx.App.Writer, "Worker key change to %s successfully sent, change happens at height %d.\n", na, mi.WorkerChangeEpoch) + fmt.Fprintf(cctx.App.Writer, "If you have no active deadlines, call 'confirm-change-worker' at or after height %d to complete.\n", mi.WorkerChangeEpoch) + + return nil + }, + } +} + +func ActorProposeChangeBeneficiaryCmd(getActor ActorAddressGetter) *cli.Command { + + return &cli.Command{ + Name: "propose-change-beneficiary", + Usage: "Propose a beneficiary address change", + ArgsUsage: "[beneficiaryAddress quota expiration]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + &cli.BoolFlag{ + Name: "overwrite-pending-change", + Usage: "Overwrite the current beneficiary change proposal", + Value: false, + }, + &cli.StringFlag{ + Name: "actor", + Usage: "specify the address of miner actor", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 3 { + return lcli.IncorrectNumArgs(cctx) + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return xerrors.Errorf("getting fullnode api: %w", err) + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + na, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return xerrors.Errorf("parsing beneficiary address: %w", err) + } + + newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("looking up new beneficiary address: %w", err) + } + + quota, err := types.ParseFIL(cctx.Args().Get(1)) + if err != nil { + return xerrors.Errorf("parsing quota: %w", err) + } + + expiration, err := strconv.ParseInt(cctx.Args().Get(2), 10, 64) + if err != nil { + return xerrors.Errorf("parsing expiration: %w", err) + } + + maddr, err := getActor(cctx) + if err != nil { + return xerrors.Errorf("getting miner address: %w", err) + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + if mi.Beneficiary == mi.Owner && newAddr == mi.Owner { + return fmt.Errorf("beneficiary %s already set to owner address", mi.Beneficiary) + } + + if mi.PendingBeneficiaryTerm != nil { + fmt.Println("WARNING: replacing Pending Beneficiary Term of:") + fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary) + fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota) + fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration) + + if !cctx.Bool("overwrite-pending-change") { + return fmt.Errorf("must pass --overwrite-pending-change to replace current pending beneficiary change. Please review CAREFULLY") + } + } + + if !cctx.Bool("really-do-it") { + fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please") + return nil + } + + params := &miner.ChangeBeneficiaryParams{ + NewBeneficiary: newAddr, + NewQuota: abi.TokenAmount(quota), + NewExpiration: abi.ChainEpoch(expiration), + } + + sp, err := actors.SerializeParams(params) + if err != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + From: mi.Owner, + To: maddr, + Method: builtin.MethodsMiner.ChangeBeneficiary, + Value: big.Zero(), + Params: sp, + }, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + fmt.Println("Propose Message CID:", smsg.Cid()) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return xerrors.Errorf("waiting for message to be included in block: %w", err) + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + return fmt.Errorf("propose beneficiary change failed") + } + + updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, wait.TipSet) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == newAddr { + fmt.Println("Beneficiary address successfully changed") + } else { + fmt.Println("Beneficiary address change awaiting additional confirmations") + } + + return nil + }, + } +} + +func ActorConfirmChangeWorkerCmd(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "confirm-change-worker", + Usage: "Confirm a worker address change", + ArgsUsage: "[address]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("must pass address of new worker address") + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + na, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return err + } + + newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK) + if err != nil { + return err + } + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + if mi.NewWorker.Empty() { + return xerrors.Errorf("no worker key change proposed") + } else if mi.NewWorker != newAddr { + return xerrors.Errorf("worker key %s does not match current worker key proposal %s", newAddr, mi.NewWorker) + } + + if head, err := api.ChainHead(ctx); err != nil { + return xerrors.Errorf("failed to get the chain head: %w", err) + } else if head.Height() < mi.WorkerChangeEpoch { + return xerrors.Errorf("worker key change cannot be confirmed until %d, current height is %d", mi.WorkerChangeEpoch, head.Height()) + } + + if !cctx.Bool("really-do-it") { + fmt.Println("Pass --really-do-it to actually execute this action") + return nil + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + From: mi.Owner, + To: maddr, + Method: builtin.MethodsMiner.ConfirmChangeWorkerAddress, + Value: big.Zero(), + }, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + fmt.Println("Confirm Message CID:", smsg.Cid()) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return err + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + fmt.Fprintln(cctx.App.Writer, "Worker change failed!") + return err + } + + mi, err = api.StateMinerInfo(ctx, maddr, wait.TipSet) + if err != nil { + return err + } + if mi.Worker != newAddr { + return fmt.Errorf("Confirmed worker address change not reflected on chain: expected '%s', found '%s'", newAddr, mi.Worker) + } + + return nil + }, + } +} + +func ActorConfirmChangeBeneficiaryCmd(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "confirm-change-beneficiary", + Usage: "Confirm a beneficiary address change", + ArgsUsage: "[minerID]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + &cli.BoolFlag{ + Name: "existing-beneficiary", + Usage: "send confirmation from the existing beneficiary address", + }, + &cli.BoolFlag{ + Name: "new-beneficiary", + Usage: "send confirmation from the new beneficiary address", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return xerrors.Errorf("getting fullnode api: %w", err) + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := address.NewFromString(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("parsing beneficiary address: %w", err) + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + if mi.PendingBeneficiaryTerm == nil { + return fmt.Errorf("no pending beneficiary term found for miner %s", maddr) + } + + if (cctx.IsSet("existing-beneficiary") && cctx.IsSet("new-beneficiary")) || (!cctx.IsSet("existing-beneficiary") && !cctx.IsSet("new-beneficiary")) { + return lcli.ShowHelp(cctx, fmt.Errorf("must pass exactly one of --existing-beneficiary or --new-beneficiary")) + } + + var fromAddr address.Address + if cctx.IsSet("existing-beneficiary") { + if mi.PendingBeneficiaryTerm.ApprovedByBeneficiary { + return fmt.Errorf("beneficiary change already approved by current beneficiary") + } + fromAddr = mi.Beneficiary + } else { + if mi.PendingBeneficiaryTerm.ApprovedByNominee { + return fmt.Errorf("beneficiary change already approved by new beneficiary") + } + fromAddr = mi.PendingBeneficiaryTerm.NewBeneficiary + } + + fmt.Println("Confirming Pending Beneficiary Term of:") + fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary) + fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota) + fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration) + + if !cctx.Bool("really-do-it") { + fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please") + return nil + } + + params := &miner.ChangeBeneficiaryParams{ + NewBeneficiary: mi.PendingBeneficiaryTerm.NewBeneficiary, + NewQuota: mi.PendingBeneficiaryTerm.NewQuota, + NewExpiration: mi.PendingBeneficiaryTerm.NewExpiration, + } + + sp, err := actors.SerializeParams(params) + if err != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + From: fromAddr, + To: maddr, + Method: builtin.MethodsMiner.ChangeBeneficiary, + Value: big.Zero(), + Params: sp, + }, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + fmt.Println("Confirm Message CID:", smsg.Cid()) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return xerrors.Errorf("waiting for message to be included in block: %w", err) + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + return fmt.Errorf("confirm beneficiary change failed with code %d", wait.Receipt.ExitCode) + } + + updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == mi.PendingBeneficiaryTerm.NewBeneficiary { + fmt.Println("Beneficiary address successfully changed") + } else { + fmt.Println("Beneficiary address change awaiting additional confirmations") + } + + return nil + }, + } +} + +func ActorCompactAllocatedCmd(getActor ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "compact-allocated", + Usage: "compact allocated sectors bitfield", + Flags: []cli.Flag{ + &cli.Uint64Flag{ + Name: "mask-last-offset", + Usage: "Mask sector IDs from 0 to 'highest_allocated - offset'", + }, + &cli.Uint64Flag{ + Name: "mask-upto-n", + Usage: "Mask sector IDs from 0 to 'n'", + }, + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Bool("really-do-it") { + fmt.Println("Pass --really-do-it to actually execute this action") + return nil + } + + if !cctx.Args().Present() { + return xerrors.Errorf("must pass address of new owner address") + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(api))) + + mst, err := lminer.Load(store, mact) + if err != nil { + return err + } + + allocs, err := mst.GetAllocatedSectors() + if err != nil { + return err + } + + var maskBf bitfield.BitField + + { + exclusiveFlags := []string{"mask-last-offset", "mask-upto-n"} + hasFlag := false + for _, f := range exclusiveFlags { + if hasFlag && cctx.IsSet(f) { + return xerrors.Errorf("more than one 'mask` flag set") + } + hasFlag = hasFlag || cctx.IsSet(f) + } + } + switch { + case cctx.IsSet("mask-last-offset"): + last, err := allocs.Last() + if err != nil { + return err + } + + m := cctx.Uint64("mask-last-offset") + if last <= m+1 { + return xerrors.Errorf("highest allocated sector lower than mask offset %d: %d", m+1, last) + } + // securty to not brick a miner + if last > 1<<60 { + return xerrors.Errorf("very high last sector number, refusing to mask: %d", last) + } + + maskBf, err = bitfield.NewFromIter(&rlepluslazy.RunSliceIterator{ + Runs: []rlepluslazy.Run{{Val: true, Len: last - m}}}) + if err != nil { + return xerrors.Errorf("forming bitfield: %w", err) + } + case cctx.IsSet("mask-upto-n"): + n := cctx.Uint64("mask-upto-n") + maskBf, err = bitfield.NewFromIter(&rlepluslazy.RunSliceIterator{ + Runs: []rlepluslazy.Run{{Val: true, Len: n}}}) + if err != nil { + return xerrors.Errorf("forming bitfield: %w", err) + } + default: + return xerrors.Errorf("no 'mask' flags set") + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + params := &miner.CompactSectorNumbersParams{ + MaskSectorNumbers: maskBf, + } + + sp, err := actors.SerializeParams(params) + if err != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + From: mi.Worker, + To: maddr, + Method: builtin.MethodsMiner.CompactSectorNumbers, + Value: big.Zero(), + Params: sp, + }, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + fmt.Println("CompactSectorNumbers Message CID:", smsg.Cid()) + + // wait for it to get mined into a block + wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) + if err != nil { + return err + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + fmt.Println("Sector Bitfield compaction failed") + return err + } + + return nil + }, + } +} + +func isController(mi lapi.MinerInfo, addr address.Address) bool { + if addr == mi.Owner || addr == mi.Worker { + return true + } + + for _, ca := range mi.ControlAddresses { + if addr == ca { + return true + } + } + + return false +} + +var ActorNewMinerCmd = &cli.Command{ + Name: "new-miner", + Usage: "Initializes a new miner actor", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "worker", + Aliases: []string{"w"}, + Usage: "worker key to use for new miner initialisation", + }, + &cli.StringFlag{ + Name: "owner", + Aliases: []string{"o"}, + Usage: "owner key to use for new miner initialisation", + }, + &cli.StringFlag{ + Name: "from", + Aliases: []string{"f"}, + Usage: "address to send actor(miner) creation message from", + }, + &cli.StringFlag{ + Name: "sector-size", + Usage: "specify sector size to use for new miner initialisation", + }, + }, + Action: func(cctx *cli.Context) error { + ctx := cctx.Context + + full, closer, err := cliutil.GetFullNodeAPIV1(cctx) + if err != nil { + return xerrors.Errorf("connecting to full node: %w", err) + } + defer closer() + + var owner address.Address + if cctx.String("owner") == "" { + return xerrors.Errorf("must provide a owner address") + } + owner, err = address.NewFromString(cctx.String("owner")) + + if err != nil { + return err + } + + worker := owner + if cctx.String("worker") != "" { + worker, err = address.NewFromString(cctx.String("worker")) + if err != nil { + return xerrors.Errorf("could not parse worker address: %w", err) + } + } + + sender := owner + if fromstr := cctx.String("from"); fromstr != "" { + faddr, err := address.NewFromString(fromstr) + if err != nil { + return xerrors.Errorf("could not parse from address: %w", err) + } + sender = faddr + } + + if !cctx.IsSet("sector-size") { + return xerrors.Errorf("must define sector size") + } + + sectorSizeInt, err := units.RAMInBytes(cctx.String("sector-size")) + if err != nil { + return err + } + ssize := abi.SectorSize(sectorSizeInt) + + _, err = CreateStorageMiner(ctx, full, owner, worker, sender, ssize, cctx.Uint64("confidence")) + if err != nil { + return err + } + return nil + }, +} + +func CreateStorageMiner(ctx context.Context, fullNode v1api.FullNode, owner, worker, sender address.Address, ssize abi.SectorSize, confidence uint64) (address.Address, error) { + // make sure the sender account exists on chain + _, err := fullNode.StateLookupID(ctx, owner, types.EmptyTSK) + if err != nil { + return address.Undef, xerrors.Errorf("sender must exist on chain: %w", err) + } + + // make sure the worker account exists on chain + _, err = fullNode.StateLookupID(ctx, worker, types.EmptyTSK) + if err != nil { + signed, err := fullNode.MpoolPushMessage(ctx, &types.Message{ + From: sender, + To: worker, + Value: types.NewInt(0), + }, nil) + if err != nil { + return address.Undef, xerrors.Errorf("push worker init: %w", err) + } + + fmt.Printf("Initializing worker account %s, message: %s\n", worker, signed.Cid()) + fmt.Println("Waiting for confirmation") + + mw, err := fullNode.StateWaitMsg(ctx, signed.Cid(), confidence, 2000, true) + if err != nil { + return address.Undef, xerrors.Errorf("waiting for worker init: %w", err) + } + if mw.Receipt.ExitCode != 0 { + return address.Undef, xerrors.Errorf("initializing worker account failed: exit code %d", mw.Receipt.ExitCode) + } + } + + // make sure the owner account exists on chain + _, err = fullNode.StateLookupID(ctx, owner, types.EmptyTSK) + if err != nil { + signed, err := fullNode.MpoolPushMessage(ctx, &types.Message{ + From: sender, + To: owner, + Value: types.NewInt(0), + }, nil) + if err != nil { + return address.Undef, xerrors.Errorf("push owner init: %w", err) + } + + fmt.Printf("Initializing owner account %s, message: %s\n", worker, signed.Cid()) + fmt.Println("Waiting for confirmation") + + mw, err := fullNode.StateWaitMsg(ctx, signed.Cid(), confidence, 2000, true) + if err != nil { + return address.Undef, xerrors.Errorf("waiting for owner init: %w", err) + } + if mw.Receipt.ExitCode != 0 { + return address.Undef, xerrors.Errorf("initializing owner account failed: exit code %d", mw.Receipt.ExitCode) + } + } + + // Note: the correct thing to do would be to call SealProofTypeFromSectorSize if actors version is v3 or later, but this still works + nv, err := fullNode.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return address.Undef, xerrors.Errorf("failed to get network version: %w", err) + } + spt, err := lminer.WindowPoStProofTypeFromSectorSize(ssize, nv) + if err != nil { + return address.Undef, xerrors.Errorf("getting post proof type: %w", err) + } + + params, err := actors.SerializeParams(&power6.CreateMinerParams{ + Owner: owner, + Worker: worker, + WindowPoStProofType: spt, + }) + if err != nil { + return address.Undef, err + } + + createStorageMinerMsg := &types.Message{ + To: power.Address, + From: sender, + Value: big.Zero(), + + Method: power.Methods.CreateMiner, + Params: params, + } + + signed, err := fullNode.MpoolPushMessage(ctx, createStorageMinerMsg, nil) + if err != nil { + return address.Undef, xerrors.Errorf("pushing createMiner message: %w", err) + } + + fmt.Printf("Pushed CreateMiner message: %s\n", signed.Cid()) + fmt.Println("Waiting for confirmation") + + mw, err := fullNode.StateWaitMsg(ctx, signed.Cid(), confidence, 2000, true) + if err != nil { + return address.Undef, xerrors.Errorf("waiting for createMiner message: %w", err) + } + + if mw.Receipt.ExitCode != 0 { + return address.Undef, xerrors.Errorf("create miner failed: exit code %d", mw.Receipt.ExitCode) + } + + var retval power2.CreateMinerReturn + if err := retval.UnmarshalCBOR(bytes.NewReader(mw.Receipt.Return)); err != nil { + return address.Undef, err + } + + fmt.Printf("New miners address is: %s (%s)\n", retval.IDAddress, retval.RobustAddress) + return retval.IDAddress, nil +} diff --git a/cli/spcli/info.go b/cli/spcli/info.go new file mode 100644 index 00000000000..69436b2c7d5 --- /dev/null +++ b/cli/spcli/info.go @@ -0,0 +1,121 @@ +package spcli + +import ( + "fmt" + + "github.com/fatih/color" + "github.com/multiformats/go-multiaddr" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + cliutil "github.com/filecoin-project/lotus/cli/util" +) + +func InfoCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "info", + Usage: "Print miner actor info", + Action: func(cctx *cli.Context) error { + api, closer, err := cliutil.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := cliutil.ReqContext(cctx) + + ts, err := lcli.LoadTipSet(ctx, cctx, api) + if err != nil { + return err + } + + addr, err := getActorAddress(cctx) + if err != nil { + return err + } + mi, err := api.StateMinerInfo(ctx, addr, ts.Key()) + if err != nil { + return err + } + + availableBalance, err := api.StateMinerAvailableBalance(ctx, addr, ts.Key()) + if err != nil { + return xerrors.Errorf("getting miner available balance: %w", err) + } + fmt.Printf("Available Balance: %s\n", types.FIL(availableBalance)) + fmt.Printf("Owner:\t%s\n", mi.Owner) + fmt.Printf("Worker:\t%s\n", mi.Worker) + for i, controlAddress := range mi.ControlAddresses { + fmt.Printf("Control %d: \t%s\n", i, controlAddress) + } + if mi.Beneficiary != address.Undef { + fmt.Printf("Beneficiary:\t%s\n", mi.Beneficiary) + if mi.Beneficiary != mi.Owner { + fmt.Printf("Beneficiary Quota:\t%s\n", mi.BeneficiaryTerm.Quota) + fmt.Printf("Beneficiary Used Quota:\t%s\n", mi.BeneficiaryTerm.UsedQuota) + fmt.Printf("Beneficiary Expiration:\t%s\n", mi.BeneficiaryTerm.Expiration) + } + } + if mi.PendingBeneficiaryTerm != nil { + fmt.Printf("Pending Beneficiary Term:\n") + fmt.Printf("New Beneficiary:\t%s\n", mi.PendingBeneficiaryTerm.NewBeneficiary) + fmt.Printf("New Quota:\t%s\n", mi.PendingBeneficiaryTerm.NewQuota) + fmt.Printf("New Expiration:\t%s\n", mi.PendingBeneficiaryTerm.NewExpiration) + fmt.Printf("Approved By Beneficiary:\t%t\n", mi.PendingBeneficiaryTerm.ApprovedByBeneficiary) + fmt.Printf("Approved By Nominee:\t%t\n", mi.PendingBeneficiaryTerm.ApprovedByNominee) + } + + fmt.Printf("PeerID:\t%s\n", mi.PeerId) + fmt.Printf("Multiaddrs:\t") + for _, addr := range mi.Multiaddrs { + a, err := multiaddr.NewMultiaddrBytes(addr) + if err != nil { + return xerrors.Errorf("undecodable listen address: %w", err) + } + fmt.Printf("%s ", a) + } + fmt.Println() + fmt.Printf("Consensus Fault End:\t%d\n", mi.ConsensusFaultElapsed) + + fmt.Printf("SectorSize:\t%s (%d)\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize))), mi.SectorSize) + pow, err := api.StateMinerPower(ctx, addr, ts.Key()) + if err != nil { + return err + } + + fmt.Printf("Byte Power: %s / %s (%0.4f%%)\n", + color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)), + types.SizeStr(pow.TotalPower.RawBytePower), + types.BigDivFloat( + types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)), + pow.TotalPower.RawBytePower, + ), + ) + + fmt.Printf("Actual Power: %s / %s (%0.4f%%)\n", + color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)), + types.DeciStr(pow.TotalPower.QualityAdjPower), + types.BigDivFloat( + types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)), + pow.TotalPower.QualityAdjPower, + ), + ) + + fmt.Println() + + cd, err := api.StateMinerProvingDeadline(ctx, addr, ts.Key()) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + fmt.Printf("Proving Period Start:\t%s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.PeriodStart)) + + return nil + }, + } +} diff --git a/cli/spcli/proving.go b/cli/spcli/proving.go new file mode 100644 index 00000000000..ed4251f1b3c --- /dev/null +++ b/cli/spcli/proving.go @@ -0,0 +1,451 @@ +package spcli + +import ( + "bytes" + "fmt" + "os" + "strconv" + "strings" + "text/tabwriter" + "time" + + "github.com/fatih/color" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/dline" + + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + cliutil "github.com/filecoin-project/lotus/cli/util" +) + +func ProvingInfoCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "info", + Usage: "View current state information", + Action: func(cctx *cli.Context) error { + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + + head, err := api.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("getting chain head: %w", err) + } + + mact, err := api.StateGetActor(ctx, maddr, head.Key()) + if err != nil { + return err + } + + stor := store.ActorStore(ctx, blockstore.NewAPIBlockstore(api)) + + mas, err := miner.Load(stor, mact) + if err != nil { + return err + } + + cd, err := api.StateMinerProvingDeadline(ctx, maddr, head.Key()) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) + + proving := uint64(0) + faults := uint64(0) + recovering := uint64(0) + curDeadlineSectors := uint64(0) + + if err := mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { + return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { + if bf, err := part.LiveSectors(); err != nil { + return err + } else if count, err := bf.Count(); err != nil { + return err + } else { + proving += count + if dlIdx == cd.Index { + curDeadlineSectors += count + } + } + + if bf, err := part.FaultySectors(); err != nil { + return err + } else if count, err := bf.Count(); err != nil { + return err + } else { + faults += count + } + + if bf, err := part.RecoveringSectors(); err != nil { + return err + } else if count, err := bf.Count(); err != nil { + return err + } else { + recovering += count + } + + return nil + }) + }); err != nil { + return xerrors.Errorf("walking miner deadlines and partitions: %w", err) + } + + var faultPerc float64 + if proving > 0 { + faultPerc = float64(faults * 100 / proving) + } + + fmt.Printf("Current Epoch: %d\n", cd.CurrentEpoch) + + fmt.Printf("Proving Period Boundary: %d\n", cd.PeriodStart%cd.WPoStProvingPeriod) + fmt.Printf("Proving Period Start: %s\n", cliutil.EpochTimeTs(cd.CurrentEpoch, cd.PeriodStart, head)) + fmt.Printf("Next Period Start: %s\n\n", cliutil.EpochTimeTs(cd.CurrentEpoch, cd.PeriodStart+cd.WPoStProvingPeriod, head)) + + fmt.Printf("Faults: %d (%.2f%%)\n", faults, faultPerc) + fmt.Printf("Recovering: %d\n", recovering) + + fmt.Printf("Deadline Index: %d\n", cd.Index) + fmt.Printf("Deadline Sectors: %d\n", curDeadlineSectors) + fmt.Printf("Deadline Open: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.Open)) + fmt.Printf("Deadline Close: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.Close)) + fmt.Printf("Deadline Challenge: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.Challenge)) + fmt.Printf("Deadline FaultCutoff: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.FaultCutoff)) + return nil + }, + } +} + +func ProvingDeadlinesCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "deadlines", + Usage: "View the current proving period deadlines information", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "all", + Usage: "Count all sectors (only live sectors are counted by default)", + Aliases: []string{"a"}, + }, + }, + Action: func(cctx *cli.Context) error { + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + + deadlines, err := api.StateMinerDeadlines(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting deadlines: %w", err) + } + + di, err := api.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting deadlines: %w", err) + } + + head, err := api.ChainHead(ctx) + if err != nil { + return err + } + + fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) + + tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) + _, _ = fmt.Fprintln(tw, "deadline\topen\tpartitions\tsectors (faults)\tproven partitions") + + for dlIdx, deadline := range deadlines { + partitions, err := api.StateMinerPartitions(ctx, maddr, uint64(dlIdx), types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting partitions for deadline %d: %w", dlIdx, err) + } + + provenPartitions, err := deadline.PostSubmissions.Count() + if err != nil { + return err + } + + sectors := uint64(0) + faults := uint64(0) + var partitionCount int + + for _, partition := range partitions { + if !cctx.Bool("all") { + sc, err := partition.LiveSectors.Count() + if err != nil { + return err + } + + if sc > 0 { + partitionCount++ + } + + sectors += sc + } else { + sc, err := partition.AllSectors.Count() + if err != nil { + return err + } + + partitionCount++ + sectors += sc + } + + fc, err := partition.FaultySectors.Count() + if err != nil { + return err + } + + faults += fc + } + + var cur string + if di.Index == uint64(dlIdx) { + cur += "\t(current)" + } + + _, _ = fmt.Fprintf(tw, "%d\t%s\t%d\t%d (%d)\t%d%s\n", dlIdx, deadlineOpenTime(head, uint64(dlIdx), di), + partitionCount, sectors, faults, provenPartitions, cur) + } + + return tw.Flush() + }, + } +} + +func deadlineOpenTime(ts *types.TipSet, dlIdx uint64, di *dline.Info) string { + gapIdx := dlIdx - di.Index + gapHeight := uint64(di.WPoStProvingPeriod) / di.WPoStPeriodDeadlines * gapIdx + + openHeight := di.Open + abi.ChainEpoch(gapHeight) + genesisBlockTimestamp := ts.MinTimestamp() - uint64(ts.Height())*build.BlockDelaySecs + + return time.Unix(int64(genesisBlockTimestamp+build.BlockDelaySecs*uint64(openHeight)), 0).Format(time.TimeOnly) +} + +func ProvingDeadlineInfoCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "deadline", + Usage: "View the current proving period deadline information by its index", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "sector-nums", + Aliases: []string{"n"}, + Usage: "Print sector/fault numbers belonging to this deadline", + }, + &cli.BoolFlag{ + Name: "bitfield", + Aliases: []string{"b"}, + Usage: "Print partition bitfield stats", + }, + }, + ArgsUsage: "", + Action: func(cctx *cli.Context) error { + + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + dlIdx, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64) + if err != nil { + return xerrors.Errorf("could not parse deadline index: %w", err) + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + + deadlines, err := api.StateMinerDeadlines(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting deadlines: %w", err) + } + + di, err := api.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting deadlines: %w", err) + } + + partitions, err := api.StateMinerPartitions(ctx, maddr, dlIdx, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting partitions for deadline %d: %w", dlIdx, err) + } + + head, err := api.ChainHead(ctx) + if err != nil { + return err + } + + provenPartitions, err := deadlines[dlIdx].PostSubmissions.Count() + if err != nil { + return err + } + + fmt.Printf("Deadline Index: %d\n", dlIdx) + fmt.Printf("Deadline Open: %s\n", deadlineOpenTime(head, dlIdx, di)) + fmt.Printf("Partitions: %d\n", len(partitions)) + fmt.Printf("Proven Partitions: %d\n", provenPartitions) + fmt.Printf("Current: %t\n\n", di.Index == dlIdx) + + for pIdx, partition := range partitions { + fmt.Printf("Partition Index: %d\n", pIdx) + + printStats := func(bf bitfield.BitField, name string) error { + count, err := bf.Count() + if err != nil { + return err + } + + rit, err := bf.RunIterator() + if err != nil { + return err + } + + if cctx.Bool("bitfield") { + var ones, zeros, oneRuns, zeroRuns, invalid uint64 + for rit.HasNext() { + r, err := rit.NextRun() + if err != nil { + return xerrors.Errorf("next run: %w", err) + } + if !r.Valid() { + invalid++ + } + if r.Val { + ones += r.Len + oneRuns++ + } else { + zeros += r.Len + zeroRuns++ + } + } + + var buf bytes.Buffer + if err := bf.MarshalCBOR(&buf); err != nil { + return err + } + sz := len(buf.Bytes()) + szstr := types.SizeStr(types.NewInt(uint64(sz))) + + fmt.Printf("\t%s Sectors:%s%d (bitfield - runs %d+%d=%d - %d 0s %d 1s - %d inv - %s %dB)\n", name, strings.Repeat(" ", 18-len(name)), count, zeroRuns, oneRuns, zeroRuns+oneRuns, zeros, ones, invalid, szstr, sz) + } else { + fmt.Printf("\t%s Sectors:%s%d\n", name, strings.Repeat(" ", 18-len(name)), count) + } + + if cctx.Bool("sector-nums") { + nums, err := bf.All(count) + if err != nil { + return err + } + fmt.Printf("\t%s Sector Numbers:%s%v\n", name, strings.Repeat(" ", 12-len(name)), nums) + } + + return nil + } + + if err := printStats(partition.AllSectors, "All"); err != nil { + return err + } + if err := printStats(partition.LiveSectors, "Live"); err != nil { + return err + } + if err := printStats(partition.ActiveSectors, "Active"); err != nil { + return err + } + if err := printStats(partition.FaultySectors, "Faulty"); err != nil { + return err + } + if err := printStats(partition.RecoveringSectors, "Recovering"); err != nil { + return err + } + } + return nil + }, + } +} + +func ProvingFaultsCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "faults", + Usage: "View the currently known proving faulty sectors information", + Action: func(cctx *cli.Context) error { + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + stor := store.ActorStore(ctx, blockstore.NewAPIBlockstore(api)) + + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + + mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + mas, err := miner.Load(stor, mact) + if err != nil { + return err + } + + fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) + + tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) + _, _ = fmt.Fprintln(tw, "deadline\tpartition\tsectors") + err = mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { + return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { + faults, err := part.FaultySectors() + if err != nil { + return err + } + return faults.ForEach(func(num uint64) error { + _, _ = fmt.Fprintf(tw, "%d\t%d\t%d\n", dlIdx, partIdx, num) + return nil + }) + }) + }) + if err != nil { + return err + } + return tw.Flush() + }, + } +} diff --git a/cli/spcli/sectors.go b/cli/spcli/sectors.go new file mode 100644 index 00000000000..95acbcd111e --- /dev/null +++ b/cli/spcli/sectors.go @@ -0,0 +1,1458 @@ +package spcli + +import ( + "bufio" + "context" + "encoding/csv" + "encoding/json" + "errors" + "fmt" + "math" + "os" + "sort" + "strconv" + "strings" + "sync" + "time" + + "github.com/fatih/color" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/samber/lo" + "github.com/urfave/cli/v2" + "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/big" + "github.com/filecoin-project/go-state-types/builtin" + miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/miner" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" + "github.com/filecoin-project/lotus/chain/actors/policy" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/lib/tablewriter" +) + +type OnDiskInfoGetter func(cctx *cli.Context, id abi.SectorNumber, onChainInfo bool) (api.SectorInfo, error) + +func SectorsStatusCmd(getActorAddress ActorAddressGetter, getOnDiskInfo OnDiskInfoGetter) *cli.Command { + return &cli.Command{ + Name: "status", + Usage: "Get the seal status of a sector by its number", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "log", + Usage: "display event log", + Aliases: []string{"l"}, + }, + &cli.BoolFlag{ + Name: "on-chain-info", + Usage: "show sector on chain info", + Aliases: []string{"c"}, + }, + &cli.BoolFlag{ + Name: "partition-info", + Usage: "show partition related info", + Aliases: []string{"p"}, + }, + &cli.BoolFlag{ + Name: "proof", + Usage: "print snark proof bytes as hex", + }, + }, + Action: func(cctx *cli.Context) error { + ctx := lcli.ReqContext(cctx) + + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + id, err := strconv.ParseUint(cctx.Args().First(), 10, 64) + if err != nil { + return err + } + + onChainInfo := cctx.Bool("on-chain-info") + + var status api.SectorInfo + if getOnDiskInfo != nil { + status, err = getOnDiskInfo(cctx, abi.SectorNumber(id), onChainInfo) + if err != nil { + return err + } + fmt.Printf("SectorID:\t%d\n", status.SectorID) + fmt.Printf("Status:\t\t%s\n", status.State) + fmt.Printf("CIDcommD:\t%s\n", status.CommD) + fmt.Printf("CIDcommR:\t%s\n", status.CommR) + fmt.Printf("Ticket:\t\t%x\n", status.Ticket.Value) + fmt.Printf("TicketH:\t%d\n", status.Ticket.Epoch) + fmt.Printf("Seed:\t\t%x\n", status.Seed.Value) + fmt.Printf("SeedH:\t\t%d\n", status.Seed.Epoch) + fmt.Printf("Precommit:\t%s\n", status.PreCommitMsg) + fmt.Printf("Commit:\t\t%s\n", status.CommitMsg) + if cctx.Bool("proof") { + fmt.Printf("Proof:\t\t%x\n", status.Proof) + } + fmt.Printf("Deals:\t\t%v\n", status.Deals) + fmt.Printf("Retries:\t%d\n", status.Retries) + if status.LastErr != "" { + fmt.Printf("Last Error:\t\t%s\n", status.LastErr) + } + + fmt.Printf("\nExpiration Info\n") + fmt.Printf("OnTime:\t\t%v\n", status.OnTime) + fmt.Printf("Early:\t\t%v\n", status.Early) + + var pamsHeaderOnce sync.Once + + for pi, piece := range status.Pieces { + if piece.DealInfo == nil { + continue + } + if piece.DealInfo.PieceActivationManifest == nil { + continue + } + pamsHeaderOnce.Do(func() { + fmt.Printf("\nPiece Activation Manifests\n") + }) + + pam := piece.DealInfo.PieceActivationManifest + + fmt.Printf("Piece %d: %s %s verif-alloc:%+v\n", pi, pam.CID, types.SizeStr(types.NewInt(uint64(pam.Size))), pam.VerifiedAllocationKey) + for ni, notification := range pam.Notify { + fmt.Printf("\tNotify %d: %s (%x)\n", ni, notification.Address, notification.Payload) + } + } + + } else { + onChainInfo = true + } + + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + + if onChainInfo { + fullApi, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + head, err := fullApi.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("getting chain head: %w", err) + } + + status, err := fullApi.StateSectorGetInfo(ctx, maddr, abi.SectorNumber(id), head.Key()) + if err != nil { + return err + } + + mid, err := address.IDFromAddress(maddr) + if err != nil { + return err + } + fmt.Printf("\nSector On Chain Info\n") + fmt.Printf("SealProof:\t\t%x\n", status.SealProof) + fmt.Printf("Activation:\t\t%v\n", cliutil.EpochTime(head.Height(), status.Activation)) + fmt.Printf("Expiration:\t\t%s\n", cliutil.EpochTime(head.Height(), status.Expiration)) + fmt.Printf("DealWeight:\t\t%v\n", status.DealWeight) + fmt.Printf("VerifiedDealWeight:\t\t%v\n", status.VerifiedDealWeight) + fmt.Printf("InitialPledge:\t\t%v\n", types.FIL(status.InitialPledge)) + fmt.Printf("SectorID:\t\t{Miner: %v, Number: %v}\n", abi.ActorID(mid), status.SectorNumber) + } + + if cctx.Bool("partition-info") { + fullApi, nCloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer nCloser() + + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + + mact, err := fullApi.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(fullApi), blockstore.NewMemory()) + mas, err := miner.Load(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), mact) + if err != nil { + return err + } + + errFound := errors.New("found") + if err := mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { + return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { + pas, err := part.AllSectors() + if err != nil { + return err + } + + set, err := pas.IsSet(id) + if err != nil { + return err + } + if set { + fmt.Printf("\nDeadline:\t%d\n", dlIdx) + fmt.Printf("Partition:\t%d\n", partIdx) + + checkIn := func(name string, bg func() (bitfield.BitField, error)) error { + bf, err := bg() + if err != nil { + return err + } + + set, err := bf.IsSet(id) + if err != nil { + return err + } + setstr := "no" + if set { + setstr = "yes" + } + fmt.Printf("%s: \t%s\n", name, setstr) + return nil + } + + if err := checkIn("Unproven", part.UnprovenSectors); err != nil { + return err + } + if err := checkIn("Live", part.LiveSectors); err != nil { + return err + } + if err := checkIn("Active", part.ActiveSectors); err != nil { + return err + } + if err := checkIn("Faulty", part.FaultySectors); err != nil { + return err + } + if err := checkIn("Recovering", part.RecoveringSectors); err != nil { + return err + } + + return errFound + } + + return nil + }) + }); err != errFound { + if err != nil { + return err + } + + fmt.Println("\nNot found in any partition") + } + } + + if cctx.Bool("log") { + fmt.Printf("--------\nEvent Log:\n") + + for i, l := range status.Log { + fmt.Printf("%d.\t%s:\t[%s]\t%s\n", i, time.Unix(int64(l.Timestamp), 0), l.Kind, l.Message) + if l.Trace != "" { + fmt.Printf("\t%s\n", l.Trace) + } + } + } + return nil + }, + } +} + +func SectorsListUpgradeBoundsCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "upgrade-bounds", + Usage: "Output upgrade bounds for available sectors", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "buckets", + Value: 25, + }, + &cli.BoolFlag{ + Name: "csv", + Usage: "output machine-readable values", + }, + &cli.BoolFlag{ + Name: "deal-terms", + Usage: "bucket by how many deal-sectors can start at a given expiration", + }, + }, + Action: func(cctx *cli.Context) error { + fullApi, closer2, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer2() + + ctx := lcli.ReqContext(cctx) + + head, err := fullApi.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("getting chain head: %w", err) + } + + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + + list, err := fullApi.StateMinerActiveSectors(ctx, maddr, head.Key()) + if err != nil { + return err + } + filter := bitfield.New() + + for _, s := range list { + filter.Set(uint64(s.SectorNumber)) + } + sset, err := fullApi.StateMinerSectors(ctx, maddr, &filter, head.Key()) + if err != nil { + return err + } + + if len(sset) == 0 { + return nil + } + + var minExpiration, maxExpiration abi.ChainEpoch + + for _, s := range sset { + if s.Expiration < minExpiration || minExpiration == 0 { + minExpiration = s.Expiration + } + if s.Expiration > maxExpiration { + maxExpiration = s.Expiration + } + } + + buckets := cctx.Int("buckets") + bucketSize := (maxExpiration - minExpiration) / abi.ChainEpoch(buckets) + bucketCounts := make([]int, buckets+1) + + for b := range bucketCounts { + bucketMin := minExpiration + abi.ChainEpoch(b)*bucketSize + bucketMax := minExpiration + abi.ChainEpoch(b+1)*bucketSize + + if cctx.Bool("deal-terms") { + bucketMax = bucketMax + policy.MarketDefaultAllocationTermBuffer + } + + for _, s := range sset { + isInBucket := s.Expiration >= bucketMin && s.Expiration < bucketMax + + if isInBucket { + bucketCounts[b]++ + } + } + + } + + // Creating CSV writer + writer := csv.NewWriter(os.Stdout) + + // Writing CSV headers + err = writer.Write([]string{"Max Expiration in Bucket", "Sector Count"}) + if err != nil { + return xerrors.Errorf("writing csv headers: %w", err) + } + + // Writing bucket details + + if cctx.Bool("csv") { + for i := 0; i < buckets; i++ { + maxExp := minExpiration + abi.ChainEpoch(i+1)*bucketSize + + timeStr := strconv.FormatInt(int64(maxExp), 10) + + err = writer.Write([]string{ + timeStr, + strconv.Itoa(bucketCounts[i]), + }) + if err != nil { + return xerrors.Errorf("writing csv row: %w", err) + } + } + + // Flush to make sure all data is written to the underlying writer + writer.Flush() + + if err := writer.Error(); err != nil { + return xerrors.Errorf("flushing csv writer: %w", err) + } + + return nil + } + + tw := tablewriter.New( + tablewriter.Col("Bucket Expiration"), + tablewriter.Col("Sector Count"), + tablewriter.Col("Bar"), + ) + + var barCols = 40 + var maxCount int + + for _, c := range bucketCounts { + if c > maxCount { + maxCount = c + } + } + + for i := 0; i < buckets; i++ { + maxExp := minExpiration + abi.ChainEpoch(i+1)*bucketSize + timeStr := cliutil.EpochTime(head.Height(), maxExp) + + tw.Write(map[string]interface{}{ + "Bucket Expiration": timeStr, + "Sector Count": color.YellowString("%d", bucketCounts[i]), + "Bar": "[" + color.GreenString(strings.Repeat("|", bucketCounts[i]*barCols/maxCount)) + strings.Repeat(" ", barCols-bucketCounts[i]*barCols/maxCount) + "]", + }) + } + + return tw.Flush(os.Stdout) + }, + } +} + +func SectorPreCommitsCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "precommits", + Usage: "Print on-chain precommit info", + Action: func(cctx *cli.Context) error { + ctx := lcli.ReqContext(cctx) + mapi, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + mact, err := mapi.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(mapi))) + mst, err := miner.Load(store, mact) + if err != nil { + return err + } + preCommitSector := make([]miner.SectorPreCommitOnChainInfo, 0) + err = mst.ForEachPrecommittedSector(func(info miner.SectorPreCommitOnChainInfo) error { + preCommitSector = append(preCommitSector, info) + return err + }) + less := func(i, j int) bool { + return preCommitSector[i].Info.SectorNumber <= preCommitSector[j].Info.SectorNumber + } + sort.Slice(preCommitSector, less) + for _, info := range preCommitSector { + fmt.Printf("%s: %s\n", info.Info.SectorNumber, info.PreCommitEpoch) + } + + return nil + }, + } +} + +func SectorsCheckExpireCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "check-expire", + Usage: "Inspect expiring sectors", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "cutoff", + Usage: "skip sectors whose current expiration is more than epochs from now, defaults to 60 days", + Value: 172800, + }, + }, + Action: func(cctx *cli.Context) error { + + fullApi, nCloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer nCloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + + head, err := fullApi.ChainHead(ctx) + if err != nil { + return err + } + currEpoch := head.Height() + + nv, err := fullApi.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return err + } + + sectors, err := fullApi.StateMinerActiveSectors(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + n := 0 + for _, s := range sectors { + if s.Expiration-currEpoch <= abi.ChainEpoch(cctx.Int64("cutoff")) { + sectors[n] = s + n++ + } + } + sectors = sectors[:n] + + sort.Slice(sectors, func(i, j int) bool { + if sectors[i].Expiration == sectors[j].Expiration { + return sectors[i].SectorNumber < sectors[j].SectorNumber + } + return sectors[i].Expiration < sectors[j].Expiration + }) + + tw := tablewriter.New( + tablewriter.Col("ID"), + tablewriter.Col("SealProof"), + tablewriter.Col("InitialPledge"), + tablewriter.Col("Activation"), + tablewriter.Col("Expiration"), + tablewriter.Col("MaxExpiration"), + tablewriter.Col("MaxExtendNow")) + + for _, sector := range sectors { + MaxExpiration := sector.Activation + policy.GetSectorMaxLifetime(sector.SealProof, nv) + maxExtension, err := policy.GetMaxSectorExpirationExtension(nv) + if err != nil { + return xerrors.Errorf("failed to get max extension: %w", err) + } + + MaxExtendNow := currEpoch + maxExtension + + if MaxExtendNow > MaxExpiration { + MaxExtendNow = MaxExpiration + } + + tw.Write(map[string]interface{}{ + "ID": sector.SectorNumber, + "SealProof": sector.SealProof, + "InitialPledge": types.FIL(sector.InitialPledge).Short(), + "Activation": cliutil.EpochTime(currEpoch, sector.Activation), + "Expiration": cliutil.EpochTime(currEpoch, sector.Expiration), + "MaxExpiration": cliutil.EpochTime(currEpoch, MaxExpiration), + "MaxExtendNow": cliutil.EpochTime(currEpoch, MaxExtendNow), + }) + } + + return tw.Flush(os.Stdout) + }, + } +} + +func SectorsExtendCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "extend", + Usage: "Extend expiring sectors while not exceeding each sector's max life", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "from", + Usage: "only consider sectors whose current expiration epoch is in the range of [from, to], defaults to: now + 120 (1 hour)", + }, + &cli.Int64Flag{ + Name: "to", + Usage: "only consider sectors whose current expiration epoch is in the range of [from, to], defaults to: now + 92160 (32 days)", + }, + &cli.StringFlag{ + Name: "sector-file", + Usage: "provide a file containing one sector number in each line, ignoring above selecting criteria", + }, + &cli.StringFlag{ + Name: "exclude", + Usage: "optionally provide a file containing excluding sectors", + }, + &cli.Int64Flag{ + Name: "extension", + Usage: "try to extend selected sectors by this number of epochs, defaults to 540 days", + Value: 1555200, + }, + &cli.Int64Flag{ + Name: "new-expiration", + Usage: "try to extend selected sectors to this epoch, ignoring extension", + }, + &cli.BoolFlag{ + Name: "only-cc", + Usage: "only extend CC sectors (useful for making sector ready for snap upgrade)", + }, + &cli.BoolFlag{ + Name: "drop-claims", + Usage: "drop claims for sectors that can be extended, but only by dropping some of their verified power claims", + }, + &cli.Int64Flag{ + Name: "tolerance", + Usage: "don't try to extend sectors by fewer than this number of epochs, defaults to 7 days", + Value: 20160, + }, + &cli.StringFlag{ + Name: "max-fee", + 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", + }, + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "pass this flag to really extend sectors, otherwise will only print out json representation of parameters", + }, + }, + Action: func(cctx *cli.Context) error { + mf, err := types.ParseFIL(cctx.String("max-fee")) + if err != nil { + return err + } + + spec := &api.MessageSendSpec{MaxFee: abi.TokenAmount(mf)} + + fullApi, nCloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer nCloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + + head, err := fullApi.ChainHead(ctx) + if err != nil { + return err + } + currEpoch := head.Height() + + nv, err := fullApi.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return err + } + + activeSet, err := fullApi.StateMinerActiveSectors(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + activeSectorsInfo := make(map[abi.SectorNumber]*miner.SectorOnChainInfo, len(activeSet)) + for _, info := range activeSet { + activeSectorsInfo[info.SectorNumber] = info + } + + mact, err := fullApi.StateGetActor(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(fullApi), blockstore.NewMemory()) + adtStore := adt.WrapStore(ctx, cbor.NewCborStore(tbs)) + mas, err := miner.Load(adtStore, mact) + if err != nil { + return err + } + + activeSectorsLocation := make(map[abi.SectorNumber]*miner.SectorLocation, len(activeSet)) + + if err := mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { + return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { + pas, err := part.ActiveSectors() + if err != nil { + return err + } + + return pas.ForEach(func(i uint64) error { + activeSectorsLocation[abi.SectorNumber(i)] = &miner.SectorLocation{ + Deadline: dlIdx, + Partition: partIdx, + } + return nil + }) + }) + }); err != nil { + return err + } + + excludeSet := make(map[abi.SectorNumber]struct{}) + if cctx.IsSet("exclude") { + excludeSectors, err := getSectorsFromFile(cctx.String("exclude")) + if err != nil { + return err + } + + for _, id := range excludeSectors { + excludeSet[id] = struct{}{} + } + } + + var sectors []abi.SectorNumber + if cctx.Args().Present() { + if cctx.IsSet("sector-file") { + return xerrors.Errorf("sector-file specified along with command line params") + } + + for i, s := range cctx.Args().Slice() { + id, err := strconv.ParseUint(s, 10, 64) + if err != nil { + return xerrors.Errorf("could not parse sector %d: %w", i, err) + } + + sectors = append(sectors, abi.SectorNumber(id)) + } + } else if cctx.IsSet("sector-file") { + sectors, err = getSectorsFromFile(cctx.String("sector-file")) + if err != nil { + return err + } + } else { + from := currEpoch + 120 + to := currEpoch + 92160 + + if cctx.IsSet("from") { + from = abi.ChainEpoch(cctx.Int64("from")) + } + + if cctx.IsSet("to") { + to = abi.ChainEpoch(cctx.Int64("to")) + } + + for _, si := range activeSet { + if si.Expiration >= from && si.Expiration <= to { + sectors = append(sectors, si.SectorNumber) + } + } + } + + var sis []*miner.SectorOnChainInfo + for _, id := range sectors { + if _, exclude := excludeSet[id]; exclude { + continue + } + + si, found := activeSectorsInfo[id] + if !found { + return xerrors.Errorf("sector %d is not active", id) + } + if len(si.DealIDs) > 0 && cctx.Bool("only-cc") { + continue + } + + sis = append(sis, si) + } + + withinTolerance := func(a, b abi.ChainEpoch) bool { + diff := a - b + if diff < 0 { + diff = -diff + } + + return diff <= abi.ChainEpoch(cctx.Int64("tolerance")) + } + + extensions := map[miner.SectorLocation]map[abi.ChainEpoch][]abi.SectorNumber{} + for _, si := range sis { + extension := abi.ChainEpoch(cctx.Int64("extension")) + newExp := si.Expiration + extension + + if cctx.IsSet("new-expiration") { + newExp = abi.ChainEpoch(cctx.Int64("new-expiration")) + } + + maxExtension, err := policy.GetMaxSectorExpirationExtension(nv) + if err != nil { + return xerrors.Errorf("failed to get max extension: %w", err) + } + + maxExtendNow := currEpoch + maxExtension + if newExp > maxExtendNow { + newExp = maxExtendNow + } + + maxExp := si.Activation + policy.GetSectorMaxLifetime(si.SealProof, nv) + if newExp > maxExp { + newExp = maxExp + } + + if newExp <= si.Expiration || withinTolerance(newExp, si.Expiration) { + continue + } + + l, found := activeSectorsLocation[si.SectorNumber] + if !found { + return xerrors.Errorf("location for sector %d not found", si.SectorNumber) + } + + es, found := extensions[*l] + if !found { + ne := make(map[abi.ChainEpoch][]abi.SectorNumber) + ne[newExp] = []abi.SectorNumber{si.SectorNumber} + extensions[*l] = ne + } else { + added := false + for exp := range es { + if withinTolerance(newExp, exp) { + es[exp] = append(es[exp], si.SectorNumber) + added = true + break + } + } + + if !added { + es[newExp] = []abi.SectorNumber{si.SectorNumber} + } + } + } + + verifregAct, err := fullApi.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("failed to lookup verifreg actor: %w", err) + } + + verifregSt, err := verifreg.Load(adtStore, verifregAct) + if err != nil { + return xerrors.Errorf("failed to load verifreg state: %w", err) + } + + claimsMap, err := verifregSt.GetClaims(maddr) + if err != nil { + return xerrors.Errorf("failed to lookup claims for miner: %w", err) + } + + claimIdsBySector, err := verifregSt.GetClaimIdsBySector(maddr) + if err != nil { + return xerrors.Errorf("failed to lookup claim IDs by sector: %w", err) + } + + sectorsMax, err := policy.GetAddressedSectorsMax(nv) + if err != nil { + return err + } + + declMax, err := policy.GetDeclarationsMax(nv) + if err != nil { + return err + } + + addrSectors := sectorsMax + if cctx.Int("max-sectors") != 0 { + addrSectors = cctx.Int("max-sectors") + if addrSectors > sectorsMax { + return xerrors.Errorf("the specified max-sectors exceeds the maximum limit") + } + } + + var params []miner.ExtendSectorExpiration2Params + + p := miner.ExtendSectorExpiration2Params{} + scount := 0 + + for l, exts := range extensions { + for newExp, numbers := range exts { + sectorsWithoutClaimsToExtend := bitfield.New() + numbersToExtend := make([]abi.SectorNumber, 0, len(numbers)) + var sectorsWithClaims []miner.SectorClaim + for _, sectorNumber := range numbers { + claimIdsToMaintain := make([]verifreg.ClaimId, 0) + claimIdsToDrop := make([]verifreg.ClaimId, 0) + cannotExtendSector := false + claimIds, ok := claimIdsBySector[sectorNumber] + // Nothing to check, add to ccSectors + if !ok { + sectorsWithoutClaimsToExtend.Set(uint64(sectorNumber)) + numbersToExtend = append(numbersToExtend, sectorNumber) + } else { + for _, claimId := range claimIds { + claim, ok := claimsMap[claimId] + if !ok { + return xerrors.Errorf("failed to find claim for claimId %d", claimId) + } + claimExpiration := claim.TermStart + claim.TermMax + // can be maintained in the extended sector + if claimExpiration > newExp { + claimIdsToMaintain = append(claimIdsToMaintain, claimId) + } else { + sectorInfo, ok := activeSectorsInfo[sectorNumber] + if !ok { + return xerrors.Errorf("failed to find sector in active sector set: %w", err) + } + if !cctx.Bool("drop-claims") || + // FIP-0045 requires the claim minimum duration to have passed + currEpoch <= (claim.TermStart+claim.TermMin) || + // FIP-0045 requires the sector to be in its last 30 days of life + (currEpoch <= sectorInfo.Expiration-builtin.EndOfLifeClaimDropPeriod) { + fmt.Printf("skipping sector %d because claim %d (client f0%s, piece %s) does not live long enough \n", sectorNumber, claimId, claim.Client, claim.Data) + cannotExtendSector = true + break + } + + claimIdsToDrop = append(claimIdsToDrop, claimId) + } + + numbersToExtend = append(numbersToExtend, sectorNumber) + } + if cannotExtendSector { + continue + } + + if len(claimIdsToMaintain)+len(claimIdsToDrop) != 0 { + sectorsWithClaims = append(sectorsWithClaims, miner.SectorClaim{ + SectorNumber: sectorNumber, + MaintainClaims: claimIdsToMaintain, + DropClaims: claimIdsToDrop, + }) + } + } + } + + sectorsWithoutClaimsCount, err := sectorsWithoutClaimsToExtend.Count() + if err != nil { + return xerrors.Errorf("failed to count cc sectors: %w", err) + } + + sectorsInDecl := int(sectorsWithoutClaimsCount) + len(sectorsWithClaims) + scount += sectorsInDecl + + if scount > addrSectors || len(p.Extensions) >= declMax { + params = append(params, p) + p = miner.ExtendSectorExpiration2Params{} + scount = sectorsInDecl + } + + p.Extensions = append(p.Extensions, miner.ExpirationExtension2{ + Deadline: l.Deadline, + Partition: l.Partition, + Sectors: SectorNumsToBitfield(numbersToExtend), + SectorsWithClaims: sectorsWithClaims, + NewExpiration: newExp, + }) + + } + } + + // if we have any sectors, then one last append is needed here + if scount != 0 { + params = append(params, p) + } + + if len(params) == 0 { + fmt.Println("nothing to extend") + return nil + } + + mi, err := fullApi.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + stotal := 0 + + for i := range params { + scount := 0 + for _, ext := range params[i].Extensions { + count, err := ext.Sectors.Count() + if err != nil { + return err + } + scount += int(count) + } + fmt.Printf("Extending %d sectors: ", scount) + stotal += scount + + sp, aerr := actors.SerializeParams(¶ms[i]) + if aerr != nil { + return xerrors.Errorf("serializing params: %w", err) + } + + m := &types.Message{ + From: mi.Worker, + To: maddr, + Method: builtin.MethodsMiner.ExtendSectorExpiration2, + Value: big.Zero(), + Params: sp, + } + + if !cctx.Bool("really-do-it") { + pp, err := NewPseudoExtendParams(¶ms[i]) + if err != nil { + return err + } + + data, err := json.MarshalIndent(pp, "", " ") + if err != nil { + return err + } + + fmt.Println("\n", string(data)) + + _, err = fullApi.GasEstimateMessageGas(ctx, m, spec, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("simulating message execution: %w", err) + } + + continue + } + + smsg, err := fullApi.MpoolPushMessage(ctx, m, spec) + if err != nil { + return xerrors.Errorf("mpool push message: %w", err) + } + + fmt.Println(smsg.Cid()) + } + + fmt.Printf("%d sectors extended\n", stotal) + + return nil + }, + } +} + +func SectorNumsToBitfield(sectors []abi.SectorNumber) bitfield.BitField { + var numbers []uint64 + for _, sector := range sectors { + numbers = append(numbers, uint64(sector)) + } + + return bitfield.NewFromSet(numbers) +} + +func getSectorsFromFile(filePath string) ([]abi.SectorNumber, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, err + } + + scanner := bufio.NewScanner(file) + sectors := make([]abi.SectorNumber, 0) + + for scanner.Scan() { + line := scanner.Text() + + id, err := strconv.ParseUint(line, 10, 64) + if err != nil { + return nil, xerrors.Errorf("could not parse %s as sector id: %s", line, err) + } + + sectors = append(sectors, abi.SectorNumber(id)) + } + + if err = file.Close(); err != nil { + return nil, err + } + + return sectors, nil +} + +func NewPseudoExtendParams(p *miner.ExtendSectorExpiration2Params) (*PseudoExtendSectorExpirationParams, error) { + res := PseudoExtendSectorExpirationParams{} + for _, ext := range p.Extensions { + scount, err := ext.Sectors.Count() + if err != nil { + return nil, err + } + + sectors, err := ext.Sectors.All(scount) + if err != nil { + return nil, err + } + + res.Extensions = append(res.Extensions, PseudoExpirationExtension{ + Deadline: ext.Deadline, + Partition: ext.Partition, + Sectors: ArrayToString(sectors), + NewExpiration: ext.NewExpiration, + }) + } + return &res, nil +} + +type PseudoExtendSectorExpirationParams struct { + Extensions []PseudoExpirationExtension +} + +type PseudoExpirationExtension struct { + Deadline uint64 + Partition uint64 + Sectors string + NewExpiration abi.ChainEpoch +} + +// ArrayToString Example: {1,3,4,5,8,9} -> "1,3-5,8-9" +func ArrayToString(array []uint64) string { + sort.Slice(array, func(i, j int) bool { + return array[i] < array[j] + }) + + var sarray []string + s := "" + + for i, elm := range array { + if i == 0 { + s = strconv.FormatUint(elm, 10) + continue + } + if elm == array[i-1] { + continue // filter out duplicates + } else if elm == array[i-1]+1 { + s = strings.Split(s, "-")[0] + "-" + strconv.FormatUint(elm, 10) + } else { + sarray = append(sarray, s) + s = strconv.FormatUint(elm, 10) + } + } + + if s != "" { + sarray = append(sarray, s) + } + + return strings.Join(sarray, ",") +} + +func SectorsCompactPartitionsCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "compact-partitions", + Usage: "removes dead sectors from partitions and reduces the number of partitions used if possible", + Flags: []cli.Flag{ + &cli.Uint64Flag{ + Name: "deadline", + Usage: "the deadline to compact the partitions in", + Required: true, + }, + &cli.Int64SliceFlag{ + Name: "partitions", + Usage: "list of partitions to compact sectors in", + Required: true, + }, + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "Actually send transaction performing the action", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + fullNodeAPI, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActorAddress(cctx) + if err != nil { + return err + } + + minfo, err := fullNodeAPI.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + deadline := cctx.Uint64("deadline") + if deadline > miner.WPoStPeriodDeadlines { + return fmt.Errorf("deadline %d out of range", deadline) + } + + parts := cctx.Int64Slice("partitions") + if len(parts) <= 0 { + return fmt.Errorf("must include at least one partition to compact") + } + fmt.Printf("compacting %d partitions\n", len(parts)) + + var makeMsgForPartitions func(partitionsBf bitfield.BitField) ([]*types.Message, error) + makeMsgForPartitions = func(partitionsBf bitfield.BitField) ([]*types.Message, error) { + params := miner.CompactPartitionsParams{ + Deadline: deadline, + Partitions: partitionsBf, + } + + sp, aerr := actors.SerializeParams(¶ms) + if aerr != nil { + return nil, xerrors.Errorf("serializing params: %w", err) + } + + msg := &types.Message{ + From: minfo.Worker, + To: maddr, + Method: builtin.MethodsMiner.CompactPartitions, + Value: big.Zero(), + Params: sp, + } + + estimatedMsg, err := fullNodeAPI.GasEstimateMessageGas(ctx, msg, nil, types.EmptyTSK) + if err != nil && errors.Is(err, &api.ErrOutOfGas{}) { + // the message is too big -- split into 2 + partitionsSlice, err := partitionsBf.All(math.MaxUint64) + if err != nil { + return nil, err + } + + partitions1 := bitfield.New() + for i := 0; i < len(partitionsSlice)/2; i++ { + partitions1.Set(uint64(i)) + } + + msgs1, err := makeMsgForPartitions(partitions1) + if err != nil { + return nil, err + } + + // time for the second half + partitions2 := bitfield.New() + for i := len(partitionsSlice) / 2; i < len(partitionsSlice); i++ { + partitions2.Set(uint64(i)) + } + + msgs2, err := makeMsgForPartitions(partitions2) + if err != nil { + return nil, err + } + + return append(msgs1, msgs2...), nil + } else if err != nil { + return nil, err + } + + return []*types.Message{estimatedMsg}, nil + } + + partitions := bitfield.New() + for _, partition := range parts { + partitions.Set(uint64(partition)) + } + + msgs, err := makeMsgForPartitions(partitions) + if err != nil { + return xerrors.Errorf("failed to make messages: %w", err) + } + + // Actually send the messages if really-do-it provided, simulate otherwise + if cctx.Bool("really-do-it") { + smsgs, err := fullNodeAPI.MpoolBatchPushMessage(ctx, msgs, nil) + if err != nil { + return xerrors.Errorf("mpool push: %w", err) + } + + if len(smsgs) == 1 { + fmt.Printf("Requested compact partitions in message %s\n", smsgs[0].Cid()) + } else { + fmt.Printf("Requested compact partitions in %d messages\n\n", len(smsgs)) + for _, v := range smsgs { + fmt.Println(v.Cid()) + } + } + + for _, v := range smsgs { + wait, err := fullNodeAPI.StateWaitMsg(ctx, v.Cid(), 2) + if err != nil { + return err + } + + // check it executed successfully + if wait.Receipt.ExitCode.IsError() { + fmt.Println(cctx.App.Writer, "compact partitions msg %s failed!", v.Cid()) + return err + } + } + + return nil + } + + for i, v := range msgs { + fmt.Printf("total of %d CompactPartitions msgs would be sent\n", len(msgs)) + + estMsg, err := fullNodeAPI.GasEstimateMessageGas(ctx, v, nil, types.EmptyTSK) + if err != nil { + return err + } + + fmt.Printf("msg %d would cost up to %s\n", i+1, types.FIL(estMsg.RequiredFunds())) + } + + return nil + + }, + } +} + +func TerminateSectorCmd(getActorAddress ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "terminate", + Usage: "Forcefully terminate a sector (WARNING: This means losing power and pay a one-time termination penalty(including collateral) for the terminated sector)", + ArgsUsage: "[sectorNum1 sectorNum2 ...]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "actor", + Usage: "specify the address of miner actor", + }, + &cli.BoolFlag{ + Name: "really-do-it", + Usage: "pass this flag if you know what you are doing", + }, + &cli.StringFlag{ + Name: "from", + Usage: "specify the address to send the terminate message from", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.NArg() < 1 { + return lcli.ShowHelp(cctx, fmt.Errorf("at least one sector must be specified")) + } + + var maddr address.Address + if act := cctx.String("actor"); act != "" { + var err error + maddr, err = address.NewFromString(act) + if err != nil { + return fmt.Errorf("parsing address %s: %w", act, err) + } + } + + if !cctx.Bool("really-do-it") { + return fmt.Errorf("this is a command for advanced users, only use it if you are sure of what you are doing") + } + + nodeApi, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := lcli.ReqContext(cctx) + + if maddr.Empty() { + maddr, err = getActorAddress(cctx) + if err != nil { + return err + } + } + + var outerErr error + sectorNumbers := lo.Map(cctx.Args().Slice(), func(sn string, _ int) int { + sectorNum, err := strconv.Atoi(sn) + if err != nil { + outerErr = fmt.Errorf("could not parse sector number: %w", err) + return 0 + } + return sectorNum + }) + if outerErr != nil { + return outerErr + } + + confidence := uint64(cctx.Int("confidence")) + + var fromAddr address.Address + if from := cctx.String("from"); from != "" { + var err error + fromAddr, err = address.NewFromString(from) + if err != nil { + return fmt.Errorf("parsing address %s: %w", from, err) + } + } else { + mi, err := nodeApi.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + fromAddr = mi.Worker + } + smsg, err := TerminateSectors(ctx, nodeApi, maddr, sectorNumbers, fromAddr) + if err != nil { + return err + } + + wait, err := nodeApi.StateWaitMsg(ctx, smsg.Cid(), confidence) + if err != nil { + return err + } + + if wait.Receipt.ExitCode.IsError() { + return fmt.Errorf("terminate sectors message returned exit %d", wait.Receipt.ExitCode) + } + return nil + }, + } +} + +type TerminatorNode interface { + StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*miner.SectorLocation, error) + MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) +} + +func TerminateSectors(ctx context.Context, full TerminatorNode, maddr address.Address, sectorNumbers []int, fromAddr address.Address) (*types.SignedMessage, error) { + + terminationDeclarationParams := []miner2.TerminationDeclaration{} + + for _, sectorNum := range sectorNumbers { + + sectorbit := bitfield.New() + sectorbit.Set(uint64(sectorNum)) + + loca, err := full.StateSectorPartition(ctx, maddr, abi.SectorNumber(sectorNum), types.EmptyTSK) + if err != nil { + return nil, fmt.Errorf("get state sector partition %s", err) + } + + para := miner2.TerminationDeclaration{ + Deadline: loca.Deadline, + Partition: loca.Partition, + Sectors: sectorbit, + } + + terminationDeclarationParams = append(terminationDeclarationParams, para) + } + + terminateSectorParams := &miner2.TerminateSectorsParams{ + Terminations: terminationDeclarationParams, + } + + sp, errA := actors.SerializeParams(terminateSectorParams) + if errA != nil { + return nil, xerrors.Errorf("serializing params: %w", errA) + } + + smsg, err := full.MpoolPushMessage(ctx, &types.Message{ + From: fromAddr, + To: maddr, + Method: builtin.MethodsMiner.TerminateSectors, + + Value: big.Zero(), + Params: sp, + }, nil) + if err != nil { + return nil, xerrors.Errorf("mpool push message: %w", err) + } + + fmt.Println("sent termination message:", smsg.Cid()) + + return smsg, nil +} diff --git a/cli/spcli/statemeta.go b/cli/spcli/statemeta.go new file mode 100644 index 00000000000..72de87807b8 --- /dev/null +++ b/cli/spcli/statemeta.go @@ -0,0 +1,95 @@ +package spcli + +import ( + "github.com/fatih/color" + + sealing "github.com/filecoin-project/lotus/storage/pipeline" +) + +type StateMeta struct { + I int + Col color.Attribute + State sealing.SectorState +} + +var StateOrder = map[sealing.SectorState]StateMeta{} +var StateList = []StateMeta{ + {Col: 39, State: "Total"}, + {Col: color.FgGreen, State: sealing.Proving}, + {Col: color.FgGreen, State: sealing.Available}, + {Col: color.FgGreen, State: sealing.UpdateActivating}, + + {Col: color.FgMagenta, State: sealing.ReceiveSector}, + + {Col: color.FgBlue, State: sealing.Empty}, + {Col: color.FgBlue, State: sealing.WaitDeals}, + {Col: color.FgBlue, State: sealing.AddPiece}, + {Col: color.FgBlue, State: sealing.SnapDealsWaitDeals}, + {Col: color.FgBlue, State: sealing.SnapDealsAddPiece}, + + {Col: color.FgRed, State: sealing.UndefinedSectorState}, + {Col: color.FgYellow, State: sealing.Packing}, + {Col: color.FgYellow, State: sealing.GetTicket}, + {Col: color.FgYellow, State: sealing.PreCommit1}, + {Col: color.FgYellow, State: sealing.PreCommit2}, + {Col: color.FgYellow, State: sealing.PreCommitting}, + {Col: color.FgYellow, State: sealing.PreCommitWait}, + {Col: color.FgYellow, State: sealing.SubmitPreCommitBatch}, + {Col: color.FgYellow, State: sealing.PreCommitBatchWait}, + {Col: color.FgYellow, State: sealing.WaitSeed}, + {Col: color.FgYellow, State: sealing.Committing}, + {Col: color.FgYellow, State: sealing.CommitFinalize}, + {Col: color.FgYellow, State: sealing.SubmitCommit}, + {Col: color.FgYellow, State: sealing.CommitWait}, + {Col: color.FgYellow, State: sealing.SubmitCommitAggregate}, + {Col: color.FgYellow, State: sealing.CommitAggregateWait}, + {Col: color.FgYellow, State: sealing.FinalizeSector}, + {Col: color.FgYellow, State: sealing.SnapDealsPacking}, + {Col: color.FgYellow, State: sealing.UpdateReplica}, + {Col: color.FgYellow, State: sealing.ProveReplicaUpdate}, + {Col: color.FgYellow, State: sealing.SubmitReplicaUpdate}, + {Col: color.FgYellow, State: sealing.ReplicaUpdateWait}, + {Col: color.FgYellow, State: sealing.WaitMutable}, + {Col: color.FgYellow, State: sealing.FinalizeReplicaUpdate}, + {Col: color.FgYellow, State: sealing.ReleaseSectorKey}, + + {Col: color.FgCyan, State: sealing.Terminating}, + {Col: color.FgCyan, State: sealing.TerminateWait}, + {Col: color.FgCyan, State: sealing.TerminateFinality}, + {Col: color.FgCyan, State: sealing.TerminateFailed}, + {Col: color.FgCyan, State: sealing.Removing}, + {Col: color.FgCyan, State: sealing.Removed}, + {Col: color.FgCyan, State: sealing.AbortUpgrade}, + + {Col: color.FgRed, State: sealing.FailedUnrecoverable}, + {Col: color.FgRed, State: sealing.AddPieceFailed}, + {Col: color.FgRed, State: sealing.SealPreCommit1Failed}, + {Col: color.FgRed, State: sealing.SealPreCommit2Failed}, + {Col: color.FgRed, State: sealing.PreCommitFailed}, + {Col: color.FgRed, State: sealing.ComputeProofFailed}, + {Col: color.FgRed, State: sealing.RemoteCommitFailed}, + {Col: color.FgRed, State: sealing.CommitFailed}, + {Col: color.FgRed, State: sealing.CommitFinalizeFailed}, + {Col: color.FgRed, State: sealing.PackingFailed}, + {Col: color.FgRed, State: sealing.FinalizeFailed}, + {Col: color.FgRed, State: sealing.Faulty}, + {Col: color.FgRed, State: sealing.FaultReported}, + {Col: color.FgRed, State: sealing.FaultedFinal}, + {Col: color.FgRed, State: sealing.RemoveFailed}, + {Col: color.FgRed, State: sealing.DealsExpired}, + {Col: color.FgRed, State: sealing.RecoverDealIDs}, + {Col: color.FgRed, State: sealing.SnapDealsAddPieceFailed}, + {Col: color.FgRed, State: sealing.SnapDealsDealsExpired}, + {Col: color.FgRed, State: sealing.ReplicaUpdateFailed}, + {Col: color.FgRed, State: sealing.ReleaseSectorKeyFailed}, + {Col: color.FgRed, State: sealing.FinalizeReplicaUpdateFailed}, +} + +func init() { + for i, state := range StateList { + StateOrder[state.State] = StateMeta{ + I: i, + Col: state.Col, + } + } +} diff --git a/cli/spcli/util.go b/cli/spcli/util.go new file mode 100644 index 00000000000..71ac371fec7 --- /dev/null +++ b/cli/spcli/util.go @@ -0,0 +1,9 @@ +package spcli + +import ( + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-address" +) + +type ActorAddressGetter func(cctx *cli.Context) (address address.Address, err error) diff --git a/cli/state.go b/cli/state.go index 31666a21c08..343e68b5389 100644 --- a/cli/state.go +++ b/cli/state.go @@ -17,10 +17,8 @@ import ( "text/tabwriter" "time" - "github.com/fatih/color" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" - "github.com/multiformats/go-multiaddr" "github.com/urfave/cli/v2" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" @@ -47,43 +45,6 @@ import ( cliutil "github.com/filecoin-project/lotus/cli/util" ) -var StateCmd = &cli.Command{ - Name: "state", - Usage: "Interact with and query filecoin chain state", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "tipset", - Usage: "specify tipset to call method on (pass comma separated array of cids)", - }, - }, - Subcommands: []*cli.Command{ - StatePowerCmd, - StateSectorsCmd, - StateActiveSectorsCmd, - StateListActorsCmd, - StateListMinersCmd, - StateCircSupplyCmd, - StateSectorCmd, - StateGetActorCmd, - StateLookupIDCmd, - StateReplayCmd, - StateSectorSizeCmd, - StateReadStateCmd, - StateListMessagesCmd, - StateComputeStateCmd, - StateCallCmd, - StateGetDealSetCmd, - StateWaitMsgCmd, - StateSearchMsgCmd, - StateMinerInfo, - StateMarketCmd, - StateExecTraceCmd, - StateNtwkVersionCmd, - StateMinerProvingDeadlineCmd, - StateSysActorCIDsCmd, - }, -} - var StateMinerProvingDeadlineCmd = &cli.Command{ Name: "miner-proving-deadline", Usage: "Retrieve information about a given miner's proving deadline", @@ -127,114 +88,6 @@ var StateMinerProvingDeadlineCmd = &cli.Command{ }, } -var StateMinerInfo = &cli.Command{ - Name: "miner-info", - Usage: "Retrieve miner information", - ArgsUsage: "[minerAddress]", - Action: func(cctx *cli.Context) error { - api, closer, err := GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - - ctx := ReqContext(cctx) - - if cctx.NArg() != 1 { - return IncorrectNumArgs(cctx) - } - - addr, err := address.NewFromString(cctx.Args().First()) - if err != nil { - return err - } - - ts, err := LoadTipSet(ctx, cctx, api) - if err != nil { - return err - } - - mi, err := api.StateMinerInfo(ctx, addr, ts.Key()) - if err != nil { - return err - } - - availableBalance, err := api.StateMinerAvailableBalance(ctx, addr, ts.Key()) - if err != nil { - return xerrors.Errorf("getting miner available balance: %w", err) - } - fmt.Printf("Available Balance: %s\n", types.FIL(availableBalance)) - fmt.Printf("Owner:\t%s\n", mi.Owner) - fmt.Printf("Worker:\t%s\n", mi.Worker) - for i, controlAddress := range mi.ControlAddresses { - fmt.Printf("Control %d: \t%s\n", i, controlAddress) - } - if mi.Beneficiary != address.Undef { - fmt.Printf("Beneficiary:\t%s\n", mi.Beneficiary) - if mi.Beneficiary != mi.Owner { - fmt.Printf("Beneficiary Quota:\t%s\n", mi.BeneficiaryTerm.Quota) - fmt.Printf("Beneficiary Used Quota:\t%s\n", mi.BeneficiaryTerm.UsedQuota) - fmt.Printf("Beneficiary Expiration:\t%s\n", mi.BeneficiaryTerm.Expiration) - } - } - if mi.PendingBeneficiaryTerm != nil { - fmt.Printf("Pending Beneficiary Term:\n") - fmt.Printf("New Beneficiary:\t%s\n", mi.PendingBeneficiaryTerm.NewBeneficiary) - fmt.Printf("New Quota:\t%s\n", mi.PendingBeneficiaryTerm.NewQuota) - fmt.Printf("New Expiration:\t%s\n", mi.PendingBeneficiaryTerm.NewExpiration) - fmt.Printf("Approved By Beneficiary:\t%t\n", mi.PendingBeneficiaryTerm.ApprovedByBeneficiary) - fmt.Printf("Approved By Nominee:\t%t\n", mi.PendingBeneficiaryTerm.ApprovedByNominee) - } - - fmt.Printf("PeerID:\t%s\n", mi.PeerId) - fmt.Printf("Multiaddrs:\t") - for _, addr := range mi.Multiaddrs { - a, err := multiaddr.NewMultiaddrBytes(addr) - if err != nil { - return xerrors.Errorf("undecodable listen address: %w", err) - } - fmt.Printf("%s ", a) - } - fmt.Println() - fmt.Printf("Consensus Fault End:\t%d\n", mi.ConsensusFaultElapsed) - - fmt.Printf("SectorSize:\t%s (%d)\n", types.SizeStr(types.NewInt(uint64(mi.SectorSize))), mi.SectorSize) - pow, err := api.StateMinerPower(ctx, addr, ts.Key()) - if err != nil { - return err - } - - fmt.Printf("Byte Power: %s / %s (%0.4f%%)\n", - color.BlueString(types.SizeStr(pow.MinerPower.RawBytePower)), - types.SizeStr(pow.TotalPower.RawBytePower), - types.BigDivFloat( - types.BigMul(pow.MinerPower.RawBytePower, big.NewInt(100)), - pow.TotalPower.RawBytePower, - ), - ) - - fmt.Printf("Actual Power: %s / %s (%0.4f%%)\n", - color.GreenString(types.DeciStr(pow.MinerPower.QualityAdjPower)), - types.DeciStr(pow.TotalPower.QualityAdjPower), - types.BigDivFloat( - types.BigMul(pow.MinerPower.QualityAdjPower, big.NewInt(100)), - pow.TotalPower.QualityAdjPower, - ), - ) - - fmt.Println() - - cd, err := api.StateMinerProvingDeadline(ctx, addr, ts.Key()) - if err != nil { - return xerrors.Errorf("getting miner info: %w", err) - } - - fmt.Printf("Proving Period Start:\t%s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.PeriodStart)) - - return nil - }, -} - func ParseTipSetString(ts string) ([]cid.Cid, error) { strs := strings.Split(ts, ",") @@ -1388,15 +1241,19 @@ func JsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, erro p, err := stmgr.GetParamType(ar, code, method) // todo use api for correct actor registry if err != nil { - return "", err + return fmt.Sprintf("raw:%x; DECODE ERR: %s", params, err.Error()), nil } if err := p.UnmarshalCBOR(bytes.NewReader(params)); err != nil { - return "", err + return fmt.Sprintf("raw:%x; DECODE cbor ERR: %s", params, err.Error()), nil } b, err := json.MarshalIndent(p, "", " ") - return string(b), err + if err != nil { + return "", err + } + + return string(b), nil } func JsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) { @@ -1407,7 +1264,7 @@ func JsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) re := reflect.New(methodMeta.Ret.Elem()) p := re.Interface().(cbg.CBORUnmarshaler) if err := p.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { - return "", err + return fmt.Sprintf("raw:%x; DECODE ERR: %s", ret, err.Error()), nil } b, err := json.MarshalIndent(p, "", " ") diff --git a/cli/util/api.go b/cli/util/api.go index 3602b752de2..7940f67c63a 100644 --- a/cli/util/api.go +++ b/cli/util/api.go @@ -76,50 +76,52 @@ func GetAPIInfoMulti(ctx *cli.Context, t repo.RepoType) ([]APIInfo, error) { if path == "" { continue } - - p, err := homedir.Expand(path) - if err != nil { - return []APIInfo{}, xerrors.Errorf("could not expand home dir (%s): %w", f, err) + return GetAPIInfoFromRepoPath(path, t) + } + for _, env := range fallbacksEnvs { + env, ok := os.LookupEnv(env) + if ok { + return ParseApiInfoMulti(env), nil } + } - r, err := repo.NewFS(p) - if err != nil { - return []APIInfo{}, xerrors.Errorf("could not open repo at path: %s; %w", p, err) - } + return []APIInfo{}, fmt.Errorf("could not determine API endpoint for node type: %v. Try setting environment variable: %s", t.Type(), primaryEnv) +} - exists, err := r.Exists() - if err != nil { - return []APIInfo{}, xerrors.Errorf("repo.Exists returned an error: %w", err) - } +func GetAPIInfoFromRepoPath(path string, t repo.RepoType) ([]APIInfo, error) { + p, err := homedir.Expand(path) + if err != nil { + return []APIInfo{}, xerrors.Errorf("could not expand home dir (%s): %w", path, err) + } - if !exists { - return []APIInfo{}, errors.New("repo directory does not exist. Make sure your configuration is correct") - } + r, err := repo.NewFS(p) + if err != nil { + return []APIInfo{}, xerrors.Errorf("could not open repo at path: %s; %w", p, err) + } - ma, err := r.APIEndpoint() - if err != nil { - return []APIInfo{}, xerrors.Errorf("could not get api endpoint: %w", err) - } + exists, err := r.Exists() + if err != nil { + return []APIInfo{}, xerrors.Errorf("repo.Exists returned an error: %w", err) + } - token, err := r.APIToken() - if err != nil { - log.Warnf("Couldn't load CLI token, capabilities may be limited: %v", err) - } + if !exists { + return []APIInfo{}, errors.New("repo directory does not exist. Make sure your configuration is correct") + } - return []APIInfo{{ - Addr: ma.String(), - Token: token, - }}, nil + ma, err := r.APIEndpoint() + if err != nil { + return []APIInfo{}, xerrors.Errorf("could not get api endpoint: %w", err) } - for _, env := range fallbacksEnvs { - env, ok := os.LookupEnv(env) - if ok { - return ParseApiInfoMulti(env), nil - } + token, err := r.APIToken() + if err != nil { + log.Warnf("Couldn't load CLI token, capabilities may be limited: %v", err) } - return []APIInfo{}, fmt.Errorf("could not determine API endpoint for node type: %v. Try setting environment variable: %s", t.Type(), primaryEnv) + return []APIInfo{{ + Addr: ma.String(), + Token: token, + }}, nil } func GetAPIInfo(ctx *cli.Context, t repo.RepoType) (APIInfo, error) { @@ -164,28 +166,6 @@ func GetRawAPIMulti(ctx *cli.Context, t repo.RepoType, version string) ([]HttpHe return httpHeads, nil } -func GetRawAPIMultiV2(ctx *cli.Context, ainfoCfg []string, version string) ([]HttpHead, error) { - var httpHeads []HttpHead - - if len(ainfoCfg) == 0 { - return httpHeads, xerrors.Errorf("could not get API info: none configured. \nConsider getting base.toml with './lotus-provider config get base >/tmp/base.toml' \nthen adding \n[APIs] \n ChainApiInfo = [\" result_from lotus auth api-info --perm=admin \"]\n and updating it with './lotus-provider config set /tmp/base.toml'") - } - for _, i := range ainfoCfg { - ainfo := ParseApiInfo(i) - addr, err := ainfo.DialArgs(version) - if err != nil { - return httpHeads, xerrors.Errorf("could not get DialArgs: %w", err) - } - httpHeads = append(httpHeads, HttpHead{addr: addr, header: ainfo.AuthHeader()}) - } - - if IsVeryVerbose { - _, _ = fmt.Fprintf(ctx.App.Writer, "using raw API %s endpoint: %s\n", version, httpHeads[0].addr) - } - - return httpHeads, nil -} - func GetRawAPI(ctx *cli.Context, t repo.RepoType, version string) (string, http.Header, error) { heads, err := GetRawAPIMulti(ctx, t, version) if err != nil { @@ -342,14 +322,14 @@ func GetFullNodeAPIV1Single(ctx *cli.Context) (v1api.FullNode, jsonrpc.ClientClo } type GetFullNodeOptions struct { - ethSubHandler api.EthSubscriber + EthSubHandler api.EthSubscriber } type GetFullNodeOption func(*GetFullNodeOptions) func FullNodeWithEthSubscribtionHandler(sh api.EthSubscriber) GetFullNodeOption { return func(opts *GetFullNodeOptions) { - opts.ethSubHandler = sh + opts.EthSubHandler = sh } } @@ -364,8 +344,8 @@ func GetFullNodeAPIV1(ctx *cli.Context, opts ...GetFullNodeOption) (v1api.FullNo } var rpcOpts []jsonrpc.Option - if options.ethSubHandler != nil { - rpcOpts = append(rpcOpts, jsonrpc.WithClientHandler("Filecoin", options.ethSubHandler), jsonrpc.WithClientHandlerAlias("eth_subscription", "Filecoin.EthSubscription")) + 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") @@ -415,68 +395,6 @@ func GetFullNodeAPIV1(ctx *cli.Context, opts ...GetFullNodeOption) (v1api.FullNo return &v1API, finalCloser, nil } -func GetFullNodeAPIV1LotusProvider(ctx *cli.Context, ainfoCfg []string, 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 := GetRawAPIMultiV2(ctx, ainfoCfg, "v1") - if err != nil { - return nil, nil, err - } - - if IsVeryVerbose { - _, _ = fmt.Fprintln(ctx.App.Writer, "using full node API v1 endpoint:", heads[0].addr) - } - - var fullNodes []api.FullNode - var closers []jsonrpc.ClientCloser - - for _, head := range heads { - 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: %s", head.addr) - continue - } - fullNodes = append(fullNodes, v1api) - closers = append(closers, closer) - } - - // When running in cluster mode and trying to establish connections to multiple nodes, fail - // if less than 2 lotus nodes are actually running - if len(heads) > 1 && len(fullNodes) < 2 { - return nil, nil, xerrors.Errorf("Not able to establish connection to more than a single node") - } - - finalCloser := func() { - for _, c := range closers { - c() - } - } - - var v1API api.FullNodeStruct - FullNodeProxy(fullNodes, &v1API) - - v, err := v1API.Version(ctx.Context) - if err != nil { - return nil, nil, err - } - if !v.APIVersion.EqMajorMinor(api.FullAPIVersion1) { - return nil, nil, xerrors.Errorf("Remote API version didn't match (expected %s, remote %s)", api.FullAPIVersion1, v.APIVersion) - } - return &v1API, finalCloser, nil -} - type GetStorageMinerOptions struct { PreferHttp bool } diff --git a/cli/wallet.go b/cli/wallet.go index faf7bc23955..4af8dca58b8 100644 --- a/cli/wallet.go +++ b/cli/wallet.go @@ -27,7 +27,7 @@ import ( "github.com/filecoin-project/lotus/lib/tablewriter" ) -var walletCmd = &cli.Command{ +var WalletCmd = &cli.Command{ Name: "wallet", Usage: "Manage wallet", Subcommands: []*cli.Command{ diff --git a/cmd/curio/cli.go b/cmd/curio/cli.go new file mode 100644 index 00000000000..6c9cb7ec67b --- /dev/null +++ b/cmd/curio/cli.go @@ -0,0 +1,249 @@ +package main + +import ( + "bufio" + "context" + "encoding/base64" + "errors" + "fmt" + "net" + "os" + "time" + + "github.com/BurntSushi/toml" + "github.com/gbrlsnchs/jwt/v3" + manet "github.com/multiformats/go-multiaddr/net" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-jsonrpc/auth" + + "github.com/filecoin-project/lotus/api" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/cmd/curio/rpc" +) + +const providerEnvVar = "CURIO_API_INFO" + +var cliCmd = &cli.Command{ + Name: "cli", + Usage: "Execute cli commands", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "machine", + Usage: "machine host:port (curio run --listen address)", + }, + }, + Before: func(cctx *cli.Context) error { + if os.Getenv(providerEnvVar) != "" { + // set already + return nil + } + if os.Getenv("LOTUS_DOCS_GENERATION") == "1" { + return nil + } + + db, err := deps.MakeDB(cctx) + if err != nil { + return err + } + + ctx := lcli.ReqContext(cctx) + + machine := cctx.String("machine") + if machine == "" { + // interactive picker + var machines []struct { + HostAndPort string `db:"host_and_port"` + LastContact time.Time `db:"last_contact"` + } + + err := db.Select(ctx, &machines, "select host_and_port, last_contact from harmony_machines") + if err != nil { + return xerrors.Errorf("getting machine list: %w", err) + } + + now := time.Now() + fmt.Println("Available machines:") + for i, m := range machines { + // A machine is healthy if contacted not longer than 2 minutes ago + healthStatus := "unhealthy" + if now.Sub(m.LastContact) <= 2*time.Minute { + healthStatus = "healthy" + } + fmt.Printf("%d. %s %s\n", i+1, m.HostAndPort, healthStatus) + } + + fmt.Print("Select: ") + reader := bufio.NewReader(os.Stdin) + input, err := reader.ReadString('\n') + if err != nil { + return xerrors.Errorf("reading selection: %w", err) + } + + var selection int + _, err = fmt.Sscanf(input, "%d", &selection) + if err != nil { + return xerrors.Errorf("parsing selection: %w", err) + } + + if selection < 1 || selection > len(machines) { + return xerrors.New("invalid selection") + } + + machine = machines[selection-1].HostAndPort + } + + var apiKeys []string + { + var dbconfigs []struct { + Config string `db:"config"` + Title string `db:"title"` + } + + err := db.Select(ctx, &dbconfigs, "select config from harmony_config") + if err != nil { + return xerrors.Errorf("getting configs: %w", err) + } + + var seen = make(map[string]struct{}) + + for _, config := range dbconfigs { + var layer struct { + Apis struct { + StorageRPCSecret string + } + } + + if _, err := toml.Decode(config.Config, &layer); err != nil { + return xerrors.Errorf("decode config layer %s: %w", config.Title, err) + } + + if layer.Apis.StorageRPCSecret != "" { + if _, ok := seen[layer.Apis.StorageRPCSecret]; ok { + continue + } + seen[layer.Apis.StorageRPCSecret] = struct{}{} + apiKeys = append(apiKeys, layer.Apis.StorageRPCSecret) + } + } + } + + if len(apiKeys) == 0 { + return xerrors.New("no api keys found in the database") + } + if len(apiKeys) > 1 { + return xerrors.Errorf("multiple api keys found in the database, not supported yet") + } + + var apiToken []byte + { + type jwtPayload struct { + Allow []auth.Permission + } + + p := jwtPayload{ + Allow: api.AllPermissions, + } + + sk, err := base64.StdEncoding.DecodeString(apiKeys[0]) + if err != nil { + return xerrors.Errorf("decode secret: %w", err) + } + + apiToken, err = jwt.Sign(&p, jwt.NewHS256(sk)) + if err != nil { + return xerrors.Errorf("signing token: %w", err) + } + } + + { + + laddr, err := net.ResolveTCPAddr("tcp", machine) + if err != nil { + return xerrors.Errorf("net resolve: %w", err) + } + + if len(laddr.IP) == 0 { + // set localhost + laddr.IP = net.IPv4(127, 0, 0, 1) + } + + ma, err := manet.FromNetAddr(laddr) + if err != nil { + return xerrors.Errorf("net from addr (%v): %w", laddr, err) + } + + token := fmt.Sprintf("%s:%s", string(apiToken), ma) + if err := os.Setenv(providerEnvVar, token); err != nil { + return xerrors.Errorf("setting env var: %w", err) + } + } + + { + api, closer, err := rpc.GetCurioAPI(cctx) + if err != nil { + return err + } + defer closer() + + v, err := api.Version(ctx) + if err != nil { + return xerrors.Errorf("querying version: %w", err) + } + + fmt.Println("remote node version:", v.String()) + } + + return nil + }, + Subcommands: []*cli.Command{ + storageCmd, + logCmd, + waitApiCmd, + }, +} + +var waitApiCmd = &cli.Command{ + Name: "wait-api", + Usage: "Wait for Curio api to come online", + Flags: []cli.Flag{ + &cli.DurationFlag{ + Name: "timeout", + Usage: "duration to wait till fail", + Value: time.Second * 30, + }, + }, + Action: func(cctx *cli.Context) error { + ctx := lcli.ReqContext(cctx) + ctx, cancel := context.WithTimeout(ctx, cctx.Duration("timeout")) + defer cancel() + for { + if ctx.Err() != nil { + break + } + + api, closer, err := rpc.GetCurioAPI(cctx) + if err != nil { + fmt.Printf("Not online yet... (%s)\n", err) + time.Sleep(time.Second) + continue + } + defer closer() + + _, err = api.Version(ctx) + if err != nil { + return err + } + + return nil + } + + if errors.Is(ctx.Err(), context.DeadlineExceeded) { + return fmt.Errorf("timed out waiting for api to come online") + } + + return ctx.Err() + }, +} diff --git a/cmd/curio/config.go b/cmd/curio/config.go new file mode 100644 index 00000000000..16b7d89c378 --- /dev/null +++ b/cmd/curio/config.go @@ -0,0 +1,440 @@ +package main + +import ( + "context" + "errors" + "fmt" + "io" + "os" + "os/exec" + "path" + "strings" + + "github.com/BurntSushi/toml" + "github.com/fatih/color" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/node/config" +) + +var configCmd = &cli.Command{ + Name: "config", + Usage: "Manage node config by layers. The layer 'base' will always be applied at Curio start-up.", + Subcommands: []*cli.Command{ + configDefaultCmd, + configSetCmd, + configGetCmd, + configListCmd, + configViewCmd, + configRmCmd, + configEditCmd, + configNewCmd, + }, +} + +var configDefaultCmd = &cli.Command{ + Name: "default", + Aliases: []string{"defaults"}, + Usage: "Print default node config", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "no-comment", + Usage: "don't comment default values", + }, + }, + Action: func(cctx *cli.Context) error { + comment := !cctx.Bool("no-comment") + cfg, err := deps.GetDefaultConfig(comment) + if err != nil { + return err + } + fmt.Print(cfg) + + return nil + }, +} + +var configSetCmd = &cli.Command{ + Name: "set", + Aliases: []string{"add", "update", "create"}, + Usage: "Set a config layer or the base by providing a filename or stdin.", + ArgsUsage: "a layer's file name", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "title", + Usage: "title of the config layer (req'd for stdin)", + }, + }, + Action: func(cctx *cli.Context) error { + args := cctx.Args() + + db, err := deps.MakeDB(cctx) + if err != nil { + return err + } + + name := cctx.String("title") + var stream io.Reader = os.Stdin + if args.Len() != 1 { + if cctx.String("title") == "" { + return errors.New("must have a title for stdin, or a file name") + } + } else { + stream, err = os.Open(args.First()) + if err != nil { + return fmt.Errorf("cannot open file %s: %w", args.First(), err) + } + if name == "" { + name = strings.Split(path.Base(args.First()), ".")[0] + } + } + bytes, err := io.ReadAll(stream) + if err != nil { + return fmt.Errorf("cannot read stream/file %w", err) + } + + curioConfig := config.DefaultCurioConfig() // ensure it's toml + _, err = deps.LoadConfigWithUpgrades(string(bytes), curioConfig) + if err != nil { + return fmt.Errorf("cannot decode file: %w", err) + } + _ = curioConfig + + err = setConfig(db, name, string(bytes)) + + if err != nil { + return fmt.Errorf("unable to save config layer: %w", err) + } + + fmt.Println("Layer " + name + " created/updated") + return nil + }, +} + +func setConfig(db *harmonydb.DB, name, config string) error { + _, err := db.Exec(context.Background(), + `INSERT INTO harmony_config (title, config) VALUES ($1, $2) + ON CONFLICT (title) DO UPDATE SET config = excluded.config`, name, config) + return err +} + +var configGetCmd = &cli.Command{ + Name: "get", + Aliases: []string{"cat", "show"}, + Usage: "Get a config layer by name. You may want to pipe the output to a file, or use 'less'", + ArgsUsage: "layer name", + Action: func(cctx *cli.Context) error { + args := cctx.Args() + if args.Len() != 1 { + return fmt.Errorf("want 1 layer arg, got %d", args.Len()) + } + db, err := deps.MakeDB(cctx) + if err != nil { + return err + } + + cfg, err := getConfig(db, args.First()) + if err != nil { + return err + } + fmt.Println(cfg) + + return nil + }, +} + +func getConfig(db *harmonydb.DB, layer string) (string, error) { + var cfg string + err := db.QueryRow(context.Background(), `SELECT config FROM harmony_config WHERE title=$1`, layer).Scan(&cfg) + if err != nil { + return "", err + } + return cfg, nil +} + +var configListCmd = &cli.Command{ + Name: "list", + Aliases: []string{"ls"}, + Usage: "List config layers present in the DB.", + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + db, err := deps.MakeDB(cctx) + if err != nil { + return err + } + var res []string + err = db.Select(context.Background(), &res, `SELECT title FROM harmony_config ORDER BY title`) + if err != nil { + return fmt.Errorf("unable to read from db: %w", err) + } + for _, r := range res { + fmt.Println(r) + } + + return nil + }, +} + +var configRmCmd = &cli.Command{ + Name: "remove", + Aliases: []string{"rm", "del", "delete"}, + Usage: "Remove a named config layer.", + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + args := cctx.Args() + if args.Len() != 1 { + return errors.New("must have exactly 1 arg for the layer name") + } + db, err := deps.MakeDB(cctx) + if err != nil { + return err + } + ct, err := db.Exec(context.Background(), `DELETE FROM harmony_config WHERE title=$1`, args.First()) + if err != nil { + return fmt.Errorf("unable to read from db: %w", err) + } + if ct == 0 { + return fmt.Errorf("no layer named %s", args.First()) + } + + return nil + }, +} +var configViewCmd = &cli.Command{ + Name: "interpret", + Aliases: []string{"view", "stacked", "stack"}, + Usage: "Interpret stacked config layers by this version of curio, with system-generated comments.", + ArgsUsage: "a list of layers to be interpreted as the final config", + Flags: []cli.Flag{ + &cli.StringSliceFlag{ + Name: "layers", + Usage: "comma or space separated list of layers to be interpreted (base is always applied)", + Required: true, + }, + }, + Action: func(cctx *cli.Context) error { + db, err := deps.MakeDB(cctx) + if err != nil { + return err + } + curioConfig, err := deps.GetConfig(cctx, db) + if err != nil { + return err + } + cb, err := config.ConfigUpdate(curioConfig, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + if err != nil { + return xerrors.Errorf("cannot interpret config: %w", err) + } + fmt.Println(string(cb)) + return nil + }, +} + +var configEditCmd = &cli.Command{ + Name: "edit", + Usage: "edit a config layer", + ArgsUsage: "[layer name]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "editor", + Usage: "editor to use", + Value: "vim", + EnvVars: []string{"EDITOR"}, + }, + &cli.StringFlag{ + Name: "source", + Usage: "source config layer", + DefaultText: "", + }, + &cli.BoolFlag{ + Name: "allow-overwrite", + Usage: "allow overwrite of existing layer if source is a different layer", + }, + &cli.BoolFlag{ + Name: "no-source-diff", + Usage: "save the whole config into the layer, not just the diff", + }, + &cli.BoolFlag{ + Name: "no-interpret-source", + Usage: "do not interpret source layer", + DefaultText: "true if --source is set", + }, + }, + Action: func(cctx *cli.Context) error { + layer := cctx.Args().First() + if layer == "" { + return errors.New("layer name is required") + } + + source := layer + if cctx.IsSet("source") { + source = cctx.String("source") + + if source == layer && !cctx.Bool("allow-owerwrite") { + return errors.New("source and target layers are the same") + } + } + + db, err := deps.MakeDB(cctx) + if err != nil { + return err + } + + sourceConfig, err := getConfig(db, source) + if err != nil { + return xerrors.Errorf("getting source config: %w", err) + } + + if cctx.IsSet("source") && source != layer && !cctx.Bool("no-interpret-source") { + lp := config.DefaultCurioConfig() + if _, err := toml.Decode(sourceConfig, lp); err != nil { + return xerrors.Errorf("parsing source config: %w", err) + } + + cb, err := config.ConfigUpdate(lp, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + if err != nil { + return xerrors.Errorf("interpreting source config: %w", err) + } + sourceConfig = string(cb) + } + + editor := cctx.String("editor") + newConfig, err := edit(editor, sourceConfig) + if err != nil { + return xerrors.Errorf("editing config: %w", err) + } + + toWrite := newConfig + + if cctx.IsSet("source") && !cctx.Bool("no-source-diff") { + updated, err := diff(sourceConfig, newConfig) + if err != nil { + return xerrors.Errorf("computing diff: %w", err) + } + + { + fmt.Printf("%s will write changes as the layer because %s is not set\n", color.YellowString(">"), color.GreenString("--no-source-diff")) + fmt.Println(updated) + fmt.Printf("%s Confirm [y]: ", color.YellowString(">")) + + for { + var confirmBuf [16]byte + n, err := os.Stdin.Read(confirmBuf[:]) + if err != nil { + return xerrors.Errorf("reading confirmation: %w", err) + } + confirm := strings.TrimSpace(string(confirmBuf[:n])) + + if confirm == "" { + confirm = "y" + } + + if confirm[:1] == "y" { + break + } + if confirm[:1] == "n" { + return nil + } + + fmt.Printf("%s Confirm [y]:\n", color.YellowString(">")) + } + } + + toWrite = updated + } + + fmt.Printf("%s Writing config for layer %s\n", color.YellowString(">"), color.GreenString(layer)) + + return setConfig(db, layer, toWrite) + }, +} + +func diff(sourceConf, newConf string) (string, error) { + lpSrc := config.DefaultCurioConfig() + lpNew := config.DefaultCurioConfig() + + _, err := toml.Decode(sourceConf, lpSrc) + if err != nil { + return "", xerrors.Errorf("decoding source config: %w", err) + } + + _, err = toml.Decode(newConf, lpNew) + if err != nil { + return "", xerrors.Errorf("decoding new config: %w", err) + } + + cb, err := config.ConfigUpdate(lpNew, lpSrc, config.Commented(true), config.NoEnv()) + if err != nil { + return "", xerrors.Errorf("interpreting source config: %w", err) + } + + lines := strings.Split(string(cb), "\n") + var outLines []string + var categoryBuf string + + for _, line := range lines { + // drop empty lines + if strings.TrimSpace(line) == "" { + continue + } + // drop lines starting with '#' + if strings.HasPrefix(strings.TrimSpace(line), "#") { + continue + } + // if starting with [, it's a category + if strings.HasPrefix(strings.TrimSpace(line), "[") { + categoryBuf = line + continue + } + + if categoryBuf != "" { + outLines = append(outLines, categoryBuf) + categoryBuf = "" + } + + outLines = append(outLines, line) + } + + return strings.Join(outLines, "\n"), nil +} + +func edit(editor, cfg string) (string, error) { + file, err := os.CreateTemp("", "curio-config-*.toml") + if err != nil { + return "", err + } + + _, err = file.WriteString(cfg) + if err != nil { + return "", err + } + + filePath := file.Name() + + if err := file.Close(); err != nil { + return "", err + } + + defer func() { + _ = os.Remove(filePath) + }() + + cmd := exec.Command(editor, filePath) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Run() + if err != nil { + return "", err + } + + data, err := os.ReadFile(filePath) + if err != nil { + return "", err + } + + return string(data), err +} diff --git a/cmd/curio/config_new.go b/cmd/curio/config_new.go new file mode 100644 index 00000000000..65549bd6995 --- /dev/null +++ b/cmd/curio/config_new.go @@ -0,0 +1,57 @@ +package main + +import ( + "fmt" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api" + cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/node/repo" +) + +var configNewCmd = &cli.Command{ + Name: "new-cluster", + Usage: "Create new configuration for a new cluster", + ArgsUsage: "[SP actor address...]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() < 1 { + return xerrors.New("must specify at least one SP actor address. Use 'lotus-shed miner create' or use 'curio guided-setup'") + } + + ctx := cctx.Context + + db, err := deps.MakeDB(cctx) + if err != nil { + return err + } + + full, closer, err := cliutil.GetFullNodeAPIV1(cctx) + if err != nil { + return xerrors.Errorf("connecting to full node: %w", err) + } + defer closer() + + ainfo, err := cliutil.GetAPIInfo(cctx, repo.FullNode) + if err != nil { + return xerrors.Errorf("could not get API info for FullNode: %w", err) + } + + token, err := full.AuthNew(ctx, api.AllPermissions) + if err != nil { + return err + } + + return deps.CreateMinerConfig(ctx, full, db, cctx.Args().Slice(), fmt.Sprintf("%s:%s", string(token), ainfo.Addr)) + }, +} diff --git a/cmd/curio/config_test.go b/cmd/curio/config_test.go new file mode 100644 index 00000000000..8043017d5ea --- /dev/null +++ b/cmd/curio/config_test.go @@ -0,0 +1,438 @@ +package main + +import ( + "reflect" + "testing" + "time" + + "github.com/invopop/jsonschema" + "github.com/samber/lo" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/node/config" +) + +var baseText = ` +[Subsystems] + # EnableWindowPost enables window post to be executed on this curio instance. Each machine in the cluster + # with WindowPoSt enabled will also participate in the window post scheduler. It is possible to have multiple + # machines with WindowPoSt enabled which will provide redundancy, and in case of multiple partitions per deadline, + # will allow for parallel processing of partitions. + # + # It is possible to have instances handling both WindowPoSt and WinningPoSt, which can provide redundancy without + # the need for additional machines. In setups like this it is generally recommended to run + # partitionsPerDeadline+1 machines. + # + # type: bool + #EnableWindowPost = false + + # type: int + #WindowPostMaxTasks = 0 + + # EnableWinningPost enables winning post to be executed on this curio instance. + # Each machine in the cluster with WinningPoSt enabled will also participate in the winning post scheduler. + # It is possible to mix machines with WindowPoSt and WinningPoSt enabled, for details see the EnableWindowPost + # documentation. + # + # type: bool + #EnableWinningPost = false + + # type: int + #WinningPostMaxTasks = 0 + + # EnableParkPiece enables the "piece parking" task to run on this node. This task is responsible for fetching + # pieces from the network and storing them in the storage subsystem until sectors are sealed. This task is + # only applicable when integrating with boost, and should be enabled on nodes which will hold deal data + # from boost until sectors containing the related pieces have the TreeD/TreeR constructed. + # Note that future Curio implementations will have a separate task type for fetching pieces from the internet. + # + # type: bool + #EnableParkPiece = false + + # type: int + #ParkPieceMaxTasks = 0 + + # EnableSealSDR enables SDR tasks to run. SDR is the long sequential computation + # creating 11 layer files in sector cache directory. + # + # SDR is the first task in the sealing pipeline. It's inputs are just the hash of the + # unsealed data (CommD), sector number, miner id, and the seal proof type. + # It's outputs are the 11 layer files in the sector cache directory. + # + # In lotus-miner this was run as part of PreCommit1. + # + # type: bool + #EnableSealSDR = false + + # The maximum amount of SDR tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. + # + # type: int + #SealSDRMaxTasks = 0 + + # EnableSealSDRTrees enables the SDR pipeline tree-building task to run. + # This task handles encoding of unsealed data into last sdr layer and building + # of TreeR, TreeC and TreeD. + # + # This task runs after SDR + # TreeD is first computed with optional input of unsealed data + # TreeR is computed from replica, which is first computed as field + # addition of the last SDR layer and the bottom layer of TreeD (which is the unsealed data) + # TreeC is computed from the 11 SDR layers + # The 3 trees will later be used to compute the PoRep proof. + # + # In case of SyntheticPoRep challenges for PoRep will be pre-generated at this step, and trees and layers + # will be dropped. SyntheticPoRep works by pre-generating a very large set of challenges (~30GiB on disk) + # then using a small subset of them for the actual PoRep computation. This allows for significant scratch space + # saving between PreCommit and PoRep generation at the expense of more computation (generating challenges in this step) + # + # In lotus-miner this was run as part of PreCommit2 (TreeD was run in PreCommit1). + # Note that nodes with SDRTrees enabled will also answer to Finalize tasks, + # which just remove unneeded tree data after PoRep is computed. + # + # type: bool + #EnableSealSDRTrees = false + + # The maximum amount of SealSDRTrees tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. + # + # type: int + #SealSDRTreesMaxTasks = 0 + + # FinalizeMaxTasks is the maximum amount of finalize tasks that can run simultaneously. + # The finalize task is enabled on all machines which also handle SDRTrees tasks. Finalize ALWAYS runs on whichever + # machine holds sector cache files, as it removes unneeded tree data after PoRep is computed. + # Finalize will run in parallel with the SubmitCommitMsg task. + # + # type: int + #FinalizeMaxTasks = 0 + + # EnableSendPrecommitMsg enables the sending of precommit messages to the chain + # from this curio instance. + # This runs after SDRTrees and uses the output CommD / CommR (roots of TreeD / TreeR) for the message + # + # type: bool + #EnableSendPrecommitMsg = false + + # EnablePoRepProof enables the computation of the porep proof + # + # This task runs after interactive-porep seed becomes available, which happens 150 epochs (75min) after the + # precommit message lands on chain. This task should run on a machine with a GPU. Vanilla PoRep proofs are + # requested from the machine which holds sector cache files which most likely is the machine which ran the SDRTrees + # task. + # + # In lotus-miner this was Commit1 / Commit2 + # + # type: bool + #EnablePoRepProof = false + + # The maximum amount of PoRepProof tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. + # + # type: int + #PoRepProofMaxTasks = 0 + + # EnableSendCommitMsg enables the sending of commit messages to the chain + # from this curio instance. + # + # type: bool + #EnableSendCommitMsg = false + + # EnableMoveStorage enables the move-into-long-term-storage task to run on this curio instance. + # This tasks should only be enabled on nodes with long-term storage. + # + # The MoveStorage task is the last task in the sealing pipeline. It moves the sealed sector data from the + # SDRTrees machine into long-term storage. This task runs after the Finalize task. + # + # type: bool + #EnableMoveStorage = false + + # The maximum amount of MoveStorage tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. It is recommended that this value is set to a number which + # uses all available network (or disk) bandwidth on the machine without causing bottlenecks. + # + # type: int + #MoveStorageMaxTasks = 0 + + # EnableWebGui enables the web GUI on this curio instance. The UI has minimal local overhead, but it should + # only need to be run on a single machine in the cluster. + # + # type: bool + #EnableWebGui = false + + # The address that should listen for Web GUI requests. + # + # type: string + #GuiAddress = ":4701" + + +[Fees] + # type: types.FIL + #DefaultMaxFee = "0.07 FIL" + + # type: types.FIL + #MaxPreCommitGasFee = "0.025 FIL" + + # type: types.FIL + #MaxCommitGasFee = "0.05 FIL" + + # type: types.FIL + #MaxTerminateGasFee = "0.5 FIL" + + # WindowPoSt is a high-value operation, so the default fee should be high. + # + # type: types.FIL + #MaxWindowPoStGasFee = "5 FIL" + + # type: types.FIL + #MaxPublishDealsFee = "0.05 FIL" + + [Fees.MaxPreCommitBatchGasFee] + # type: types.FIL + #Base = "0 FIL" + + # type: types.FIL + #PerSector = "0.02 FIL" + + [Fees.MaxCommitBatchGasFee] + # type: types.FIL + #Base = "0 FIL" + + # type: types.FIL + #PerSector = "0.03 FIL" + +[[Addresses]] + #PreCommitControl = [] + + #CommitControl = [] + + #TerminateControl = [] + + #DisableOwnerFallback = false + + #DisableWorkerFallback = false + + MinerAddresses = ["t01013"] + + +[[Addresses]] + #PreCommitControl = [] + + #CommitControl = [] + + #TerminateControl = [] + + #DisableOwnerFallback = false + + #DisableWorkerFallback = false + + #MinerAddresses = [] + + +[[Addresses]] + #PreCommitControl = [] + + #CommitControl = [] + + #TerminateControl = [] + + #DisableOwnerFallback = false + + #DisableWorkerFallback = false + + MinerAddresses = ["t01006"] + + +[Proving] + # Maximum number of sector checks to run in parallel. (0 = unlimited) + # + # WARNING: Setting this value too high may make the node crash by running out of stack + # WARNING: Setting this value too low may make sector challenge reading much slower, resulting in failed PoSt due + # to late submission. + # + # After changing this option, confirm that the new value works in your setup by invoking + # 'lotus-miner proving compute window-post 0' + # + # type: int + #ParallelCheckLimit = 32 + + # Maximum amount of time a proving pre-check can take for a sector. If the check times out the sector will be skipped + # + # WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the + # test challenge took longer than this timeout + # WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this sector are + # blocked (e.g. in case of disconnected NFS mount) + # + # type: Duration + #SingleCheckTimeout = "10m0s" + + # Maximum amount of time a proving pre-check can take for an entire partition. If the check times out, sectors in + # the partition which didn't get checked on time will be skipped + # + # WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the + # test challenge took longer than this timeout + # WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this partition are + # blocked or slow + # + # type: Duration + #PartitionCheckTimeout = "20m0s" + + # Disable Window PoSt computation on the lotus-miner process even if no window PoSt workers are present. + # + # WARNING: If no windowPoSt workers are connected, window PoSt WILL FAIL resulting in faulty sectors which will need + # to be recovered. Before enabling this option, make sure your PoSt workers work correctly. + # + # After changing this option, confirm that the new value works in your setup by invoking + # 'lotus-miner proving compute window-post 0' + # + # type: bool + #DisableBuiltinWindowPoSt = false + + # Disable Winning PoSt computation on the lotus-miner process even if no winning PoSt workers are present. + # + # WARNING: If no WinningPoSt workers are connected, Winning PoSt WILL FAIL resulting in lost block rewards. + # Before enabling this option, make sure your PoSt workers work correctly. + # + # type: bool + #DisableBuiltinWinningPoSt = false + + # Disable WindowPoSt provable sector readability checks. + # + # In normal operation, when preparing to compute WindowPoSt, lotus-miner will perform a round of reading challenges + # from all sectors to confirm that those sectors can be proven. Challenges read in this process are discarded, as + # we're only interested in checking that sector data can be read. + # + # When using builtin proof computation (no PoSt workers, and DisableBuiltinWindowPoSt is set to false), this process + # can save a lot of time and compute resources in the case that some sectors are not readable - this is caused by + # the builtin logic not skipping snark computation when some sectors need to be skipped. + # + # When using PoSt workers, this process is mostly redundant, with PoSt workers challenges will be read once, and + # if challenges for some sectors aren't readable, those sectors will just get skipped. + # + # Disabling sector pre-checks will slightly reduce IO load when proving sectors, possibly resulting in shorter + # time to produce window PoSt. In setups with good IO capabilities the effect of this option on proving time should + # be negligible. + # + # NOTE: It likely is a bad idea to disable sector pre-checks in setups with no PoSt workers. + # + # NOTE: Even when this option is enabled, recovering sectors will be checked before recovery declaration message is + # sent to the chain + # + # After changing this option, confirm that the new value works in your setup by invoking + # 'lotus-miner proving compute window-post 0' + # + # type: bool + #DisableWDPoStPreChecks = false + + # Maximum number of partitions to prove in a single SubmitWindowPoSt messace. 0 = network limit (3 in nv21) + # + # A single partition may contain up to 2349 32GiB sectors, or 2300 64GiB sectors. + # // + # Note that setting this value lower may result in less efficient gas use - more messages will be sent, + # to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) + # + # Setting this value above the network limit has no effect + # + # type: int + #MaxPartitionsPerPoStMessage = 0 + + # In some cases when submitting DeclareFaultsRecovered messages, + # there may be too many recoveries to fit in a BlockGasLimit. + # In those cases it may be necessary to set this value to something low (eg 1); + # Note that setting this value lower may result in less efficient gas use - more messages will be sent than needed, + # resulting in more total gas use (but each message will have lower gas limit) + # + # type: int + #MaxPartitionsPerRecoveryMessage = 0 + + # Enable single partition per PoSt Message for partitions containing recovery sectors + # + # In cases when submitting PoSt messages which contain recovering sectors, the default network limit may still be + # too high to fit in the block gas limit. In those cases, it becomes useful to only house the single partition + # with recovering sectors in the post message + # + # Note that setting this value lower may result in less efficient gas use - more messages will be sent, + # to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) + # + # type: bool + #SingleRecoveringPartitionPerPostMessage = false + + +[Journal] + # Events of the form: "system1:event1,system1:event2[,...]" + # + # type: string + #DisabledEvents = "" + + +[Apis] + # ChainApiInfo is the API endpoint for the Lotus daemon. + # + # type: []string + ChainApiInfo = ["eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJBbGxvdyI6WyJyZWFkIiwid3JpdGUiLCJzaWduIiwiYWRtaW4iXX0.T_jmG4DTs9Zjd7rr78862lT7D2U63uz-zqcUKHwcqaU:/dns/localhost/tcp/1234/http"] + + # RPC Secret for the storage subsystem. + # If integrating with lotus-miner this must match the value from + # cat ~/.lotusminer/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU | jq -r .PrivateKey + # + # type: string + StorageRPCSecret = "HxHe8YLHiY0LjHVw/WT/4XQkPGgRyCEYk+xiFi0Ob0o=" + +` + +func TestConfig(t *testing.T) { + baseCfg := config.DefaultCurioConfig() + + addr1 := config.CurioAddresses{ + PreCommitControl: []string{}, + CommitControl: []string{}, + TerminateControl: []string{"t3qroiebizgkz7pvj26reg5r5mqiftrt5hjdske2jzjmlacqr2qj7ytjncreih2mvujxoypwpfusmwpipvxncq"}, + DisableOwnerFallback: false, + DisableWorkerFallback: false, + MinerAddresses: []string{"t01000"}, + } + + addr2 := config.CurioAddresses{ + MinerAddresses: []string{"t01001"}, + } + + _, err := deps.LoadConfigWithUpgrades(baseText, baseCfg) + require.NoError(t, err) + + baseCfg.Addresses = append(baseCfg.Addresses, addr1) + baseCfg.Addresses = lo.Filter(baseCfg.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + + _, err = config.ConfigUpdate(baseCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + require.NoError(t, err) + + baseCfg.Addresses = append(baseCfg.Addresses, addr2) + baseCfg.Addresses = lo.Filter(baseCfg.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + + _, err = config.ConfigUpdate(baseCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + require.NoError(t, err) + +} + +func TestCustomConfigDurationJson(t *testing.T) { + ref := new(jsonschema.Reflector) + ref.Mapper = func(i reflect.Type) *jsonschema.Schema { + if i == reflect.TypeOf(config.Duration(time.Second)) { + return &jsonschema.Schema{ + Type: "string", + Format: "duration", + } + } + return nil + } + + sch := ref.Reflect(config.CurioConfig{}) + definitions := sch.Definitions["CurioProvingConfig"] + prop, ok := definitions.Properties.Get("SingleCheckTimeout") + require.True(t, ok) + require.Equal(t, prop.Type, "string") +} diff --git a/cmd/curio/deps/apiinfo.go b/cmd/curio/deps/apiinfo.go new file mode 100644 index 00000000000..0dd96d81735 --- /dev/null +++ b/cmd/curio/deps/apiinfo.go @@ -0,0 +1,94 @@ +package deps + +import ( + "fmt" + "net/http" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-jsonrpc" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/lotus/api/v1api" + cliutil "github.com/filecoin-project/lotus/cli/util" +) + +func getFullNodeAPIV1Curio(ctx *cli.Context, ainfoCfg []string, opts ...cliutil.GetFullNodeOption) (v1api.FullNode, jsonrpc.ClientCloser, error) { + if tn, ok := ctx.App.Metadata["testnode-full"]; ok { + return tn.(v1api.FullNode), func() {}, nil + } + + var options cliutil.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")) + } + + var httpHeads []httpHead + version := "v1" + { + if len(ainfoCfg) == 0 { + return nil, nil, xerrors.Errorf("could not get API info: none configured. \nConsider getting base.toml with './curio config get base >/tmp/base.toml' \nthen adding \n[APIs] \n ChainApiInfo = [\" result_from lotus auth api-info --perm=admin \"]\n and updating it with './curio config set /tmp/base.toml'") + } + for _, i := range ainfoCfg { + ainfo := cliutil.ParseApiInfo(i) + addr, err := ainfo.DialArgs(version) + if err != nil { + return nil, nil, xerrors.Errorf("could not get DialArgs: %w", err) + } + httpHeads = append(httpHeads, httpHead{addr: addr, header: ainfo.AuthHeader()}) + } + } + + if cliutil.IsVeryVerbose { + _, _ = fmt.Fprintln(ctx.App.Writer, "using full node API v1 endpoint:", httpHeads[0].addr) + } + + var fullNodes []api.FullNode + var closers []jsonrpc.ClientCloser + + for _, head := range httpHeads { + 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: %s, Reason: %s", head.addr, err.Error()) + continue + } + fullNodes = append(fullNodes, v1api) + closers = append(closers, closer) + } + + // When running in cluster mode and trying to establish connections to multiple nodes, fail + // if less than 2 lotus nodes are actually running + if len(httpHeads) > 1 && len(fullNodes) < 2 { + return nil, nil, xerrors.Errorf("Not able to establish connection to more than a single node") + } + + finalCloser := func() { + for _, c := range closers { + c() + } + } + + var v1API api.FullNodeStruct + cliutil.FullNodeProxy(fullNodes, &v1API) + + v, err := v1API.Version(ctx.Context) + if err != nil { + return nil, nil, err + } + if !v.APIVersion.EqMajorMinor(api.FullAPIVersion1) { + return nil, nil, xerrors.Errorf("Remote API version didn't match (expected %s, remote %s)", api.FullAPIVersion1, v.APIVersion) + } + return &v1API, finalCloser, nil +} + +type httpHead struct { + addr string + header http.Header +} diff --git a/cmd/curio/deps/deps.go b/cmd/curio/deps/deps.go new file mode 100644 index 00000000000..2050a1cafba --- /dev/null +++ b/cmd/curio/deps/deps.go @@ -0,0 +1,537 @@ +// Package deps provides the dependencies for the curio node. +package deps + +import ( + "context" + "crypto/rand" + "database/sql" + "encoding/base64" + "errors" + "fmt" + "io" + "net" + "net/http" + "net/url" + "os" + "path/filepath" + "strings" + + "github.com/BurntSushi/toml" + "github.com/gbrlsnchs/jwt/v3" + ds "github.com/ipfs/go-datastore" + dssync "github.com/ipfs/go-datastore/sync" + logging "github.com/ipfs/go-log/v2" + "github.com/samber/lo" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc/auth" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-statestore" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/v1api" + "github.com/filecoin-project/lotus/chain/types" + curio "github.com/filecoin-project/lotus/curiosrc" + "github.com/filecoin-project/lotus/curiosrc/multictladdr" + "github.com/filecoin-project/lotus/journal" + "github.com/filecoin-project/lotus/journal/alerting" + "github.com/filecoin-project/lotus/journal/fsjournal" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/node/modules" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/lotus/storage/paths" + "github.com/filecoin-project/lotus/storage/sealer" + "github.com/filecoin-project/lotus/storage/sealer/ffiwrapper" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +var log = logging.Logger("curio/deps") + +func MakeDB(cctx *cli.Context) (*harmonydb.DB, error) { + // #1 CLI opts + fromCLI := func() (*harmonydb.DB, error) { + dbConfig := config.HarmonyDB{ + Username: cctx.String("db-user"), + Password: cctx.String("db-password"), + Hosts: strings.Split(cctx.String("db-host"), ","), + Database: cctx.String("db-name"), + Port: cctx.String("db-port"), + } + return harmonydb.NewFromConfig(dbConfig) + } + + readToml := func(path string) (*harmonydb.DB, error) { + cfg, err := config.FromFile(path) + if err != nil { + return nil, err + } + if c, ok := cfg.(*config.StorageMiner); ok { + return harmonydb.NewFromConfig(c.HarmonyDB) + } + return nil, errors.New("not a miner config") + } + + // #2 Try local miner config + fromMinerEnv := func() (*harmonydb.DB, error) { + v := os.Getenv("LOTUS_MINER_PATH") + if v == "" { + return nil, errors.New("no miner env") + } + return readToml(filepath.Join(v, "config.toml")) + + } + + fromMiner := func() (*harmonydb.DB, error) { + u, err := os.UserHomeDir() + if err != nil { + return nil, err + } + return readToml(filepath.Join(u, ".lotusminer/config.toml")) + } + fromEnv := func() (*harmonydb.DB, error) { + // #3 Try env + u, err := url.Parse(os.Getenv("CURIO_DB")) + if err != nil { + return nil, errors.New("no db connection string found in CURIO_DB env") + } + cfg := config.DefaultStorageMiner().HarmonyDB + if u.User.Username() != "" { + cfg.Username = u.User.Username() + } + if p, ok := u.User.Password(); ok && p != "" { + cfg.Password = p + } + if u.Hostname() != "" { + cfg.Hosts = []string{u.Hostname()} + } + if u.Port() != "" { + cfg.Port = u.Port() + } + if strings.TrimPrefix(u.Path, "/") != "" { + cfg.Database = strings.TrimPrefix(u.Path, "/") + } + + return harmonydb.NewFromConfig(cfg) + } + + for _, f := range []func() (*harmonydb.DB, error){fromCLI, fromMinerEnv, fromMiner, fromEnv} { + db, err := f() + if err != nil { + continue + } + return db, nil + } + log.Error("No db connection string found. User CLI args or env var: set CURIO_DB=postgres://USER:PASSWORD@HOST:PORT/DATABASE") + return fromCLI() //in-case it's not about bad config. +} + +type JwtPayload struct { + Allow []auth.Permission +} + +func StorageAuth(apiKey string) (sealer.StorageAuth, error) { + if apiKey == "" { + return nil, xerrors.Errorf("no api key provided") + } + + rawKey, err := base64.StdEncoding.DecodeString(apiKey) + if err != nil { + return nil, xerrors.Errorf("decoding api key: %w", err) + } + + key := jwt.NewHS256(rawKey) + + p := JwtPayload{ + Allow: []auth.Permission{"admin"}, + } + + token, err := jwt.Sign(&p, key) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Add("Authorization", "Bearer "+string(token)) + return sealer.StorageAuth(headers), nil +} + +func GetDeps(ctx context.Context, cctx *cli.Context) (*Deps, error) { + var deps Deps + return &deps, deps.PopulateRemainingDeps(ctx, cctx, true) +} + +type Deps struct { + Layers []string + Cfg *config.CurioConfig // values + DB *harmonydb.DB // has itest capability + Full api.FullNode + Verif storiface.Verifier + LW *sealer.LocalWorker + As *multictladdr.MultiAddressSelector + Maddrs map[dtypes.MinerAddress]bool + ProofTypes map[abi.RegisteredSealProof]bool + Stor *paths.Remote + Si *paths.DBIndex + LocalStore *paths.Local + LocalPaths *paths.BasicLocalStorage + ListenAddr string +} + +const ( + FlagRepoPath = "repo-path" +) + +func (deps *Deps) PopulateRemainingDeps(ctx context.Context, cctx *cli.Context, makeRepo bool) error { + var err error + if makeRepo { + // Open repo + repoPath := cctx.String(FlagRepoPath) + fmt.Println("repopath", repoPath) + r, err := repo.NewFS(repoPath) + if err != nil { + return err + } + + ok, err := r.Exists() + if err != nil { + return err + } + if !ok { + if err := r.Init(repo.Curio); err != nil { + return err + } + } + } + + if deps.Cfg == nil { + deps.DB, err = MakeDB(cctx) + if err != nil { + return err + } + } + if deps.Layers == nil { + deps.Layers = append([]string{"base"}, cctx.StringSlice("layers")...) // Always stack on top of "base" layer + } + + if deps.Cfg == nil { + // The config feeds into task runners & their helpers + deps.Cfg, err = GetConfig(cctx, deps.DB) + if err != nil { + return xerrors.Errorf("populate config: %w", err) + } + } + + log.Debugw("config", "config", deps.Cfg) + + if deps.Verif == nil { + deps.Verif = ffiwrapper.ProofVerifier + } + + if deps.As == nil { + deps.As, err = curio.AddressSelector(deps.Cfg.Addresses)() + if err != nil { + return err + } + } + + if deps.Si == nil { + de, err := journal.ParseDisabledEvents(deps.Cfg.Journal.DisabledEvents) + if err != nil { + return err + } + j, err := fsjournal.OpenFSJournalPath(cctx.String("journal"), de) + if err != nil { + return err + } + go func() { + <-ctx.Done() + _ = j.Close() + }() + + al := alerting.NewAlertingSystem(j) + deps.Si = paths.NewDBIndex(al, deps.DB) + } + + if deps.Full == nil { + var fullCloser func() + cfgApiInfo := deps.Cfg.Apis.ChainApiInfo + if v := os.Getenv("FULLNODE_API_INFO"); v != "" { + cfgApiInfo = []string{v} + } + deps.Full, fullCloser, err = getFullNodeAPIV1Curio(cctx, cfgApiInfo) + if err != nil { + return err + } + + go func() { + <-ctx.Done() + fullCloser() + }() + } + + deps.LocalPaths = &paths.BasicLocalStorage{ + PathToJSON: cctx.String("storage-json"), + } + + if deps.ListenAddr == "" { + listenAddr := cctx.String("listen") + const unspecifiedAddress = "0.0.0.0" + addressSlice := strings.Split(listenAddr, ":") + if ip := net.ParseIP(addressSlice[0]); ip != nil { + if ip.String() == unspecifiedAddress { + rip, err := deps.DB.GetRoutableIP() + if err != nil { + return err + } + deps.ListenAddr = rip + ":" + addressSlice[1] + } + } + } + if deps.LocalStore == nil { + deps.LocalStore, err = paths.NewLocal(ctx, deps.LocalPaths, deps.Si, []string{"http://" + deps.ListenAddr + "/remote"}) + if err != nil { + return err + } + } + + sa, err := StorageAuth(deps.Cfg.Apis.StorageRPCSecret) + if err != nil { + return xerrors.Errorf(`'%w' while parsing the config toml's + [Apis] + StorageRPCSecret=%v +Get it with: jq .PrivateKey ~/.lotus-miner/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU`, err, deps.Cfg.Apis.StorageRPCSecret) + } + if deps.Stor == nil { + deps.Stor = paths.NewRemote(deps.LocalStore, deps.Si, http.Header(sa), 10, &paths.DefaultPartialFileHandler{}) + } + if deps.LW == nil { + wstates := statestore.New(dssync.MutexWrap(ds.NewMapDatastore())) + + // todo localWorker isn't the abstraction layer we want to use here, we probably want to go straight to ffiwrapper + // maybe with a curio specific abstraction. LocalWorker does persistent call tracking which we probably + // don't need (ehh.. maybe we do, the async callback system may actually work decently well with harmonytask) + deps.LW = sealer.NewLocalWorker(sealer.WorkerConfig{ + MaxParallelChallengeReads: deps.Cfg.Proving.ParallelCheckLimit, + }, deps.Stor, deps.LocalStore, deps.Si, nil, wstates) + } + if deps.Maddrs == nil { + deps.Maddrs = map[dtypes.MinerAddress]bool{} + } + if len(deps.Maddrs) == 0 { + for _, s := range deps.Cfg.Addresses { + for _, s := range s.MinerAddresses { + addr, err := address.NewFromString(s) + if err != nil { + return err + } + deps.Maddrs[dtypes.MinerAddress(addr)] = true + } + } + } + + if deps.ProofTypes == nil { + deps.ProofTypes = map[abi.RegisteredSealProof]bool{} + } + if len(deps.ProofTypes) == 0 { + for maddr := range deps.Maddrs { + spt, err := modules.SealProofType(maddr, deps.Full) + if err != nil { + return err + } + deps.ProofTypes[spt] = true + } + } + + return nil +} + +func LoadConfigWithUpgrades(text string, curioConfigWithDefaults *config.CurioConfig) (toml.MetaData, error) { + // allow migration from old config format that was limited to 1 wallet setup. + newText := strings.Join(lo.Map(strings.Split(text, "\n"), func(line string, _ int) string { + if strings.EqualFold(line, "[addresses]") { + return "[[addresses]]" + } + return line + }), "\n") + meta, err := toml.Decode(newText, &curioConfigWithDefaults) + for i := range curioConfigWithDefaults.Addresses { + if curioConfigWithDefaults.Addresses[i].PreCommitControl == nil { + curioConfigWithDefaults.Addresses[i].PreCommitControl = []string{} + } + if curioConfigWithDefaults.Addresses[i].CommitControl == nil { + curioConfigWithDefaults.Addresses[i].CommitControl = []string{} + } + if curioConfigWithDefaults.Addresses[i].TerminateControl == nil { + curioConfigWithDefaults.Addresses[i].TerminateControl = []string{} + } + } + return meta, err +} +func GetConfig(cctx *cli.Context, db *harmonydb.DB) (*config.CurioConfig, error) { + curioConfig := config.DefaultCurioConfig() + have := []string{} + layers := append([]string{"base"}, cctx.StringSlice("layers")...) // Always stack on top of "base" layer + for _, layer := range layers { + text := "" + err := db.QueryRow(cctx.Context, `SELECT config FROM harmony_config WHERE title=$1`, layer).Scan(&text) + if err != nil { + if strings.Contains(err.Error(), sql.ErrNoRows.Error()) { + return nil, fmt.Errorf("missing layer '%s' ", layer) + } + if layer == "base" { + return nil, errors.New(`curio defaults to a layer named 'base'. + Either use 'migrate' command or edit a base.toml and upload it with: curio config set base.toml`) + } + return nil, fmt.Errorf("could not read layer '%s': %w", layer, err) + } + + meta, err := LoadConfigWithUpgrades(text, curioConfig) + if err != nil { + return curioConfig, fmt.Errorf("could not read layer, bad toml %s: %w", layer, err) + } + for _, k := range meta.Keys() { + have = append(have, strings.Join(k, " ")) + } + log.Debugw("Using layer", "layer", layer, "config", curioConfig) + } + _ = have // FUTURE: verify that required fields are here. + // If config includes 3rd-party config, consider JSONSchema as a way that + // 3rd-parties can dynamically include config requirements and we can + // validate the config. Because of layering, we must validate @ startup. + return curioConfig, nil +} + +func GetDefaultConfig(comment bool) (string, error) { + c := config.DefaultCurioConfig() + cb, err := config.ConfigUpdate(c, nil, config.Commented(comment), config.DefaultKeepUncommented(), config.NoEnv()) + if err != nil { + return "", err + } + return string(cb), nil +} + +func GetDepsCLI(ctx context.Context, cctx *cli.Context) (*Deps, error) { + db, err := MakeDB(cctx) + if err != nil { + return nil, err + } + + cfg, err := GetConfig(cctx, db) + if err != nil { + return nil, err + } + + full, fullCloser, err := getFullNodeAPIV1Curio(cctx, cfg.Apis.ChainApiInfo) + if err != nil { + return nil, err + } + go func() { + select { + case <-ctx.Done(): + fullCloser() + } + }() + + return &Deps{ + Cfg: cfg, + DB: db, + Full: full, + }, nil +} + +func CreateMinerConfig(ctx context.Context, full v1api.FullNode, db *harmonydb.DB, miners []string, info string) error { + var titles []string + err := db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + if err != nil { + return fmt.Errorf("cannot reach the db. Ensure that Yugabyte flags are set correctly to"+ + " reach Yugabyte: %s", err.Error()) + } + + // setup config + curioConfig := config.DefaultCurioConfig() + + for _, addr := range miners { + maddr, err := address.NewFromString(addr) + if err != nil { + return xerrors.Errorf("Invalid address: %s", addr) + } + + _, err = full.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("Failed to get miner info: %w", err) + } + + curioConfig.Addresses = append(curioConfig.Addresses, config.CurioAddresses{ + PreCommitControl: []string{}, + CommitControl: []string{}, + TerminateControl: []string{}, + DisableOwnerFallback: false, + DisableWorkerFallback: false, + MinerAddresses: []string{addr}, + }) + } + + { + sk, err := io.ReadAll(io.LimitReader(rand.Reader, 32)) + if err != nil { + return err + } + + curioConfig.Apis.StorageRPCSecret = base64.StdEncoding.EncodeToString(sk) + } + + { + curioConfig.Apis.ChainApiInfo = append(curioConfig.Apis.ChainApiInfo, info) + } + + curioConfig.Addresses = lo.Filter(curioConfig.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + + // If no base layer is present + if !lo.Contains(titles, "base") { + cb, err := config.ConfigUpdate(curioConfig, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + if err != nil { + return xerrors.Errorf("Failed to generate default config: %w", err) + } + cfg := string(cb) + _, err = db.Exec(ctx, "INSERT INTO harmony_config (title, config) VALUES ('base', $1)", cfg) + if err != nil { + return xerrors.Errorf("failed to insert the 'base' into the database: %w", err) + } + fmt.Printf("The base layer has been updated with miner[s] %s\n", miners) + return nil + } + + // if base layer is present + baseCfg := config.DefaultCurioConfig() + var baseText string + err = db.QueryRow(ctx, "SELECT config FROM harmony_config WHERE title='base'").Scan(&baseText) + if err != nil { + return xerrors.Errorf("Cannot load base config from database: %w", err) + } + _, err = LoadConfigWithUpgrades(baseText, baseCfg) + if err != nil { + return xerrors.Errorf("Cannot parse base config: %w", err) + } + + baseCfg.Addresses = append(baseCfg.Addresses, curioConfig.Addresses...) + baseCfg.Addresses = lo.Filter(baseCfg.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + + cb, err := config.ConfigUpdate(baseCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + if err != nil { + return xerrors.Errorf("cannot interpret config: %w", err) + } + _, err = db.Exec(ctx, "UPDATE harmony_config SET config=$1 WHERE title='base'", string(cb)) + if err != nil { + return xerrors.Errorf("cannot update base config: %w", err) + } + fmt.Printf("The base layer has been updated with miner[s] %s\n", miners) + return nil +} diff --git a/cmd/curio/guidedsetup/guidedsetup.go b/cmd/curio/guidedsetup/guidedsetup.go new file mode 100644 index 00000000000..1bdb8e784ca --- /dev/null +++ b/cmd/curio/guidedsetup/guidedsetup.go @@ -0,0 +1,881 @@ +// guidedSetup for migration from lotus-miner to Curio +// +// IF STRINGS CHANGED { +// follow instructions at ../internal/translations/translations.go +// } +package guidedsetup + +import ( + "bytes" + "context" + "crypto/rand" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "math/bits" + "net/http" + "os" + "os/signal" + "path" + "reflect" + "strconv" + "strings" + "syscall" + "time" + + "github.com/BurntSushi/toml" + "github.com/charmbracelet/lipgloss" + "github.com/docker/go-units" + "github.com/manifoldco/promptui" + "github.com/mitchellh/go-homedir" + "github.com/samber/lo" + "github.com/urfave/cli/v2" + "golang.org/x/text/language" + "golang.org/x/text/message" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/v1api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/cli/spcli" + cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/cmd/curio/deps" + _ "github.com/filecoin-project/lotus/cmd/curio/internal/translations" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/node/repo" +) + +// URL to upload user-selected fields to help direct developer's focus. +const DeveloperFocusRequestURL = "https://curiostorage.org/cgi-bin/savedata.php" + +var GuidedsetupCmd = &cli.Command{ + Name: "guided-setup", + Usage: "Run the guided setup for migrating from lotus-miner to Curio or Creating a new Curio miner", + Flags: []cli.Flag{ + &cli.StringFlag{ // for cliutil.GetFullNodeAPI + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", + }, + }, + Action: func(cctx *cli.Context) (err error) { + T, say := SetupLanguage() + setupCtrlC(say) + + // Run the migration steps + migrationData := MigrationData{ + T: T, + say: say, + selectTemplates: &promptui.SelectTemplates{ + Help: T("Use the arrow keys to navigate: ↓ ↑ → ← "), + }, + cctx: cctx, + ctx: cctx.Context, + } + + newOrMigrate(&migrationData) + if migrationData.init { + say(header, "This interactive tool creates a new miner actor and creates the basic configuration layer for it.") + say(notice, "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster < miner ID >' to finish the configuration.") + for _, step := range newMinerSteps { + step(&migrationData) + } + } else { + say(header, "This interactive tool migrates lotus-miner to Curio in 5 minutes.") + say(notice, "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.") + + for _, step := range migrationSteps { + step(&migrationData) + } + } + + for _, closer := range migrationData.closers { + closer() + } + return nil + }, +} + +func setupCtrlC(say func(style lipgloss.Style, key message.Reference, a ...interface{})) { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + go func() { + <-c + say(notice, "Ctrl+C pressed in Terminal") + os.Exit(2) + }() +} + +var ( + header = lipgloss.NewStyle(). + Align(lipgloss.Left). + Foreground(lipgloss.Color("#00FF00")). + Background(lipgloss.Color("#242424")). + BorderStyle(lipgloss.NormalBorder()). + Width(60).Margin(1) + + notice = lipgloss.NewStyle(). + Align(lipgloss.Left). + Bold(true). + Foreground(lipgloss.Color("#CCCCCC")). + Background(lipgloss.Color("#333300")).MarginBottom(1) + + green = lipgloss.NewStyle(). + Align(lipgloss.Left). + Foreground(lipgloss.Color("#00FF00")). + Background(lipgloss.Color("#000000")) + + plain = lipgloss.NewStyle().Align(lipgloss.Left) + + section = lipgloss.NewStyle(). + Align(lipgloss.Left). + Foreground(lipgloss.Color("#000000")). + Background(lipgloss.Color("#FFFFFF")). + Underline(true) + + code = lipgloss.NewStyle(). + Align(lipgloss.Left). + Foreground(lipgloss.Color("#00FF00")). + Background(lipgloss.Color("#f8f9fa")) +) + +func SetupLanguage() (func(key message.Reference, a ...interface{}) string, func(style lipgloss.Style, key message.Reference, a ...interface{})) { + langText := "en" + problem := false + if len(os.Getenv("LANG")) > 1 { + langText = os.Getenv("LANG")[:2] + } else { + problem = true + } + + lang, err := language.Parse(langText) + if err != nil { + lang = language.English + problem = true + fmt.Println("Error parsing language") + } + + langs := message.DefaultCatalog.Languages() + have := lo.SliceToMap(langs, func(t language.Tag) (string, bool) { return t.String(), true }) + if _, ok := have[lang.String()]; !ok { + lang = language.English + problem = true + } + if problem { + _ = os.Setenv("LANG", "en-US") // for later users of this function + notice.Copy().AlignHorizontal(lipgloss.Right). + Render("$LANG=" + langText + " unsupported. Available: " + strings.Join(lo.Keys(have), ", ")) + fmt.Println("Defaulting to English. Please reach out to the Curio team if you would like to have additional language support.") + } + return func(key message.Reference, a ...interface{}) string { + return message.NewPrinter(lang).Sprintf(key, a...) + }, func(sty lipgloss.Style, key message.Reference, a ...interface{}) { + msg := message.NewPrinter(lang).Sprintf(key, a...) + fmt.Println(sty.Render(msg)) + } +} + +func newOrMigrate(d *MigrationData) { + i, _, err := (&promptui.Select{ + Label: d.T("I want to:"), + Items: []string{ + d.T("Migrate from existing Lotus-Miner"), + d.T("Create a new miner")}, + Templates: d.selectTemplates, + }).Run() + if err != nil { + d.say(notice, "Aborting remaining steps.", err.Error()) + os.Exit(1) + } + if i == 1 { + d.init = true + } +} + +type migrationStep func(*MigrationData) + +var migrationSteps = []migrationStep{ + readMinerConfig, // Tells them to be on the miner machine + yugabyteConnect, // Miner is updated + configToDB, // work on base configuration migration. + verifySectors, // Verify the sectors are in the database + doc, + oneLastThing, + complete, +} + +type newMinerStep func(data *MigrationData) + +var newMinerSteps = []newMinerStep{ + stepPresteps, + stepCreateActor, + stepNewMinerConfig, + doc, + oneLastThing, + completeInit, +} + +type MigrationData struct { + T func(key message.Reference, a ...interface{}) string + say func(style lipgloss.Style, key message.Reference, a ...interface{}) + selectTemplates *promptui.SelectTemplates + MinerConfigPath string + MinerConfig *config.StorageMiner + DB *harmonydb.DB + MinerID address.Address + full v1api.FullNode + cctx *cli.Context + closers []jsonrpc.ClientCloser + ctx context.Context + owner address.Address + worker address.Address + sender address.Address + ssize abi.SectorSize + confidence uint64 + init bool +} + +func complete(d *MigrationData) { + stepCompleted(d, d.T("Lotus-Miner to Curio Migration.")) + d.say(plain, "Try the web interface with %s for further guided improvements.", code.Render("curio run --layers=gui")) + d.say(plain, "You can now migrate your market node (%s), if applicable.", "Boost") +} + +func completeInit(d *MigrationData) { + stepCompleted(d, d.T("New Miner initialization complete.")) + d.say(plain, "Try the web interface with %s for further guided improvements.", "--layers=gui") +} + +func configToDB(d *MigrationData) { + d.say(section, "Migrating lotus-miner config.toml to Curio in-database configuration.") + + { + var closer jsonrpc.ClientCloser + var err error + d.full, closer, err = cliutil.GetFullNodeAPIV1(d.cctx) + d.closers = append(d.closers, closer) + if err != nil { + d.say(notice, "Error getting API: %s", err.Error()) + os.Exit(1) + } + } + ainfo, err := cliutil.GetAPIInfo(d.cctx, repo.FullNode) + if err != nil { + d.say(notice, "could not get API info for FullNode: %w", err) + os.Exit(1) + } + token, err := d.full.AuthNew(context.Background(), api.AllPermissions) + if err != nil { + d.say(notice, "Error getting token: %s", err.Error()) + os.Exit(1) + } + + chainApiInfo := fmt.Sprintf("%s:%s", string(token), ainfo.Addr) + + d.MinerID, err = SaveConfigToLayer(d.MinerConfigPath, chainApiInfo) + if err != nil { + d.say(notice, "Error saving config to layer: %s. Aborting Migration", err.Error()) + os.Exit(1) + } +} + +// bucket returns the power's 4 highest bits (rounded down). +func bucket(power *api.MinerPower) uint64 { + rawQAP := power.TotalPower.QualityAdjPower.Uint64() + magnitude := lo.Max([]int{bits.Len64(rawQAP), 5}) + + // shifting erases resolution so we cannot distinguish SPs of similar scales. + return rawQAP >> (uint64(magnitude) - 4) << (uint64(magnitude - 4)) +} + +type uploadType int + +const uploadTypeIndividual uploadType = 0 +const uploadTypeAggregate uploadType = 1 + +// const uploadTypeHint uploadType = 2 +const uploadTypeNothing uploadType = 3 + +func oneLastThing(d *MigrationData) { + d.say(section, "The Curio team wants to improve the software you use. Tell the team you're using `%s`.", "curio") + i, _, err := (&promptui.Select{ + Label: d.T("Select what you want to share with the Curio team."), + Items: []string{ + d.T("Individual Data: Miner ID, Curio version, chain (%s or %s). Signed.", "mainnet", "calibration"), + d.T("Aggregate-Anonymous: version, chain, and Miner power (bucketed)."), + d.T("Hint: I am someone running Curio on whichever chain."), + d.T("Nothing.")}, + Templates: d.selectTemplates, + }).Run() + preference := uploadType(i) + if err != nil { + d.say(notice, "Aborting remaining steps.", err.Error()) + os.Exit(1) + } + if preference != uploadTypeNothing { + msgMap := map[string]any{ + "domain": "curio-newuser", + "net": build.BuildTypeString(), + } + if preference == uploadTypeIndividual || preference == uploadTypeAggregate { + // articles of incorporation + power, err := d.full.StateMinerPower(context.Background(), d.MinerID, types.EmptyTSK) + if err != nil { + d.say(notice, "Error getting miner power: %s", err.Error()) + os.Exit(1) + } + msgMap["version"] = build.BuildVersion + msgMap["net"] = build.BuildType + msgMap["power"] = map[uploadType]uint64{ + uploadTypeIndividual: power.MinerPower.QualityAdjPower.Uint64(), + uploadTypeAggregate: bucket(power)}[preference] + + if preference == uploadTypeIndividual { // Sign it + msgMap["miner_id"] = d.MinerID + msg, err := json.Marshal(msgMap) + if err != nil { + d.say(notice, "Error marshalling message: %s", err.Error()) + os.Exit(1) + } + mi, err := d.full.StateMinerInfo(context.Background(), d.MinerID, types.EmptyTSK) + if err != nil { + d.say(notice, "Error getting miner info: %s", err.Error()) + os.Exit(1) + } + sig, err := d.full.WalletSign(context.Background(), mi.Worker, msg) + if err != nil { + d.say(notice, "Error signing message: %s", err.Error()) + os.Exit(1) + } + msgMap["signature"] = base64.StdEncoding.EncodeToString(sig.Data) + } + } + msg, err := json.Marshal(msgMap) + if err != nil { + d.say(notice, "Error marshalling message: %s", err.Error()) + os.Exit(1) + } + + resp, err := http.DefaultClient.Post(DeveloperFocusRequestURL, "application/json", bytes.NewReader(msg)) + if err != nil { + d.say(notice, "Error sending message: %s", err.Error()) + } + if resp != nil { + defer func() { _ = resp.Body.Close() }() + if resp.StatusCode != 200 { + b, err := io.ReadAll(resp.Body) + if err == nil { + d.say(notice, "Error sending message: Status %s, Message: ", resp.Status, string(b)) + } + } else { + stepCompleted(d, d.T("Message sent.")) + } + } + } +} + +func doc(d *MigrationData) { + d.say(plain, "Documentation: ") + d.say(plain, "The '%s' layer stores common configuration. All curio instances can include it in their %s argument.", "base", "--layers") + d.say(plain, "You can add other layers for per-machine configuration changes.") + + d.say(plain, "Filecoin %s channels: %s and %s", "Slack", "#fil-curio-help", "#fil-curio-dev") + + d.say(plain, "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'") + //d.say(plain, "Point your browser to your web GUI to complete setup with %s and advanced featues.", "Boost") + d.say(plain, "One database can serve multiple miner IDs: Run a migration for each lotus-miner.") +} + +func verifySectors(d *MigrationData) { + var i []int + var lastError string + fmt.Println() + d.say(section, "Please start (or restart) %s now that database credentials are in %s.", "lotus-miner", "config.toml") + d.say(notice, "Waiting for %s to write sectors into Yugabyte.", "lotus-miner") + + mid, err := address.IDFromAddress(d.MinerID) + if err != nil { + d.say(notice, "Error interpreting miner ID: %s: ID: %s", err.Error(), d.MinerID.String()) + os.Exit(1) + } + + for { + err := d.DB.Select(context.Background(), &i, ` + SELECT count(*) FROM sector_location WHERE miner_id=$1`, mid) + if err != nil { + if err.Error() != lastError { + d.say(notice, "Error verifying sectors: %s", err.Error()) + lastError = err.Error() + } + continue + } + if i[0] > 0 { + break + } + fmt.Print(".") + time.Sleep(5 * time.Second) + } + d.say(plain, "The sectors are in the database. The database is ready for %s.", "Curio") + d.say(notice, "Now shut down lotus-miner and lotus-worker and use run %s instead.", code.Render("curio run")) + + _, err = (&promptui.Prompt{Label: d.T("Press return to continue")}).Run() + if err != nil { + d.say(notice, "Aborting migration.") + os.Exit(1) + } + stepCompleted(d, d.T("Sectors verified. %d sector locations found.", i)) +} + +func yugabyteConnect(d *MigrationData) { + harmonyCfg := config.DefaultStorageMiner().HarmonyDB //copy the config to a local variable + if d.MinerConfig != nil { + harmonyCfg = d.MinerConfig.HarmonyDB //copy the config to a local variable + } + var err error + d.DB, err = harmonydb.NewFromConfig(harmonyCfg) + if err != nil { + hcfg := getDBDetails(d) + harmonyCfg = *hcfg + } + + d.say(plain, "Connected to Yugabyte. Schema is current.") + if !reflect.DeepEqual(harmonyCfg, d.MinerConfig.HarmonyDB) || !d.MinerConfig.Subsystems.EnableSectorIndexDB { + d.MinerConfig.HarmonyDB = harmonyCfg + d.MinerConfig.Subsystems.EnableSectorIndexDB = true + + d.say(plain, "Enabling Sector Indexing in the database.") + buf, err := config.ConfigUpdate(d.MinerConfig, config.DefaultStorageMiner()) + if err != nil { + d.say(notice, "Error encoding config.toml: %s", err.Error()) + os.Exit(1) + } + _, err = (&promptui.Prompt{ + Label: d.T("Press return to update %s with Yugabyte info. A Backup file will be written to that folder before changes are made.", "config.toml")}).Run() + if err != nil { + os.Exit(1) + } + p, err := homedir.Expand(d.MinerConfigPath) + if err != nil { + d.say(notice, "Error expanding path: %s", err.Error()) + os.Exit(1) + } + tomlPath := path.Join(p, "config.toml") + stat, err := os.Stat(tomlPath) + if err != nil { + d.say(notice, "Error reading filemode of config.toml: %s", err.Error()) + os.Exit(1) + } + fBackup, err := os.CreateTemp(p, "config-backup-*.toml") + if err != nil { + d.say(notice, "Error creating backup file: %s", err.Error()) + os.Exit(1) + } + fBackupContents, err := os.ReadFile(tomlPath) + if err != nil { + d.say(notice, "Error reading config.toml: %s", err.Error()) + os.Exit(1) + } + _, err = fBackup.Write(fBackupContents) + if err != nil { + d.say(notice, "Error writing backup file: %s", err.Error()) + os.Exit(1) + } + err = fBackup.Close() + if err != nil { + d.say(notice, "Error closing backup file: %s", err.Error()) + os.Exit(1) + } + + filemode := stat.Mode() + err = os.WriteFile(path.Join(p, "config.toml"), buf, filemode) + if err != nil { + d.say(notice, "Error writing config.toml: %s", err.Error()) + os.Exit(1) + } + d.say(section, "Restart Lotus Miner. ") + } + stepCompleted(d, d.T("Connected to Yugabyte")) +} + +func readMinerConfig(d *MigrationData) { + d.say(plain, "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.") + + verifyPath := func(dir string) (*config.StorageMiner, error) { + cfg := config.DefaultStorageMiner() + dir, err := homedir.Expand(dir) + if err != nil { + return nil, err + } + _, err = toml.DecodeFile(path.Join(dir, "config.toml"), &cfg) + return cfg, err + } + + dirs := map[string]*config.StorageMiner{"~/.lotusminer": nil, "~/.lotus-miner-local-net": nil} + if v := os.Getenv("LOTUS_MINER_PATH"); v != "" { + dirs[v] = nil + } + for dir := range dirs { + cfg, err := verifyPath(dir) + if err != nil { + delete(dirs, dir) + } + dirs[dir] = cfg + } + + var otherPath bool + if len(dirs) > 0 { + _, str, err := (&promptui.Select{ + Label: d.T("Select the location of your lotus-miner config directory?"), + Items: append(lo.Keys(dirs), d.T("Other")), + Templates: d.selectTemplates, + }).Run() + if err != nil { + if err.Error() == "^C" { + os.Exit(1) + } + otherPath = true + } else { + if str == d.T("Other") { + otherPath = true + } else { + d.MinerConfigPath = str + d.MinerConfig = dirs[str] + } + } + } + if otherPath { + minerPathEntry: + str, err := (&promptui.Prompt{ + Label: d.T("Enter the path to the configuration directory used by %s", "lotus-miner"), + }).Run() + if err != nil { + d.say(notice, "No path provided, abandoning migration ") + os.Exit(1) + } + cfg, err := verifyPath(str) + if err != nil { + d.say(notice, "Cannot read the config.toml file in the provided directory, Error: %s", err.Error()) + goto minerPathEntry + } + d.MinerConfigPath = str + d.MinerConfig = cfg + } + + // Try to lock Miner repo to verify that lotus-miner is not running + { + r, err := repo.NewFS(d.MinerConfigPath) + if err != nil { + d.say(plain, "Could not create repo from directory: %s. Aborting migration", err.Error()) + os.Exit(1) + } + lr, err := r.Lock(repo.StorageMiner) + if err != nil { + d.say(plain, "Could not lock miner repo. Your miner must be stopped: %s\n Aborting migration", err.Error()) + os.Exit(1) + } + _ = lr.Close() + } + + stepCompleted(d, d.T("Read Miner Config")) +} +func stepCompleted(d *MigrationData, step string) { + fmt.Print(green.Render("✔ ")) + d.say(plain, "Step Complete: %s\n", step) +} + +func stepCreateActor(d *MigrationData) { + d.say(plain, "Initializing a new miner actor.") + + for { + i, _, err := (&promptui.Select{ + Label: d.T("Enter the info to create a new miner"), + Items: []string{ + d.T("Owner Address: %s", d.owner.String()), + d.T("Worker Address: %s", d.worker.String()), + d.T("Sender Address: %s", d.sender.String()), + d.T("Sector Size: %d", d.ssize), + d.T("Confidence epochs: %d", d.confidence), + d.T("Continue to verify the addresses and create a new miner actor.")}, + Size: 6, + Templates: d.selectTemplates, + }).Run() + if err != nil { + d.say(notice, "Miner creation error occurred: %s ", err.Error()) + os.Exit(1) + } + switch i { + case 0: + owner, err := (&promptui.Prompt{ + Label: d.T("Enter the owner address"), + }).Run() + if err != nil { + d.say(notice, "No address provided") + continue + } + ownerAddr, err := address.NewFromString(owner) + if err != nil { + d.say(notice, "Failed to parse the address: %s", err.Error()) + } + d.owner = ownerAddr + case 1, 2: + val, err := (&promptui.Prompt{ + Label: d.T("Enter %s address", []string{"worker", "sender"}[i-1]), + Default: d.owner.String(), + }).Run() + if err != nil { + d.say(notice, err.Error()) + continue + } + addr, err := address.NewFromString(val) + if err != nil { + d.say(notice, "Failed to parse the address: %s", err.Error()) + } + switch i { + case 1: + d.worker = addr + case 2: + d.sender = addr + } + continue + case 3: + val, err := (&promptui.Prompt{ + Label: d.T("Enter the sector size"), + }).Run() + if err != nil { + d.say(notice, "No value provided") + continue + } + sectorSize, err := units.RAMInBytes(val) + if err != nil { + d.say(notice, "Failed to parse sector size: %s", err.Error()) + continue + } + d.ssize = abi.SectorSize(sectorSize) + continue + case 4: + confidenceStr, err := (&promptui.Prompt{ + Label: d.T("Confidence epochs"), + Default: strconv.Itoa(5), + }).Run() + if err != nil { + d.say(notice, err.Error()) + continue + } + confidence, err := strconv.ParseUint(confidenceStr, 10, 64) + if err != nil { + d.say(notice, "Failed to parse confidence: %s", err.Error()) + continue + } + d.confidence = confidence + goto minerInit // break out of the for loop once we have all the values + } + } + +minerInit: + miner, err := spcli.CreateStorageMiner(d.ctx, d.full, d.owner, d.worker, d.sender, d.ssize, d.confidence) + if err != nil { + d.say(notice, "Failed to create the miner actor: %s", err.Error()) + os.Exit(1) + } + + d.MinerID = miner + stepCompleted(d, d.T("Miner %s created successfully", miner.String())) +} + +func stepPresteps(d *MigrationData) { + + // Setup and connect to YugabyteDB + _ = getDBDetails(d) + + // Verify HarmonyDB connection + var titles []string + err := d.DB.Select(d.ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + if err != nil { + d.say(notice, "Cannot reach the DB: %s", err.Error()) + os.Exit(1) + } + + // Get full node API + full, closer, err := cliutil.GetFullNodeAPIV1(d.cctx) + if err != nil { + d.say(notice, "Error connecting to full node API: %s", err.Error()) + os.Exit(1) + } + d.full = full + d.closers = append(d.closers, closer) + stepCompleted(d, d.T("Pre-initialization steps complete")) +} + +func stepNewMinerConfig(d *MigrationData) { + curioCfg := config.DefaultCurioConfig() + curioCfg.Addresses = append(curioCfg.Addresses, config.CurioAddresses{ + PreCommitControl: []string{}, + CommitControl: []string{}, + TerminateControl: []string{}, + DisableOwnerFallback: false, + DisableWorkerFallback: false, + MinerAddresses: []string{d.MinerID.String()}, + }) + + sk, err := io.ReadAll(io.LimitReader(rand.Reader, 32)) + if err != nil { + d.say(notice, "Failed to generate random bytes for secret: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + curioCfg.Apis.StorageRPCSecret = base64.StdEncoding.EncodeToString(sk) + + ainfo, err := cliutil.GetAPIInfo(d.cctx, repo.FullNode) + if err != nil { + d.say(notice, "Failed to get API info for FullNode: %w", err) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + token, err := d.full.AuthNew(d.ctx, api.AllPermissions) + if err != nil { + d.say(notice, "Failed to verify the auth token from daemon node: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + curioCfg.Apis.ChainApiInfo = append(curioCfg.Apis.ChainApiInfo, fmt.Sprintf("%s:%s", string(token), ainfo.Addr)) + + // write config + var titles []string + err = d.DB.Select(d.ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + if err != nil { + d.say(notice, "Cannot reach the DB: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + // If 'base' layer is not present + if !lo.Contains(titles, "base") { + curioCfg.Addresses = lo.Filter(curioCfg.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + cb, err := config.ConfigUpdate(curioCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + if err != nil { + d.say(notice, "Failed to generate default config: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + _, err = d.DB.Exec(d.ctx, "INSERT INTO harmony_config (title, config) VALUES ('base', $1)", string(cb)) + if err != nil { + d.say(notice, "Failed to insert 'base' config layer in database: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + stepCompleted(d, d.T("Configuration 'base' was updated to include this miner's address")) + return + } + + // If base layer is already present + baseCfg := config.DefaultCurioConfig() + var baseText string + + err = d.DB.QueryRow(d.ctx, "SELECT config FROM harmony_config WHERE title='base'").Scan(&baseText) + if err != nil { + d.say(notice, "Failed to load base config from database: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + _, err = deps.LoadConfigWithUpgrades(baseText, baseCfg) + if err != nil { + d.say(notice, "Failed to parse base config: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + baseCfg.Addresses = append(baseCfg.Addresses, curioCfg.Addresses...) + baseCfg.Addresses = lo.Filter(baseCfg.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + + cb, err := config.ConfigUpdate(baseCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + if err != nil { + d.say(notice, "Failed to regenerate base config: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + _, err = d.DB.Exec(d.ctx, "UPDATE harmony_config SET config=$1 WHERE title='base'", string(cb)) + if err != nil { + d.say(notice, "Failed to insert 'base' config layer in database: %s", err.Error()) + d.say(notice, "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration", d.MinerID.String()) + os.Exit(1) + } + + stepCompleted(d, d.T("Configuration 'base' was updated to include this miner's address")) +} + +func getDBDetails(d *MigrationData) *config.HarmonyDB { + harmonyCfg := config.DefaultStorageMiner().HarmonyDB + for { + i, _, err := (&promptui.Select{ + Label: d.T("Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)"), + Items: []string{ + d.T("Host: %s", strings.Join(harmonyCfg.Hosts, ",")), + d.T("Port: %s", harmonyCfg.Port), + d.T("Username: %s", harmonyCfg.Username), + d.T("Password: %s", harmonyCfg.Password), + d.T("Database: %s", harmonyCfg.Database), + d.T("Continue to connect and update schema.")}, + Size: 6, + Templates: d.selectTemplates, + }).Run() + if err != nil { + d.say(notice, "Database config error occurred, abandoning migration: %s ", err.Error()) + os.Exit(1) + } + switch i { + case 0: + host, err := (&promptui.Prompt{ + Label: d.T("Enter the Yugabyte database host(s)"), + }).Run() + if err != nil { + d.say(notice, "No host provided") + continue + } + harmonyCfg.Hosts = strings.Split(host, ",") + case 1, 2, 3, 4: + val, err := (&promptui.Prompt{ + Label: d.T("Enter the Yugabyte database %s", []string{"port", "username", "password", "database"}[i-1]), + }).Run() + if err != nil { + d.say(notice, "No value provided") + continue + } + switch i { + case 1: + harmonyCfg.Port = val + case 2: + harmonyCfg.Username = val + case 3: + harmonyCfg.Password = val + case 4: + harmonyCfg.Database = val + } + continue + case 5: + db, err := harmonydb.NewFromConfig(harmonyCfg) + if err != nil { + if err.Error() == "^C" { + os.Exit(1) + } + d.say(notice, "Error connecting to Yugabyte database: %s", err.Error()) + continue + } + d.DB = db + return &harmonyCfg + } + } +} diff --git a/cmd/curio/guidedsetup/shared.go b/cmd/curio/guidedsetup/shared.go new file mode 100644 index 00000000000..6e7d81c0382 --- /dev/null +++ b/cmd/curio/guidedsetup/shared.go @@ -0,0 +1,258 @@ +package guidedsetup + +import ( + "bytes" + "context" + "encoding/base64" + "fmt" + "os" + "path" + "strings" + + "github.com/BurntSushi/toml" + "github.com/ipfs/go-datastore" + "github.com/samber/lo" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/node/modules" + "github.com/filecoin-project/lotus/node/repo" +) + +const ( + FlagMinerRepo = "miner-repo" +) + +const FlagMinerRepoDeprecation = "storagerepo" + +func SaveConfigToLayer(minerRepoPath, chainApiInfo string) (minerAddress address.Address, err error) { + _, say := SetupLanguage() + ctx := context.Background() + + r, err := repo.NewFS(minerRepoPath) + if err != nil { + return minerAddress, err + } + + ok, err := r.Exists() + if err != nil { + return minerAddress, err + } + + if !ok { + return minerAddress, fmt.Errorf("repo not initialized at: %s", minerRepoPath) + } + + lr, err := r.LockRO(repo.StorageMiner) + if err != nil { + return minerAddress, fmt.Errorf("locking repo: %w", err) + } + defer func() { + err = lr.Close() + if err != nil { + fmt.Println("error closing repo: ", err) + } + }() + + cfgNode, err := lr.Config() + if err != nil { + return minerAddress, fmt.Errorf("getting node config: %w", err) + } + smCfg := cfgNode.(*config.StorageMiner) + + db, err := harmonydb.NewFromConfig(smCfg.HarmonyDB) + if err != nil { + return minerAddress, fmt.Errorf("could not reach the database. Ensure the Miner config toml's HarmonyDB entry"+ + " is setup to reach Yugabyte correctly: %w", err) + } + + var titles []string + err = db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + if err != nil { + return minerAddress, fmt.Errorf("miner cannot reach the db. Ensure the config toml's HarmonyDB entry"+ + " is setup to reach Yugabyte correctly: %s", err.Error()) + } + + // Copy over identical settings: + + buf, err := os.ReadFile(path.Join(lr.Path(), "config.toml")) + if err != nil { + return minerAddress, fmt.Errorf("could not read config.toml: %w", err) + } + curioCfg := config.DefaultCurioConfig() + + ensureEmptyArrays(curioCfg) + _, err = deps.LoadConfigWithUpgrades(string(buf), curioCfg) + + if err != nil { + return minerAddress, fmt.Errorf("could not decode toml: %w", err) + } + + // Populate Miner Address + mmeta, err := lr.Datastore(ctx, "/metadata") + if err != nil { + return minerAddress, xerrors.Errorf("opening miner metadata datastore: %w", err) + } + defer func() { + // _ = mmeta.Close() + }() + + maddrBytes, err := mmeta.Get(ctx, datastore.NewKey("miner-address")) + if err != nil { + return minerAddress, xerrors.Errorf("getting miner address datastore entry: %w", err) + } + + addr, err := address.NewFromBytes(maddrBytes) + if err != nil { + return minerAddress, xerrors.Errorf("parsing miner actor address: %w", err) + } + + minerAddress = addr + + curioCfg.Addresses = []config.CurioAddresses{{ + MinerAddresses: []string{addr.String()}, + PreCommitControl: smCfg.Addresses.PreCommitControl, + CommitControl: smCfg.Addresses.CommitControl, + TerminateControl: smCfg.Addresses.TerminateControl, + DisableOwnerFallback: smCfg.Addresses.DisableOwnerFallback, + DisableWorkerFallback: smCfg.Addresses.DisableWorkerFallback, + }} + + ks, err := lr.KeyStore() + if err != nil { + return minerAddress, xerrors.Errorf("keystore err: %w", err) + } + js, err := ks.Get(modules.JWTSecretName) + if err != nil { + return minerAddress, xerrors.Errorf("error getting JWTSecretName: %w", err) + } + + curioCfg.Apis.StorageRPCSecret = base64.StdEncoding.EncodeToString(js.PrivateKey) + + curioCfg.Apis.ChainApiInfo = append(curioCfg.Apis.ChainApiInfo, chainApiInfo) + // Express as configTOML + configTOML := &bytes.Buffer{} + if err = toml.NewEncoder(configTOML).Encode(curioCfg); err != nil { + return minerAddress, err + } + + if lo.Contains(titles, "base") { + // append addresses + var baseCfg = config.DefaultCurioConfig() + var baseText string + err = db.QueryRow(ctx, "SELECT config FROM harmony_config WHERE title='base'").Scan(&baseText) + if err != nil { + return minerAddress, xerrors.Errorf("Cannot load base config: %w", err) + } + ensureEmptyArrays(baseCfg) + _, err := deps.LoadConfigWithUpgrades(baseText, baseCfg) + if err != nil { + return minerAddress, xerrors.Errorf("Cannot load base config: %w", err) + } + for _, addr := range baseCfg.Addresses { + if lo.Contains(addr.MinerAddresses, curioCfg.Addresses[0].MinerAddresses[0]) { + goto skipWritingToBase + } + } + // write to base + { + baseCfg.Addresses = append(baseCfg.Addresses, curioCfg.Addresses[0]) + baseCfg.Addresses = lo.Filter(baseCfg.Addresses, func(a config.CurioAddresses, _ int) bool { + return len(a.MinerAddresses) > 0 + }) + if baseCfg.Apis.ChainApiInfo == nil { + baseCfg.Apis.ChainApiInfo = append(baseCfg.Apis.ChainApiInfo, chainApiInfo) + } + if baseCfg.Apis.StorageRPCSecret == "" { + baseCfg.Apis.StorageRPCSecret = curioCfg.Apis.StorageRPCSecret + } + + cb, err := config.ConfigUpdate(baseCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + if err != nil { + return minerAddress, xerrors.Errorf("cannot interpret config: %w", err) + } + _, err = db.Exec(ctx, "UPDATE harmony_config SET config=$1 WHERE title='base'", string(cb)) + if err != nil { + return minerAddress, xerrors.Errorf("cannot update base config: %w", err) + } + say(plain, "Configuration 'base' was updated to include this miner's address (%s) and its wallet setup.", minerAddress) + } + say(plain, "Compare the configurations %s to %s. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.", "base", "mig-"+curioCfg.Addresses[0].MinerAddresses[0]) + skipWritingToBase: + } else { + _, err = db.Exec(ctx, `INSERT INTO harmony_config (title, config) VALUES ('base', $1) + ON CONFLICT(title) DO UPDATE SET config=EXCLUDED.config`, configTOML) + + if err != nil { + return minerAddress, xerrors.Errorf("Cannot insert base config: %w", err) + } + say(notice, "Configuration 'base' was created to resemble this lotus-miner's config.toml .") + } + + { // make a layer representing the migration + layerName := fmt.Sprintf("mig-%s", curioCfg.Addresses[0].MinerAddresses[0]) + _, err = db.Exec(ctx, "DELETE FROM harmony_config WHERE title=$1", layerName) + if err != nil { + return minerAddress, xerrors.Errorf("Cannot delete existing layer: %w", err) + } + + _, err = db.Exec(ctx, "INSERT INTO harmony_config (title, config) VALUES ($1, $2)", layerName, configTOML.String()) + if err != nil { + return minerAddress, xerrors.Errorf("Cannot insert layer after layer created message: %w", err) + } + say(plain, "Layer %s created. ", layerName) + } + + dbSettings := getDBSettings(*smCfg) + say(plain, "To work with the config: ") + fmt.Println(code.Render(`curio ` + dbSettings + ` config edit base`)) + say(plain, `To run Curio: With machine or cgroup isolation, use the command (with example layer selection):`) + fmt.Println(code.Render(`curio ` + dbSettings + ` run --layer=post`)) + return minerAddress, nil +} + +func getDBSettings(smCfg config.StorageMiner) string { + dbSettings := "" + def := config.DefaultStorageMiner().HarmonyDB + if def.Hosts[0] != smCfg.HarmonyDB.Hosts[0] { + dbSettings += ` --db-host="` + strings.Join(smCfg.HarmonyDB.Hosts, ",") + `"` + } + if def.Port != smCfg.HarmonyDB.Port { + dbSettings += " --db-port=" + smCfg.HarmonyDB.Port + } + if def.Username != smCfg.HarmonyDB.Username { + dbSettings += ` --db-user="` + smCfg.HarmonyDB.Username + `"` + } + if def.Password != smCfg.HarmonyDB.Password { + dbSettings += ` --db-password="` + smCfg.HarmonyDB.Password + `"` + } + if def.Database != smCfg.HarmonyDB.Database { + dbSettings += ` --db-name="` + smCfg.HarmonyDB.Database + `"` + } + return dbSettings +} + +func ensureEmptyArrays(cfg *config.CurioConfig) { + if cfg.Addresses == nil { + cfg.Addresses = []config.CurioAddresses{} + } else { + for i := range cfg.Addresses { + if cfg.Addresses[i].PreCommitControl == nil { + cfg.Addresses[i].PreCommitControl = []string{} + } + if cfg.Addresses[i].CommitControl == nil { + cfg.Addresses[i].CommitControl = []string{} + } + if cfg.Addresses[i].TerminateControl == nil { + cfg.Addresses[i].TerminateControl = []string{} + } + } + } + if cfg.Apis.ChainApiInfo == nil { + cfg.Apis.ChainApiInfo = []string{} + } +} diff --git a/cmd/curio/internal/translations/catalog.go b/cmd/curio/internal/translations/catalog.go new file mode 100644 index 00000000000..6e0ad30870d --- /dev/null +++ b/cmd/curio/internal/translations/catalog.go @@ -0,0 +1,476 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +package translations + +import ( + "golang.org/x/text/language" + "golang.org/x/text/message" + "golang.org/x/text/message/catalog" +) + +type dictionary struct { + index []uint32 + data string +} + +func (d *dictionary) Lookup(key string) (data string, ok bool) { + p, ok := messageKeyToIndex[key] + if !ok { + return "", false + } + start, end := d.index[p], d.index[p+1] + if start == end { + return "", false + } + return d.data[start:end], true +} + +func init() { + dict := map[string]catalog.Dictionary{ + "en": &dictionary{index: enIndex, data: enData}, + "ko": &dictionary{index: koIndex, data: koData}, + "zh": &dictionary{index: zhIndex, data: zhData}, + } + fallback := language.MustParse("en") + cat, err := catalog.NewFromMap(dict, catalog.Fallback(fallback)) + if err != nil { + panic(err) + } + message.DefaultCatalog = cat +} + +var messageKeyToIndex = map[string]int{ + "Aborting migration.": 45, + "Aborting remaining steps.": 9, + "Aggregate-Anonymous: version, chain, and Miner power (bucketed).": 22, + "Cannot reach the DB: %s": 90, + "Cannot read the config.toml file in the provided directory, Error: %s": 65, + "Compare the configurations %s to %s. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.": 116, + "Confidence epochs": 86, + "Confidence epochs: %d": 76, + "Configuration 'base' was created to resemble this lotus-miner's config.toml .": 117, + "Configuration 'base' was updated to include this miner's address": 99, + "Configuration 'base' was updated to include this miner's address (%s) and its wallet setup.": 115, + "Connected to Yugabyte": 59, + "Connected to Yugabyte. Schema is current.": 47, + "Continue to connect and update schema.": 109, + "Continue to verify the addresses and create a new miner actor.": 77, + "Could not create repo from directory: %s. Aborting migration": 66, + "Could not lock miner repo. Your miner must be stopped: %s\n Aborting migration": 67, + "Create a new miner": 8, + "Ctrl+C pressed in Terminal": 5, + "Database config error occurred, abandoning migration: %s ": 110, + "Database: %s": 108, + "Documentation: ": 32, + "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.": 4, + "Enabling Sector Indexing in the database.": 48, + "Enter %s address": 82, + "Enter the Yugabyte database %s": 113, + "Enter the Yugabyte database host(s)": 111, + "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)": 103, + "Enter the info to create a new miner": 71, + "Enter the owner address": 79, + "Enter the path to the configuration directory used by %s": 63, + "Enter the sector size": 83, + "Error closing backup file: %s": 56, + "Error connecting to Yugabyte database: %s": 114, + "Error connecting to full node API: %s": 91, + "Error creating backup file: %s": 53, + "Error encoding config.toml: %s": 49, + "Error expanding path: %s": 51, + "Error getting API: %s": 15, + "Error getting miner info: %s": 27, + "Error getting miner power: %s": 25, + "Error getting token: %s": 17, + "Error interpreting miner ID: %s: ID: %s": 40, + "Error marshalling message: %s": 26, + "Error reading config.toml: %s": 54, + "Error reading filemode of config.toml: %s": 52, + "Error saving config to layer: %s. Aborting Migration": 18, + "Error sending message: %s": 29, + "Error sending message: Status %s, Message: ": 30, + "Error signing message: %s": 28, + "Error verifying sectors: %s": 41, + "Error writing backup file: %s": 55, + "Error writing config.toml: %s": 57, + "Failed to create the miner actor: %s": 88, + "Failed to generate default config: %s": 97, + "Failed to generate random bytes for secret: %s": 93, + "Failed to get API info for FullNode: %w": 95, + "Failed to insert 'base' config layer in database: %s": 98, + "Failed to load base config from database: %s": 100, + "Failed to parse base config: %s": 101, + "Failed to parse confidence: %s": 87, + "Failed to parse sector size: %s": 85, + "Failed to parse the address: %s": 81, + "Failed to regenerate base config: %s": 102, + "Failed to verify the auth token from daemon node: %s": 96, + "Filecoin %s channels: %s and %s": 35, + "Hint: I am someone running Curio on whichever chain.": 23, + "Host: %s": 104, + "I want to:": 6, + "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'": 36, + "Individual Data: Miner ID, Curio version, chain (%s or %s). Signed.": 21, + "Initializing a new miner actor.": 70, + "Layer %s created. ": 118, + "Lotus-Miner to Curio Migration.": 10, + "Message sent.": 31, + "Migrate from existing Lotus-Miner": 7, + "Migrating lotus-miner config.toml to Curio in-database configuration.": 14, + "Miner %s created successfully": 89, + "Miner creation error occurred: %s ": 78, + "New Miner initialization complete.": 13, + "No address provided": 80, + "No host provided": 112, + "No path provided, abandoning migration ": 64, + "No value provided": 84, + "Nothing.": 24, + "Now shut down lotus-miner and lotus-worker and use run %s instead.": 43, + "One database can serve multiple miner IDs: Run a migration for each lotus-miner.": 37, + "Other": 62, + "Owner Address: %s": 72, + "Password: %s": 107, + "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster %s' to finish the configuration": 94, + "Please start (or restart) %s now that database credentials are in %s.": 38, + "Port: %s": 105, + "Pre-initialization steps complete": 92, + "Press return to continue": 44, + "Press return to update %s with Yugabyte info. A Backup file will be written to that folder before changes are made.": 50, + "Read Miner Config": 68, + "Restart Lotus Miner. ": 58, + "Sector Size: %d": 75, + "Sectors verified. %d sector locations found.": 46, + "Select the location of your lotus-miner config directory?": 61, + "Select what you want to share with the Curio team.": 20, + "Sender Address: %s": 74, + "Step Complete: %s\n": 69, + "The '%s' layer stores common configuration. All curio instances can include it in their %s argument.": 33, + "The Curio team wants to improve the software you use. Tell the team you're using `%s`.": 19, + "The sectors are in the database. The database is ready for %s.": 42, + "This interactive tool creates a new miner actor and creates the basic configuration layer for it.": 1, + "This interactive tool migrates lotus-miner to Curio in 5 minutes.": 3, + "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster < miner ID >' to finish the configuration.": 2, + "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):": 120, + "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.": 60, + "To work with the config: ": 119, + "Try the web interface with %s for further guided improvements.": 11, + "Use the arrow keys to navigate: ↓ ↑ → ← ": 0, + "Username: %s": 106, + "Waiting for %s to write sectors into Yugabyte.": 39, + "Worker Address: %s": 73, + "You can add other layers for per-machine configuration changes.": 34, + "You can now migrate your market node (%s), if applicable.": 12, + "could not get API info for FullNode: %w": 16, +} + +var enIndex = []uint32{ // 122 elements + // Entry 0 - 1F + 0x00000000, 0x00000035, 0x00000097, 0x0000015a, + 0x0000019c, 0x000001f5, 0x00000210, 0x0000021b, + 0x0000023d, 0x00000250, 0x0000026a, 0x0000028a, + 0x000002cc, 0x00000309, 0x0000032c, 0x00000372, + 0x0000038b, 0x000003b6, 0x000003d1, 0x00000409, + 0x00000463, 0x00000496, 0x000004e0, 0x00000521, + 0x00000556, 0x0000055f, 0x00000580, 0x000005a1, + 0x000005c1, 0x000005de, 0x000005fb, 0x0000062e, + // Entry 20 - 3F + 0x0000063c, 0x00000650, 0x000006bb, 0x000006fb, + 0x00000724, 0x0000079b, 0x000007ec, 0x00000838, + 0x0000086a, 0x00000898, 0x000008b7, 0x000008f9, + 0x0000093f, 0x00000958, 0x0000096c, 0x0000099c, + 0x000009c6, 0x000009f0, 0x00000a12, 0x00000a89, + 0x00000aa5, 0x00000ad2, 0x00000af4, 0x00000b15, + 0x00000b36, 0x00000b57, 0x00000b78, 0x00000b92, + 0x00000ba8, 0x00000bf5, 0x00000c2f, 0x00000c35, + // Entry 40 - 5F + 0x00000c71, 0x00000c9d, 0x00000ce6, 0x00000d26, + 0x00000d77, 0x00000d89, 0x00000da3, 0x00000dc3, + 0x00000de8, 0x00000dfd, 0x00000e13, 0x00000e29, + 0x00000e3c, 0x00000e55, 0x00000e94, 0x00000ebe, + 0x00000ed6, 0x00000eea, 0x00000f0d, 0x00000f21, + 0x00000f37, 0x00000f49, 0x00000f6c, 0x00000f7e, + 0x00000fa0, 0x00000fc8, 0x00000fe9, 0x00001004, + 0x0000102d, 0x0000104f, 0x00001081, 0x00001118, + // Entry 60 - 7F + 0x00001143, 0x0000117b, 0x000011a4, 0x000011dc, + 0x0000121d, 0x0000124d, 0x00001270, 0x00001298, + 0x000012fa, 0x00001306, 0x00001312, 0x00001322, + 0x00001332, 0x00001342, 0x00001369, 0x000013aa, + 0x000013ce, 0x000013df, 0x00001401, 0x0000142e, + 0x0000148d, 0x0000152a, 0x00001578, 0x00001592, + 0x000015b0, 0x00001610, +} // Size: 512 bytes + +const enData string = "" + // Size: 5648 bytes + "\x04\x00\x01 0\x02Use the arrow keys to navigate: ↓ ↑ → ←\x02This intera" + + "ctive tool creates a new miner actor and creates the basic configuration" + + " layer for it.\x02This process is partially idempotent. Once a new miner" + + " actor has been created and subsequent steps fail, the user need to run " + + "'curio config new-cluster < miner ID >' to finish the configuration.\x02" + + "This interactive tool migrates lotus-miner to Curio in 5 minutes.\x02Eac" + + "h step needs your confirmation and can be reversed. Press Ctrl+C to exit" + + " at any time.\x02Ctrl+C pressed in Terminal\x02I want to:\x02Migrate fro" + + "m existing Lotus-Miner\x02Create a new miner\x02Aborting remaining steps" + + ".\x02Lotus-Miner to Curio Migration.\x02Try the web interface with %[1]s" + + " for further guided improvements.\x02You can now migrate your market nod" + + "e (%[1]s), if applicable.\x02New Miner initialization complete.\x02Migra" + + "ting lotus-miner config.toml to Curio in-database configuration.\x02Erro" + + "r getting API: %[1]s\x02could not get API info for FullNode: %[1]w\x02Er" + + "ror getting token: %[1]s\x02Error saving config to layer: %[1]s. Abortin" + + "g Migration\x02The Curio team wants to improve the software you use. Tel" + + "l the team you're using `%[1]s`.\x02Select what you want to share with t" + + "he Curio team.\x02Individual Data: Miner ID, Curio version, chain (%[1]s" + + " or %[2]s). Signed.\x02Aggregate-Anonymous: version, chain, and Miner po" + + "wer (bucketed).\x02Hint: I am someone running Curio on whichever chain." + + "\x02Nothing.\x02Error getting miner power: %[1]s\x02Error marshalling me" + + "ssage: %[1]s\x02Error getting miner info: %[1]s\x02Error signing message" + + ": %[1]s\x02Error sending message: %[1]s\x04\x00\x01 .\x02Error sending m" + + "essage: Status %[1]s, Message:\x02Message sent.\x04\x00\x01 \x0f\x02Docu" + + "mentation:\x02The '%[1]s' layer stores common configuration. All curio i" + + "nstances can include it in their %[2]s argument.\x02You can add other la" + + "yers for per-machine configuration changes.\x02Filecoin %[1]s channels: " + + "%[2]s and %[3]s\x02Increase reliability using redundancy: start multiple" + + " machines with at-least the post layer: 'curio run --layers=post'\x02One" + + " database can serve multiple miner IDs: Run a migration for each lotus-m" + + "iner.\x02Please start (or restart) %[1]s now that database credentials a" + + "re in %[2]s.\x02Waiting for %[1]s to write sectors into Yugabyte.\x02Err" + + "or interpreting miner ID: %[1]s: ID: %[2]s\x02Error verifying sectors: %" + + "[1]s\x02The sectors are in the database. The database is ready for %[1]s" + + ".\x02Now shut down lotus-miner and lotus-worker and use run %[1]s instea" + + "d.\x02Press return to continue\x02Aborting migration.\x02Sectors verifie" + + "d. %[1]d sector locations found.\x02Connected to Yugabyte. Schema is cur" + + "rent.\x02Enabling Sector Indexing in the database.\x02Error encoding con" + + "fig.toml: %[1]s\x02Press return to update %[1]s with Yugabyte info. A Ba" + + "ckup file will be written to that folder before changes are made.\x02Err" + + "or expanding path: %[1]s\x02Error reading filemode of config.toml: %[1]s" + + "\x02Error creating backup file: %[1]s\x02Error reading config.toml: %[1]" + + "s\x02Error writing backup file: %[1]s\x02Error closing backup file: %[1]" + + "s\x02Error writing config.toml: %[1]s\x04\x00\x01 \x15\x02Restart Lotus " + + "Miner.\x02Connected to Yugabyte\x02To start, ensure your sealing pipelin" + + "e is drained and shut-down lotus-miner.\x02Select the location of your l" + + "otus-miner config directory?\x02Other\x02Enter the path to the configura" + + "tion directory used by %[1]s\x04\x00\x01 '\x02No path provided, abandoni" + + "ng migration\x02Cannot read the config.toml file in the provided directo" + + "ry, Error: %[1]s\x02Could not create repo from directory: %[1]s. Abortin" + + "g migration\x02Could not lock miner repo. Your miner must be stopped: %[" + + "1]s\x0a Aborting migration\x02Read Miner Config\x04\x00\x01\x0a\x15\x02S" + + "tep Complete: %[1]s\x02Initializing a new miner actor.\x02Enter the info" + + " to create a new miner\x02Owner Address: %[1]s\x02Worker Address: %[1]s" + + "\x02Sender Address: %[1]s\x02Sector Size: %[1]d\x02Confidence epochs: %[" + + "1]d\x02Continue to verify the addresses and create a new miner actor." + + "\x04\x00\x01 %\x02Miner creation error occurred: %[1]s\x02Enter the owne" + + "r address\x02No address provided\x02Failed to parse the address: %[1]s" + + "\x02Enter %[1]s address\x02Enter the sector size\x02No value provided" + + "\x02Failed to parse sector size: %[1]s\x02Confidence epochs\x02Failed to" + + " parse confidence: %[1]s\x02Failed to create the miner actor: %[1]s\x02M" + + "iner %[1]s created successfully\x02Cannot reach the DB: %[1]s\x02Error c" + + "onnecting to full node API: %[1]s\x02Pre-initialization steps complete" + + "\x02Failed to generate random bytes for secret: %[1]s\x02Please do not r" + + "un guided-setup again as miner creation is not idempotent. You need to r" + + "un 'curio config new-cluster %[1]s' to finish the configuration\x02Faile" + + "d to get API info for FullNode: %[1]w\x02Failed to verify the auth token" + + " from daemon node: %[1]s\x02Failed to generate default config: %[1]s\x02" + + "Failed to insert 'base' config layer in database: %[1]s\x02Configuration" + + " 'base' was updated to include this miner's address\x02Failed to load ba" + + "se config from database: %[1]s\x02Failed to parse base config: %[1]s\x02" + + "Failed to regenerate base config: %[1]s\x02Enter the info to connect to " + + "your Yugabyte database installation (https://download.yugabyte.com/)\x02" + + "Host: %[1]s\x02Port: %[1]s\x02Username: %[1]s\x02Password: %[1]s\x02Data" + + "base: %[1]s\x02Continue to connect and update schema.\x04\x00\x01 <\x02D" + + "atabase config error occurred, abandoning migration: %[1]s\x02Enter the " + + "Yugabyte database host(s)\x02No host provided\x02Enter the Yugabyte data" + + "base %[1]s\x02Error connecting to Yugabyte database: %[1]s\x02Configurat" + + "ion 'base' was updated to include this miner's address (%[1]s) and its w" + + "allet setup.\x02Compare the configurations %[1]s to %[2]s. Changes betwe" + + "en the miner IDs other than wallet addreses should be a new, minimal lay" + + "er for runners that need it.\x02Configuration 'base' was created to rese" + + "mble this lotus-miner's config.toml .\x04\x00\x01 \x15\x02Layer %[1]s cr" + + "eated.\x04\x00\x01 \x19\x02To work with the config:\x02To run Curio: Wit" + + "h machine or cgroup isolation, use the command (with example layer selec" + + "tion):" + +var koIndex = []uint32{ // 122 elements + // Entry 0 - 1F + 0x00000000, 0x00000044, 0x000000c1, 0x000001c1, + 0x0000020e, 0x00000289, 0x000002aa, 0x000002bc, + 0x000002e5, 0x00000300, 0x00000325, 0x00000348, + 0x000003b2, 0x00000402, 0x00000428, 0x00000481, + 0x000004a0, 0x000004dc, 0x0000050c, 0x00000564, + 0x000005f0, 0x00000629, 0x0000067f, 0x000006bd, + 0x0000070b, 0x00000726, 0x00000760, 0x00000793, + 0x000007cd, 0x000007f7, 0x00000821, 0x00000863, + // Entry 20 - 3F + 0x00000887, 0x00000894, 0x0000091a, 0x0000096c, + 0x00000993, 0x00000a2f, 0x00000ac1, 0x00000b3c, + 0x00000b80, 0x00000bbe, 0x00000be5, 0x00000c50, + 0x00000c9d, 0x00000cc4, 0x00000cdf, 0x00000d2e, + 0x00000d6f, 0x00000daf, 0x00000df6, 0x00000e9c, + 0x00000ecc, 0x00000f1b, 0x00000f3e, 0x00000f5f, + 0x00000f82, 0x00000fa5, 0x00000fe3, 0x00001007, + 0x0000101d, 0x00001088, 0x000010d7, 0x000010de, + // Entry 40 - 5F + 0x00001126, 0x00001178, 0x000011d2, 0x0000123c, + 0x000012cd, 0x000012e5, 0x000012ff, 0x00001323, + 0x00001356, 0x0000136e, 0x00001386, 0x0000139e, + 0x000013b3, 0x000013cb, 0x00001422, 0x0000144d, + 0x00001465, 0x0000148c, 0x000014af, 0x000014c3, + 0x000014d8, 0x000014fc, 0x00001526, 0x00001537, + 0x0000155d, 0x00001583, 0x000015bc, 0x000015f4, + 0x0000162c, 0x0000164b, 0x00001697, 0x00001755, + // Entry 60 - 7F + 0x000017a1, 0x000017ef, 0x00001812, 0x0000186e, + 0x000018be, 0x00001913, 0x00001956, 0x00001995, + 0x00001a03, 0x00001a14, 0x00001a22, 0x00001a3a, + 0x00001a4e, 0x00001a68, 0x00001a92, 0x00001af5, + 0x00001b31, 0x00001b5b, 0x00001b93, 0x00001be7, + 0x00001c60, 0x00001d1a, 0x00001d71, 0x00001da0, + 0x00001dc7, 0x00001e53, +} // Size: 512 bytes + +const koData string = "" + // Size: 7763 bytes + "\x04\x00\x01 ?\x02화살표 키를 사용하여 이동하세요: ↓ ↑ → ←\x02이 대화형 도구는 새로운 채굴자 액터를 생성" + + "하고 그에 대한 기본 구성 레이어를 생성합니다.\x02이 프로세스는 부분적으로 항등원적입니다. 새로운 채굴자 액터가 생성되었고" + + " 후속 단계가 실패하는 경우 사용자는 구성을 완료하기 위해 'curio config new-cluster < 채굴자 ID >'를 " + + "실행해야 합니다.\x02이 대화형 도구는 5분 안에 lotus-miner를 Curio로 이주합니다.\x02각 단계는 확인이 필" + + "요하며 되돌릴 수 있습니다. 언제든지 Ctrl+C를 눌러 종료할 수 있습니다.\x02터미널에서 Ctrl+C가 눌림\x02나는 " + + "원한다:\x02기존의 Lotus-Miner에서 이전하기\x02새로운 채굴자 생성\x02나머지 단계를 중단합니다.\x02Lotu" + + "s-Miner에서 Curio로 이주.\x02%[1]s를 사용하여 웹 인터페이스를 시도하고 더 나은 안내된 개선을 진행하세요." + + "\x02해당하는 경우 이제 시장 노드를 이주할 수 있습니다 (%[1]s).\x02새로운 채굴자 초기화 완료.\x02lotus-mi" + + "ner config.toml을 Curio의 데이터베이스 구성으로 이전 중입니다.\x02API 가져오기 오류: %[1]s\x02Fu" + + "llNode의 API 정보를 가져올 수 없습니다: %[1]w\x02토큰을 가져오는 중 오류 발생: %[1]s\x02레이어에 구성을" + + " 저장하는 중 오류 발생: %[1]s. 마이그레이션 중단\x02Curio 팀은 당신이 사용하는 소프트웨어를 개선하고자 합니다. 팀" + + "에게 `%[1]s`를 사용 중이라고 알려주세요.\x02Curio 팀과 공유하고 싶은 것을 선택하세요.\x02개별 데이터: 채굴" + + "자 ID, Curio 버전, 체인 (%[1]s 또는 %[2]s). 서명됨.\x02집계-익명: 버전, 체인, 및 채굴자 파워 (" + + "버킷).\x02힌트: 나는 어떤 체인에서든 Curio를 실행 중인 사람입니다.\x02아무것도 없습니다.\x02마이너 파워를 가" + + "져오는 중 오류 발생: %[1]s\x02메시지를 마샬하는 중 오류 발생: %[1]s\x02마이너 정보를 가져오는 중 오류 발생" + + ": %[1]s\x02메시지 서명 중 오류 발생: %[1]s\x02메시지 전송 중 오류 발생: %[1]s\x04\x00\x01 =" + + "\x02메시지 전송 중 오류 발생: 상태 %[1]s, 메시지:\x02메시지가 전송되었습니다.\x04\x00\x01 \x08\x02" + + "문서:\x02'%[1]s' 레이어에는 공통 구성이 저장됩니다. 모든 Curio 인스턴스는 %[2]s 인수에 포함시킬 수 있습니" + + "다.\x02기계별 구성 변경을 위해 다른 레이어를 추가할 수 있습니다.\x02Filecoin %[1]s 채널: %[2]s 및 " + + "%[3]s\x02신뢰성 향상을 위한 중복성 사용: 적어도 post 레이어를 사용하여 여러 대의 기계를 시작하십시오: 'curio " + + "run --layers=post'\x02한 개의 데이터베이스는 여러 광부 ID를 제공할 수 있습니다: 각 lotus-miner에 " + + "대해 마이그레이션을 실행하세요.\x02데이터베이스 자격 증명이 %[2]s에 입력되었으므로 지금 %[1]s을 시작하거나 다시 시" + + "작하세요.\x02%[1]s가 Yugabyte에 섹터를 기록하도록 대기 중입니다.\x02광부 ID를 해석하는 중 오류 발생: %" + + "[1]s: ID: %[2]s\x02섹터 확인 중 오류 발생: %[1]s\x02섹터가 데이터베이스에 있습니다. 데이터베이스가 %[1" + + "]s를 위해 준비되었습니다.\x02이제 lotus-miner와 lotus-worker를 종료하고 %[1]s을 실행하세요.\x02계" + + "속하려면 리턴을 누르세요\x02마이그레이션 중단.\x02섹터가 확인되었습니다. %[1]d개의 섹터 위치를 찾았습니다.\x02Y" + + "ugabyte에 연결되었습니다. 스키마가 현재입니다.\x02데이터베이스에서 Sector Indexing을 활성화합니다.\x02co" + + "nfig.toml을 인코딩하는 중 오류가 발생했습니다: %[1]s\x02%[1]s을 Yugabyte 정보로 업데이트하려면 리턴 키" + + "를 누르세요. 변경 사항을 적용하기 전에 해당 폴더에 백업 파일이 작성됩니다.\x02경로를 확장하는 중 오류 발생: %[1]s" + + "\x02config.toml의 파일 모드를 읽는 중 오류가 발생했습니다: %[1]s\x02백업 파일 생성 오류: %[1]s\x02" + + "config.toml 읽기 오류: %[1]s\x02백업 파일 쓰기 오류: %[1]s\x02백업 파일 닫기 오류: %[1]s\x02" + + "config.toml을 쓰는 중 오류가 발생했습니다: %[1]s\x04\x00\x01 \x1f\x02로터스 마이너 재시작.\x02" + + "Yugabyte에 연결됨\x02시작하려면 밀봉 파이프라인이 비어 있고 lotus-miner가 종료되었는지 확인하세요.\x02로터스" + + " 마이너 구성 디렉토리의 위치를 선택하시겠습니까?\x02기타\x02%[1]s에서 사용하는 구성 디렉터리 경로를 입력하세요.\x04" + + "\x00\x01 M\x02경로가 제공되지 않았으므로 마이그레이션을 포기합니다\x02제공된 디렉토리에서 config.toml 파일을" + + " 읽을 수 없습니다. 오류: %[1]s\x02디렉토리에서 저장소를 생성할 수 없습니다: %[1]s. 마이그레이션을 중단합니다." + + "\x02광부 저장소를 잠금 해제할 수 없습니다. 귀하의 광부를 중지해야 합니다: %[1]s\x0a 마이그레이션을 중단합니다." + + "\x02마이너 구성 읽기\x04\x00\x01\x0a\x15\x02단계 완료: %[1]s\x02새 채굴자 액터 초기화 중.\x02" + + "새 채굴자를 생성하기 위한 정보 입력\x02소유자 주소: %[1]s\x02작업자 주소: %[1]s\x02송신자 주소: %[1]" + + "s\x02섹터 크기: %[1]d\x02신뢰 에포크: %[1]d\x02주소를 확인하고 새 채굴자 액터를 생성하려면 계속 진행하세요." + + "\x04\x00\x01 &\x02채굴자 생성 오류 발생: %[1]s\x02소유자 주소 입력\x02주소가 제공되지 않았습니다\x02" + + "주소 구문 분석 실패: %[1]s\x02%[1]s 주소 입력\x02섹터 크기 입력\x02값이 제공되지 않았습니다\x02섹터 크" + + "기 구문 분석 실패: %[1]s\x02신뢰 에포크\x02신뢰도 구문 분석 실패: %[1]s\x02채굴자 액터 생성 실패: %[" + + "1]s\x02%[1]s 채굴자가 성공적으로 생성되었습니다\x02데이터베이스에 연결할 수 없습니다: %[1]s\x02풀 노드 API" + + "에 연결하는 중 오류 발생: %[1]s\x02사전 초기화 단계 완료\x02비밀번호를 위한 랜덤 바이트 생성에 실패했습니다: %" + + "[1]s\x02마이너 생성은 idempotent하지 않으므로 가이드 설정을 다시 실행하지 마십시오. 구성을 완료하려면 'curio" + + " config new-cluster %[1]s'를 실행해야 합니다.\x02FullNode에 대한 API 정보를 가져오는 데 실패했" + + "습니다: %[1]w\x02데몬 노드로부터 인증 토큰을 확인하는 중 오류 발생: %[1]s\x02기본 구성 생성 실패: %[1]" + + "s\x02데이터베이스에 'base' 구성 레이어를 삽입하는 데 실패했습니다: %[1]s\x02이 마이너 주소를 포함한 구성 'ba" + + "se'가 업데이트되었습니다.\x02데이터베이스에서 기본 구성을 로드하는 데 실패했습니다: %[1]s\x02기본 구성을 구문 분석하" + + "는 데 실패했습니다: %[1]s\x02기본 구성을 재생성하는 데 실패했습니다: %[1]s\x02Yugabyte 데이터베이스 설" + + "치에 연결할 정보를 입력하십시오 (https://download.yugabyte.com/)\x02호스트: %[1]s\x02포트" + + ": %[1]s\x02사용자 이름: %[1]s\x02비밀번호: %[1]s\x02데이터베이스: %[1]s\x02계속 연결 및 스키마 " + + "업데이트.\x04\x00\x01 ^\x02데이터베이스 구성 오류가 발생하여 마이그레이션을 포기합니다: %[1]s\x02Yuga" + + "byte 데이터베이스 호스트를 입력하십시오\x02호스트가 제공되지 않았습니다\x02Yugabyte 데이터베이스 %[1]s을 입력하" + + "십시오\x02Yugabyte 데이터베이스에 연결하는 중 오류가 발생했습니다: %[1]s\x02기본 설정 'base'가 이 마이" + + "너의 주소(%[1]s) 및 지갑 설정을 포함하도록 업데이트되었습니다.\x02구성 %[1]s를 %[2]s과 비교하세요. 지갑 주" + + "소 이외의 마이너 ID 사이의 변경 사항은 필요한 실행자를 위한 새로운 최소한의 레이어여야 합니다.\x02'base' 설정이 " + + "이 lotus-miner의 config.toml과 유사하게 만들어졌습니다.\x04\x00\x01 *\x02레이어 %[1]s가 " + + "생성되었습니다.\x04\x00\x01 \x22\x02구성 파일을 사용하려면:\x02Curio를 실행하려면: 기계 또는 cgro" + + "up 격리를 사용하여 다음 명령을 사용하세요 (예제 레이어 선택과 함께):" + +var zhIndex = []uint32{ // 122 elements + // Entry 0 - 1F + 0x00000000, 0x00000033, 0x0000008b, 0x00000134, + 0x0000017c, 0x000001cb, 0x000001e4, 0x000001f1, + 0x00000211, 0x0000022a, 0x00000240, 0x0000025d, + 0x000002a5, 0x000002e6, 0x00000302, 0x00000347, + 0x00000364, 0x0000038d, 0x000003ab, 0x000003e4, + 0x00000438, 0x00000465, 0x000004b4, 0x000004ef, + 0x00000524, 0x0000052e, 0x00000552, 0x00000570, + 0x00000594, 0x000005b2, 0x000005d0, 0x00000605, + // Entry 20 - 3F + 0x00000618, 0x00000627, 0x00000681, 0x000006be, + 0x000006e6, 0x00000745, 0x00000795, 0x000007e8, + 0x0000080e, 0x0000083b, 0x00000859, 0x00000895, + 0x000008d9, 0x000008e9, 0x000008f9, 0x0000092c, + 0x00000959, 0x0000097e, 0x000009a1, 0x00000a19, + 0x00000a37, 0x00000a66, 0x00000a8a, 0x00000aaf, + 0x00000ad3, 0x00000af7, 0x00000b1a, 0x00000b3a, + 0x00000b4f, 0x00000b9a, 0x00000bca, 0x00000bd1, + // Entry 40 - 5F + 0x00000bfb, 0x00000c1f, 0x00000c63, 0x00000c95, + 0x00000cde, 0x00000cf1, 0x00000d0b, 0x00000d2a, + 0x00000d4f, 0x00000d67, 0x00000d7c, 0x00000d94, + 0x00000da8, 0x00000dbf, 0x00000df0, 0x00000e15, + 0x00000e2b, 0x00000e3b, 0x00000e55, 0x00000e69, + 0x00000e7c, 0x00000e89, 0x00000ea9, 0x00000eb9, + 0x00000ed6, 0x00000ef6, 0x00000f10, 0x00000f2d, + 0x00000f5e, 0x00000f77, 0x00000fa0, 0x0000102d, + // Entry 60 - 7F + 0x00001059, 0x00001094, 0x000010b4, 0x000010e5, + 0x00001118, 0x00001145, 0x00001166, 0x0000118c, + 0x000011e6, 0x000011f5, 0x00001204, 0x00001216, + 0x00001225, 0x00001237, 0x00001256, 0x0000128e, + 0x000012b3, 0x000012c3, 0x000012e1, 0x0000130d, + 0x0000135e, 0x000013e0, 0x00001427, 0x00001441, + 0x00001459, 0x000014b0, +} // Size: 512 bytes + +const zhData string = "" + // Size: 5296 bytes + "\x04\x00\x01 .\x02使用箭头键进行导航:↓ ↑ → ←\x02此交互式工具将创建一个新的矿工角色,并为其创建基本配置层。\x02" + + "该过程部分幂等。一旦创建了新的矿工角色,并且随后的步骤失败,用户需要运行 'curio config new-cluster < 矿工 ID" + + " >' 来完成配置。\x02这个交互式工具可以在5分钟内将lotus-miner迁移到Curio。\x02每一步都需要您的确认,并且可以撤销。随" + + "时按Ctrl+C退出。\x02在终端中按下Ctrl+C\x02我想要:\x02从现有的 Lotus-Miner 迁移\x02创建一个新的矿工" + + "\x02中止剩余步骤。\x02Lotus-Miner到Curio迁移。\x02尝试使用%[1]s的网络界面进行更进一步的指导性改进。\x02如果" + + "适用,您现在可以迁移您的市场节点(%[1]s)。\x02新矿工初始化完成。\x02将 lotus-miner config.toml 迁移到" + + " Curio 的数据库配置中。\x02获取 API 时出错:%[1]s\x02无法获取FullNode的API信息:%[1]w\x02获取令牌时" + + "出错:%[1]s\x02保存配置到层时出错:%[1]s。正在中止迁移\x02Curio 团队希望改进您使用的软件。告诉团队您正在使用 `%[" + + "1]s`。\x02选择您想与Curio团队分享的内容。\x02个人数据:矿工 ID,Curio 版本,链(%[1]s 或 %[2]s)。签名。" + + "\x02聚合-匿名:版本,链和矿工算力(分桶)。\x02提示:我是在任何链上运行 Curio 的人。\x02没有。\x02获取矿工功率时出错:%" + + "[1]s\x02整理消息时出错:%[1]s\x02获取矿工信息时出错:%[1]s\x02签署消息时出错:%[1]s\x02发送消息时出错:%[1" + + "]s\x04\x00\x01 0\x02发送消息时出错:状态%[1]s,消息:\x02消息已发送。\x04\x00\x01 \x0a\x02文档" + + ":\x02'%[1]s'层存储通用配置。所有Curio实例都可以在其%[2]s参数中包含它。\x02您可以添加其他层进行每台机器的配置更改。" + + "\x02Filecoin %[1]s 频道:%[2]s 和 %[3]s\x02通过冗余增加可靠性:使用至少后层启动多台机器:'curio run" + + " --layers=post'\x02一个数据库可以服务多个矿工ID:为每个lotus-miner运行迁移。\x02请立即启动(或重新启动)%[" + + "1]s,因为数据库凭据已在%[2]s中。\x02等待%[1]s将扇区写入Yugabyte。\x02解释矿工ID时出错:%[1]s:ID:%[2]" + + "s\x02验证扇区时出错:%[1]s\x02扇区在数据库中。数据库已准备好用于%[1]s。\x02现在关闭lotus-miner和lotus-w" + + "orker,改为使用%[1]s运行。\x02按回车继续\x02中止迁移。\x02扇区已验证。发现了%[1]d个扇区位置。\x02已连接到Yuga" + + "byte。模式是当前的。\x02在数据库中启用扇区索引。\x02编码config.toml时出错:%[1]s\x02按回车键更新 %[1]s 以" + + "包含 Yugabyte 信息。在进行更改之前,将在该文件夹中写入备份文件。\x02扩展路径时出错:%[1]s\x02读取config.tom" + + "l文件模式时出错:%[1]s\x02创建备份文件时出错:%[1]s\x02读取 config.toml 时出错:%[1]s\x02写入备份文件时" + + "出错:%[1]s\x02关闭备份文件时出错:%[1]s\x02写入config.toml时出错:%[1]s\x04\x00\x01 \x1b" + + "\x02重新启动Lotus Miner。\x02已连接到Yugabyte\x02开始之前,请确保您的密封管道已排空并关闭lotus-miner。" + + "\x02选择您的lotus-miner配置目录的位置?\x02其他\x02输入%[1]s使用的配置目录的路径\x04\x00\x01 \x1f" + + "\x02未提供路径,放弃迁移\x02无法读取提供的目录中的config.toml文件,错误:%[1]s\x02无法从目录创建repo:%[1]s" + + "。 中止迁移\x02无法锁定矿工repo。 您的矿工必须停止:%[1]s\x0a 中止迁移\x02读取矿工配置\x04\x00\x01" + + "\x0a\x15\x02步骤完成:%[1]s\x02初始化新的矿工角色。\x02输入创建新矿工所需的信息\x02所有者地址:%[1]s\x02工" + + "作地址:%[1]s\x02发送者地址:%[1]s\x02扇区大小: %[1]d\x02置信度时期: %[1]d\x02继续验证地址并创建新的" + + "矿工角色。\x04\x00\x01 \x02矿工创建错误发生: %[1]s\x02输入所有者地址\x02未提供地址\x02解析地址失败: " + + "%[1]s\x02输入 %[1]s 地址\x02输入扇区大小\x02未提供值\x02解析扇区大小失败: %[1]s\x02置信度时期\x02解析" + + "置信度失败: %[1]s\x02创建矿工角色失败: %[1]s\x02矿工 %[1]s 创建成功\x02无法访问数据库: %[1]s\x02" + + "连接到完整节点 API 时发生错误: %[1]s\x02预初始化步骤完成\x02生成密码的随机字节失败: %[1]s\x02请不要再次运行引" + + "导设置,因为矿工创建不是幂等的。 您需要运行 'curio config new-cluster %[1]s' 来完成配置。\x02无法获取" + + " FullNode 的 API 信息: %[1]w\x02无法验证来自守护进程节点的授权令牌: %[1]s\x02无法生成默认配置: %[1]s" + + "\x02无法将 'base' 配置层插入数据库: %[1]s\x02配置 'base' 已更新以包含此矿工的地址\x02从数据库加载基本配置失败" + + ":%[1]s\x02解析基本配置失败:%[1]s\x02重新生成基本配置失败: %[1]s\x02输入连接到您的Yugabyte数据库安装的" + + "信息(https://download.yugabyte.com/)\x02主机:%[1]s\x02端口:%[1]s\x02用户名:%[1]" + + "s\x02密码:%[1]s\x02数据库:%[1]s\x02继续连接和更新架构。\x04\x00\x01 3\x02发生数据库配置错误,放弃迁移" + + ":%[1]s\x02输入Yugabyte数据库主机(S)\x02未提供主机\x02输入Yugabyte数据库 %[1]s\x02连接到Yug" + + "abyte数据库时出错:%[1]s\x02'base'配置已更新,包括该矿工的地址(%[1]s)及其钱包设置。\x02比较配置%[1]s和%[2" + + "]s。矿工ID之间除了钱包地址的变化应该是需要的运行者的一个新的、最小的层。\x02'base'配置已创建,以类似于这个lotus-miner的" + + "config.toml。\x04\x00\x01 \x15\x02层%[1]s已创建。\x04\x00\x01 \x13\x02要使用配置:" + + "\x02运行Curio:使用机器或cgroup隔离,使用命令(附带示例层选择):" + + // Total table size 20243 bytes (19KiB); checksum: AB52E150 diff --git a/cmd/curio/internal/translations/knowns/main.go b/cmd/curio/internal/translations/knowns/main.go new file mode 100644 index 00000000000..a30a940657e --- /dev/null +++ b/cmd/curio/internal/translations/knowns/main.go @@ -0,0 +1,82 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "path" + + "github.com/samber/lo" +) + +func main() { + for _, arg := range os.Args { + handleKnowns(arg) + } +} + +func handleKnowns(pathStart string) { + outpath := path.Join(pathStart, "out.gotext.json") + b, err := os.ReadFile(outpath) + if err != nil { + fmt.Println("cannot open "+outpath+":", err) + return + } + type TMsg struct { + ID string `json:"id"` + Translation string `json:"translation"` + Message string `json:"message"` + Placeholder json.RawMessage `json:"placeholder"` + } + type Dataformat struct { + Language string `json:"language"` + Messages []TMsg `json:"messages"` + } + var outData Dataformat + err = json.NewDecoder(bytes.NewBuffer(b)).Decode(&outData) + if err != nil { + fmt.Println("cannot decode "+outpath+":", err) + return + } + + f, err := os.Open(path.Join(pathStart, "messages.gotext.json")) + if err != nil { + fmt.Println("cannot open "+path.Join(pathStart, "messages.gotext.json")+":", err) + return + } + defer func() { _ = f.Close() }() + + var msgData Dataformat + err = json.NewDecoder(f).Decode(&msgData) + if err != nil { + fmt.Println("cannot decode "+path.Join(pathStart, "messages.gotext.json")+":", err) + return + } + + knowns := map[string]string{} + for _, msg := range msgData.Messages { + knowns[msg.ID] = msg.Translation + } + + toTranslate := lo.Filter(outData.Messages, func(msg TMsg, _ int) bool { + _, ok := knowns[msg.ID] + return !ok + }) + + outData.Messages = toTranslate // drop the "done" messages + var outJSON bytes.Buffer + enc := json.NewEncoder(&outJSON) + enc.SetIndent(" ", " ") + err = enc.Encode(outData) + if err != nil { + fmt.Println("cannot encode "+outpath+":", err) + return + } + err = os.WriteFile(outpath, outJSON.Bytes(), 0644) + if err != nil { + fmt.Println("cannot write "+outpath+":", err) + return + } + fmt.Println("rearranged successfully") +} diff --git a/cmd/curio/internal/translations/locales/en/out.gotext.json b/cmd/curio/internal/translations/locales/en/out.gotext.json new file mode 100644 index 00000000000..6046786220d --- /dev/null +++ b/cmd/curio/internal/translations/locales/en/out.gotext.json @@ -0,0 +1,1636 @@ +{ + "language": "en", + "messages": [ + { + "id": "Use the arrow keys to navigate: ↓ ↑ → ←", + "message": "Use the arrow keys to navigate: ↓ ↑ → ←", + "translation": "Use the arrow keys to navigate: ↓ ↑ → ←", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "message": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "translation": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "message": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "translation": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "This interactive tool migrates lotus-miner to Curio in 5 minutes.", + "message": "This interactive tool migrates lotus-miner to Curio in 5 minutes.", + "translation": "This interactive tool migrates lotus-miner to Curio in 5 minutes.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.", + "message": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.", + "translation": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Ctrl+C pressed in Terminal", + "message": "Ctrl+C pressed in Terminal", + "translation": "Ctrl+C pressed in Terminal", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "I want to:", + "message": "I want to:", + "translation": "I want to:", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Migrate from existing Lotus-Miner", + "message": "Migrate from existing Lotus-Miner", + "translation": "Migrate from existing Lotus-Miner", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Create a new miner", + "message": "Create a new miner", + "translation": "Create a new miner", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Aborting remaining steps.", + "message": "Aborting remaining steps.", + "translation": "Aborting remaining steps.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]v", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Lotus-Miner to Curio Migration.", + "message": "Lotus-Miner to Curio Migration.", + "translation": "Lotus-Miner to Curio Migration.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Try the web interface with {Rendercurio_run___layersgui} for further guided improvements.", + "message": "Try the web interface with {Rendercurio_run___layersgui} for further guided improvements.", + "translation": "Try the web interface with {Rendercurio_run___layersgui} for further guided improvements.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Rendercurio_run___layersgui", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "code.Render(\"curio run --layers=gui\")" + } + ], + "fuzzy": true + }, + { + "id": "You can now migrate your market node ({Boost}), if applicable.", + "message": "You can now migrate your market node ({Boost}), if applicable.", + "translation": "You can now migrate your market node ({Boost}), if applicable.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Boost", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"Boost\"" + } + ], + "fuzzy": true + }, + { + "id": "New Miner initialization complete.", + "message": "New Miner initialization complete.", + "translation": "New Miner initialization complete.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "message": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "translation": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Error getting API: {Error}", + "message": "Error getting API: {Error}", + "translation": "Error getting API: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "could not get API info for FullNode: {Err}", + "message": "could not get API info for FullNode: {Err}", + "translation": "could not get API info for FullNode: {Err}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Err", + "string": "%[1]w", + "type": "error", + "underlyingType": "interface{Error() string}", + "argNum": 1, + "expr": "err" + } + ], + "fuzzy": true + }, + { + "id": "Error getting token: {Error}", + "message": "Error getting token: {Error}", + "translation": "Error getting token: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error saving config to layer: {Error}. Aborting Migration", + "message": "Error saving config to layer: {Error}. Aborting Migration", + "translation": "Error saving config to layer: {Error}. Aborting Migration", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "message": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "translation": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Curio", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"curio\"" + } + ], + "fuzzy": true + }, + { + "id": "Select what you want to share with the Curio team.", + "message": "Select what you want to share with the Curio team.", + "translation": "Select what you want to share with the Curio team.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "message": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "translation": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Mainnet", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"mainnet\"" + }, + { + "id": "Calibration", + "string": "%[2]s", + "type": "string", + "underlyingType": "string", + "argNum": 2, + "expr": "\"calibration\"" + } + ], + "fuzzy": true + }, + { + "id": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "message": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "translation": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Hint: I am someone running Curio on whichever chain.", + "message": "Hint: I am someone running Curio on whichever chain.", + "translation": "Hint: I am someone running Curio on whichever chain.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Nothing.", + "message": "Nothing.", + "translation": "Nothing.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Error getting miner power: {Error}", + "message": "Error getting miner power: {Error}", + "translation": "Error getting miner power: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error marshalling message: {Error}", + "message": "Error marshalling message: {Error}", + "translation": "Error marshalling message: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error getting miner info: {Error}", + "message": "Error getting miner info: {Error}", + "translation": "Error getting miner info: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error signing message: {Error}", + "message": "Error signing message: {Error}", + "translation": "Error signing message: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error sending message: {Error}", + "message": "Error sending message: {Error}", + "translation": "Error sending message: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error sending message: Status {Status}, Message:", + "message": "Error sending message: Status {Status}, Message:", + "translation": "Error sending message: Status {Status}, Message:", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Status", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "resp.Status" + }, + { + "id": "Stringb", + "string": "%[2]v", + "type": "string", + "underlyingType": "string", + "argNum": 2, + "expr": "string(b)" + } + ], + "fuzzy": true + }, + { + "id": "Message sent.", + "message": "Message sent.", + "translation": "Message sent.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Documentation:", + "message": "Documentation:", + "translation": "Documentation:", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.", + "message": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.", + "translation": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Base", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"base\"" + }, + { + "id": "__layers", + "string": "%[2]s", + "type": "string", + "underlyingType": "string", + "argNum": 2, + "expr": "\"--layers\"" + } + ], + "fuzzy": true + }, + { + "id": "You can add other layers for per-machine configuration changes.", + "message": "You can add other layers for per-machine configuration changes.", + "translation": "You can add other layers for per-machine configuration changes.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}", + "message": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}", + "translation": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Slack", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"Slack\"" + }, + { + "id": "Fil_curio_help", + "string": "%[2]s", + "type": "string", + "underlyingType": "string", + "argNum": 2, + "expr": "\"#fil-curio-help\"" + }, + { + "id": "Fil_curio_dev", + "string": "%[3]s", + "type": "string", + "underlyingType": "string", + "argNum": 3, + "expr": "\"#fil-curio-dev\"" + } + ], + "fuzzy": true + }, + { + "id": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "message": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "translation": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.", + "message": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.", + "translation": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.", + "message": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.", + "translation": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Lotus_miner", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"lotus-miner\"" + }, + { + "id": "Toml", + "string": "%[2]s", + "type": "string", + "underlyingType": "string", + "argNum": 2, + "expr": "\"config.toml\"" + } + ], + "fuzzy": true + }, + { + "id": "Waiting for {Lotus_miner} to write sectors into Yugabyte.", + "message": "Waiting for {Lotus_miner} to write sectors into Yugabyte.", + "translation": "Waiting for {Lotus_miner} to write sectors into Yugabyte.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Lotus_miner", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"lotus-miner\"" + } + ], + "fuzzy": true + }, + { + "id": "Error interpreting miner ID: {Error}: ID: {String}", + "message": "Error interpreting miner ID: {Error}: ID: {String}", + "translation": "Error interpreting miner ID: {Error}: ID: {String}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + }, + { + "id": "String", + "string": "%[2]s", + "type": "string", + "underlyingType": "string", + "argNum": 2, + "expr": "d.MinerID.String()" + } + ], + "fuzzy": true + }, + { + "id": "Error verifying sectors: {Error}", + "message": "Error verifying sectors: {Error}", + "translation": "Error verifying sectors: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "The sectors are in the database. The database is ready for {Curio}.", + "message": "The sectors are in the database. The database is ready for {Curio}.", + "translation": "The sectors are in the database. The database is ready for {Curio}.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Curio", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"Curio\"" + } + ], + "fuzzy": true + }, + { + "id": "Now shut down lotus-miner and lotus-worker and use run {Rendercurio_run} instead.", + "message": "Now shut down lotus-miner and lotus-worker and use run {Rendercurio_run} instead.", + "translation": "Now shut down lotus-miner and lotus-worker and use run {Rendercurio_run} instead.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Rendercurio_run", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "code.Render(\"curio run\")" + } + ], + "fuzzy": true + }, + { + "id": "Press return to continue", + "message": "Press return to continue", + "translation": "Press return to continue", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Aborting migration.", + "message": "Aborting migration.", + "translation": "Aborting migration.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Sectors verified. {I} sector locations found.", + "message": "Sectors verified. {I} sector locations found.", + "translation": "Sectors verified. {I} sector locations found.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "I", + "string": "%[1]d", + "type": "[]int", + "underlyingType": "[]int", + "argNum": 1, + "expr": "i" + } + ], + "fuzzy": true + }, + { + "id": "Connected to Yugabyte. Schema is current.", + "message": "Connected to Yugabyte. Schema is current.", + "translation": "Connected to Yugabyte. Schema is current.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Enabling Sector Indexing in the database.", + "message": "Enabling Sector Indexing in the database.", + "translation": "Enabling Sector Indexing in the database.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Error encoding config.toml: {Error}", + "message": "Error encoding config.toml: {Error}", + "translation": "Error encoding config.toml: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "message": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "translation": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Toml", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"config.toml\"" + } + ], + "fuzzy": true + }, + { + "id": "Error expanding path: {Error}", + "message": "Error expanding path: {Error}", + "translation": "Error expanding path: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error reading filemode of config.toml: {Error}", + "message": "Error reading filemode of config.toml: {Error}", + "translation": "Error reading filemode of config.toml: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error creating backup file: {Error}", + "message": "Error creating backup file: {Error}", + "translation": "Error creating backup file: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error reading config.toml: {Error}", + "message": "Error reading config.toml: {Error}", + "translation": "Error reading config.toml: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error writing backup file: {Error}", + "message": "Error writing backup file: {Error}", + "translation": "Error writing backup file: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error closing backup file: {Error}", + "message": "Error closing backup file: {Error}", + "translation": "Error closing backup file: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error writing config.toml: {Error}", + "message": "Error writing config.toml: {Error}", + "translation": "Error writing config.toml: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Restart Lotus Miner.", + "message": "Restart Lotus Miner.", + "translation": "Restart Lotus Miner.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Connected to Yugabyte", + "message": "Connected to Yugabyte", + "translation": "Connected to Yugabyte", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.", + "message": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.", + "translation": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Select the location of your lotus-miner config directory?", + "message": "Select the location of your lotus-miner config directory?", + "translation": "Select the location of your lotus-miner config directory?", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Other", + "message": "Other", + "translation": "Other", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Enter the path to the configuration directory used by {Lotus_miner}", + "message": "Enter the path to the configuration directory used by {Lotus_miner}", + "translation": "Enter the path to the configuration directory used by {Lotus_miner}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Lotus_miner", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"lotus-miner\"" + } + ], + "fuzzy": true + }, + { + "id": "No path provided, abandoning migration", + "message": "No path provided, abandoning migration", + "translation": "No path provided, abandoning migration", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Cannot read the config.toml file in the provided directory, Error: {Error}", + "message": "Cannot read the config.toml file in the provided directory, Error: {Error}", + "translation": "Cannot read the config.toml file in the provided directory, Error: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Could not create repo from directory: {Error}. Aborting migration", + "message": "Could not create repo from directory: {Error}. Aborting migration", + "translation": "Could not create repo from directory: {Error}. Aborting migration", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration", + "message": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration", + "translation": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Read Miner Config", + "message": "Read Miner Config", + "translation": "Read Miner Config", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Step Complete: {Step}", + "message": "Step Complete: {Step}", + "translation": "Step Complete: {Step}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Step", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "step" + } + ], + "fuzzy": true + }, + { + "id": "Initializing a new miner actor.", + "message": "Initializing a new miner actor.", + "translation": "Initializing a new miner actor.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Enter the info to create a new miner", + "message": "Enter the info to create a new miner", + "translation": "Enter the info to create a new miner", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Owner Address: {String}", + "message": "Owner Address: {String}", + "translation": "Owner Address: {String}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "String", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "d.owner.String()" + } + ], + "fuzzy": true + }, + { + "id": "Worker Address: {String}", + "message": "Worker Address: {String}", + "translation": "Worker Address: {String}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "String", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "d.worker.String()" + } + ], + "fuzzy": true + }, + { + "id": "Sender Address: {String}", + "message": "Sender Address: {String}", + "translation": "Sender Address: {String}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "String", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "d.sender.String()" + } + ], + "fuzzy": true + }, + { + "id": "Sector Size: {Ssize}", + "message": "Sector Size: {Ssize}", + "translation": "Sector Size: {Ssize}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Ssize", + "string": "%[1]d", + "type": "github.com/filecoin-project/go-state-types/abi.SectorSize", + "underlyingType": "uint64", + "argNum": 1, + "expr": "d.ssize" + } + ], + "fuzzy": true + }, + { + "id": "Confidence epochs: {Confidence}", + "message": "Confidence epochs: {Confidence}", + "translation": "Confidence epochs: {Confidence}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Confidence", + "string": "%[1]d", + "type": "uint64", + "underlyingType": "uint64", + "argNum": 1, + "expr": "d.confidence" + } + ], + "fuzzy": true + }, + { + "id": "Continue to verify the addresses and create a new miner actor.", + "message": "Continue to verify the addresses and create a new miner actor.", + "translation": "Continue to verify the addresses and create a new miner actor.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Miner creation error occurred: {Error}", + "message": "Miner creation error occurred: {Error}", + "translation": "Miner creation error occurred: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Enter the owner address", + "message": "Enter the owner address", + "translation": "Enter the owner address", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "No address provided", + "message": "No address provided", + "translation": "No address provided", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Failed to parse the address: {Error}", + "message": "Failed to parse the address: {Error}", + "translation": "Failed to parse the address: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Enter {Stringworker_senderi_1} address", + "message": "Enter {Stringworker_senderi_1} address", + "translation": "Enter {Stringworker_senderi_1} address", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Stringworker_senderi_1", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "[]string{\"worker\", \"sender\"}[i-1]" + } + ], + "fuzzy": true + }, + { + "id": "Enter the sector size", + "message": "Enter the sector size", + "translation": "Enter the sector size", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "No value provided", + "message": "No value provided", + "translation": "No value provided", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Failed to parse sector size: {Error}", + "message": "Failed to parse sector size: {Error}", + "translation": "Failed to parse sector size: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Confidence epochs", + "message": "Confidence epochs", + "translation": "Confidence epochs", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Failed to parse confidence: {Error}", + "message": "Failed to parse confidence: {Error}", + "translation": "Failed to parse confidence: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to create the miner actor: {Error}", + "message": "Failed to create the miner actor: {Error}", + "translation": "Failed to create the miner actor: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Miner {String} created successfully", + "message": "Miner {String} created successfully", + "translation": "Miner {String} created successfully", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "String", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "miner.String()" + } + ], + "fuzzy": true + }, + { + "id": "Cannot reach the DB: {Error}", + "message": "Cannot reach the DB: {Error}", + "translation": "Cannot reach the DB: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Error connecting to full node API: {Error}", + "message": "Error connecting to full node API: {Error}", + "translation": "Error connecting to full node API: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Pre-initialization steps complete", + "message": "Pre-initialization steps complete", + "translation": "Pre-initialization steps complete", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Failed to generate random bytes for secret: {Error}", + "message": "Failed to generate random bytes for secret: {Error}", + "translation": "Failed to generate random bytes for secret: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "message": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "translation": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "String", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "d.MinerID.String()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to get API info for FullNode: {Err}", + "message": "Failed to get API info for FullNode: {Err}", + "translation": "Failed to get API info for FullNode: {Err}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Err", + "string": "%[1]w", + "type": "error", + "underlyingType": "interface{Error() string}", + "argNum": 1, + "expr": "err" + } + ], + "fuzzy": true + }, + { + "id": "Failed to verify the auth token from daemon node: {Error}", + "message": "Failed to verify the auth token from daemon node: {Error}", + "translation": "Failed to verify the auth token from daemon node: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to generate default config: {Error}", + "message": "Failed to generate default config: {Error}", + "translation": "Failed to generate default config: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to insert 'base' config layer in database: {Error}", + "message": "Failed to insert 'base' config layer in database: {Error}", + "translation": "Failed to insert 'base' config layer in database: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Configuration 'base' was updated to include this miner's address", + "message": "Configuration 'base' was updated to include this miner's address", + "translation": "Configuration 'base' was updated to include this miner's address", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Failed to load base config from database: {Error}", + "message": "Failed to load base config from database: {Error}", + "translation": "Failed to load base config from database: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to parse base config: {Error}", + "message": "Failed to parse base config: {Error}", + "translation": "Failed to parse base config: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Failed to regenerate base config: {Error}", + "message": "Failed to regenerate base config: {Error}", + "translation": "Failed to regenerate base config: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)", + "message": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)", + "translation": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Host: {Hosts_}", + "message": "Host: {Hosts_}", + "translation": "Host: {Hosts_}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Hosts_", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "strings.Join(harmonyCfg.Hosts, \",\")" + } + ], + "fuzzy": true + }, + { + "id": "Port: {Port}", + "message": "Port: {Port}", + "translation": "Port: {Port}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Port", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonyCfg.Port" + } + ], + "fuzzy": true + }, + { + "id": "Username: {Username}", + "message": "Username: {Username}", + "translation": "Username: {Username}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Username", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonyCfg.Username" + } + ], + "fuzzy": true + }, + { + "id": "Password: {Password}", + "message": "Password: {Password}", + "translation": "Password: {Password}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Password", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonyCfg.Password" + } + ], + "fuzzy": true + }, + { + "id": "Database: {Database}", + "message": "Database: {Database}", + "translation": "Database: {Database}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Database", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonyCfg.Database" + } + ], + "fuzzy": true + }, + { + "id": "Continue to connect and update schema.", + "message": "Continue to connect and update schema.", + "translation": "Continue to connect and update schema.", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Database config error occurred, abandoning migration: {Error}", + "message": "Database config error occurred, abandoning migration: {Error}", + "translation": "Database config error occurred, abandoning migration: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Enter the Yugabyte database host(s)", + "message": "Enter the Yugabyte database host(s)", + "translation": "Enter the Yugabyte database host(s)", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "No host provided", + "message": "No host provided", + "translation": "No host provided", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", + "message": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", + "translation": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Stringport_username_password_databasei_1", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "[]string{\"port\", \"username\", \"password\", \"database\"}[i-1]" + } + ], + "fuzzy": true + }, + { + "id": "Error connecting to Yugabyte database: {Error}", + "message": "Error connecting to Yugabyte database: {Error}", + "translation": "Error connecting to Yugabyte database: {Error}", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ], + "fuzzy": true + }, + { + "id": "Configuration 'base' was updated to include this miner's address ({MinerAddress}) and its wallet setup.", + "message": "Configuration 'base' was updated to include this miner's address ({MinerAddress}) and its wallet setup.", + "translation": "Configuration 'base' was updated to include this miner's address ({MinerAddress}) and its wallet setup.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "MinerAddress", + "string": "%[1]s", + "type": "github.com/filecoin-project/go-address.Address", + "underlyingType": "struct{str string}", + "argNum": 1, + "expr": "minerAddress" + } + ], + "fuzzy": true + }, + { + "id": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.", + "message": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.", + "translation": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "Base", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "\"base\"" + }, + { + "id": "MinerAddresses0", + "string": "%[2]s", + "type": "string", + "underlyingType": "string", + "argNum": 2, + "expr": "\"mig-\" + curioCfg.Addresses[0].MinerAddresses[0]" + } + ], + "fuzzy": true + }, + { + "id": "Configuration 'base' was created to resemble this lotus-miner's config.toml .", + "message": "Configuration 'base' was created to resemble this lotus-miner's config.toml .", + "translation": "Configuration 'base' was created to resemble this lotus-miner's config.toml .", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "Layer {LayerName} created.", + "message": "Layer {LayerName} created.", + "translation": "Layer {LayerName} created.", + "translatorComment": "Copied from source.", + "placeholders": [ + { + "id": "LayerName", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "layerName" + } + ], + "fuzzy": true + }, + { + "id": "To work with the config:", + "message": "To work with the config:", + "translation": "To work with the config:", + "translatorComment": "Copied from source.", + "fuzzy": true + }, + { + "id": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):", + "message": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):", + "translation": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):", + "translatorComment": "Copied from source.", + "fuzzy": true + } + ] +} \ No newline at end of file diff --git a/cmd/curio/internal/translations/locales/ko/messages.gotext.json b/cmd/curio/internal/translations/locales/ko/messages.gotext.json new file mode 100644 index 00000000000..bac1140e8e0 --- /dev/null +++ b/cmd/curio/internal/translations/locales/ko/messages.gotext.json @@ -0,0 +1,1106 @@ +{ + "language": "ko", + "messages": [ + { + "id": "This interactive tool will walk you through migration of Curio.\nPress Ctrl+C to exit at any time.", + "message": "This interactive tool will walk you through migration of Curio.\nPress Ctrl+C to exit at any time.", + "translation": "이 대화형 도구는 Curio 마이그레이션 과정을 안내합니다.\n언제든지 종료하려면 Ctrl+C를 누르십시오." + }, + { + "id": "This tool confirms each action it does.", + "message": "This tool confirms each action it does.", + "translation": "이 도구는 수행하는 각 작업을 확인합니다." + }, + { + "id": "Ctrl+C pressed in Terminal", + "message": "Ctrl+C pressed in Terminal", + "translation": "터미널에서 Ctrl+C가 눌림" + }, + { + "id": "Verifying Sectors exist in Yugabyte.", + "message": "Verifying Sectors exist in Yugabyte.", + "translation": "Yugabyte에 섹터가 존재하는지 확인 중." + }, + { + "id": "Error verifying sectors: {Error}", + "message": "Error verifying sectors: {Error}", + "translation": "섹터 확인 중 오류 발생: {Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Sectors verified. {I} sectors found.", + "message": "Sectors verified. {I} sectors found.", + "translation": "섹터가 확인되었습니다. {I}개의 섹터가 발견되었습니다.", + "placeholders": [ + { + "id": "I", + "string": "%[1]d", + "type": "[]int", + "underlyingType": "[]int", + "argNum": 1, + "expr": "i" + } + ] + }, + { + "id": "Never remove the database info from the config.toml for lotus-miner as it avoids double PoSt.", + "message": "Never remove the database info from the config.toml for lotus-miner as it avoids double PoSt.", + "translation": "로터스 마이너의 config.toml에서 데이터베이스 정보를 제거하지 마십시오. 두 번의 PoSt를 피하기 위함입니다." + }, + { + "id": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)", + "message": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)", + "translation": "Yugabyte 데이터베이스 설치에 연결할 정보를 입력하십시오 (https://download.yugabyte.com/)" + }, + { + "id": "Host: {Hosts_}", + "message": "Host: {Hosts_}", + "translation": "호스트: {Hosts_}", + "placeholders": [ + { + "id": "Hosts_", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "strings.Join(harmonycfg.Hosts, \",\")" + } + ] + }, + { + "id": "Port: {Port}", + "message": "Port: {Port}", + "translation": "포트: {Port}", + "placeholders": [ + { + "id": "Port", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonycfg.Port" + } + ] + }, + { + "id": "Username: {Username}", + "message": "Username: {Username}", + "translation": "사용자 이름: {Username}", + "placeholders": [ + { + "id": "Username", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonycfg.Username" + } + ] + }, + { + "id": "Password: {Password}", + "message": "Password: {Password}", + "translation": "비밀번호: {Password}", + "placeholders": [ + { + "id": "Password", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonycfg.Password" + } + ] + }, + { + "id": "Database: {Database}", + "message": "Database: {Database}", + "translation": "데이터베이스: {Database}", + "placeholders": [ + { + "id": "Database", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonycfg.Database" + } + ] + }, + { + "id": "Continue to connect and update schema.", + "message": "Continue to connect and update schema.", + "translation": "계속 연결 및 스키마 업데이트." + }, + { + "id": "Database config error occurred, abandoning migration: {Error}", + "message": "Database config error occurred, abandoning migration: {Error}", + "translation": "데이터베이스 구성 오류가 발생하여 마이그레이션을 포기합니다: {Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Enter the Yugabyte database host(s)", + "message": "Enter the Yugabyte database host(s)", + "translation": "Yugabyte 데이터베이스 호스트를 입력하십시오" + }, + { + "id": "No host provided", + "message": "No host provided", + "translation": "호스트가 제공되지 않았습니다" + }, + { + "id": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", + "message": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", + "translation": "Yugabyte 데이터베이스 {Stringport_username_password_databasei_1}을 입력하십시오", + "placeholders": [ + { + "id": "Stringport_username_password_databasei_1", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "[]string{\"port\", \"username\", \"password\", \"database\"}[i-1]" + } + ] + }, + { + "id": "No value provided", + "message": "No value provided", + "translation": "값이 제공되지 않았습니다" + }, + { + "id": "Error connecting to Yugabyte database: {Error}", + "message": "Error connecting to Yugabyte database: {Error}", + "translation": "Yugabyte 데이터베이스에 연결하는 중 오류가 발생했습니다: {Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Connected to Yugabyte. Schema is current.", + "message": "Connected to Yugabyte. Schema is current.", + "translation": "Yugabyte에 연결되었습니다. 스키마가 현재입니다." + }, + { + "id": "Error encoding config.toml: {Error}", + "message": "Error encoding config.toml: {Error}", + "translation": "config.toml을 인코딩하는 중 오류가 발생했습니다: {Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Error reading filemode of config.toml: {Error}", + "message": "Error reading filemode of config.toml: {Error}", + "translation": "config.toml의 파일 모드를 읽는 중 오류가 발생했습니다: {Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Error writing config.toml: {Error}", + "message": "Error writing config.toml: {Error}", + "translation": "config.toml을 쓰는 중 오류가 발생했습니다: {Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Restart Lotus Miner.", + "message": "Restart Lotus Miner.", + "translation": "로터스 마이너 재시작." + }, + { + "id": "Connected to Yugabyte", + "message": "Connected to Yugabyte", + "translation": "Yugabyte에 연결됨" + }, + { + "id": "Select the location of your lotus-miner config directory?", + "message": "Select the location of your lotus-miner config directory?", + "translation": "로터스 마이너 구성 디렉토리의 위치를 선택하시겠습니까?" + }, + { + "id": "Other", + "message": "Other", + "translation": "기타" + }, + { + "id": "Enter the path to the configuration directory used by lotus-miner", + "message": "Enter the path to the configuration directory used by lotus-miner", + "translation": "로터스 마이너에서 사용하는 구성 디렉토리의 경로를 입력하십시오" + }, + { + "id": "No path provided, abandoning migration", + "message": "No path provided, abandoning migration", + "translation": "경로가 제공되지 않았으므로 마이그레이션을 포기합니다" + }, + { + "id": "Cannot read the config.toml file in the provided directory, Error: {Error}", + "message": "Cannot read the config.toml file in the provided directory, Error: {Error}", + "translation": "제공된 디렉토리에서 config.toml 파일을 읽을 수 없습니다. 오류: {Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Read Miner Config", + "message": "Read Miner Config", + "translation": "마이너 구성 읽기" + }, + { + "id": "Completed Step: {Step}", + "message": "Completed Step: {Step}", + "translation": "단계 완료: {Step}", + "placeholders": [ + { + "id": "Step", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "step" + } + ] + }, + { + "id": "This interactive tool migrates lotus-miner to Curio in 5 minutes.", + "translation": "이 대화형 도구는 5분 안에 lotus-miner를 Curio로 이주합니다.", + "message": "This interactive tool migrates lotus-miner to Curio in 5 minutes.", + "placeholder": null + }, + { + "id": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.", + "translation": "각 단계는 확인이 필요하며 되돌릴 수 있습니다. 언제든지 Ctrl+C를 눌러 종료할 수 있습니다.", + "message": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.", + "placeholder": null + }, + { + "id": "Use the arrow keys to navigate: ↓ ↑ → ←", + "translation": "화살표 키를 사용하여 이동하세요: ↓ ↑ → ←", + "message": "Use the arrow keys to navigate: ↓ ↑ → ←", + "placeholder": null + }, + { + "id": "Lotus-Miner to Curio Migration.", + "translation": "Lotus-Miner에서 Curio로 이주.", + "message": "Lotus-Miner to Curio Migration.", + "placeholder": null + }, + { + "id": "Try the web interface with for further guided improvements.", + "translation": "더 나은 안내를 위해 웹 인터페이스를 사용해보세요.", + "message": "Try the web interface with for further guided improvements.", + "placeholder": null + }, + { + "id": "You can now migrate your market node ({Boost}), if applicable.", + "translation": "해당하는 경우 이제 시장 노드를 이주할 수 있습니다 ({Boost}).", + "message": "You can now migrate your market node ({Boost}), if applicable.", + "placeholder": null + }, + { + "id": "Migrating config.toml to database.", + "translation": "config.toml을 데이터베이스로 이주 중입니다.", + "message": "Migrating config.toml to database.", + "placeholder": null + }, + { + "id": "Error reading from database: {Error}. Aborting Migration.", + "translation": "데이터베이스에서 읽는 중 오류 발생: {Error}. 마이그레이션 중단.", + "message": "Error reading from database: {Error}. Aborting Migration.", + "placeholder": null + }, + { + "id": "cannot read API: {Error}. Aborting Migration", + "translation": "API를 읽을 수 없습니다: {Error}. 마이그레이션 중단", + "message": "cannot read API: {Error}. Aborting Migration", + "placeholder": null + }, + { + "id": "Error saving config to layer: {Error}. Aborting Migration", + "translation": "레이어에 구성을 저장하는 중 오류 발생: {Error}. 마이그레이션 중단", + "message": "Error saving config to layer: {Error}. Aborting Migration", + "placeholder": null + }, + { + "id": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.", + "translation": "Protocol Labs는 당신이 사용하는 소프트웨어를 개선하고 싶어합니다. Curio를 사용 중이라고 팀에 알려주세요.", + "message": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.", + "placeholder": null + }, + { + "id": "Select what you want to share with the Curio team.", + "translation": "Curio 팀과 공유하고 싶은 것을 선택하세요.", + "message": "Select what you want to share with the Curio team.", + "placeholder": null + }, + { + "id": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.", + "translation": "개별 데이터: 마이너 ID, Curio 버전, 네트워크 ({Mainnet} 또는 {Testnet}). 서명됨.", + "message": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.", + "placeholder": null + }, + { + "id": "Aggregate-Anonymous: version, net, and Miner power (bucketed).", + "translation": "집계-익명: 버전, 네트워크, 그리고 마이너 파워 (버킷).", + "message": "Aggregate-Anonymous: version, net, and Miner power (bucketed).", + "placeholder": null + }, + { + "id": "Hint: I am someone running Curio on net.", + "translation": "힌트: 네트워크에서 Curio를 실행 중인 사람입니다.", + "message": "Hint: I am someone running Curio on net.", + "placeholder": null + }, + { + "id": "Nothing.", + "translation": "아무것도 없습니다.", + "message": "Nothing.", + "placeholder": null + }, + { + "id": "Aborting remaining steps.", + "translation": "나머지 단계를 중단합니다.", + "message": "Aborting remaining steps.", + "placeholder": null + }, + { + "id": "Error connecting to lotus node: {Error}", + "translation": "로터스 노드에 연결하는 중 오류 발생: {Error}", + "message": "Error connecting to lotus node: {Error}", + "placeholder": null + }, + { + "id": "Error getting miner power: {Error}", + "translation": "마이너 파워를 가져오는 중 오류 발생: {Error}", + "message": "Error getting miner power: {Error}", + "placeholder": null + }, + { + "id": "Error marshalling message: {Error}", + "translation": "메시지를 마샬하는 중 오류 발생: {Error}", + "message": "Error marshalling message: {Error}", + "placeholder": null + }, + { + "id": "Error getting miner info: {Error}", + "translation": "마이너 정보를 가져오는 중 오류 발생: {Error}", + "message": "Error getting miner info: {Error}", + "placeholder": null + }, + { + "id": "Error signing message: {Error}", + "translation": "메시지 서명 중 오류 발생: {Error}", + "message": "Error signing message: {Error}", + "placeholder": null + }, + { + "id": "Error sending message: {Error}", + "translation": "메시지 전송 중 오류 발생: {Error}", + "message": "Error sending message: {Error}", + "placeholder": null + }, + { + "id": "Error sending message: Status {Status}, Message:", + "translation": "메시지 전송 중 오류 발생: 상태 {Status}, 메시지:", + "message": "Error sending message: Status {Status}, Message:", + "placeholder": null + }, + { + "id": "Message sent.", + "translation": "메시지가 전송되었습니다.", + "message": "Message sent.", + "placeholder": null + }, + { + "id": "Documentation:", + "translation": "문서:", + "message": "Documentation:", + "placeholder": null + }, + { + "id": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.", + "translation": "'{Base}' 레이어에는 공통 구성이 저장됩니다. 모든 Curio 인스턴스는 {__layers} 인수에 포함시킬 수 있습니다.", + "message": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.", + "placeholder": null + }, + { + "id": "You can add other layers for per-machine configuration changes.", + "translation": "기계별 구성 변경을 위해 다른 레이어를 추가할 수 있습니다.", + "message": "You can add other layers for per-machine configuration changes.", + "placeholder": null + }, + { + "id": "Join {Fil_curio_help} in Filecoin {Slack} for help.", + "translation": "도움을 위해 Filecoin {Slack}의 {Fil_curio_help}에 가입하세요.", + "message": "Join {Fil_curio_help} in Filecoin {Slack} for help.", + "placeholder": null + }, + { + "id": "Join {Fil_curio_dev} in Filecoin {Slack} to follow development and feedback!", + "translation": "개발과 피드백을 따르려면 Filecoin {Slack}의 {Fil_curio_dev}에 가입하세요!", + "message": "Join {Fil_curio_dev} in Filecoin {Slack} to follow development and feedback!", + "placeholder": null + }, + { + "id": "Want PoST redundancy? Run many Curio instances with the '{Post}' layer.", + "translation": "PoST 중복성이 필요하신가요? '{Post}' 레이어와 함께 여러 Curio 인스턴스를 실행하세요.", + "message": "Want PoST redundancy? Run many Curio instances with the '{Post}' layer.", + "placeholder": null + }, + { + "id": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.", + "translation": "브라우저를 웹 GUI로 이동하여 {Boost} 및 고급 기능으로 설정을 완료하세요.", + "message": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.", + "placeholder": null + }, + { + "id": "For SPs with multiple Miner IDs, run 1 migration per lotus-miner all to the same 1 database. The cluster will serve all Miner IDs.", + "translation": "여러 마이너 ID가 있는 SP의 경우 각 lotus-miner당 1회 마이그레이션을 동일한 1개의 데이터베이스로 모두 실행하세요. 클러스터는 모든 마이너 ID를 제공합니다.", + "message": "For SPs with multiple Miner IDs, run 1 migration per lotus-miner all to the same 1 database. The cluster will serve all Miner IDs.", + "placeholder": null + }, + { + "id": "Please start {Lotus_miner} now that database credentials are in {Toml}.", + "translation": "데이터베이스 자격 증명이 {Toml}에 있으므로 이제 {Lotus_miner}를 시작하세요.", + "message": "Please start {Lotus_miner} now that database credentials are in {Toml}.", + "placeholder": null + }, + { + "id": "Waiting for {Lotus_miner} to write sectors into Yugabyte.", + "translation": "{Lotus_miner}가 Yugabyte에 섹터를 기록하도록 대기 중입니다.", + "message": "Waiting for {Lotus_miner} to write sectors into Yugabyte.", + "placeholder": null + }, + { + "id": "The sectors are in the database. The database is ready for {Curio}.", + "translation": "섹터가 데이터베이스에 있습니다. 데이터베이스가 {Curio}를 위해 준비되었습니다.", + "message": "The sectors are in the database. The database is ready for {Curio}.", + "placeholder": null + }, + { + "id": "Now shut down lotus-miner and move the systems to {Curio}.", + "translation": "이제 lotus-miner를 종료하고 시스템을 {Curio}로 이동하세요.", + "message": "Now shut down lotus-miner and move the systems to {Curio}.", + "placeholder": null + }, + { + "id": "Press return to continue", + "translation": "계속하려면 리턴을 누르세요", + "message": "Press return to continue", + "placeholder": null + }, + { + "id": "Aborting migration.", + "translation": "마이그레이션 중단.", + "message": "Aborting migration.", + "placeholder": null + }, + { + "id": "Sectors verified. {I} sector locations found.", + "translation": "섹터가 확인되었습니다. {I}개의 섹터 위치를 찾았습니다.", + "message": "Sectors verified. {I} sector locations found.", + "placeholder": null + }, + { + "id": "Press return to update {Toml} with Yugabyte info. Backup the file now.", + "translation": "{Toml}을 Yugabyte 정보로 업데이트하려면 리턴을 누르세요. 지금 파일을 백업하세요.", + "message": "Press return to update {Toml} with Yugabyte info. Backup the file now.", + "placeholder": null + }, + { + "id": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.", + "translation": "시작하려면 밀봉 파이프라인이 비어 있고 lotus-miner가 종료되었는지 확인하세요.", + "message": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.", + "placeholder": null + }, + { + "id": "Enter the path to the configuration directory used by {Lotus_miner}", + "translation": "{Lotus_miner}에서 사용하는 구성 디렉터리 경로를 입력하세요.", + "message": "Enter the path to the configuration directory used by {Lotus_miner}", + "placeholder": null + }, + { + "id": "Step Complete: {Step}", + "translation": "단계 완료: {Step}", + "message": "Step Complete: {Step}", + "placeholder": null + }, + { + "id": "Configuration 'base' was updated to include this miner's address and its wallet setup.", + "translation": "이 마이너의 주소와 지갑 설정을 포함하도록 구성 'base'가 업데이트되었습니다.", + "message": "Configuration 'base' was updated to include this miner's address and its wallet setup.", + "placeholder": null + }, + { + "id": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.", + "translation": "구성 {Base}를 {MinerAddresses0}과 비교하세요. 지갑 주소 이외의 마이너 ID 사이의 변경 사항은 필요한 실행자를 위한 새로운 최소한의 레이어여야 합니다.", + "message": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.", + "placeholder": null + }, + { + "id": "Configuration 'base' was created to include this miner's address and its wallet setup.", + "translation": "이 마이너의 주소와 지갑 설정을 포함하도록 구성 'base'가 생성되었습니다.", + "message": "Configuration 'base' was created to include this miner's address and its wallet setup.", + "placeholder": null + }, + { + "id": "Layer {LayerName} created.", + "translation": "레이어 {LayerName}가 생성되었습니다.", + "message": "Layer {LayerName} created.", + "placeholder": null + }, + { + "id": "To work with the config: \\n", + "translation": "구성을 사용하려면: \\n", + "message": "To work with the config: \\n", + "placeholder": null + }, + { + "id": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):", + "translation": "Curio를 실행하려면: 기계 또는 cgroup 격리를 사용하여 다음 명령을 사용하세요 (예제 레이어 선택과 함께):", + "message": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):", + "placeholder": null + }, + { + "id": "Try the web interface with {__layersgui} for further guided improvements.", + "translation": "더 많은 안내를 위해 {__layersgui}를 사용하여 웹 인터페이스를 시도하세요.", + "message": "Try the web interface with {__layersgui} for further guided improvements.", + "placeholder": null + }, + { + "id": "Error connecting to lotus node: {Error} {Error_1}", + "translation": "lotus 노드에 연결하는 중 오류 발생: {Error} {Error_1}", + "message": "Error connecting to lotus node: {Error} {Error_1}", + "placeholder": null + }, + { + "id": "could not get API info for FullNode: {Err}", + "translation": "FullNode의 API 정보를 가져올 수 없습니다: {Err}", + "message": "could not get API info for FullNode: {Err}", + "placeholder": null + }, + { + "id": "Error getting token: {Error}", + "translation": "토큰을 가져오는 중 오류 발생: {Error}", + "message": "Error getting token: {Error}", + "placeholder": null + }, + { + "id": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}", + "translation": "Filecoin {Slack} 채널: {Fil_curio_help} 및 {Fil_curio_dev}", + "message": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}", + "placeholder": null + }, + { + "id": "Start multiple Curio instances with the '{Post}' layer to redundancy.", + "translation": "'{Post}' 레이어로 여러 Curio 인스턴스를 시작하여 중복성을 확보하세요.", + "message": "Start multiple Curio instances with the '{Post}' layer to redundancy.", + "placeholder": null + }, + { + "id": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.", + "translation": "한 개의 데이터베이스는 여러 광부 ID를 제공할 수 있습니다: 각 lotus-miner에 대해 마이그레이션을 실행하세요.", + "message": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.", + "placeholder": null + }, + { + "id": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.", + "translation": "데이터베이스 자격 증명이 {Toml}에 입력되었으므로 지금 {Lotus_miner}을 시작하거나 다시 시작하세요.", + "message": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.", + "placeholder": null + }, + { + "id": "Error interpreting miner ID: {Error}: ID: {String}", + "translation": "광부 ID를 해석하는 중 오류 발생: {Error}: ID: {String}", + "message": "Error interpreting miner ID: {Error}: ID: {String}", + "placeholder": null + }, + { + "id": "Enabling Sector Indexing in the database.", + "translation": "데이터베이스에서 Sector Indexing을 활성화합니다.", + "message": "Enabling Sector Indexing in the database.", + "placeholder": null + }, + { + "id": "Error expanding path: {Error}", + "translation": "경로를 확장하는 중 오류 발생: {Error}", + "message": "Error expanding path: {Error}", + "placeholder": null + }, + { + "id": "Could not create repo from directory: {Error}. Aborting migration", + "translation": "디렉토리에서 저장소를 생성할 수 없습니다: {Error}. 마이그레이션을 중단합니다.", + "message": "Could not create repo from directory: {Error}. Aborting migration", + "placeholder": null + }, + { + "id": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration", + "translation": "광부 저장소를 잠금 해제할 수 없습니다. 귀하의 광부를 중지해야 합니다: {Error}\n 마이그레이션을 중단합니다.", + "message": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration", + "placeholder": null + }, + { + "id": "To work with the config:", + "translation": "구성 파일을 사용하려면:", + "message": "To work with the config:", + "placeholder": null + }, + { + "id": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "translation": "이 대화형 도구는 새로운 채굴자 액터를 생성하고 그에 대한 기본 구성 레이어를 생성합니다.", + "message": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "placeholder": null + }, + { + "id": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster {Arg_1}' to finish the configuration.", + "translation": "이 프로세스는 부분적으로 idempotent합니다. 새로운 채굴자 액터가 생성되었고 후속 단계가 실패하면 사용자는 구성을 완료하기 위해 'curio config new-cluster {Arg_1}'를 실행해야 합니다.", + "message": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster {Arg_1}' to finish the configuration.", + "placeholder": null + }, + { + "id": "Choose if you with to create a new miner or migrate from existing Lotus-Miner", + "translation": "새 채굴자를 생성할지 기존의 Lotus-Miner에서 이전할지 선택하세요.", + "message": "Choose if you with to create a new miner or migrate from existing Lotus-Miner", + "placeholder": null + }, + { + "id": "Migrate from existing Lotus-Miner", + "translation": "기존의 Lotus-Miner에서 이전하기", + "message": "Migrate from existing Lotus-Miner", + "placeholder": null + }, + { + "id": "Create a new miner", + "translation": "새로운 채굴자 생성", + "message": "Create a new miner", + "placeholder": null + }, + { + "id": "New Miner initialization complete.", + "translation": "새로운 채굴자 초기화 완료.", + "message": "New Miner initialization complete.", + "placeholder": null + }, + { + "id": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "translation": "lotus-miner config.toml을 Curio의 데이터베이스 구성으로 이전 중입니다.", + "message": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "placeholder": null + }, + { + "id": "Error getting API: {Error}", + "translation": "API 가져오기 오류: {Error}", + "message": "Error getting API: {Error}", + "placeholder": null + }, + { + "id": "The Curio team wants to improve the software you use. Tell the team you're using {Curio}.", + "translation": "Curio 팀은 당신이 사용하는 소프트웨어를 개선하고자 합니다. 팀에게 {Curio}를 사용 중이라고 알려주세요.", + "message": "The Curio team wants to improve the software you use. Tell the team you're using {Curio}.", + "placeholder": null + }, + { + "id": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "translation": "개별 데이터: 채굴자 ID, Curio 버전, 체인 ({Mainnet} 또는 {Calibration}). 서명됨.", + "message": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "placeholder": null + }, + { + "id": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "translation": "집계-익명: 버전, 체인, 및 채굴자 파워 (버킷).", + "message": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "placeholder": null + }, + { + "id": "Hint: I am someone running Curio on whichever chain.", + "translation": "힌트: 나는 어떤 체인에서든 Curio를 실행 중인 사람입니다.", + "message": "Hint: I am someone running Curio on whichever chain.", + "placeholder": null + }, + { + "id": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "translation": "{Toml}을 Yugabyte 정보로 업데이트하려면 리턴 키를 누르세요. 변경 사항을 적용하기 전에 해당 폴더에 백업 파일이 작성됩니다.", + "message": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "placeholder": null + }, + { + "id": "Error creating backup file: {Error}", + "translation": "백업 파일 생성 오류: {Error}", + "message": "Error creating backup file: {Error}", + "placeholder": null + }, + { + "id": "Error reading config.toml: {Error}", + "translation": "config.toml 읽기 오류: {Error}", + "message": "Error reading config.toml: {Error}", + "placeholder": null + }, + { + "id": "Error writing backup file: {Error}", + "translation": "백업 파일 쓰기 오류: {Error}", + "message": "Error writing backup file: {Error}", + "placeholder": null + }, + { + "id": "Error closing backup file: {Error}", + "translation": "백업 파일 닫기 오류: {Error}", + "message": "Error closing backup file: {Error}", + "placeholder": null + }, + { + "id": "Initializing a new miner actor.", + "translation": "새 채굴자 액터 초기화 중.", + "message": "Initializing a new miner actor.", + "placeholder": null + }, + { + "id": "Enter the info to create a new miner", + "translation": "새 채굴자를 생성하기 위한 정보 입력", + "message": "Enter the info to create a new miner", + "placeholder": null + }, + { + "id": "Owner Address: {String}", + "translation": "소유자 주소: {String}", + "message": "Owner Address: {String}", + "placeholder": null + }, + { + "id": "Worker Address: {String}", + "translation": "작업자 주소: {String}", + "message": "Worker Address: {String}", + "placeholder": null + }, + { + "id": "Sender Address: {String}", + "translation": "송신자 주소: {String}", + "message": "Sender Address: {String}", + "placeholder": null + }, + { + "id": "Sector Size: {Ssize}", + "translation": "섹터 크기: {Ssize}", + "message": "Sector Size: {Ssize}", + "placeholder": null + }, + { + "id": "Confidence: {Confidence}", + "translation": "신뢰도: {Confidence}", + "message": "Confidence: {Confidence}", + "placeholder": null + }, + { + "id": "Continue to verify the addresses and create a new miner actor.", + "translation": "주소를 확인하고 새 채굴자 액터를 생성하려면 계속 진행하세요.", + "message": "Continue to verify the addresses and create a new miner actor.", + "placeholder": null + }, + { + "id": "Miner creation error occurred: {Error}", + "translation": "채굴자 생성 오류 발생: {Error}", + "message": "Miner creation error occurred: {Error}", + "placeholder": null + }, + { + "id": "Enter the owner address", + "translation": "소유자 주소 입력", + "message": "Enter the owner address", + "placeholder": null + }, + { + "id": "No address provided", + "translation": "주소가 제공되지 않았습니다", + "message": "No address provided", + "placeholder": null + }, + { + "id": "Failed to parse the address: {Error}", + "translation": "주소 구문 분석 실패: {Error}", + "message": "Failed to parse the address: {Error}", + "placeholder": null + }, + { + "id": "Enter {Stringworker_senderi_1} address", + "translation": "{Stringworker_senderi_1} 주소 입력", + "message": "Enter {Stringworker_senderi_1} address", + "placeholder": null + }, + { + "id": "Enter the sector size", + "translation": "섹터 크기 입력", + "message": "Enter the sector size", + "placeholder": null + }, + { + "id": "Failed to parse sector size: {Error}", + "translation": "섹터 크기 구문 분석 실패: {Error}", + "message": "Failed to parse sector size: {Error}", + "placeholder": null + }, + { + "id": "Enter the confidence", + "translation": "신뢰도 입력", + "message": "Enter the confidence", + "placeholder": null + }, + { + "id": "Failed to parse confidence: {Error}", + "translation": "신뢰도 구문 분석 실패: {Error}", + "message": "Failed to parse confidence: {Error}", + "placeholder": null + }, + { + "id": "Failed to create the miner actor: {Error}", + "translation": "채굴자 액터 생성 실패: {Error}", + "message": "Failed to create the miner actor: {Error}", + "placeholder": null + }, + { + "id": "Miner {String} created successfully", + "translation": "{String} 채굴자가 성공적으로 생성되었습니다", + "message": "Miner {String} created successfully", + "placeholder": null + }, + { + "id": "Cannot reach the DB: {Error}", + "translation": "데이터베이스에 연결할 수 없습니다: {Error}", + "message": "Cannot reach the DB: {Error}", + "placeholder": null + }, + { + "id": "Error connecting to full node API: {Error}", + "translation": "풀 노드 API에 연결하는 중 오류 발생: {Error}", + "message": "Error connecting to full node API: {Error}", + "placeholder": null + }, + { + "id": "Pre-initialization steps complete", + "translation": "사전 초기화 단계 완료", + "message": "Pre-initialization steps complete", + "placeholder": null + }, + { + "id": "Failed to random bytes for secret: {Error}", + "translation": "비밀을 위한 랜덤 바이트 생성 실패: {Error}", + "message": "Failed to random bytes for secret: {Error}", + "placeholder": null + }, + { + "id": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "translation": "마이너 생성은 idempotent하지 않으므로 가이드 설정을 다시 실행하지 마십시오. 구성을 완료하려면 'curio config new-cluster {String}'를 실행해야 합니다.", + "message": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "placeholder": null + }, + { + "id": "Failed to verify the auth token from daemon node: {Error}", + "translation": "데몬 노드로부터 인증 토큰을 확인하는 중 오류 발생: {Error}", + "message": "Failed to verify the auth token from daemon node: {Error}", + "placeholder": null + }, + { + "id": "Failed to encode the config: {Error}", + "translation": "구성을 인코딩하는 중 오류 발생: {Error}", + "message": "Failed to encode the config: {Error}", + "placeholder": null + }, + { + "id": "Failed to generate default config: {Error}", + "translation": "기본 구성 생성 실패: {Error}", + "message": "Failed to generate default config: {Error}", + "placeholder": null + }, + { + "id": "Failed to inset 'base' config layer in database: {Error}", + "translation": "데이터베이스에 'base' 구성 레이어 삽입 실패: {Error}", + "message": "Failed to inset 'base' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "Failed to inset '{String}' config layer in database: {Error}", + "translation": "데이터베이스에 '{String}' 구성 레이어 삽입 실패: {Error}", + "message": "Failed to inset '{String}' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "New Curio configuration layer '{String}' created", + "translation": "새로운 Curio 구성 레이어 '{String}'가 생성되었습니다", + "message": "New Curio configuration layer '{String}' created", + "placeholder": null + }, + { + "id": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "translation": "Curio 팀은 당신이 사용하는 소프트웨어를 개선하고자 합니다. 팀에게 `{Curio}`를 사용 중이라고 알려주세요.", + "message": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "placeholder": null + }, + { + "id": "Confidence epochs: {Confidence}", + "translation": "신뢰 에포크: {Confidence}", + "message": "Confidence epochs: {Confidence}", + "placeholder": null + }, + { + "id": "Failed to generate random bytes for secret: {Error}", + "translation": "비밀번호를 위한 랜덤 바이트 생성에 실패했습니다: {Error}", + "message": "Failed to generate random bytes for secret: {Error}", + "placeholder": null + }, + { + "id": "Failed to get API info for FullNode: {Err}", + "translation": "FullNode에 대한 API 정보를 가져오는 데 실패했습니다: {Err}", + "message": "Failed to get API info for FullNode: {Err}", + "placeholder": null + }, + { + "id": "Failed to insert 'base' config layer in database: {Error}", + "translation": "데이터베이스에 'base' 구성 레이어를 삽입하는 데 실패했습니다: {Error}", + "message": "Failed to insert 'base' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "Failed to insert '{String}' config layer in database: {Error}", + "translation": "데이터베이스에 '{String}' 구성 레이어를 삽입하는 데 실패했습니다: {Error}", + "message": "Failed to insert '{String}' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "translation": "이 프로세스는 부분적으로 항등원적입니다. 새로운 채굴자 액터가 생성되었고 후속 단계가 실패하는 경우 사용자는 구성을 완료하기 위해 'curio config new-cluster \u003c 채굴자 ID \u003e'를 실행해야 합니다.", + "message": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "placeholder": null + }, + { + "id": "Confidence epochs", + "translation": "신뢰 에포크", + "message": "Confidence epochs", + "placeholder": null + }, + { + "id": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "translation": "신뢰성 향상을 위한 중복성 사용: 적어도 post 레이어를 사용하여 여러 대의 기계를 시작하십시오: 'curio run --layers=post'", + "message": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "placeholder": null + }, + { + "id": "I want to:", + "translation": "나는 원한다:", + "message": "I want to:", + "placeholder": null + }, + { + "id": "Configuration 'base' was updated to include this miner's address", + "translation": "이 마이너 주소를 포함한 구성 'base'가 업데이트되었습니다.", + "message": "Configuration 'base' was updated to include this miner's address", + "placeholder": null + }, + { + "id": "Cannot load base config: {Error}", + "translation": "기본 구성을 불러올 수 없습니다: {Error}", + "message": "Cannot load base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to load base config: {Error}", + "translation": "기본 구성을 로드하는 데 실패했습니다: {Error}", + "message": "Failed to load base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to regenerate base config: {Error}", + "translation": "기본 구성을 재생성하는 데 실패했습니다: {Error}", + "message": "Failed to regenerate base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to load base config from database: {Error}", + "translation": "데이터베이스에서 기본 구성을 로드하는 데 실패했습니다: {Error}", + "message": "Failed to load base config from database: {Error}", + "placeholder": null + }, + { + "id": "Failed to parse base config: {Error}", + "translation": "기본 구성을 구문 분석하는 데 실패했습니다: {Error}", + "message": "Failed to parse base config: {Error}", + "placeholder": null + }, + { + "id": "Try the web interface with {Rendercurio_run___layersgui} for further guided improvements.", + "translation": "{Rendercurio_run___layersgui}를 사용하여 웹 인터페이스를 시도하고 더 나은 안내된 개선을 진행하세요.", + "message": "Try the web interface with {Rendercurio_run___layersgui} for further guided improvements.", + "placeholder": null + }, + { + "id": "Now shut down lotus-miner and lotus-worker and use run {Rendercurio_run} instead.", + "translation": "이제 lotus-miner와 lotus-worker를 종료하고 {Rendercurio_run}을 실행하세요.", + "message": "Now shut down lotus-miner and lotus-worker and use run {Rendercurio_run} instead.", + "placeholder": null + }, + { + "id": "Configuration 'base' was updated to include this miner's address ({MinerAddress}) and its wallet setup.", + "translation": "기본 설정 'base'가 이 마이너의 주소({MinerAddress}) 및 지갑 설정을 포함하도록 업데이트되었습니다.", + "message": "Configuration 'base' was updated to include this miner's address ({MinerAddress}) and its wallet setup.", + "placeholder": null + }, + { + "id": "Configuration 'base' was created to resemble this lotus-miner's config.toml .", + "translation": "'base' 설정이 이 lotus-miner의 config.toml과 유사하게 만들어졌습니다.", + "message": "Configuration 'base' was created to resemble this lotus-miner's config.toml .", + "placeholder": null + } + ] +} \ No newline at end of file diff --git a/cmd/curio/internal/translations/locales/ko/out.gotext.json b/cmd/curio/internal/translations/locales/ko/out.gotext.json new file mode 100644 index 00000000000..8e0014cd46d --- /dev/null +++ b/cmd/curio/internal/translations/locales/ko/out.gotext.json @@ -0,0 +1,4 @@ +{ + "language": "ko", + "messages": [] + } diff --git a/cmd/curio/internal/translations/locales/zh/messages.gotext.json b/cmd/curio/internal/translations/locales/zh/messages.gotext.json new file mode 100644 index 00000000000..1e2608fa8d7 --- /dev/null +++ b/cmd/curio/internal/translations/locales/zh/messages.gotext.json @@ -0,0 +1,1076 @@ +{ + "language": "zh", + "messages": [ + { + "id": "This interactive tool will walk you through migration of Curio.\nPress Ctrl+C to exit at any time.", + "message": "This interactive tool will walk you through migration of Curio.\nPress Ctrl+C to exit at any time.", + "translation": "此互动工具将引导您完成Curio的迁移。\n随时按Ctrl+C退出。" + }, + { + "id": "This tool confirms each action it does.", + "message": "This tool confirms each action it does.", + "translation": "此工具确认其执行的每个操作。" + }, + { + "id": "Ctrl+C pressed in Terminal", + "message": "Ctrl+C pressed in Terminal", + "translation": "在终端中按下Ctrl+C" + }, + { + "id": "Verifying Sectors exist in Yugabyte.", + "message": "Verifying Sectors exist in Yugabyte.", + "translation": "正在验证Yugabyte中的扇区是否存在。" + }, + { + "id": "Error verifying sectors: {Error}", + "message": "Error verifying sectors: {Error}", + "translation": "验证扇区时出错:{Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Sectors verified. {I} sectors found.", + "message": "Sectors verified. {I} sectors found.", + "translation": "已验证扇区。找到了{I}个扇区。", + "placeholders": [ + { + "id": "I", + "string": "%[1]d", + "type": "[]int", + "underlyingType": "[]int", + "argNum": 1, + "expr": "i" + } + ] + }, + { + "id": "Never remove the database info from the config.toml for lotus-miner as it avoids double PoSt.", + "message": "Never remove the database info from the config.toml for lotus-miner as it avoids double PoSt.", + "translation": "从config.toml中永远不要删除lotus-miner的数据库信息,因为它避免了双PoSt。" + }, + { + "id": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)", + "message": "Enter the info to connect to your Yugabyte database installation (https://download.yugabyte.com/)", + "translation": "输入连接到您的Yugabyte数据库安装的信息(https://download.yugabyte.com/)" + }, + { + "id": "Host: {Hosts_}", + "message": "Host: {Hosts_}", + "translation": "主机:{Hosts_}", + "placeholders": [ + { + "id": "Hosts_", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "strings.Join(harmonycfg.Hosts, \",\")" + } + ] + }, + { + "id": "Port: {Port}", + "message": "Port: {Port}", + "translation": "端口:{Port}", + "placeholders": [ + { + "id": "Port", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonycfg.Port" + } + ] + }, + { + "id": "Username: {Username}", + "message": "Username: {Username}", + "translation": "用户名:{Username}", + "placeholders": [ + { + "id": "Username", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonycfg.Username" + } + ] + }, + { + "id": "Password: {Password}", + "message": "Password: {Password}", + "translation": "密码:{Password}", + "placeholders": [ + { + "id": "Password", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonycfg.Password" + } + ] + }, + { + "id": "Database: {Database}", + "message": "Database: {Database}", + "translation": "数据库:{Database}", + "placeholders": [ + { + "id": "Database", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "harmonycfg.Database" + } + ] + }, + { + "id": "Continue to connect and update schema.", + "message": "Continue to connect and update schema.", + "translation": "继续连接和更新架构。" + }, + { + "id": "Database config error occurred, abandoning migration: {Error}", + "message": "Database config error occurred, abandoning migration: {Error}", + "translation": "发生数据库配置错误,放弃迁移:{Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Enter the Yugabyte database host(s)", + "message": "Enter the Yugabyte database host(s)", + "translation": "输入Yugabyte数据库主机(S)" + }, + { + "id": "No host provided", + "message": "No host provided", + "translation": "未提供主机" + }, + { + "id": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", + "message": "Enter the Yugabyte database {Stringport_username_password_databasei_1}", + "translation": "输入Yugabyte数据库 {Stringport_username_password_databasei_1}", + "placeholders": [ + { + "id": "Stringport_username_password_databasei_1", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "[]string{\"port\", \"username\", \"password\", \"database\"}[i-1]" + } + ] + }, + { + "id": "No value provided", + "message": "No value provided", + "translation": "未提供值" + }, + { + "id": "Error connecting to Yugabyte database: {Error}", + "message": "Error connecting to Yugabyte database: {Error}", + "translation": "连接到Yugabyte数据库时出错:{Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Connected to Yugabyte. Schema is current.", + "message": "Connected to Yugabyte. Schema is current.", + "translation": "已连接到Yugabyte。模式是当前的。" + }, + { + "id": "Error encoding config.toml: {Error}", + "message": "Error encoding config.toml: {Error}", + "translation": "编码config.toml时出错:{Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Error reading filemode of config.toml: {Error}", + "message": "Error reading filemode of config.toml: {Error}", + "translation": "读取config.toml文件模式时出错:{Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Error writing config.toml: {Error}", + "message": "Error writing config.toml: {Error}", + "translation": "写入config.toml时出错:{Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Restart Lotus Miner.", + "message": "Restart Lotus Miner.", + "translation": "重新启动Lotus Miner。" + }, + { + "id": "Connected to Yugabyte", + "message": "Connected to Yugabyte", + "translation": "已连接到Yugabyte" + }, + { + "id": "Select the location of your lotus-miner config directory?", + "message": "Select the location of your lotus-miner config directory?", + "translation": "选择您的lotus-miner配置目录的位置?" + }, + { + "id": "Other", + "message": "Other", + "translation": "其他" + }, + { + "id": "Enter the path to the configuration directory used by lotus-miner", + "message": "Enter the path to the configuration directory used by lotus-miner", + "translation": "输入lotus-miner使用的配置目录的路径" + }, + { + "id": "No path provided, abandoning migration", + "message": "No path provided, abandoning migration", + "translation": "未提供路径,放弃迁移" + }, + { + "id": "Cannot read the config.toml file in the provided directory, Error: {Error}", + "message": "Cannot read the config.toml file in the provided directory, Error: {Error}", + "translation": "无法读取提供的目录中的config.toml文件,错误:{Error}", + "placeholders": [ + { + "id": "Error", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "err.Error()" + } + ] + }, + { + "id": "Read Miner Config", + "message": "Read Miner Config", + "translation": "读取矿工配置" + }, + { + "id": "Completed Step: {Step}", + "message": "Completed Step: {Step}", + "translation": "完成步骤:{Step}", + "placeholders": [ + { + "id": "Step", + "string": "%[1]s", + "type": "string", + "underlyingType": "string", + "argNum": 1, + "expr": "step" + } + ] + }, + { + "id": "This interactive tool migrates lotus-miner to Curio in 5 minutes.", + "translation": "这个交互式工具可以在5分钟内将lotus-miner迁移到Curio。", + "message": "This interactive tool migrates lotus-miner to Curio in 5 minutes.", + "placeholder": null + }, + { + "id": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.", + "translation": "每一步都需要您的确认,并且可以撤销。随时按Ctrl+C退出。", + "message": "Each step needs your confirmation and can be reversed. Press Ctrl+C to exit at any time.", + "placeholder": null + }, + { + "id": "Use the arrow keys to navigate: ↓ ↑ → ←", + "translation": "使用箭头键进行导航:↓ ↑ → ←", + "message": "Use the arrow keys to navigate: ↓ ↑ → ←", + "placeholder": null + }, + { + "id": "Lotus-Miner to Curio Migration.", + "translation": "Lotus-Miner到Curio迁移。", + "message": "Lotus-Miner to Curio Migration.", + "placeholder": null + }, + { + "id": "Try the web interface with for further guided improvements.", + "translation": "尝试使用网页界面进行进一步的指导改进。", + "message": "Try the web interface with for further guided improvements.", + "placeholder": null + }, + { + "id": "You can now migrate your market node ({Boost}), if applicable.", + "translation": "如果适用,您现在可以迁移您的市场节点({Boost})。", + "message": "You can now migrate your market node ({Boost}), if applicable.", + "placeholder": null + }, + { + "id": "Migrating config.toml to database.", + "translation": "正在将config.toml迁移到数据库。", + "message": "Migrating config.toml to database.", + "placeholder": null + }, + { + "id": "Error reading from database: {Error}. Aborting Migration.", + "translation": "读取数据库时出错:{Error}。正在中止迁移。", + "message": "Error reading from database: {Error}. Aborting Migration.", + "placeholder": null + }, + { + "id": "cannot read API: {Error}. Aborting Migration", + "translation": "无法读取API:{Error}。正在中止迁移", + "message": "cannot read API: {Error}. Aborting Migration", + "placeholder": null + }, + { + "id": "Error saving config to layer: {Error}. Aborting Migration", + "translation": "保存配置到层时出错:{Error}。正在中止迁移", + "message": "Error saving config to layer: {Error}. Aborting Migration", + "placeholder": null + }, + { + "id": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.", + "translation": "Protocol Labs希望改进您使用的软件。告诉团队您正在使用Curio。", + "message": "Protocol Labs wants to improve the software you use. Tell the team you're using Curio.", + "placeholder": null + }, + { + "id": "Select what you want to share with the Curio team.", + "translation": "选择您想与Curio团队分享的内容。", + "message": "Select what you want to share with the Curio team.", + "placeholder": null + }, + { + "id": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.", + "translation": "个人数据:矿工ID、Curio版本、网络({Mainnet}或{Testnet})。已签名。", + "message": "Individual Data: Miner ID, Curio version, net ({Mainnet} or {Testnet}). Signed.", + "placeholder": null + }, + { + "id": "Aggregate-Anonymous: version, net, and Miner power (bucketed).", + "translation": "聚合-匿名:版本、网络和矿工功率(分桶)。", + "message": "Aggregate-Anonymous: version, net, and Miner power (bucketed).", + "placeholder": null + }, + { + "id": "Hint: I am someone running Curio on net.", + "translation": "提示:我是在网络上运行Curio的人。", + "message": "Hint: I am someone running Curio on net.", + "placeholder": null + }, + { + "id": "Nothing.", + "translation": "没有。", + "message": "Nothing.", + "placeholder": null + }, + { + "id": "Aborting remaining steps.", + "translation": "中止剩余步骤。", + "message": "Aborting remaining steps.", + "placeholder": null + }, + { + "id": "Error connecting to lotus node: {Error}", + "translation": "连接到莲花节点时出错:{Error}", + "message": "Error connecting to lotus node: {Error}", + "placeholder": null + }, + { + "id": "Error getting miner power: {Error}", + "translation": "获取矿工功率时出错:{Error}", + "message": "Error getting miner power: {Error}", + "placeholder": null + }, + { + "id": "Error marshalling message: {Error}", + "translation": "整理消息时出错:{Error}", + "message": "Error marshalling message: {Error}", + "placeholder": null + }, + { + "id": "Error getting miner info: {Error}", + "translation": "获取矿工信息时出错:{Error}", + "message": "Error getting miner info: {Error}", + "placeholder": null + }, + { + "id": "Error signing message: {Error}", + "translation": "签署消息时出错:{Error}", + "message": "Error signing message: {Error}", + "placeholder": null + }, + { + "id": "Error sending message: {Error}", + "translation": "发送消息时出错:{Error}", + "message": "Error sending message: {Error}", + "placeholder": null + }, + { + "id": "Error sending message: Status {Status}, Message:", + "translation": "发送消息时出错:状态{Status},消息:", + "message": "Error sending message: Status {Status}, Message:", + "placeholder": null + }, + { + "id": "Message sent.", + "translation": "消息已发送。", + "message": "Message sent.", + "placeholder": null + }, + { + "id": "Documentation:", + "translation": "文档:", + "message": "Documentation:", + "placeholder": null + }, + { + "id": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.", + "translation": "'{Base}'层存储通用配置。所有Curio实例都可以在其{__layers}参数中包含它。", + "message": "The '{Base}' layer stores common configuration. All curio instances can include it in their {__layers} argument.", + "placeholder": null + }, + { + "id": "You can add other layers for per-machine configuration changes.", + "translation": "您可以添加其他层进行每台机器的配置更改。", + "message": "You can add other layers for per-machine configuration changes.", + "placeholder": null + }, + { + "id": "Join {Fil_curio_help} in Filecoin {Slack} for help.", + "translation": "加入Filecoin {Slack}中的{Fil_curio_help}寻求帮助。", + "message": "Join {Fil_curio_help} in Filecoin {Slack} for help.", + "placeholder": null + }, + { + "id": "Join {Fil_curio_dev} in Filecoin {Slack} to follow development and feedback!", + "translation": "加入Filecoin {Slack}中的{Fil_curio_dev}来跟踪开发和反馈!", + "message": "Join {Fil_curio_dev} in Filecoin {Slack} to follow development and feedback!", + "placeholder": null + }, + { + "id": "Want PoST redundancy? Run many Curio instances with the '{Post}' layer.", + "translation": "需要PoST冗余?使用'{Post}'层运行多个Curio实例。", + "message": "Want PoST redundancy? Run many Curio instances with the '{Post}' layer.", + "placeholder": null + }, + { + "id": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.", + "translation": "将您的浏览器指向您的网络GUI,以使用{Boost}和高级功能完成设置。", + "message": "Point your browser to your web GUI to complete setup with {Boost} and advanced featues.", + "placeholder": null + }, + { + "id": "For SPs with multiple Miner IDs, run 1 migration per lotus-miner all to the same 1 database. The cluster will serve all Miner IDs.", + "translation": "对于具有多个矿工ID的SP,针对所有lotus-miner运行1次迁移到同一个数据库。集群将服务所有矿工ID。", + "message": "For SPs with multiple Miner IDs, run 1 migration per lotus-miner all to the same 1 database. The cluster will serve all Miner IDs.", + "placeholder": null + }, + { + "id": "Please start {Lotus_miner} now that database credentials are in {Toml}.", + "translation": "现在数据库凭证在{Toml}中,请启动{Lotus_miner}。", + "message": "Please start {Lotus_miner} now that database credentials are in {Toml}.", + "placeholder": null + }, + { + "id": "Waiting for {Lotus_miner} to write sectors into Yugabyte.", + "translation": "等待{Lotus_miner}将扇区写入Yugabyte。", + "message": "Waiting for {Lotus_miner} to write sectors into Yugabyte.", + "placeholder": null + }, + { + "id": "The sectors are in the database. The database is ready for {Curio}.", + "translation": "扇区在数据库中。数据库已准备好用于{Curio}。", + "message": "The sectors are in the database. The database is ready for {Curio}.", + "placeholder": null + }, + { + "id": "Now shut down lotus-miner and move the systems to {Curio}.", + "translation": "现在关闭lotus-miner并将系统移至{Curio}。", + "message": "Now shut down lotus-miner and move the systems to {Curio}.", + "placeholder": null + }, + { + "id": "Press return to continue", + "translation": "按回车继续", + "message": "Press return to continue", + "placeholder": null + }, + { + "id": "Aborting migration.", + "translation": "中止迁移。", + "message": "Aborting migration.", + "placeholder": null + }, + { + "id": "Sectors verified. {I} sector locations found.", + "translation": "扇区已验证。发现了{I}个扇区位置。", + "message": "Sectors verified. {I} sector locations found.", + "placeholder": null + }, + { + "id": "Press return to update {Toml} with Yugabyte info. Backup the file now.", + "translation": "按回车更新{Toml}以获取Yugabyte信息。现在备份文件。", + "message": "Press return to update {Toml} with Yugabyte info. Backup the file now.", + "placeholder": null + }, + { + "id": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.", + "translation": "开始之前,请确保您的密封管道已排空并关闭lotus-miner。", + "message": "To start, ensure your sealing pipeline is drained and shut-down lotus-miner.", + "placeholder": null + }, + { + "id": "Enter the path to the configuration directory used by {Lotus_miner}", + "translation": "输入{Lotus_miner}使用的配置目录的路径", + "message": "Enter the path to the configuration directory used by {Lotus_miner}", + "placeholder": null + }, + { + "id": "Step Complete: {Step}", + "translation": "步骤完成:{Step}", + "message": "Step Complete: {Step}", + "placeholder": null + }, + { + "id": "Configuration 'base' was updated to include this miner's address and its wallet setup.", + "translation": "配置'base'已更新,包含了这个矿工的地址和其钱包设置。", + "message": "Configuration 'base' was updated to include this miner's address and its wallet setup.", + "placeholder": null + }, + { + "id": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.", + "translation": "比较配置{Base}和{MinerAddresses0}。矿工ID之间除了钱包地址的变化应该是需要的运行者的一个新的、最小的层。", + "message": "Compare the configurations {Base} to {MinerAddresses0}. Changes between the miner IDs other than wallet addreses should be a new, minimal layer for runners that need it.", + "placeholder": null + }, + { + "id": "Configuration 'base' was created to include this miner's address and its wallet setup.", + "translation": "配置'base'已创建,包括了这个矿工的地址和其钱包设置。", + "message": "Configuration 'base' was created to include this miner's address and its wallet setup.", + "placeholder": null + }, + { + "id": "Layer {LayerName} created.", + "translation": "层{LayerName}已创建。", + "message": "Layer {LayerName} created.", + "placeholder": null + }, + { + "id": "To work with the config: \\n", + "translation": "要使用配置:\\n", + "message": "To work with the config: \\n", + "placeholder": null + }, + { + "id": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):", + "translation": "运行Curio:使用机器或cgroup隔离,使用命令(附带示例层选择):", + "message": "To run Curio: With machine or cgroup isolation, use the command (with example layer selection):", + "placeholder": null + }, + { + "id": "Try the web interface with {__layersgui} for further guided improvements.", + "translation": "尝试使用{__layersgui}的Web界面进行进一步引导式改进。", + "message": "Try the web interface with {__layersgui} for further guided improvements.", + "placeholder": null + }, + { + "id": "Error connecting to lotus node: {Error} {Error_1}", + "translation": "连接到lotus节点时出错:{Error} {Error_1}", + "message": "Error connecting to lotus node: {Error} {Error_1}", + "placeholder": null + }, + { + "id": "could not get API info for FullNode: {Err}", + "translation": "无法获取FullNode的API信息:{Err}", + "message": "could not get API info for FullNode: {Err}", + "placeholder": null + }, + { + "id": "Error getting token: {Error}", + "translation": "获取令牌时出错:{Error}", + "message": "Error getting token: {Error}", + "placeholder": null + }, + { + "id": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}", + "translation": "Filecoin {Slack} 频道:{Fil_curio_help} 和 {Fil_curio_dev}", + "message": "Filecoin {Slack} channels: {Fil_curio_help} and {Fil_curio_dev}", + "placeholder": null + }, + { + "id": "Start multiple Curio instances with the '{Post}' layer to redundancy.", + "translation": "使用'{Post}'层启动多个Curio实例以实现冗余。", + "message": "Start multiple Curio instances with the '{Post}' layer to redundancy.", + "placeholder": null + }, + { + "id": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.", + "translation": "一个数据库可以服务多个矿工ID:为每个lotus-miner运行迁移。", + "message": "One database can serve multiple miner IDs: Run a migration for each lotus-miner.", + "placeholder": null + }, + { + "id": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.", + "translation": "请立即启动(或重新启动){Lotus_miner},因为数据库凭据已在{Toml}中。", + "message": "Please start (or restart) {Lotus_miner} now that database credentials are in {Toml}.", + "placeholder": null + }, + { + "id": "Error interpreting miner ID: {Error}: ID: {String}", + "translation": "解释矿工ID时出错:{Error}:ID:{String}", + "message": "Error interpreting miner ID: {Error}: ID: {String}", + "placeholder": null + }, + { + "id": "Enabling Sector Indexing in the database.", + "translation": "在数据库中启用扇区索引。", + "message": "Enabling Sector Indexing in the database.", + "placeholder": null + }, + { + "id": "Error expanding path: {Error}", + "translation": "扩展路径时出错:{Error}", + "message": "Error expanding path: {Error}", + "placeholder": null + }, + { + "id": "Could not create repo from directory: {Error}. Aborting migration", + "translation": "无法从目录创建repo:{Error}。 中止迁移", + "message": "Could not create repo from directory: {Error}. Aborting migration", + "placeholder": null + }, + { + "id": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration", + "translation": "无法锁定矿工repo。 您的矿工必须停止:{Error}\n 中止迁移", + "message": "Could not lock miner repo. Your miner must be stopped: {Error}\n Aborting migration", + "placeholder": null + }, + { + "id": "To work with the config:", + "translation": "要使用配置:", + "message": "To work with the config:", + "placeholder": null + }, + { + "id": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "translation": "此交互式工具将创建一个新的矿工角色,并为其创建基本配置层。", + "message": "This interactive tool creates a new miner actor and creates the basic configuration layer for it.", + "placeholder": null + }, + { + "id": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster {Arg_1}' to finish the configuration.", + "translation": "此过程在某种程度上是幂等的。一旦创建了新的矿工角色,并且后续步骤失败,用户需要运行'curio config new-cluster {Arg_1}'来完成配置。", + "message": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster {Arg_1}' to finish the configuration.", + "placeholder": null + }, + { + "id": "Choose if you with to create a new miner or migrate from existing Lotus-Miner", + "translation": "选择您是否要创建新矿工或从现有的 Lotus-Miner 迁移", + "message": "Choose if you with to create a new miner or migrate from existing Lotus-Miner", + "placeholder": null + }, + { + "id": "Migrate from existing Lotus-Miner", + "translation": "从现有的 Lotus-Miner 迁移", + "message": "Migrate from existing Lotus-Miner", + "placeholder": null + }, + { + "id": "Create a new miner", + "translation": "创建一个新的矿工", + "message": "Create a new miner", + "placeholder": null + }, + { + "id": "New Miner initialization complete.", + "translation": "新矿工初始化完成。", + "message": "New Miner initialization complete.", + "placeholder": null + }, + { + "id": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "translation": "将 lotus-miner config.toml 迁移到 Curio 的数据库配置中。", + "message": "Migrating lotus-miner config.toml to Curio in-database configuration.", + "placeholder": null + }, + { + "id": "Error getting API: {Error}", + "translation": "获取 API 时出错:{Error}", + "message": "Error getting API: {Error}", + "placeholder": null + }, + { + "id": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "translation": "Curio 团队希望改进您使用的软件。告诉团队您正在使用 `{Curio}`。", + "message": "The Curio team wants to improve the software you use. Tell the team you're using `{Curio}`.", + "placeholder": null + }, + { + "id": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "translation": "个人数据:矿工 ID,Curio 版本,链({Mainnet} 或 {Calibration})。签名。", + "message": "Individual Data: Miner ID, Curio version, chain ({Mainnet} or {Calibration}). Signed.", + "placeholder": null + }, + { + "id": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "translation": "聚合-匿名:版本,链和矿工算力(分桶)。", + "message": "Aggregate-Anonymous: version, chain, and Miner power (bucketed).", + "placeholder": null + }, + { + "id": "Hint: I am someone running Curio on whichever chain.", + "translation": "提示:我是在任何链上运行 Curio 的人。", + "message": "Hint: I am someone running Curio on whichever chain.", + "placeholder": null + }, + { + "id": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "translation": "按回车键更新 {Toml} 以包含 Yugabyte 信息。在进行更改之前,将在该文件夹中写入备份文件。", + "message": "Press return to update {Toml} with Yugabyte info. A Backup file will be written to that folder before changes are made.", + "placeholder": null + }, + { + "id": "Error creating backup file: {Error}", + "translation": "创建备份文件时出错:{Error}", + "message": "Error creating backup file: {Error}", + "placeholder": null + }, + { + "id": "Error reading config.toml: {Error}", + "translation": "读取 config.toml 时出错:{Error}", + "message": "Error reading config.toml: {Error}", + "placeholder": null + }, + { + "id": "Error writing backup file: {Error}", + "translation": "写入备份文件时出错:{Error}", + "message": "Error writing backup file: {Error}", + "placeholder": null + }, + { + "id": "Error closing backup file: {Error}", + "translation": "关闭备份文件时出错:{Error}", + "message": "Error closing backup file: {Error}", + "placeholder": null + }, + { + "id": "Initializing a new miner actor.", + "translation": "初始化新的矿工角色。", + "message": "Initializing a new miner actor.", + "placeholder": null + }, + { + "id": "Enter the info to create a new miner", + "translation": "输入创建新矿工所需的信息", + "message": "Enter the info to create a new miner", + "placeholder": null + }, + { + "id": "Owner Address: {String}", + "translation": "所有者地址:{String}", + "message": "Owner Address: {String}", + "placeholder": null + }, + { + "id": "Worker Address: {String}", + "translation": "工作地址:{String}", + "message": "Worker Address: {String}", + "placeholder": null + }, + { + "id": "Sender Address: {String}", + "translation": "发送者地址:{String}", + "message": "Sender Address: {String}", + "placeholder": null + }, + { + "id": "Sector Size: {Ssize}", + "translation": "扇区大小: {Ssize}", + "message": "Sector Size: {Ssize}", + "placeholder": null + }, + { + "id": "Confidence epochs: {Confidence}", + "translation": "置信度时期: {Confidence}", + "message": "Confidence epochs: {Confidence}", + "placeholder": null + }, + { + "id": "Continue to verify the addresses and create a new miner actor.", + "translation": "继续验证地址并创建新的矿工角色。", + "message": "Continue to verify the addresses and create a new miner actor.", + "placeholder": null + }, + { + "id": "Miner creation error occurred: {Error}", + "translation": "矿工创建错误发生: {Error}", + "message": "Miner creation error occurred: {Error}", + "placeholder": null + }, + { + "id": "Enter the owner address", + "translation": "输入所有者地址", + "message": "Enter the owner address", + "placeholder": null + }, + { + "id": "No address provided", + "translation": "未提供地址", + "message": "No address provided", + "placeholder": null + }, + { + "id": "Failed to parse the address: {Error}", + "translation": "解析地址失败: {Error}", + "message": "Failed to parse the address: {Error}", + "placeholder": null + }, + { + "id": "Enter {Stringworker_senderi_1} address", + "translation": "输入 {Stringworker_senderi_1} 地址", + "message": "Enter {Stringworker_senderi_1} address", + "placeholder": null + }, + { + "id": "Enter the sector size", + "translation": "输入扇区大小", + "message": "Enter the sector size", + "placeholder": null + }, + { + "id": "Failed to parse sector size: {Error}", + "translation": "解析扇区大小失败: {Error}", + "message": "Failed to parse sector size: {Error}", + "placeholder": null + }, + { + "id": "Enter the confidence", + "translation": "输入置信度", + "message": "Enter the confidence", + "placeholder": null + }, + { + "id": "Failed to parse confidence: {Error}", + "translation": "解析置信度失败: {Error}", + "message": "Failed to parse confidence: {Error}", + "placeholder": null + }, + { + "id": "Failed to create the miner actor: {Error}", + "translation": "创建矿工角色失败: {Error}", + "message": "Failed to create the miner actor: {Error}", + "placeholder": null + }, + { + "id": "Miner {String} created successfully", + "translation": "矿工 {String} 创建成功", + "message": "Miner {String} created successfully", + "placeholder": null + }, + { + "id": "Cannot reach the DB: {Error}", + "translation": "无法访问数据库: {Error}", + "message": "Cannot reach the DB: {Error}", + "placeholder": null + }, + { + "id": "Error connecting to full node API: {Error}", + "translation": "连接到完整节点 API 时发生错误: {Error}", + "message": "Error connecting to full node API: {Error}", + "placeholder": null + }, + { + "id": "Pre-initialization steps complete", + "translation": "预初始化步骤完成", + "message": "Pre-initialization steps complete", + "placeholder": null + }, + { + "id": "Failed to generate random bytes for secret: {Error}", + "translation": "生成密码的随机字节失败: {Error}", + "message": "Failed to generate random bytes for secret: {Error}", + "placeholder": null + }, + { + "id": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "translation": "请不要再次运行引导设置,因为矿工创建不是幂等的。 您需要运行 'curio config new-cluster {String}' 来完成配置。", + "message": "Please do not run guided-setup again as miner creation is not idempotent. You need to run 'curio config new-cluster {String}' to finish the configuration", + "placeholder": null + }, + { + "id": "Failed to get API info for FullNode: {Err}", + "translation": "无法获取 FullNode 的 API 信息: {Err}", + "message": "Failed to get API info for FullNode: {Err}", + "placeholder": null + }, + { + "id": "Failed to verify the auth token from daemon node: {Error}", + "translation": "无法验证来自守护进程节点的授权令牌: {Error}", + "message": "Failed to verify the auth token from daemon node: {Error}", + "placeholder": null + }, + { + "id": "Failed to encode the config: {Error}", + "translation": "无法编码配置: {Error}", + "message": "Failed to encode the config: {Error}", + "placeholder": null + }, + { + "id": "Failed to generate default config: {Error}", + "translation": "无法生成默认配置: {Error}", + "message": "Failed to generate default config: {Error}", + "placeholder": null + }, + { + "id": "Failed to insert 'base' config layer in database: {Error}", + "translation": "无法将 'base' 配置层插入数据库: {Error}", + "message": "Failed to insert 'base' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "Failed to insert '{String}' config layer in database: {Error}", + "translation": "无法将 '{String}' 配置层插入数据库: {Error}", + "message": "Failed to insert '{String}' config layer in database: {Error}", + "placeholder": null + }, + { + "id": "New Curio configuration layer '{String}' created", + "translation": "新的 Curio 配置层 '{String}' 已创建", + "message": "New Curio configuration layer '{String}' created", + "placeholder": null + }, + { + "id": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "translation": "该过程部分幂等。一旦创建了新的矿工角色,并且随后的步骤失败,用户需要运行 'curio config new-cluster \u003c 矿工 ID \u003e' 来完成配置。", + "message": "This process is partially idempotent. Once a new miner actor has been created and subsequent steps fail, the user need to run 'curio config new-cluster \u003c miner ID \u003e' to finish the configuration.", + "placeholder": null + }, + { + "id": "Confidence epochs", + "translation": "置信度时期", + "message": "Confidence epochs", + "placeholder": null + }, + { + "id": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "translation": "通过冗余增加可靠性:使用至少后层启动多台机器:'curio run --layers=post'", + "message": "Increase reliability using redundancy: start multiple machines with at-least the post layer: 'curio run --layers=post'", + "placeholder": null + }, + { + "id": "I want to:", + "translation": "我想要:", + "message": "I want to:", + "placeholder": null + }, + { + "id": "Configuration 'base' was updated to include this miner's address", + "translation": "配置 'base' 已更新以包含此矿工的地址", + "message": "Configuration 'base' was updated to include this miner's address", + "placeholder": null + }, + { + "id": "Cannot load base config: {Error}", + "translation": "无法加载基本配置: {Error}", + "message": "Cannot load base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to load base config: {Error}", + "translation": "加载基本配置失败: {Error}", + "message": "Failed to load base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to regenerate base config: {Error}", + "translation": "重新生成基本配置失败: {Error}", + "message": "Failed to regenerate base config: {Error}", + "placeholder": null + }, + { + "id": "Failed to load base config from database: {Error}", + "translation": "从数据库加载基本配置失败:{Error}", + "message": "Failed to load base config from database: {Error}", + "placeholder": null + }, + { + "id": "Failed to parse base config: {Error}", + "translation": "解析基本配置失败:{Error}", + "message": "Failed to parse base config: {Error}", + "placeholder": null + }, + { + "id": "Try the web interface with {Rendercurio_run___layersgui} for further guided improvements.", + "translation": "尝试使用{Rendercurio_run___layersgui}的网络界面进行更进一步的指导性改进。", + "message": "Try the web interface with {Rendercurio_run___layersgui} for further guided improvements.", + "placeholder": null + }, + { + "id": "Now shut down lotus-miner and lotus-worker and use run {Rendercurio_run} instead.", + "translation": "现在关闭lotus-miner和lotus-worker,改为使用{Rendercurio_run}运行。", + "message": "Now shut down lotus-miner and lotus-worker and use run {Rendercurio_run} instead.", + "placeholder": null + }, + { + "id": "Configuration 'base' was updated to include this miner's address ({MinerAddress}) and its wallet setup.", + "translation": "'base'配置已更新,包括该矿工的地址({MinerAddress})及其钱包设置。", + "message": "Configuration 'base' was updated to include this miner's address ({MinerAddress}) and its wallet setup.", + "placeholder": null + }, + { + "id": "Configuration 'base' was created to resemble this lotus-miner's config.toml .", + "translation": "'base'配置已创建,以类似于这个lotus-miner的config.toml。", + "message": "Configuration 'base' was created to resemble this lotus-miner's config.toml .", + "placeholder": null + } + ] +} \ No newline at end of file diff --git a/cmd/curio/internal/translations/locales/zh/out.gotext.json b/cmd/curio/internal/translations/locales/zh/out.gotext.json new file mode 100644 index 00000000000..bb9d25e4cad --- /dev/null +++ b/cmd/curio/internal/translations/locales/zh/out.gotext.json @@ -0,0 +1,4 @@ +{ + "language": "zh", + "messages": [] + } diff --git a/cmd/curio/internal/translations/translations.go b/cmd/curio/internal/translations/translations.go new file mode 100644 index 00000000000..361e8e89401 --- /dev/null +++ b/cmd/curio/internal/translations/translations.go @@ -0,0 +1,27 @@ +// Usage: +// To UPDATE translations: +// +// 1. add/change strings in guidedsetup folder that use d.T() or d.say(). +// +// 2. run `go generate` in the cmd/curio/internal/translations/ folder. +// +// 3. ChatGPT 3.5 can translate the ./locales/??/out.gotext.json files' +// which ONLY include the un-translated messages. +// APPEND to the messages.gotext.json files's array. +// +// ChatGPT fuss: +// - on a good day, you may need to hit "continue generating". +// - > 60? you'll need to give it sections of the file. +// +// 4. Re-import with `go generate` again. +// +// To ADD a language: +// 1. Add it to the list in updateLang.sh +// 2. Run `go generate` in the cmd/curio/internal/translations/ folder. +// 3. Follow the "Update translations" steps here. +// 4. Code will auto-detect the new language and use it. +// +// FUTURE Reliability: OpenAPI automation. +package translations + +//go:generate ./updateLang.sh diff --git a/cmd/curio/internal/translations/updateLang.sh b/cmd/curio/internal/translations/updateLang.sh new file mode 100755 index 00000000000..984f63fd5d8 --- /dev/null +++ b/cmd/curio/internal/translations/updateLang.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +#OP: Only run if some file in ../guidedsetup* is newer than catalog.go +# Change this condition if using translations more widely. +if [ "$(find ../../guidedsetup/* -newer catalog.go)" ] || [ "$(find locales/* -newer catalog.go)" ]; then + gotext -srclang=en update -out=catalog.go -lang=en,zh,ko github.com/filecoin-project/lotus/cmd/curio/guidedsetup + go run knowns/main.go locales/zh locales/ko +fi diff --git a/cmd/curio/log.go b/cmd/curio/log.go new file mode 100644 index 00000000000..0af41a679dd --- /dev/null +++ b/cmd/curio/log.go @@ -0,0 +1,105 @@ +package main + +import ( + "fmt" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cmd/curio/rpc" +) + +var logCmd = &cli.Command{ + Name: "log", + Usage: "Manage logging", + Subcommands: []*cli.Command{ + LogList, + LogSetLevel, + }, +} + +var LogList = &cli.Command{ + Name: "list", + Usage: "List log systems", + Action: func(cctx *cli.Context) error { + minerApi, closer, err := rpc.GetCurioAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := lcli.ReqContext(cctx) + + systems, err := minerApi.LogList(ctx) + if err != nil { + return err + } + + for _, system := range systems { + fmt.Println(system) + } + + return nil + }, +} + +var LogSetLevel = &cli.Command{ + Name: "set-level", + Usage: "Set log level", + ArgsUsage: "[level]", + Description: `Set the log level for logging systems: + + The system flag can be specified multiple times. + + eg) log set-level --system chain --system chainxchg debug + + Available Levels: + debug + info + warn + error + + Environment Variables: + GOLOG_LOG_LEVEL - Default log level for all log systems + 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 +`, + Flags: []cli.Flag{ + &cli.StringSliceFlag{ + Name: "system", + Usage: "limit to log system", + Value: &cli.StringSlice{}, + }, + }, + Action: func(cctx *cli.Context) error { + minerApi, closer, err := rpc.GetCurioAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + if !cctx.Args().Present() { + return fmt.Errorf("level is required") + } + + systems := cctx.StringSlice("system") + if len(systems) == 0 { + var err error + systems, err = minerApi.LogList(ctx) + if err != nil { + return err + } + } + + for _, system := range systems { + if err := minerApi.LogSetLevel(ctx, system, cctx.Args().First()); err != nil { + return xerrors.Errorf("setting log level on %s: %v", system, err) + } + } + + return nil + }, +} diff --git a/cmd/lotus-provider/main.go b/cmd/curio/main.go similarity index 51% rename from cmd/lotus-provider/main.go rename to cmd/curio/main.go index 19cc6f5f946..9a092dad0f5 100644 --- a/cmd/lotus-provider/main.go +++ b/cmd/curio/main.go @@ -5,16 +5,23 @@ import ( "fmt" "os" "os/signal" - "runtime/debug" + "runtime/pprof" "syscall" + "github.com/docker/go-units" "github.com/fatih/color" logging "github.com/ipfs/go-log/v2" + "github.com/mitchellh/go-homedir" "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-paramfetch" "github.com/filecoin-project/lotus/build" lcli "github.com/filecoin-project/lotus/cli" cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/cmd/curio/guidedsetup" "github.com/filecoin-project/lotus/lib/lotuslog" "github.com/filecoin-project/lotus/lib/tracing" "github.com/filecoin-project/lotus/node/repo" @@ -22,37 +29,39 @@ import ( var log = logging.Logger("main") -func SetupCloseHandler() { +const ( + FlagMinerRepo = "miner-repo" +) + +func setupCloseHandler() { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) go func() { <-c fmt.Println("\r- Ctrl+C pressed in Terminal") - debug.PrintStack() - os.Exit(1) + _ = pprof.Lookup("goroutine").WriteTo(os.Stdout, 1) + panic(1) }() } func main() { - SetupCloseHandler() lotuslog.SetupLogLevels() local := []*cli.Command{ - //initCmd, + cliCmd, runCmd, stopCmd, configCmd, testCmd, - //backupCmd, - //lcli.WithCategory("chain", actorCmd), - //lcli.WithCategory("storage", sectorsCmd), - //lcli.WithCategory("storage", provingCmd), - //lcli.WithCategory("storage", storageCmd), - //lcli.WithCategory("storage", sealingCmd), + webCmd, + guidedsetup.GuidedsetupCmd, + sealCmd, + marketCmd, + fetchParamCmd, } - jaeger := tracing.SetupJaegerTracing("lotus") + jaeger := tracing.SetupJaegerTracing("curio") defer func() { if jaeger != nil { _ = jaeger.ForceFlush(context.Background()) @@ -66,7 +75,7 @@ func main() { if jaeger != nil { _ = jaeger.Shutdown(cctx.Context) } - jaeger = tracing.SetupJaegerTracing("lotus/" + cmd.Name) + jaeger = tracing.SetupJaegerTracing("curio/" + cmd.Name) if cctx.IsSet("color") { color.NoColor = !cctx.Bool("color") @@ -81,10 +90,14 @@ func main() { } app := &cli.App{ - Name: "lotus-provider", + Name: "curio", Usage: "Filecoin decentralized storage network provider", Version: build.UserVersion(), EnableBashCompletion: true, + Before: func(c *cli.Context) error { + setupCloseHandler() + return nil + }, Flags: []cli.Flag{ &cli.BoolFlag{ // examined in the Before above @@ -94,67 +107,83 @@ func main() { }, &cli.StringFlag{ Name: "panic-reports", - EnvVars: []string{"LOTUS_PANIC_REPORT_PATH"}, + EnvVars: []string{"CURIO_PANIC_REPORT_PATH"}, Hidden: true, - Value: "~/.lotusprovider", // should follow --repo default + Value: "~/.curio", // should follow --repo default }, &cli.StringFlag{ Name: "db-host", - EnvVars: []string{"LOTUS_DB_HOST"}, + EnvVars: []string{"CURIO_DB_HOST", "CURIO_HARMONYDB_HOSTS"}, Usage: "Command separated list of hostnames for yugabyte cluster", - Value: "yugabyte", + Value: "127.0.0.1", }, &cli.StringFlag{ Name: "db-name", - EnvVars: []string{"LOTUS_DB_NAME", "LOTUS_HARMONYDB_HOSTS"}, + EnvVars: []string{"CURIO_DB_NAME", "CURIO_HARMONYDB_NAME"}, Value: "yugabyte", }, &cli.StringFlag{ Name: "db-user", - EnvVars: []string{"LOTUS_DB_USER", "LOTUS_HARMONYDB_USERNAME"}, + EnvVars: []string{"CURIO_DB_USER", "CURIO_HARMONYDB_USERNAME"}, Value: "yugabyte", }, &cli.StringFlag{ Name: "db-password", - EnvVars: []string{"LOTUS_DB_PASSWORD", "LOTUS_HARMONYDB_PASSWORD"}, + EnvVars: []string{"CURIO_DB_PASSWORD", "CURIO_HARMONYDB_PASSWORD"}, Value: "yugabyte", }, &cli.StringFlag{ Name: "db-port", - EnvVars: []string{"LOTUS_DB_PORT", "LOTUS_HARMONYDB_PORT"}, - Hidden: true, + EnvVars: []string{"CURIO_DB_PORT", "CURIO_HARMONYDB_PORT"}, Value: "5433", }, &cli.StringFlag{ - Name: "layers", - EnvVars: []string{"LOTUS_LAYERS", "LOTUS_CONFIG_LAYERS"}, - Value: "base", - }, - &cli.StringFlag{ - Name: FlagRepoPath, - EnvVars: []string{"LOTUS_REPO_PATH"}, - Value: "~/.lotusprovider", + Name: deps.FlagRepoPath, + EnvVars: []string{"CURIO_REPO_PATH"}, + Value: "~/.curio", }, cliutil.FlagVeryVerbose, }, - Commands: append(local, lcli.CommonCommands...), - Before: func(c *cli.Context) error { - return nil - }, + Commands: local, After: func(c *cli.Context) error { if r := recover(); r != nil { - // Generate report in LOTUS_PATH and re-raise panic - build.GeneratePanicReport(c.String("panic-reports"), c.String(FlagRepoPath), c.App.Name) + p, err := homedir.Expand(c.String(FlagMinerRepo)) + if err != nil { + log.Errorw("could not expand repo path for panic report", "error", err) + panic(r) + } + + // Generate report in CURIO_PATH and re-raise panic + build.GeneratePanicReport(c.String("panic-reports"), p, c.App.Name) panic(r) } return nil }, } app.Setup() - app.Metadata["repoType"] = repo.Provider + app.Metadata["repoType"] = repo.Curio lcli.RunApp(app) } -const ( - FlagRepoPath = "repo-path" -) +var fetchParamCmd = &cli.Command{ + Name: "fetch-params", + Usage: "Fetch proving parameters", + ArgsUsage: "[sectorSize]", + Action: func(cctx *cli.Context) error { + if cctx.NArg() != 1 { + return xerrors.Errorf("incorrect number of arguments") + } + sectorSizeInt, err := units.RAMInBytes(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("error parsing sector size (specify as \"32GiB\", for instance): %w", err) + } + sectorSize := uint64(sectorSizeInt) + + err = paramfetch.GetParams(lcli.ReqContext(cctx), build.ParametersJSON(), build.SrsJSON(), sectorSize) + if err != nil { + return xerrors.Errorf("fetching proof parameters: %w", err) + } + + return nil + }, +} diff --git a/cmd/curio/market.go b/cmd/curio/market.go new file mode 100644 index 00000000000..cc562db932c --- /dev/null +++ b/cmd/curio/market.go @@ -0,0 +1,70 @@ +package main + +import ( + "fmt" + "sort" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/curiosrc/market/lmrpc" +) + +var marketCmd = &cli.Command{ + Name: "market", + Subcommands: []*cli.Command{ + marketRPCInfoCmd, + }, +} + +var marketRPCInfoCmd = &cli.Command{ + Flags: []cli.Flag{ + &cli.StringSliceFlag{ + Name: "layers", + Usage: "list of layers to be interpreted (atop defaults). Default: base", + }, + }, + Action: func(cctx *cli.Context) error { + db, err := deps.MakeDB(cctx) + if err != nil { + return err + } + + cfg, err := deps.GetConfig(cctx, db) + if err != nil { + return xerrors.Errorf("get config: %w", err) + } + + ts, err := lmrpc.MakeTokens(cfg) + if err != nil { + return xerrors.Errorf("make tokens: %w", err) + } + + var addrTokens []struct { + Address string + Token string + } + + for address, s := range ts { + addrTokens = append(addrTokens, struct { + Address string + Token string + }{ + Address: address.String(), + Token: s, + }) + } + + sort.Slice(addrTokens, func(i, j int) bool { + return addrTokens[i].Address < addrTokens[j].Address + }) + + for _, at := range addrTokens { + fmt.Printf("[lotus-miner/boost compatible] %s %s\n", at.Address, at.Token) + } + + return nil + }, + Name: "rpc-info", +} diff --git a/cmd/curio/migrate.go b/cmd/curio/migrate.go new file mode 100644 index 00000000000..06ab7d0f9a3 --- /dev/null +++ b/cmd/curio/migrate.go @@ -0,0 +1 @@ +package main diff --git a/cmd/curio/pipeline.go b/cmd/curio/pipeline.go new file mode 100644 index 00000000000..1c3f5d94a28 --- /dev/null +++ b/cmd/curio/pipeline.go @@ -0,0 +1,135 @@ +package main + +import ( + "fmt" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/curiosrc/seal" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" +) + +var sealCmd = &cli.Command{ + Name: "seal", + Usage: "Manage the sealing pipeline", + Subcommands: []*cli.Command{ + sealStartCmd, + }, +} + +var sealStartCmd = &cli.Command{ + Name: "start", + Usage: "Start new sealing operations manually", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "actor", + Usage: "Specify actor address to start sealing sectors for", + Required: true, + }, + &cli.BoolFlag{ + Name: "now", + Usage: "Start sealing sectors for all actors now (not on schedule)", + }, + &cli.BoolFlag{ + Name: "cc", + Usage: "Start sealing new CC sectors", + }, + &cli.IntFlag{ + Name: "count", + Usage: "Number of sectors to start", + Value: 1, + }, + &cli.BoolFlag{ + Name: "synthetic", + Usage: "Use synthetic PoRep", + Value: false, // todo implement synthetic + }, + &cli.StringSliceFlag{ + Name: "layers", + Usage: "list of layers to be interpreted (atop defaults). Default: base", + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Bool("now") { + return xerrors.Errorf("schedule not implemented, use --now") + } + if !cctx.IsSet("actor") { + return cli.ShowCommandHelp(cctx, "start") + } + if !cctx.Bool("cc") { + return xerrors.Errorf("only CC sectors supported for now") + } + + act, err := address.NewFromString(cctx.String("actor")) + if err != nil { + return xerrors.Errorf("parsing --actor: %w", err) + } + + ctx := lcli.ReqContext(cctx) + dep, err := deps.GetDepsCLI(ctx, cctx) + if err != nil { + return err + } + + /* + create table sectors_sdr_pipeline ( + sp_id bigint not null, + sector_number bigint not null, + + -- at request time + create_time timestamp not null, + reg_seal_proof int not null, + comm_d_cid text not null, + + [... other not relevant fields] + */ + + mid, err := address.IDFromAddress(act) + if err != nil { + return xerrors.Errorf("getting miner id: %w", err) + } + + mi, err := dep.Full.StateMinerInfo(ctx, act, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + nv, err := dep.Full.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting network version: %w", err) + } + + wpt := mi.WindowPoStProofType + spt, err := miner.PreferredSealProofTypeFromWindowPoStType(nv, wpt, cctx.Bool("synthetic")) + if err != nil { + return xerrors.Errorf("getting seal proof type: %w", err) + } + + num, err := seal.AllocateSectorNumbers(ctx, dep.Full, dep.DB, act, cctx.Int("count"), func(tx *harmonydb.Tx, numbers []abi.SectorNumber) (bool, error) { + for _, n := range numbers { + _, err := tx.Exec("insert into sectors_sdr_pipeline (sp_id, sector_number, reg_seal_proof) values ($1, $2, $3)", mid, n, spt) + if err != nil { + return false, xerrors.Errorf("inserting into sectors_sdr_pipeline: %w", err) + } + } + return true, nil + }) + if err != nil { + return xerrors.Errorf("allocating sector numbers: %w", err) + } + + for _, number := range num { + fmt.Println(number) + } + + return nil + }, +} diff --git a/cmd/lotus-provider/proving.go b/cmd/curio/proving.go similarity index 80% rename from cmd/lotus-provider/proving.go rename to cmd/curio/proving.go index a3211b17693..3b5a3e0e47b 100644 --- a/cmd/lotus-provider/proving.go +++ b/cmd/curio/proving.go @@ -15,8 +15,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/lotus/cmd/curio/deps" + curio "github.com/filecoin-project/lotus/curiosrc" "github.com/filecoin-project/lotus/lib/harmony/harmonydb" - "github.com/filecoin-project/lotus/provider" ) var testCmd = &cli.Command{ @@ -26,6 +27,9 @@ var testCmd = &cli.Command{ //provingInfoCmd, wdPostCmd, }, + Before: func(cctx *cli.Context) error { + return nil + }, } var wdPostCmd = &cli.Command{ @@ -46,7 +50,7 @@ var wdPostCmd = &cli.Command{ var wdPostTaskCmd = &cli.Command{ Name: "task", Aliases: []string{"scheduled", "schedule", "async", "asynchronous"}, - Usage: "Test the windowpost scheduler by running it on the next available lotus-provider. ", + Usage: "Test the windowpost scheduler by running it on the next available curio. ", Flags: []cli.Flag{ &cli.Uint64Flag{ Name: "deadline", @@ -56,24 +60,24 @@ var wdPostTaskCmd = &cli.Command{ &cli.StringSliceFlag{ Name: "layers", Usage: "list of layers to be interpreted (atop defaults). Default: base", - Value: cli.NewStringSlice("base"), }, }, Action: func(cctx *cli.Context) error { ctx := context.Background() - deps, err := getDeps(ctx, cctx) + deps, err := deps.GetDeps(ctx, cctx) if err != nil { - return err + return xerrors.Errorf("get config: %w", err) } - ts, err := deps.full.ChainHead(ctx) + ts, err := deps.Full.ChainHead(ctx) if err != nil { return xerrors.Errorf("cannot get chainhead %w", err) } ht := ts.Height() - addr, err := address.NewFromString(deps.cfg.Addresses.MinerAddresses[0]) + // It's not important to be super-accurate as it's only for basic testing. + addr, err := address.NewFromString(deps.Cfg.Addresses[0].MinerAddresses[0]) if err != nil { return xerrors.Errorf("cannot get miner address %w", err) } @@ -81,34 +85,35 @@ var wdPostTaskCmd = &cli.Command{ if err != nil { return xerrors.Errorf("cannot get miner id %w", err) } - var id int64 - _, err = deps.db.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { - err = tx.QueryRow(`INSERT INTO harmony_task (name, posted_time, added_by) VALUES ('WdPost', CURRENT_TIMESTAMP, 123) RETURNING id`).Scan(&id) + var taskId int64 + + _, err = deps.DB.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { + err = tx.QueryRow(`INSERT INTO harmony_task (name, posted_time, added_by) VALUES ('WdPost', CURRENT_TIMESTAMP, 123) RETURNING id`).Scan(&taskId) if err != nil { log.Error("inserting harmony_task: ", err) return false, xerrors.Errorf("inserting harmony_task: %w", err) } _, err = tx.Exec(`INSERT INTO wdpost_partition_tasks (task_id, sp_id, proving_period_start, deadline_index, partition_index) VALUES ($1, $2, $3, $4, $5)`, - id, maddr, ht, cctx.Uint64("deadline"), 0) + taskId, maddr, ht, cctx.Uint64("deadline"), 0) if err != nil { log.Error("inserting wdpost_partition_tasks: ", err) return false, xerrors.Errorf("inserting wdpost_partition_tasks: %w", err) } - _, err = tx.Exec("INSERT INTO harmony_test (task_id) VALUES ($1)", id) + _, err = tx.Exec("INSERT INTO harmony_test (task_id) VALUES ($1)", taskId) if err != nil { return false, xerrors.Errorf("inserting into harmony_tests: %w", err) } return true, nil - }) + }, harmonydb.OptionRetry()) if err != nil { return xerrors.Errorf("writing SQL transaction: %w", err) } - fmt.Printf("Inserted task %v. Waiting for success ", id) + fmt.Printf("Inserted task %v. Waiting for success ", taskId) var result sql.NullString for { time.Sleep(time.Second) - err = deps.db.QueryRow(ctx, `SELECT result FROM harmony_test WHERE task_id=$1`, id).Scan(&result) + err = deps.DB.QueryRow(ctx, `SELECT result FROM harmony_test WHERE task_id=$1`, taskId).Scan(&result) if err != nil { return xerrors.Errorf("reading result from harmony_test: %w", err) } @@ -117,6 +122,7 @@ var wdPostTaskCmd = &cli.Command{ } fmt.Print(".") } + fmt.Println() log.Infof("Result: %s", result.String) return nil }, @@ -141,12 +147,11 @@ It will not send any messages to the chain. Since it can compute any deadline, o &cli.StringSliceFlag{ Name: "layers", Usage: "list of layers to be interpreted (atop defaults). Default: base", - Value: cli.NewStringSlice("base"), }, &cli.StringFlag{ Name: "storage-json", Usage: "path to json file containing storage config", - Value: "~/.lotus-provider/storage.json", + Value: "~/.curio/storage.json", }, &cli.Uint64Flag{ Name: "partition", @@ -157,29 +162,30 @@ It will not send any messages to the chain. Since it can compute any deadline, o Action: func(cctx *cli.Context) error { ctx := context.Background() - deps, err := getDeps(ctx, cctx) + deps, err := deps.GetDeps(ctx, cctx) if err != nil { return err } - wdPostTask, wdPoStSubmitTask, derlareRecoverTask, err := provider.WindowPostScheduler(ctx, deps.cfg.Fees, deps.cfg.Proving, deps.full, deps.verif, deps.lw, nil, - deps.as, deps.maddrs, deps.db, deps.stor, deps.si, deps.cfg.Subsystems.WindowPostMaxTasks) + wdPostTask, wdPoStSubmitTask, derlareRecoverTask, err := curio.WindowPostScheduler( + ctx, deps.Cfg.Fees, deps.Cfg.Proving, deps.Full, deps.Verif, deps.LW, nil, nil, + deps.As, deps.Maddrs, deps.DB, deps.Stor, deps.Si, deps.Cfg.Subsystems.WindowPostMaxTasks) if err != nil { return err } _, _ = wdPoStSubmitTask, derlareRecoverTask - if len(deps.maddrs) == 0 { + if len(deps.Maddrs) == 0 { return errors.New("no miners to compute WindowPoSt for") } - head, err := deps.full.ChainHead(ctx) + head, err := deps.Full.ChainHead(ctx) if err != nil { return xerrors.Errorf("failed to get chain head: %w", err) } di := dline.NewInfo(head.Height(), cctx.Uint64("deadline"), 0, 0, 0, 10 /*challenge window*/, 0, 0) - for _, maddr := range deps.maddrs { + for maddr := range deps.Maddrs { out, err := wdPostTask.DoPartition(ctx, head, address.Address(maddr), di, cctx.Uint64("partition")) if err != nil { fmt.Println("Error computing WindowPoSt for miner", maddr, err) diff --git a/cmd/curio/rpc/rpc.go b/cmd/curio/rpc/rpc.go new file mode 100644 index 00000000000..1b2bb25e643 --- /dev/null +++ b/cmd/curio/rpc/rpc.go @@ -0,0 +1,325 @@ +// Package rpc provides all direct access to this node. +package rpc + +import ( + "context" + "encoding/base64" + "encoding/json" + "net" + "net/http" + "net/url" + "os" + "path/filepath" + "time" + + "github.com/gbrlsnchs/jwt/v3" + "github.com/google/uuid" + "github.com/gorilla/mux" + logging "github.com/ipfs/go-log/v2" + "github.com/mitchellh/go-homedir" + "github.com/urfave/cli/v2" + "go.opencensus.io/tag" + "golang.org/x/sync/errgroup" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-jsonrpc/auth" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/api/client" + cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/curiosrc/market" + "github.com/filecoin-project/lotus/curiosrc/web" + "github.com/filecoin-project/lotus/lib/rpcenc" + "github.com/filecoin-project/lotus/metrics" + "github.com/filecoin-project/lotus/metrics/proxy" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/lotus/storage/paths" + "github.com/filecoin-project/lotus/storage/sealer/fsutil" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +const metaFile = "sectorstore.json" + +var log = logging.Logger("curio/rpc") +var permissioned = os.Getenv("LOTUS_DISABLE_AUTH_PERMISSIONED") != "1" + +func CurioHandler( + authv func(ctx context.Context, token string) ([]auth.Permission, error), + remote http.HandlerFunc, + a api.Curio, + permissioned bool) http.Handler { + mux := mux.NewRouter() + readerHandler, readerServerOpt := rpcenc.ReaderParamDecoder() + rpcServer := jsonrpc.NewServer(jsonrpc.WithServerErrors(api.RPCErrors), readerServerOpt) + + wapi := proxy.MetricedAPI[api.Curio, api.CurioStruct](a) + if permissioned { + wapi = api.PermissionedAPI[api.Curio, api.CurioStruct](wapi) + } + + rpcServer.Register("Filecoin", wapi) + rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover") + + mux.Handle("/rpc/v0", rpcServer) + mux.Handle("/rpc/streams/v0/push/{uuid}", readerHandler) + mux.PathPrefix("/remote").HandlerFunc(remote) + mux.PathPrefix("/").Handler(http.DefaultServeMux) // pprof + + if !permissioned { + return mux + } + + ah := &auth.Handler{ + Verify: authv, + Next: mux.ServeHTTP, + } + return ah +} + +type CurioAPI struct { + *deps.Deps + paths.SectorIndex + ShutdownChan chan struct{} +} + +func (p *CurioAPI) Version(context.Context) (api.Version, error) { + return api.CurioAPIVersion0, nil +} +func (p *CurioAPI) StorageDetachLocal(ctx context.Context, path string) error { + path, err := homedir.Expand(path) + if err != nil { + return xerrors.Errorf("expanding local path: %w", err) + } + + // check that we have the path opened + lps, err := p.LocalStore.Local(ctx) + if err != nil { + return xerrors.Errorf("getting local path list: %w", err) + } + + var localPath *storiface.StoragePath + for _, lp := range lps { + if lp.LocalPath == path { + lp := lp // copy to make the linter happy + localPath = &lp + break + } + } + if localPath == nil { + return xerrors.Errorf("no local paths match '%s'", path) + } + + // drop from the persisted storage.json + var found bool + if err := p.LocalPaths.SetStorage(func(sc *storiface.StorageConfig) { + out := make([]storiface.LocalPath, 0, len(sc.StoragePaths)) + for _, storagePath := range sc.StoragePaths { + if storagePath.Path != path { + out = append(out, storagePath) + continue + } + found = true + } + sc.StoragePaths = out + }); err != nil { + return xerrors.Errorf("set storage config: %w", err) + } + if !found { + // maybe this is fine? + return xerrors.Errorf("path not found in storage.json") + } + + // unregister locally, drop from sector index + return p.LocalStore.ClosePath(ctx, localPath.ID) +} + +func (p *CurioAPI) StorageLocal(ctx context.Context) (map[storiface.ID]string, error) { + ps, err := p.LocalStore.Local(ctx) + if err != nil { + return nil, err + } + + var out = make(map[storiface.ID]string) + for _, path := range ps { + out[path.ID] = path.LocalPath + } + + return out, nil +} + +func (p *CurioAPI) StorageStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, error) { + return p.Stor.FsStat(ctx, id) +} + +func (p *CurioAPI) AllocatePieceToSector(ctx context.Context, maddr address.Address, piece api.PieceDealInfo, rawSize int64, source url.URL, header http.Header) (api.SectorOffset, error) { + di := market.NewPieceIngester(p.Deps.DB, p.Deps.Full) + + return di.AllocatePieceToSector(ctx, maddr, piece, rawSize, source, header) +} + +// Trigger shutdown +func (p *CurioAPI) Shutdown(context.Context) error { + close(p.ShutdownChan) + return nil +} + +func (p *CurioAPI) StorageInit(ctx context.Context, path string, opts storiface.LocalStorageMeta) error { + path, err := homedir.Expand(path) + if err != nil { + return xerrors.Errorf("expanding local path: %w", err) + } + + if err := os.MkdirAll(path, 0755); err != nil { + if !os.IsExist(err) { + return err + } + } + _, err = os.Stat(filepath.Join(path, metaFile)) + if !os.IsNotExist(err) { + if err == nil { + return xerrors.Errorf("path is already initialized") + } + return err + } + if opts.ID == "" { + opts.ID = storiface.ID(uuid.New().String()) + } + if !(opts.CanStore || opts.CanSeal) { + return xerrors.Errorf("must specify at least one of --store or --seal") + } + b, err := json.MarshalIndent(opts, "", " ") + if err != nil { + return xerrors.Errorf("marshaling storage config: %w", err) + } + if err := os.WriteFile(filepath.Join(path, metaFile), b, 0644); err != nil { + return xerrors.Errorf("persisting storage metadata (%s): %w", filepath.Join(path, metaFile), err) + } + return nil +} + +func (p *CurioAPI) StorageAddLocal(ctx context.Context, path string) error { + path, err := homedir.Expand(path) + if err != nil { + return xerrors.Errorf("expanding local path: %w", err) + } + + if err := p.LocalStore.OpenPath(ctx, path); err != nil { + return xerrors.Errorf("opening local path: %w", err) + } + + if err := p.LocalPaths.SetStorage(func(sc *storiface.StorageConfig) { + sc.StoragePaths = append(sc.StoragePaths, storiface.LocalPath{Path: path}) + }); err != nil { + return xerrors.Errorf("get storage config: %w", err) + } + + return nil +} + +func (p *CurioAPI) LogList(ctx context.Context) ([]string, error) { + return logging.GetSubsystems(), nil +} + +func (p *CurioAPI) LogSetLevel(ctx context.Context, subsystem, level string) error { + return logging.SetLogLevel(subsystem, level) +} + +func ListenAndServe(ctx context.Context, dependencies *deps.Deps, shutdownChan chan struct{}) error { + fh := &paths.FetchHandler{Local: dependencies.LocalStore, PfHandler: &paths.DefaultPartialFileHandler{}} + remoteHandler := func(w http.ResponseWriter, r *http.Request) { + if !auth.HasPerm(r.Context(), nil, api.PermAdmin) { + w.WriteHeader(401) + _ = json.NewEncoder(w).Encode(struct{ Error string }{"unauthorized: missing admin permission"}) + return + } + + fh.ServeHTTP(w, r) + } + + var authVerify func(context.Context, string) ([]auth.Permission, error) + { + privateKey, err := base64.StdEncoding.DecodeString(dependencies.Cfg.Apis.StorageRPCSecret) + if err != nil { + return xerrors.Errorf("decoding storage rpc secret: %w", err) + } + authVerify = func(ctx context.Context, token string) ([]auth.Permission, error) { + var payload deps.JwtPayload + if _, err := jwt.Verify([]byte(token), jwt.NewHS256(privateKey), &payload); err != nil { + return nil, xerrors.Errorf("JWT Verification failed: %w", err) + } + + return payload.Allow, nil + } + } + // Serve the RPC. + srv := &http.Server{ + Handler: CurioHandler( + authVerify, + remoteHandler, + &CurioAPI{dependencies, dependencies.Si, shutdownChan}, + permissioned), + ReadHeaderTimeout: time.Minute * 3, + BaseContext: func(listener net.Listener) context.Context { + ctx, _ := tag.New(context.Background(), tag.Upsert(metrics.APIInterface, "lotus-worker")) + return ctx + }, + Addr: dependencies.ListenAddr, + } + + log.Infof("Setting up RPC server at %s", dependencies.ListenAddr) + eg := errgroup.Group{} + eg.Go(srv.ListenAndServe) + + if dependencies.Cfg.Subsystems.EnableWebGui { + web, err := web.GetSrv(ctx, dependencies) + if err != nil { + return err + } + + go func() { + <-ctx.Done() + log.Warn("Shutting down...") + if err := srv.Shutdown(context.TODO()); err != nil { + log.Errorf("shutting down RPC server failed: %s", err) + } + if err := web.Shutdown(context.Background()); err != nil { + log.Errorf("shutting down web server failed: %s", err) + } + log.Warn("Graceful shutdown successful") + }() + + uiAddress := dependencies.Cfg.Subsystems.GuiAddress + if uiAddress == "" || uiAddress[0] == ':' { + uiAddress = "localhost" + uiAddress + } + log.Infof("GUI: http://%s", uiAddress) + eg.Go(web.ListenAndServe) + } + return eg.Wait() +} + +func GetCurioAPI(ctx *cli.Context) (api.Curio, jsonrpc.ClientCloser, error) { + addr, headers, err := cliutil.GetRawAPI(ctx, repo.Curio, "v0") + if err != nil { + return nil, nil, err + } + + u, err := url.Parse(addr) + if err != nil { + return nil, nil, xerrors.Errorf("parsing miner api URL: %w", err) + } + + switch u.Scheme { + case "ws": + u.Scheme = "http" + case "wss": + u.Scheme = "https" + } + + addr = u.String() + + return client.NewCurioRpc(ctx.Context, addr, headers) +} diff --git a/cmd/curio/run.go b/cmd/curio/run.go new file mode 100644 index 00000000000..cacacfc0fee --- /dev/null +++ b/cmd/curio/run.go @@ -0,0 +1,196 @@ +package main + +import ( + "context" + "fmt" + "os" + "strings" + + "github.com/pkg/errors" + "github.com/urfave/cli/v2" + "go.opencensus.io/stats" + "go.opencensus.io/tag" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/build" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/cmd/curio/rpc" + "github.com/filecoin-project/lotus/cmd/curio/tasks" + "github.com/filecoin-project/lotus/curiosrc/market/lmrpc" + "github.com/filecoin-project/lotus/lib/ulimit" + "github.com/filecoin-project/lotus/metrics" + "github.com/filecoin-project/lotus/node" +) + +type stackTracer interface { + StackTrace() errors.StackTrace +} + +var runCmd = &cli.Command{ + Name: "run", + Usage: "Start a Curio process", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "listen", + Usage: "host address and port the worker api will listen on", + Value: "0.0.0.0:12300", + EnvVars: []string{"LOTUS_WORKER_LISTEN"}, + }, + &cli.BoolFlag{ + Name: "nosync", + Usage: "don't check full-node sync status", + }, + &cli.BoolFlag{ + Name: "halt-after-init", + Usage: "only run init, then return", + Hidden: true, + }, + &cli.BoolFlag{ + Name: "manage-fdlimit", + Usage: "manage open file limit", + Value: true, + }, + &cli.StringFlag{ + Name: "storage-json", + Usage: "path to json file containing storage config", + Value: "~/.curio/storage.json", + }, + &cli.StringFlag{ + Name: "journal", + Usage: "path to journal files", + Value: "~/.curio/", + }, + &cli.StringSliceFlag{ + Name: "layers", + Aliases: []string{"l", "layer"}, + Usage: "list of layers to be interpreted (atop defaults). Default: base", + }, + }, + Action: func(cctx *cli.Context) (err error) { + defer func() { + if err != nil { + if err, ok := err.(stackTracer); ok { + for _, f := range err.StackTrace() { + fmt.Printf("%+s:%d\n", f, f) + } + } + } + }() + if !cctx.Bool("enable-gpu-proving") { + err := os.Setenv("BELLMAN_NO_GPU", "true") + if err != nil { + return err + } + } + + if err := os.MkdirAll(os.TempDir(), 0755); err != nil { + log.Errorf("ensuring tempdir exists: %s", err) + } + + ctx, _ := tag.New(lcli.DaemonContext(cctx), + tag.Insert(metrics.Version, build.BuildVersion), + tag.Insert(metrics.Commit, build.CurrentCommit), + tag.Insert(metrics.NodeType, "curio"), + ) + shutdownChan := make(chan struct{}) + { + var ctxclose func() + ctx, ctxclose = context.WithCancel(ctx) + go func() { + <-shutdownChan + ctxclose() + }() + } + // Register all metric views + /* + if err := view.Register( + metrics.MinerNodeViews..., + ); err != nil { + log.Fatalf("Cannot register the view: %v", err) + } + */ + // Set the metric to one so it is published to the exporter + stats.Record(ctx, metrics.LotusInfo.M(1)) + + if cctx.Bool("manage-fdlimit") { + if _, _, err := ulimit.ManageFdLimit(); err != nil { + log.Errorf("setting file descriptor limit: %s", err) + } + } + + dependencies := &deps.Deps{} + err = dependencies.PopulateRemainingDeps(ctx, cctx, true) + if err != nil { + return err + } + + taskEngine, err := tasks.StartTasks(ctx, dependencies) + + if err != nil { + return nil + } + defer taskEngine.GracefullyTerminate() + + if err := lmrpc.ServeCurioMarketRPCFromConfig(dependencies.DB, dependencies.Full, dependencies.Cfg); err != nil { + return xerrors.Errorf("starting market RPCs: %w", err) + } + + err = rpc.ListenAndServe(ctx, dependencies, shutdownChan) // Monitor for shutdown. + if err != nil { + return err + } + + finishCh := node.MonitorShutdown(shutdownChan) //node.ShutdownHandler{Component: "rpc server", StopFunc: rpcStopper}, + //node.ShutdownHandler{Component: "curio", StopFunc: stop}, + + <-finishCh + return nil + }, +} + +var webCmd = &cli.Command{ + Name: "web", + Usage: "Start Curio web interface", + Description: `Start an instance of Curio web interface. + This creates the 'web' layer if it does not exist, then calls run with that layer.`, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "listen", + Usage: "Address to listen on", + Value: "127.0.0.1:4701", + }, + &cli.BoolFlag{ + Name: "nosync", + Usage: "don't check full-node sync status", + }, + &cli.StringSliceFlag{ + Name: "layers", + Usage: "list of layers to be interpreted (atop defaults). Default: base", + }, + }, + Action: func(cctx *cli.Context) error { + + db, err := deps.MakeDB(cctx) + if err != nil { + return err + } + + webtxt, err := getConfig(db, "web") + if err != nil || webtxt == "" { + + s := `[Susbystems] + EnableWebGui = true + ` + if err = setConfig(db, "web", s); err != nil { + return err + } + } + layers := append([]string{"web"}, cctx.StringSlice("layers")...) + err = cctx.Set("layers", strings.Join(layers, ",")) + if err != nil { + return err + } + return runCmd.Action(cctx) + }, +} diff --git a/cmd/lotus-provider/stop.go b/cmd/curio/stop.go similarity index 91% rename from cmd/lotus-provider/stop.go rename to cmd/curio/stop.go index 3376d762a46..eb61a34fa4e 100644 --- a/cmd/lotus-provider/stop.go +++ b/cmd/curio/stop.go @@ -10,9 +10,10 @@ import ( var stopCmd = &cli.Command{ Name: "stop", - Usage: "Stop a running lotus provider", + Usage: "Stop a running Curio process", Flags: []cli.Flag{}, Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetAPI(cctx) if err != nil { return err diff --git a/cmd/curio/storage.go b/cmd/curio/storage.go new file mode 100644 index 00000000000..2fa6d2d5291 --- /dev/null +++ b/cmd/curio/storage.go @@ -0,0 +1,499 @@ +package main + +import ( + "fmt" + "math/bits" + "sort" + "strconv" + "strings" + "time" + + "github.com/docker/go-units" + "github.com/fatih/color" + "github.com/google/uuid" + "github.com/mitchellh/go-homedir" + "github.com/urfave/cli/v2" + "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" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cmd/curio/rpc" + "github.com/filecoin-project/lotus/storage/sealer/fsutil" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +var storageCmd = &cli.Command{ + Name: "storage", + Usage: "manage sector storage", + Description: `Sectors can be stored across many filesystem paths. These +commands provide ways to manage the storage the miner will used to store sectors +long term for proving (references as 'store') as well as how sectors will be +stored while moving through the sealing pipeline (references as 'seal').`, + Subcommands: []*cli.Command{ + storageAttachCmd, + storageDetachCmd, + storageListCmd, + storageFindCmd, + /*storageDetachCmd, + storageRedeclareCmd, + storageCleanupCmd, + storageLocks,*/ + }, +} + +var storageAttachCmd = &cli.Command{ + Name: "attach", + Usage: "attach local storage path", + ArgsUsage: "[path]", + Description: `Storage can be attached to the miner using this command. The storage volume +list is stored local to the miner in storage.json set in curio run. We do not +recommend manually modifying this value without further understanding of the +storage system. + +Each storage volume contains a configuration file which describes the +capabilities of the volume. When the '--init' flag is provided, this file will +be created using the additional flags. + +Weight +A high weight value means data will be more likely to be stored in this path + +Seal +Data for the sealing process will be stored here + +Store +Finalized sectors that will be moved here for long term storage and be proven +over time + `, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "init", + Usage: "initialize the path first", + }, + &cli.Uint64Flag{ + Name: "weight", + Usage: "(for init) path weight", + Value: 10, + }, + &cli.BoolFlag{ + Name: "seal", + Usage: "(for init) use path for sealing", + }, + &cli.BoolFlag{ + Name: "store", + Usage: "(for init) use path for long-term storage", + }, + &cli.StringFlag{ + Name: "max-storage", + Usage: "(for init) limit storage space for sectors (expensive for very large paths!)", + }, + &cli.StringSliceFlag{ + Name: "groups", + Usage: "path group names", + }, + &cli.StringSliceFlag{ + Name: "allow-to", + Usage: "path groups allowed to pull data from this path (allow all if not specified)", + }, + }, + Action: func(cctx *cli.Context) error { + minerApi, closer, err := rpc.GetCurioAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + p, err := homedir.Expand(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("expanding path: %w", err) + } + + if cctx.Bool("init") { + var maxStor int64 + if cctx.IsSet("max-storage") { + maxStor, err = units.RAMInBytes(cctx.String("max-storage")) + if err != nil { + return xerrors.Errorf("parsing max-storage: %w", err) + } + } + + cfg := storiface.LocalStorageMeta{ + ID: storiface.ID(uuid.New().String()), + Weight: cctx.Uint64("weight"), + CanSeal: cctx.Bool("seal"), + CanStore: cctx.Bool("store"), + MaxStorage: uint64(maxStor), + Groups: cctx.StringSlice("groups"), + AllowTo: cctx.StringSlice("allow-to"), + } + + if !(cfg.CanStore || cfg.CanSeal) { + return xerrors.Errorf("must specify at least one of --store or --seal") + } + + if err := minerApi.StorageInit(ctx, p, cfg); err != nil { + return xerrors.Errorf("init storage: %w", err) + } + } + + return minerApi.StorageAddLocal(ctx, p) + }, +} + +var storageDetachCmd = &cli.Command{ + Name: "detach", + Usage: "detach local storage path", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "really-do-it", + }, + }, + ArgsUsage: "[path]", + Action: func(cctx *cli.Context) error { + minerApi, closer, err := rpc.GetCurioAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + p, err := homedir.Expand(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("expanding path: %w", err) + } + + if !cctx.Bool("really-do-it") { + return xerrors.Errorf("pass --really-do-it to execute the action") + } + + return minerApi.StorageDetachLocal(ctx, p) + }, +} + +var storageListCmd = &cli.Command{ + Name: "list", + Usage: "list local storage paths", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "local", + Usage: "only list local storage paths", + }, + }, + Subcommands: []*cli.Command{ + //storageListSectorsCmd, + }, + Action: func(cctx *cli.Context) error { + minerApi, closer, err := rpc.GetCurioAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + st, err := minerApi.StorageList(ctx) + if err != nil { + return err + } + + local, err := minerApi.StorageLocal(ctx) + if err != nil { + return err + } + + type fsInfo struct { + storiface.ID + sectors []storiface.Decl + stat fsutil.FsStat + } + + sorted := make([]fsInfo, 0, len(st)) + for id, decls := range st { + if cctx.Bool("local") { + if _, ok := local[id]; !ok { + continue + } + } + + st, err := minerApi.StorageStat(ctx, id) + if err != nil { + sorted = append(sorted, fsInfo{ID: id, sectors: decls}) + continue + } + + sorted = append(sorted, fsInfo{id, decls, st}) + } + + sort.Slice(sorted, func(i, j int) bool { + if sorted[i].stat.Capacity != sorted[j].stat.Capacity { + return sorted[i].stat.Capacity > sorted[j].stat.Capacity + } + return sorted[i].ID < sorted[j].ID + }) + + for _, s := range sorted { + + var cnt [5]int + for _, decl := range s.sectors { + for i := range cnt { + if decl.SectorFileType&(1< 98: + percCol = color.FgRed + case usedPercent > 90: + percCol = color.FgYellow + } + + set := (st.Capacity - st.FSAvailable) * barCols / st.Capacity + used := (st.Capacity - (st.FSAvailable + st.Reserved)) * barCols / st.Capacity + reserved := set - used + bar := safeRepeat("#", int(used)) + safeRepeat("*", int(reserved)) + safeRepeat(" ", int(barCols-set)) + + desc := "" + if st.Max > 0 { + desc = " (filesystem)" + } + + fmt.Printf("\t[%s] %s/%s %s%s\n", color.New(percCol).Sprint(bar), + types.SizeStr(types.NewInt(uint64(st.Capacity-st.FSAvailable))), + types.SizeStr(types.NewInt(uint64(st.Capacity))), + color.New(percCol).Sprintf("%d%%", usedPercent), desc) + } + + // optional configured limit bar + if st.Max > 0 { + usedPercent := st.Used * 100 / st.Max + + percCol := color.FgGreen + switch { + case usedPercent > 98: + percCol = color.FgRed + case usedPercent > 90: + percCol = color.FgYellow + } + + set := st.Used * barCols / st.Max + used := (st.Used + st.Reserved) * barCols / st.Max + reserved := set - used + bar := safeRepeat("#", int(used)) + safeRepeat("*", int(reserved)) + safeRepeat(" ", int(barCols-set)) + + fmt.Printf("\t[%s] %s/%s %s (limit)\n", color.New(percCol).Sprint(bar), + types.SizeStr(types.NewInt(uint64(st.Used))), + types.SizeStr(types.NewInt(uint64(st.Max))), + color.New(percCol).Sprintf("%d%%", usedPercent)) + } + + fmt.Printf("\t%s; %s; %s; %s; %s; Reserved: %s\n", + color.YellowString("Unsealed: %d", cnt[0]), + color.GreenString("Sealed: %d", cnt[1]), + color.BlueString("Caches: %d", cnt[2]), + color.GreenString("Updated: %d", cnt[3]), + color.BlueString("Update-caches: %d", cnt[4]), + types.SizeStr(types.NewInt(uint64(st.Reserved)))) + + si, err := minerApi.StorageInfo(ctx, s.ID) + if err != nil { + return err + } + + fmt.Print("\t") + if si.CanSeal || si.CanStore { + fmt.Printf("Weight: %d; Use: ", si.Weight) + if si.CanSeal { + fmt.Print(color.MagentaString("Seal ")) + } + if si.CanStore { + fmt.Print(color.CyanString("Store")) + } + } else { + fmt.Print(color.HiYellowString("Use: ReadOnly")) + } + fmt.Println() + + if len(si.Groups) > 0 { + fmt.Printf("\tGroups: %s\n", strings.Join(si.Groups, ", ")) + } + if len(si.AllowTo) > 0 { + fmt.Printf("\tAllowTo: %s\n", strings.Join(si.AllowTo, ", ")) + } + + if len(si.AllowTypes) > 0 || len(si.DenyTypes) > 0 { + denied := storiface.FTAll.SubAllowed(si.AllowTypes, si.DenyTypes) + allowed := storiface.FTAll ^ denied + + switch { + case bits.OnesCount64(uint64(allowed)) == 0: + fmt.Printf("\tAllow Types: %s\n", color.RedString("None")) + case bits.OnesCount64(uint64(allowed)) < bits.OnesCount64(uint64(denied)): + fmt.Printf("\tAllow Types: %s\n", color.GreenString(strings.Join(allowed.Strings(), " "))) + default: + fmt.Printf("\tDeny Types: %s\n", color.RedString(strings.Join(denied.Strings(), " "))) + } + } + + if localPath, ok := local[s.ID]; ok { + fmt.Printf("\tLocal: %s\n", color.GreenString(localPath)) + } + for i, l := range si.URLs { + var rtt string + if _, ok := local[s.ID]; !ok && i == 0 { + rtt = " (latency: " + ping.Truncate(time.Microsecond*100).String() + ")" + } + + fmt.Printf("\tURL: %s%s\n", l, rtt) // TODO; try pinging maybe?? print latency? + } + fmt.Println() + } + + return nil + }, +} + +type storedSector struct { + id storiface.ID + store storiface.SectorStorageInfo + types map[storiface.SectorFileType]bool +} + +var storageFindCmd = &cli.Command{ + Name: "find", + Usage: "find sector in the storage system", + ArgsUsage: "[miner address] [sector number]", + Action: func(cctx *cli.Context) error { + minerApi, closer, err := rpc.GetCurioAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := lcli.ReqContext(cctx) + + if cctx.NArg() != 2 { + return lcli.IncorrectNumArgs(cctx) + } + + maddr := cctx.Args().First() + ma, err := address.NewFromString(maddr) + if err != nil { + return xerrors.Errorf("parsing miner address: %w", err) + } + + mid, err := address.IDFromAddress(ma) + if err != nil { + return err + } + + if !cctx.Args().Present() { + return xerrors.New("Usage: lotus-miner storage find [sector number]") + } + + snum, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64) + if err != nil { + return err + } + + sid := abi.SectorID{ + Miner: abi.ActorID(mid), + Number: abi.SectorNumber(snum), + } + + sectorTypes := []storiface.SectorFileType{ + storiface.FTUnsealed, storiface.FTSealed, storiface.FTCache, storiface.FTUpdate, storiface.FTUpdateCache, + } + + byId := make(map[storiface.ID]*storedSector) + for _, sectorType := range sectorTypes { + infos, err := minerApi.StorageFindSector(ctx, sid, sectorType, 0, false) + if err != nil { + return xerrors.Errorf("finding sector type %d: %w", sectorType, err) + } + + for _, info := range infos { + sts, ok := byId[info.ID] + if !ok { + sts = &storedSector{ + id: info.ID, + store: info, + types: make(map[storiface.SectorFileType]bool), + } + byId[info.ID] = sts + } + sts.types[sectorType] = true + } + } + + local, err := minerApi.StorageLocal(ctx) + if err != nil { + return err + } + + var out []*storedSector + for _, sector := range byId { + out = append(out, sector) + } + sort.Slice(out, func(i, j int) bool { + return out[i].id < out[j].id + }) + + for _, info := range out { + var types []string + for sectorType, present := range info.types { + if present { + types = append(types, sectorType.String()) + } + } + sort.Strings(types) // Optional: Sort types for consistent output + fmt.Printf("In %s (%s)\n", info.id, strings.Join(types, ", ")) + fmt.Printf("\tSealing: %t; Storage: %t\n", info.store.CanSeal, info.store.CanStore) + if localPath, ok := local[info.id]; ok { + fmt.Printf("\tLocal (%s)\n", localPath) + } else { + fmt.Printf("\tRemote\n") + } + for _, l := range info.store.URLs { + fmt.Printf("\tURL: %s\n", l) + } + } + + return nil + }, +} diff --git a/cmd/curio/tasks/tasks.go b/cmd/curio/tasks/tasks.go new file mode 100644 index 00000000000..71923018d9e --- /dev/null +++ b/cmd/curio/tasks/tasks.go @@ -0,0 +1,240 @@ +// Package tasks contains tasks that can be run by the curio command. +package tasks + +import ( + "context" + "sort" + "strings" + "time" + + logging "github.com/ipfs/go-log/v2" + "github.com/samber/lo" + "golang.org/x/exp/maps" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/cmd/curio/deps" + curio "github.com/filecoin-project/lotus/curiosrc" + "github.com/filecoin-project/lotus/curiosrc/chainsched" + "github.com/filecoin-project/lotus/curiosrc/ffi" + "github.com/filecoin-project/lotus/curiosrc/gc" + "github.com/filecoin-project/lotus/curiosrc/message" + "github.com/filecoin-project/lotus/curiosrc/piece" + "github.com/filecoin-project/lotus/curiosrc/seal" + "github.com/filecoin-project/lotus/curiosrc/winning" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/lazy" + "github.com/filecoin-project/lotus/lib/must" + "github.com/filecoin-project/lotus/node/modules" + "github.com/filecoin-project/lotus/node/modules/dtypes" +) + +var log = logging.Logger("curio/deps") + +func StartTasks(ctx context.Context, dependencies *deps.Deps) (*harmonytask.TaskEngine, error) { + cfg := dependencies.Cfg + db := dependencies.DB + full := dependencies.Full + verif := dependencies.Verif + lw := dependencies.LW + as := dependencies.As + maddrs := dependencies.Maddrs + stor := dependencies.Stor + lstor := dependencies.LocalStore + si := dependencies.Si + var activeTasks []harmonytask.TaskInterface + + sender, sendTask := message.NewSender(full, full, db) + activeTasks = append(activeTasks, sendTask) + + chainSched := chainsched.New(full) + + var needProofParams bool + + /////////////////////////////////////////////////////////////////////// + ///// Task Selection + /////////////////////////////////////////////////////////////////////// + { + // PoSt + + if cfg.Subsystems.EnableWindowPost { + wdPostTask, wdPoStSubmitTask, derlareRecoverTask, err := curio.WindowPostScheduler( + ctx, cfg.Fees, cfg.Proving, full, verif, lw, sender, chainSched, + as, maddrs, db, stor, si, cfg.Subsystems.WindowPostMaxTasks) + + if err != nil { + return nil, err + } + activeTasks = append(activeTasks, wdPostTask, wdPoStSubmitTask, derlareRecoverTask) + needProofParams = true + } + + if cfg.Subsystems.EnableWinningPost { + winPoStTask := winning.NewWinPostTask(cfg.Subsystems.WinningPostMaxTasks, db, lw, verif, full, maddrs) + activeTasks = append(activeTasks, winPoStTask) + needProofParams = true + } + } + + slrLazy := lazy.MakeLazy(func() (*ffi.SealCalls, error) { + return ffi.NewSealCalls(stor, lstor, si), nil + }) + + { + // Piece handling + if cfg.Subsystems.EnableParkPiece { + parkPieceTask := piece.NewParkPieceTask(db, must.One(slrLazy.Val()), cfg.Subsystems.ParkPieceMaxTasks) + cleanupPieceTask := piece.NewCleanupPieceTask(db, must.One(slrLazy.Val()), 0) + activeTasks = append(activeTasks, parkPieceTask, cleanupPieceTask) + } + } + + hasAnySealingTask := cfg.Subsystems.EnableSealSDR || + cfg.Subsystems.EnableSealSDRTrees || + cfg.Subsystems.EnableSendPrecommitMsg || + cfg.Subsystems.EnablePoRepProof || + cfg.Subsystems.EnableMoveStorage || + cfg.Subsystems.EnableSendCommitMsg + { + // Sealing + + var sp *seal.SealPoller + var slr *ffi.SealCalls + if hasAnySealingTask { + sp = seal.NewPoller(db, full) + go sp.RunPoller(ctx) + + slr = must.One(slrLazy.Val()) + } + + // NOTE: Tasks with the LEAST priority are at the top + if cfg.Subsystems.EnableSealSDR { + sdrTask := seal.NewSDRTask(full, db, sp, slr, cfg.Subsystems.SealSDRMaxTasks) + activeTasks = append(activeTasks, sdrTask) + } + if cfg.Subsystems.EnableSealSDRTrees { + treesTask := seal.NewTreesTask(sp, db, slr, cfg.Subsystems.SealSDRTreesMaxTasks) + finalizeTask := seal.NewFinalizeTask(cfg.Subsystems.FinalizeMaxTasks, sp, slr, db) + activeTasks = append(activeTasks, treesTask, finalizeTask) + } + if cfg.Subsystems.EnableSendPrecommitMsg { + precommitTask := seal.NewSubmitPrecommitTask(sp, db, full, sender, as, cfg.Fees.MaxPreCommitGasFee) + activeTasks = append(activeTasks, precommitTask) + } + if cfg.Subsystems.EnablePoRepProof { + porepTask := seal.NewPoRepTask(db, full, sp, slr, cfg.Subsystems.PoRepProofMaxTasks) + activeTasks = append(activeTasks, porepTask) + needProofParams = true + } + if cfg.Subsystems.EnableMoveStorage { + moveStorageTask := seal.NewMoveStorageTask(sp, slr, db, cfg.Subsystems.MoveStorageMaxTasks) + activeTasks = append(activeTasks, moveStorageTask) + } + if cfg.Subsystems.EnableSendCommitMsg { + commitTask := seal.NewSubmitCommitTask(sp, db, full, sender, as, cfg.Fees.MaxCommitGasFee) + activeTasks = append(activeTasks, commitTask) + } + } + + if hasAnySealingTask { + // Sealing nodes maintain storage index when bored + storageEndpointGcTask := gc.NewStorageEndpointGC(si, stor, db) + activeTasks = append(activeTasks, storageEndpointGcTask) + } + + if needProofParams { + for spt := range dependencies.ProofTypes { + if err := modules.GetParams(true)(spt); err != nil { + return nil, xerrors.Errorf("getting params: %w", err) + } + } + } + + minerAddresses := make([]string, 0, len(maddrs)) + for k := range maddrs { + minerAddresses = append(minerAddresses, address.Address(k).String()) + } + + log.Infow("This Curio instance handles", + "miner_addresses", minerAddresses, + "tasks", lo.Map(activeTasks, func(t harmonytask.TaskInterface, _ int) string { return t.TypeDetails().Name })) + + // harmony treats the first task as highest priority, so reverse the order + // (we could have just appended to this list in the reverse order, but defining + // tasks in pipeline order is more intuitive) + activeTasks = lo.Reverse(activeTasks) + + ht, err := harmonytask.New(db, activeTasks, dependencies.ListenAddr) + if err != nil { + return nil, err + } + go machineDetails(dependencies, activeTasks, ht.ResourcesAvailable().MachineID) + + if hasAnySealingTask { + watcher, err := message.NewMessageWatcher(db, ht, chainSched, full) + if err != nil { + return nil, err + } + _ = watcher + } + + if cfg.Subsystems.EnableWindowPost || hasAnySealingTask { + go chainSched.Run(ctx) + } + + return ht, nil +} + +func machineDetails(deps *deps.Deps, activeTasks []harmonytask.TaskInterface, machineID int) { + taskNames := lo.Map(activeTasks, func(item harmonytask.TaskInterface, _ int) string { + return item.TypeDetails().Name + }) + + miners := lo.Map(maps.Keys(deps.Maddrs), func(item dtypes.MinerAddress, _ int) string { + return address.Address(item).String() + }) + sort.Strings(miners) + + _, err := deps.DB.Exec(context.Background(), `INSERT INTO harmony_machine_details + (tasks, layers, startup_time, miners, machine_id) VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (machine_id) DO UPDATE SET tasks=$1, layers=$2, startup_time=$3, miners=$4`, + strings.Join(taskNames, ","), strings.Join(deps.Layers, ","), + time.Now(), strings.Join(miners, ","), machineID) + + if err != nil { + log.Errorf("failed to update machine details: %s", err) + return + } + + // maybePostWarning + if !lo.Contains(taskNames, "WdPost") && !lo.Contains(taskNames, "WinPost") { + // Maybe we aren't running a PoSt for these miners? + var allMachines []struct { + MachineID int `db:"machine_id"` + Miners string `db:"miners"` + Tasks string `db:"tasks"` + } + err := deps.DB.Select(context.Background(), &allMachines, `SELECT machine_id, miners, tasks FROM harmony_machine_details`) + if err != nil { + log.Errorf("failed to get machine details: %s", err) + return + } + + for _, miner := range miners { + var myPostIsHandled bool + for _, m := range allMachines { + if !lo.Contains(strings.Split(m.Miners, ","), miner) { + continue + } + if lo.Contains(strings.Split(m.Tasks, ","), "WdPost") && lo.Contains(strings.Split(m.Tasks, ","), "WinPost") { + myPostIsHandled = true + break + } + } + if !myPostIsHandled { + log.Errorf("No PoSt tasks are running for miner %s. Start handling PoSts immediately with:\n\tcurio run --layers=\"post\" ", miner) + } + } + } +} diff --git a/cmd/lotus-bench/cli.go b/cmd/lotus-bench/cli.go index 0eaeb6ccba2..4379036d33a 100644 --- a/cmd/lotus-bench/cli.go +++ b/cmd/lotus-bench/cli.go @@ -270,7 +270,7 @@ func (c *CMD) startWorker(qpsTicker *time.Ticker) { start := time.Now() - var statusCode int = 0 + var statusCode int arr := strings.Fields(c.cmd) diff --git a/cmd/lotus-bench/main.go b/cmd/lotus-bench/main.go index 545ed1eb90b..1a7a0d08792 100644 --- a/cmd/lotus-bench/main.go +++ b/cmd/lotus-bench/main.go @@ -93,7 +93,7 @@ type Commit2In struct { } func main() { - logging.SetLogLevel("*", "INFO") + _ = logging.SetLogLevel("*", "INFO") log.Info("Starting lotus-bench") diff --git a/cmd/lotus-bench/reporter.go b/cmd/lotus-bench/reporter.go index ad2ad6b9d86..7ade7b19d00 100644 --- a/cmd/lotus-bench/reporter.go +++ b/cmd/lotus-bench/reporter.go @@ -88,7 +88,7 @@ func (r *Reporter) Print(elapsed time.Duration, w io.Writer) { return r.latencies[i] < r.latencies[j] }) - var totalLatency int64 = 0 + var totalLatency int64 for _, latency := range r.latencies { totalLatency += latency } diff --git a/cmd/lotus-fountain/main.go b/cmd/lotus-fountain/main.go index f6d503c2f3d..36d5faf0c29 100644 --- a/cmd/lotus-fountain/main.go +++ b/cmd/lotus-fountain/main.go @@ -30,7 +30,7 @@ import ( var log = logging.Logger("main") func main() { - logging.SetLogLevel("*", "INFO") + _ = logging.SetLogLevel("*", "INFO") log.Info("Starting fountain") diff --git a/cmd/lotus-health/main.go b/cmd/lotus-health/main.go index a7052f21480..59c81e7c91a 100644 --- a/cmd/lotus-health/main.go +++ b/cmd/lotus-health/main.go @@ -25,7 +25,7 @@ type CidWindow [][]cid.Cid var log = logging.Logger("lotus-health") func main() { - logging.SetLogLevel("*", "INFO") + _ = logging.SetLogLevel("*", "INFO") log.Info("Starting health agent") diff --git a/cmd/lotus-miner/actor.go b/cmd/lotus-miner/actor.go index 6d76cc07fdc..1ff613fc15a 100644 --- a/cmd/lotus-miner/actor.go +++ b/cmd/lotus-miner/actor.go @@ -1,38 +1,20 @@ package main import ( - "bytes" "fmt" "os" - "strconv" "strings" "github.com/fatih/color" - "github.com/ipfs/go-cid" - cbor "github.com/ipfs/go-ipld-cbor" - "github.com/libp2p/go-libp2p/core/peer" - ma "github.com/multiformats/go-multiaddr" "github.com/urfave/cli/v2" - "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" - "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/go-state-types/builtin" - "github.com/filecoin-project/go-state-types/builtin/v9/miner" - "github.com/filecoin-project/go-state-types/network" - "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" - "github.com/filecoin-project/lotus/chain/actors/adt" + lapi "github.com/filecoin-project/lotus/api" builtin2 "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" lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/spcli" "github.com/filecoin-project/lotus/lib/tablewriter" ) @@ -40,399 +22,37 @@ var actorCmd = &cli.Command{ Name: "actor", Usage: "manipulate the miner actor", Subcommands: []*cli.Command{ - actorSetAddrsCmd, - actorWithdrawCmd, - actorRepayDebtCmd, - actorSetPeeridCmd, - actorSetOwnerCmd, - actorControl, - actorProposeChangeWorker, - actorConfirmChangeWorker, - actorCompactAllocatedCmd, - actorProposeChangeBeneficiary, - actorConfirmChangeBeneficiary, + spcli.ActorSetAddrsCmd(LMActorGetter), + spcli.ActorWithdrawCmd(LMActorGetter), + spcli.ActorRepayDebtCmd(LMActorGetter), + spcli.ActorSetPeeridCmd(LMActorGetter), + spcli.ActorSetOwnerCmd(LMConfigOrActorGetter), + spcli.ActorControlCmd(LMConfigOrActorGetter, actorControlListCmd), + spcli.ActorProposeChangeWorkerCmd(LMActorGetter), + spcli.ActorConfirmChangeWorkerCmd(LMActorGetter), + spcli.ActorCompactAllocatedCmd(LMActorGetter), + spcli.ActorProposeChangeBeneficiaryCmd(LMActorGetter), + spcli.ActorConfirmChangeBeneficiaryCmd(LMConfigOrActorGetter), }, } -var actorSetAddrsCmd = &cli.Command{ - Name: "set-addresses", - Aliases: []string{"set-addrs"}, - Usage: "set addresses that your miner can be publicly dialed on", - ArgsUsage: "", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "from", - Usage: "optionally specify the account to send the message from", - }, - &cli.Int64Flag{ - Name: "gas-limit", - Usage: "set gas limit", - Value: 0, - }, - &cli.BoolFlag{ - Name: "unset", - Usage: "unset address", - Value: false, - }, - }, - Action: func(cctx *cli.Context) error { - args := cctx.Args().Slice() - unset := cctx.Bool("unset") - if len(args) == 0 && !unset { - return cli.ShowSubcommandHelp(cctx) - } - if len(args) > 0 && unset { - return fmt.Errorf("unset can only be used with no arguments") - } - - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - var addrs []abi.Multiaddrs - for _, a := range args { - maddr, err := ma.NewMultiaddr(a) - if err != nil { - return fmt.Errorf("failed to parse %q as a multiaddr: %w", a, err) - } - - maddrNop2p, strip := ma.SplitFunc(maddr, func(c ma.Component) bool { - return c.Protocol().Code == ma.P_P2P - }) - - if strip != nil { - fmt.Println("Stripping peerid ", strip, " from ", maddr) - } - addrs = append(addrs, maddrNop2p.Bytes()) - } - - maddr, err := minerApi.ActorAddress(ctx) - if err != nil { - return err - } - - minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - fromAddr := minfo.Worker - if from := cctx.String("from"); from != "" { - addr, err := address.NewFromString(from) - if err != nil { - return err - } - - fromAddr = addr - } - - fromId, err := api.StateLookupID(ctx, fromAddr, types.EmptyTSK) - if err != nil { - return err - } - - if !isController(minfo, fromId) { - return xerrors.Errorf("sender isn't a controller of miner: %s", fromId) - } - - params, err := actors.SerializeParams(&miner.ChangeMultiaddrsParams{NewMultiaddrs: addrs}) - if err != nil { - return err - } - - gasLimit := cctx.Int64("gas-limit") - - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - To: maddr, - From: fromId, - Value: types.NewInt(0), - GasLimit: gasLimit, - Method: builtin.MethodsMiner.ChangeMultiaddrs, - Params: params, - }, nil) - if err != nil { - return err - } - - fmt.Printf("Requested multiaddrs change in message %s\n", smsg.Cid()) - return nil - - }, -} - -var actorSetPeeridCmd = &cli.Command{ - Name: "set-peer-id", - Usage: "set the peer id of your miner", - ArgsUsage: "", - Flags: []cli.Flag{ - &cli.Int64Flag{ - Name: "gas-limit", - Usage: "set gas limit", - Value: 0, - }, - }, - Action: func(cctx *cli.Context) error { - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - if cctx.NArg() != 1 { - return lcli.IncorrectNumArgs(cctx) - } - - pid, err := peer.Decode(cctx.Args().Get(0)) - if err != nil { - return fmt.Errorf("failed to parse input as a peerId: %w", err) - } - - maddr, err := minerApi.ActorAddress(ctx) - if err != nil { - return err - } - - minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - params, err := actors.SerializeParams(&miner.ChangePeerIDParams{NewID: abi.PeerID(pid)}) - if err != nil { - return err - } - - gasLimit := cctx.Int64("gas-limit") - - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - To: maddr, - From: minfo.Worker, - Value: types.NewInt(0), - GasLimit: gasLimit, - Method: builtin.MethodsMiner.ChangePeerID, - Params: params, - }, nil) - if err != nil { - return err - } - - fmt.Printf("Requested peerid change in message %s\n", smsg.Cid()) - return nil - - }, -} - -var actorWithdrawCmd = &cli.Command{ - Name: "withdraw", - Usage: "withdraw available balance to beneficiary", - ArgsUsage: "[amount (FIL)]", - Flags: []cli.Flag{ - &cli.IntFlag{ - Name: "confidence", - Usage: "number of block confirmations to wait for", - Value: int(build.MessageConfidence), - }, - &cli.BoolFlag{ - Name: "beneficiary", - Usage: "send withdraw message from the beneficiary address", - }, - }, - Action: func(cctx *cli.Context) error { - amount := abi.NewTokenAmount(0) - - if cctx.Args().Present() { - f, err := types.ParseFIL(cctx.Args().First()) - if err != nil { - return xerrors.Errorf("parsing 'amount' argument: %w", err) - } - - amount = abi.TokenAmount(f) - } - - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - var res cid.Cid - if cctx.IsSet("beneficiary") { - res, err = minerApi.BeneficiaryWithdrawBalance(ctx, amount) - } else { - res, err = minerApi.ActorWithdrawBalance(ctx, amount) - } - if err != nil { - return err - } - - fmt.Printf("Requested withdrawal in message %s\nwaiting for it to be included in a block..\n", res) - - // 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", res) - } - - if wait.Receipt.ExitCode.IsError() { - return xerrors.Errorf("Failed to execute withdrawal message %s: %w", wait.Message, wait.Receipt.ExitCode.Error()) - } - - nv, err := api.StateNetworkVersion(ctx, wait.TipSet) - if err != nil { - return err - } - - if nv >= network.Version14 { - var withdrawn abi.TokenAmount - if err := withdrawn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil { - return err - } - - fmt.Printf("Successfully withdrew %s \n", types.FIL(withdrawn)) - if withdrawn.LessThan(amount) { - fmt.Printf("Note that this is less than the requested amount of %s\n", types.FIL(amount)) - } - } - - return nil - }, +func LMConfigOrActorGetter(cctx *cli.Context) (address.Address, error) { + ctx := lcli.ReqContext(cctx) + return getActorAddress(ctx, cctx) } -var actorRepayDebtCmd = &cli.Command{ - Name: "repay-debt", - Usage: "pay down a miner's debt", - ArgsUsage: "[amount (FIL)]", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "from", - Usage: "optionally specify the account to send funds from", - }, - }, - Action: func(cctx *cli.Context) error { - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - maddr, err := minerApi.ActorAddress(ctx) - if err != nil { - return err - } - - mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - var amount abi.TokenAmount - if cctx.Args().Present() { - f, err := types.ParseFIL(cctx.Args().First()) - if err != nil { - return xerrors.Errorf("parsing 'amount' argument: %w", err) - } - - amount = abi.TokenAmount(f) - } else { - mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(api))) - - mst, err := lminer.Load(store, mact) - if err != nil { - return err - } - - amount, err = mst.FeeDebt() - if err != nil { - return err - } - - } - - fromAddr := mi.Worker - if from := cctx.String("from"); from != "" { - addr, err := address.NewFromString(from) - if err != nil { - return err - } - - fromAddr = addr - } - - fromId, err := api.StateLookupID(ctx, fromAddr, types.EmptyTSK) - if err != nil { - return err - } - - if !isController(mi, fromId) { - return xerrors.Errorf("sender isn't a controller of miner: %s", fromId) - } - - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - To: maddr, - From: fromId, - Value: amount, - Method: builtin.MethodsMiner.RepayDebt, - Params: nil, - }, nil) - if err != nil { - return err - } - - fmt.Printf("Sent repay debt message %s\n", smsg.Cid()) - - return nil - }, -} +func getControlAddresses(cctx *cli.Context, actor address.Address) (lapi.AddressConfig, error) { + minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return lapi.AddressConfig{}, err + } + defer closer() -var actorControl = &cli.Command{ - Name: "control", - Usage: "Manage control addresses", - Subcommands: []*cli.Command{ - actorControlList, - actorControlSet, - }, + ctx := lcli.ReqContext(cctx) + return minerApi.ActorAddressConfig(ctx) } -var actorControlList = &cli.Command{ +var actorControlListCmd = &cli.Command{ Name: "list", Usage: "Get currently set control addresses", Flags: []cli.Flag{ @@ -441,12 +61,6 @@ var actorControlList = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - api, acloser, err := lcli.GetFullNodeAPIV1(cctx) if err != nil { return err @@ -455,7 +69,7 @@ var actorControlList = &cli.Command{ ctx := lcli.ReqContext(cctx) - maddr, err := getActorAddress(ctx, cctx) + maddr, err := LMActorOrEnvGetter(cctx) if err != nil { return err } @@ -473,11 +87,10 @@ var actorControlList = &cli.Command{ tablewriter.Col("balance"), ) - ac, err := minerApi.ActorAddressConfig(ctx) + ac, err := getControlAddresses(cctx, maddr) if err != nil { return err } - commit := map[address.Address]struct{}{} precommit := map[address.Address]struct{}{} terminate := map[address.Address]struct{}{} @@ -600,853 +213,3 @@ var actorControlList = &cli.Command{ return tw.Flush(os.Stdout) }, } - -var actorControlSet = &cli.Command{ - Name: "set", - Usage: "Set control address(-es)", - ArgsUsage: "[...address]", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "really-do-it", - Usage: "Actually send transaction performing the action", - Value: false, - }, - }, - Action: func(cctx *cli.Context) error { - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - maddr, err := minerApi.ActorAddress(ctx) - if err != nil { - return err - } - - mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - del := map[address.Address]struct{}{} - existing := map[address.Address]struct{}{} - for _, controlAddress := range mi.ControlAddresses { - ka, err := api.StateAccountKey(ctx, controlAddress, types.EmptyTSK) - if err != nil { - return err - } - - del[ka] = struct{}{} - existing[ka] = struct{}{} - } - - var toSet []address.Address - - for i, as := range cctx.Args().Slice() { - a, err := address.NewFromString(as) - if err != nil { - return xerrors.Errorf("parsing address %d: %w", i, err) - } - - ka, err := api.StateAccountKey(ctx, a, types.EmptyTSK) - if err != nil { - return err - } - - // make sure the address exists on chain - _, err = api.StateLookupID(ctx, ka, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("looking up %s: %w", ka, err) - } - - delete(del, ka) - toSet = append(toSet, ka) - } - - for a := range del { - fmt.Println("Remove", a) - } - for _, a := range toSet { - if _, exists := existing[a]; !exists { - fmt.Println("Add", a) - } - } - - if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action") - return nil - } - - cwp := &miner.ChangeWorkerAddressParams{ - NewWorker: mi.Worker, - NewControlAddrs: toSet, - } - - sp, err := actors.SerializeParams(cwp) - if err != nil { - return xerrors.Errorf("serializing params: %w", err) - } - - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - From: mi.Owner, - To: maddr, - Method: builtin.MethodsMiner.ChangeWorkerAddress, - - Value: big.Zero(), - Params: sp, - }, nil) - if err != nil { - return xerrors.Errorf("mpool push: %w", err) - } - - fmt.Println("Message CID:", smsg.Cid()) - - return nil - }, -} - -var actorSetOwnerCmd = &cli.Command{ - Name: "set-owner", - Usage: "Set owner address (this command should be invoked twice, first with the old owner as the senderAddress, and then with the new owner)", - ArgsUsage: "[newOwnerAddress senderAddress]", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "really-do-it", - Usage: "Actually send transaction performing the action", - Value: false, - }, - }, - Action: func(cctx *cli.Context) error { - if cctx.NArg() != 2 { - return lcli.IncorrectNumArgs(cctx) - } - - if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action") - return nil - } - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - na, err := address.NewFromString(cctx.Args().First()) - if err != nil { - return err - } - - newAddrId, err := api.StateLookupID(ctx, na, types.EmptyTSK) - if err != nil { - return err - } - - fa, err := address.NewFromString(cctx.Args().Get(1)) - if err != nil { - return err - } - - fromAddrId, err := api.StateLookupID(ctx, fa, types.EmptyTSK) - if err != nil { - return err - } - - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - - mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - if fromAddrId != mi.Owner && fromAddrId != newAddrId { - return xerrors.New("from address must either be the old owner or the new owner") - } - - sp, err := actors.SerializeParams(&newAddrId) - if err != nil { - return xerrors.Errorf("serializing params: %w", err) - } - - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - From: fromAddrId, - To: maddr, - Method: builtin.MethodsMiner.ChangeOwnerAddress, - Value: big.Zero(), - Params: sp, - }, nil) - if err != nil { - return xerrors.Errorf("mpool push: %w", err) - } - - fmt.Println("Message CID:", smsg.Cid()) - - // wait for it to get mined into a block - wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) - if err != nil { - return err - } - - // check it executed successfully - if wait.Receipt.ExitCode.IsError() { - fmt.Println("owner change failed!") - return err - } - - fmt.Println("message succeeded!") - - return nil - }, -} - -var actorProposeChangeWorker = &cli.Command{ - Name: "propose-change-worker", - Usage: "Propose a worker address change", - ArgsUsage: "[address]", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "really-do-it", - Usage: "Actually send transaction performing the action", - Value: false, - }, - }, - Action: func(cctx *cli.Context) error { - if !cctx.Args().Present() { - return fmt.Errorf("must pass address of new worker address") - } - - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - na, err := address.NewFromString(cctx.Args().First()) - if err != nil { - return err - } - - newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK) - if err != nil { - return err - } - - maddr, err := minerApi.ActorAddress(ctx) - if err != nil { - return err - } - - mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - if mi.NewWorker.Empty() { - if mi.Worker == newAddr { - return fmt.Errorf("worker address already set to %s", na) - } - } else { - if mi.NewWorker == newAddr { - return fmt.Errorf("change to worker address %s already pending", na) - } - } - - if !cctx.Bool("really-do-it") { - fmt.Fprintln(cctx.App.Writer, "Pass --really-do-it to actually execute this action") - return nil - } - - cwp := &miner.ChangeWorkerAddressParams{ - NewWorker: newAddr, - NewControlAddrs: mi.ControlAddresses, - } - - sp, err := actors.SerializeParams(cwp) - if err != nil { - return xerrors.Errorf("serializing params: %w", err) - } - - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - From: mi.Owner, - To: maddr, - Method: builtin.MethodsMiner.ChangeWorkerAddress, - Value: big.Zero(), - Params: sp, - }, nil) - if err != nil { - return xerrors.Errorf("mpool push: %w", err) - } - - fmt.Fprintln(cctx.App.Writer, "Propose Message CID:", smsg.Cid()) - - // wait for it to get mined into a block - wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) - if err != nil { - return err - } - - // check it executed successfully - if wait.Receipt.ExitCode.IsError() { - return fmt.Errorf("propose worker change failed") - } - - mi, err = api.StateMinerInfo(ctx, maddr, wait.TipSet) - if err != nil { - return err - } - if mi.NewWorker != newAddr { - return fmt.Errorf("Proposed worker address change not reflected on chain: expected '%s', found '%s'", na, mi.NewWorker) - } - - fmt.Fprintf(cctx.App.Writer, "Worker key change to %s successfully sent, change happens at height %d.\n", na, mi.WorkerChangeEpoch) - fmt.Fprintf(cctx.App.Writer, "If you have no active deadlines, call 'confirm-change-worker' at or after height %d to complete.\n", mi.WorkerChangeEpoch) - - return nil - }, -} - -var actorProposeChangeBeneficiary = &cli.Command{ - Name: "propose-change-beneficiary", - Usage: "Propose a beneficiary address change", - ArgsUsage: "[beneficiaryAddress quota expiration]", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "really-do-it", - Usage: "Actually send transaction performing the action", - Value: false, - }, - &cli.BoolFlag{ - Name: "overwrite-pending-change", - Usage: "Overwrite the current beneficiary change proposal", - Value: false, - }, - &cli.StringFlag{ - Name: "actor", - Usage: "specify the address of miner actor", - }, - }, - Action: func(cctx *cli.Context) error { - if cctx.NArg() != 3 { - return lcli.IncorrectNumArgs(cctx) - } - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return xerrors.Errorf("getting fullnode api: %w", err) - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - na, err := address.NewFromString(cctx.Args().Get(0)) - if err != nil { - return xerrors.Errorf("parsing beneficiary address: %w", err) - } - - newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("looking up new beneficiary address: %w", err) - } - - quota, err := types.ParseFIL(cctx.Args().Get(1)) - if err != nil { - return xerrors.Errorf("parsing quota: %w", err) - } - - expiration, err := strconv.ParseInt(cctx.Args().Get(2), 10, 64) - if err != nil { - return xerrors.Errorf("parsing expiration: %w", err) - } - - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return xerrors.Errorf("getting miner address: %w", err) - } - - mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting miner info: %w", err) - } - - if mi.Beneficiary == mi.Owner && newAddr == mi.Owner { - return fmt.Errorf("beneficiary %s already set to owner address", mi.Beneficiary) - } - - if mi.PendingBeneficiaryTerm != nil { - fmt.Println("WARNING: replacing Pending Beneficiary Term of:") - fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary) - fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota) - fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration) - - if !cctx.Bool("overwrite-pending-change") { - return fmt.Errorf("must pass --overwrite-pending-change to replace current pending beneficiary change. Please review CAREFULLY") - } - } - - if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please") - return nil - } - - params := &miner.ChangeBeneficiaryParams{ - NewBeneficiary: newAddr, - NewQuota: abi.TokenAmount(quota), - NewExpiration: abi.ChainEpoch(expiration), - } - - sp, err := actors.SerializeParams(params) - if err != nil { - return xerrors.Errorf("serializing params: %w", err) - } - - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - From: mi.Owner, - To: maddr, - Method: builtin.MethodsMiner.ChangeBeneficiary, - Value: big.Zero(), - Params: sp, - }, nil) - if err != nil { - return xerrors.Errorf("mpool push: %w", err) - } - - fmt.Println("Propose Message CID:", smsg.Cid()) - - // wait for it to get mined into a block - wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) - if err != nil { - return xerrors.Errorf("waiting for message to be included in block: %w", err) - } - - // check it executed successfully - if wait.Receipt.ExitCode.IsError() { - return fmt.Errorf("propose beneficiary change failed") - } - - updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, wait.TipSet) - if err != nil { - return xerrors.Errorf("getting miner info: %w", err) - } - - if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == newAddr { - fmt.Println("Beneficiary address successfully changed") - } else { - fmt.Println("Beneficiary address change awaiting additional confirmations") - } - - return nil - }, -} - -var actorConfirmChangeWorker = &cli.Command{ - Name: "confirm-change-worker", - Usage: "Confirm a worker address change", - ArgsUsage: "[address]", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "really-do-it", - Usage: "Actually send transaction performing the action", - Value: false, - }, - }, - Action: func(cctx *cli.Context) error { - if !cctx.Args().Present() { - return fmt.Errorf("must pass address of new worker address") - } - - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - na, err := address.NewFromString(cctx.Args().First()) - if err != nil { - return err - } - - newAddr, err := api.StateLookupID(ctx, na, types.EmptyTSK) - if err != nil { - return err - } - - maddr, err := minerApi.ActorAddress(ctx) - if err != nil { - return err - } - - mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - if mi.NewWorker.Empty() { - return xerrors.Errorf("no worker key change proposed") - } else if mi.NewWorker != newAddr { - return xerrors.Errorf("worker key %s does not match current worker key proposal %s", newAddr, mi.NewWorker) - } - - if head, err := api.ChainHead(ctx); err != nil { - return xerrors.Errorf("failed to get the chain head: %w", err) - } else if head.Height() < mi.WorkerChangeEpoch { - return xerrors.Errorf("worker key change cannot be confirmed until %d, current height is %d", mi.WorkerChangeEpoch, head.Height()) - } - - if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action") - return nil - } - - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - From: mi.Owner, - To: maddr, - Method: builtin.MethodsMiner.ConfirmChangeWorkerAddress, - Value: big.Zero(), - }, nil) - if err != nil { - return xerrors.Errorf("mpool push: %w", err) - } - - fmt.Println("Confirm Message CID:", smsg.Cid()) - - // wait for it to get mined into a block - wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) - if err != nil { - return err - } - - // check it executed successfully - if wait.Receipt.ExitCode.IsError() { - fmt.Fprintln(cctx.App.Writer, "Worker change failed!") - return err - } - - mi, err = api.StateMinerInfo(ctx, maddr, wait.TipSet) - if err != nil { - return err - } - if mi.Worker != newAddr { - return fmt.Errorf("Confirmed worker address change not reflected on chain: expected '%s', found '%s'", newAddr, mi.Worker) - } - - return nil - }, -} - -var actorConfirmChangeBeneficiary = &cli.Command{ - Name: "confirm-change-beneficiary", - Usage: "Confirm a beneficiary address change", - ArgsUsage: "[minerID]", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "really-do-it", - Usage: "Actually send transaction performing the action", - Value: false, - }, - &cli.BoolFlag{ - Name: "existing-beneficiary", - Usage: "send confirmation from the existing beneficiary address", - }, - &cli.BoolFlag{ - Name: "new-beneficiary", - Usage: "send confirmation from the new beneficiary address", - }, - }, - Action: func(cctx *cli.Context) error { - if cctx.NArg() != 1 { - return lcli.IncorrectNumArgs(cctx) - } - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return xerrors.Errorf("getting fullnode api: %w", err) - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - maddr, err := address.NewFromString(cctx.Args().First()) - if err != nil { - return xerrors.Errorf("parsing beneficiary address: %w", err) - } - - mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting miner info: %w", err) - } - - if mi.PendingBeneficiaryTerm == nil { - return fmt.Errorf("no pending beneficiary term found for miner %s", maddr) - } - - if (cctx.IsSet("existing-beneficiary") && cctx.IsSet("new-beneficiary")) || (!cctx.IsSet("existing-beneficiary") && !cctx.IsSet("new-beneficiary")) { - return lcli.ShowHelp(cctx, fmt.Errorf("must pass exactly one of --existing-beneficiary or --new-beneficiary")) - } - - var fromAddr address.Address - if cctx.IsSet("existing-beneficiary") { - if mi.PendingBeneficiaryTerm.ApprovedByBeneficiary { - return fmt.Errorf("beneficiary change already approved by current beneficiary") - } - fromAddr = mi.Beneficiary - } else { - if mi.PendingBeneficiaryTerm.ApprovedByNominee { - return fmt.Errorf("beneficiary change already approved by new beneficiary") - } - fromAddr = mi.PendingBeneficiaryTerm.NewBeneficiary - } - - fmt.Println("Confirming Pending Beneficiary Term of:") - fmt.Println("Beneficiary: ", mi.PendingBeneficiaryTerm.NewBeneficiary) - fmt.Println("Quota:", mi.PendingBeneficiaryTerm.NewQuota) - fmt.Println("Expiration Epoch:", mi.PendingBeneficiaryTerm.NewExpiration) - - if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action. Review what you're about to approve CAREFULLY please") - return nil - } - - params := &miner.ChangeBeneficiaryParams{ - NewBeneficiary: mi.PendingBeneficiaryTerm.NewBeneficiary, - NewQuota: mi.PendingBeneficiaryTerm.NewQuota, - NewExpiration: mi.PendingBeneficiaryTerm.NewExpiration, - } - - sp, err := actors.SerializeParams(params) - if err != nil { - return xerrors.Errorf("serializing params: %w", err) - } - - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - From: fromAddr, - To: maddr, - Method: builtin.MethodsMiner.ChangeBeneficiary, - Value: big.Zero(), - Params: sp, - }, nil) - if err != nil { - return xerrors.Errorf("mpool push: %w", err) - } - - fmt.Println("Confirm Message CID:", smsg.Cid()) - - // wait for it to get mined into a block - wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) - if err != nil { - return xerrors.Errorf("waiting for message to be included in block: %w", err) - } - - // check it executed successfully - if wait.Receipt.ExitCode.IsError() { - return fmt.Errorf("confirm beneficiary change failed with code %d", wait.Receipt.ExitCode) - } - - updatedMinerInfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - if updatedMinerInfo.PendingBeneficiaryTerm == nil && updatedMinerInfo.Beneficiary == mi.PendingBeneficiaryTerm.NewBeneficiary { - fmt.Println("Beneficiary address successfully changed") - } else { - fmt.Println("Beneficiary address change awaiting additional confirmations") - } - - return nil - }, -} - -var actorCompactAllocatedCmd = &cli.Command{ - Name: "compact-allocated", - Usage: "compact allocated sectors bitfield", - Flags: []cli.Flag{ - &cli.Uint64Flag{ - Name: "mask-last-offset", - Usage: "Mask sector IDs from 0 to 'highest_allocated - offset'", - }, - &cli.Uint64Flag{ - Name: "mask-upto-n", - Usage: "Mask sector IDs from 0 to 'n'", - }, - &cli.BoolFlag{ - Name: "really-do-it", - Usage: "Actually send transaction performing the action", - Value: false, - }, - }, - Action: func(cctx *cli.Context) error { - if !cctx.Bool("really-do-it") { - fmt.Println("Pass --really-do-it to actually execute this action") - return nil - } - - if !cctx.Args().Present() { - return fmt.Errorf("must pass address of new owner address") - } - - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - maddr, err := minerApi.ActorAddress(ctx) - if err != nil { - return err - } - - mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(api))) - - mst, err := lminer.Load(store, mact) - if err != nil { - return err - } - - allocs, err := mst.GetAllocatedSectors() - if err != nil { - return err - } - - var maskBf bitfield.BitField - - { - exclusiveFlags := []string{"mask-last-offset", "mask-upto-n"} - hasFlag := false - for _, f := range exclusiveFlags { - if hasFlag && cctx.IsSet(f) { - return xerrors.Errorf("more than one 'mask` flag set") - } - hasFlag = hasFlag || cctx.IsSet(f) - } - } - switch { - case cctx.IsSet("mask-last-offset"): - last, err := allocs.Last() - if err != nil { - return err - } - - m := cctx.Uint64("mask-last-offset") - if last <= m+1 { - return xerrors.Errorf("highest allocated sector lower than mask offset %d: %d", m+1, last) - } - // securty to not brick a miner - if last > 1<<60 { - return xerrors.Errorf("very high last sector number, refusing to mask: %d", last) - } - - maskBf, err = bitfield.NewFromIter(&rlepluslazy.RunSliceIterator{ - Runs: []rlepluslazy.Run{{Val: true, Len: last - m}}}) - if err != nil { - return xerrors.Errorf("forming bitfield: %w", err) - } - case cctx.IsSet("mask-upto-n"): - n := cctx.Uint64("mask-upto-n") - maskBf, err = bitfield.NewFromIter(&rlepluslazy.RunSliceIterator{ - Runs: []rlepluslazy.Run{{Val: true, Len: n}}}) - if err != nil { - return xerrors.Errorf("forming bitfield: %w", err) - } - default: - return xerrors.Errorf("no 'mask' flags set") - } - - mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - params := &miner.CompactSectorNumbersParams{ - MaskSectorNumbers: maskBf, - } - - sp, err := actors.SerializeParams(params) - if err != nil { - return xerrors.Errorf("serializing params: %w", err) - } - - smsg, err := api.MpoolPushMessage(ctx, &types.Message{ - From: mi.Worker, - To: maddr, - Method: builtin.MethodsMiner.CompactSectorNumbers, - Value: big.Zero(), - Params: sp, - }, nil) - if err != nil { - return xerrors.Errorf("mpool push: %w", err) - } - - fmt.Println("CompactSectorNumbers Message CID:", smsg.Cid()) - - // wait for it to get mined into a block - wait, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence) - if err != nil { - return err - } - - // check it executed successfully - if wait.Receipt.ExitCode.IsError() { - fmt.Println("Propose owner change failed!") - return err - } - - return nil - }, -} - -func isController(mi api.MinerInfo, addr address.Address) bool { - if addr == mi.Owner || addr == mi.Worker { - return true - } - - for _, ca := range mi.ControlAddresses { - if addr == ca { - return true - } - } - - return false -} diff --git a/cmd/lotus-miner/actor_test.go b/cmd/lotus-miner/actor_test.go index dfb4522137c..5f9e923e680 100644 --- a/cmd/lotus-miner/actor_test.go +++ b/cmd/lotus-miner/actor_test.go @@ -19,6 +19,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/cli/spcli" "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/node/repo" ) @@ -67,7 +68,7 @@ func TestWorkerKeyChange(t *testing.T) { // Initialize wallet. kit.SendFunds(ctx, t, client1, newKey, abi.NewTokenAmount(0)) - require.NoError(t, run(actorProposeChangeWorker, "--really-do-it", newKey.String())) + require.NoError(t, run(spcli.ActorProposeChangeWorkerCmd(LMActorGetter), "--really-do-it", newKey.String())) result := output.String() output.Reset() @@ -82,12 +83,12 @@ func TestWorkerKeyChange(t *testing.T) { require.NotZero(t, targetEpoch) // Too early. - require.Error(t, run(actorConfirmChangeWorker, "--really-do-it", newKey.String())) + require.Error(t, run(spcli.ActorConfirmChangeWorkerCmd(LMActorGetter), "--really-do-it", newKey.String())) output.Reset() client1.WaitTillChain(ctx, kit.HeightAtLeast(abi.ChainEpoch(targetEpoch))) - require.NoError(t, run(actorConfirmChangeWorker, "--really-do-it", newKey.String())) + require.NoError(t, run(spcli.ActorConfirmChangeWorkerCmd(LMActorGetter), "--really-do-it", newKey.String())) output.Reset() head, err := client1.ChainHead(ctx) diff --git a/cmd/lotus-miner/info.go b/cmd/lotus-miner/info.go index 6d8ade340ef..52b230daab0 100644 --- a/cmd/lotus-miner/info.go +++ b/cmd/lotus-miner/info.go @@ -29,6 +29,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin/reward" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/spcli" cliutil "github.com/filecoin-project/lotus/cli/util" "github.com/filecoin-project/lotus/journal/alerting" sealing "github.com/filecoin-project/lotus/storage/pipeline" @@ -369,94 +370,6 @@ func handleMiningInfo(ctx context.Context, cctx *cli.Context, fullapi v1api.Full return nil } -type stateMeta struct { - i int - col color.Attribute - state sealing.SectorState -} - -var stateOrder = map[sealing.SectorState]stateMeta{} -var stateList = []stateMeta{ - {col: 39, state: "Total"}, - {col: color.FgGreen, state: sealing.Proving}, - {col: color.FgGreen, state: sealing.Available}, - {col: color.FgGreen, state: sealing.UpdateActivating}, - - {col: color.FgMagenta, state: sealing.ReceiveSector}, - - {col: color.FgBlue, state: sealing.Empty}, - {col: color.FgBlue, state: sealing.WaitDeals}, - {col: color.FgBlue, state: sealing.AddPiece}, - {col: color.FgBlue, state: sealing.SnapDealsWaitDeals}, - {col: color.FgBlue, state: sealing.SnapDealsAddPiece}, - - {col: color.FgRed, state: sealing.UndefinedSectorState}, - {col: color.FgYellow, state: sealing.Packing}, - {col: color.FgYellow, state: sealing.GetTicket}, - {col: color.FgYellow, state: sealing.PreCommit1}, - {col: color.FgYellow, state: sealing.PreCommit2}, - {col: color.FgYellow, state: sealing.PreCommitting}, - {col: color.FgYellow, state: sealing.PreCommitWait}, - {col: color.FgYellow, state: sealing.SubmitPreCommitBatch}, - {col: color.FgYellow, state: sealing.PreCommitBatchWait}, - {col: color.FgYellow, state: sealing.WaitSeed}, - {col: color.FgYellow, state: sealing.Committing}, - {col: color.FgYellow, state: sealing.CommitFinalize}, - {col: color.FgYellow, state: sealing.SubmitCommit}, - {col: color.FgYellow, state: sealing.CommitWait}, - {col: color.FgYellow, state: sealing.SubmitCommitAggregate}, - {col: color.FgYellow, state: sealing.CommitAggregateWait}, - {col: color.FgYellow, state: sealing.FinalizeSector}, - {col: color.FgYellow, state: sealing.SnapDealsPacking}, - {col: color.FgYellow, state: sealing.UpdateReplica}, - {col: color.FgYellow, state: sealing.ProveReplicaUpdate}, - {col: color.FgYellow, state: sealing.SubmitReplicaUpdate}, - {col: color.FgYellow, state: sealing.ReplicaUpdateWait}, - {col: color.FgYellow, state: sealing.WaitMutable}, - {col: color.FgYellow, state: sealing.FinalizeReplicaUpdate}, - {col: color.FgYellow, state: sealing.ReleaseSectorKey}, - - {col: color.FgCyan, state: sealing.Terminating}, - {col: color.FgCyan, state: sealing.TerminateWait}, - {col: color.FgCyan, state: sealing.TerminateFinality}, - {col: color.FgCyan, state: sealing.TerminateFailed}, - {col: color.FgCyan, state: sealing.Removing}, - {col: color.FgCyan, state: sealing.Removed}, - {col: color.FgCyan, state: sealing.AbortUpgrade}, - - {col: color.FgRed, state: sealing.FailedUnrecoverable}, - {col: color.FgRed, state: sealing.AddPieceFailed}, - {col: color.FgRed, state: sealing.SealPreCommit1Failed}, - {col: color.FgRed, state: sealing.SealPreCommit2Failed}, - {col: color.FgRed, state: sealing.PreCommitFailed}, - {col: color.FgRed, state: sealing.ComputeProofFailed}, - {col: color.FgRed, state: sealing.RemoteCommitFailed}, - {col: color.FgRed, state: sealing.CommitFailed}, - {col: color.FgRed, state: sealing.CommitFinalizeFailed}, - {col: color.FgRed, state: sealing.PackingFailed}, - {col: color.FgRed, state: sealing.FinalizeFailed}, - {col: color.FgRed, state: sealing.Faulty}, - {col: color.FgRed, state: sealing.FaultReported}, - {col: color.FgRed, state: sealing.FaultedFinal}, - {col: color.FgRed, state: sealing.RemoveFailed}, - {col: color.FgRed, state: sealing.DealsExpired}, - {col: color.FgRed, state: sealing.RecoverDealIDs}, - {col: color.FgRed, state: sealing.SnapDealsAddPieceFailed}, - {col: color.FgRed, state: sealing.SnapDealsDealsExpired}, - {col: color.FgRed, state: sealing.ReplicaUpdateFailed}, - {col: color.FgRed, state: sealing.ReleaseSectorKeyFailed}, - {col: color.FgRed, state: sealing.FinalizeReplicaUpdateFailed}, -} - -func init() { - for i, state := range stateList { - stateOrder[state.state] = stateMeta{ - i: i, - col: state.col, - } - } -} - func sectorsInfo(ctx context.Context, mapi api.StorageMiner) error { summary, err := mapi.SectorsSummary(ctx) if err != nil { @@ -471,17 +384,17 @@ func sectorsInfo(ctx context.Context, mapi api.StorageMiner) error { } buckets["Total"] = total - var sorted []stateMeta + var sorted []spcli.StateMeta for state, i := range buckets { - sorted = append(sorted, stateMeta{i: i, state: state}) + sorted = append(sorted, spcli.StateMeta{I: i, State: state}) } sort.Slice(sorted, func(i, j int) bool { - return stateOrder[sorted[i].state].i < stateOrder[sorted[j].state].i + return spcli.StateOrder[sorted[i].State].I < spcli.StateOrder[sorted[j].State].I }) for _, s := range sorted { - _, _ = color.New(stateOrder[s.state].col).Printf("\t%s: %d\n", s.state, s.i) + _, _ = color.New(spcli.StateOrder[s.State].Col).Printf("\t%s: %d\n", s.State, s.I) } return nil diff --git a/cmd/lotus-miner/info_all.go b/cmd/lotus-miner/info_all.go index 2cf07385c00..5b83467a2f8 100644 --- a/cmd/lotus-miner/info_all.go +++ b/cmd/lotus-miner/info_all.go @@ -8,6 +8,7 @@ import ( "github.com/urfave/cli/v2" lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/spcli" ) var _test = false @@ -82,17 +83,17 @@ var infoAllCmd = &cli.Command{ } fmt.Println("\n#: Proving Info") - if err := provingInfoCmd.Action(cctx); err != nil { + if err := spcli.ProvingInfoCmd(LMActorOrEnvGetter).Action(cctx); err != nil { fmt.Println("ERROR: ", err) } fmt.Println("\n#: Proving Deadlines") - if err := provingDeadlinesCmd.Action(cctx); err != nil { + if err := spcli.ProvingDeadlinesCmd(LMActorOrEnvGetter).Action(cctx); err != nil { fmt.Println("ERROR: ", err) } fmt.Println("\n#: Proving Faults") - if err := provingFaultsCmd.Action(cctx); err != nil { + if err := spcli.ProvingFaultsCmd(LMActorOrEnvGetter).Action(cctx); err != nil { fmt.Println("ERROR: ", err) } @@ -237,7 +238,7 @@ var infoAllCmd = &cli.Command{ fmt.Printf("\n##: Sector %d Status\n", s) fs := &flag.FlagSet{} - for _, f := range sectorsStatusCmd.Flags { + for _, f := range spcli.SectorsStatusCmd(LMActorOrEnvGetter, getOnDiskInfo).Flags { if err := f.Apply(fs); err != nil { fmt.Println("ERROR: ", err) } @@ -246,7 +247,7 @@ var infoAllCmd = &cli.Command{ fmt.Println("ERROR: ", err) } - if err := sectorsStatusCmd.Action(cli.NewContext(cctx.App, fs, cctx)); err != nil { + if err := spcli.SectorsStatusCmd(LMActorOrEnvGetter, getOnDiskInfo).Action(cli.NewContext(cctx.App, fs, cctx)); err != nil { fmt.Println("ERROR: ", err) } diff --git a/cmd/lotus-miner/init.go b/cmd/lotus-miner/init.go index e27b2d716c6..9ab4e8b05b0 100644 --- a/cmd/lotus-miner/init.go +++ b/cmd/lotus-miner/init.go @@ -121,6 +121,11 @@ var initCmd = &cli.Command{ Name: "from", Usage: "select which address to send actor creation message from", }, + &cli.Uint64Flag{ + Name: "confidence", + Usage: "number of block confirmations to wait for", + Value: build.MessageConfidence, + }, }, Subcommands: []*cli.Command{ restoreCmd, @@ -147,6 +152,8 @@ var initCmd = &cli.Command{ return xerrors.Errorf("failed to parse gas-price flag: %s", err) } + confidence := cctx.Uint64("confidence") + symlink := cctx.Bool("symlink-imported-sectors") if symlink { log.Info("will attempt to symlink to imported sectors") @@ -266,7 +273,7 @@ var initCmd = &cli.Command{ } } - if err := storageMinerInit(ctx, cctx, api, r, ssize, gasPrice); err != nil { + if err := storageMinerInit(ctx, cctx, api, r, ssize, gasPrice, confidence); err != nil { log.Errorf("Failed to initialize lotus-miner: %+v", err) path, err := homedir.Expand(repoPath) if err != nil { @@ -415,7 +422,7 @@ func findMarketDealID(ctx context.Context, api v1api.FullNode, deal markettypes. return 0, xerrors.New("deal not found") } -func storageMinerInit(ctx context.Context, cctx *cli.Context, api v1api.FullNode, r repo.Repo, ssize abi.SectorSize, gasPrice types.BigInt) error { +func storageMinerInit(ctx context.Context, cctx *cli.Context, api v1api.FullNode, r repo.Repo, ssize abi.SectorSize, gasPrice types.BigInt, confidence uint64) error { lr, err := r.Lock(repo.StorageMiner) if err != nil { return err @@ -502,7 +509,7 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api v1api.FullNode return xerrors.Errorf("failed to start up genesis miner: %w", err) } - cerr := configureStorageMiner(ctx, api, a, peerid, gasPrice) + cerr := configureStorageMiner(ctx, api, a, peerid, gasPrice, confidence) if err := m.Stop(ctx); err != nil { log.Error("failed to shut down miner: ", err) @@ -542,13 +549,13 @@ func storageMinerInit(ctx context.Context, cctx *cli.Context, api v1api.FullNode } } - if err := configureStorageMiner(ctx, api, a, peerid, gasPrice); err != nil { + if err := configureStorageMiner(ctx, api, a, peerid, gasPrice, confidence); err != nil { return xerrors.Errorf("failed to configure miner: %w", err) } addr = a } else { - a, err := createStorageMiner(ctx, api, ssize, peerid, gasPrice, cctx) + a, err := createStorageMiner(ctx, api, ssize, peerid, gasPrice, confidence, cctx) if err != nil { return xerrors.Errorf("creating miner failed: %w", err) } @@ -590,7 +597,7 @@ func makeHostKey(lr repo.LockedRepo) (crypto.PrivKey, error) { return pk, nil } -func configureStorageMiner(ctx context.Context, api v1api.FullNode, addr address.Address, peerid peer.ID, gasPrice types.BigInt) error { +func configureStorageMiner(ctx context.Context, api v1api.FullNode, addr address.Address, peerid peer.ID, gasPrice types.BigInt, confidence uint64) error { mi, err := api.StateMinerInfo(ctx, addr, types.EmptyTSK) if err != nil { return xerrors.Errorf("getWorkerAddr returned bad address: %w", err) @@ -616,7 +623,7 @@ func configureStorageMiner(ctx context.Context, api v1api.FullNode, addr address } log.Info("Waiting for message: ", smsg.Cid()) - ret, err := api.StateWaitMsg(ctx, smsg.Cid(), build.MessageConfidence, lapi.LookbackNoLimit, true) + ret, err := api.StateWaitMsg(ctx, smsg.Cid(), confidence, lapi.LookbackNoLimit, true) if err != nil { return err } @@ -628,7 +635,7 @@ func configureStorageMiner(ctx context.Context, api v1api.FullNode, addr address return nil } -func createStorageMiner(ctx context.Context, api v1api.FullNode, ssize abi.SectorSize, peerid peer.ID, gasPrice types.BigInt, cctx *cli.Context) (address.Address, error) { +func createStorageMiner(ctx context.Context, api v1api.FullNode, ssize abi.SectorSize, peerid peer.ID, gasPrice types.BigInt, confidence uint64, cctx *cli.Context) (address.Address, error) { var err error var owner address.Address if cctx.String("owner") != "" { @@ -680,7 +687,7 @@ func createStorageMiner(ctx context.Context, api v1api.FullNode, ssize abi.Secto log.Infof("Initializing worker account %s, message: %s", worker, signed.Cid()) log.Infof("Waiting for confirmation") - mw, err := api.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence, lapi.LookbackNoLimit, true) + mw, err := api.StateWaitMsg(ctx, signed.Cid(), confidence, lapi.LookbackNoLimit, true) if err != nil { return address.Undef, xerrors.Errorf("waiting for worker init: %w", err) } @@ -704,7 +711,7 @@ func createStorageMiner(ctx context.Context, api v1api.FullNode, ssize abi.Secto log.Infof("Initializing owner account %s, message: %s", worker, signed.Cid()) log.Infof("Waiting for confirmation") - mw, err := api.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence, lapi.LookbackNoLimit, true) + mw, err := api.StateWaitMsg(ctx, signed.Cid(), confidence, lapi.LookbackNoLimit, true) if err != nil { return address.Undef, xerrors.Errorf("waiting for owner init: %w", err) } @@ -753,7 +760,7 @@ func createStorageMiner(ctx context.Context, api v1api.FullNode, ssize abi.Secto log.Infof("Pushed CreateMiner message: %s", signed.Cid()) log.Infof("Waiting for confirmation") - mw, err := api.StateWaitMsg(ctx, signed.Cid(), build.MessageConfidence, lapi.LookbackNoLimit, true) + mw, err := api.StateWaitMsg(ctx, signed.Cid(), confidence, lapi.LookbackNoLimit, true) if err != nil { return address.Undef, xerrors.Errorf("waiting for createMiner message: %w", err) } diff --git a/cmd/lotus-miner/init_restore.go b/cmd/lotus-miner/init_restore.go index 7e28729bbeb..272754c23d4 100644 --- a/cmd/lotus-miner/init_restore.go +++ b/cmd/lotus-miner/init_restore.go @@ -80,8 +80,7 @@ var restoreCmd = &cli.Command{ } log.Info("Configuring miner actor") - - if err := configureStorageMiner(ctx, api, maddr, peerid, big.Zero()); err != nil { + if err := configureStorageMiner(ctx, api, maddr, peerid, big.Zero(), cctx.Uint64("confidence")); err != nil { return err } diff --git a/cmd/lotus-miner/init_service.go b/cmd/lotus-miner/init_service.go index 235e4e4c8cc..876313941f9 100644 --- a/cmd/lotus-miner/init_service.go +++ b/cmd/lotus-miner/init_service.go @@ -105,7 +105,7 @@ var serviceCmd = &cli.Command{ if es.Contains(MarketsService) { log.Info("Configuring miner actor") - if err := configureStorageMiner(ctx, api, maddr, peerid, big.Zero()); err != nil { + if err := configureStorageMiner(ctx, api, maddr, peerid, big.Zero(), cctx.Uint64("confidence")); err != nil { return err } } diff --git a/cmd/lotus-miner/main.go b/cmd/lotus-miner/main.go index 911e98e260a..1fc7abfa8da 100644 --- a/cmd/lotus-miner/main.go +++ b/cmd/lotus-miner/main.go @@ -197,3 +197,17 @@ func setHidden(cmd *cli.Command) *cli.Command { cmd.Hidden = true return cmd } + +func LMActorOrEnvGetter(cctx *cli.Context) (address.Address, error) { + return getActorAddress(cctx.Context, cctx) +} + +func LMActorGetter(cctx *cli.Context) (address.Address, error) { + minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return address.Undef, err + } + defer closer() + + return minerApi.ActorAddress(cctx.Context) +} diff --git a/cmd/lotus-miner/precommits-info.go b/cmd/lotus-miner/precommits-info.go deleted file mode 100644 index 3f9e8c92742..00000000000 --- a/cmd/lotus-miner/precommits-info.go +++ /dev/null @@ -1,56 +0,0 @@ -package main - -import ( - "fmt" - "sort" - - cbor "github.com/ipfs/go-ipld-cbor" - "github.com/urfave/cli/v2" - - "github.com/filecoin-project/specs-actors/v7/actors/util/adt" - - "github.com/filecoin-project/lotus/blockstore" - "github.com/filecoin-project/lotus/chain/actors/builtin/miner" - "github.com/filecoin-project/lotus/chain/types" - lcli "github.com/filecoin-project/lotus/cli" -) - -var sectorPreCommitsCmd = &cli.Command{ - Name: "precommits", - Usage: "Print on-chain precommit info", - Action: func(cctx *cli.Context) error { - ctx := lcli.ReqContext(cctx) - mapi, closer, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - mact, err := mapi.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - store := adt.WrapStore(ctx, cbor.NewCborStore(blockstore.NewAPIBlockstore(mapi))) - mst, err := miner.Load(store, mact) - if err != nil { - return err - } - preCommitSector := make([]miner.SectorPreCommitOnChainInfo, 0) - err = mst.ForEachPrecommittedSector(func(info miner.SectorPreCommitOnChainInfo) error { - preCommitSector = append(preCommitSector, info) - return err - }) - less := func(i, j int) bool { - return preCommitSector[i].Info.SectorNumber <= preCommitSector[j].Info.SectorNumber - } - sort.Slice(preCommitSector, less) - for _, info := range preCommitSector { - fmt.Printf("%s: %s\n", info.Info.SectorNumber, info.PreCommitEpoch) - } - - return nil - }, -} diff --git a/cmd/lotus-miner/proving.go b/cmd/lotus-miner/proving.go index 2fc1427b520..9048da8e2b3 100644 --- a/cmd/lotus-miner/proving.go +++ b/cmd/lotus-miner/proving.go @@ -1,12 +1,10 @@ package main import ( - "bytes" "encoding/json" "fmt" "os" "strconv" - "strings" "sync" "text/tabwriter" "time" @@ -17,17 +15,13 @@ import ( "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/proof" - "github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/actors/builtin/miner" - "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" - cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/cli/spcli" "github.com/filecoin-project/lotus/storage/sealer/storiface" ) @@ -35,10 +29,10 @@ var provingCmd = &cli.Command{ Name: "proving", Usage: "View proving information", Subcommands: []*cli.Command{ - provingInfoCmd, - provingDeadlinesCmd, - provingDeadlineInfoCmd, - provingFaultsCmd, + spcli.ProvingInfoCmd(LMActorOrEnvGetter), + spcli.ProvingDeadlinesCmd(LMActorOrEnvGetter), + spcli.ProvingDeadlineInfoCmd(LMActorOrEnvGetter), + spcli.ProvingFaultsCmd(LMActorOrEnvGetter), provingCheckProvableCmd, workersCmd(false), provingComputeCmd, @@ -46,399 +40,6 @@ var provingCmd = &cli.Command{ }, } -var provingFaultsCmd = &cli.Command{ - Name: "faults", - Usage: "View the currently known proving faulty sectors information", - Action: func(cctx *cli.Context) error { - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - stor := store.ActorStore(ctx, blockstore.NewAPIBlockstore(api)) - - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - - mact, err := api.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - mas, err := miner.Load(stor, mact) - if err != nil { - return err - } - - fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) - - tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) - _, _ = fmt.Fprintln(tw, "deadline\tpartition\tsectors") - err = mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { - return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { - faults, err := part.FaultySectors() - if err != nil { - return err - } - return faults.ForEach(func(num uint64) error { - _, _ = fmt.Fprintf(tw, "%d\t%d\t%d\n", dlIdx, partIdx, num) - return nil - }) - }) - }) - if err != nil { - return err - } - return tw.Flush() - }, -} - -var provingInfoCmd = &cli.Command{ - Name: "info", - Usage: "View current state information", - Action: func(cctx *cli.Context) error { - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - - head, err := api.ChainHead(ctx) - if err != nil { - return xerrors.Errorf("getting chain head: %w", err) - } - - mact, err := api.StateGetActor(ctx, maddr, head.Key()) - if err != nil { - return err - } - - stor := store.ActorStore(ctx, blockstore.NewAPIBlockstore(api)) - - mas, err := miner.Load(stor, mact) - if err != nil { - return err - } - - cd, err := api.StateMinerProvingDeadline(ctx, maddr, head.Key()) - if err != nil { - return xerrors.Errorf("getting miner info: %w", err) - } - - fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) - - proving := uint64(0) - faults := uint64(0) - recovering := uint64(0) - curDeadlineSectors := uint64(0) - - if err := mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { - return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { - if bf, err := part.LiveSectors(); err != nil { - return err - } else if count, err := bf.Count(); err != nil { - return err - } else { - proving += count - if dlIdx == cd.Index { - curDeadlineSectors += count - } - } - - if bf, err := part.FaultySectors(); err != nil { - return err - } else if count, err := bf.Count(); err != nil { - return err - } else { - faults += count - } - - if bf, err := part.RecoveringSectors(); err != nil { - return err - } else if count, err := bf.Count(); err != nil { - return err - } else { - recovering += count - } - - return nil - }) - }); err != nil { - return xerrors.Errorf("walking miner deadlines and partitions: %w", err) - } - - var faultPerc float64 - if proving > 0 { - faultPerc = float64(faults * 100 / proving) - } - - fmt.Printf("Current Epoch: %d\n", cd.CurrentEpoch) - - fmt.Printf("Proving Period Boundary: %d\n", cd.PeriodStart%cd.WPoStProvingPeriod) - fmt.Printf("Proving Period Start: %s\n", cliutil.EpochTimeTs(cd.CurrentEpoch, cd.PeriodStart, head)) - fmt.Printf("Next Period Start: %s\n\n", cliutil.EpochTimeTs(cd.CurrentEpoch, cd.PeriodStart+cd.WPoStProvingPeriod, head)) - - fmt.Printf("Faults: %d (%.2f%%)\n", faults, faultPerc) - fmt.Printf("Recovering: %d\n", recovering) - - fmt.Printf("Deadline Index: %d\n", cd.Index) - fmt.Printf("Deadline Sectors: %d\n", curDeadlineSectors) - fmt.Printf("Deadline Open: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.Open)) - fmt.Printf("Deadline Close: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.Close)) - fmt.Printf("Deadline Challenge: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.Challenge)) - fmt.Printf("Deadline FaultCutoff: %s\n", cliutil.EpochTime(cd.CurrentEpoch, cd.FaultCutoff)) - return nil - }, -} - -var provingDeadlinesCmd = &cli.Command{ - Name: "deadlines", - Usage: "View the current proving period deadlines information", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "all", - Usage: "Count all sectors (only live sectors are counted by default)", - Aliases: []string{"a"}, - }, - }, - Action: func(cctx *cli.Context) error { - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - - deadlines, err := api.StateMinerDeadlines(ctx, maddr, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting deadlines: %w", err) - } - - di, err := api.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting deadlines: %w", err) - } - - fmt.Printf("Miner: %s\n", color.BlueString("%s", maddr)) - - tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) - _, _ = fmt.Fprintln(tw, "deadline\tpartitions\tsectors (faults)\tproven partitions") - - for dlIdx, deadline := range deadlines { - partitions, err := api.StateMinerPartitions(ctx, maddr, uint64(dlIdx), types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting partitions for deadline %d: %w", dlIdx, err) - } - - provenPartitions, err := deadline.PostSubmissions.Count() - if err != nil { - return err - } - - sectors := uint64(0) - faults := uint64(0) - var partitionCount int - - for _, partition := range partitions { - if !cctx.Bool("all") { - sc, err := partition.LiveSectors.Count() - if err != nil { - return err - } - - if sc > 0 { - partitionCount++ - } - - sectors += sc - } else { - sc, err := partition.AllSectors.Count() - if err != nil { - return err - } - - partitionCount++ - sectors += sc - } - - fc, err := partition.FaultySectors.Count() - if err != nil { - return err - } - - faults += fc - } - - var cur string - if di.Index == uint64(dlIdx) { - cur += "\t(current)" - } - _, _ = fmt.Fprintf(tw, "%d\t%d\t%d (%d)\t%d%s\n", dlIdx, partitionCount, sectors, faults, provenPartitions, cur) - } - - return tw.Flush() - }, -} - -var provingDeadlineInfoCmd = &cli.Command{ - Name: "deadline", - Usage: "View the current proving period deadline information by its index", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "sector-nums", - Aliases: []string{"n"}, - Usage: "Print sector/fault numbers belonging to this deadline", - }, - &cli.BoolFlag{ - Name: "bitfield", - Aliases: []string{"b"}, - Usage: "Print partition bitfield stats", - }, - }, - ArgsUsage: "", - Action: func(cctx *cli.Context) error { - - if cctx.NArg() != 1 { - return lcli.IncorrectNumArgs(cctx) - } - - dlIdx, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64) - if err != nil { - return xerrors.Errorf("could not parse deadline index: %w", err) - } - - api, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - - deadlines, err := api.StateMinerDeadlines(ctx, maddr, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting deadlines: %w", err) - } - - di, err := api.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting deadlines: %w", err) - } - - partitions, err := api.StateMinerPartitions(ctx, maddr, dlIdx, types.EmptyTSK) - if err != nil { - return xerrors.Errorf("getting partitions for deadline %d: %w", dlIdx, err) - } - - provenPartitions, err := deadlines[dlIdx].PostSubmissions.Count() - if err != nil { - return err - } - - fmt.Printf("Deadline Index: %d\n", dlIdx) - fmt.Printf("Partitions: %d\n", len(partitions)) - fmt.Printf("Proven Partitions: %d\n", provenPartitions) - fmt.Printf("Current: %t\n\n", di.Index == dlIdx) - - for pIdx, partition := range partitions { - fmt.Printf("Partition Index: %d\n", pIdx) - - printStats := func(bf bitfield.BitField, name string) error { - count, err := bf.Count() - if err != nil { - return err - } - - rit, err := bf.RunIterator() - if err != nil { - return err - } - - if cctx.Bool("bitfield") { - var ones, zeros, oneRuns, zeroRuns, invalid uint64 - for rit.HasNext() { - r, err := rit.NextRun() - if err != nil { - return xerrors.Errorf("next run: %w", err) - } - if !r.Valid() { - invalid++ - } - if r.Val { - ones += r.Len - oneRuns++ - } else { - zeros += r.Len - zeroRuns++ - } - } - - var buf bytes.Buffer - if err := bf.MarshalCBOR(&buf); err != nil { - return err - } - sz := len(buf.Bytes()) - szstr := types.SizeStr(types.NewInt(uint64(sz))) - - fmt.Printf("\t%s Sectors:%s%d (bitfield - runs %d+%d=%d - %d 0s %d 1s - %d inv - %s %dB)\n", name, strings.Repeat(" ", 18-len(name)), count, zeroRuns, oneRuns, zeroRuns+oneRuns, zeros, ones, invalid, szstr, sz) - } else { - fmt.Printf("\t%s Sectors:%s%d\n", name, strings.Repeat(" ", 18-len(name)), count) - } - - if cctx.Bool("sector-nums") { - nums, err := bf.All(count) - if err != nil { - return err - } - fmt.Printf("\t%s Sector Numbers:%s%v\n", name, strings.Repeat(" ", 12-len(name)), nums) - } - - return nil - } - - if err := printStats(partition.AllSectors, "All"); err != nil { - return err - } - if err := printStats(partition.LiveSectors, "Live"); err != nil { - return err - } - if err := printStats(partition.ActiveSectors, "Active"); err != nil { - return err - } - if err := printStats(partition.FaultySectors, "Faulty"); err != nil { - return err - } - if err := printStats(partition.RecoveringSectors, "Recovering"); err != nil { - return err - } - } - return nil - }, -} - var provingCheckProvableCmd = &cli.Command{ Name: "check", Usage: "Check sectors provable", diff --git a/cmd/lotus-miner/sealing.go b/cmd/lotus-miner/sealing.go index b2f4dcab911..ed2b2d2948a 100644 --- a/cmd/lotus-miner/sealing.go +++ b/cmd/lotus-miner/sealing.go @@ -151,7 +151,7 @@ func workersCmd(sealing bool) *cli.Command { ramTotal := stat.Info.Resources.MemPhysical ramTasks := stat.MemUsedMin ramUsed := stat.Info.Resources.MemUsed - var ramReserved uint64 = 0 + var ramReserved uint64 if ramUsed > ramTasks { ramReserved = ramUsed - ramTasks } @@ -167,7 +167,7 @@ func workersCmd(sealing bool) *cli.Command { vmemTotal := stat.Info.Resources.MemPhysical + stat.Info.Resources.MemSwap vmemTasks := stat.MemUsedMax vmemUsed := stat.Info.Resources.MemUsed + stat.Info.Resources.MemSwapUsed - var vmemReserved uint64 = 0 + var vmemReserved uint64 if vmemUsed > vmemTasks { vmemReserved = vmemUsed - vmemTasks } diff --git a/cmd/lotus-miner/sectors.go b/cmd/lotus-miner/sectors.go index 8b8fc65cbe5..cf32f424895 100644 --- a/cmd/lotus-miner/sectors.go +++ b/cmd/lotus-miner/sectors.go @@ -3,10 +3,7 @@ package main import ( "bufio" "encoding/csv" - "encoding/json" - "errors" "fmt" - "math" "os" "sort" "strconv" @@ -23,18 +20,16 @@ import ( "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/blockstore" - "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/adt" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" - "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/spcli" cliutil "github.com/filecoin-project/lotus/cli/util" "github.com/filecoin-project/lotus/lib/result" "github.com/filecoin-project/lotus/lib/strle" @@ -48,16 +43,16 @@ var sectorsCmd = &cli.Command{ Name: "sectors", Usage: "interact with sector store", Subcommands: []*cli.Command{ - sectorsStatusCmd, + spcli.SectorsStatusCmd(LMActorOrEnvGetter, getOnDiskInfo), sectorsListCmd, sectorsRefsCmd, sectorsUpdateCmd, sectorsPledgeCmd, sectorsNumbersCmd, - sectorPreCommitsCmd, - sectorsCheckExpireCmd, + spcli.SectorPreCommitsCmd(LMActorOrEnvGetter), + spcli.SectorsCheckExpireCmd(LMActorOrEnvGetter), sectorsExpiredCmd, - sectorsExtendCmd, + spcli.SectorsExtendCmd(LMActorOrEnvGetter), sectorsTerminateCmd, sectorsRemoveCmd, sectorsSnapUpCmd, @@ -67,11 +62,20 @@ var sectorsCmd = &cli.Command{ sectorsCapacityCollateralCmd, sectorsBatching, sectorsRefreshPieceMatchingCmd, - sectorsCompactPartitionsCmd, + spcli.SectorsCompactPartitionsCmd(LMActorOrEnvGetter), sectorsUnsealCmd, }, } +func getOnDiskInfo(cctx *cli.Context, id abi.SectorNumber, onChainInfo bool) (api.SectorInfo, error) { + minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return api.SectorInfo{}, err + } + defer closer() + return minerApi.SectorsStatus(cctx.Context, id, onChainInfo) +} + var sectorsPledgeCmd = &cli.Command{ Name: "pledge", Usage: "store random data in a sector", @@ -94,187 +98,6 @@ var sectorsPledgeCmd = &cli.Command{ }, } -var sectorsStatusCmd = &cli.Command{ - Name: "status", - Usage: "Get the seal status of a sector by its number", - ArgsUsage: "", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "log", - Usage: "display event log", - Aliases: []string{"l"}, - }, - &cli.BoolFlag{ - Name: "on-chain-info", - Usage: "show sector on chain info", - Aliases: []string{"c"}, - }, - &cli.BoolFlag{ - Name: "partition-info", - Usage: "show partition related info", - Aliases: []string{"p"}, - }, - &cli.BoolFlag{ - Name: "proof", - Usage: "print snark proof bytes as hex", - }, - }, - Action: func(cctx *cli.Context) error { - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := lcli.ReqContext(cctx) - - if cctx.NArg() != 1 { - return lcli.IncorrectNumArgs(cctx) - } - - id, err := strconv.ParseUint(cctx.Args().First(), 10, 64) - if err != nil { - return err - } - - onChainInfo := cctx.Bool("on-chain-info") - status, err := minerApi.SectorsStatus(ctx, abi.SectorNumber(id), onChainInfo) - if err != nil { - return err - } - - fmt.Printf("SectorID:\t%d\n", status.SectorID) - fmt.Printf("Status:\t\t%s\n", status.State) - fmt.Printf("CIDcommD:\t%s\n", status.CommD) - fmt.Printf("CIDcommR:\t%s\n", status.CommR) - fmt.Printf("Ticket:\t\t%x\n", status.Ticket.Value) - fmt.Printf("TicketH:\t%d\n", status.Ticket.Epoch) - fmt.Printf("Seed:\t\t%x\n", status.Seed.Value) - fmt.Printf("SeedH:\t\t%d\n", status.Seed.Epoch) - fmt.Printf("Precommit:\t%s\n", status.PreCommitMsg) - fmt.Printf("Commit:\t\t%s\n", status.CommitMsg) - if cctx.Bool("proof") { - fmt.Printf("Proof:\t\t%x\n", status.Proof) - } - fmt.Printf("Deals:\t\t%v\n", status.Deals) - fmt.Printf("Retries:\t%d\n", status.Retries) - if status.LastErr != "" { - fmt.Printf("Last Error:\t\t%s\n", status.LastErr) - } - - if onChainInfo { - fmt.Printf("\nSector On Chain Info\n") - fmt.Printf("SealProof:\t\t%x\n", status.SealProof) - fmt.Printf("Activation:\t\t%v\n", status.Activation) - fmt.Printf("Expiration:\t\t%v\n", status.Expiration) - fmt.Printf("DealWeight:\t\t%v\n", status.DealWeight) - fmt.Printf("VerifiedDealWeight:\t\t%v\n", status.VerifiedDealWeight) - fmt.Printf("InitialPledge:\t\t%v\n", types.FIL(status.InitialPledge)) - fmt.Printf("\nExpiration Info\n") - fmt.Printf("OnTime:\t\t%v\n", status.OnTime) - fmt.Printf("Early:\t\t%v\n", status.Early) - } - - if cctx.Bool("partition-info") { - fullApi, nCloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer nCloser() - - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - - mact, err := fullApi.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(fullApi), blockstore.NewMemory()) - mas, err := miner.Load(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), mact) - if err != nil { - return err - } - - errFound := errors.New("found") - if err := mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { - return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { - pas, err := part.AllSectors() - if err != nil { - return err - } - - set, err := pas.IsSet(id) - if err != nil { - return err - } - if set { - fmt.Printf("\nDeadline:\t%d\n", dlIdx) - fmt.Printf("Partition:\t%d\n", partIdx) - - checkIn := func(name string, bg func() (bitfield.BitField, error)) error { - bf, err := bg() - if err != nil { - return err - } - - set, err := bf.IsSet(id) - if err != nil { - return err - } - setstr := "no" - if set { - setstr = "yes" - } - fmt.Printf("%s: \t%s\n", name, setstr) - return nil - } - - if err := checkIn("Unproven", part.UnprovenSectors); err != nil { - return err - } - if err := checkIn("Live", part.LiveSectors); err != nil { - return err - } - if err := checkIn("Active", part.ActiveSectors); err != nil { - return err - } - if err := checkIn("Faulty", part.FaultySectors); err != nil { - return err - } - if err := checkIn("Recovering", part.RecoveringSectors); err != nil { - return err - } - - return errFound - } - - return nil - }) - }); err != errFound { - if err != nil { - return err - } - - fmt.Println("\nNot found in any partition") - } - } - - if cctx.Bool("log") { - fmt.Printf("--------\nEvent Log:\n") - - for i, l := range status.Log { - fmt.Printf("%d.\t%s:\t[%s]\t%s\n", i, time.Unix(int64(l.Timestamp), 0), l.Kind, l.Message) - if l.Trace != "" { - fmt.Printf("\t%s\n", l.Trace) - } - } - } - return nil - }, -} - var sectorsListCmd = &cli.Command{ Name: "list", Usage: "List sectors", @@ -501,7 +324,7 @@ var sectorsListCmd = &cli.Command{ m := map[string]interface{}{ "ID": s, - "State": color.New(stateOrder[sealing.SectorState(st.State)].col).Sprint(st.State), + "State": color.New(spcli.StateOrder[sealing.SectorState(st.State)].Col).Sprint(st.State), "OnChain": yesno(inSSet), "Active": yesno(inASet), } @@ -600,837 +423,189 @@ var sectorsListCmd = &cli.Command{ var sectorsListUpgradeBoundsCmd = &cli.Command{ Name: "upgrade-bounds", - Usage: "Output upgrade bounds for available sectors", - Flags: []cli.Flag{ - &cli.IntFlag{ - Name: "buckets", - Value: 25, - }, - &cli.BoolFlag{ - Name: "csv", - Usage: "output machine-readable values", - }, - &cli.BoolFlag{ - Name: "deal-terms", - Usage: "bucket by how many deal-sectors can start at a given expiration", - }, - }, - Action: func(cctx *cli.Context) error { - minerApi, closer, err := lcli.GetStorageMinerAPI(cctx, cliutil.StorageMinerUseHttp) - if err != nil { - return err - } - defer closer() - - fullApi, closer2, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer2() - - ctx := lcli.ReqContext(cctx) - - list, err := minerApi.SectorsListInStates(ctx, []api.SectorState{ - api.SectorState(sealing.Available), - }) - if err != nil { - return xerrors.Errorf("getting sector list: %w", err) - } - - head, err := fullApi.ChainHead(ctx) - if err != nil { - return xerrors.Errorf("getting chain head: %w", err) - } - - filter := bitfield.New() - - for _, s := range list { - filter.Set(uint64(s)) - } - - maddr, err := minerApi.ActorAddress(ctx) - if err != nil { - return err - } - - sset, err := fullApi.StateMinerSectors(ctx, maddr, &filter, head.Key()) - if err != nil { - return err - } - - if len(sset) == 0 { - return nil - } - - var minExpiration, maxExpiration abi.ChainEpoch - - for _, s := range sset { - if s.Expiration < minExpiration || minExpiration == 0 { - minExpiration = s.Expiration - } - if s.Expiration > maxExpiration { - maxExpiration = s.Expiration - } - } - - buckets := cctx.Int("buckets") - bucketSize := (maxExpiration - minExpiration) / abi.ChainEpoch(buckets) - bucketCounts := make([]int, buckets+1) - - for b := range bucketCounts { - bucketMin := minExpiration + abi.ChainEpoch(b)*bucketSize - bucketMax := minExpiration + abi.ChainEpoch(b+1)*bucketSize - - if cctx.Bool("deal-terms") { - bucketMax = bucketMax + policy.MarketDefaultAllocationTermBuffer - } - - for _, s := range sset { - isInBucket := s.Expiration >= bucketMin && s.Expiration < bucketMax - - if isInBucket { - bucketCounts[b]++ - } - } - - } - - // Creating CSV writer - writer := csv.NewWriter(os.Stdout) - - // Writing CSV headers - err = writer.Write([]string{"Max Expiration in Bucket", "Sector Count"}) - if err != nil { - return xerrors.Errorf("writing csv headers: %w", err) - } - - // Writing bucket details - - if cctx.Bool("csv") { - for i := 0; i < buckets; i++ { - maxExp := minExpiration + abi.ChainEpoch(i+1)*bucketSize - - timeStr := strconv.FormatInt(int64(maxExp), 10) - - err = writer.Write([]string{ - timeStr, - strconv.Itoa(bucketCounts[i]), - }) - if err != nil { - return xerrors.Errorf("writing csv row: %w", err) - } - } - - // Flush to make sure all data is written to the underlying writer - writer.Flush() - - if err := writer.Error(); err != nil { - return xerrors.Errorf("flushing csv writer: %w", err) - } - - return nil - } - - tw := tablewriter.New( - tablewriter.Col("Bucket Expiration"), - tablewriter.Col("Sector Count"), - tablewriter.Col("Bar"), - ) - - var barCols = 40 - var maxCount int - - for _, c := range bucketCounts { - if c > maxCount { - maxCount = c - } - } - - for i := 0; i < buckets; i++ { - maxExp := minExpiration + abi.ChainEpoch(i+1)*bucketSize - timeStr := cliutil.EpochTime(head.Height(), maxExp) - - tw.Write(map[string]interface{}{ - "Bucket Expiration": timeStr, - "Sector Count": color.YellowString("%d", bucketCounts[i]), - "Bar": "[" + color.GreenString(strings.Repeat("|", bucketCounts[i]*barCols/maxCount)) + strings.Repeat(" ", barCols-bucketCounts[i]*barCols/maxCount) + "]", - }) - } - - return tw.Flush(os.Stdout) - }, -} - -var sectorsRefsCmd = &cli.Command{ - Name: "refs", - Usage: "List References to sectors", - Action: func(cctx *cli.Context) error { - nodeApi, closer, err := lcli.GetMarketsAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := lcli.ReqContext(cctx) - - refs, err := nodeApi.SectorsRefs(ctx) - if err != nil { - return err - } - - for name, refs := range refs { - fmt.Printf("Block %s:\n", name) - for _, ref := range refs { - fmt.Printf("\t%d+%d %d bytes\n", ref.SectorID, ref.Offset, ref.Size) - } - } - return nil - }, -} - -var sectorsCheckExpireCmd = &cli.Command{ - Name: "check-expire", - Usage: "Inspect expiring sectors", - Flags: []cli.Flag{ - &cli.Int64Flag{ - Name: "cutoff", - Usage: "skip sectors whose current expiration is more than epochs from now, defaults to 60 days", - Value: 172800, - }, - }, - Action: func(cctx *cli.Context) error { - - fullApi, nCloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer nCloser() - - ctx := lcli.ReqContext(cctx) - - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - - head, err := fullApi.ChainHead(ctx) - if err != nil { - return err - } - currEpoch := head.Height() - - nv, err := fullApi.StateNetworkVersion(ctx, types.EmptyTSK) - if err != nil { - return err - } - - sectors, err := fullApi.StateMinerActiveSectors(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - n := 0 - for _, s := range sectors { - if s.Expiration-currEpoch <= abi.ChainEpoch(cctx.Int64("cutoff")) { - sectors[n] = s - n++ - } - } - sectors = sectors[:n] - - sort.Slice(sectors, func(i, j int) bool { - if sectors[i].Expiration == sectors[j].Expiration { - return sectors[i].SectorNumber < sectors[j].SectorNumber - } - return sectors[i].Expiration < sectors[j].Expiration - }) - - tw := tablewriter.New( - tablewriter.Col("ID"), - tablewriter.Col("SealProof"), - tablewriter.Col("InitialPledge"), - tablewriter.Col("Activation"), - tablewriter.Col("Expiration"), - tablewriter.Col("MaxExpiration"), - tablewriter.Col("MaxExtendNow")) - - for _, sector := range sectors { - MaxExpiration := sector.Activation + policy.GetSectorMaxLifetime(sector.SealProof, nv) - maxExtension, err := policy.GetMaxSectorExpirationExtension(nv) - if err != nil { - return xerrors.Errorf("failed to get max extension: %w", err) - } - - MaxExtendNow := currEpoch + maxExtension - - if MaxExtendNow > MaxExpiration { - MaxExtendNow = MaxExpiration - } - - tw.Write(map[string]interface{}{ - "ID": sector.SectorNumber, - "SealProof": sector.SealProof, - "InitialPledge": types.FIL(sector.InitialPledge).Short(), - "Activation": cliutil.EpochTime(currEpoch, sector.Activation), - "Expiration": cliutil.EpochTime(currEpoch, sector.Expiration), - "MaxExpiration": cliutil.EpochTime(currEpoch, MaxExpiration), - "MaxExtendNow": cliutil.EpochTime(currEpoch, MaxExtendNow), - }) - } - - return tw.Flush(os.Stdout) - }, -} - -type PseudoExpirationExtension struct { - Deadline uint64 - Partition uint64 - Sectors string - NewExpiration abi.ChainEpoch -} - -type PseudoExtendSectorExpirationParams struct { - Extensions []PseudoExpirationExtension -} - -func NewPseudoExtendParams(p *miner.ExtendSectorExpiration2Params) (*PseudoExtendSectorExpirationParams, error) { - res := PseudoExtendSectorExpirationParams{} - for _, ext := range p.Extensions { - scount, err := ext.Sectors.Count() - if err != nil { - return nil, err - } - - sectors, err := ext.Sectors.All(scount) - if err != nil { - return nil, err - } - - res.Extensions = append(res.Extensions, PseudoExpirationExtension{ - Deadline: ext.Deadline, - Partition: ext.Partition, - Sectors: ArrayToString(sectors), - NewExpiration: ext.NewExpiration, - }) - } - return &res, nil -} - -// ArrayToString Example: {1,3,4,5,8,9} -> "1,3-5,8-9" -func ArrayToString(array []uint64) string { - sort.Slice(array, func(i, j int) bool { - return array[i] < array[j] - }) - - var sarray []string - s := "" - - for i, elm := range array { - if i == 0 { - s = strconv.FormatUint(elm, 10) - continue - } - if elm == array[i-1] { - continue // filter out duplicates - } else if elm == array[i-1]+1 { - s = strings.Split(s, "-")[0] + "-" + strconv.FormatUint(elm, 10) - } else { - sarray = append(sarray, s) - s = strconv.FormatUint(elm, 10) - } - } - - if s != "" { - sarray = append(sarray, s) - } - - return strings.Join(sarray, ",") -} - -func getSectorsFromFile(filePath string) ([]abi.SectorNumber, error) { - file, err := os.Open(filePath) - if err != nil { - return nil, err - } - - scanner := bufio.NewScanner(file) - sectors := make([]abi.SectorNumber, 0) - - for scanner.Scan() { - line := scanner.Text() - - id, err := strconv.ParseUint(line, 10, 64) - if err != nil { - return nil, xerrors.Errorf("could not parse %s as sector id: %s", line, err) - } - - sectors = append(sectors, abi.SectorNumber(id)) - } - - if err = file.Close(); err != nil { - return nil, err - } - - return sectors, nil -} - -func SectorNumsToBitfield(sectors []abi.SectorNumber) bitfield.BitField { - var numbers []uint64 - for _, sector := range sectors { - numbers = append(numbers, uint64(sector)) - } - - return bitfield.NewFromSet(numbers) -} - -var sectorsExtendCmd = &cli.Command{ - Name: "extend", - Usage: "Extend expiring sectors while not exceeding each sector's max life", - ArgsUsage: "", - Flags: []cli.Flag{ - &cli.Int64Flag{ - Name: "from", - Usage: "only consider sectors whose current expiration epoch is in the range of [from, to], defaults to: now + 120 (1 hour)", - }, - &cli.Int64Flag{ - Name: "to", - Usage: "only consider sectors whose current expiration epoch is in the range of [from, to], defaults to: now + 92160 (32 days)", - }, - &cli.StringFlag{ - Name: "sector-file", - Usage: "provide a file containing one sector number in each line, ignoring above selecting criteria", - }, - &cli.StringFlag{ - Name: "exclude", - Usage: "optionally provide a file containing excluding sectors", - }, - &cli.Int64Flag{ - Name: "extension", - Usage: "try to extend selected sectors by this number of epochs, defaults to 540 days", - Value: 1555200, - }, - &cli.Int64Flag{ - Name: "new-expiration", - Usage: "try to extend selected sectors to this epoch, ignoring extension", - }, - &cli.BoolFlag{ - Name: "only-cc", - Usage: "only extend CC sectors (useful for making sector ready for snap upgrade)", - }, - &cli.BoolFlag{ - Name: "drop-claims", - Usage: "drop claims for sectors that can be extended, but only by dropping some of their verified power claims", - }, - &cli.Int64Flag{ - Name: "tolerance", - Usage: "don't try to extend sectors by fewer than this number of epochs, defaults to 7 days", - Value: 20160, - }, - &cli.StringFlag{ - Name: "max-fee", - 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", - }, - &cli.BoolFlag{ - Name: "really-do-it", - Usage: "pass this flag to really extend sectors, otherwise will only print out json representation of parameters", - }, - }, - Action: func(cctx *cli.Context) error { - mf, err := types.ParseFIL(cctx.String("max-fee")) - if err != nil { - return err - } - - spec := &api.MessageSendSpec{MaxFee: abi.TokenAmount(mf)} - - fullApi, nCloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer nCloser() - - ctx := lcli.ReqContext(cctx) - - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - - head, err := fullApi.ChainHead(ctx) - if err != nil { - return err - } - currEpoch := head.Height() - - nv, err := fullApi.StateNetworkVersion(ctx, types.EmptyTSK) - if err != nil { - return err - } - - activeSet, err := fullApi.StateMinerActiveSectors(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - activeSectorsInfo := make(map[abi.SectorNumber]*miner.SectorOnChainInfo, len(activeSet)) - for _, info := range activeSet { - activeSectorsInfo[info.SectorNumber] = info - } - - mact, err := fullApi.StateGetActor(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(fullApi), blockstore.NewMemory()) - adtStore := adt.WrapStore(ctx, cbor.NewCborStore(tbs)) - mas, err := miner.Load(adtStore, mact) - if err != nil { - return err - } - - activeSectorsLocation := make(map[abi.SectorNumber]*miner.SectorLocation, len(activeSet)) - - if err := mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { - return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { - pas, err := part.ActiveSectors() - if err != nil { - return err - } - - return pas.ForEach(func(i uint64) error { - activeSectorsLocation[abi.SectorNumber(i)] = &miner.SectorLocation{ - Deadline: dlIdx, - Partition: partIdx, - } - return nil - }) - }) - }); err != nil { - return err - } - - excludeSet := make(map[abi.SectorNumber]struct{}) - if cctx.IsSet("exclude") { - excludeSectors, err := getSectorsFromFile(cctx.String("exclude")) - if err != nil { - return err - } - - for _, id := range excludeSectors { - excludeSet[id] = struct{}{} - } - } - - var sectors []abi.SectorNumber - if cctx.Args().Present() { - if cctx.IsSet("sector-file") { - return xerrors.Errorf("sector-file specified along with command line params") - } - - for i, s := range cctx.Args().Slice() { - id, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return xerrors.Errorf("could not parse sector %d: %w", i, err) - } - - sectors = append(sectors, abi.SectorNumber(id)) - } - } else if cctx.IsSet("sector-file") { - sectors, err = getSectorsFromFile(cctx.String("sector-file")) - if err != nil { - return err - } - } else { - from := currEpoch + 120 - to := currEpoch + 92160 - - if cctx.IsSet("from") { - from = abi.ChainEpoch(cctx.Int64("from")) - } - - if cctx.IsSet("to") { - to = abi.ChainEpoch(cctx.Int64("to")) - } - - for _, si := range activeSet { - if si.Expiration >= from && si.Expiration <= to { - sectors = append(sectors, si.SectorNumber) - } - } - } - - var sis []*miner.SectorOnChainInfo - for _, id := range sectors { - if _, exclude := excludeSet[id]; exclude { - continue - } - - si, found := activeSectorsInfo[id] - if !found { - return xerrors.Errorf("sector %d is not active", id) - } - if len(si.DealIDs) > 0 && cctx.Bool("only-cc") { - continue - } - - sis = append(sis, si) - } - - withinTolerance := func(a, b abi.ChainEpoch) bool { - diff := a - b - if diff < 0 { - diff = -diff - } - - return diff <= abi.ChainEpoch(cctx.Int64("tolerance")) - } - - extensions := map[miner.SectorLocation]map[abi.ChainEpoch][]abi.SectorNumber{} - for _, si := range sis { - extension := abi.ChainEpoch(cctx.Int64("extension")) - newExp := si.Expiration + extension - - if cctx.IsSet("new-expiration") { - newExp = abi.ChainEpoch(cctx.Int64("new-expiration")) - } - - maxExtension, err := policy.GetMaxSectorExpirationExtension(nv) - if err != nil { - return xerrors.Errorf("failed to get max extension: %w", err) - } - - maxExtendNow := currEpoch + maxExtension - if newExp > maxExtendNow { - newExp = maxExtendNow - } - - maxExp := si.Activation + policy.GetSectorMaxLifetime(si.SealProof, nv) - if newExp > maxExp { - newExp = maxExp - } - - if newExp <= si.Expiration || withinTolerance(newExp, si.Expiration) { - continue - } - - l, found := activeSectorsLocation[si.SectorNumber] - if !found { - return xerrors.Errorf("location for sector %d not found", si.SectorNumber) - } - - es, found := extensions[*l] - if !found { - ne := make(map[abi.ChainEpoch][]abi.SectorNumber) - ne[newExp] = []abi.SectorNumber{si.SectorNumber} - extensions[*l] = ne - } else { - added := false - for exp := range es { - if withinTolerance(newExp, exp) { - es[exp] = append(es[exp], si.SectorNumber) - added = true - break - } - } - - if !added { - es[newExp] = []abi.SectorNumber{si.SectorNumber} - } - } + Usage: "Output upgrade bounds for available sectors", + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "buckets", + Value: 25, + }, + &cli.BoolFlag{ + Name: "csv", + Usage: "output machine-readable values", + }, + &cli.BoolFlag{ + Name: "deal-terms", + Usage: "bucket by how many deal-sectors can start at a given expiration", + }, + }, + Action: func(cctx *cli.Context) error { + minerApi, closer, err := lcli.GetStorageMinerAPI(cctx, cliutil.StorageMinerUseHttp) + if err != nil { + return err } + defer closer() - verifregAct, err := fullApi.StateGetActor(ctx, builtin.VerifiedRegistryActorAddr, types.EmptyTSK) + fullApi, closer2, err := lcli.GetFullNodeAPI(cctx) if err != nil { - return xerrors.Errorf("failed to lookup verifreg actor: %w", err) + return err } + defer closer2() + + ctx := lcli.ReqContext(cctx) - verifregSt, err := verifreg.Load(adtStore, verifregAct) + list, err := minerApi.SectorsListInStates(ctx, []api.SectorState{ + api.SectorState(sealing.Available), + }) if err != nil { - return xerrors.Errorf("failed to load verifreg state: %w", err) + return xerrors.Errorf("getting sector list: %w", err) } - claimsMap, err := verifregSt.GetClaims(maddr) + head, err := fullApi.ChainHead(ctx) if err != nil { - return xerrors.Errorf("failed to lookup claims for miner: %w", err) + return xerrors.Errorf("getting chain head: %w", err) } - claimIdsBySector, err := verifregSt.GetClaimIdsBySector(maddr) - if err != nil { - return xerrors.Errorf("failed to lookup claim IDs by sector: %w", err) + filter := bitfield.New() + + for _, s := range list { + filter.Set(uint64(s)) } - sectorsMax, err := policy.GetAddressedSectorsMax(nv) + maddr, err := minerApi.ActorAddress(ctx) if err != nil { return err } - declMax, err := policy.GetDeclarationsMax(nv) + sset, err := fullApi.StateMinerSectors(ctx, maddr, &filter, head.Key()) if err != nil { return err } - addrSectors := sectorsMax - if cctx.Int("max-sectors") != 0 { - addrSectors = cctx.Int("max-sectors") - if addrSectors > sectorsMax { - return xerrors.Errorf("the specified max-sectors exceeds the maximum limit") - } + if len(sset) == 0 { + return nil } - var params []miner.ExtendSectorExpiration2Params + var minExpiration, maxExpiration abi.ChainEpoch - p := miner.ExtendSectorExpiration2Params{} - scount := 0 + for _, s := range sset { + if s.Expiration < minExpiration || minExpiration == 0 { + minExpiration = s.Expiration + } + if s.Expiration > maxExpiration { + maxExpiration = s.Expiration + } + } - for l, exts := range extensions { - for newExp, numbers := range exts { - sectorsWithoutClaimsToExtend := bitfield.New() - var sectorsWithClaims []miner.SectorClaim - for _, sectorNumber := range numbers { - claimIdsToMaintain := make([]verifreg.ClaimId, 0) - claimIdsToDrop := make([]verifreg.ClaimId, 0) - cannotExtendSector := false - claimIds, ok := claimIdsBySector[sectorNumber] - // Nothing to check, add to ccSectors - if !ok { - sectorsWithoutClaimsToExtend.Set(uint64(sectorNumber)) - } else { - for _, claimId := range claimIds { - claim, ok := claimsMap[claimId] - if !ok { - return xerrors.Errorf("failed to find claim for claimId %d", claimId) - } - claimExpiration := claim.TermStart + claim.TermMax - // can be maintained in the extended sector - if claimExpiration > newExp { - claimIdsToMaintain = append(claimIdsToMaintain, claimId) - } else { - sectorInfo, ok := activeSectorsInfo[sectorNumber] - if !ok { - return xerrors.Errorf("failed to find sector in active sector set: %w", err) - } - if !cctx.Bool("drop-claims") || - // FIP-0045 requires the claim minimum duration to have passed - currEpoch <= (claim.TermStart+claim.TermMin) || - // FIP-0045 requires the sector to be in its last 30 days of life - (currEpoch <= sectorInfo.Expiration-builtin.EndOfLifeClaimDropPeriod) { - fmt.Printf("skipping sector %d because claim %d does not live long enough \n", sectorNumber, claimId) - cannotExtendSector = true - break - } - - claimIdsToDrop = append(claimIdsToDrop, claimId) - } - } - if cannotExtendSector { - continue - } + buckets := cctx.Int("buckets") + bucketSize := (maxExpiration - minExpiration) / abi.ChainEpoch(buckets) + bucketCounts := make([]int, buckets+1) - if len(claimIdsToMaintain)+len(claimIdsToDrop) != 0 { - sectorsWithClaims = append(sectorsWithClaims, miner.SectorClaim{ - SectorNumber: sectorNumber, - MaintainClaims: claimIdsToMaintain, - DropClaims: claimIdsToDrop, - }) - } - } - } + for b := range bucketCounts { + bucketMin := minExpiration + abi.ChainEpoch(b)*bucketSize + bucketMax := minExpiration + abi.ChainEpoch(b+1)*bucketSize - sectorsWithoutClaimsCount, err := sectorsWithoutClaimsToExtend.Count() - if err != nil { - return xerrors.Errorf("failed to count cc sectors: %w", err) - } + if cctx.Bool("deal-terms") { + bucketMax = bucketMax + policy.MarketDefaultAllocationTermBuffer + } - sectorsInDecl := int(sectorsWithoutClaimsCount) + len(sectorsWithClaims) - scount += sectorsInDecl + for _, s := range sset { + isInBucket := s.Expiration >= bucketMin && s.Expiration < bucketMax - if scount > addrSectors || len(p.Extensions) >= declMax { - params = append(params, p) - p = miner.ExtendSectorExpiration2Params{} - scount = sectorsInDecl + if isInBucket { + bucketCounts[b]++ } - - p.Extensions = append(p.Extensions, miner.ExpirationExtension2{ - Deadline: l.Deadline, - Partition: l.Partition, - Sectors: SectorNumsToBitfield(numbers), - SectorsWithClaims: sectorsWithClaims, - NewExpiration: newExp, - }) - } - } - // if we have any sectors, then one last append is needed here - if scount != 0 { - params = append(params, p) } - if len(params) == 0 { - fmt.Println("nothing to extend") - return nil - } + // Creating CSV writer + writer := csv.NewWriter(os.Stdout) - mi, err := fullApi.StateMinerInfo(ctx, maddr, types.EmptyTSK) + // Writing CSV headers + err = writer.Write([]string{"Max Expiration in Bucket", "Sector Count"}) if err != nil { - return xerrors.Errorf("getting miner info: %w", err) + return xerrors.Errorf("writing csv headers: %w", err) } - stotal := 0 + // Writing bucket details - for i := range params { - scount := 0 - for _, ext := range params[i].Extensions { - count, err := ext.Sectors.Count() - if err != nil { - return err - } - scount += int(count) - } - fmt.Printf("Extending %d sectors: ", scount) - stotal += scount + if cctx.Bool("csv") { + for i := 0; i < buckets; i++ { + maxExp := minExpiration + abi.ChainEpoch(i+1)*bucketSize - if !cctx.Bool("really-do-it") { - pp, err := NewPseudoExtendParams(¶ms[i]) - if err != nil { - return err - } + timeStr := strconv.FormatInt(int64(maxExp), 10) - data, err := json.MarshalIndent(pp, "", " ") + err = writer.Write([]string{ + timeStr, + strconv.Itoa(bucketCounts[i]), + }) if err != nil { - return err + return xerrors.Errorf("writing csv row: %w", err) } - - fmt.Println("\n", string(data)) - continue } - sp, aerr := actors.SerializeParams(¶ms[i]) - if aerr != nil { - return xerrors.Errorf("serializing params: %w", err) + // Flush to make sure all data is written to the underlying writer + writer.Flush() + + if err := writer.Error(); err != nil { + return xerrors.Errorf("flushing csv writer: %w", err) } - smsg, err := fullApi.MpoolPushMessage(ctx, &types.Message{ - From: mi.Worker, - To: maddr, - Method: builtin.MethodsMiner.ExtendSectorExpiration2, - Value: big.Zero(), - Params: sp, - }, spec) - if err != nil { - return xerrors.Errorf("mpool push message: %w", err) + return nil + } + + tw := tablewriter.New( + tablewriter.Col("Bucket Expiration"), + tablewriter.Col("Sector Count"), + tablewriter.Col("Bar"), + ) + + var barCols = 40 + var maxCount int + + for _, c := range bucketCounts { + if c > maxCount { + maxCount = c } + } + + for i := 0; i < buckets; i++ { + maxExp := minExpiration + abi.ChainEpoch(i+1)*bucketSize + timeStr := cliutil.EpochTime(head.Height(), maxExp) - fmt.Println(smsg.Cid()) + tw.Write(map[string]interface{}{ + "Bucket Expiration": timeStr, + "Sector Count": color.YellowString("%d", bucketCounts[i]), + "Bar": "[" + color.GreenString(strings.Repeat("|", bucketCounts[i]*barCols/maxCount)) + strings.Repeat(" ", barCols-bucketCounts[i]*barCols/maxCount) + "]", + }) + } + + return tw.Flush(os.Stdout) + }, +} + +var sectorsRefsCmd = &cli.Command{ + Name: "refs", + Usage: "List References to sectors", + Action: func(cctx *cli.Context) error { + nodeApi, closer, err := lcli.GetMarketsAPI(cctx) + if err != nil { + return err } + defer closer() + ctx := lcli.ReqContext(cctx) - fmt.Printf("%d sectors extended\n", stotal) + refs, err := nodeApi.SectorsRefs(ctx) + if err != nil { + return err + } + for name, refs := range refs { + fmt.Printf("Block %s:\n", name) + for _, ref := range refs { + fmt.Printf("\t%d+%d %d bytes\n", ref.SectorID, ref.Offset, ref.Size) + } + } return nil }, } @@ -2130,14 +1305,11 @@ var sectorsBatchingPendingCommit = &cli.Command{ return cctx.Command.Action(cctx) } else if userInput == "no" { return nil - } else { - fmt.Println("Invalid input. Please answer with 'yes' or 'no'.") - return nil } - - } else { - fmt.Println("No sectors queued to be committed") + fmt.Println("Invalid input. Please answer with 'yes' or 'no'.") + return nil } + fmt.Println("No sectors queued to be committed") return nil }, } @@ -2209,14 +1381,11 @@ var sectorsBatchingPendingPreCommit = &cli.Command{ return cctx.Command.Action(cctx) } else if userInput == "no" { return nil - } else { - fmt.Println("Invalid input. Please answer with 'yes' or 'no'.") - return nil } - - } else { - fmt.Println("No sectors queued to be committed") + fmt.Println("Invalid input. Please answer with 'yes' or 'no'.") + return nil } + fmt.Println("No sectors queued to be committed") return nil }, } @@ -2247,175 +1416,6 @@ func yesno(b bool) string { return color.RedString("NO") } -var sectorsCompactPartitionsCmd = &cli.Command{ - Name: "compact-partitions", - Usage: "removes dead sectors from partitions and reduces the number of partitions used if possible", - Flags: []cli.Flag{ - &cli.Uint64Flag{ - Name: "deadline", - Usage: "the deadline to compact the partitions in", - Required: true, - }, - &cli.Int64SliceFlag{ - Name: "partitions", - Usage: "list of partitions to compact sectors in", - Required: true, - }, - &cli.BoolFlag{ - Name: "really-do-it", - Usage: "Actually send transaction performing the action", - Value: false, - }, - &cli.StringFlag{ - Name: "actor", - Usage: "Specify the address of the miner to run this command", - }, - }, - Action: func(cctx *cli.Context) error { - fullNodeAPI, acloser, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer acloser() - - ctx := lcli.ReqContext(cctx) - - maddr, err := getActorAddress(ctx, cctx) - if err != nil { - return err - } - - minfo, err := fullNodeAPI.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - deadline := cctx.Uint64("deadline") - if deadline > miner.WPoStPeriodDeadlines { - return fmt.Errorf("deadline %d out of range", deadline) - } - - parts := cctx.Int64Slice("partitions") - if len(parts) <= 0 { - return fmt.Errorf("must include at least one partition to compact") - } - fmt.Printf("compacting %d paritions\n", len(parts)) - - var makeMsgForPartitions func(partitionsBf bitfield.BitField) ([]*types.Message, error) - makeMsgForPartitions = func(partitionsBf bitfield.BitField) ([]*types.Message, error) { - params := miner.CompactPartitionsParams{ - Deadline: deadline, - Partitions: partitionsBf, - } - - sp, aerr := actors.SerializeParams(¶ms) - if aerr != nil { - return nil, xerrors.Errorf("serializing params: %w", err) - } - - msg := &types.Message{ - From: minfo.Worker, - To: maddr, - Method: builtin.MethodsMiner.CompactPartitions, - Value: big.Zero(), - Params: sp, - } - - estimatedMsg, err := fullNodeAPI.GasEstimateMessageGas(ctx, msg, nil, types.EmptyTSK) - if err != nil && xerrors.Is(err, &api.ErrOutOfGas{}) { - // the message is too big -- split into 2 - partitionsSlice, err := partitionsBf.All(math.MaxUint64) - if err != nil { - return nil, err - } - - partitions1 := bitfield.New() - for i := 0; i < len(partitionsSlice)/2; i++ { - partitions1.Set(uint64(i)) - } - - msgs1, err := makeMsgForPartitions(partitions1) - if err != nil { - return nil, err - } - - // time for the second half - partitions2 := bitfield.New() - for i := len(partitionsSlice) / 2; i < len(partitionsSlice); i++ { - partitions2.Set(uint64(i)) - } - - msgs2, err := makeMsgForPartitions(partitions2) - if err != nil { - return nil, err - } - - return append(msgs1, msgs2...), nil - } else if err != nil { - return nil, err - } - - return []*types.Message{estimatedMsg}, nil - } - - partitions := bitfield.New() - for _, partition := range parts { - partitions.Set(uint64(partition)) - } - - msgs, err := makeMsgForPartitions(partitions) - if err != nil { - return xerrors.Errorf("failed to make messages: %w", err) - } - - // Actually send the messages if really-do-it provided, simulate otherwise - if cctx.Bool("really-do-it") { - smsgs, err := fullNodeAPI.MpoolBatchPushMessage(ctx, msgs, nil) - if err != nil { - return xerrors.Errorf("mpool push: %w", err) - } - - if len(smsgs) == 1 { - fmt.Printf("Requested compact partitions in message %s\n", smsgs[0].Cid()) - } else { - fmt.Printf("Requested compact partitions in %d messages\n\n", len(smsgs)) - for _, v := range smsgs { - fmt.Println(v.Cid()) - } - } - - for _, v := range smsgs { - wait, err := fullNodeAPI.StateWaitMsg(ctx, v.Cid(), 2) - if err != nil { - return err - } - - // check it executed successfully - if wait.Receipt.ExitCode.IsError() { - fmt.Println(cctx.App.Writer, "compact partitions msg %s failed!", v.Cid()) - return err - } - } - - return nil - } - - for i, v := range msgs { - fmt.Printf("total of %d CompactPartitions msgs would be sent\n", len(msgs)) - - estMsg, err := fullNodeAPI.GasEstimateMessageGas(ctx, v, nil, types.EmptyTSK) - if err != nil { - return err - } - - fmt.Printf("msg %d would cost up to %s\n", i+1, types.FIL(estMsg.RequiredFunds())) - } - - return nil - - }, -} - var sectorsNumbersCmd = &cli.Command{ Name: "numbers", Usage: "manage sector number assignments", diff --git a/cmd/lotus-miner/storage.go b/cmd/lotus-miner/storage.go index fdd5b569656..b39fe2bf750 100644 --- a/cmd/lotus-miner/storage.go +++ b/cmd/lotus-miner/storage.go @@ -27,6 +27,7 @@ import ( "github.com/filecoin-project/lotus/api/v0api" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/spcli" "github.com/filecoin-project/lotus/lib/tablewriter" sealing "github.com/filecoin-project/lotus/storage/pipeline" "github.com/filecoin-project/lotus/storage/sealer/fsutil" @@ -803,7 +804,7 @@ var storageListSectorsCmd = &cli.Command{ "Storage": color.New(sc1).Sprint(e.storage), "Sector": e.id, "Type": e.ft.String(), - "State": color.New(stateOrder[sealing.SectorState(e.state)].col).Sprint(e.state), + "State": color.New(spcli.StateOrder[sealing.SectorState(e.state)].Col).Sprint(e.state), "Primary": maybeStr(e.primary, color.FgGreen, "primary") + maybeStr(e.copy, color.FgBlue, "copy") + maybeStr(e.main, color.FgRed, "main"), "Path use": maybeStr(e.seal, color.FgMagenta, "seal ") + maybeStr(e.store, color.FgCyan, "store"), "URLs": e.urls, @@ -995,7 +996,7 @@ var storageLocks = &cli.Command{ return xerrors.Errorf("getting sector status(%d): %w", lock.Sector.Number, err) } - lockstr := fmt.Sprintf("%d\t%s\t", lock.Sector.Number, color.New(stateOrder[sealing.SectorState(st.State)].col).Sprint(st.State)) + lockstr := fmt.Sprintf("%d\t%s\t", lock.Sector.Number, color.New(spcli.StateOrder[sealing.SectorState(st.State)].Col).Sprint(st.State)) for i := 0; i < storiface.FileTypes; i++ { if lock.Write[i] > 0 { diff --git a/cmd/lotus-provider/config.go b/cmd/lotus-provider/config.go deleted file mode 100644 index 5bd6814293e..00000000000 --- a/cmd/lotus-provider/config.go +++ /dev/null @@ -1,259 +0,0 @@ -package main - -import ( - "context" - "database/sql" - "errors" - "fmt" - "io" - "os" - "path" - "strings" - - "github.com/BurntSushi/toml" - "github.com/urfave/cli/v2" - "golang.org/x/xerrors" - - "github.com/filecoin-project/lotus/lib/harmony/harmonydb" - "github.com/filecoin-project/lotus/node/config" -) - -var configCmd = &cli.Command{ - Name: "config", - Usage: "Manage node config by layers. The layer 'base' will always be applied. ", - Subcommands: []*cli.Command{ - configDefaultCmd, - configSetCmd, - configGetCmd, - configListCmd, - configViewCmd, - configRmCmd, - configMigrateCmd, - }, -} - -var configDefaultCmd = &cli.Command{ - Name: "default", - Aliases: []string{"defaults"}, - Usage: "Print default node config", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "no-comment", - Usage: "don't comment default values", - }, - }, - Action: func(cctx *cli.Context) error { - comment := !cctx.Bool("no-comment") - cfg, err := getDefaultConfig(comment) - if err != nil { - return err - } - fmt.Print(cfg) - - return nil - }, -} - -func getDefaultConfig(comment bool) (string, error) { - c := config.DefaultLotusProvider() - cb, err := config.ConfigUpdate(c, nil, config.Commented(comment), config.DefaultKeepUncommented(), config.NoEnv()) - if err != nil { - return "", err - } - return string(cb), nil -} - -var configSetCmd = &cli.Command{ - Name: "set", - Aliases: []string{"add", "update", "create"}, - Usage: "Set a config layer or the base by providing a filename or stdin.", - ArgsUsage: "a layer's file name", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "title", - Usage: "title of the config layer (req'd for stdin)", - }, - }, - Action: func(cctx *cli.Context) error { - args := cctx.Args() - - db, err := makeDB(cctx) - if err != nil { - return err - } - - name := cctx.String("title") - var stream io.Reader = os.Stdin - if args.Len() != 1 { - if cctx.String("title") == "" { - return errors.New("must have a title for stdin, or a file name") - } - } else { - stream, err = os.Open(args.First()) - if err != nil { - return fmt.Errorf("cannot open file %s: %w", args.First(), err) - } - if name == "" { - name = strings.Split(path.Base(args.First()), ".")[0] - } - } - bytes, err := io.ReadAll(stream) - if err != nil { - return fmt.Errorf("cannot read stream/file %w", err) - } - - lp := config.DefaultLotusProvider() // ensure it's toml - _, err = toml.Decode(string(bytes), lp) - if err != nil { - return fmt.Errorf("cannot decode file: %w", err) - } - _ = lp - - _, err = db.Exec(context.Background(), - `INSERT INTO harmony_config (title, config) VALUES ($1, $2) - ON CONFLICT (title) DO UPDATE SET config = excluded.config`, name, string(bytes)) - if err != nil { - return fmt.Errorf("unable to save config layer: %w", err) - } - - fmt.Println("Layer " + name + " created/updated") - return nil - }, -} - -var configGetCmd = &cli.Command{ - Name: "get", - Aliases: []string{"cat", "show"}, - Usage: "Get a config layer by name. You may want to pipe the output to a file, or use 'less'", - ArgsUsage: "layer name", - Action: func(cctx *cli.Context) error { - args := cctx.Args() - if args.Len() != 1 { - return fmt.Errorf("want 1 layer arg, got %d", args.Len()) - } - db, err := makeDB(cctx) - if err != nil { - return err - } - - var cfg string - err = db.QueryRow(context.Background(), `SELECT config FROM harmony_config WHERE title=$1`, args.First()).Scan(&cfg) - if err != nil { - return err - } - fmt.Println(cfg) - - return nil - }, -} - -var configListCmd = &cli.Command{ - Name: "list", - Aliases: []string{"ls"}, - Usage: "List config layers you can get.", - Flags: []cli.Flag{}, - Action: func(cctx *cli.Context) error { - db, err := makeDB(cctx) - if err != nil { - return err - } - var res []string - err = db.Select(context.Background(), &res, `SELECT title FROM harmony_config ORDER BY title`) - if err != nil { - return fmt.Errorf("unable to read from db: %w", err) - } - for _, r := range res { - fmt.Println(r) - } - - return nil - }, -} - -var configRmCmd = &cli.Command{ - Name: "remove", - Aliases: []string{"rm", "del", "delete"}, - Usage: "Remove a named config layer.", - Flags: []cli.Flag{}, - Action: func(cctx *cli.Context) error { - args := cctx.Args() - if args.Len() != 1 { - return errors.New("must have exactly 1 arg for the layer name") - } - db, err := makeDB(cctx) - if err != nil { - return err - } - ct, err := db.Exec(context.Background(), `DELETE FROM harmony_config WHERE title=$1`, args.First()) - if err != nil { - return fmt.Errorf("unable to read from db: %w", err) - } - if ct == 0 { - return fmt.Errorf("no layer named %s", args.First()) - } - - return nil - }, -} -var configViewCmd = &cli.Command{ - Name: "interpret", - Aliases: []string{"view", "stacked", "stack"}, - Usage: "Interpret stacked config layers by this version of lotus-provider, with system-generated comments.", - ArgsUsage: "a list of layers to be interpreted as the final config", - Flags: []cli.Flag{ - &cli.StringSliceFlag{ - Name: "layers", - Usage: "comma or space separated list of layers to be interpreted", - Value: cli.NewStringSlice("base"), - Required: true, - }, - }, - Action: func(cctx *cli.Context) error { - db, err := makeDB(cctx) - if err != nil { - return err - } - lp, err := getConfig(cctx, db) - if err != nil { - return err - } - cb, err := config.ConfigUpdate(lp, config.DefaultLotusProvider(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) - if err != nil { - return xerrors.Errorf("cannot interpret config: %w", err) - } - fmt.Println(string(cb)) - return nil - }, -} - -func getConfig(cctx *cli.Context, db *harmonydb.DB) (*config.LotusProviderConfig, error) { - lp := config.DefaultLotusProvider() - have := []string{} - layers := cctx.StringSlice("layers") - for _, layer := range layers { - text := "" - err := db.QueryRow(cctx.Context, `SELECT config FROM harmony_config WHERE title=$1`, layer).Scan(&text) - if err != nil { - if strings.Contains(err.Error(), sql.ErrNoRows.Error()) { - return nil, fmt.Errorf("missing layer '%s' ", layer) - } - if layer == "base" { - return nil, errors.New(`lotus-provider defaults to a layer named 'base'. - Either use 'migrate' command or edit a base.toml and upload it with: lotus-provider config set base.toml`) - } - return nil, fmt.Errorf("could not read layer '%s': %w", layer, err) - } - meta, err := toml.Decode(text, &lp) - if err != nil { - return nil, fmt.Errorf("could not read layer, bad toml %s: %w", layer, err) - } - for _, k := range meta.Keys() { - have = append(have, strings.Join(k, " ")) - } - } - _ = have // FUTURE: verify that required fields are here. - // If config includes 3rd-party config, consider JSONSchema as a way that - // 3rd-parties can dynamically include config requirements and we can - // validate the config. Because of layering, we must validate @ startup. - return lp, nil -} diff --git a/cmd/lotus-provider/migrate.go b/cmd/lotus-provider/migrate.go deleted file mode 100644 index 3869c7dfb97..00000000000 --- a/cmd/lotus-provider/migrate.go +++ /dev/null @@ -1,247 +0,0 @@ -package main - -import ( - "bytes" - "context" - "encoding/base64" - "errors" - "fmt" - "os" - "path" - "strings" - - "github.com/BurntSushi/toml" - "github.com/fatih/color" - "github.com/ipfs/go-datastore" - "github.com/samber/lo" - "github.com/urfave/cli/v2" - "golang.org/x/xerrors" - - "github.com/filecoin-project/go-address" - - cliutil "github.com/filecoin-project/lotus/cli/util" - "github.com/filecoin-project/lotus/lib/harmony/harmonydb" - "github.com/filecoin-project/lotus/node/config" - "github.com/filecoin-project/lotus/node/modules" - "github.com/filecoin-project/lotus/node/repo" -) - -var configMigrateCmd = &cli.Command{ - Name: "from-miner", - Usage: "Express a database config (for lotus-provider) from an existing miner.", - Description: "Express a database config (for lotus-provider) from an existing miner.", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: FlagMinerRepo, - Aliases: []string{FlagMinerRepoDeprecation}, - EnvVars: []string{"LOTUS_MINER_PATH", "LOTUS_STORAGE_PATH"}, - Value: "~/.lotusminer", - Usage: fmt.Sprintf("Specify miner repo path. flag(%s) and env(LOTUS_STORAGE_PATH) are DEPRECATION, will REMOVE SOON", FlagMinerRepoDeprecation), - }, - &cli.StringFlag{ - Name: "repo", - EnvVars: []string{"LOTUS_PATH"}, - Hidden: true, - Value: "~/.lotus", - }, - &cli.StringFlag{ - Name: "to-layer", - Aliases: []string{"t"}, - Usage: "The layer name for this data push. 'base' is recommended for single-miner setup.", - }, - &cli.BoolFlag{ - Name: "overwrite", - Aliases: []string{"o"}, - Usage: "Use this with --to-layer to replace an existing layer", - }, - }, - Action: fromMiner, -} - -const ( - FlagMinerRepo = "miner-repo" -) - -const FlagMinerRepoDeprecation = "storagerepo" - -func fromMiner(cctx *cli.Context) (err error) { - ctx := context.Background() - cliCommandColor := color.New(color.FgHiBlue).SprintFunc() - configColor := color.New(color.FgHiGreen).SprintFunc() - - r, err := repo.NewFS(cctx.String(FlagMinerRepo)) - if err != nil { - return err - } - - ok, err := r.Exists() - if err != nil { - return err - } - - if !ok { - return fmt.Errorf("repo not initialized") - } - - lr, err := r.LockRO(repo.StorageMiner) - if err != nil { - return fmt.Errorf("locking repo: %w", err) - } - defer func() { _ = lr.Close() }() - - cfgNode, err := lr.Config() - if err != nil { - return fmt.Errorf("getting node config: %w", err) - } - smCfg := cfgNode.(*config.StorageMiner) - - db, err := harmonydb.NewFromConfig(smCfg.HarmonyDB) - if err != nil { - return fmt.Errorf("could not reach the database. Ensure the Miner config toml's HarmonyDB entry"+ - " is setup to reach Yugabyte correctly: %w", err) - } - - var titles []string - err = db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) - if err != nil { - return fmt.Errorf("miner cannot reach the db. Ensure the config toml's HarmonyDB entry"+ - " is setup to reach Yugabyte correctly: %s", err.Error()) - } - name := cctx.String("to-layer") - if name == "" { - name = fmt.Sprintf("mig%d", len(titles)) - } else { - if lo.Contains(titles, name) && !cctx.Bool("overwrite") { - return errors.New("the overwrite flag is needed to replace existing layer: " + name) - } - } - msg := "Layer " + configColor(name) + ` created. ` - - // Copy over identical settings: - - buf, err := os.ReadFile(path.Join(lr.Path(), "config.toml")) - if err != nil { - return fmt.Errorf("could not read config.toml: %w", err) - } - var lpCfg config.LotusProviderConfig - _, err = toml.Decode(string(buf), &lpCfg) - if err != nil { - return fmt.Errorf("could not decode toml: %w", err) - } - - // Populate Miner Address - mmeta, err := lr.Datastore(ctx, "/metadata") - if err != nil { - return xerrors.Errorf("opening miner metadata datastore: %w", err) - } - defer func() { - _ = mmeta.Close() - }() - - maddrBytes, err := mmeta.Get(ctx, datastore.NewKey("miner-address")) - if err != nil { - return xerrors.Errorf("getting miner address datastore entry: %w", err) - } - - addr, err := address.NewFromBytes(maddrBytes) - if err != nil { - return xerrors.Errorf("parsing miner actor address: %w", err) - } - - lpCfg.Addresses.MinerAddresses = []string{addr.String()} - - ks, err := lr.KeyStore() - if err != nil { - return xerrors.Errorf("keystore err: %w", err) - } - js, err := ks.Get(modules.JWTSecretName) - if err != nil { - return xerrors.Errorf("error getting JWTSecretName: %w", err) - } - - lpCfg.Apis.StorageRPCSecret = base64.StdEncoding.EncodeToString(js.PrivateKey) - - // Populate API Key - _, header, err := cliutil.GetRawAPI(cctx, repo.FullNode, "v0") - if err != nil { - return fmt.Errorf("cannot read API: %w", err) - } - - ainfo, err := cliutil.GetAPIInfo(&cli.Context{}, repo.FullNode) - if err != nil { - return xerrors.Errorf(`could not get API info for FullNode: %w - Set the environment variable to the value of "lotus auth api-info --perm=admin"`, err) - } - lpCfg.Apis.ChainApiInfo = []string{header.Get("Authorization")[7:] + ":" + ainfo.Addr} - - // Enable WindowPoSt - lpCfg.Subsystems.EnableWindowPost = true - msg += "\nBefore running lotus-provider, ensure any miner/worker answering of WindowPost is disabled by " + - "(on Miner) " + configColor("DisableBuiltinWindowPoSt=true") + " and (on Workers) not enabling windowpost on CLI or via " + - "environment variable " + configColor("LOTUS_WORKER_WINDOWPOST") + "." - - // Express as configTOML - configTOML := &bytes.Buffer{} - if err = toml.NewEncoder(configTOML).Encode(lpCfg); err != nil { - return err - } - - if !lo.Contains(titles, "base") { - cfg, err := getDefaultConfig(true) - if err != nil { - return xerrors.Errorf("Cannot get default config: %w", err) - } - _, err = db.Exec(ctx, "INSERT INTO harmony_config (title, config) VALUES ('base', $1)", cfg) - - if err != nil { - return err - } - } - - if cctx.Bool("overwrite") { - i, err := db.Exec(ctx, "DELETE FROM harmony_config WHERE title=$1", name) - if i != 0 { - fmt.Println("Overwriting existing layer") - } - if err != nil { - fmt.Println("Got error while deleting existing layer: " + err.Error()) - } - } - - _, err = db.Exec(ctx, "INSERT INTO harmony_config (title, config) VALUES ($1, $2)", name, configTOML.String()) - if err != nil { - return err - } - - dbSettings := "" - def := config.DefaultStorageMiner().HarmonyDB - if def.Hosts[0] != smCfg.HarmonyDB.Hosts[0] { - dbSettings += ` --db-host="` + strings.Join(smCfg.HarmonyDB.Hosts, ",") + `"` - } - if def.Port != smCfg.HarmonyDB.Port { - dbSettings += " --db-port=" + smCfg.HarmonyDB.Port - } - if def.Username != smCfg.HarmonyDB.Username { - dbSettings += ` --db-user="` + smCfg.HarmonyDB.Username + `"` - } - if def.Password != smCfg.HarmonyDB.Password { - dbSettings += ` --db-password="` + smCfg.HarmonyDB.Password + `"` - } - if def.Database != smCfg.HarmonyDB.Database { - dbSettings += ` --db-name="` + smCfg.HarmonyDB.Database + `"` - } - - var layerMaybe string - if name != "base" { - layerMaybe = "--layer=" + name - } - - msg += ` -To work with the config: -` + cliCommandColor(`lotus-provider `+dbSettings+` config help `) - msg += ` -To run Lotus Provider: in its own machine or cgroup without other files, use the command: -` + cliCommandColor(`lotus-provider `+dbSettings+` run `+layerMaybe) - fmt.Println(msg) - return nil -} diff --git a/cmd/lotus-provider/rpc/rpc.go b/cmd/lotus-provider/rpc/rpc.go deleted file mode 100644 index 3ae3e2a1fae..00000000000 --- a/cmd/lotus-provider/rpc/rpc.go +++ /dev/null @@ -1,51 +0,0 @@ -package rpc - -import ( - "context" - "net/http" - - "github.com/gorilla/mux" - - // logging "github.com/ipfs/go-log/v2" - "github.com/filecoin-project/go-jsonrpc" - "github.com/filecoin-project/go-jsonrpc/auth" - - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/lib/rpcenc" - "github.com/filecoin-project/lotus/metrics/proxy" -) - -//var log = logging.Logger("lp/rpc") - -func LotusProviderHandler( - authv func(ctx context.Context, token string) ([]auth.Permission, error), - remote http.HandlerFunc, - a api.LotusProvider, - permissioned bool) http.Handler { - mux := mux.NewRouter() - readerHandler, readerServerOpt := rpcenc.ReaderParamDecoder() - rpcServer := jsonrpc.NewServer(jsonrpc.WithServerErrors(api.RPCErrors), readerServerOpt) - - wapi := proxy.MetricedAPI[api.LotusProvider, api.LotusProviderStruct](a) - if permissioned { - wapi = api.PermissionedAPI[api.LotusProvider, api.LotusProviderStruct](wapi) - } - - rpcServer.Register("Filecoin", wapi) - rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover") - - mux.Handle("/rpc/v0", rpcServer) - mux.Handle("/rpc/streams/v0/push/{uuid}", readerHandler) - mux.PathPrefix("/remote").HandlerFunc(remote) - mux.PathPrefix("/").Handler(http.DefaultServeMux) // pprof - - if !permissioned { - return mux - } - - ah := &auth.Handler{ - Verify: authv, - Next: mux.ServeHTTP, - } - return ah -} diff --git a/cmd/lotus-provider/run.go b/cmd/lotus-provider/run.go deleted file mode 100644 index de97aa76603..00000000000 --- a/cmd/lotus-provider/run.go +++ /dev/null @@ -1,467 +0,0 @@ -package main - -import ( - "context" - "encoding/base64" - "encoding/json" - "fmt" - "net" - "net/http" - "os" - "strings" - "time" - - "github.com/gbrlsnchs/jwt/v3" - "github.com/gorilla/mux" - ds "github.com/ipfs/go-datastore" - dssync "github.com/ipfs/go-datastore/sync" - "github.com/pkg/errors" - "github.com/samber/lo" - "github.com/urfave/cli/v2" - "go.opencensus.io/stats" - "go.opencensus.io/tag" - "golang.org/x/xerrors" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-jsonrpc/auth" - "github.com/filecoin-project/go-statestore" - - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - lcli "github.com/filecoin-project/lotus/cli" - cliutil "github.com/filecoin-project/lotus/cli/util" - "github.com/filecoin-project/lotus/cmd/lotus-provider/rpc" - "github.com/filecoin-project/lotus/journal" - "github.com/filecoin-project/lotus/journal/alerting" - "github.com/filecoin-project/lotus/journal/fsjournal" - "github.com/filecoin-project/lotus/lib/harmony/harmonydb" - "github.com/filecoin-project/lotus/lib/harmony/harmonytask" - "github.com/filecoin-project/lotus/lib/ulimit" - "github.com/filecoin-project/lotus/metrics" - "github.com/filecoin-project/lotus/node" - "github.com/filecoin-project/lotus/node/config" - "github.com/filecoin-project/lotus/node/modules/dtypes" - "github.com/filecoin-project/lotus/node/repo" - "github.com/filecoin-project/lotus/provider" - "github.com/filecoin-project/lotus/provider/lpmessage" - "github.com/filecoin-project/lotus/provider/lpwinning" - "github.com/filecoin-project/lotus/storage/ctladdr" - "github.com/filecoin-project/lotus/storage/paths" - "github.com/filecoin-project/lotus/storage/sealer" - "github.com/filecoin-project/lotus/storage/sealer/ffiwrapper" - "github.com/filecoin-project/lotus/storage/sealer/storiface" -) - -type stackTracer interface { - StackTrace() errors.StackTrace -} - -var runCmd = &cli.Command{ - Name: "run", - Usage: "Start a lotus provider process", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "listen", - Usage: "host address and port the worker api will listen on", - Value: "0.0.0.0:12300", - EnvVars: []string{"LOTUS_WORKER_LISTEN"}, - }, - &cli.BoolFlag{ - Name: "nosync", - Usage: "don't check full-node sync status", - }, - &cli.BoolFlag{ - Name: "halt-after-init", - Usage: "only run init, then return", - Hidden: true, - }, - &cli.BoolFlag{ - Name: "manage-fdlimit", - Usage: "manage open file limit", - Value: true, - }, - &cli.StringSliceFlag{ - Name: "layers", - Usage: "list of layers to be interpreted (atop defaults). Default: base", - Value: cli.NewStringSlice("base"), - }, - &cli.StringFlag{ - Name: "storage-json", - Usage: "path to json file containing storage config", - Value: "~/.lotus-provider/storage.json", - }, - &cli.StringFlag{ - Name: "journal", - Usage: "path to journal files", - Value: "~/.lotus-provider/", - }, - }, - Action: func(cctx *cli.Context) (err error) { - defer func() { - if err != nil { - if err, ok := err.(stackTracer); ok { - for _, f := range err.StackTrace() { - fmt.Printf("%+s:%d\n", f, f) - } - } - } - }() - if !cctx.Bool("enable-gpu-proving") { - err := os.Setenv("BELLMAN_NO_GPU", "true") - if err != nil { - return err - } - } - - ctx, _ := tag.New(lcli.DaemonContext(cctx), - tag.Insert(metrics.Version, build.BuildVersion), - tag.Insert(metrics.Commit, build.CurrentCommit), - tag.Insert(metrics.NodeType, "provider"), - ) - shutdownChan := make(chan struct{}) - { - var ctxclose func() - ctx, ctxclose = context.WithCancel(ctx) - go func() { - <-shutdownChan - ctxclose() - }() - } - // Register all metric views - /* - if err := view.Register( - metrics.MinerNodeViews..., - ); err != nil { - log.Fatalf("Cannot register the view: %v", err) - } - */ - // Set the metric to one so it is published to the exporter - stats.Record(ctx, metrics.LotusInfo.M(1)) - - if cctx.Bool("manage-fdlimit") { - if _, _, err := ulimit.ManageFdLimit(); err != nil { - log.Errorf("setting file descriptor limit: %s", err) - } - } - - deps, err := getDeps(ctx, cctx) - - if err != nil { - return err - } - cfg, db, full, verif, lw, as, maddrs, stor, si, localStore := deps.cfg, deps.db, deps.full, deps.verif, deps.lw, deps.as, deps.maddrs, deps.stor, deps.si, deps.localStore - - var activeTasks []harmonytask.TaskInterface - - sender, sendTask := lpmessage.NewSender(full, full, db) - activeTasks = append(activeTasks, sendTask) - - /////////////////////////////////////////////////////////////////////// - ///// Task Selection - /////////////////////////////////////////////////////////////////////// - { - - if cfg.Subsystems.EnableWindowPost { - wdPostTask, wdPoStSubmitTask, derlareRecoverTask, err := provider.WindowPostScheduler(ctx, cfg.Fees, cfg.Proving, full, verif, lw, sender, - as, maddrs, db, stor, si, cfg.Subsystems.WindowPostMaxTasks) - if err != nil { - return err - } - activeTasks = append(activeTasks, wdPostTask, wdPoStSubmitTask, derlareRecoverTask) - } - - if cfg.Subsystems.EnableWinningPost { - winPoStTask := lpwinning.NewWinPostTask(cfg.Subsystems.WinningPostMaxTasks, db, lw, verif, full, maddrs) - activeTasks = append(activeTasks, winPoStTask) - } - } - log.Infow("This lotus_provider instance handles", - "miner_addresses", minerAddressesToStrings(maddrs), - "tasks", lo.Map(activeTasks, func(t harmonytask.TaskInterface, _ int) string { return t.TypeDetails().Name })) - - taskEngine, err := harmonytask.New(db, activeTasks, deps.listenAddr) - if err != nil { - return err - } - - defer taskEngine.GracefullyTerminate(time.Hour) - - fh := &paths.FetchHandler{Local: localStore, PfHandler: &paths.DefaultPartialFileHandler{}} - remoteHandler := func(w http.ResponseWriter, r *http.Request) { - if !auth.HasPerm(r.Context(), nil, api.PermAdmin) { - w.WriteHeader(401) - _ = json.NewEncoder(w).Encode(struct{ Error string }{"unauthorized: missing admin permission"}) - return - } - - fh.ServeHTTP(w, r) - } - // local APIs - { - // debugging - mux := mux.NewRouter() - mux.PathPrefix("/").Handler(http.DefaultServeMux) // pprof - mux.PathPrefix("/remote").HandlerFunc(remoteHandler) - - /*ah := &auth.Handler{ - Verify: authv, - Next: mux.ServeHTTP, - }*/ // todo - - } - - var authVerify func(context.Context, string) ([]auth.Permission, error) - { - privateKey, err := base64.StdEncoding.DecodeString(deps.cfg.Apis.StorageRPCSecret) - if err != nil { - return xerrors.Errorf("decoding storage rpc secret: %w", err) - } - authVerify = func(ctx context.Context, token string) ([]auth.Permission, error) { - var payload jwtPayload - if _, err := jwt.Verify([]byte(token), jwt.NewHS256(privateKey), &payload); err != nil { - return nil, xerrors.Errorf("JWT Verification failed: %w", err) - } - - return payload.Allow, nil - } - } - // Serve the RPC. - srv := &http.Server{ - Handler: rpc.LotusProviderHandler( - authVerify, - remoteHandler, - &ProviderAPI{deps, shutdownChan}, - true), - ReadHeaderTimeout: time.Minute * 3, - BaseContext: func(listener net.Listener) context.Context { - ctx, _ := tag.New(context.Background(), tag.Upsert(metrics.APIInterface, "lotus-worker")) - return ctx - }, - } - - go func() { - <-ctx.Done() - log.Warn("Shutting down...") - if err := srv.Shutdown(context.TODO()); err != nil { - log.Errorf("shutting down RPC server failed: %s", err) - } - log.Warn("Graceful shutdown successful") - }() - - // Monitor for shutdown. - // TODO provide a graceful shutdown API on shutdownChan - finishCh := node.MonitorShutdown(shutdownChan) //node.ShutdownHandler{Component: "rpc server", StopFunc: rpcStopper}, - //node.ShutdownHandler{Component: "provider", StopFunc: stop}, - - <-finishCh - return nil - }, -} - -func makeDB(cctx *cli.Context) (*harmonydb.DB, error) { - dbConfig := config.HarmonyDB{ - Username: cctx.String("db-user"), - Password: cctx.String("db-password"), - Hosts: strings.Split(cctx.String("db-host"), ","), - Database: cctx.String("db-name"), - Port: cctx.String("db-port"), - } - return harmonydb.NewFromConfig(dbConfig) -} - -type jwtPayload struct { - Allow []auth.Permission -} - -func StorageAuth(apiKey string) (sealer.StorageAuth, error) { - if apiKey == "" { - return nil, xerrors.Errorf("no api key provided") - } - - rawKey, err := base64.StdEncoding.DecodeString(apiKey) - if err != nil { - return nil, xerrors.Errorf("decoding api key: %w", err) - } - - key := jwt.NewHS256(rawKey) - - p := jwtPayload{ - Allow: []auth.Permission{"admin"}, - } - - token, err := jwt.Sign(&p, key) - if err != nil { - return nil, err - } - - headers := http.Header{} - headers.Add("Authorization", "Bearer "+string(token)) - return sealer.StorageAuth(headers), nil -} - -type Deps struct { - cfg *config.LotusProviderConfig - db *harmonydb.DB - full api.FullNode - verif storiface.Verifier - lw *sealer.LocalWorker - as *ctladdr.AddressSelector - maddrs []dtypes.MinerAddress - stor *paths.Remote - si *paths.DBIndex - localStore *paths.Local - listenAddr string -} - -func getDeps(ctx context.Context, cctx *cli.Context) (*Deps, error) { - // Open repo - - repoPath := cctx.String(FlagRepoPath) - fmt.Println("repopath", repoPath) - r, err := repo.NewFS(repoPath) - if err != nil { - return nil, err - } - - ok, err := r.Exists() - if err != nil { - return nil, err - } - if !ok { - if err := r.Init(repo.Provider); err != nil { - return nil, err - } - } - - db, err := makeDB(cctx) - if err != nil { - return nil, err - } - - /////////////////////////////////////////////////////////////////////// - ///// Dependency Setup - /////////////////////////////////////////////////////////////////////// - - // The config feeds into task runners & their helpers - cfg, err := getConfig(cctx, db) - if err != nil { - return nil, err - } - - log.Debugw("config", "config", cfg) - - var verif storiface.Verifier = ffiwrapper.ProofVerifier - - as, err := provider.AddressSelector(&cfg.Addresses)() - if err != nil { - return nil, err - } - - de, err := journal.ParseDisabledEvents(cfg.Journal.DisabledEvents) - if err != nil { - return nil, err - } - j, err := fsjournal.OpenFSJournalPath(cctx.String("journal"), de) - if err != nil { - return nil, err - } - - full, fullCloser, err := cliutil.GetFullNodeAPIV1LotusProvider(cctx, cfg.Apis.ChainApiInfo) - if err != nil { - return nil, err - } - - go func() { - select { - case <-ctx.Done(): - fullCloser() - _ = j.Close() - } - }() - sa, err := StorageAuth(cfg.Apis.StorageRPCSecret) - if err != nil { - return nil, xerrors.Errorf(`'%w' while parsing the config toml's - [Apis] - StorageRPCSecret=%v -Get it with: jq .PrivateKey ~/.lotus-miner/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU`, err, cfg.Apis.StorageRPCSecret) - } - - al := alerting.NewAlertingSystem(j) - si := paths.NewDBIndex(al, db) - bls := &paths.BasicLocalStorage{ - PathToJSON: cctx.String("storage-json"), - } - - listenAddr := cctx.String("listen") - const unspecifiedAddress = "0.0.0.0" - addressSlice := strings.Split(listenAddr, ":") - if ip := net.ParseIP(addressSlice[0]); ip != nil { - if ip.String() == unspecifiedAddress { - rip, err := db.GetRoutableIP() - if err != nil { - return nil, err - } - listenAddr = rip + ":" + addressSlice[1] - } - } - localStore, err := paths.NewLocal(ctx, bls, si, []string{"http://" + listenAddr + "/remote"}) - if err != nil { - return nil, err - } - - stor := paths.NewRemote(localStore, si, http.Header(sa), 10, &paths.DefaultPartialFileHandler{}) - - wstates := statestore.New(dssync.MutexWrap(ds.NewMapDatastore())) - - // todo localWorker isn't the abstraction layer we want to use here, we probably want to go straight to ffiwrapper - // maybe with a lotus-provider specific abstraction. LocalWorker does persistent call tracking which we probably - // don't need (ehh.. maybe we do, the async callback system may actually work decently well with harmonytask) - lw := sealer.NewLocalWorker(sealer.WorkerConfig{}, stor, localStore, si, nil, wstates) - - var maddrs []dtypes.MinerAddress - for _, s := range cfg.Addresses.MinerAddresses { - addr, err := address.NewFromString(s) - if err != nil { - return nil, err - } - maddrs = append(maddrs, dtypes.MinerAddress(addr)) - } - - return &Deps{ // lint: intentionally not-named so it will fail if one is forgotten - cfg, - db, - full, - verif, - lw, - as, - maddrs, - stor, - si, - localStore, - listenAddr, - }, nil - -} - -type ProviderAPI struct { - *Deps - ShutdownChan chan struct{} -} - -func (p *ProviderAPI) Version(context.Context) (api.Version, error) { - return api.ProviderAPIVersion0, nil -} - -// Trigger shutdown -func (p *ProviderAPI) Shutdown(context.Context) error { - close(p.ShutdownChan) - return nil -} - -func minerAddressesToStrings(maddrs []dtypes.MinerAddress) []string { - strs := make([]string, len(maddrs)) - for i, addr := range maddrs { - strs[i] = address.Address(addr).String() - } - return strs -} diff --git a/cmd/lotus-seed/main.go b/cmd/lotus-seed/main.go index d362804c95d..9deae560eb9 100644 --- a/cmd/lotus-seed/main.go +++ b/cmd/lotus-seed/main.go @@ -26,7 +26,7 @@ import ( var log = logging.Logger("lotus-seed") func main() { - logging.SetLogLevel("*", "INFO") + _ = logging.SetLogLevel("*", "INFO") local := []*cli.Command{ genesisCmd, diff --git a/cmd/lotus-shed/actor.go b/cmd/lotus-shed/actor.go index 8562b63c32d..2acf89076bc 100644 --- a/cmd/lotus-shed/actor.go +++ b/cmd/lotus-shed/actor.go @@ -8,6 +8,8 @@ import ( "strconv" "github.com/fatih/color" + "github.com/libp2p/go-libp2p/core/peer" + ma "github.com/multiformats/go-multiaddr" "github.com/urfave/cli/v2" "golang.org/x/xerrors" @@ -39,6 +41,176 @@ var actorCmd = &cli.Command{ actorGetMethodNum, actorProposeChangeBeneficiary, actorConfirmChangeBeneficiary, + actorSetAddrsCmd, + actorSetPeeridCmd, + }, +} + +var actorSetAddrsCmd = &cli.Command{ + Name: "set-p2p-addrs", + Usage: "set addresses that your miner can be publicly dialed on", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "actor", + Usage: "specify the address of miner actor", + Required: true, + }, + &cli.StringFlag{ + Name: "from", + Usage: "optionally specify the account to send the message from", + }, + &cli.BoolFlag{ + Name: "unset", + Usage: "unset address", + Value: false, + }, + }, + Action: func(cctx *cli.Context) error { + args := cctx.Args().Slice() + unset := cctx.Bool("unset") + if len(args) == 0 && !unset { + return cli.ShowSubcommandHelp(cctx) + } + if len(args) > 0 && unset { + return fmt.Errorf("unset can only be used with no arguments") + } + + var maddr address.Address + maddr, err := address.NewFromString(cctx.String("actor")) + if err != nil { + return fmt.Errorf("parsing address %s: %w", cctx.String("actor"), err) + } + + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + var addrs []abi.Multiaddrs + for _, a := range args { + maddr, err := ma.NewMultiaddr(a) + if err != nil { + return fmt.Errorf("failed to parse %q as a multiaddr: %w", a, err) + } + + maddrNop2p, strip := ma.SplitFunc(maddr, func(c ma.Component) bool { + return c.Protocol().Code == ma.P_P2P + }) + + if strip != nil { + fmt.Println("Stripping peerid ", strip, " from ", maddr) + } + addrs = append(addrs, maddrNop2p.Bytes()) + } + + minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + fromAddr := minfo.Worker + if from := cctx.String("from"); from != "" { + addr, err := address.NewFromString(from) + if err != nil { + return err + } + + fromAddr = addr + } + + fromId, err := api.StateLookupID(ctx, fromAddr, types.EmptyTSK) + if err != nil { + return err + } + + if !isController(minfo, fromId) { + return xerrors.Errorf("sender isn't a controller of miner: %s", fromId) + } + + params, err := actors.SerializeParams(&miner.ChangeMultiaddrsParams{NewMultiaddrs: addrs}) + if err != nil { + return err + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + To: maddr, + From: fromId, + Value: types.NewInt(0), + Method: builtin.MethodsMiner.ChangeMultiaddrs, + Params: params, + }, nil) + if err != nil { + return err + } + + fmt.Printf("Requested multiaddrs change in message %s\n", smsg.Cid()) + return nil + + }, +} + +var actorSetPeeridCmd = &cli.Command{ + Name: "set-peer-id", + Usage: "set the peer id of your miner", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "actor", + Usage: "specify the address of miner actor", + Required: true, + }, + }, + Action: func(cctx *cli.Context) error { + api, acloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := address.NewFromString(cctx.String("actor")) + if err != nil { + return fmt.Errorf("parsing address %s: %w", cctx.String("actor"), err) + } + + if cctx.NArg() != 1 { + return lcli.IncorrectNumArgs(cctx) + } + + pid, err := peer.Decode(cctx.Args().Get(0)) + if err != nil { + return fmt.Errorf("failed to parse input as a peerId: %w", err) + } + + minfo, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + params, err := actors.SerializeParams(&miner.ChangePeerIDParams{NewID: abi.PeerID(pid)}) + if err != nil { + return err + } + + smsg, err := api.MpoolPushMessage(ctx, &types.Message{ + To: maddr, + From: minfo.Worker, + Value: types.NewInt(0), + Method: builtin.MethodsMiner.ChangePeerID, + Params: params, + }, nil) + if err != nil { + return err + } + + fmt.Printf("Requested peerid change in message %s\n", smsg.Cid()) + return nil + }, } @@ -1087,3 +1259,17 @@ var actorConfirmChangeBeneficiary = &cli.Command{ return nil }, } + +func isController(mi api.MinerInfo, addr address.Address) bool { + if addr == mi.Owner || addr == mi.Worker { + return true + } + + for _, ca := range mi.ControlAddresses { + if addr == ca { + return true + } + } + + return false +} diff --git a/cmd/lotus-shed/balances.go b/cmd/lotus-shed/balances.go index 28569cd1212..666abbfe8aa 100644 --- a/cmd/lotus-shed/balances.go +++ b/cmd/lotus-shed/balances.go @@ -685,7 +685,7 @@ var chainPledgeCmd = &cli.Command{ }, ArgsUsage: "[stateroot epoch]", Action: func(cctx *cli.Context) error { - logging.SetLogLevel("badger", "ERROR") + _ = logging.SetLogLevel("badger", "ERROR") ctx := context.TODO() if !cctx.Args().Present() { @@ -916,13 +916,13 @@ var fillBalancesCmd = &cli.Command{ } w := csv.NewWriter(os.Stdout) - w.Write(append([]string{"Wallet Address"}, datestrs...)) // nolint:errcheck + _ = w.Write(append([]string{"Wallet Address"}, datestrs...)) for i := 0; i < len(addrs); i++ { row := []string{addrs[i].String()} for _, b := range balances[i] { row = append(row, types.FIL(b).String()) } - w.Write(row) // nolint:errcheck + _ = w.Write(row) } w.Flush() return nil diff --git a/cmd/lotus-shed/datastore.go b/cmd/lotus-shed/datastore.go index 5614e34f67f..8e31ccc3c44 100644 --- a/cmd/lotus-shed/datastore.go +++ b/cmd/lotus-shed/datastore.go @@ -57,7 +57,7 @@ var datastoreListCmd = &cli.Command{ }, ArgsUsage: "[namespace prefix]", Action: func(cctx *cli.Context) error { - logging.SetLogLevel("badger", "ERROR") // nolint:errcheck + _ = logging.SetLogLevel("badger", "ERROR") r, err := repo.NewFS(cctx.String("repo")) if err != nil { @@ -123,7 +123,7 @@ var datastoreGetCmd = &cli.Command{ }, ArgsUsage: "[namespace key]", Action: func(cctx *cli.Context) error { - logging.SetLogLevel("badger", "ERROR") // nolint:errcheck + _ = logging.SetLogLevel("badger", "ERROR") r, err := repo.NewFS(cctx.String("repo")) if err != nil { diff --git a/cmd/lotus-shed/deal.go b/cmd/lotus-shed/deal.go new file mode 100644 index 00000000000..3a350976e9b --- /dev/null +++ b/cmd/lotus-shed/deal.go @@ -0,0 +1,284 @@ +package main + +import ( + "bytes" + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + "os" + + "github.com/fatih/color" + "github.com/mitchellh/go-homedir" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + cborutil "github.com/filecoin-project/go-cbor-util" + commcid "github.com/filecoin-project/go-fil-commcid" + commp "github.com/filecoin-project/go-fil-commp-hashhash" + "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" + "github.com/filecoin-project/go-state-types/builtin/v9/market" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/must" +) + +var lpUtilCmd = &cli.Command{ + Name: "curio-util", + Usage: "curio utility commands", + Subcommands: []*cli.Command{ + lpUtilStartDealCmd, + }, +} + +var lpUtilStartDealCmd = &cli.Command{ + Name: "start-deal", + Usage: "start a deal with a specific curio instance", + ArgsUsage: "[dataFile] [miner]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "curio-rpc", + Value: "http://127.0.0.1:12300", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 2 { + return xerrors.Errorf("expected 2 arguments") + } + + maddr, err := address.NewFromString(cctx.Args().Get(1)) + if err != nil { + return xerrors.Errorf("parse miner address: %w", err) + } + + full, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + defAddr, err := full.WalletDefaultAddress(ctx) + if err != nil { + return xerrors.Errorf("get default address: %w", err) + } + + // open rpc + var rpc api.CurioStruct + closer2, err := jsonrpc.NewMergeClient(ctx, cctx.String("curio-rpc"), "Filecoin", []interface{}{&rpc.Internal}, nil) + if err != nil { + return xerrors.Errorf("open rpc: %w", err) + } + defer closer2() + + v, err := rpc.Version(ctx) + if err != nil { + return xerrors.Errorf("rpc version: %w", err) + } + + fmt.Printf("* curio version: %s\n", v.String()) + + // open data file + data, err := homedir.Expand(cctx.Args().Get(0)) + if err != nil { + return xerrors.Errorf("get data file: %w", err) + } + + df, err := os.Open(data) + if err != nil { + return xerrors.Errorf("open data file: %w", err) + } + + dstat, err := df.Stat() + if err != nil { + return xerrors.Errorf("stat data file: %w", err) + } + + // compute commd + color.Green("> computing piece CID\n") + + writer := new(commp.Calc) + _, err = io.Copy(writer, df) + if err != nil { + return xerrors.Errorf("compute commd copy: %w", err) + } + + commp, pps, err := writer.Digest() + if err != nil { + return xerrors.Errorf("compute commd: %w", err) + } + + pieceCid, err := commcid.PieceCommitmentV1ToCID(commp) + if err != nil { + return xerrors.Errorf("make pieceCid: %w", err) + } + + fmt.Printf("* piece CID: %s\n", pieceCid) + fmt.Printf("* piece size: %d\n", pps) + + // start serving the file + color.Green("> starting temp http server\n") + + deleteCalled := make(chan struct{}) + + mux := http.NewServeMux() + mux.HandleFunc("/"+pieceCid.String(), func(w http.ResponseWriter, r *http.Request) { + // log request and method + color.Blue("< %s %s\n", r.Method, r.URL) + + if r.Method == http.MethodDelete { + close(deleteCalled) + return + } + + http.ServeFile(w, r, data) + }) + + ts := httptest.NewServer(mux) + + dataUrl, err := url.Parse(ts.URL) + if err != nil { + return xerrors.Errorf("parse data url: %w", err) + } + dataUrl.Path = "/" + pieceCid.String() + + fmt.Printf("* data url: %s\n", dataUrl) + + // publish the deal + color.Green("> publishing deal\n") + + head, err := full.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("get chain head: %w", err) + } + + verif := false + + bds, err := full.StateDealProviderCollateralBounds(ctx, abi.PaddedPieceSize(pps), verif, head.Key()) + if err != nil { + return xerrors.Errorf("get provider collateral bounds: %w", err) + } + + pcoll := big.Mul(bds.Min, big.NewInt(2)) + + dealProposal := market.DealProposal{ + PieceCID: pieceCid, + PieceSize: abi.PaddedPieceSize(pps), + VerifiedDeal: verif, + Client: defAddr, + Provider: maddr, + Label: must.One(market.NewLabelFromString("lotus-shed-made-this")), + StartEpoch: head.Height() + 2000, + EndEpoch: head.Height() + 2880*300, + StoragePricePerEpoch: big.Zero(), + ProviderCollateral: pcoll, + ClientCollateral: big.Zero(), + } + + pbuf, err := cborutil.Dump(&dealProposal) + if err != nil { + return xerrors.Errorf("dump deal proposal: %w", err) + } + + sig, err := full.WalletSign(ctx, defAddr, pbuf) + if err != nil { + return xerrors.Errorf("sign deal proposal: %w", err) + } + + params := market.PublishStorageDealsParams{ + Deals: []market.ClientDealProposal{ + { + Proposal: dealProposal, + ClientSignature: *sig, + }, + }, + } + + var buf bytes.Buffer + err = params.MarshalCBOR(&buf) + if err != nil { + return xerrors.Errorf("marshal params: %w", err) + } + + msg := &types.Message{ + To: builtin.StorageMarketActorAddr, + From: defAddr, + Method: builtin.MethodsMarket.PublishStorageDeals, + Params: buf.Bytes(), + } + + smsg, err := full.MpoolPushMessage(ctx, msg, nil) + if err != nil { + return xerrors.Errorf("push message: %w", err) + } + + fmt.Printf("* PSD message cid: %s\n", smsg.Cid()) + + // wait for deal to be published + color.Green("> waiting for PublishStorageDeals to land on chain\n") + + rcpt, err := full.StateWaitMsg(ctx, smsg.Cid(), 3) + if err != nil { + return xerrors.Errorf("wait message: %w", err) + } + + if rcpt.Receipt.ExitCode != 0 { + return xerrors.Errorf("publish deal failed: exit code %d", rcpt.Receipt.ExitCode) + } + + // parse results + var ret market.PublishStorageDealsReturn + err = ret.UnmarshalCBOR(bytes.NewReader(rcpt.Receipt.Return)) + if err != nil { + return xerrors.Errorf("unmarshal return: %w", err) + } + + if len(ret.IDs) != 1 { + return xerrors.Errorf("expected 1 deal id, got %d", len(ret.IDs)) + } + + dealId := ret.IDs[0] + + fmt.Printf("* deal id: %d\n", dealId) + + // start deal + color.Green("> starting deal\n") + + pcid := smsg.Cid() + + pdi := api.PieceDealInfo{ + PublishCid: &pcid, + DealID: dealId, + DealProposal: &dealProposal, + DealSchedule: api.DealSchedule{ + StartEpoch: dealProposal.StartEpoch, + EndEpoch: dealProposal.EndEpoch, + }, + KeepUnsealed: true, + } + + soff, err := rpc.AllocatePieceToSector(ctx, maddr, pdi, dstat.Size(), *dataUrl, nil) + if err != nil { + return xerrors.Errorf("allocate piece to sector: %w", err) + } + + fmt.Printf("* sector offset: %d\n", soff) + + // wait for delete call on the file + color.Green("> waiting for file to be deleted (on sector finalize)\n") + + <-deleteCalled + + fmt.Println("* done") + + return nil + }, +} diff --git a/cmd/lotus-shed/diff.go b/cmd/lotus-shed/diff.go index a8eac657514..bdd2126b6d0 100644 --- a/cmd/lotus-shed/diff.go +++ b/cmd/lotus-shed/diff.go @@ -253,9 +253,8 @@ var diffStateTrees = &cli.Command{ if ok { diff(stateA, stateB) continue - } else { - fmt.Printf(" actor does not exist in second state-tree (%s)\n", rootB) } + fmt.Printf(" actor does not exist in second state-tree (%s)\n", rootB) fmt.Println() delete(changedB, addr) } @@ -265,9 +264,8 @@ var diffStateTrees = &cli.Command{ if ok { diff(stateA, stateB) continue - } else { - fmt.Printf(" actor does not exist in first state-tree (%s)\n", rootA) } + fmt.Printf(" actor does not exist in first state-tree (%s)\n", rootA) fmt.Println() } return nil diff --git a/cmd/lotus-shed/hello.go b/cmd/lotus-shed/hello.go index d16f9373563..3c905b798a4 100644 --- a/cmd/lotus-shed/hello.go +++ b/cmd/lotus-shed/hello.go @@ -51,6 +51,7 @@ var helloCmd = &cli.Command{ func HandleStream(s inet.Stream) { var hmsg hello.HelloMessage + _ = s.SetReadDeadline(time.Now().Add(30 * time.Second)) if err := cborutil.ReadCborRPC(s, &hmsg); err != nil { log.Infow("failed to read hello message, disconnecting", "error", err) _ = s.Conn().Close() diff --git a/cmd/lotus-shed/indexes.go b/cmd/lotus-shed/indexes.go index 620933e25f8..12ebe0082b5 100644 --- a/cmd/lotus-shed/indexes.go +++ b/cmd/lotus-shed/indexes.go @@ -72,7 +72,7 @@ var backfillEventsCmd = &cli.Command{ } if cctx.IsSet("from") { // we need to fetch the tipset after the epoch being specified since we will need to advance currTs - currTs, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int("from")+1), currTs.Key()) + currTs, err = api.ChainGetTipSetAfterHeight(ctx, abi.ChainEpoch(cctx.Int("from")+1), currTs.Key()) if err != nil { return err } diff --git a/cmd/lotus-shed/invariants.go b/cmd/lotus-shed/invariants.go index 5c6fb2d4f0a..e3507015a36 100644 --- a/cmd/lotus-shed/invariants.go +++ b/cmd/lotus-shed/invariants.go @@ -18,6 +18,7 @@ import ( v10 "github.com/filecoin-project/go-state-types/builtin/v10" v11 "github.com/filecoin-project/go-state-types/builtin/v11" v12 "github.com/filecoin-project/go-state-types/builtin/v12" + v13 "github.com/filecoin-project/go-state-types/builtin/v13" v8 "github.com/filecoin-project/go-state-types/builtin/v8" v9 "github.com/filecoin-project/go-state-types/builtin/v9" @@ -186,6 +187,11 @@ var invariantsCmd = &cli.Command{ if err != nil { return xerrors.Errorf("checking state invariants: %w", err) } + case actorstypes.Version13: + messages, err = v13.CheckStateInvariants(actorTree, abi.ChainEpoch(epoch), actorCodeCids) + if err != nil { + return xerrors.Errorf("checking state invariants: %w", err) + } default: return xerrors.Errorf("unsupported actor version: %v", av) } diff --git a/cmd/lotus-shed/itestd.go b/cmd/lotus-shed/itestd.go index 7b9b7460dae..0ff37132221 100644 --- a/cmd/lotus-shed/itestd.go +++ b/cmd/lotus-shed/itestd.go @@ -64,7 +64,7 @@ var itestdCmd = &cli.Command{ cs := readline.NewCancelableStdin(os.Stdin) go func() { <-cctx.Done() - cs.Close() // nolint:errcheck + _ = cs.Close() }() rl := bufio.NewReader(cs) diff --git a/cmd/lotus-shed/ledger.go b/cmd/lotus-shed/ledger.go index d9a888d2061..0cc66898573 100644 --- a/cmd/lotus-shed/ledger.go +++ b/cmd/lotus-shed/ledger.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/urfave/cli/v2" - ledgerfil "github.com/whyrusleeping/ledger-filecoin-go" + ledgerfil "github.com/zondax/ledger-filecoin-go" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/big" diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index 2b3b18670da..4770f714597 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -92,6 +92,7 @@ func main() { mismatchesCmd, blockCmd, adlCmd, + lpUtilCmd, } app := &cli.App{ diff --git a/cmd/lotus-shed/market.go b/cmd/lotus-shed/market.go index 6fb1566b671..749941f4cd5 100644 --- a/cmd/lotus-shed/market.go +++ b/cmd/lotus-shed/market.go @@ -214,7 +214,7 @@ var marketExportDatastoreCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { - logging.SetLogLevel("badger", "ERROR") // nolint:errcheck + _ = logging.SetLogLevel("badger", "ERROR") // If the backup dir is not specified, just use the OS temp dir backupDir := cctx.String("backup-dir") @@ -332,7 +332,7 @@ var marketImportDatastoreCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { - logging.SetLogLevel("badger", "ERROR") // nolint:errcheck + _ = logging.SetLogLevel("badger", "ERROR") backupPath := cctx.String("backup-path") diff --git a/cmd/lotus-shed/miner.go b/cmd/lotus-shed/miner.go index a8bb9374422..2f9b4ecf103 100644 --- a/cmd/lotus-shed/miner.go +++ b/cmd/lotus-shed/miner.go @@ -553,7 +553,7 @@ var sendInvalidWindowPoStCmd = &cli.Command{ return xerrors.Errorf("serializing params: %w", err) } - fmt.Printf("submitting bad PoST for %d paritions\n", len(partitionIndices)) + fmt.Printf("submitting bad PoST for %d partitions\n", len(partitionIndices)) smsg, err := api.MpoolPushMessage(ctx, &types.Message{ From: minfo.Worker, To: maddr, diff --git a/cmd/lotus-shed/rpc.go b/cmd/lotus-shed/rpc.go index 8ef79912921..42b99c664e2 100644 --- a/cmd/lotus-shed/rpc.go +++ b/cmd/lotus-shed/rpc.go @@ -67,7 +67,7 @@ var rpcCmd = &cli.Command{ cs := readline.NewCancelableStdin(afmt.Stdin) go func() { <-ctx.Done() - cs.Close() // nolint:errcheck + _ = cs.Close() }() send := func(method, params string) error { @@ -148,9 +148,8 @@ var rpcCmd = &cli.Command{ if err == readline.ErrInterrupt { if len(line) == 0 { break - } else { - continue } + continue } else if err == io.EOF { break } diff --git a/cmd/lotus-shed/sectors.go b/cmd/lotus-shed/sectors.go index 899e0f290b4..176f232fe6a 100644 --- a/cmd/lotus-shed/sectors.go +++ b/cmd/lotus-shed/sectors.go @@ -31,6 +31,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/spcli" "github.com/filecoin-project/lotus/lib/parmap" "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/storage/paths" @@ -44,7 +45,7 @@ var sectorsCmd = &cli.Command{ Usage: "Tools for interacting with sectors", Flags: []cli.Flag{}, Subcommands: []*cli.Command{ - terminateSectorCmd, + spcli.TerminateSectorCmd(shedGetActor), terminateSectorPenaltyEstimationCmd, visAllocatedSectorsCmd, dumpRLESectorCmd, @@ -53,138 +54,14 @@ var sectorsCmd = &cli.Command{ }, } -var terminateSectorCmd = &cli.Command{ - Name: "terminate", - Usage: "Forcefully terminate a sector (WARNING: This means losing power and pay a one-time termination penalty(including collateral) for the terminated sector)", - ArgsUsage: "[sectorNum1 sectorNum2 ...]", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "actor", - Usage: "specify the address of miner actor", - }, - &cli.BoolFlag{ - Name: "really-do-it", - Usage: "pass this flag if you know what you are doing", - }, - &cli.StringFlag{ - Name: "from", - Usage: "specify the address to send the terminate message from", - }, - }, - Action: func(cctx *cli.Context) error { - if cctx.NArg() < 1 { - return lcli.ShowHelp(cctx, fmt.Errorf("at least one sector must be specified")) - } - - var maddr address.Address - if act := cctx.String("actor"); act != "" { - var err error - maddr, err = address.NewFromString(act) - if err != nil { - return fmt.Errorf("parsing address %s: %w", act, err) - } - } - - if !cctx.Bool("really-do-it") { - return fmt.Errorf("this is a command for advanced users, only use it if you are sure of what you are doing") - } - - nodeApi, closer, err := lcli.GetFullNodeAPI(cctx) - if err != nil { - return err - } - defer closer() - - ctx := lcli.ReqContext(cctx) - - if maddr.Empty() { - minerApi, acloser, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer acloser() - - maddr, err = minerApi.ActorAddress(ctx) - if err != nil { - return err - } - } - - mi, err := nodeApi.StateMinerInfo(ctx, maddr, types.EmptyTSK) - if err != nil { - return err - } - - terminationDeclarationParams := []miner2.TerminationDeclaration{} - - for _, sn := range cctx.Args().Slice() { - sectorNum, err := strconv.ParseUint(sn, 10, 64) - if err != nil { - return fmt.Errorf("could not parse sector number: %w", err) - } - - sectorbit := bitfield.New() - sectorbit.Set(sectorNum) - - loca, err := nodeApi.StateSectorPartition(ctx, maddr, abi.SectorNumber(sectorNum), types.EmptyTSK) - if err != nil { - return fmt.Errorf("get state sector partition %s", err) - } - - para := miner2.TerminationDeclaration{ - Deadline: loca.Deadline, - Partition: loca.Partition, - Sectors: sectorbit, - } - - terminationDeclarationParams = append(terminationDeclarationParams, para) - } - - terminateSectorParams := &miner2.TerminateSectorsParams{ - Terminations: terminationDeclarationParams, - } - - sp, err := actors.SerializeParams(terminateSectorParams) - if err != nil { - return xerrors.Errorf("serializing params: %w", err) - } - - var fromAddr address.Address - if from := cctx.String("from"); from != "" { - var err error - fromAddr, err = address.NewFromString(from) - if err != nil { - return fmt.Errorf("parsing address %s: %w", from, err) - } - } else { - fromAddr = mi.Worker - } - - smsg, err := nodeApi.MpoolPushMessage(ctx, &types.Message{ - From: fromAddr, - To: maddr, - Method: builtin.MethodsMiner.TerminateSectors, - - Value: big.Zero(), - Params: sp, - }, nil) - if err != nil { - return xerrors.Errorf("mpool push message: %w", err) - } - - fmt.Println("sent termination message:", smsg.Cid()) - - wait, err := nodeApi.StateWaitMsg(ctx, smsg.Cid(), uint64(cctx.Int("confidence"))) - if err != nil { - return err - } - - if wait.Receipt.ExitCode.IsError() { - return fmt.Errorf("terminate sectors message returned exit %d", wait.Receipt.ExitCode) - } +func shedGetActor(cctx *cli.Context) (address.Address, error) { + minerApi, acloser, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return address.Address{}, err + } + defer acloser() - return nil - }, + return minerApi.ActorAddress(cctx.Context) } func findPenaltyInInternalExecutions(prefix string, trace []types.ExecutionTrace) { diff --git a/cmd/lotus-shed/state-stats.go b/cmd/lotus-shed/state-stats.go index 4eb00f98183..59e0d7a1624 100644 --- a/cmd/lotus-shed/state-stats.go +++ b/cmd/lotus-shed/state-stats.go @@ -723,7 +723,7 @@ to reduce the number of decode operations performed by caching the decoded objec go func() { // error is check later - eg.Wait() //nolint:errcheck + _ = eg.Wait() close(results) }() diff --git a/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go b/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go index a4c9fdeaaa0..273ab337c1b 100644 --- a/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go +++ b/cmd/lotus-sim/simulation/blockbuilder/blockbuilder.go @@ -99,7 +99,7 @@ func NewBlockBuilder(ctx context.Context, logger *zap.SugaredLogger, sm *stmgr.S return bb, nil } -// PushMessages tries to push the specified message into the block. +// PushMessage tries to push the specified message into the block. // // 1. All messages will be executed in-order. // 2. Gas computation & nonce selection will be handled internally. diff --git a/cmd/lotus-sim/simulation/mock/mock.go b/cmd/lotus-sim/simulation/mock/mock.go index 4699b2aa665..002524070cc 100644 --- a/cmd/lotus-sim/simulation/mock/mock.go +++ b/cmd/lotus-sim/simulation/mock/mock.go @@ -149,7 +149,7 @@ func MockWindowPoStProof(proofType abi.RegisteredPoStProof, minerAddr address.Ad return proof, nil } -// makeCommR generates a "fake" but valid CommR for a sector. It is unique for the given sector/miner. +// MockCommR generates a "fake" but valid CommR for a sector. It is unique for the given sector/miner. func MockCommR(minerAddr address.Address, sno abi.SectorNumber) cid.Cid { return tutils.MakeCID(fmt.Sprintf("%s:%d", minerAddr, sno), &miner5.SealedCIDPrefix) } diff --git a/cmd/lotus-sim/simulation/simulation.go b/cmd/lotus-sim/simulation/simulation.go index 47d06aeda91..d73a033cf96 100644 --- a/cmd/lotus-sim/simulation/simulation.go +++ b/cmd/lotus-sim/simulation/simulation.go @@ -117,7 +117,7 @@ func (sim *Simulation) saveConfig() error { var simulationPrefix = datastore.NewKey("/simulation") -// key returns the the key in the form /simulation//. For example, +// key returns the key in the form /simulation//. For example, // /simulation/head/default. func (sim *Simulation) key(subkey string) datastore.Key { return simulationPrefix.ChildString(subkey).ChildString(sim.name) diff --git a/cmd/lotus-sim/simulation/stages/commit_queue.go b/cmd/lotus-sim/simulation/stages/commit_queue.go index 60cbfa4badf..f68dc67edfa 100644 --- a/cmd/lotus-sim/simulation/stages/commit_queue.go +++ b/cmd/lotus-sim/simulation/stages/commit_queue.go @@ -165,7 +165,7 @@ func (q *commitQueue) advanceEpoch(epoch abi.ChainEpoch) { }) } -// enquueProveCommit enqueues prove-commit for the given pre-commit for the given miner. +// enqueueProveCommit enqueues prove-commit for the given pre-commit for the given miner. func (q *commitQueue) enqueueProveCommit(addr address.Address, preCommitEpoch abi.ChainEpoch, info minertypes.SectorPreCommitInfo) error { // Compute the epoch at which we can start trying to commit. preCommitDelay := policy.GetPreCommitChallengeDelay() diff --git a/cmd/lotus-sim/simulation/stages/precommit_stage.go b/cmd/lotus-sim/simulation/stages/precommit_stage.go index 1a89413d72c..a47ec2a6e6c 100644 --- a/cmd/lotus-sim/simulation/stages/precommit_stage.go +++ b/cmd/lotus-sim/simulation/stages/precommit_stage.go @@ -54,7 +54,7 @@ func (*PreCommitStage) Name() string { return "pre-commit" } -// packPreCommits packs pre-commit messages until the block is full. +// PackMessages packs pre-commit messages until the block is full. func (stage *PreCommitStage) PackMessages(ctx context.Context, bb *blockbuilder.BlockBuilder) (_err error) { if !stage.initialized { if err := stage.load(ctx, bb); err != nil { diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index 5d8096d1fa1..369938020f5 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -178,6 +178,8 @@ var DaemonCmd = &cli.Command{ return xerrors.Errorf("enabling runtime metrics: %w", err) } + interactive := cctx.Bool("interactive") + if cctx.Bool("manage-fdlimit") { if _, _, err := ulimit.ManageFdLimit(); err != nil { log.Errorf("setting file descriptor limit: %s", err) @@ -299,8 +301,8 @@ var DaemonCmd = &cli.Command{ willImportChain = true } - willRemoveChain := cctx.Bool("remove-existing-chain") - if willImportChain && !willRemoveChain { + var willRemoveChain bool + if interactive && willImportChain && !cctx.IsSet("remove-existing-chain") { // Confirm with the user about the intention to remove chain data. reader := bufio.NewReader(os.Stdin) fmt.Print("Importing chain or snapshot will by default delete existing local chain data. Do you want to proceed and delete? (yes/no): ") @@ -309,14 +311,16 @@ var DaemonCmd = &cli.Command{ return xerrors.Errorf("reading user input: %w", err) } userInput = strings.ToLower(strings.TrimSpace(userInput)) - - if userInput == "yes" { + switch userInput { + case "yes": willRemoveChain = true - } else if userInput == "no" { + case "no": willRemoveChain = false - } else { + default: return fmt.Errorf("invalid input. please answer with 'yes' or 'no'") } + } else { + willRemoveChain = cctx.Bool("remove-existing-chain") } if willRemoveChain { @@ -657,22 +661,10 @@ func removeExistingChain(cctx *cli.Context, lr repo.Repo) error { } }() - cfg, err := lockedRepo.Config() + log.Info("removing splitstore directory...") + err = deleteSplitstoreDir(lockedRepo) if err != nil { - return xerrors.Errorf("error getting config: %w", err) - } - - fullNodeConfig, ok := cfg.(*config.FullNode) - if !ok { - return xerrors.Errorf("wrong config type: %T", cfg) - } - - if fullNodeConfig.Chainstore.EnableSplitstore { - log.Info("removing splitstore directory...") - err = deleteSplitstoreDir(lockedRepo) - if err != nil { - return xerrors.Errorf("error removing splitstore directory: %w", err) - } + return xerrors.Errorf("error removing splitstore directory: %w", err) } // Get the base repo path diff --git a/cmd/lotus/main.go b/cmd/lotus/main.go index 85324e466b5..fce9a6136f4 100644 --- a/cmd/lotus/main.go +++ b/cmd/lotus/main.go @@ -13,6 +13,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/clicommands" cliutil "github.com/filecoin-project/lotus/cli/util" "github.com/filecoin-project/lotus/lib/lotuslog" "github.com/filecoin-project/lotus/lib/tracing" @@ -112,7 +113,7 @@ func main() { return nil }, - Commands: append(local, lcli.Commands...), + Commands: append(local, clicommands.Commands...), } app.Setup() diff --git a/cmd/sptool/actor.go b/cmd/sptool/actor.go new file mode 100644 index 00000000000..f17568a3115 --- /dev/null +++ b/cmd/sptool/actor.go @@ -0,0 +1,141 @@ +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/fatih/color" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-address" + + builtin2 "github.com/filecoin-project/lotus/chain/actors/builtin" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/spcli" + "github.com/filecoin-project/lotus/lib/tablewriter" +) + +var actorCmd = &cli.Command{ + Name: "actor", + Usage: "Manage Filecoin Miner Actor Metadata", + Subcommands: []*cli.Command{ + spcli.ActorSetAddrsCmd(SPTActorGetter), + spcli.ActorWithdrawCmd(SPTActorGetter), + spcli.ActorRepayDebtCmd(SPTActorGetter), + spcli.ActorSetPeeridCmd(SPTActorGetter), + spcli.ActorSetOwnerCmd(SPTActorGetter), + spcli.ActorControlCmd(SPTActorGetter, actorControlListCmd(SPTActorGetter)), + spcli.ActorProposeChangeWorkerCmd(SPTActorGetter), + spcli.ActorConfirmChangeWorkerCmd(SPTActorGetter), + spcli.ActorCompactAllocatedCmd(SPTActorGetter), + spcli.ActorProposeChangeBeneficiaryCmd(SPTActorGetter), + spcli.ActorConfirmChangeBeneficiaryCmd(SPTActorGetter), + spcli.ActorNewMinerCmd, + }, +} + +func actorControlListCmd(getActor spcli.ActorAddressGetter) *cli.Command { + return &cli.Command{ + Name: "list", + Usage: "Get currently set control addresses. Note: This excludes most roles as they are not known to the immediate chain state.", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "verbose", + }, + }, + Action: func(cctx *cli.Context) error { + api, acloser, err := lcli.GetFullNodeAPIV1(cctx) + if err != nil { + return err + } + defer acloser() + + ctx := lcli.ReqContext(cctx) + + maddr, err := getActor(cctx) + if err != nil { + return err + } + + mi, err := api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return err + } + + tw := tablewriter.New( + tablewriter.Col("name"), + tablewriter.Col("ID"), + tablewriter.Col("key"), + tablewriter.Col("use"), + tablewriter.Col("balance"), + ) + + post := map[address.Address]struct{}{} + + for _, ca := range mi.ControlAddresses { + post[ca] = struct{}{} + } + + printKey := func(name string, a address.Address) { + var actor *types.Actor + if actor, err = api.StateGetActor(ctx, a, types.EmptyTSK); err != nil { + fmt.Printf("%s\t%s: error getting actor: %s\n", name, a, err) + return + } + b := actor.Balance + + var k = a + // 'a' maybe a 'robust', in that case, 'StateAccountKey' returns an error. + if builtin2.IsAccountActor(actor.Code) { + if k, err = api.StateAccountKey(ctx, a, types.EmptyTSK); err != nil { + fmt.Printf("%s\t%s: error getting account key: %s\n", name, a, err) + return + } + } + kstr := k.String() + if !cctx.Bool("verbose") { + if len(kstr) > 9 { + kstr = kstr[:6] + "..." + } + } + + bstr := types.FIL(b).String() + switch { + case b.LessThan(types.FromFil(10)): + bstr = color.RedString(bstr) + case b.LessThan(types.FromFil(50)): + bstr = color.YellowString(bstr) + default: + bstr = color.GreenString(bstr) + } + + var uses []string + if a == mi.Worker { + uses = append(uses, color.YellowString("other")) + } + if _, ok := post[a]; ok { + uses = append(uses, color.GreenString("post")) + } + + tw.Write(map[string]interface{}{ + "name": name, + "ID": a, + "key": kstr, + "use": strings.Join(uses, " "), + "balance": bstr, + }) + } + + printKey("owner", mi.Owner) + printKey("worker", mi.Worker) + printKey("beneficiary", mi.Beneficiary) + for i, ca := range mi.ControlAddresses { + printKey(fmt.Sprintf("control-%d", i), ca) + } + + return tw.Flush(os.Stdout) + }, + } +} diff --git a/cmd/sptool/main.go b/cmd/sptool/main.go new file mode 100644 index 00000000000..7970b8db37c --- /dev/null +++ b/cmd/sptool/main.go @@ -0,0 +1,84 @@ +package main + +import ( + "context" + "fmt" + "os" + "os/signal" + + logging "github.com/ipfs/go-log/v2" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/cli/spcli" +) + +var log = logging.Logger("sptool") + +func main() { + local := []*cli.Command{ + actorCmd, + spcli.InfoCmd(SPTActorGetter), + sectorsCmd, + provingCmd, + //multiSigCmd, + } + + app := &cli.App{ + Name: "sptool", + Usage: "Manage Filecoin Miner Actor", + Version: build.UserVersion(), + Commands: local, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + EnvVars: []string{"LOTUS_PATH"}, + Hidden: true, + Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME + }, + &cli.StringFlag{ + Name: "log-level", + Value: "info", + }, + &cli.StringFlag{ + Name: "actor", + Required: os.Getenv("LOTUS_DOCS_GENERATION") != "1", + Usage: "miner actor to manage", + EnvVars: []string{"SP_ADDRESS"}, + }, + }, + Before: func(cctx *cli.Context) error { + return logging.SetLogLevel("sptool", cctx.String("sptool")) + }, + } + + // terminate early on ctrl+c + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + ctx, cancel := context.WithCancel(context.Background()) + go func() { + <-c + cancel() + fmt.Println("Received interrupt, shutting down... Press CTRL+C again to force shutdown") + <-c + fmt.Println("Forcing stop") + os.Exit(1) + }() + + if err := app.RunContext(ctx, os.Args); err != nil { + log.Errorf("%+v", err) + os.Exit(1) + return + } + +} + +func SPTActorGetter(cctx *cli.Context) (address.Address, error) { + addr, err := address.NewFromString(cctx.String("actor")) + if err != nil { + return address.Undef, fmt.Errorf("parsing address: %w", err) + } + return addr, nil +} diff --git a/cmd/sptool/proving.go b/cmd/sptool/proving.go new file mode 100644 index 00000000000..87c67b5f4e5 --- /dev/null +++ b/cmd/sptool/proving.go @@ -0,0 +1,18 @@ +package main + +import ( + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/cli/spcli" +) + +var provingCmd = &cli.Command{ + Name: "proving", + Usage: "View proving information", + Subcommands: []*cli.Command{ + spcli.ProvingInfoCmd(SPTActorGetter), + spcli.ProvingDeadlinesCmd(SPTActorGetter), + spcli.ProvingDeadlineInfoCmd(SPTActorGetter), + spcli.ProvingFaultsCmd(SPTActorGetter), + }, +} diff --git a/cmd/sptool/sector.go b/cmd/sptool/sector.go new file mode 100644 index 00000000000..8f341b5ccc2 --- /dev/null +++ b/cmd/sptool/sector.go @@ -0,0 +1,355 @@ +package main + +import ( + "fmt" + "os" + "sort" + + "github.com/docker/go-units" + "github.com/fatih/color" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/policy" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/spcli" + cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/lib/tablewriter" +) + +var sectorsCmd = &cli.Command{ + Name: "sectors", + Usage: "interact with sector store", + Subcommands: []*cli.Command{ + spcli.SectorsStatusCmd(SPTActorGetter, nil), + sectorsListCmd, // in-house b/c chain-only is so different. Needs Curio *web* implementation + spcli.SectorPreCommitsCmd(SPTActorGetter), + spcli.SectorsCheckExpireCmd(SPTActorGetter), + sectorsExpiredCmd, // in-house b/c chain-only is so different + spcli.SectorsExtendCmd(SPTActorGetter), + spcli.TerminateSectorCmd(SPTActorGetter), + spcli.SectorsCompactPartitionsCmd(SPTActorGetter), + }} + +var sectorsExpiredCmd = &cli.Command{ + Name: "expired", + Usage: "Get or cleanup expired sectors", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "expired-epoch", + Usage: "epoch at which to check sector expirations", + DefaultText: "WinningPoSt lookback epoch", + }, + }, + Action: func(cctx *cli.Context) error { + fullApi, nCloser, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return xerrors.Errorf("getting fullnode api: %w", err) + } + defer nCloser() + ctx := lcli.ReqContext(cctx) + + head, err := fullApi.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("getting chain head: %w", err) + } + + lbEpoch := abi.ChainEpoch(cctx.Int64("expired-epoch")) + if !cctx.IsSet("expired-epoch") { + nv, err := fullApi.StateNetworkVersion(ctx, head.Key()) + if err != nil { + return xerrors.Errorf("getting network version: %w", err) + } + + lbEpoch = head.Height() - policy.GetWinningPoStSectorSetLookback(nv) + if lbEpoch < 0 { + return xerrors.Errorf("too early to terminate sectors") + } + } + + if cctx.IsSet("confirm-remove-count") && !cctx.IsSet("expired-epoch") { + return xerrors.Errorf("--expired-epoch must be specified with --confirm-remove-count") + } + + lbts, err := fullApi.ChainGetTipSetByHeight(ctx, lbEpoch, head.Key()) + if err != nil { + return xerrors.Errorf("getting lookback tipset: %w", err) + } + + maddr, err := SPTActorGetter(cctx) + if err != nil { + return xerrors.Errorf("getting actor address: %w", err) + } + + // toCheck is a working bitfield which will only contain terminated sectors + toCheck := bitfield.New() + { + sectors, err := fullApi.StateMinerSectors(ctx, maddr, nil, lbts.Key()) + if err != nil { + return xerrors.Errorf("getting sector on chain info: %w", err) + } + + for _, sector := range sectors { + if sector.Expiration <= lbts.Height() { + toCheck.Set(uint64(sector.SectorNumber)) + } + } + } + + mact, err := fullApi.StateGetActor(ctx, maddr, lbts.Key()) + if err != nil { + return err + } + + tbs := blockstore.NewTieredBstore(blockstore.NewAPIBlockstore(fullApi), blockstore.NewMemory()) + mas, err := miner.Load(adt.WrapStore(ctx, cbor.NewCborStore(tbs)), mact) + if err != nil { + return err + } + + alloc, err := mas.GetAllocatedSectors() + if err != nil { + return xerrors.Errorf("getting allocated sectors: %w", err) + } + + // only allocated sectors can be expired, + toCheck, err = bitfield.IntersectBitField(toCheck, *alloc) + if err != nil { + return xerrors.Errorf("intersecting bitfields: %w", err) + } + + if err := mas.ForEachDeadline(func(dlIdx uint64, dl miner.Deadline) error { + return dl.ForEachPartition(func(partIdx uint64, part miner.Partition) error { + live, err := part.LiveSectors() + if err != nil { + return err + } + + toCheck, err = bitfield.SubtractBitField(toCheck, live) + if err != nil { + return err + } + + unproven, err := part.UnprovenSectors() + if err != nil { + return err + } + + toCheck, err = bitfield.SubtractBitField(toCheck, unproven) + + return err + }) + }); err != nil { + return err + } + + err = mas.ForEachPrecommittedSector(func(pci miner.SectorPreCommitOnChainInfo) error { + toCheck.Unset(uint64(pci.Info.SectorNumber)) + return nil + }) + if err != nil { + return err + } + + // toCheck now only contains sectors which either failed to precommit or are expired/terminated + fmt.Printf("Sectors that either failed to precommit or are expired/terminated:\n") + + err = toCheck.ForEach(func(u uint64) error { + fmt.Println(abi.SectorNumber(u)) + + return nil + }) + if err != nil { + return err + } + + return nil + }, +} + +var sectorsListCmd = &cli.Command{ + Name: "list", + Usage: "List sectors", + Flags: []cli.Flag{ + /* + &cli.BoolFlag{ + Name: "show-removed", + Usage: "show removed sectors", + Aliases: []string{"r"}, + }, + &cli.BoolFlag{ + Name: "fast", + Usage: "don't show on-chain info for better performance", + Aliases: []string{"f"}, + }, + &cli.BoolFlag{ + Name: "events", + Usage: "display number of events the sector has received", + Aliases: []string{"e"}, + }, + &cli.BoolFlag{ + Name: "initial-pledge", + Usage: "display initial pledge", + Aliases: []string{"p"}, + }, + &cli.BoolFlag{ + Name: "seal-time", + Usage: "display how long it took for the sector to be sealed", + Aliases: []string{"t"}, + }, + &cli.StringFlag{ + Name: "states", + Usage: "filter sectors by a comma-separated list of states", + }, + &cli.BoolFlag{ + Name: "unproven", + Usage: "only show sectors which aren't in the 'Proving' state", + Aliases: []string{"u"}, + }, + */ + }, + Subcommands: []*cli.Command{ + //sectorsListUpgradeBoundsCmd, + }, + Action: func(cctx *cli.Context) error { + fullApi, closer2, err := lcli.GetFullNodeAPI(cctx) // TODO: consider storing full node address in config + if err != nil { + return err + } + defer closer2() + + ctx := lcli.ReqContext(cctx) + + maddr, err := SPTActorGetter(cctx) + if err != nil { + return err + } + + head, err := fullApi.ChainHead(ctx) + if err != nil { + return err + } + + activeSet, err := fullApi.StateMinerActiveSectors(ctx, maddr, head.Key()) + if err != nil { + return err + } + activeIDs := make(map[abi.SectorNumber]struct{}, len(activeSet)) + for _, info := range activeSet { + activeIDs[info.SectorNumber] = struct{}{} + } + + sset, err := fullApi.StateMinerSectors(ctx, maddr, nil, head.Key()) + if err != nil { + return err + } + commitedIDs := make(map[abi.SectorNumber]struct{}, len(sset)) + for _, info := range sset { + commitedIDs[info.SectorNumber] = struct{}{} + } + + sort.Slice(sset, func(i, j int) bool { + return sset[i].SectorNumber < sset[j].SectorNumber + }) + + tw := tablewriter.New( + tablewriter.Col("ID"), + tablewriter.Col("State"), + tablewriter.Col("OnChain"), + tablewriter.Col("Active"), + tablewriter.Col("Expiration"), + tablewriter.Col("SealTime"), + tablewriter.Col("Events"), + tablewriter.Col("Deals"), + tablewriter.Col("DealWeight"), + tablewriter.Col("VerifiedPower"), + tablewriter.Col("Pledge"), + tablewriter.NewLineCol("Error"), + tablewriter.NewLineCol("RecoveryTimeout")) + + fast := cctx.Bool("fast") + + for _, st := range sset { + s := st.SectorNumber + _, inSSet := commitedIDs[s] + _, inASet := activeIDs[s] + + const verifiedPowerGainMul = 9 + dw, vp := .0, .0 + { + rdw := big.Add(st.DealWeight, st.VerifiedDealWeight) + dw = float64(big.Div(rdw, big.NewInt(int64(st.Expiration-st.Activation))).Uint64()) + vp = float64(big.Div(big.Mul(st.VerifiedDealWeight, big.NewInt(verifiedPowerGainMul)), big.NewInt(int64(st.Expiration-st.Activation))).Uint64()) + } + + var deals int + for _, deal := range st.DealIDs { + if deal != 0 { + deals++ + } + } + + exp := st.Expiration + // if st.OnTime > 0 && st.OnTime < exp { + // exp = st.OnTime // Can be different when the sector was CC upgraded + // } + + m := map[string]interface{}{ + "ID": s, + //"State": color.New(spcli.StateOrder[sealing.SectorState(st.State)].Col).Sprint(st.State), + "OnChain": yesno(inSSet), + "Active": yesno(inASet), + } + + if deals > 0 { + m["Deals"] = color.GreenString("%d", deals) + } else { + m["Deals"] = color.BlueString("CC") + // if st.ToUpgrade { + // m["Deals"] = color.CyanString("CC(upgrade)") + // } + } + + if !fast { + if !inSSet { + m["Expiration"] = "n/a" + } else { + m["Expiration"] = cliutil.EpochTime(head.Height(), exp) + // if st.Early > 0 { + // m["RecoveryTimeout"] = color.YellowString(cliutil.EpochTime(head.Height(), st.Early)) + // } + } + if inSSet && cctx.Bool("initial-pledge") { + m["Pledge"] = types.FIL(st.InitialPledge).Short() + } + } + + if !fast && deals > 0 { + m["DealWeight"] = units.BytesSize(dw) + if vp > 0 { + m["VerifiedPower"] = color.GreenString(units.BytesSize(vp)) + } + } + + tw.Write(m) + } + + return tw.Flush(os.Stdout) + }, +} + +func yesno(b bool) string { + if b { + return color.GreenString("YES") + } + return color.RedString("NO") +} diff --git a/cmd/tvx/extract_tipset.go b/cmd/tvx/extract_tipset.go index 553961f4491..0be4c04b08d 100644 --- a/cmd/tvx/extract_tipset.go +++ b/cmd/tvx/extract_tipset.go @@ -57,7 +57,7 @@ func doExtractTipset(opts extractOpts) error { return err } - // are are squashing all tipsets into a single multi-tipset vector? + // are squashing all tipsets into a single multi-tipset vector? if opts.squash { vector, err := extractTipsets(ctx, tss...) if err != nil { diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index 3a8b2b50af5..125e3a4347c 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -274,9 +274,8 @@ type AbortWithArgs struct { func (a Actor) AbortWith(rt runtime2.Runtime, args *AbortWithArgs) *abi.EmptyValue { if args.Uncontrolled { // uncontrolled abort: directly panic panic(args.Message) - } else { - rt.Abortf(args.Code, args.Message) } + rt.Abortf(args.Code, args.Message) return nil } diff --git a/conformance/driver.go b/conformance/driver.go index 3c62ca7b9ef..be06687ac6b 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -100,7 +100,7 @@ type ExecuteTipsetParams struct { // ExecuteTipset executes the supplied tipset on top of the state represented // by the preroot CID. // -// This method returns the the receipts root, the poststate root, and the VM +// This method returns the receipts root, the poststate root, and the VM // message results. The latter _include_ implicit messages, such as cron ticks // and reward withdrawal per miner. func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params ExecuteTipsetParams) (*ExecuteTipsetResult, error) { @@ -196,6 +196,7 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, params type ExecuteMessageParams struct { Preroot cid.Cid Epoch abi.ChainEpoch + Timestamp uint64 Message *types.Message CircSupply abi.TokenAmount BaseFee abi.TokenAmount @@ -249,6 +250,7 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP vmOpts := &vm.VMOpts{ StateBase: params.Preroot, Epoch: params.Epoch, + Timestamp: params.Timestamp, Bstore: bs, Syscalls: vm.Syscalls(ffiwrapper.ProofVerifier), CircSupplyCalc: func(_ context.Context, _ abi.ChainEpoch, _ *state.StateTree) (abi.TokenAmount, error) { diff --git a/curiosrc/address.go b/curiosrc/address.go new file mode 100644 index 00000000000..6d1738f2dc3 --- /dev/null +++ b/curiosrc/address.go @@ -0,0 +1,64 @@ +package curio + +import ( + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/curiosrc/multictladdr" + "github.com/filecoin-project/lotus/node/config" +) + +func AddressSelector(addrConf []config.CurioAddresses) func() (*multictladdr.MultiAddressSelector, error) { + return func() (*multictladdr.MultiAddressSelector, error) { + as := &multictladdr.MultiAddressSelector{ + MinerMap: make(map[address.Address]api.AddressConfig), + } + if addrConf == nil { + return as, nil + } + + for _, addrConf := range addrConf { + for _, minerID := range addrConf.MinerAddresses { + tmp := api.AddressConfig{ + DisableOwnerFallback: addrConf.DisableOwnerFallback, + DisableWorkerFallback: addrConf.DisableWorkerFallback, + } + + for _, s := range addrConf.PreCommitControl { + addr, err := address.NewFromString(s) + if err != nil { + return nil, xerrors.Errorf("parsing precommit control address: %w", err) + } + + tmp.PreCommitControl = append(tmp.PreCommitControl, addr) + } + + for _, s := range addrConf.CommitControl { + addr, err := address.NewFromString(s) + if err != nil { + return nil, xerrors.Errorf("parsing commit control address: %w", err) + } + + tmp.CommitControl = append(tmp.CommitControl, addr) + } + + for _, s := range addrConf.TerminateControl { + addr, err := address.NewFromString(s) + if err != nil { + return nil, xerrors.Errorf("parsing terminate control address: %w", err) + } + + tmp.TerminateControl = append(tmp.TerminateControl, addr) + } + a, err := address.NewFromString(minerID) + if err != nil { + return nil, xerrors.Errorf("parsing miner address %s: %w", minerID, err) + } + as.MinerMap[a] = tmp + } + } + return as, nil + } +} diff --git a/curiosrc/builder.go b/curiosrc/builder.go new file mode 100644 index 00000000000..3cd4bd0cdd2 --- /dev/null +++ b/curiosrc/builder.go @@ -0,0 +1,46 @@ +package curio + +import ( + "context" + "time" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/curiosrc/chainsched" + "github.com/filecoin-project/lotus/curiosrc/message" + "github.com/filecoin-project/lotus/curiosrc/multictladdr" + "github.com/filecoin-project/lotus/curiosrc/window" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/node/config" + dtypes "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/lotus/storage/paths" + "github.com/filecoin-project/lotus/storage/sealer" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +//var log = logging.Logger("provider") + +func WindowPostScheduler(ctx context.Context, fc config.CurioFees, pc config.CurioProvingConfig, + api api.FullNode, verif storiface.Verifier, lw *sealer.LocalWorker, sender *message.Sender, chainSched *chainsched.CurioChainSched, + as *multictladdr.MultiAddressSelector, addresses map[dtypes.MinerAddress]bool, db *harmonydb.DB, + stor paths.Store, idx paths.SectorIndex, max int) (*window.WdPostTask, *window.WdPostSubmitTask, *window.WdPostRecoverDeclareTask, error) { + + // todo config + ft := window.NewSimpleFaultTracker(stor, idx, pc.ParallelCheckLimit, time.Duration(pc.SingleCheckTimeout), time.Duration(pc.PartitionCheckTimeout)) + + computeTask, err := window.NewWdPostTask(db, api, ft, lw, verif, chainSched, addresses, max) + if err != nil { + return nil, nil, nil, err + } + + submitTask, err := window.NewWdPostSubmitTask(chainSched, sender, db, api, fc.MaxWindowPoStGasFee, as) + if err != nil { + return nil, nil, nil, err + } + + recoverTask, err := window.NewWdPostRecoverDeclareTask(sender, db, api, ft, as, chainSched, fc.MaxWindowPoStGasFee, addresses) + if err != nil { + return nil, nil, nil, err + } + + return computeTask, submitTask, recoverTask, nil +} diff --git a/provider/chainsched/chain_sched.go b/curiosrc/chainsched/chain_sched.go similarity index 73% rename from provider/chainsched/chain_sched.go rename to curiosrc/chainsched/chain_sched.go index 559a0274f29..42a387fbc2a 100644 --- a/provider/chainsched/chain_sched.go +++ b/curiosrc/chainsched/chain_sched.go @@ -14,29 +14,29 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) -var log = logging.Logger("chainsched") +var log = logging.Logger("curio/chainsched") type NodeAPI interface { ChainHead(context.Context) (*types.TipSet, error) ChainNotify(context.Context) (<-chan []*api.HeadChange, error) } -type ProviderChainSched struct { +type CurioChainSched struct { api NodeAPI callbacks []UpdateFunc started bool } -func New(api NodeAPI) *ProviderChainSched { - return &ProviderChainSched{ +func New(api NodeAPI) *CurioChainSched { + return &CurioChainSched{ api: api, } } type UpdateFunc func(ctx context.Context, revert, apply *types.TipSet) error -func (s *ProviderChainSched) AddHandler(ch UpdateFunc) error { +func (s *CurioChainSched) AddHandler(ch UpdateFunc) error { if s.started { return xerrors.Errorf("cannot add handler after start") } @@ -45,7 +45,7 @@ func (s *ProviderChainSched) AddHandler(ch UpdateFunc) error { return nil } -func (s *ProviderChainSched) Run(ctx context.Context) { +func (s *CurioChainSched) Run(ctx context.Context) { s.started = true var ( @@ -66,13 +66,13 @@ func (s *ProviderChainSched) Run(ctx context.Context) { } gotCur = false - log.Info("restarting window post scheduler") + log.Info("restarting chain scheduler") } select { case changes, ok := <-notifs: if !ok { - log.Warn("window post scheduler notifs channel closed") + log.Warn("chain notifs channel closed") notifs = nil continue } @@ -88,7 +88,7 @@ func (s *ProviderChainSched) Run(ctx context.Context) { continue } - ctx, span := trace.StartSpan(ctx, "ProviderChainSched.headChange") + ctx, span := trace.StartSpan(ctx, "CurioChainSched.headChange") s.update(ctx, nil, chg.Val) @@ -97,7 +97,7 @@ func (s *ProviderChainSched) Run(ctx context.Context) { continue } - ctx, span := trace.StartSpan(ctx, "ProviderChainSched.headChange") + ctx, span := trace.StartSpan(ctx, "CurioChainSched.headChange") var lowest, highest *types.TipSet = nil, nil @@ -122,15 +122,15 @@ func (s *ProviderChainSched) Run(ctx context.Context) { } } -func (s *ProviderChainSched) update(ctx context.Context, revert, apply *types.TipSet) { +func (s *CurioChainSched) update(ctx context.Context, revert, apply *types.TipSet) { if apply == nil { - log.Error("no new tipset in window post ProviderChainSched.update") + log.Error("no new tipset in CurioChainSched.update") return } for _, ch := range s.callbacks { if err := ch(ctx, revert, apply); err != nil { - log.Errorf("handling head updates in provider chain sched: %+v", err) + log.Errorf("handling head updates in curio chain sched: %+v", err) } } } diff --git a/curiosrc/ffi/piece_funcs.go b/curiosrc/ffi/piece_funcs.go new file mode 100644 index 00000000000..a548f5cc2df --- /dev/null +++ b/curiosrc/ffi/piece_funcs.go @@ -0,0 +1,76 @@ +package ffi + +import ( + "context" + "io" + "os" + "time" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +func (sb *SealCalls) WritePiece(ctx context.Context, taskID *harmonytask.TaskID, pieceID storiface.PieceNumber, size int64, data io.Reader) error { + // todo: config(?): allow setting PathStorage for this + // todo storage reservations + paths, _, done, err := sb.sectors.AcquireSector(ctx, taskID, pieceID.Ref(), storiface.FTNone, storiface.FTPiece, storiface.PathSealing) + if err != nil { + return err + } + defer done() + + dest := paths.Piece + tempDest := dest + ".tmp" + + destFile, err := os.OpenFile(tempDest, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return xerrors.Errorf("creating temp piece file '%s': %w", tempDest, err) + } + + removeTemp := true + defer func() { + if removeTemp { + rerr := os.Remove(tempDest) + if rerr != nil { + log.Errorf("removing temp file: %+v", rerr) + } + } + }() + + copyStart := time.Now() + + n, err := io.CopyBuffer(destFile, io.LimitReader(data, size), make([]byte, 8<<20)) + if err != nil { + _ = destFile.Close() + return xerrors.Errorf("copying piece data: %w", err) + } + + if err := destFile.Close(); err != nil { + return xerrors.Errorf("closing temp piece file: %w", err) + } + + if n != size { + return xerrors.Errorf("short write: %d", n) + } + + copyEnd := time.Now() + + log.Infow("wrote parked piece", "piece", pieceID, "size", size, "duration", copyEnd.Sub(copyStart), "dest", dest, "MiB/s", float64(size)/(1<<20)/copyEnd.Sub(copyStart).Seconds()) + + if err := os.Rename(tempDest, dest); err != nil { + return xerrors.Errorf("rename temp piece to dest %s -> %s: %w", tempDest, dest, err) + } + + removeTemp = false + return nil +} + +func (sb *SealCalls) PieceReader(ctx context.Context, id storiface.PieceNumber) (io.ReadCloser, error) { + return sb.sectors.storage.ReaderSeq(ctx, id.Ref(), storiface.FTPiece) +} + +func (sb *SealCalls) RemovePiece(ctx context.Context, id storiface.PieceNumber) error { + return sb.sectors.storage.Remove(ctx, id.Ref().ID, storiface.FTPiece, true, nil) +} diff --git a/curiosrc/ffi/sdr_funcs.go b/curiosrc/ffi/sdr_funcs.go new file mode 100644 index 00000000000..e9ce62831de --- /dev/null +++ b/curiosrc/ffi/sdr_funcs.go @@ -0,0 +1,627 @@ +package ffi + +import ( + "context" + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + + "github.com/KarpelesLab/reflink" + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" + "github.com/puzpuzpuz/xsync/v2" + "golang.org/x/xerrors" + + ffi "github.com/filecoin-project/filecoin-ffi" + commcid "github.com/filecoin-project/go-fil-commcid" + "github.com/filecoin-project/go-state-types/abi" + proof2 "github.com/filecoin-project/go-state-types/proof" + + "github.com/filecoin-project/lotus/curiosrc/proof" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/storage/paths" + "github.com/filecoin-project/lotus/storage/sealer/proofpaths" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +var log = logging.Logger("lpffi") + +/* +type ExternPrecommit2 func(ctx context.Context, sector storiface.SectorRef, cache, sealed string, pc1out storiface.PreCommit1Out) (sealedCID cid.Cid, unsealedCID cid.Cid, err error) + + type ExternalSealer struct { + PreCommit2 ExternPrecommit2 + } +*/ +type SealCalls struct { + sectors *storageProvider + + /*// externCalls cointain overrides for calling alternative sealing logic + externCalls ExternalSealer*/ +} + +func NewSealCalls(st *paths.Remote, ls *paths.Local, si paths.SectorIndex) *SealCalls { + return &SealCalls{ + sectors: &storageProvider{ + storage: st, + localStore: ls, + sindex: si, + storageReservations: xsync.NewIntegerMapOf[harmonytask.TaskID, *StorageReservation](), + }, + } +} + +type storageProvider struct { + storage *paths.Remote + localStore *paths.Local + sindex paths.SectorIndex + storageReservations *xsync.MapOf[harmonytask.TaskID, *StorageReservation] +} + +func (l *storageProvider) AcquireSector(ctx context.Context, taskID *harmonytask.TaskID, sector storiface.SectorRef, existing, allocate storiface.SectorFileType, sealing storiface.PathType) (fspaths, ids storiface.SectorPaths, release func(), err error) { + var paths, storageIDs storiface.SectorPaths + var releaseStorage func() + + var ok bool + var resv *StorageReservation + if taskID != nil { + resv, ok = l.storageReservations.Load(*taskID) + } + if ok && resv != nil { + if resv.Alloc != allocate || resv.Existing != existing { + // this should never happen, only when task definition is wrong + return storiface.SectorPaths{}, storiface.SectorPaths{}, nil, xerrors.Errorf("storage reservation type mismatch") + } + + log.Debugw("using existing storage reservation", "task", taskID, "sector", sector, "existing", existing, "allocate", allocate) + + paths = resv.Paths + storageIDs = resv.PathIDs + releaseStorage = resv.Release + + if len(existing.AllSet()) > 0 { + // there are some "existing" files in the reservation. Some of them may need fetching, so call l.storage.AcquireSector + // (which unlike in the reservation code will be called on the paths.Remote instance) to ensure that the files are + // present locally. Note that we do not care about 'allocate' reqeuests, those files don't exist, and are just + // proposed paths with a reservation of space. + + _, checkPathIDs, err := l.storage.AcquireSector(ctx, sector, existing, storiface.FTNone, sealing, storiface.AcquireMove, storiface.AcquireInto(storiface.PathsWithIDs{Paths: paths, IDs: storageIDs})) + if err != nil { + return storiface.SectorPaths{}, storiface.SectorPaths{}, nil, xerrors.Errorf("acquire reserved existing files: %w", err) + } + + // assert that checkPathIDs is the same as storageIDs + if storageIDs.Subset(existing) != checkPathIDs.Subset(existing) { + return storiface.SectorPaths{}, storiface.SectorPaths{}, nil, xerrors.Errorf("acquire reserved existing files: pathIDs mismatch %#v != %#v", storageIDs, checkPathIDs) + } + } + } else { + // No related reservation, acquire storage as usual + + var err error + paths, storageIDs, err = l.storage.AcquireSector(ctx, sector, existing, allocate, sealing, storiface.AcquireMove) + if err != nil { + return storiface.SectorPaths{}, storiface.SectorPaths{}, nil, err + } + + releaseStorage, err = l.localStore.Reserve(ctx, sector, allocate, storageIDs, storiface.FSOverheadSeal) + if err != nil { + return storiface.SectorPaths{}, storiface.SectorPaths{}, nil, xerrors.Errorf("reserving storage space: %w", err) + } + } + + log.Debugf("acquired sector %d (e:%d; a:%d): %v", sector, existing, allocate, paths) + + return paths, storageIDs, func() { + releaseStorage() + + for _, fileType := range storiface.PathTypes { + if fileType&allocate == 0 { + continue + } + + sid := storiface.PathByType(storageIDs, fileType) + if err := l.sindex.StorageDeclareSector(ctx, storiface.ID(sid), sector.ID, fileType, true); err != nil { + log.Errorf("declare sector error: %+v", err) + } + } + }, nil +} + +func (sb *SealCalls) GenerateSDR(ctx context.Context, taskID harmonytask.TaskID, sector storiface.SectorRef, ticket abi.SealRandomness, commKcid cid.Cid) error { + paths, pathIDs, releaseSector, err := sb.sectors.AcquireSector(ctx, &taskID, sector, storiface.FTNone, storiface.FTCache, storiface.PathSealing) + if err != nil { + return xerrors.Errorf("acquiring sector paths: %w", err) + } + defer releaseSector() + + // prepare SDR params + commp, err := commcid.CIDToDataCommitmentV1(commKcid) + if err != nil { + return xerrors.Errorf("computing commK: %w", err) + } + + replicaID, err := sector.ProofType.ReplicaId(sector.ID.Miner, sector.ID.Number, ticket, commp) + if err != nil { + return xerrors.Errorf("computing replica id: %w", err) + } + + // make sure the cache dir is empty + if err := os.RemoveAll(paths.Cache); err != nil { + return xerrors.Errorf("removing cache dir: %w", err) + } + if err := os.MkdirAll(paths.Cache, 0755); err != nil { + return xerrors.Errorf("mkdir cache dir: %w", err) + } + + // generate new sector key + err = ffi.GenerateSDR( + sector.ProofType, + paths.Cache, + replicaID, + ) + if err != nil { + return xerrors.Errorf("generating SDR %d (%s): %w", sector.ID.Number, paths.Unsealed, err) + } + + if err := sb.ensureOneCopy(ctx, sector.ID, pathIDs, storiface.FTCache); err != nil { + return xerrors.Errorf("ensure one copy: %w", err) + } + + return nil +} + +// ensureOneCopy makes sure that there is only one version of sector data. +// Usually called after a successful operation was done successfully on sector data. +func (sb *SealCalls) ensureOneCopy(ctx context.Context, sid abi.SectorID, pathIDs storiface.SectorPaths, fts storiface.SectorFileType) error { + if !pathIDs.HasAllSet(fts) { + return xerrors.Errorf("ensure one copy: not all paths are set") + } + + for _, fileType := range fts.AllSet() { + pid := storiface.PathByType(pathIDs, fileType) + keepIn := []storiface.ID{storiface.ID(pid)} + + log.Debugw("ensureOneCopy", "sector", sid, "type", fileType, "keep", keepIn) + + if err := sb.sectors.storage.Remove(ctx, sid, fileType, true, keepIn); err != nil { + return err + } + } + + return nil +} + +func (sb *SealCalls) TreeDRC(ctx context.Context, task *harmonytask.TaskID, sector storiface.SectorRef, unsealed cid.Cid, size abi.PaddedPieceSize, data io.Reader, unpaddedData bool) (scid cid.Cid, ucid cid.Cid, err error) { + p1o, err := sb.makePhase1Out(unsealed, sector.ProofType) + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("make phase1 output: %w", err) + } + + paths, pathIDs, releaseSector, err := sb.sectors.AcquireSector(ctx, task, sector, storiface.FTCache, storiface.FTSealed, storiface.PathSealing) + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("acquiring sector paths: %w", err) + } + defer releaseSector() + + defer func() { + if err != nil { + clerr := removeDRCTrees(paths.Cache) + if clerr != nil { + log.Errorw("removing tree files after TreeDRC error", "error", clerr, "exec-error", err, "sector", sector, "cache", paths.Cache) + } + } + }() + + treeDUnsealed, err := proof.BuildTreeD(data, unpaddedData, filepath.Join(paths.Cache, proofpaths.TreeDName), size) + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("building tree-d: %w", err) + } + + if treeDUnsealed != unsealed { + return cid.Undef, cid.Undef, xerrors.Errorf("tree-d cid mismatch with supplied unsealed cid") + } + + { + // create sector-sized file at paths.Sealed; PC2 transforms it into a sealed sector in-place + ssize, err := sector.ProofType.SectorSize() + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("getting sector size: %w", err) + } + + { + // copy TreeD prefix to sealed sector, SealPreCommitPhase2 will mutate it in place into the sealed sector + + // first try reflink + truncate, that should be way faster + err := reflink.Always(filepath.Join(paths.Cache, proofpaths.TreeDName), paths.Sealed) + if err == nil { + err = os.Truncate(paths.Sealed, int64(ssize)) + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("truncating reflinked sealed file: %w", err) + } + } else { + log.Errorw("reflink treed -> sealed failed, falling back to slow copy, use single scratch btrfs or xfs filesystem", "error", err, "sector", sector, "cache", paths.Cache, "sealed", paths.Sealed) + + // fallback to slow copy, copy ssize bytes from treed to sealed + dst, err := os.OpenFile(paths.Sealed, os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("opening sealed sector file: %w", err) + } + src, err := os.Open(filepath.Join(paths.Cache, proofpaths.TreeDName)) + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("opening treed sector file: %w", err) + } + + _, err = io.CopyN(dst, src, int64(ssize)) + derr := dst.Close() + _ = src.Close() + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("copying treed -> sealed: %w", err) + } + if derr != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("closing sealed file: %w", derr) + } + } + } + } + + sl, uns, err := ffi.SealPreCommitPhase2(p1o, paths.Cache, paths.Sealed) + if err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("computing seal proof: %w", err) + } + + if uns != unsealed { + return cid.Undef, cid.Undef, xerrors.Errorf("unsealed cid changed after sealing") + } + + if err := sb.ensureOneCopy(ctx, sector.ID, pathIDs, storiface.FTCache|storiface.FTSealed); err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("ensure one copy: %w", err) + } + + return sl, uns, nil +} + +func removeDRCTrees(cache string) error { + // list files in cache + files, err := os.ReadDir(cache) + if err != nil { + return xerrors.Errorf("listing cache: %w", err) + } + + for _, file := range files { + if proofpaths.IsTreeFile(file.Name()) { + err := os.Remove(filepath.Join(cache, file.Name())) + if err != nil { + return xerrors.Errorf("removing tree file: %w", err) + } + } + } + + return nil +} + +func (sb *SealCalls) GenerateSynthPoRep() { + panic("todo") +} + +func (sb *SealCalls) PoRepSnark(ctx context.Context, sn storiface.SectorRef, sealed, unsealed cid.Cid, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness) ([]byte, error) { + vproof, err := sb.sectors.storage.GeneratePoRepVanillaProof(ctx, sn, sealed, unsealed, ticket, seed) + if err != nil { + return nil, xerrors.Errorf("failed to generate vanilla proof: %w", err) + } + + proof, err := ffi.SealCommitPhase2(vproof, sn.ID.Number, sn.ID.Miner) + if err != nil { + return nil, xerrors.Errorf("computing seal proof failed: %w", err) + } + + ok, err := ffi.VerifySeal(proof2.SealVerifyInfo{ + SealProof: sn.ProofType, + SectorID: sn.ID, + DealIDs: nil, + Randomness: ticket, + InteractiveRandomness: seed, + Proof: proof, + SealedCID: sealed, + UnsealedCID: unsealed, + }) + if err != nil { + return nil, xerrors.Errorf("failed to verify proof: %w", err) + } + if !ok { + return nil, xerrors.Errorf("porep failed to validate") + } + + return proof, nil +} + +func (sb *SealCalls) makePhase1Out(unsCid cid.Cid, spt abi.RegisteredSealProof) ([]byte, error) { + commd, err := commcid.CIDToDataCommitmentV1(unsCid) + if err != nil { + return nil, xerrors.Errorf("make uns cid: %w", err) + } + + type Config struct { + ID string `json:"id"` + Path string `json:"path"` + RowsToDiscard int `json:"rows_to_discard"` + Size int `json:"size"` + } + + type Labels struct { + H *string `json:"_h"` // proofs want this.. + Labels []Config `json:"labels"` + } + + var phase1Output struct { + CommD [32]byte `json:"comm_d"` + Config Config `json:"config"` // TreeD + Labels map[string]*Labels `json:"labels"` + RegisteredProof string `json:"registered_proof"` + } + + copy(phase1Output.CommD[:], commd) + + phase1Output.Config.ID = "tree-d" + phase1Output.Config.Path = "/placeholder" + phase1Output.Labels = map[string]*Labels{} + + switch spt { + case abi.RegisteredSealProof_StackedDrg2KiBV1_1, abi.RegisteredSealProof_StackedDrg2KiBV1_1_Feat_SyntheticPoRep: + phase1Output.Config.RowsToDiscard = 0 + phase1Output.Config.Size = 127 + phase1Output.Labels["StackedDrg2KiBV1"] = &Labels{} + phase1Output.RegisteredProof = "StackedDrg2KiBV1_1" + + for i := 0; i < 2; i++ { + phase1Output.Labels["StackedDrg2KiBV1"].Labels = append(phase1Output.Labels["StackedDrg2KiBV1"].Labels, Config{ + ID: fmt.Sprintf("layer-%d", i+1), + Path: "/placeholder", + RowsToDiscard: 0, + Size: 64, + }) + } + + case abi.RegisteredSealProof_StackedDrg8MiBV1_1, abi.RegisteredSealProof_StackedDrg8MiBV1_1_Feat_SyntheticPoRep: + phase1Output.Config.RowsToDiscard = 0 + phase1Output.Config.Size = 524287 + phase1Output.Labels["StackedDrg8MiBV1"] = &Labels{} + phase1Output.RegisteredProof = "StackedDrg8MiBV1_1" + + for i := 0; i < 2; i++ { + phase1Output.Labels["StackedDrg8MiBV1"].Labels = append(phase1Output.Labels["StackedDrg8MiBV1"].Labels, Config{ + ID: fmt.Sprintf("layer-%d", i+1), + Path: "/placeholder", + RowsToDiscard: 0, + Size: 262144, + }) + } + + case abi.RegisteredSealProof_StackedDrg512MiBV1_1: + phase1Output.Config.RowsToDiscard = 0 + phase1Output.Config.Size = 33554431 + phase1Output.Labels["StackedDrg512MiBV1"] = &Labels{} + phase1Output.RegisteredProof = "StackedDrg512MiBV1_1" + + for i := 0; i < 2; i++ { + phase1Output.Labels["StackedDrg512MiBV1"].Labels = append(phase1Output.Labels["StackedDrg512MiBV1"].Labels, Config{ + ID: fmt.Sprintf("layer-%d", i+1), + Path: "placeholder", + RowsToDiscard: 0, + Size: 16777216, + }) + } + + case abi.RegisteredSealProof_StackedDrg32GiBV1_1: + phase1Output.Config.RowsToDiscard = 0 + phase1Output.Config.Size = 2147483647 + phase1Output.Labels["StackedDrg32GiBV1"] = &Labels{} + phase1Output.RegisteredProof = "StackedDrg32GiBV1_1" + + for i := 0; i < 11; i++ { + phase1Output.Labels["StackedDrg32GiBV1"].Labels = append(phase1Output.Labels["StackedDrg32GiBV1"].Labels, Config{ + ID: fmt.Sprintf("layer-%d", i+1), + Path: "/placeholder", + RowsToDiscard: 0, + Size: 1073741824, + }) + } + + case abi.RegisteredSealProof_StackedDrg64GiBV1_1: + phase1Output.Config.RowsToDiscard = 0 + phase1Output.Config.Size = 4294967295 + phase1Output.Labels["StackedDrg64GiBV1"] = &Labels{} + phase1Output.RegisteredProof = "StackedDrg64GiBV1_1" + + for i := 0; i < 11; i++ { + phase1Output.Labels["StackedDrg64GiBV1"].Labels = append(phase1Output.Labels["StackedDrg64GiBV1"].Labels, Config{ + ID: fmt.Sprintf("layer-%d", i+1), + Path: "/placeholder", + RowsToDiscard: 0, + Size: 2147483648, + }) + } + + default: + panic("proof type not handled") + } + + return json.Marshal(phase1Output) +} + +func (sb *SealCalls) LocalStorage(ctx context.Context) ([]storiface.StoragePath, error) { + return sb.sectors.localStore.Local(ctx) +} + +func (sb *SealCalls) FinalizeSector(ctx context.Context, sector storiface.SectorRef, keepUnsealed bool) error { + alloc := storiface.FTNone + if keepUnsealed { + // note: In Curio we don't write the unsealed file in any of the previous stages, it's only written here from tree-d + alloc = storiface.FTUnsealed + } + + sectorPaths, pathIDs, releaseSector, err := sb.sectors.AcquireSector(ctx, nil, sector, storiface.FTCache, alloc, storiface.PathSealing) + if err != nil { + return xerrors.Errorf("acquiring sector paths: %w", err) + } + defer releaseSector() + + ssize, err := sector.ProofType.SectorSize() + if err != nil { + return xerrors.Errorf("getting sector size: %w", err) + } + + if keepUnsealed { + // tree-d contains exactly unsealed data in the prefix, so + // * we move it to a temp file + // * we truncate the temp file to the sector size + // * we move the temp file to the unsealed location + + // temp path in cache where we'll move tree-d before truncating + // it is in the cache directory so that we can use os.Rename to move it + // to unsealed (which may be on a different filesystem) + tempUnsealed := filepath.Join(sectorPaths.Cache, storiface.SectorName(sector.ID)) + + _, terr := os.Stat(tempUnsealed) + tempUnsealedExists := terr == nil + + // First handle an edge case where we have already gone through this step, + // but ClearCache or later steps failed. In that case we'll see tree-d missing and unsealed present + + if _, err := os.Stat(filepath.Join(sectorPaths.Cache, proofpaths.TreeDName)); err != nil { + if os.IsNotExist(err) { + // check that unsealed exists and is the right size + st, err := os.Stat(sectorPaths.Unsealed) + if err != nil { + if os.IsNotExist(err) { + if tempUnsealedExists { + // unsealed file does not exist, but temp unsealed file does + // so we can just resume where the previous attempt left off + goto retryUnsealedMove + } + return xerrors.Errorf("neither unsealed file nor temp-unsealed file exists") + } + return xerrors.Errorf("stat unsealed file: %w", err) + } + if st.Size() != int64(ssize) { + if tempUnsealedExists { + // unsealed file exists but is the wrong size, and temp unsealed file exists + // so we can just resume where the previous attempt left off with some cleanup + + if err := os.Remove(sectorPaths.Unsealed); err != nil { + return xerrors.Errorf("removing unsealed file from last attempt: %w", err) + } + + goto retryUnsealedMove + } + return xerrors.Errorf("unsealed file is not the right size: %d != %d and temp unsealed is missing", st.Size(), ssize) + } + + // all good, just log that this edge case happened + log.Warnw("unsealed file exists but tree-d is missing, skipping move", "sector", sector.ID, "unsealed", sectorPaths.Unsealed, "cache", sectorPaths.Cache) + goto afterUnsealedMove + } + return xerrors.Errorf("stat tree-d file: %w", err) + } + + // If the state in clean do the move + + // move tree-d to temp file + if err := os.Rename(filepath.Join(sectorPaths.Cache, proofpaths.TreeDName), tempUnsealed); err != nil { + return xerrors.Errorf("moving tree-d to temp file: %w", err) + } + + retryUnsealedMove: + + // truncate sealed file to sector size + if err := os.Truncate(tempUnsealed, int64(ssize)); err != nil { + return xerrors.Errorf("truncating unsealed file to sector size: %w", err) + } + + // move temp file to unsealed location + if err := paths.Move(tempUnsealed, sectorPaths.Unsealed); err != nil { + return xerrors.Errorf("move temp unsealed sector to final location (%s -> %s): %w", tempUnsealed, sectorPaths.Unsealed, err) + } + } + +afterUnsealedMove: + if err := ffi.ClearCache(uint64(ssize), sectorPaths.Cache); err != nil { + return xerrors.Errorf("clearing cache: %w", err) + } + + if err := sb.ensureOneCopy(ctx, sector.ID, pathIDs, storiface.FTCache|alloc); err != nil { + return xerrors.Errorf("ensure one copy: %w", err) + } + + return nil +} + +func (sb *SealCalls) MoveStorage(ctx context.Context, sector storiface.SectorRef, taskID *harmonytask.TaskID) error { + // only move the unsealed file if it still exists and needs moving + moveUnsealed := storiface.FTUnsealed + { + found, unsealedPathType, err := sb.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 + } + } + + toMove := storiface.FTCache | storiface.FTSealed | moveUnsealed + + var opts []storiface.AcquireOption + if taskID != nil { + resv, ok := sb.sectors.storageReservations.Load(*taskID) + // if the reservation is missing MoveStorage will simply create one internally. This is fine as the reservation + // will only be missing when the node is restarting, which means that the missing reservations will get recreated + // anyways, and before we start claiming other tasks. + if ok { + defer resv.Release() + + if resv.Alloc != storiface.FTNone { + return xerrors.Errorf("task %d has storage reservation with alloc", taskID) + } + if resv.Existing != toMove|storiface.FTUnsealed { + return xerrors.Errorf("task %d has storage reservation with different existing", taskID) + } + + opts = append(opts, storiface.AcquireInto(storiface.PathsWithIDs{Paths: resv.Paths, IDs: resv.PathIDs})) + } + } + + err := sb.sectors.storage.MoveStorage(ctx, sector, toMove, opts...) + if err != nil { + return xerrors.Errorf("moving storage: %w", err) + } + + for _, fileType := range toMove.AllSet() { + if err := sb.sectors.storage.RemoveCopies(ctx, sector.ID, fileType); err != nil { + return xerrors.Errorf("rm copies (t:%s, s:%v): %w", fileType, sector, err) + } + } + + return nil +} + +func (sb *SealCalls) sectorStorageType(ctx context.Context, sector storiface.SectorRef, ft storiface.SectorFileType) (sectorFound bool, ptype storiface.PathType, err error) { + stores, err := sb.sectors.sindex.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 +} diff --git a/curiosrc/ffi/task_storage.go b/curiosrc/ffi/task_storage.go new file mode 100644 index 00000000000..f01a472fa8c --- /dev/null +++ b/curiosrc/ffi/task_storage.go @@ -0,0 +1,231 @@ +package ffi + +import ( + "context" + "sync" + "time" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + storagePaths "github.com/filecoin-project/lotus/storage/paths" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +type SectorRef struct { + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + RegSealProof abi.RegisteredSealProof `db:"reg_seal_proof"` +} + +func (sr SectorRef) ID() abi.SectorID { + return abi.SectorID{ + Miner: abi.ActorID(sr.SpID), + Number: abi.SectorNumber(sr.SectorNumber), + } +} + +func (sr SectorRef) Ref() storiface.SectorRef { + return storiface.SectorRef{ + ID: sr.ID(), + ProofType: sr.RegSealProof, + } +} + +type TaskStorage struct { + sc *SealCalls + + alloc, existing storiface.SectorFileType + ssize abi.SectorSize + pathType storiface.PathType + + taskToSectorRef func(taskID harmonytask.TaskID) (SectorRef, error) +} + +type ReleaseStorageFunc func() // free storage reservation + +type StorageReservation struct { + SectorRef SectorRef + Release ReleaseStorageFunc + Paths storiface.SectorPaths + PathIDs storiface.SectorPaths + + Alloc, Existing storiface.SectorFileType +} + +func (sb *SealCalls) Storage(taskToSectorRef func(taskID harmonytask.TaskID) (SectorRef, error), alloc, existing storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType) *TaskStorage { + return &TaskStorage{ + sc: sb, + alloc: alloc, + existing: existing, + ssize: ssize, + pathType: pathType, + taskToSectorRef: taskToSectorRef, + } +} + +func (t *TaskStorage) HasCapacity() bool { + ctx := context.Background() + + paths, err := t.sc.sectors.sindex.StorageBestAlloc(ctx, t.alloc, t.ssize, t.pathType, storagePaths.NoMinerFilter) + if err != nil { + log.Errorf("finding best alloc in HasCapacity: %+v", err) + return false + } + + local, err := t.sc.sectors.localStore.Local(ctx) + if err != nil { + log.Errorf("getting local storage: %+v", err) + return false + } + + for _, path := range paths { + if t.pathType == storiface.PathStorage && !path.CanStore { + continue // we want to store, and this isn't a store path + } + if t.pathType == storiface.PathSealing && !path.CanSeal { + continue // we want to seal, and this isn't a seal path + } + + // check if this path is on this node + var found bool + for _, storagePath := range local { + if storagePath.ID == path.ID { + found = true + break + } + } + if !found { + // this path isn't on this node + continue + } + + // StorageBestAlloc already checks that there is enough space; Not atomic like reserving space, but it's + // good enough for HasCapacity + return true + } + + return false // no path found +} + +func (t *TaskStorage) Claim(taskID int) error { + // TaskStorage Claim Attempts to reserve storage for the task + // A: Create a reservation for files to be allocated + // B: Create a reservation for existing files to be fetched into local storage + // C: Create a reservation for existing files in local storage which may be extended (e.g. sector cache when computing Trees) + + ctx := context.Background() + + sectorRef, err := t.taskToSectorRef(harmonytask.TaskID(taskID)) + if err != nil { + return xerrors.Errorf("getting sector ref: %w", err) + } + + // storage writelock sector + lkctx, cancel := context.WithCancel(ctx) + + requestedTypes := t.alloc | t.existing + + lockAcquireTimuout := time.Second * 10 + lockAcquireTimer := time.NewTimer(lockAcquireTimuout) + + go func() { + defer cancel() + + select { + case <-lockAcquireTimer.C: + case <-ctx.Done(): + } + }() + + if err := t.sc.sectors.sindex.StorageLock(lkctx, sectorRef.ID(), storiface.FTNone, requestedTypes); err != nil { + // timer will expire + return xerrors.Errorf("claim StorageLock: %w", err) + } + + if !lockAcquireTimer.Stop() { + // timer expired, so lkctx is done, and that means the lock was acquired and dropped.. + return xerrors.Errorf("failed to acquire lock") + } + defer func() { + // make sure we release the sector lock + lockAcquireTimer.Reset(0) + }() + + // First see what we have locally. We are putting allocate and existing together because local acquire will look + // for existing files for allocate requests, separately existing files which aren't found locally will be need to + // be fetched, so we will need to create reservations for that too. + // NOTE localStore.AcquireSector does not open or create any files, nor does it reserve space. It only proposes + // paths to be used. + pathsFs, pathIDs, err := t.sc.sectors.localStore.AcquireSector(ctx, sectorRef.Ref(), storiface.FTNone, requestedTypes, t.pathType, storiface.AcquireMove) + if err != nil { + return err + } + + // reserve the space + release, err := t.sc.sectors.localStore.Reserve(ctx, sectorRef.Ref(), requestedTypes, pathIDs, storiface.FSOverheadSeal) + if err != nil { + return err + } + + var releaseOnce sync.Once + releaseFunc := func() { + releaseOnce.Do(release) + } + + sres := &StorageReservation{ + SectorRef: sectorRef, + Release: releaseFunc, + Paths: pathsFs, + PathIDs: pathIDs, + + Alloc: t.alloc, + Existing: t.existing, + } + + t.sc.sectors.storageReservations.Store(harmonytask.TaskID(taskID), sres) + + log.Debugw("claimed storage", "task_id", taskID, "sector", sectorRef.ID(), "paths", pathsFs) + + // note: we drop the sector writelock on return; THAT IS INTENTIONAL, this code runs in CanAccept, which doesn't + // guarantee that the work for this sector will happen on this node; SDR CanAccept just ensures that the node can + // run the job, harmonytask is what ensures that only one SDR runs at a time + return nil +} + +func (t *TaskStorage) MarkComplete(taskID int) error { + // MarkComplete is ALWAYS called after the task is done or not scheduled + // If Claim is called and returns without errors, MarkComplete with the same + // taskID is guaranteed to eventually be called + + sectorRef, err := t.taskToSectorRef(harmonytask.TaskID(taskID)) + if err != nil { + return xerrors.Errorf("getting sector ref: %w", err) + } + + sres, ok := t.sc.sectors.storageReservations.Load(harmonytask.TaskID(taskID)) + if !ok { + return xerrors.Errorf("no reservation found for task %d", taskID) + } + + if sectorRef != sres.SectorRef { + return xerrors.Errorf("reservation sector ref doesn't match task sector ref: %+v != %+v", sectorRef, sres.SectorRef) + } + + log.Debugw("marking storage complete", "task_id", taskID, "sector", sectorRef.ID(), "paths", sres.Paths) + + // remove the reservation + t.sc.sectors.storageReservations.Delete(harmonytask.TaskID(taskID)) + + // release the reservation + sres.Release() + + // note: this only frees the reservation, allocated sectors are declared in AcquireSector which is aware of + // the reservation + return nil +} + +var _ resources.Storage = &TaskStorage{} diff --git a/curiosrc/gc/storage_endpoint_gc.go b/curiosrc/gc/storage_endpoint_gc.go new file mode 100644 index 00000000000..45783f35367 --- /dev/null +++ b/curiosrc/gc/storage_endpoint_gc.go @@ -0,0 +1,287 @@ +package gc + +import ( + "context" + "strings" + "sync" + "time" + + logging "github.com/ipfs/go-log/v2" + "github.com/samber/lo" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + "github.com/filecoin-project/lotus/lib/result" + "github.com/filecoin-project/lotus/storage/paths" + "github.com/filecoin-project/lotus/storage/sealer/fsutil" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +var log = logging.Logger("curiogc") + +const StorageEndpointGCInterval = 21 * time.Minute +const StorageEndpointDeadTime = StorageEndpointGCInterval * 6 // ~2h +const MaxParallelEndpointChecks = 32 + +type StorageEndpointGC struct { + si *paths.DBIndex + remote *paths.Remote + db *harmonydb.DB +} + +func NewStorageEndpointGC(si *paths.DBIndex, remote *paths.Remote, db *harmonydb.DB) *StorageEndpointGC { + return &StorageEndpointGC{ + si: si, + remote: remote, + db: db, + } +} + +func (s *StorageEndpointGC) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + /* + 1. Get all storage paths + urls (endpoints) + 2. Ping each url, record results + 3. Update sector_path_url_liveness with success/failure + 4.1 If a URL was consistently down for StorageEndpointDeadTime, remove it from the storage_path table + 4.2 Remove storage paths with no URLs remaining + 4.2.1 in the same transaction remove sector refs to the dead path + */ + + ctx := context.Background() + + var pathRefs []struct { + StorageID storiface.ID `db:"storage_id"` + Urls string `db:"urls"` + LastHeartbeat *time.Time `db:"last_heartbeat"` + } + + err = s.db.Select(ctx, &pathRefs, `SELECT storage_id, urls, last_heartbeat FROM storage_path`) + if err != nil { + return false, xerrors.Errorf("getting path metadata: %w", err) + } + + type pingResult struct { + storageID storiface.ID + url string + + res result.Result[fsutil.FsStat] + } + + var pingResults []pingResult + var resultLk sync.Mutex + var resultThrottle = make(chan struct{}, MaxParallelEndpointChecks) + + for _, pathRef := range pathRefs { + pathRef := pathRef + urls := strings.Split(pathRef.Urls, paths.URLSeparator) + + for _, url := range urls { + url := url + + select { + case resultThrottle <- struct{}{}: + case <-ctx.Done(): + return false, ctx.Err() + } + + go func() { + defer func() { + <-resultThrottle + }() + + st, err := s.remote.StatUrl(ctx, url, pathRef.StorageID) + + res := pingResult{ + storageID: pathRef.StorageID, + url: url, + res: result.Wrap(st, err), + } + + resultLk.Lock() + pingResults = append(pingResults, res) + resultLk.Unlock() + }() + } + } + + // Wait for all pings to finish + for i := 0; i < MaxParallelEndpointChecks; i++ { + select { + case resultThrottle <- struct{}{}: + case <-ctx.Done(): + return false, ctx.Err() + } + } + + // Update the liveness table + + /* + create table sector_path_url_liveness ( + storage_id text, + url text, + + last_checked timestamp not null, + last_live timestamp, + last_dead timestamp, + last_dead_reason text, + + primary key (storage_id, url), + + foreign key (storage_id) references storage_path (storage_id) on delete cascade + ) + */ + + currentTime := time.Now().UTC() + + committed, err := s.db.BeginTransaction(ctx, func(tx *harmonydb.Tx) (bool, error) { + for _, pingResult := range pingResults { + var lastLive, lastDead, lastDeadReason interface{} + if pingResult.res.Error == nil { + lastLive = currentTime.UTC() + lastDead = nil + lastDeadReason = nil + } else { + lastLive = nil + lastDead = currentTime.UTC() + lastDeadReason = pingResult.res.Error.Error() + } + + // This function updates the liveness data for a URL in the `sector_path_url_liveness` table. + // + // On conflict, where the same `storage_id` and `url` are found: + // - last_checked is always updated to the current timestamp. + // - last_live is updated to the new `last_live` if it is not null; otherwise, it retains the existing value. + // - last_dead is conditionally updated based on two criteria: + // 1. It is set to the new `last_dead` if the existing `last_dead` is null (indicating this is the first recorded failure). + // 2. It is updated to the new `last_dead` if there has been a live instance recorded after the most recent dead timestamp, indicating the resource was alive again before this new failure. + // 3. It retains the existing value if none of the above conditions are met. + // - last_dead_reason is updated similarly to `last_live`, using COALESCE to prefer the new reason if it's provided. + _, err := tx.Exec(` + INSERT INTO sector_path_url_liveness (storage_id, url, last_checked, last_live, last_dead, last_dead_reason) + VALUES ($1, $2, $3, $4, $5, $6) + ON CONFLICT (storage_id, url) DO UPDATE + SET last_checked = EXCLUDED.last_checked, + last_live = COALESCE(EXCLUDED.last_live, sector_path_url_liveness.last_live), + last_dead = CASE + WHEN sector_path_url_liveness.last_dead IS NULL THEN EXCLUDED.last_dead + WHEN sector_path_url_liveness.last_dead IS NOT NULL AND sector_path_url_liveness.last_live > sector_path_url_liveness.last_dead THEN EXCLUDED.last_dead + ELSE sector_path_url_liveness.last_dead + END, + last_dead_reason = COALESCE(EXCLUDED.last_dead_reason, sector_path_url_liveness.last_dead_reason) + `, pingResult.storageID, pingResult.url, currentTime, lastLive, lastDead, lastDeadReason) + if err != nil { + return false, xerrors.Errorf("updating liveness data: %w", err) + } + } + + return true, nil + }, harmonydb.OptionRetry()) + if err != nil { + return false, xerrors.Errorf("sector_path_url_liveness update: %w", err) + } + if !committed { + return false, xerrors.Errorf("sector_path_url_liveness update: transaction didn't commit") + } + + /////// + // Now we do the actual database cleanup + if !stillOwned() { + return false, xerrors.Errorf("task no longer owned") + } + + committed, err = s.db.BeginTransaction(ctx, func(tx *harmonydb.Tx) (bool, error) { + // Identify URLs that are consistently down + var deadURLs []struct { + StorageID storiface.ID + URL string + } + err = tx.Select(&deadURLs, ` + SELECT storage_id, url FROM sector_path_url_liveness + WHERE last_dead > COALESCE(last_live, '1970-01-01') AND last_dead < $1 + `, currentTime.Add(-StorageEndpointDeadTime).UTC()) + if err != nil { + return false, xerrors.Errorf("selecting dead URLs: %w", err) + } + + log.Debugw("dead urls", "dead_urls", deadURLs) + + // Remove dead URLs from storage_path entries and handle path cleanup + for _, du := range deadURLs { + // Fetch the current URLs for the storage path + var URLs string + err = tx.QueryRow("SELECT urls FROM storage_path WHERE storage_id = $1", du.StorageID).Scan(&URLs) + if err != nil { + return false, xerrors.Errorf("fetching storage paths: %w", err) + } + + // Filter out the dead URL using lo.Reject and prepare the updated list + urls := strings.Split(URLs, paths.URLSeparator) + urls = lo.Reject(urls, func(u string, _ int) bool { + return u == du.URL + }) + + log.Debugw("filtered urls", "urls", urls, "dead_url", du.URL, "storage_id", du.StorageID) + + if len(urls) == 0 { + // If no URLs left, remove the storage path entirely + _, err = tx.Exec("DELETE FROM storage_path WHERE storage_id = $1", du.StorageID) + if err != nil { + return false, xerrors.Errorf("deleting storage path: %w", err) + } + _, err = tx.Exec("DELETE FROM sector_location WHERE storage_id = $1", du.StorageID) + if err != nil { + return false, xerrors.Errorf("deleting sector locations: %w", err) + } + } else { + // Update the storage path with the filtered URLs + newURLs := strings.Join(urls, paths.URLSeparator) + _, err = tx.Exec("UPDATE storage_path SET urls = $1 WHERE storage_id = $2", newURLs, du.StorageID) + if err != nil { + return false, xerrors.Errorf("updating storage path urls: %w", err) + } + // Remove sector_path_url_liveness entry + _, err = tx.Exec("DELETE FROM sector_path_url_liveness WHERE storage_id = $1 AND url = $2", du.StorageID, du.URL) + if err != nil { + return false, xerrors.Errorf("deleting sector_path_url_liveness entry: %w", err) + } + } + } + + return true, nil + }, harmonydb.OptionRetry()) + if err != nil { + return false, xerrors.Errorf("removing dead URLs and cleaning storage paths: %w", err) + } + if !committed { + return false, xerrors.Errorf("transaction for removing dead URLs and cleaning paths did not commit") + } + + return true, nil +} + +func (s *StorageEndpointGC) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + id := ids[0] + return &id, nil +} + +func (s *StorageEndpointGC) TypeDetails() harmonytask.TaskTypeDetails { + return harmonytask.TaskTypeDetails{ + Max: 1, + Name: "StorageMetaGC", + Cost: resources.Resources{ + Cpu: 1, + Ram: 64 << 20, + Gpu: 0, + }, + IAmBored: harmonytask.SingletonTaskAdder(StorageEndpointGCInterval, s), + } +} + +func (s *StorageEndpointGC) Adder(taskFunc harmonytask.AddTaskFunc) { + // lazy endpoint, added when bored + return +} + +var _ harmonytask.TaskInterface = &StorageEndpointGC{} diff --git a/curiosrc/market/deal_ingest.go b/curiosrc/market/deal_ingest.go new file mode 100644 index 00000000000..ea382717acc --- /dev/null +++ b/curiosrc/market/deal_ingest.go @@ -0,0 +1,137 @@ +package market + +import ( + "context" + "encoding/json" + "net/http" + "net/url" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-padreader" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/curiosrc/seal" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" +) + +type Ingester interface { + AllocatePieceToSector(ctx context.Context, maddr address.Address, piece api.PieceDealInfo, rawSize int64, source url.URL, header http.Header) (api.SectorOffset, error) +} + +type PieceIngesterApi interface { + StateMinerInfo(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) + StateMinerAllocated(ctx context.Context, a address.Address, key types.TipSetKey) (*bitfield.BitField, error) + StateNetworkVersion(ctx context.Context, key types.TipSetKey) (network.Version, error) +} + +type PieceIngester struct { + db *harmonydb.DB + api PieceIngesterApi +} + +func NewPieceIngester(db *harmonydb.DB, api PieceIngesterApi) *PieceIngester { + return &PieceIngester{db: db, api: api} +} + +func (p *PieceIngester) AllocatePieceToSector(ctx context.Context, maddr address.Address, piece api.PieceDealInfo, rawSize int64, source url.URL, header http.Header) (api.SectorOffset, error) { + mi, err := p.api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return api.SectorOffset{}, err + } + + if piece.DealProposal.PieceSize != abi.PaddedPieceSize(mi.SectorSize) { + return api.SectorOffset{}, xerrors.Errorf("only full sector pieces supported for now") + } + + // check raw size + if piece.DealProposal.PieceSize != padreader.PaddedSize(uint64(rawSize)).Padded() { + return api.SectorOffset{}, xerrors.Errorf("raw size doesn't match padded piece size") + } + + // add initial piece + to a sector + nv, err := p.api.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return api.SectorOffset{}, xerrors.Errorf("getting network version: %w", err) + } + + synth := false // todo synthetic porep config + spt, err := miner.PreferredSealProofTypeFromWindowPoStType(nv, mi.WindowPoStProofType, synth) + if err != nil { + return api.SectorOffset{}, xerrors.Errorf("getting seal proof type: %w", err) + } + + mid, err := address.IDFromAddress(maddr) + if err != nil { + return api.SectorOffset{}, xerrors.Errorf("getting miner ID: %w", err) + } + + num, err := seal.AllocateSectorNumbers(ctx, p.api, p.db, maddr, 1, func(tx *harmonydb.Tx, numbers []abi.SectorNumber) (bool, error) { + if len(numbers) != 1 { + return false, xerrors.Errorf("expected one sector number") + } + n := numbers[0] + + _, err := tx.Exec("INSERT INTO sectors_sdr_pipeline (sp_id, sector_number, reg_seal_proof) VALUES ($1, $2, $3)", mid, n, spt) + if err != nil { + return false, xerrors.Errorf("inserting into sectors_sdr_pipeline: %w", err) + } + + dataHdrJson, err := json.Marshal(header) + if err != nil { + return false, xerrors.Errorf("json.Marshal(header): %w", err) + } + + dealProposalJson, err := json.Marshal(piece.DealProposal) + if err != nil { + return false, xerrors.Errorf("json.Marshal(piece.DealProposal): %w", err) + } + + _, err = tx.Exec(`INSERT INTO sectors_sdr_initial_pieces (sp_id, + sector_number, + piece_index, + + piece_cid, + piece_size, + + data_url, + data_headers, + data_raw_size, + data_delete_on_finalize, + + f05_publish_cid, + f05_deal_id, + f05_deal_proposal, + f05_deal_start_epoch, + f05_deal_end_epoch) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)`, + mid, n, 0, + piece.DealProposal.PieceCID, piece.DealProposal.PieceSize, + source.String(), dataHdrJson, rawSize, !piece.KeepUnsealed, + piece.PublishCid, piece.DealID, dealProposalJson, piece.DealSchedule.StartEpoch, piece.DealSchedule.EndEpoch) + if err != nil { + return false, xerrors.Errorf("inserting into sectors_sdr_initial_pieces: %w", err) + } + + return true, nil + }) + if err != nil { + return api.SectorOffset{}, xerrors.Errorf("allocating sector numbers: %w", err) + } + + if len(num) != 1 { + return api.SectorOffset{}, xerrors.Errorf("expected one sector number") + } + + // After we insert the piece/sector_pipeline entries, the lpseal/poller will take it from here + + return api.SectorOffset{ + Sector: num[0], + Offset: 0, + }, nil +} diff --git a/curiosrc/market/fakelm/iface.go b/curiosrc/market/fakelm/iface.go new file mode 100644 index 00000000000..1bc91b35e75 --- /dev/null +++ b/curiosrc/market/fakelm/iface.go @@ -0,0 +1,33 @@ +package fakelm + +import ( + "context" + + "github.com/google/uuid" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +// MinimalLMApi is a subset of the LotusMiner API that is exposed by Curio +// for consumption by boost +type MinimalLMApi interface { + ActorAddress(context.Context) (address.Address, error) + + WorkerJobs(context.Context) (map[uuid.UUID][]storiface.WorkerJob, error) + + SectorsStatus(ctx context.Context, sid abi.SectorNumber, showOnChainInfo bool) (api.SectorInfo, error) + + SectorsList(context.Context) ([]abi.SectorNumber, error) + SectorsSummary(ctx context.Context) (map[api.SectorState]int, error) + + SectorsListInStates(context.Context, []api.SectorState) ([]abi.SectorNumber, error) + + StorageRedeclareLocal(context.Context, *storiface.ID, bool) error + + ComputeDataCid(ctx context.Context, pieceSize abi.UnpaddedPieceSize, pieceData storiface.Data) (abi.PieceInfo, error) + SectorAddPieceToAny(ctx context.Context, size abi.UnpaddedPieceSize, r storiface.Data, d api.PieceDealInfo) (api.SectorOffset, error) +} diff --git a/curiosrc/market/fakelm/lmimpl.go b/curiosrc/market/fakelm/lmimpl.go new file mode 100644 index 00000000000..9dc19e627d8 --- /dev/null +++ b/curiosrc/market/fakelm/lmimpl.go @@ -0,0 +1,348 @@ +package fakelm + +import ( + "context" + "encoding/base64" + "net/http" + "net/url" + + "github.com/gbrlsnchs/jwt/v3" + "github.com/google/uuid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-jsonrpc/auth" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/network" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/curiosrc/market" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/storage/paths" + sealing "github.com/filecoin-project/lotus/storage/pipeline" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +type LMRPCProvider struct { + si paths.SectorIndex + full api.FullNode + + maddr address.Address // lotus-miner RPC is single-actor + minerID abi.ActorID + + ssize abi.SectorSize + + pi market.Ingester + db *harmonydb.DB + conf *config.CurioConfig +} + +func NewLMRPCProvider(si paths.SectorIndex, full api.FullNode, maddr address.Address, minerID abi.ActorID, ssize abi.SectorSize, pi market.Ingester, db *harmonydb.DB, conf *config.CurioConfig) *LMRPCProvider { + return &LMRPCProvider{ + si: si, + full: full, + maddr: maddr, + minerID: minerID, + ssize: ssize, + pi: pi, + db: db, + conf: conf, + } +} + +func (l *LMRPCProvider) ActorAddress(ctx context.Context) (address.Address, error) { + return l.maddr, nil +} + +func (l *LMRPCProvider) WorkerJobs(ctx context.Context) (map[uuid.UUID][]storiface.WorkerJob, error) { + // correct enough + return map[uuid.UUID][]storiface.WorkerJob{}, nil +} + +func (l *LMRPCProvider) SectorsStatus(ctx context.Context, sid abi.SectorNumber, showOnChainInfo bool) (api.SectorInfo, error) { + si, err := l.si.StorageFindSector(ctx, abi.SectorID{Miner: l.minerID, Number: sid}, storiface.FTSealed|storiface.FTCache, 0, false) + if err != nil { + return api.SectorInfo{}, err + } + + var ssip []struct { + PieceCID *string `db:"piece_cid"` + DealID *int64 `db:"f05_deal_id"` + } + + err = l.db.Select(ctx, &ssip, "SELECT ssip.piece_cid, ssip.f05_deal_id FROM sectors_sdr_pipeline p LEFT JOIN sectors_sdr_initial_pieces ssip ON p.sp_id = ssip.sp_id AND p.sector_number = ssip.sector_number WHERE p.sp_id = $1 AND p.sector_number = $2", l.minerID, sid) + if err != nil { + return api.SectorInfo{}, err + } + + var deals []abi.DealID + if len(ssip) > 0 { + for _, d := range ssip { + if d.DealID != nil { + deals = append(deals, abi.DealID(*d.DealID)) + } + } + } else { + osi, err := l.full.StateSectorGetInfo(ctx, l.maddr, sid, types.EmptyTSK) + if err != nil { + return api.SectorInfo{}, err + } + + if osi != nil { + deals = osi.DealIDs + } + } + + spt, err := miner.SealProofTypeFromSectorSize(l.ssize, network.Version20, false) // good enough, just need this for ssize anyways + if err != nil { + return api.SectorInfo{}, err + } + + if len(si) == 0 { + state := api.SectorState(sealing.UndefinedSectorState) + if len(ssip) > 0 { + state = api.SectorState(sealing.PreCommit1) + } + + return api.SectorInfo{ + SectorID: sid, + State: state, + CommD: nil, + CommR: nil, + Proof: nil, + Deals: deals, + Pieces: nil, + Ticket: api.SealTicket{}, + Seed: api.SealSeed{}, + PreCommitMsg: nil, + CommitMsg: nil, + Retries: 0, + ToUpgrade: false, + ReplicaUpdateMessage: nil, + LastErr: "", + Log: nil, + SealProof: spt, + Activation: 0, + Expiration: 0, + DealWeight: big.Zero(), + VerifiedDealWeight: big.Zero(), + InitialPledge: big.Zero(), + OnTime: 0, + Early: 0, + }, nil + } + + var state = api.SectorState(sealing.Proving) + if !si[0].CanStore { + state = api.SectorState(sealing.PreCommit2) + } + + // todo improve this with on-chain info + return api.SectorInfo{ + SectorID: sid, + State: state, + CommD: nil, + CommR: nil, + Proof: nil, + Deals: deals, + Pieces: nil, + Ticket: api.SealTicket{}, + Seed: api.SealSeed{}, + PreCommitMsg: nil, + CommitMsg: nil, + Retries: 0, + ToUpgrade: false, + ReplicaUpdateMessage: nil, + LastErr: "", + Log: nil, + + SealProof: spt, + Activation: 0, + Expiration: 0, + DealWeight: big.Zero(), + VerifiedDealWeight: big.Zero(), + InitialPledge: big.Zero(), + OnTime: 0, + Early: 0, + }, nil +} + +func (l *LMRPCProvider) SectorsList(ctx context.Context) ([]abi.SectorNumber, error) { + decls, err := l.si.StorageList(ctx) + if err != nil { + return nil, err + } + + var out []abi.SectorNumber + for _, decl := range decls { + for _, s := range decl { + if s.Miner != l.minerID { + continue + } + + out = append(out, s.SectorID.Number) + } + } + + return out, nil +} + +type sectorParts struct { + sealed, unsealed, cache bool + inStorage bool +} + +func (l *LMRPCProvider) SectorsSummary(ctx context.Context) (map[api.SectorState]int, error) { + decls, err := l.si.StorageList(ctx) + if err != nil { + return nil, err + } + + states := map[abi.SectorID]sectorParts{} + for si, decll := range decls { + sinfo, err := l.si.StorageInfo(ctx, si) + if err != nil { + return nil, err + } + + for _, decl := range decll { + if decl.Miner != l.minerID { + continue + } + + state := states[abi.SectorID{Miner: decl.Miner, Number: decl.SectorID.Number}] + state.sealed = state.sealed || decl.Has(storiface.FTSealed) + state.unsealed = state.unsealed || decl.Has(storiface.FTUnsealed) + state.cache = state.cache || decl.Has(storiface.FTCache) + state.inStorage = state.inStorage || sinfo.CanStore + states[abi.SectorID{Miner: decl.Miner, Number: decl.SectorID.Number}] = state + } + } + + out := map[api.SectorState]int{} + for _, state := range states { + switch { + case state.sealed && state.inStorage: + out[api.SectorState(sealing.Proving)]++ + default: + // not even close to correct, but good enough for now + out[api.SectorState(sealing.PreCommit1)]++ + } + } + + return out, nil +} + +func (l *LMRPCProvider) SectorsListInStates(ctx context.Context, want []api.SectorState) ([]abi.SectorNumber, error) { + decls, err := l.si.StorageList(ctx) + if err != nil { + return nil, err + } + + wantProving, wantPrecommit1 := false, false + for _, s := range want { + switch s { + case api.SectorState(sealing.Proving): + wantProving = true + case api.SectorState(sealing.PreCommit1): + wantPrecommit1 = true + } + } + + states := map[abi.SectorID]sectorParts{} + + for si, decll := range decls { + sinfo, err := l.si.StorageInfo(ctx, si) + if err != nil { + return nil, err + } + + for _, decl := range decll { + if decl.Miner != l.minerID { + continue + } + + state := states[abi.SectorID{Miner: decl.Miner, Number: decl.SectorID.Number}] + state.sealed = state.sealed || decl.Has(storiface.FTSealed) + state.unsealed = state.unsealed || decl.Has(storiface.FTUnsealed) + state.cache = state.cache || decl.Has(storiface.FTCache) + state.inStorage = state.inStorage || sinfo.CanStore + states[abi.SectorID{Miner: decl.Miner, Number: decl.SectorID.Number}] = state + } + } + var out []abi.SectorNumber + + for id, state := range states { + switch { + case state.sealed && state.inStorage: + if wantProving { + out = append(out, id.Number) + } + default: + // not even close to correct, but good enough for now + if wantPrecommit1 { + out = append(out, id.Number) + } + } + } + + return out, nil +} + +func (l *LMRPCProvider) StorageRedeclareLocal(ctx context.Context, id *storiface.ID, b bool) error { + // so this rescans and redeclares sectors on lotus-miner; whyyy is boost even calling this? + + return nil +} + +func (l *LMRPCProvider) IsUnsealed(ctx context.Context, sectorNum abi.SectorNumber, offset abi.UnpaddedPieceSize, length abi.UnpaddedPieceSize) (bool, error) { + sectorID := abi.SectorID{Miner: l.minerID, Number: sectorNum} + + si, err := l.si.StorageFindSector(ctx, sectorID, storiface.FTUnsealed, 0, false) + if err != nil { + return false, err + } + + // yes, yes, technically sectors can be partially unsealed, but that is never done in practice + // and can't even be easily done with the current implementation + return len(si) > 0, nil +} + +func (l *LMRPCProvider) ComputeDataCid(ctx context.Context, pieceSize abi.UnpaddedPieceSize, pieceData storiface.Data) (abi.PieceInfo, error) { + return abi.PieceInfo{}, xerrors.Errorf("not supported") +} + +func (l *LMRPCProvider) SectorAddPieceToAny(ctx context.Context, size abi.UnpaddedPieceSize, r storiface.Data, d api.PieceDealInfo) (api.SectorOffset, error) { + if d.DealProposal.PieceSize != abi.PaddedPieceSize(l.ssize) { + return api.SectorOffset{}, xerrors.Errorf("only full-sector pieces are supported") + } + + return api.SectorOffset{}, xerrors.Errorf("not supported, use AllocatePieceToSector") +} + +func (l *LMRPCProvider) AllocatePieceToSector(ctx context.Context, maddr address.Address, piece api.PieceDealInfo, rawSize int64, source url.URL, header http.Header) (api.SectorOffset, error) { + return l.pi.AllocatePieceToSector(ctx, maddr, piece, rawSize, source, header) +} + +func (l *LMRPCProvider) AuthNew(ctx context.Context, perms []auth.Permission) ([]byte, error) { + type jwtPayload struct { + Allow []auth.Permission + } + + p := jwtPayload{ + Allow: perms, + } + + sk, err := base64.StdEncoding.DecodeString(l.conf.Apis.StorageRPCSecret) + if err != nil { + return nil, xerrors.Errorf("decode secret: %w", err) + } + + return jwt.Sign(&p, jwt.NewHS256(sk)) +} + +var _ MinimalLMApi = &LMRPCProvider{} diff --git a/curiosrc/market/lmrpc/lmrpc.go b/curiosrc/market/lmrpc/lmrpc.go new file mode 100644 index 00000000000..7286cf3667d --- /dev/null +++ b/curiosrc/market/lmrpc/lmrpc.go @@ -0,0 +1,499 @@ +package lmrpc + +import ( + "context" + "fmt" + "io" + "net" + "net/http" + "net/url" + "strconv" + "strings" + "sync" + "time" + + "github.com/google/uuid" + logging "github.com/ipfs/go-log/v2" + "github.com/jackc/pgx/v5" + manet "github.com/multiformats/go-multiaddr/net" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" + cumarket "github.com/filecoin-project/lotus/curiosrc/market" + "github.com/filecoin-project/lotus/curiosrc/market/fakelm" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/nullreader" + "github.com/filecoin-project/lotus/metrics/proxy" + "github.com/filecoin-project/lotus/node" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/storage/paths" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +var log = logging.Logger("lmrpc") + +const backpressureWaitTime = 30 * time.Second + +func ServeCurioMarketRPCFromConfig(db *harmonydb.DB, full api.FullNode, cfg *config.CurioConfig) error { + return forEachMarketRPC(cfg, func(maddr string, listen string) error { + addr, err := address.NewFromString(maddr) + if err != nil { + return xerrors.Errorf("parsing actor address: %w", err) + } + + go func() { + err := ServeCurioMarketRPC(db, full, addr, cfg, listen) + if err != nil { + log.Errorf("failed to serve market rpc: %s", err) + } + }() + + return nil + }) +} + +func MakeTokens(cfg *config.CurioConfig) (map[address.Address]string, error) { + out := map[address.Address]string{} + + err := forEachMarketRPC(cfg, func(smaddr string, listen string) error { + ctx := context.Background() + + laddr, err := net.ResolveTCPAddr("tcp", listen) + if err != nil { + return xerrors.Errorf("net resolve: %w", err) + } + + if len(laddr.IP) == 0 || laddr.IP.IsUnspecified() { + return xerrors.Errorf("market rpc server listen address must be a specific address, not %s (probably missing bind IP)", listen) + } + + // need minimal provider with just the config + lp := fakelm.NewLMRPCProvider(nil, nil, address.Undef, 0, 0, nil, nil, cfg) + + tok, err := lp.AuthNew(ctx, api.AllPermissions) + if err != nil { + return err + } + + // parse listen into multiaddr + ma, err := manet.FromNetAddr(laddr) + if err != nil { + return xerrors.Errorf("net from addr (%v): %w", laddr, err) + } + + maddr, err := address.NewFromString(smaddr) + if err != nil { + return xerrors.Errorf("parsing actor address: %w", err) + } + + token := fmt.Sprintf("%s:%s", tok, ma) + out[maddr] = token + + return nil + }) + + return out, err +} + +func forEachMarketRPC(cfg *config.CurioConfig, cb func(string, string) error) error { + for n, server := range cfg.Subsystems.BoostAdapters { + n := n + + // server: [f0.. actor address]:[bind address] + // bind address is either a numeric port or a full address + + // first split at first : to get the actor address and the bind address + split := strings.SplitN(server, ":", 2) + + // if the split length is not 2, return an error + if len(split) != 2 { + return fmt.Errorf("bad market rpc server config %d %s, expected [f0.. actor address]:[bind address]", n, server) + } + + // get the actor address and the bind address + strMaddr, strListen := split[0], split[1] + + maddr, err := address.NewFromString(strMaddr) + if err != nil { + return xerrors.Errorf("parsing actor address: %w", err) + } + + // check the listen address + if strListen == "" { + return fmt.Errorf("bad market rpc server config %d %s, expected [f0.. actor address]:[bind address]", n, server) + } + // if listen address is numeric, prepend the default host + if _, err := strconv.Atoi(strListen); err == nil { + strListen = "0.0.0.0:" + strListen + } + // check if the listen address is a valid address + if _, _, err := net.SplitHostPort(strListen); err != nil { + return fmt.Errorf("bad market rpc server config %d %s, expected [f0.. actor address]:[bind address]", n, server) + } + + log.Infow("Starting market RPC server", "actor", maddr, "listen", strListen) + + if err := cb(strMaddr, strListen); err != nil { + return err + } + } + + return nil +} + +func ServeCurioMarketRPC(db *harmonydb.DB, full api.FullNode, maddr address.Address, conf *config.CurioConfig, listen string) error { + ctx := context.Background() + + pin := cumarket.NewPieceIngester(db, full) + + si := paths.NewDBIndex(nil, db) + + mid, err := address.IDFromAddress(maddr) + if err != nil { + return xerrors.Errorf("getting miner id: %w", err) + } + + mi, err := full.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + lp := fakelm.NewLMRPCProvider(si, full, maddr, abi.ActorID(mid), mi.SectorSize, pin, db, conf) + + laddr, err := net.ResolveTCPAddr("tcp", listen) + if err != nil { + return xerrors.Errorf("net resolve: %w", err) + } + + if len(laddr.IP) == 0 || laddr.IP.IsUnspecified() { + return xerrors.Errorf("market rpc server listen address must be a specific address, not %s (probably missing bind IP)", listen) + } + rootUrl := url.URL{ + Scheme: "http", + Host: laddr.String(), + } + + ast := api.StorageMinerStruct{} + + ast.CommonStruct.Internal.Version = func(ctx context.Context) (api.APIVersion, error) { + return api.APIVersion{ + Version: "curio-proxy-v0", + APIVersion: api.MinerAPIVersion0, + BlockDelay: build.BlockDelaySecs, + }, nil + } + + ast.CommonStruct.Internal.AuthNew = lp.AuthNew + + ast.Internal.ActorAddress = lp.ActorAddress + ast.Internal.WorkerJobs = lp.WorkerJobs + ast.Internal.SectorsStatus = lp.SectorsStatus + ast.Internal.SectorsList = lp.SectorsList + ast.Internal.SectorsSummary = lp.SectorsSummary + ast.Internal.SectorsListInStates = lp.SectorsListInStates + ast.Internal.StorageRedeclareLocal = lp.StorageRedeclareLocal + ast.Internal.ComputeDataCid = lp.ComputeDataCid + + type pieceInfo struct { + data storiface.Data + size abi.UnpaddedPieceSize + + done chan struct{} + } + + pieceInfoLk := new(sync.Mutex) + pieceInfos := map[uuid.UUID][]pieceInfo{} + + ast.Internal.SectorAddPieceToAny = func(ctx context.Context, pieceSize abi.UnpaddedPieceSize, pieceData storiface.Data, deal api.PieceDealInfo) (api.SectorOffset, error) { + origPieceData := pieceData + defer func() { + closer, ok := origPieceData.(io.Closer) + if !ok { + log.Warnf("DataCid: cannot close pieceData reader %T because it is not an io.Closer", origPieceData) + return + } + if err := closer.Close(); err != nil { + log.Warnw("closing pieceData in DataCid", "error", err) + } + }() + + pi := pieceInfo{ + data: pieceData, + size: pieceSize, + + done: make(chan struct{}), + } + + pieceUUID := uuid.New() + + //color.Blue("%s %s piece assign request with id %s", deal.DealProposal.PieceCID, deal.DealProposal.Provider, pieceUUID) + log.Infow("piece assign request", "piece_cid", deal.DealProposal.PieceCID, "provider", deal.DealProposal.Provider, "piece_uuid", pieceUUID) + + pieceInfoLk.Lock() + pieceInfos[pieceUUID] = append(pieceInfos[pieceUUID], pi) + pieceInfoLk.Unlock() + + // /piece?piece_cid=xxxx + dataUrl := rootUrl + dataUrl.Path = "/piece" + dataUrl.RawQuery = "piece_id=" + pieceUUID.String() + + // add piece entry + + var refID int64 + var pieceWasCreated bool + + for { + var backpressureWait bool + + comm, err := db.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { + // BACKPRESSURE + wait, err := maybeApplyBackpressure(tx, conf.Ingest) + if err != nil { + return false, xerrors.Errorf("backpressure checks: %w", err) + } + if wait { + backpressureWait = true + return false, nil + } + + var pieceID int64 + // Attempt to select the piece ID first + err = tx.QueryRow(`SELECT id FROM parked_pieces WHERE piece_cid = $1`, deal.DealProposal.PieceCID.String()).Scan(&pieceID) + + if err != nil { + if err == pgx.ErrNoRows { + // Piece does not exist, attempt to insert + err = tx.QueryRow(` + INSERT INTO parked_pieces (piece_cid, piece_padded_size, piece_raw_size) + VALUES ($1, $2, $3) + ON CONFLICT (piece_cid) DO NOTHING + RETURNING id`, deal.DealProposal.PieceCID.String(), int64(pieceSize.Padded()), int64(pieceSize)).Scan(&pieceID) + if err != nil { + return false, xerrors.Errorf("inserting new parked piece and getting id: %w", err) + } + pieceWasCreated = true // New piece was created + } else { + // Some other error occurred during select + return false, xerrors.Errorf("checking existing parked piece: %w", err) + } + } else { + pieceWasCreated = false // Piece already exists, no new piece was created + } + + // Add parked_piece_ref + err = tx.QueryRow(`INSERT INTO parked_piece_refs (piece_id, data_url) + VALUES ($1, $2) RETURNING ref_id`, pieceID, dataUrl.String()).Scan(&refID) + if err != nil { + return false, xerrors.Errorf("inserting parked piece ref: %w", err) + } + + // If everything went well, commit the transaction + return true, nil // This will commit the transaction + }, harmonydb.OptionRetry()) + if err != nil { + return api.SectorOffset{}, xerrors.Errorf("inserting parked piece: %w", err) + } + if !comm { + if backpressureWait { + // Backpressure was applied, wait and try again + select { + case <-time.After(backpressureWaitTime): + case <-ctx.Done(): + return api.SectorOffset{}, xerrors.Errorf("context done while waiting for backpressure: %w", ctx.Err()) + } + continue + } + + return api.SectorOffset{}, xerrors.Errorf("piece tx didn't commit") + } + + break + } + + // wait for piece to be parked + if pieceWasCreated { + <-pi.done + } else { + // If the piece was not created, we need to close the done channel + close(pi.done) + + go func() { + // close the data reader (drain to eof if it's not a closer) + if closer, ok := pieceData.(io.Closer); ok { + if err := closer.Close(); err != nil { + log.Warnw("closing pieceData in DataCid", "error", err) + } + } else { + log.Warnw("pieceData is not an io.Closer", "type", fmt.Sprintf("%T", pieceData)) + + _, err := io.Copy(io.Discard, pieceData) + if err != nil { + log.Warnw("draining pieceData in DataCid", "error", err) + } + } + }() + } + pieceIDUrl := url.URL{ + Scheme: "pieceref", + Opaque: fmt.Sprintf("%d", refID), + } + + // make a sector + so, err := pin.AllocatePieceToSector(ctx, maddr, deal, int64(pieceSize), pieceIDUrl, nil) + if err != nil { + return api.SectorOffset{}, err + } + + log.Infow("piece assigned to sector", "piece_cid", deal.DealProposal.PieceCID, "sector", so.Sector, "offset", so.Offset) + + return so, nil + } + + ast.Internal.StorageList = si.StorageList + ast.Internal.StorageDetach = si.StorageDetach + ast.Internal.StorageReportHealth = si.StorageReportHealth + ast.Internal.StorageDeclareSector = si.StorageDeclareSector + ast.Internal.StorageDropSector = si.StorageDropSector + ast.Internal.StorageFindSector = si.StorageFindSector + ast.Internal.StorageInfo = si.StorageInfo + ast.Internal.StorageBestAlloc = si.StorageBestAlloc + ast.Internal.StorageLock = si.StorageLock + ast.Internal.StorageTryLock = si.StorageTryLock + ast.Internal.StorageGetLocks = si.StorageGetLocks + + var pieceHandler http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) { + // /piece?piece_id=xxxx + pieceUUID := r.URL.Query().Get("piece_id") + + pu, err := uuid.Parse(pieceUUID) + if err != nil { + http.Error(w, "bad piece id", http.StatusBadRequest) + return + } + + if r.Method != http.MethodGet { + http.Error(w, "bad method", http.StatusMethodNotAllowed) + return + } + + fmt.Printf("%s request for piece from %s\n", pieceUUID, r.RemoteAddr) + + pieceInfoLk.Lock() + pis, ok := pieceInfos[pu] + if !ok { + http.Error(w, "piece not found", http.StatusNotFound) + log.Warnw("piece not found", "piece_uuid", pu) + pieceInfoLk.Unlock() + return + } + + // pop + pi := pis[0] + pis = pis[1:] + + pieceInfos[pu] = pis + if len(pis) == 0 { + delete(pieceInfos, pu) + } + + pieceInfoLk.Unlock() + + start := time.Now() + + pieceData := io.LimitReader(io.MultiReader( + pi.data, + nullreader.Reader{}, + ), int64(pi.size)) + + n, err := io.Copy(w, pieceData) + close(pi.done) + + took := time.Since(start) + mbps := float64(n) / (1024 * 1024) / took.Seconds() + + if err != nil { + log.Errorf("copying piece data: %s", err) + return + } + + log.Infow("piece served", "piece_uuid", pu, "size", float64(n)/(1024*1024), "duration", took, "speed", mbps) + } + + finalApi := proxy.LoggingAPI[api.StorageMiner, api.StorageMinerStruct](&ast) + + mh, err := node.MinerHandler(finalApi, false) // todo permissioned + if err != nil { + return err + } + + mux := http.NewServeMux() + mux.Handle("/piece", pieceHandler) + mux.Handle("/", mh) + + server := &http.Server{ + Addr: listen, + Handler: mux, + ReadTimeout: 48 * time.Hour, + WriteTimeout: 48 * time.Hour, // really high because we block until pieces are saved in PiecePark + } + + return server.ListenAndServe() +} + +func maybeApplyBackpressure(tx *harmonydb.Tx, cfg config.CurioIngestConfig) (wait bool, err error) { + var bufferedSDR, bufferedTrees, bufferedPoRep int + err = tx.QueryRow(`WITH BufferedSDR AS ( + SELECT SUM(buffered_count) AS buffered_sdr_count + FROM ( + SELECT COUNT(p.task_id_sdr) - COUNT(t.owner_id) AS buffered_count + FROM sectors_sdr_pipeline p + LEFT JOIN harmony_task t ON p.task_id_sdr = t.id + WHERE p.after_sdr = false + UNION ALL + SELECT COUNT(1) AS buffered_count + FROM parked_pieces + WHERE complete = false + ) AS subquery +), + BufferedTrees AS ( + SELECT COUNT(p.task_id_tree_r) - COUNT(t.owner_id) AS buffered_trees_count + FROM sectors_sdr_pipeline p + LEFT JOIN harmony_task t ON p.task_id_tree_r = t.id + WHERE p.after_sdr = true AND p.after_tree_r = false + ), + BufferedPoRep AS ( + SELECT COUNT(p.task_id_porep) - COUNT(t.owner_id) AS buffered_porep_count + FROM sectors_sdr_pipeline p + LEFT JOIN harmony_task t ON p.task_id_porep = t.id + WHERE p.after_tree_r = true AND p.after_porep = false + ) +SELECT + (SELECT buffered_sdr_count FROM BufferedSDR) AS total_buffered, + (SELECT buffered_trees_count FROM BufferedTrees) AS buffered_trees_count, + (SELECT buffered_porep_count FROM BufferedPoRep) AS buffered_porep_count +`).Scan(&bufferedSDR, &bufferedTrees, &bufferedPoRep) + if err != nil { + return false, xerrors.Errorf("counting parked pieces: %w", err) + } + + if cfg.MaxQueueSDR != 0 && bufferedSDR > cfg.MaxQueueSDR { + log.Debugw("backpressure", "reason", "too many SDR tasks", "buffered", bufferedSDR, "max", cfg.MaxQueueSDR) + return true, nil + } + if cfg.MaxQueueTrees != 0 && bufferedTrees > cfg.MaxQueueTrees { + log.Debugw("backpressure", "reason", "too many tree tasks", "buffered", bufferedTrees, "max", cfg.MaxQueueTrees) + return true, nil + } + if cfg.MaxQueuePoRep != 0 && bufferedPoRep > cfg.MaxQueuePoRep { + log.Debugw("backpressure", "reason", "too many PoRep tasks", "buffered", bufferedPoRep, "max", cfg.MaxQueuePoRep) + return true, nil + } + + return false, nil +} diff --git a/provider/lpmessage/sender.go b/curiosrc/message/sender.go similarity index 97% rename from provider/lpmessage/sender.go rename to curiosrc/message/sender.go index 0db0c0b5102..614bc0be23a 100644 --- a/provider/lpmessage/sender.go +++ b/curiosrc/message/sender.go @@ -1,4 +1,4 @@ -package lpmessage +package message import ( "bytes" @@ -22,7 +22,7 @@ import ( "github.com/filecoin-project/lotus/lib/promise" ) -var log = logging.Logger("lpmessage") +var log = logging.Logger("curio/message") var SendLockedWait = 100 * time.Millisecond @@ -187,7 +187,7 @@ func (s *SendTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done b } else { // Note: this handles an unlikely edge-case: // We have previously signed the message but either failed to send it or failed to update the db - // note that when that happens the likely cause is the provider process losing its db connection + // note that when that happens the likely cause is the curio process losing its db connection // or getting killed before it can update the db. In that case the message lock will still be held // so it will be safe to rebroadcast the signed message @@ -390,7 +390,7 @@ func (s *Sender) Send(ctx context.Context, msg *types.Message, mss *api.MessageS break } - log.Infow("sent message", "cid", sigCid, "task_id", taskAdder, "send_error", sendErr, "poll_loops", pollLoops) + log.Infow("sent message", "cid", sigCid, "task_id", sendTaskID, "send_error", sendErr, "poll_loops", pollLoops) return sigCid, sendErr } diff --git a/curiosrc/message/watch.go b/curiosrc/message/watch.go new file mode 100644 index 00000000000..2253df28434 --- /dev/null +++ b/curiosrc/message/watch.go @@ -0,0 +1,214 @@ +package message + +import ( + "context" + "encoding/json" + "sync/atomic" + + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/curiosrc/chainsched" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" +) + +const MinConfidence = 6 + +type MessageWaiterApi interface { + StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) + ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) + ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error) + StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) + ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Message, error) +} + +type MessageWatcher struct { + db *harmonydb.DB + ht *harmonytask.TaskEngine + api MessageWaiterApi + + stopping, stopped chan struct{} + + updateCh chan struct{} + bestTs atomic.Pointer[types.TipSetKey] +} + +func NewMessageWatcher(db *harmonydb.DB, ht *harmonytask.TaskEngine, pcs *chainsched.CurioChainSched, api MessageWaiterApi) (*MessageWatcher, error) { + mw := &MessageWatcher{ + db: db, + ht: ht, + api: api, + stopping: make(chan struct{}), + stopped: make(chan struct{}), + updateCh: make(chan struct{}), + } + go mw.run() + if err := pcs.AddHandler(mw.processHeadChange); err != nil { + return nil, err + } + return mw, nil +} + +func (mw *MessageWatcher) run() { + defer close(mw.stopped) + + for { + select { + case <-mw.stopping: + // todo cleanup assignments + return + case <-mw.updateCh: + mw.update() + } + } +} + +func (mw *MessageWatcher) update() { + ctx := context.Background() + + tsk := *mw.bestTs.Load() + + ts, err := mw.api.ChainGetTipSet(ctx, tsk) + if err != nil { + log.Errorf("failed to get tipset: %+v", err) + return + } + + lbts, err := mw.api.ChainGetTipSetByHeight(ctx, ts.Height()-MinConfidence, tsk) + if err != nil { + log.Errorf("failed to get tipset: %+v", err) + return + } + lbtsk := lbts.Key() + + machineID := mw.ht.ResourcesAvailable().MachineID + + // first if we see pending messages with null owner, assign them to ourselves + { + n, err := mw.db.Exec(ctx, `UPDATE message_waits SET waiter_machine_id = $1 WHERE waiter_machine_id IS NULL AND executed_tsk_cid IS NULL`, machineID) + if err != nil { + log.Errorf("failed to assign pending messages: %+v", err) + return + } + if n > 0 { + log.Debugw("assigned pending messages to ourselves", "assigned", n) + } + } + + // get messages assigned to us + var msgs []struct { + Cid string `db:"signed_message_cid"` + From string `db:"from_key"` + Nonce uint64 `db:"nonce"` + + FromAddr address.Address `db:"-"` + } + + // really large limit in case of things getting stuck and backlogging severely + err = mw.db.Select(ctx, &msgs, `SELECT signed_message_cid, from_key, nonce FROM message_waits + JOIN message_sends ON signed_message_cid = signed_cid + WHERE waiter_machine_id = $1 LIMIT 10000`, machineID) + if err != nil { + log.Errorf("failed to get assigned messages: %+v", err) + return + } + + // get address/nonce set to check + toCheck := make(map[address.Address]uint64) + + for i := range msgs { + msgs[i].FromAddr, err = address.NewFromString(msgs[i].From) + if err != nil { + log.Errorf("failed to parse from address: %+v", err) + return + } + toCheck[msgs[i].FromAddr] = 0 + } + + // get the nonce for each address + for addr := range toCheck { + act, err := mw.api.StateGetActor(ctx, addr, lbtsk) + if err != nil { + log.Errorf("failed to get actor: %+v", err) + return + } + + toCheck[addr] = act.Nonce + } + + // check if any of the messages we have assigned to us are now on chain, and have been for MinConfidence epochs + for _, msg := range msgs { + if msg.Nonce > toCheck[msg.FromAddr] { + continue // definitely not on chain yet + } + + look, err := mw.api.StateSearchMsg(ctx, lbtsk, cid.MustParse(msg.Cid), api.LookbackNoLimit, false) + if err != nil { + log.Errorf("failed to search for message: %+v", err) + return + } + + if look == nil { + continue // not on chain yet (or not executed yet) + } + + tskCid, err := look.TipSet.Cid() + if err != nil { + log.Errorf("failed to get tipset cid: %+v", err) + return + } + + emsg, err := mw.api.ChainGetMessage(ctx, look.Message) + if err != nil { + log.Errorf("failed to get message: %+v", err) + return + } + + execMsg, err := json.Marshal(emsg) + if err != nil { + log.Errorf("failed to marshal message: %+v", err) + return + } + + // record in db + _, err = mw.db.Exec(ctx, `UPDATE message_waits SET + waiter_machine_id = NULL, + executed_tsk_cid = $1, executed_tsk_epoch = $2, + executed_msg_cid = $3, executed_msg_data = $4, + executed_rcpt_exitcode = $5, executed_rcpt_return = $6, executed_rcpt_gas_used = $7 + WHERE signed_message_cid = $8`, tskCid, look.Height, + look.Message, execMsg, + look.Receipt.ExitCode, look.Receipt.Return, look.Receipt.GasUsed, + msg.Cid) + if err != nil { + log.Errorf("failed to update message wait: %+v", err) + return + } + } +} + +func (mw *MessageWatcher) Stop(ctx context.Context) error { + close(mw.stopping) + select { + case <-mw.stopped: + case <-ctx.Done(): + return ctx.Err() + } + + return nil +} + +func (mw *MessageWatcher) processHeadChange(ctx context.Context, revert *types.TipSet, apply *types.TipSet) error { + best := apply.Key() + mw.bestTs.Store(&best) + select { + case mw.updateCh <- struct{}{}: + default: + } + return nil +} diff --git a/curiosrc/multictladdr/multiaddresses.go b/curiosrc/multictladdr/multiaddresses.go new file mode 100644 index 00000000000..af751ff17e7 --- /dev/null +++ b/curiosrc/multictladdr/multiaddresses.go @@ -0,0 +1,81 @@ +package multictladdr + +import ( + "context" + + logging "github.com/ipfs/go-log/v2" + + "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/storage/ctladdr" +) + +var log = logging.Logger("curio/multictladdr") + +type MultiAddressSelector struct { + MinerMap map[address.Address]api.AddressConfig +} + +func (as *MultiAddressSelector) AddressFor(ctx context.Context, a ctladdr.NodeApi, minerID address.Address, mi api.MinerInfo, use api.AddrUse, goodFunds, minFunds abi.TokenAmount) (address.Address, abi.TokenAmount, error) { + if as == nil { + // should only happen in some tests + log.Warnw("smart address selection disabled, using worker address") + return mi.Worker, big.Zero(), nil + } + + tmp := as.MinerMap[minerID] + + var addrs []address.Address + switch use { + case api.PreCommitAddr: + addrs = append(addrs, tmp.PreCommitControl...) + case api.CommitAddr: + addrs = append(addrs, tmp.CommitControl...) + case api.TerminateSectorsAddr: + addrs = append(addrs, tmp.TerminateControl...) + case api.DealPublishAddr: + addrs = append(addrs, tmp.DealPublishControl...) + default: + defaultCtl := map[address.Address]struct{}{} + for _, a := range mi.ControlAddresses { + defaultCtl[a] = struct{}{} + } + delete(defaultCtl, mi.Owner) + delete(defaultCtl, mi.Worker) + + configCtl := append([]address.Address{}, tmp.PreCommitControl...) + configCtl = append(configCtl, tmp.CommitControl...) + configCtl = append(configCtl, tmp.TerminateControl...) + configCtl = append(configCtl, tmp.DealPublishControl...) + + for _, addr := range configCtl { + if addr.Protocol() != address.ID { + var err error + addr, err = a.StateLookupID(ctx, addr, types.EmptyTSK) + if err != nil { + log.Warnw("looking up control address", "address", addr, "error", err) + continue + } + } + + delete(defaultCtl, addr) + } + + for a := range defaultCtl { + addrs = append(addrs, a) + } + } + + if len(addrs) == 0 || !tmp.DisableWorkerFallback { + addrs = append(addrs, mi.Worker) + } + if !tmp.DisableOwnerFallback { + addrs = append(addrs, mi.Owner) + } + + return ctladdr.PickAddress(ctx, a, mi, goodFunds, minFunds, addrs) +} diff --git a/curiosrc/piece/task_cleanup_piece.go b/curiosrc/piece/task_cleanup_piece.go new file mode 100644 index 00000000000..ed22ccb46d3 --- /dev/null +++ b/curiosrc/piece/task_cleanup_piece.go @@ -0,0 +1,130 @@ +package piece + +import ( + "context" + "time" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/curiosrc/ffi" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + "github.com/filecoin-project/lotus/lib/promise" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +type CleanupPieceTask struct { + max int + db *harmonydb.DB + sc *ffi.SealCalls + + TF promise.Promise[harmonytask.AddTaskFunc] +} + +func NewCleanupPieceTask(db *harmonydb.DB, sc *ffi.SealCalls, max int) *CleanupPieceTask { + pt := &CleanupPieceTask{ + db: db, + sc: sc, + + max: max, + } + go pt.pollCleanupTasks(context.Background()) + return pt +} + +func (c *CleanupPieceTask) pollCleanupTasks(ctx context.Context) { + for { + // select pieces with no refs and null cleanup_task_id + var pieceIDs []struct { + ID storiface.PieceNumber `db:"id"` + } + + err := c.db.Select(ctx, &pieceIDs, `SELECT id FROM parked_pieces WHERE cleanup_task_id IS NULL AND (SELECT count(*) FROM parked_piece_refs WHERE piece_id = parked_pieces.id) = 0`) + if err != nil { + log.Errorf("failed to get parked pieces: %s", err) + time.Sleep(PieceParkPollInterval) + continue + } + + if len(pieceIDs) == 0 { + time.Sleep(PieceParkPollInterval) + continue + } + + for _, pieceID := range pieceIDs { + pieceID := pieceID + + // create a task for each piece + c.TF.Val(ctx)(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, err error) { + // update + n, err := tx.Exec(`UPDATE parked_pieces SET cleanup_task_id = $1 WHERE id = $2 AND (SELECT count(*) FROM parked_piece_refs WHERE piece_id = parked_pieces.id) = 0`, id, pieceID.ID) + if err != nil { + return false, xerrors.Errorf("updating parked piece: %w", err) + } + + // commit only if we updated the piece + return n > 0, nil + }) + } + } +} + +func (c *CleanupPieceTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + ctx := context.Background() + + // select by cleanup_task_id + var pieceID int64 + + err = c.db.QueryRow(ctx, "SELECT id FROM parked_pieces WHERE cleanup_task_id = $1", taskID).Scan(&pieceID) + if err != nil { + return false, xerrors.Errorf("query parked_piece: %w", err) + } + + // delete from parked_pieces where id = $1 where ref count = 0 + // note: we delete from the db first because that guarantees that the piece is no longer in use + // if storage delete fails, it will be retried later is other cleanup tasks + n, err := c.db.Exec(ctx, "DELETE FROM parked_pieces WHERE id = $1 AND (SELECT count(*) FROM parked_piece_refs WHERE piece_id = $1) = 0", pieceID) + if err != nil { + return false, xerrors.Errorf("delete parked_piece: %w", err) + } + + if n == 0 { + return true, nil + } + + // remove from storage + err = c.sc.RemovePiece(ctx, storiface.PieceNumber(pieceID)) + if err != nil { + log.Errorw("remove piece", "piece_id", pieceID, "error", err) + } + + return true, nil +} + +func (c *CleanupPieceTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + // the remove call runs on paths.Remote storage, so it doesn't really matter where it runs + + id := ids[0] + return &id, nil +} + +func (c *CleanupPieceTask) TypeDetails() harmonytask.TaskTypeDetails { + return harmonytask.TaskTypeDetails{ + Max: c.max, + Name: "DropPiece", + Cost: resources.Resources{ + Cpu: 1, + Gpu: 0, + Ram: 64 << 20, + Storage: nil, + }, + MaxFailures: 10, + } +} + +func (c *CleanupPieceTask) Adder(taskFunc harmonytask.AddTaskFunc) { + c.TF.Set(taskFunc) +} + +var _ harmonytask.TaskInterface = &CleanupPieceTask{} diff --git a/curiosrc/piece/task_park_piece.go b/curiosrc/piece/task_park_piece.go new file mode 100644 index 00000000000..68a94a295a0 --- /dev/null +++ b/curiosrc/piece/task_park_piece.go @@ -0,0 +1,221 @@ +package piece + +import ( + "context" + "encoding/json" + "strconv" + "time" + + logging "github.com/ipfs/go-log/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/curiosrc/ffi" + "github.com/filecoin-project/lotus/curiosrc/seal" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + "github.com/filecoin-project/lotus/lib/promise" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +var log = logging.Logger("lppiece") +var PieceParkPollInterval = time.Second * 15 + +// ParkPieceTask gets a piece from some origin, and parks it in storage +// Pieces are always f00, piece ID is mapped to pieceCID in the DB +type ParkPieceTask struct { + db *harmonydb.DB + sc *ffi.SealCalls + + TF promise.Promise[harmonytask.AddTaskFunc] + + max int +} + +func NewParkPieceTask(db *harmonydb.DB, sc *ffi.SealCalls, max int) *ParkPieceTask { + pt := &ParkPieceTask{ + db: db, + sc: sc, + + max: max, + } + + go pt.pollPieceTasks(context.Background()) + return pt +} + +func (p *ParkPieceTask) pollPieceTasks(ctx context.Context) { + for { + // select parked pieces with no task_id + var pieceIDs []struct { + ID storiface.PieceNumber `db:"id"` + } + + err := p.db.Select(ctx, &pieceIDs, `SELECT id FROM parked_pieces WHERE complete = FALSE AND task_id IS NULL`) + if err != nil { + log.Errorf("failed to get parked pieces: %s", err) + time.Sleep(PieceParkPollInterval) + continue + } + + if len(pieceIDs) == 0 { + time.Sleep(PieceParkPollInterval) + continue + } + + for _, pieceID := range pieceIDs { + pieceID := pieceID + + // create a task for each piece + p.TF.Val(ctx)(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, err error) { + // update + n, err := tx.Exec(`UPDATE parked_pieces SET task_id = $1 WHERE id = $2 AND complete = FALSE AND task_id IS NULL`, id, pieceID.ID) + if err != nil { + return false, xerrors.Errorf("updating parked piece: %w", err) + } + + // commit only if we updated the piece + return n > 0, nil + }) + } + } +} + +func (p *ParkPieceTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + ctx := context.Background() + + // Define a struct to hold piece data. + var piecesData []struct { + PieceID int64 `db:"id"` + PieceCreatedAt time.Time `db:"created_at"` + PieceCID string `db:"piece_cid"` + Complete bool `db:"complete"` + PiecePaddedSize int64 `db:"piece_padded_size"` + PieceRawSize string `db:"piece_raw_size"` + } + + // Select the piece data using the task ID. + err = p.db.Select(ctx, &piecesData, ` + SELECT id, created_at, piece_cid, complete, piece_padded_size, piece_raw_size + FROM parked_pieces + WHERE task_id = $1 + `, taskID) + if err != nil { + return false, xerrors.Errorf("fetching piece data: %w", err) + } + + if len(piecesData) == 0 { + return false, xerrors.Errorf("no piece data found for task_id: %d", taskID) + } + + pieceData := piecesData[0] + + if pieceData.Complete { + log.Warnw("park piece task already complete", "task_id", taskID, "piece_cid", pieceData.PieceCID) + return true, nil + } + + // Define a struct for reference data. + var refData []struct { + DataURL string `db:"data_url"` + DataHeaders json.RawMessage `db:"data_headers"` + } + + // Now, select the first reference data that has a URL. + err = p.db.Select(ctx, &refData, ` + SELECT data_url, data_headers + FROM parked_piece_refs + WHERE piece_id = $1 AND data_url IS NOT NULL + LIMIT 1 + `, pieceData.PieceID) + if err != nil { + return false, xerrors.Errorf("fetching reference data: %w", err) + } + + if len(refData) == 0 { + return false, xerrors.Errorf("no refs found for piece_id: %d", pieceData.PieceID) + } + + // Convert piece_raw_size from string to int64. + pieceRawSize, err := strconv.ParseInt(pieceData.PieceRawSize, 10, 64) + if err != nil { + return false, xerrors.Errorf("parsing piece raw size: %w", err) + } + + if refData[0].DataURL != "" { + upr := &seal.UrlPieceReader{ + Url: refData[0].DataURL, + RawSize: pieceRawSize, + } + defer func() { + _ = upr.Close() + }() + + pnum := storiface.PieceNumber(pieceData.PieceID) + + if err := p.sc.WritePiece(ctx, &taskID, pnum, pieceRawSize, upr); err != nil { + return false, xerrors.Errorf("write piece: %w", err) + } + + // Update the piece as complete after a successful write. + _, err = p.db.Exec(ctx, `UPDATE parked_pieces SET complete = TRUE WHERE id = $1`, pieceData.PieceID) + if err != nil { + return false, xerrors.Errorf("marking piece as complete: %w", err) + } + + return true, nil + } + + // If no URL is found, this indicates an issue since at least one URL is expected. + return false, xerrors.Errorf("no data URL found for piece_id: %d", pieceData.PieceID) +} + +func (p *ParkPieceTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + id := ids[0] + return &id, nil +} + +func (p *ParkPieceTask) TypeDetails() harmonytask.TaskTypeDetails { + const maxSizePiece = 64 << 30 + + return harmonytask.TaskTypeDetails{ + Max: p.max, + Name: "ParkPiece", + Cost: resources.Resources{ + Cpu: 1, + Gpu: 0, + Ram: 64 << 20, + Storage: p.sc.Storage(p.taskToRef, storiface.FTPiece, storiface.FTNone, maxSizePiece, storiface.PathSealing), + }, + MaxFailures: 10, + } +} + +func (p *ParkPieceTask) taskToRef(id harmonytask.TaskID) (ffi.SectorRef, error) { + var pieceIDs []struct { + ID storiface.PieceNumber `db:"id"` + } + + err := p.db.Select(context.Background(), &pieceIDs, `SELECT id FROM parked_pieces WHERE task_id = $1`, id) + if err != nil { + return ffi.SectorRef{}, xerrors.Errorf("getting piece id: %w", err) + } + + if len(pieceIDs) != 1 { + return ffi.SectorRef{}, xerrors.Errorf("expected 1 piece id, got %d", len(pieceIDs)) + } + + pref := pieceIDs[0].ID.Ref() + + return ffi.SectorRef{ + SpID: int64(pref.ID.Miner), + SectorNumber: int64(pref.ID.Number), + RegSealProof: pref.ProofType, + }, nil +} + +func (p *ParkPieceTask) Adder(taskFunc harmonytask.AddTaskFunc) { + p.TF.Set(taskFunc) +} + +var _ harmonytask.TaskInterface = &ParkPieceTask{} diff --git a/curiosrc/proof/treed_build.go b/curiosrc/proof/treed_build.go new file mode 100644 index 00000000000..7145c9257ca --- /dev/null +++ b/curiosrc/proof/treed_build.go @@ -0,0 +1,292 @@ +package proof + +import ( + "io" + "math/bits" + "os" + "runtime" + "sync" + "time" + + "github.com/hashicorp/go-multierror" + "github.com/ipfs/go-cid" + pool "github.com/libp2p/go-buffer-pool" + "github.com/minio/sha256-simd" + "golang.org/x/xerrors" + + commcid "github.com/filecoin-project/go-fil-commcid" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/storage/sealer/fr32" +) + +const nodeSize = 32 +const threadChunkSize = 1 << 20 + +func hashChunk(data [][]byte) { + l1Nodes := len(data[0]) / nodeSize / 2 + + d := sha256.New() + + sumBuf := make([]byte, nodeSize) + + for i := 0; i < l1Nodes; i++ { + levels := bits.TrailingZeros(^uint(i)) + 1 + + inNode := i * 2 // at level 0 + outNode := i + + for l := 0; l < levels; l++ { + d.Reset() + inNodeData := data[l][inNode*nodeSize : (inNode+2)*nodeSize] + d.Write(inNodeData) + copy(data[l+1][outNode*nodeSize:(outNode+1)*nodeSize], d.Sum(sumBuf[:0])) + // set top bits to 00 + data[l+1][outNode*nodeSize+nodeSize-1] &= 0x3f + + inNode-- + inNode >>= 1 + outNode >>= 1 + } + } +} + +func BuildTreeD(data io.Reader, unpaddedData bool, outPath string, size abi.PaddedPieceSize) (_ cid.Cid, err error) { + out, err := os.Create(outPath) + if err != nil { + return cid.Undef, err + } + defer func() { + cerr := out.Close() + + if err != nil { + // remove the file, it's probably bad + rerr := os.Remove(outPath) + if rerr != nil { + err = multierror.Append(err, rerr) + } + } + + if cerr != nil { + err = multierror.Append(err, cerr) + } + }() + + outSize := treeSize(size) + + // allocate space for the tree + err = out.Truncate(int64(outSize)) + if err != nil { + return cid.Undef, err + } + + // setup buffers + maxThreads := int64(size) / threadChunkSize + if maxThreads > int64(runtime.NumCPU())*15/10 { + maxThreads = int64(runtime.NumCPU()) * 15 / 10 + } + if maxThreads < 1 { + maxThreads = 1 + } + + // allocate buffers + var bufLk sync.Mutex + workerBuffers := make([][][]byte, maxThreads) // [worker][level][levelSize] + + for i := range workerBuffers { + workerBuffer := make([][]byte, 1) + + bottomBufSize := int64(threadChunkSize) + if bottomBufSize > int64(size) { + bottomBufSize = int64(size) + } + workerBuffer[0] = pool.Get(int(bottomBufSize)) + + // append levels until we get to a 32 byte level + for len(workerBuffer[len(workerBuffer)-1]) > 32 { + newLevel := pool.Get(len(workerBuffer[len(workerBuffer)-1]) / 2) + workerBuffer = append(workerBuffer, newLevel) + } + workerBuffers[i] = workerBuffer + } + + // prepare apex buffer + var apexBuf [][]byte + { + apexBottomSize := uint64(size) / uint64(len(workerBuffers[0][0])) + if apexBottomSize == 0 { + apexBottomSize = 1 + } + + apexBuf = make([][]byte, 1) + apexBuf[0] = pool.Get(int(apexBottomSize * nodeSize)) + for len(apexBuf[len(apexBuf)-1]) > 32 { + newLevel := pool.Get(len(apexBuf[len(apexBuf)-1]) / 2) + apexBuf = append(apexBuf, newLevel) + } + } + + // defer free pool buffers + defer func() { + for _, workerBuffer := range workerBuffers { + for _, level := range workerBuffer { + pool.Put(level) + } + } + for _, level := range apexBuf { + pool.Put(level) + } + }() + + // start processing + var processed uint64 + var workWg sync.WaitGroup + var errLock sync.Mutex + var oerr error + + for processed < uint64(size) { + // get a buffer + bufLk.Lock() + if len(workerBuffers) == 0 { + bufLk.Unlock() + time.Sleep(50 * time.Microsecond) + continue + } + + // pop last + workBuffer := workerBuffers[len(workerBuffers)-1] + workerBuffers = workerBuffers[:len(workerBuffers)-1] + + bufLk.Unlock() + + // before reading check that we didn't get a write error + errLock.Lock() + if oerr != nil { + errLock.Unlock() + return cid.Undef, oerr + } + errLock.Unlock() + + // read data into the bottom level + // note: the bottom level will never be too big; data is power of two + // size, and if it's smaller than a single buffer, we only have one + // smaller buffer + + processedSize := uint64(len(workBuffer[0])) + if unpaddedData { + workBuffer[0] = workBuffer[0][:abi.PaddedPieceSize(len(workBuffer[0])).Unpadded()] + } + + _, err := io.ReadFull(data, workBuffer[0]) + if err != nil && err != io.EOF { + return cid.Undef, err + } + + // start processing + workWg.Add(1) + go func(startOffset uint64) { + defer workWg.Done() + + if unpaddedData { + paddedBuf := pool.Get(int(abi.UnpaddedPieceSize(len(workBuffer[0])).Padded())) + fr32.PadSingle(workBuffer[0], paddedBuf) + pool.Put(workBuffer[0]) + workBuffer[0] = paddedBuf + } + hashChunk(workBuffer) + + // persist apex + { + apexHash := workBuffer[len(workBuffer)-1] + hashPos := startOffset / uint64(len(workBuffer[0])) * nodeSize + + copy(apexBuf[0][hashPos:hashPos+nodeSize], apexHash) + } + + // write results + offsetInLayer := startOffset + for layer, layerData := range workBuffer { + + // layerOff is outSize:bits[most significant bit - layer] + layerOff := layerOffset(uint64(size), layer) + dataOff := offsetInLayer + layerOff + offsetInLayer /= 2 + + _, werr := out.WriteAt(layerData, int64(dataOff)) + if werr != nil { + errLock.Lock() + oerr = multierror.Append(oerr, werr) + errLock.Unlock() + return + } + } + + // return buffer + bufLk.Lock() + workerBuffers = append(workerBuffers, workBuffer) + bufLk.Unlock() + }(processed) + + processed += processedSize + } + + workWg.Wait() + + if oerr != nil { + return cid.Undef, oerr + } + + threadLayers := bits.Len(uint(len(workerBuffers[0][0])) / nodeSize) + + if len(apexBuf) > 0 { + // hash the apex + hashChunk(apexBuf) + + // write apex + for apexLayer, layerData := range apexBuf { + if apexLayer == 0 { + continue + } + layer := apexLayer + threadLayers - 1 + + layerOff := layerOffset(uint64(size), layer) + _, werr := out.WriteAt(layerData, int64(layerOff)) + if werr != nil { + return cid.Undef, xerrors.Errorf("write apex: %w", werr) + } + } + } + + var commp [32]byte + copy(commp[:], apexBuf[len(apexBuf)-1]) + + commCid, err := commcid.DataCommitmentV1ToCID(commp[:]) + if err != nil { + return cid.Undef, err + } + + return commCid, nil +} + +func treeSize(data abi.PaddedPieceSize) uint64 { + bytesToAlloc := uint64(data) + + // append bytes until we get to nodeSize + for todo := bytesToAlloc; todo > nodeSize; todo /= 2 { + bytesToAlloc += todo / 2 + } + + return bytesToAlloc +} + +func layerOffset(size uint64, layer int) uint64 { + allOnes := uint64(0xffff_ffff_ffff_ffff) + + // get 'layer' bits set to 1 + layerOnes := allOnes >> uint64(64-layer) + + // shift layerOnes to the left such that the highest bit is at the same position as the highest bit in size (which is power-of-two) + sizeBitPos := bits.Len64(size) - 1 + layerOnes <<= sizeBitPos - (layer - 1) + return layerOnes +} diff --git a/curiosrc/proof/treed_build_test.go b/curiosrc/proof/treed_build_test.go new file mode 100644 index 00000000000..f69e9832247 --- /dev/null +++ b/curiosrc/proof/treed_build_test.go @@ -0,0 +1,516 @@ +package proof + +import ( + "bufio" + "bytes" + "crypto/rand" + "fmt" + "io" + "os" + "path/filepath" + "runtime" + "testing" + + pool "github.com/libp2p/go-buffer-pool" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/storage/pipeline/lib/nullreader" +) + +func TestTreeSize(t *testing.T) { + require.Equal(t, uint64(32), treeSize(abi.PaddedPieceSize(32))) + require.Equal(t, uint64(64+32), treeSize(abi.PaddedPieceSize(64))) + require.Equal(t, uint64(128+64+32), treeSize(abi.PaddedPieceSize(128))) + require.Equal(t, uint64(256+128+64+32), treeSize(abi.PaddedPieceSize(256))) +} + +func TestTreeLayerOffset(t *testing.T) { + require.Equal(t, uint64(0), layerOffset(128, 0)) + require.Equal(t, uint64(128), layerOffset(128, 1)) + require.Equal(t, uint64(128+64), layerOffset(128, 2)) + require.Equal(t, uint64(128+64+32), layerOffset(128, 3)) +} + +func TestHashChunk(t *testing.T) { + chunk := make([]byte, 64) + chunk[0] = 0x01 + + out := make([]byte, 32) + + data := [][]byte{chunk, out} + hashChunk(data) + + // 16 ab ab 34 1f b7 f3 70 e2 7e 4d ad cf 81 76 6d + // d0 df d0 ae 64 46 94 77 bb 2c f6 61 49 38 b2 2f + expect := []byte{ + 0x16, 0xab, 0xab, 0x34, 0x1f, 0xb7, 0xf3, 0x70, + 0xe2, 0x7e, 0x4d, 0xad, 0xcf, 0x81, 0x76, 0x6d, + 0xd0, 0xdf, 0xd0, 0xae, 0x64, 0x46, 0x94, 0x77, + 0xbb, 0x2c, 0xf6, 0x61, 0x49, 0x38, 0xb2, 0x2f, + } + + require.Equal(t, expect, out) +} + +func TestHashChunk2L(t *testing.T) { + data0 := make([]byte, 128) + data0[0] = 0x01 + + l1 := make([]byte, 64) + l2 := make([]byte, 32) + + data := [][]byte{data0, l1, l2} + hashChunk(data) + + // 16 ab ab 34 1f b7 f3 70 e2 7e 4d ad cf 81 76 6d + // d0 df d0 ae 64 46 94 77 bb 2c f6 61 49 38 b2 2f + expectL1Left := []byte{ + 0x16, 0xab, 0xab, 0x34, 0x1f, 0xb7, 0xf3, 0x70, + 0xe2, 0x7e, 0x4d, 0xad, 0xcf, 0x81, 0x76, 0x6d, + 0xd0, 0xdf, 0xd0, 0xae, 0x64, 0x46, 0x94, 0x77, + 0xbb, 0x2c, 0xf6, 0x61, 0x49, 0x38, 0xb2, 0x2f, + } + + // f5 a5 fd 42 d1 6a 20 30 27 98 ef 6e d3 09 97 9b + // 43 00 3d 23 20 d9 f0 e8 ea 98 31 a9 27 59 fb 0b + expectL1Rest := []byte{ + 0xf5, 0xa5, 0xfd, 0x42, 0xd1, 0x6a, 0x20, 0x30, + 0x27, 0x98, 0xef, 0x6e, 0xd3, 0x09, 0x97, 0x9b, + 0x43, 0x00, 0x3d, 0x23, 0x20, 0xd9, 0xf0, 0xe8, + 0xea, 0x98, 0x31, 0xa9, 0x27, 0x59, 0xfb, 0x0b, + } + + require.Equal(t, expectL1Left, l1[:32]) + require.Equal(t, expectL1Rest, l1[32:]) + + // 0d d6 da e4 1c 2f 75 55 01 29 59 4f b6 44 e4 a8 + // 42 cf af b3 16 a2 d5 93 21 e3 88 fe 84 a1 ec 2f + expectL2 := []byte{ + 0x0d, 0xd6, 0xda, 0xe4, 0x1c, 0x2f, 0x75, 0x55, + 0x01, 0x29, 0x59, 0x4f, 0xb6, 0x44, 0xe4, 0xa8, + 0x42, 0xcf, 0xaf, 0xb3, 0x16, 0xa2, 0xd5, 0x93, + 0x21, 0xe3, 0x88, 0xfe, 0x84, 0xa1, 0xec, 0x2f, + } + + require.Equal(t, expectL2, l2) +} + +func Test2K(t *testing.T) { + data := make([]byte, 2048) + data[0] = 0x01 + + tempFile := filepath.Join(t.TempDir(), "tree.dat") + + commd, err := BuildTreeD(bytes.NewReader(data), false, tempFile, 2048) + require.NoError(t, err) + fmt.Println(commd) + + // dump tree.dat + dat, err := os.ReadFile(tempFile) + require.NoError(t, err) + + for i, b := range dat { + // 32 values per line + if i%32 == 0 { + fmt.Println() + + // line offset hexdump style + fmt.Printf("%04x: ", i) + } + fmt.Printf("%02x ", b) + } + fmt.Println() + + require.Equal(t, "baga6ea4seaqovgk4kr4eoifujh6jfmdqvw3m6zrvyjqzu6s6abkketui6jjoydi", commd.String()) + +} + +const expectD8M = `00000000: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* +00800000: 16 ab ab 34 1f b7 f3 70 e2 7e 4d ad cf 81 76 6d d0 df d0 ae 64 46 94 77 bb 2c f6 61 49 38 b2 2f +00800020: f5 a5 fd 42 d1 6a 20 30 27 98 ef 6e d3 09 97 9b 43 00 3d 23 20 d9 f0 e8 ea 98 31 a9 27 59 fb 0b +* +00c00000: 0d d6 da e4 1c 2f 75 55 01 29 59 4f b6 44 e4 a8 42 cf af b3 16 a2 d5 93 21 e3 88 fe 84 a1 ec 2f +00c00020: 37 31 bb 99 ac 68 9f 66 ee f5 97 3e 4a 94 da 18 8f 4d dc ae 58 07 24 fc 6f 3f d6 0d fd 48 83 33 +* +00e00000: 11 b1 c4 80 05 21 d5 e5 83 4a de b3 70 7c 74 15 9f f3 37 b0 96 16 3c 94 31 16 73 40 e7 b1 17 1d +00e00020: 64 2a 60 7e f8 86 b0 04 bf 2c 19 78 46 3a e1 d4 69 3a c0 f4 10 eb 2d 1b 7a 47 fe 20 5e 5e 75 0f +* +00f00000: ec 69 25 55 9b cc 52 84 0a 22 38 5b 2b 6b 35 b4 50 14 50 04 28 f4 59 fe c1 23 01 0f e7 ef 18 1c +00f00020: 57 a2 38 1a 28 65 2b f4 7f 6b ef 7a ca 67 9b e4 ae de 58 71 ab 5c f3 eb 2c 08 11 44 88 cb 85 26 +* +00f80000: 3d d2 eb 19 3e e2 f0 47 34 87 bf 4b 83 aa 3a bd a9 c8 4e fa e5 52 6d 8a fd 61 2d 5d 9e 3d 79 34 +00f80020: 1f 7a c9 59 55 10 e0 9e a4 1c 46 0b 17 64 30 bb 32 2c d6 fb 41 2e c5 7c b1 7d 98 9a 43 10 37 2f +* +00fc0000: ea 99 5c 54 78 47 20 b4 49 fc 92 b0 70 ad b6 cf 66 35 c2 61 9a 7a 5e 00 54 a2 4e 88 f2 52 ec 0d +00fc0020: fc 7e 92 82 96 e5 16 fa ad e9 86 b2 8f 92 d4 4a 4f 24 b9 35 48 52 23 37 6a 79 90 27 bc 18 f8 33 +* +00fe0000: b9 97 02 8b 06 d7 2e 96 07 86 79 58 e1 5f 8d 07 b7 ae 37 ab 29 ab 3f a9 de fe c9 8e aa 37 6e 28 +00fe0020: 08 c4 7b 38 ee 13 bc 43 f4 1b 91 5c 0e ed 99 11 a2 60 86 b3 ed 62 40 1b f9 d5 8b 8d 19 df f6 24 +* +00ff0000: a0 c4 4f 7b a4 4c d2 3c 2e bf 75 98 7b e8 98 a5 63 80 73 b2 f9 11 cf ee ce 14 5a 77 58 0c 6c 12 +00ff0020: b2 e4 7b fb 11 fa cd 94 1f 62 af 5c 75 0f 3e a5 cc 4d f5 17 d5 c4 f1 6d b2 b4 d7 7b ae c1 a3 2f +* +00ff8000: 89 2d 2b 00 a5 c1 54 10 94 ca 65 de 21 3b bd 45 90 14 15 ed d1 10 17 cd 29 f3 ed 75 73 02 a0 3f +00ff8020: f9 22 61 60 c8 f9 27 bf dc c4 18 cd f2 03 49 31 46 00 8e ae fb 7d 02 19 4d 5e 54 81 89 00 51 08 +* +00ffc000: 22 48 54 8b ba a5 8f e2 db 0b 07 18 c1 d7 20 1f ed 64 c7 8d 7d 22 88 36 b2 a1 b2 f9 42 0b ef 3c +00ffc020: 2c 1a 96 4b b9 0b 59 eb fe 0f 6d a2 9a d6 5a e3 e4 17 72 4a 8f 7c 11 74 5a 40 ca c1 e5 e7 40 11 +* +00ffe000: 1c 6a 48 08 3e 17 49 90 ef c0 56 ec b1 44 75 1d e2 76 d8 a5 1c 3d 93 d7 4c 81 92 48 ab 78 cc 30 +00ffe020: fe e3 78 ce f1 64 04 b1 99 ed e0 b1 3e 11 b6 24 ff 9d 78 4f bb ed 87 8d 83 29 7e 79 5e 02 4f 02 +* +00fff000: 0a b4 26 38 1b 72 cd 3b b3 e3 c7 82 18 fe 1f 18 3b 3a 19 db c4 d9 26 94 30 03 cd 01 b6 d1 8d 0b +00fff020: 8e 9e 24 03 fa 88 4c f6 23 7f 60 df 25 f8 3e e4 0d ca 9e d8 79 eb 6f 63 52 d1 50 84 f5 ad 0d 3f +* +00fff800: 16 0d 87 17 1b e7 ae e4 20 a3 54 24 cf df 4f fe a2 fd 7b 94 58 89 58 f3 45 11 57 fc 39 8f 34 26 +00fff820: 75 2d 96 93 fa 16 75 24 39 54 76 e3 17 a9 85 80 f0 09 47 af b7 a3 05 40 d6 25 a9 29 1c c1 2a 07 +* +00fffc00: 1f 40 60 11 da 08 f8 09 80 63 97 dc 1c 57 b9 87 83 37 5a 59 5d d6 81 42 6c 1e cd d4 3c ab e3 3c +00fffc20: 70 22 f6 0f 7e f6 ad fa 17 11 7a 52 61 9e 30 ce a8 2c 68 07 5a df 1c 66 77 86 ec 50 6e ef 2d 19 +* +00fffe00: 51 4e dd 2f 6f 8f 6d fd 54 b0 d1 20 7b b7 06 df 85 c5 a3 19 0e af 38 72 37 20 c5 07 56 67 7f 14 +00fffe20: d9 98 87 b9 73 57 3a 96 e1 13 93 64 52 36 c1 7b 1f 4c 70 34 d7 23 c7 a9 9f 70 9b b4 da 61 16 2b +* +00ffff00: 5a 1d 84 74 85 a3 4b 28 08 93 a9 cf b2 8b 54 44 67 12 8b eb c0 22 bd de c1 04 be ca b4 f4 81 31 +00ffff20: d0 b5 30 db b0 b4 f2 5c 5d 2f 2a 28 df ee 80 8b 53 41 2a 02 93 1f 18 c4 99 f5 a2 54 08 6b 13 26 +* +00ffff80: c5 fb f3 f9 4c c2 2b 3c 51 ad c1 ea af e9 4b a0 9f b2 73 f3 73 d2 10 1f 12 0b 11 c6 85 21 66 2f +00ffffa0: 84 c0 42 1b a0 68 5a 01 bf 79 5a 23 44 06 4f e4 24 bd 52 a9 d2 43 77 b3 94 ff 4c 4b 45 68 e8 11 +00ffffc0: 23 40 4a 88 80 f9 cb c7 20 39 cb 86 14 35 9c 28 34 84 55 70 fe 95 19 0b bd 4d 93 41 42 e8 25 2c +` + +func Test8MiB(t *testing.T) { + data := make([]byte, 8<<20) + data[0] = 0x01 + + tempFile := filepath.Join(t.TempDir(), "tree.dat") + + commd, err := BuildTreeD(bytes.NewReader(data), false, tempFile, 8<<20) + require.NoError(t, err) + fmt.Println(commd) + + // dump tree.dat + dat, err := os.ReadFile(tempFile) + require.NoError(t, err) + + actualD := hexPrint32LDedup(bytes.NewReader(dat)) + fmt.Println(actualD) + + require.EqualValues(t, expectD8M, actualD) + require.Equal(t, "baga6ea4seaqcgqckrcapts6hea44xbqugwocqneekvyp5fizbo6u3e2biluckla", commd.String()) +} + +func Test8MiBUnpad(t *testing.T) { + data := make([]byte, abi.PaddedPieceSize(8<<20).Unpadded()) + data[0] = 0x01 + + tempFile := filepath.Join(t.TempDir(), "tree.dat") + + commd, err := BuildTreeD(bytes.NewReader(data), true, tempFile, 8<<20) + require.NoError(t, err) + fmt.Println(commd) + + // dump tree.dat + dat, err := os.ReadFile(tempFile) + require.NoError(t, err) + + actualD := hexPrint32LDedup(bytes.NewReader(dat)) + fmt.Println(actualD) + + require.EqualValues(t, expectD8M, actualD) + require.Equal(t, "baga6ea4seaqcgqckrcapts6hea44xbqugwocqneekvyp5fizbo6u3e2biluckla", commd.String()) +} + +/*func Test32Golden(t *testing.T) { + datFile, err := os.Open("../../seal/cac/sc-02-data-tree-d.dat") + require.NoError(t, err) + + bufReader := bufio.NewReaderSize(datFile, 1<<20) + + actualD := hexPrint32LDedup(bufReader) + fmt.Println(actualD) +} +*/ + +var expect32Null = `00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* +800000000: f5 a5 fd 42 d1 6a 20 30 27 98 ef 6e d3 09 97 9b 43 00 3d 23 20 d9 f0 e8 ea 98 31 a9 27 59 fb 0b +* +c00000000: 37 31 bb 99 ac 68 9f 66 ee f5 97 3e 4a 94 da 18 8f 4d dc ae 58 07 24 fc 6f 3f d6 0d fd 48 83 33 +* +e00000000: 64 2a 60 7e f8 86 b0 04 bf 2c 19 78 46 3a e1 d4 69 3a c0 f4 10 eb 2d 1b 7a 47 fe 20 5e 5e 75 0f +* +f00000000: 57 a2 38 1a 28 65 2b f4 7f 6b ef 7a ca 67 9b e4 ae de 58 71 ab 5c f3 eb 2c 08 11 44 88 cb 85 26 +* +f80000000: 1f 7a c9 59 55 10 e0 9e a4 1c 46 0b 17 64 30 bb 32 2c d6 fb 41 2e c5 7c b1 7d 98 9a 43 10 37 2f +* +fc0000000: fc 7e 92 82 96 e5 16 fa ad e9 86 b2 8f 92 d4 4a 4f 24 b9 35 48 52 23 37 6a 79 90 27 bc 18 f8 33 +* +fe0000000: 08 c4 7b 38 ee 13 bc 43 f4 1b 91 5c 0e ed 99 11 a2 60 86 b3 ed 62 40 1b f9 d5 8b 8d 19 df f6 24 +* +ff0000000: b2 e4 7b fb 11 fa cd 94 1f 62 af 5c 75 0f 3e a5 cc 4d f5 17 d5 c4 f1 6d b2 b4 d7 7b ae c1 a3 2f +* +ff8000000: f9 22 61 60 c8 f9 27 bf dc c4 18 cd f2 03 49 31 46 00 8e ae fb 7d 02 19 4d 5e 54 81 89 00 51 08 +* +ffc000000: 2c 1a 96 4b b9 0b 59 eb fe 0f 6d a2 9a d6 5a e3 e4 17 72 4a 8f 7c 11 74 5a 40 ca c1 e5 e7 40 11 +* +ffe000000: fe e3 78 ce f1 64 04 b1 99 ed e0 b1 3e 11 b6 24 ff 9d 78 4f bb ed 87 8d 83 29 7e 79 5e 02 4f 02 +* +fff000000: 8e 9e 24 03 fa 88 4c f6 23 7f 60 df 25 f8 3e e4 0d ca 9e d8 79 eb 6f 63 52 d1 50 84 f5 ad 0d 3f +* +fff800000: 75 2d 96 93 fa 16 75 24 39 54 76 e3 17 a9 85 80 f0 09 47 af b7 a3 05 40 d6 25 a9 29 1c c1 2a 07 +* +fffc00000: 70 22 f6 0f 7e f6 ad fa 17 11 7a 52 61 9e 30 ce a8 2c 68 07 5a df 1c 66 77 86 ec 50 6e ef 2d 19 +* +fffe00000: d9 98 87 b9 73 57 3a 96 e1 13 93 64 52 36 c1 7b 1f 4c 70 34 d7 23 c7 a9 9f 70 9b b4 da 61 16 2b +* +ffff00000: d0 b5 30 db b0 b4 f2 5c 5d 2f 2a 28 df ee 80 8b 53 41 2a 02 93 1f 18 c4 99 f5 a2 54 08 6b 13 26 +* +ffff80000: 84 c0 42 1b a0 68 5a 01 bf 79 5a 23 44 06 4f e4 24 bd 52 a9 d2 43 77 b3 94 ff 4c 4b 45 68 e8 11 +* +ffffc0000: 65 f2 9e 5d 98 d2 46 c3 8b 38 8c fc 06 db 1f 6b 02 13 03 c5 a2 89 00 0b dc e8 32 a9 c3 ec 42 1c +* +ffffe0000: a2 24 75 08 28 58 50 96 5b 7e 33 4b 31 27 b0 c0 42 b1 d0 46 dc 54 40 21 37 62 7c d8 79 9c e1 3a +* +fffff0000: da fd ab 6d a9 36 44 53 c2 6d 33 72 6b 9f ef e3 43 be 8f 81 64 9e c0 09 aa d3 fa ff 50 61 75 08 +* +fffff8000: d9 41 d5 e0 d6 31 4a 99 5c 33 ff bd 4f be 69 11 8d 73 d4 e5 fd 2c d3 1f 0f 7c 86 eb dd 14 e7 06 +* +fffffc000: 51 4c 43 5c 3d 04 d3 49 a5 36 5f bd 59 ff c7 13 62 91 11 78 59 91 c1 a3 c5 3a f2 20 79 74 1a 2f +* +fffffe000: ad 06 85 39 69 d3 7d 34 ff 08 e0 9f 56 93 0a 4a d1 9a 89 de f6 0c bf ee 7e 1d 33 81 c1 e7 1c 37 +* +ffffff000: 39 56 0e 7b 13 a9 3b 07 a2 43 fd 27 20 ff a7 cb 3e 1d 2e 50 5a b3 62 9e 79 f4 63 13 51 2c da 06 +* +ffffff800: cc c3 c0 12 f5 b0 5e 81 1a 2b bf dd 0f 68 33 b8 42 75 b4 7b f2 29 c0 05 2a 82 48 4f 3c 1a 5b 3d +* +ffffffc00: 7d f2 9b 69 77 31 99 e8 f2 b4 0b 77 91 9d 04 85 09 ee d7 68 e2 c7 29 7b 1f 14 37 03 4f c3 c6 2c +* +ffffffe00: 66 ce 05 a3 66 75 52 cf 45 c0 2b cc 4e 83 92 91 9b de ac 35 de 2f f5 62 71 84 8e 9f 7b 67 51 07 +* +fffffff00: d8 61 02 18 42 5a b5 e9 5b 1c a6 23 9d 29 a2 e4 20 d7 06 a9 6f 37 3e 2f 9c 9a 91 d7 59 d1 9b 01 +* +fffffff80: 6d 36 4b 1e f8 46 44 1a 5a 4a 68 86 23 14 ac c0 a4 6f 01 67 17 e5 34 43 e8 39 ee df 83 c2 85 3c +* +fffffffc0: 07 7e 5f de 35 c5 0a 93 03 a5 50 09 e3 49 8a 4e be df f3 9c 42 b7 10 b7 30 d8 ec 7a c7 af a6 3e +` + +func Test32G(t *testing.T) { + if os.Getenv("LOTUS_TEST_LARGE_SECTORS") != "1" { + t.Skip("skipping large sector test without env LOTUS_TEST_LARGE_SECTORS=1") + } + + data := nullreader.NewNullReader(abi.PaddedPieceSize(32 << 30).Unpadded()) + + tempFile := filepath.Join(t.TempDir(), "tree.dat") + + commd, err := BuildTreeD(data, true, tempFile, 32<<30) + require.NoError(t, err) + fmt.Println(commd) + + // dump tree.dat + datFile, err := os.Open(tempFile) + require.NoError(t, err) + defer func() { + require.NoError(t, datFile.Close()) + }() + + actualD := hexPrint32LDedup(bufio.NewReaderSize(datFile, 1<<20)) + fmt.Println(actualD) + + require.EqualValues(t, expect32Null, actualD) + require.Equal(t, "baga6ea4seaqao7s73y24kcutaosvacpdjgfe5pw76ooefnyqw4ynr3d2y6x2mpq", commd.String()) +} + +func hexPrint32LDedup(r io.Reader) string { + var prevLine []byte + var outStr string + var duplicateLine bool + buffer := make([]byte, 32) + offset := 0 + + for { + n, err := r.Read(buffer) + if err == io.EOF { + break + } + if err != nil { + // Handle the error according to your application's requirements + fmt.Println("Error reading:", err) + break + } + + if string(prevLine) == string(buffer) { + // Mark as duplicate and skip processing + duplicateLine = true + } else { + if duplicateLine { + // Output a marker for the previous duplicate line + outStr += "*\n" + duplicateLine = false + } + // Convert to hex and output + outStr += fmt.Sprintf("%08x: %s\n", offset, toHex(buffer)) + + // Update prevLine + if len(prevLine) != 32 { + prevLine = make([]byte, 32) + } + copy(prevLine, buffer) + } + + offset += n + } + + // If the last line was a duplicate, ensure we mark it + if duplicateLine { + outStr += "*\n" + } + + return outStr +} + +func toHex(data []byte) string { + var hexStr string + for _, b := range data { + hexStr += fmt.Sprintf("%02x ", b) + } + return hexStr +} + +func BenchmarkHashChunk(b *testing.B) { + const benchSize = 1024 * 1024 + + // Generate 1 MiB of random data + randomData := make([]byte, benchSize) + if _, err := rand.Read(randomData); err != nil { + b.Fatalf("Failed to generate random data: %v", err) + } + + // Prepare data structure for hashChunk + data := make([][]byte, 1) + data[0] = randomData + + // append levels until we get to a 32 byte level + for len(data[len(data)-1]) > 32 { + newLevel := make([]byte, len(data[len(data)-1])/2) + data = append(data, newLevel) + } + + b.SetBytes(benchSize) // Set the number of bytes for the benchmark + + b.ResetTimer() // Start the timer after setup + + for i := 0; i < b.N; i++ { + hashChunk(data) + // Use the result in some way to avoid compiler optimization + _ = data[1] + } +} + +func BenchmarkBuildTreeD512M(b *testing.B) { + const dataSize = 512 * 1024 * 1024 // 512 MiB + + // Generate 512 MiB of random data + data := make([]byte, dataSize) + if _, err := rand.Read(data); err != nil { + b.Fatalf("Failed to generate random data: %v", err) + } + + // preallocate NumCPU+1 1MiB/512k/256k/... + // with Pool.Get / Pool.Put, so that they are in the pool + { + nc := runtime.NumCPU() + bufs := [][]byte{} + for i := 0; i < nc+1; i++ { + for sz := 1 << 20; sz > 32; sz >>= 1 { + b := pool.Get(sz) + bufs = append(bufs, b) + } + } + for _, b := range bufs { + pool.Put(b) + } + } + + /*if b.N == 1 { + b.N = 10 + }*/ + + b.SetBytes(int64(dataSize)) // Set the number of bytes for the benchmark + + for i := 0; i < b.N; i++ { + // Create a temporary file for each iteration + tempFile, err := os.CreateTemp("", "tree.dat") + if err != nil { + b.Fatalf("Failed to create temporary file: %v", err) + } + tempFilePath := tempFile.Name() + err = tempFile.Close() + if err != nil { + b.Fatalf("Failed to close temporary file: %v", err) + } + + b.StartTimer() // Start the timer for the BuildTreeD operation + + _, err = BuildTreeD(bytes.NewReader(data), false, tempFilePath, dataSize) + if err != nil { + b.Fatalf("BuildTreeD failed: %v", err) + } + + b.StopTimer() // Stop the timer after BuildTreeD completes + + // Clean up the temporary file + err = os.Remove(tempFilePath) + if err != nil { + b.Fatalf("Failed to remove temporary file: %v", err) + } + } +} + +func TestLayerOffset(t *testing.T) { + { + size := uint64(2048) + + require.Equal(t, uint64(0), layerOffset(size, 0)) + require.Equal(t, size, layerOffset(size, 1)) + require.Equal(t, size+(size/2), layerOffset(size, 2)) + require.Equal(t, size+(size/2)+(size/4), layerOffset(size, 3)) + require.Equal(t, size+(size/2)+(size/4)+(size/8), layerOffset(size, 4)) + require.Equal(t, size+(size/2)+(size/4)+(size/8)+(size/16), layerOffset(size, 5)) + } + + { + size := uint64(32 << 30) + maxLayers := 30 + + for i := 0; i <= maxLayers; i++ { + var expect uint64 + for j := 0; j < i; j++ { + expect += size >> uint64(j) + } + + fmt.Printf("layer %d: %d\n", i, expect) + require.Equal(t, expect, layerOffset(size, i)) + } + } + + { + size := uint64(64 << 30) + maxLayers := 31 + + for i := 0; i <= maxLayers; i++ { + var expect uint64 + for j := 0; j < i; j++ { + expect += size >> uint64(j) + } + + fmt.Printf("layer %d: %d\n", i, expect) + require.Equal(t, expect, layerOffset(size, i)) + } + } +} diff --git a/curiosrc/seal/README.md b/curiosrc/seal/README.md new file mode 100644 index 00000000000..b148e4204d1 --- /dev/null +++ b/curiosrc/seal/README.md @@ -0,0 +1,28 @@ +# Curio Sealer + +## Overview + +The Curio sealer is a collection of harmony tasks and a common poller +which implement the sealing functionality of the Filecoin protocol. + +## Pipeline Tasks + +* SDR pipeline + * `SDR` - Generate SDR layers + * `SDRTrees` - Generate tree files (TreeD, TreeR, TreeC) + * `PreCommitSubmit` - Submit precommit message to the network + * `PoRep` - Generate PoRep proof + * `CommitSubmit` - Submit commit message to the network + +# Poller + +The poller is a background process running on every node which runs any of the +SDR pipeline tasks. It periodically checks the state of sectors in the SDR pipeline +and schedules any tasks to run which will move the sector along the pipeline. + +# Error Handling + +* Pipeline tasks are expected to always finish successfully as harmonytask tasks. + If a sealing task encounters an error, it should mark the sector pipeline entry + as failed and exit without erroring. The poller will then figure out a recovery + strategy for the sector. diff --git a/curiosrc/seal/finalize_pieces.go b/curiosrc/seal/finalize_pieces.go new file mode 100644 index 00000000000..354eed1413e --- /dev/null +++ b/curiosrc/seal/finalize_pieces.go @@ -0,0 +1,51 @@ +package seal + +import ( + "context" + "net/url" + "strconv" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" +) + +func DropSectorPieceRefs(ctx context.Context, db *harmonydb.DB, sid abi.SectorID) error { + //_, err := db.Exec(ctx, `SELECT FROM sectors_sdr_initial_pieces WHERE sp_id = $1 AND sector_number = $2`, sid.Miner, sid.Number) + + var PieceURL []struct { + URL string `db:"data_url"` + } + + err := db.Select(ctx, &PieceURL, `SELECT data_url FROM sectors_sdr_initial_pieces WHERE sp_id = $1 AND sector_number = $2`, sid.Miner, sid.Number) + if err != nil { + return xerrors.Errorf("getting piece url: %w", err) + } + + for _, pu := range PieceURL { + gourl, err := url.Parse(pu.URL) + if err != nil { + log.Errorw("failed to parse piece url", "url", pu.URL, "error", err, "miner", sid.Miner, "sector", sid.Number) + continue + } + + if gourl.Scheme == "pieceref" { + refID, err := strconv.ParseInt(gourl.Opaque, 10, 64) + if err != nil { + log.Errorw("failed to parse piece ref id", "url", pu.URL, "error", err, "miner", sid.Miner, "sector", sid.Number) + continue + } + + n, err := db.Exec(ctx, `DELETE FROM parked_piece_refs WHERE ref_id = $1`, refID) + if err != nil { + log.Errorw("failed to delete piece ref", "url", pu.URL, "error", err, "miner", sid.Miner, "sector", sid.Number) + } + + log.Debugw("deleted piece ref", "url", pu.URL, "miner", sid.Miner, "sector", sid.Number, "rows", n) + } + } + + return err +} diff --git a/curiosrc/seal/poller.go b/curiosrc/seal/poller.go new file mode 100644 index 00000000000..568280bdbce --- /dev/null +++ b/curiosrc/seal/poller.go @@ -0,0 +1,285 @@ +package seal + +import ( + "context" + "time" + + logging "github.com/ipfs/go-log/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/promise" +) + +var log = logging.Logger("lpseal") + +const ( + pollerSDR = iota + pollerTrees + pollerPrecommitMsg + pollerPoRep + pollerCommitMsg + pollerFinalize + pollerMoveStorage + + numPollers +) + +const sealPollerInterval = 10 * time.Second +const seedEpochConfidence = 3 + +type SealPollerAPI interface { + StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) + StateSectorGetInfo(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tsk types.TipSetKey) (*miner.SectorOnChainInfo, error) + ChainHead(context.Context) (*types.TipSet, error) +} + +type SealPoller struct { + db *harmonydb.DB + api SealPollerAPI + + pollers [numPollers]promise.Promise[harmonytask.AddTaskFunc] +} + +func NewPoller(db *harmonydb.DB, api SealPollerAPI) *SealPoller { + return &SealPoller{ + db: db, + api: api, + } +} + +func (s *SealPoller) RunPoller(ctx context.Context) { + ticker := time.NewTicker(sealPollerInterval) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + if err := s.poll(ctx); err != nil { + log.Errorw("polling failed", "error", err) + } + } + } +} + +/* +NOTE: TaskIDs are ONLY set while the tasks are executing or waiting to execute. + This means that there are ~4 states each task can be in: +* Not run, and dependencies not solved (dependencies are 'After' fields of previous stages), task is null, After is false +* Not run, and dependencies solved, task is null, After is false +* Running or queued, task is set, After is false +* Finished, task is null, After is true +*/ + +type pollTask struct { + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + + TaskSDR *int64 `db:"task_id_sdr"` + AfterSDR bool `db:"after_sdr"` + + TaskTreeD *int64 `db:"task_id_tree_d"` + AfterTreeD bool `db:"after_tree_d"` + + TaskTreeC *int64 `db:"task_id_tree_c"` + AfterTreeC bool `db:"after_tree_c"` + + TaskTreeR *int64 `db:"task_id_tree_r"` + AfterTreeR bool `db:"after_tree_r"` + + TaskPrecommitMsg *int64 `db:"task_id_precommit_msg"` + AfterPrecommitMsg bool `db:"after_precommit_msg"` + + AfterPrecommitMsgSuccess bool `db:"after_precommit_msg_success"` + SeedEpoch *int64 `db:"seed_epoch"` + + TaskPoRep *int64 `db:"task_id_porep"` + PoRepProof []byte `db:"porep_proof"` + AfterPoRep bool `db:"after_porep"` + + TaskFinalize *int64 `db:"task_id_finalize"` + AfterFinalize bool `db:"after_finalize"` + + TaskMoveStorage *int64 `db:"task_id_move_storage"` + AfterMoveStorage bool `db:"after_move_storage"` + + TaskCommitMsg *int64 `db:"task_id_commit_msg"` + AfterCommitMsg bool `db:"after_commit_msg"` + + AfterCommitMsgSuccess bool `db:"after_commit_msg_success"` + + Failed bool `db:"failed"` + FailedReason string `db:"failed_reason"` +} + +func (s *SealPoller) poll(ctx context.Context) error { + var tasks []pollTask + + err := s.db.Select(ctx, &tasks, `SELECT + sp_id, sector_number, + task_id_sdr, after_sdr, + task_id_tree_d, after_tree_d, + task_id_tree_c, after_tree_c, + task_id_tree_r, after_tree_r, + task_id_precommit_msg, after_precommit_msg, + after_precommit_msg_success, seed_epoch, + task_id_porep, porep_proof, after_porep, + task_id_finalize, after_finalize, + task_id_move_storage, after_move_storage, + task_id_commit_msg, after_commit_msg, + after_commit_msg_success, + failed, failed_reason + FROM sectors_sdr_pipeline WHERE after_commit_msg_success != TRUE OR after_move_storage != TRUE`) + if err != nil { + return err + } + + for _, task := range tasks { + task := task + if task.Failed { + continue + } + + ts, err := s.api.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("getting chain head: %w", err) + } + + s.pollStartSDR(ctx, task) + s.pollStartSDRTrees(ctx, task) + s.pollStartPrecommitMsg(ctx, task) + s.mustPoll(s.pollPrecommitMsgLanded(ctx, task)) + s.pollStartPoRep(ctx, task, ts) + s.pollStartFinalize(ctx, task, ts) + s.pollStartMoveStorage(ctx, task) + s.pollStartCommitMsg(ctx, task) + s.mustPoll(s.pollCommitMsgLanded(ctx, task)) + } + + return nil +} + +func (s *SealPoller) pollStartSDR(ctx context.Context, task pollTask) { + if !task.AfterSDR && task.TaskSDR == nil && s.pollers[pollerSDR].IsSet() { + s.pollers[pollerSDR].Val(ctx)(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, seriousError error) { + n, err := tx.Exec(`UPDATE sectors_sdr_pipeline SET task_id_sdr = $1 WHERE sp_id = $2 AND sector_number = $3 AND task_id_sdr IS NULL`, id, task.SpID, task.SectorNumber) + if err != nil { + return false, xerrors.Errorf("update sectors_sdr_pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("expected to update 1 row, updated %d", n) + } + + return true, nil + }) + } +} + +func (t pollTask) afterSDR() bool { + return t.AfterSDR +} + +func (s *SealPoller) pollStartSDRTrees(ctx context.Context, task pollTask) { + if !task.AfterTreeD && !task.AfterTreeC && !task.AfterTreeR && + task.TaskTreeD == nil && task.TaskTreeC == nil && task.TaskTreeR == nil && + s.pollers[pollerTrees].IsSet() && task.AfterSDR { + + s.pollers[pollerTrees].Val(ctx)(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, seriousError error) { + n, err := tx.Exec(`UPDATE sectors_sdr_pipeline SET task_id_tree_d = $1, task_id_tree_c = $1, task_id_tree_r = $1 + WHERE sp_id = $2 AND sector_number = $3 AND after_sdr = TRUE AND task_id_tree_d IS NULL AND task_id_tree_c IS NULL AND task_id_tree_r IS NULL`, id, task.SpID, task.SectorNumber) + if err != nil { + return false, xerrors.Errorf("update sectors_sdr_pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("expected to update 1 row, updated %d", n) + } + + return true, nil + }) + } +} + +func (t pollTask) afterTrees() bool { + return t.AfterTreeD && t.AfterTreeC && t.AfterTreeR && t.afterSDR() +} + +func (t pollTask) afterPrecommitMsg() bool { + return t.AfterPrecommitMsg && t.afterTrees() +} + +func (t pollTask) afterPrecommitMsgSuccess() bool { + return t.AfterPrecommitMsgSuccess && t.afterPrecommitMsg() +} + +func (s *SealPoller) pollStartPoRep(ctx context.Context, task pollTask, ts *types.TipSet) { + if s.pollers[pollerPoRep].IsSet() && task.afterPrecommitMsgSuccess() && task.SeedEpoch != nil && + task.TaskPoRep == nil && !task.AfterPoRep && + ts.Height() >= abi.ChainEpoch(*task.SeedEpoch+seedEpochConfidence) { + + s.pollers[pollerPoRep].Val(ctx)(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, seriousError error) { + n, err := tx.Exec(`UPDATE sectors_sdr_pipeline SET task_id_porep = $1 WHERE sp_id = $2 AND sector_number = $3 AND task_id_porep IS NULL`, id, task.SpID, task.SectorNumber) + if err != nil { + return false, xerrors.Errorf("update sectors_sdr_pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("expected to update 1 row, updated %d", n) + } + + return true, nil + }) + } +} + +func (t pollTask) afterPoRep() bool { + return t.AfterPoRep && t.afterPrecommitMsgSuccess() +} + +func (s *SealPoller) pollStartFinalize(ctx context.Context, task pollTask, ts *types.TipSet) { + if s.pollers[pollerFinalize].IsSet() && task.afterPoRep() && !task.AfterFinalize && task.TaskFinalize == nil { + s.pollers[pollerFinalize].Val(ctx)(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, seriousError error) { + n, err := tx.Exec(`UPDATE sectors_sdr_pipeline SET task_id_finalize = $1 WHERE sp_id = $2 AND sector_number = $3 AND task_id_finalize IS NULL`, id, task.SpID, task.SectorNumber) + if err != nil { + return false, xerrors.Errorf("update sectors_sdr_pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("expected to update 1 row, updated %d", n) + } + + return true, nil + }) + } +} + +func (t pollTask) afterFinalize() bool { + return t.AfterFinalize && t.afterPoRep() +} + +func (s *SealPoller) pollStartMoveStorage(ctx context.Context, task pollTask) { + if s.pollers[pollerMoveStorage].IsSet() && task.afterFinalize() && !task.AfterMoveStorage && task.TaskMoveStorage == nil { + s.pollers[pollerMoveStorage].Val(ctx)(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, seriousError error) { + n, err := tx.Exec(`UPDATE sectors_sdr_pipeline SET task_id_move_storage = $1 WHERE sp_id = $2 AND sector_number = $3 AND task_id_move_storage IS NULL`, id, task.SpID, task.SectorNumber) + if err != nil { + return false, xerrors.Errorf("update sectors_sdr_pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("expected to update 1 row, updated %d", n) + } + + return true, nil + }) + } +} + +func (s *SealPoller) mustPoll(err error) { + if err != nil { + log.Errorw("poller operation failed", "error", err) + } +} diff --git a/curiosrc/seal/poller_commit_msg.go b/curiosrc/seal/poller_commit_msg.go new file mode 100644 index 00000000000..9a88129b04e --- /dev/null +++ b/curiosrc/seal/poller_commit_msg.go @@ -0,0 +1,108 @@ +package seal + +import ( + "context" + + "golang.org/x/xerrors" + + "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/chain/types" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" +) + +func (s *SealPoller) pollStartCommitMsg(ctx context.Context, task pollTask) { + if task.afterPoRep() && len(task.PoRepProof) > 0 && task.TaskCommitMsg == nil && !task.AfterCommitMsg && s.pollers[pollerCommitMsg].IsSet() { + s.pollers[pollerCommitMsg].Val(ctx)(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, seriousError error) { + n, err := tx.Exec(`UPDATE sectors_sdr_pipeline SET task_id_commit_msg = $1 WHERE sp_id = $2 AND sector_number = $3 AND task_id_commit_msg IS NULL`, id, task.SpID, task.SectorNumber) + if err != nil { + return false, xerrors.Errorf("update sectors_sdr_pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("expected to update 1 row, updated %d", n) + } + + return true, nil + }) + } +} + +func (s *SealPoller) pollCommitMsgLanded(ctx context.Context, task pollTask) error { + if task.AfterCommitMsg && !task.AfterCommitMsgSuccess && s.pollers[pollerCommitMsg].IsSet() { + var execResult []dbExecResult + + err := s.db.Select(ctx, &execResult, `SELECT spipeline.precommit_msg_cid, spipeline.commit_msg_cid, executed_tsk_cid, executed_tsk_epoch, executed_msg_cid, executed_rcpt_exitcode, executed_rcpt_gas_used + FROM sectors_sdr_pipeline spipeline + JOIN message_waits ON spipeline.commit_msg_cid = message_waits.signed_message_cid + WHERE sp_id = $1 AND sector_number = $2 AND executed_tsk_epoch IS NOT NULL`, task.SpID, task.SectorNumber) + if err != nil { + log.Errorw("failed to query message_waits", "error", err) + } + + if len(execResult) > 0 { + maddr, err := address.NewIDAddress(uint64(task.SpID)) + if err != nil { + return err + } + + if exitcode.ExitCode(execResult[0].ExecutedRcptExitCode) != exitcode.Ok { + return s.pollCommitMsgFail(ctx, task, execResult[0]) + } + + si, err := s.api.StateSectorGetInfo(ctx, maddr, abi.SectorNumber(task.SectorNumber), types.EmptyTSK) + if err != nil { + return xerrors.Errorf("get sector info: %w", err) + } + + if si == nil { + log.Errorw("todo handle missing sector info (not found after cron)", "sp", task.SpID, "sector", task.SectorNumber, "exec_epoch", execResult[0].ExecutedTskEpoch, "exec_tskcid", execResult[0].ExecutedTskCID, "msg_cid", execResult[0].ExecutedMsgCID) + // todo handdle missing sector info (not found after cron) + } else { + // yay! + + _, err := s.db.Exec(ctx, `UPDATE sectors_sdr_pipeline SET + after_commit_msg_success = TRUE, commit_msg_tsk = $1 + WHERE sp_id = $2 AND sector_number = $3 AND after_commit_msg_success = FALSE`, + execResult[0].ExecutedTskCID, task.SpID, task.SectorNumber) + if err != nil { + return xerrors.Errorf("update sectors_sdr_pipeline: %w", err) + } + } + } + } + + return nil +} + +func (s *SealPoller) pollCommitMsgFail(ctx context.Context, task pollTask, execResult dbExecResult) error { + switch exitcode.ExitCode(execResult.ExecutedRcptExitCode) { + case exitcode.SysErrInsufficientFunds: + fallthrough + case exitcode.SysErrOutOfGas: + // just retry + return s.pollRetryCommitMsgSend(ctx, task, execResult) + default: + return xerrors.Errorf("commit message failed with exit code %s", exitcode.ExitCode(execResult.ExecutedRcptExitCode)) + } +} + +func (s *SealPoller) pollRetryCommitMsgSend(ctx context.Context, task pollTask, execResult dbExecResult) error { + if execResult.CommitMsgCID == nil { + return xerrors.Errorf("commit msg cid was nil") + } + + // make the pipeline entry seem like precommit send didn't happen, next poll loop will retry + + _, err := s.db.Exec(ctx, `UPDATE sectors_sdr_pipeline SET + commit_msg_cid = NULL, task_id_commit_msg = NULL, after_commit_msg = FALSE + WHERE commit_msg_cid = $1 AND sp_id = $2 AND sector_number = $3 AND after_commit_msg_success = FALSE`, + *execResult.CommitMsgCID, task.SpID, task.SectorNumber) + if err != nil { + return xerrors.Errorf("update sectors_sdr_pipeline to retry precommit msg send: %w", err) + } + + return nil +} diff --git a/curiosrc/seal/poller_precommit_msg.go b/curiosrc/seal/poller_precommit_msg.go new file mode 100644 index 00000000000..4372cbb9223 --- /dev/null +++ b/curiosrc/seal/poller_precommit_msg.go @@ -0,0 +1,119 @@ +package seal + +import ( + "context" + + "golang.org/x/xerrors" + + "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/chain/actors/policy" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" +) + +func (s *SealPoller) pollStartPrecommitMsg(ctx context.Context, task pollTask) { + if task.TaskPrecommitMsg == nil && !task.AfterPrecommitMsg && task.afterTrees() && s.pollers[pollerPrecommitMsg].IsSet() { + s.pollers[pollerPrecommitMsg].Val(ctx)(func(id harmonytask.TaskID, tx *harmonydb.Tx) (shouldCommit bool, seriousError error) { + n, err := tx.Exec(`UPDATE sectors_sdr_pipeline SET task_id_precommit_msg = $1 WHERE sp_id = $2 AND sector_number = $3 AND task_id_precommit_msg IS NULL AND after_tree_r = TRUE AND after_tree_d = TRUE`, id, task.SpID, task.SectorNumber) + if err != nil { + return false, xerrors.Errorf("update sectors_sdr_pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("expected to update 1 row, updated %d", n) + } + + return true, nil + }) + } +} + +type dbExecResult struct { + PrecommitMsgCID *string `db:"precommit_msg_cid"` + CommitMsgCID *string `db:"commit_msg_cid"` + + ExecutedTskCID string `db:"executed_tsk_cid"` + ExecutedTskEpoch int64 `db:"executed_tsk_epoch"` + ExecutedMsgCID string `db:"executed_msg_cid"` + + ExecutedRcptExitCode int64 `db:"executed_rcpt_exitcode"` + ExecutedRcptGasUsed int64 `db:"executed_rcpt_gas_used"` +} + +func (s *SealPoller) pollPrecommitMsgLanded(ctx context.Context, task pollTask) error { + if task.AfterPrecommitMsg && !task.AfterPrecommitMsgSuccess { + var execResult []dbExecResult + + err := s.db.Select(ctx, &execResult, `SELECT spipeline.precommit_msg_cid, spipeline.commit_msg_cid, executed_tsk_cid, executed_tsk_epoch, executed_msg_cid, executed_rcpt_exitcode, executed_rcpt_gas_used + FROM sectors_sdr_pipeline spipeline + JOIN message_waits ON spipeline.precommit_msg_cid = message_waits.signed_message_cid + WHERE sp_id = $1 AND sector_number = $2 AND executed_tsk_epoch IS NOT NULL`, task.SpID, task.SectorNumber) + if err != nil { + log.Errorw("failed to query message_waits", "error", err) + } + + if len(execResult) > 0 { + if exitcode.ExitCode(execResult[0].ExecutedRcptExitCode) != exitcode.Ok { + return s.pollPrecommitMsgFail(ctx, task, execResult[0]) + } + + maddr, err := address.NewIDAddress(uint64(task.SpID)) + if err != nil { + return err + } + + pci, err := s.api.StateSectorPreCommitInfo(ctx, maddr, abi.SectorNumber(task.SectorNumber), types.EmptyTSK) + if err != nil { + return xerrors.Errorf("get precommit info: %w", err) + } + + if pci != nil { + randHeight := pci.PreCommitEpoch + policy.GetPreCommitChallengeDelay() + + _, err := s.db.Exec(ctx, `UPDATE sectors_sdr_pipeline SET + seed_epoch = $1, precommit_msg_tsk = $2, after_precommit_msg_success = TRUE + WHERE sp_id = $3 AND sector_number = $4 AND seed_epoch IS NULL`, + randHeight, execResult[0].ExecutedTskCID, task.SpID, task.SectorNumber) + if err != nil { + return xerrors.Errorf("update sectors_sdr_pipeline: %w", err) + } + } // todo handle missing precommit info (eg expired precommit) + + } + } + + return nil +} + +func (s *SealPoller) pollPrecommitMsgFail(ctx context.Context, task pollTask, execResult dbExecResult) error { + switch exitcode.ExitCode(execResult.ExecutedRcptExitCode) { + case exitcode.SysErrInsufficientFunds: + fallthrough + case exitcode.SysErrOutOfGas: + // just retry + return s.pollRetryPrecommitMsgSend(ctx, task, execResult) + default: + return xerrors.Errorf("precommit message failed with exit code %s", exitcode.ExitCode(execResult.ExecutedRcptExitCode)) + } +} + +func (s *SealPoller) pollRetryPrecommitMsgSend(ctx context.Context, task pollTask, execResult dbExecResult) error { + if execResult.PrecommitMsgCID == nil { + return xerrors.Errorf("precommit msg cid was nil") + } + + // make the pipeline entry seem like precommit send didn't happen, next poll loop will retry + + _, err := s.db.Exec(ctx, `UPDATE sectors_sdr_pipeline SET + precommit_msg_cid = NULL, task_id_precommit_msg = NULL, after_precommit_msg = FALSE + WHERE precommit_msg_cid = $1 AND sp_id = $2 AND sector_number = $3 AND after_precommit_msg_success = FALSE`, + *execResult.PrecommitMsgCID, task.SpID, task.SectorNumber) + if err != nil { + return xerrors.Errorf("update sectors_sdr_pipeline to retry precommit msg send: %w", err) + } + + return nil +} diff --git a/curiosrc/seal/sector_num_alloc.go b/curiosrc/seal/sector_num_alloc.go new file mode 100644 index 00000000000..010ebee395d --- /dev/null +++ b/curiosrc/seal/sector_num_alloc.go @@ -0,0 +1,127 @@ +package seal + +import ( + "context" + + "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" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" +) + +type AllocAPI interface { + StateMinerAllocated(context.Context, address.Address, types.TipSetKey) (*bitfield.BitField, error) +} + +func AllocateSectorNumbers(ctx context.Context, a AllocAPI, db *harmonydb.DB, maddr address.Address, count int, txcb ...func(*harmonydb.Tx, []abi.SectorNumber) (bool, error)) ([]abi.SectorNumber, error) { + chainAlloc, err := a.StateMinerAllocated(ctx, maddr, types.EmptyTSK) + if err != nil { + return nil, xerrors.Errorf("getting on-chain allocated sector numbers: %w", err) + } + + mid, err := address.IDFromAddress(maddr) + if err != nil { + return nil, xerrors.Errorf("getting miner id: %w", err) + } + + var res []abi.SectorNumber + + comm, err := db.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { + res = nil // reset result in case of retry + + // query from db, if exists unmarsal to bitfield + var dbAllocated bitfield.BitField + var rawJson []byte + + err = tx.QueryRow("SELECT COALESCE(allocated, '[0]') from sectors_allocated_numbers sa FULL OUTER JOIN (SELECT 1) AS d ON TRUE WHERE sp_id = $1 OR sp_id IS NULL", mid).Scan(&rawJson) + if err != nil { + return false, xerrors.Errorf("querying allocated sector numbers: %w", err) + } + + if rawJson != nil { + err = dbAllocated.UnmarshalJSON(rawJson) + if err != nil { + return false, xerrors.Errorf("unmarshaling allocated sector numbers: %w", err) + } + } + + if err := dbAllocated.UnmarshalJSON(rawJson); err != nil { + return false, xerrors.Errorf("unmarshaling allocated sector numbers: %w", err) + } + + merged, err := bitfield.MergeBitFields(*chainAlloc, dbAllocated) + if err != nil { + return false, xerrors.Errorf("merging allocated sector numbers: %w", err) + } + + allAssignable, err := bitfield.NewFromIter(&rlepluslazy.RunSliceIterator{Runs: []rlepluslazy.Run{ + { + Val: true, + Len: abi.MaxSectorNumber, + }, + }}) + if err != nil { + return false, xerrors.Errorf("creating assignable sector numbers: %w", err) + } + + inverted, err := bitfield.SubtractBitField(allAssignable, merged) + if err != nil { + return false, xerrors.Errorf("subtracting allocated sector numbers: %w", err) + } + + toAlloc, err := inverted.Slice(0, uint64(count)) + if err != nil { + return false, xerrors.Errorf("getting slice of allocated sector numbers: %w", err) + } + + err = toAlloc.ForEach(func(u uint64) error { + res = append(res, abi.SectorNumber(u)) + return nil + }) + if err != nil { + return false, xerrors.Errorf("iterating allocated sector numbers: %w", err) + } + + toPersist, err := bitfield.MergeBitFields(merged, toAlloc) + if err != nil { + return false, xerrors.Errorf("merging allocated sector numbers: %w", err) + } + + rawJson, err = toPersist.MarshalJSON() + if err != nil { + return false, xerrors.Errorf("marshaling allocated sector numbers: %w", err) + } + + _, err = tx.Exec("INSERT INTO sectors_allocated_numbers(sp_id, allocated) VALUES($1, $2) ON CONFLICT(sp_id) DO UPDATE SET allocated = $2", mid, rawJson) + if err != nil { + return false, xerrors.Errorf("persisting allocated sector numbers: %w", err) + } + + for i, f := range txcb { + commit, err = f(tx, res) + if err != nil { + return false, xerrors.Errorf("executing tx callback %d: %w", i, err) + } + + if !commit { + return false, nil + } + } + + return true, nil + }, harmonydb.OptionRetry()) + + if err != nil { + return nil, xerrors.Errorf("allocating sector numbers: %w", err) + } + if !comm { + return nil, xerrors.Errorf("allocating sector numbers: commit failed") + } + + return res, nil +} diff --git a/curiosrc/seal/task_finalize.go b/curiosrc/seal/task_finalize.go new file mode 100644 index 00000000000..2b362d7bead --- /dev/null +++ b/curiosrc/seal/task_finalize.go @@ -0,0 +1,156 @@ +package seal + +import ( + "context" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/curiosrc/ffi" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +type FinalizeTask struct { + max int + sp *SealPoller + sc *ffi.SealCalls + db *harmonydb.DB +} + +func NewFinalizeTask(max int, sp *SealPoller, sc *ffi.SealCalls, db *harmonydb.DB) *FinalizeTask { + return &FinalizeTask{ + max: max, + sp: sp, + sc: sc, + db: db, + } +} + +func (f *FinalizeTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + var tasks []struct { + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + RegSealProof int64 `db:"reg_seal_proof"` + } + + ctx := context.Background() + + err = f.db.Select(ctx, &tasks, ` + SELECT sp_id, sector_number, reg_seal_proof FROM sectors_sdr_pipeline WHERE task_id_finalize = $1`, taskID) + if err != nil { + return false, xerrors.Errorf("getting task: %w", err) + } + + if len(tasks) != 1 { + return false, xerrors.Errorf("expected one task") + } + task := tasks[0] + + var keepUnsealed bool + + if err := f.db.QueryRow(ctx, `SELECT COALESCE(BOOL_OR(NOT data_delete_on_finalize), FALSE) FROM sectors_sdr_initial_pieces WHERE sp_id = $1 AND sector_number = $2`, task.SpID, task.SectorNumber).Scan(&keepUnsealed); err != nil { + return false, err + } + + sector := storiface.SectorRef{ + ID: abi.SectorID{ + Miner: abi.ActorID(task.SpID), + Number: abi.SectorNumber(task.SectorNumber), + }, + ProofType: abi.RegisteredSealProof(task.RegSealProof), + } + + err = f.sc.FinalizeSector(ctx, sector, keepUnsealed) + if err != nil { + return false, xerrors.Errorf("finalizing sector: %w", err) + } + + if err := DropSectorPieceRefs(ctx, f.db, sector.ID); err != nil { + return false, xerrors.Errorf("dropping sector piece refs: %w", err) + } + + // set after_finalize + _, err = f.db.Exec(ctx, `update sectors_sdr_pipeline set after_finalize=true where task_id_finalize=$1`, taskID) + if err != nil { + return false, xerrors.Errorf("updating task: %w", err) + } + + return true, nil +} + +func (f *FinalizeTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + var tasks []struct { + TaskID harmonytask.TaskID `db:"task_id_finalize"` + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + StorageID string `db:"storage_id"` + } + + if storiface.FTCache != 4 { + panic("storiface.FTCache != 4") + } + + ctx := context.Background() + + indIDs := make([]int64, len(ids)) + for i, id := range ids { + indIDs[i] = int64(id) + } + + err := f.db.Select(ctx, &tasks, ` + SELECT p.task_id_finalize, p.sp_id, p.sector_number, l.storage_id FROM sectors_sdr_pipeline p + INNER JOIN sector_location l ON p.sp_id = l.miner_id AND p.sector_number = l.sector_num + WHERE task_id_finalize = ANY ($1) AND l.sector_filetype = 4 +`, indIDs) + if err != nil { + return nil, xerrors.Errorf("getting tasks: %w", err) + } + + ls, err := f.sc.LocalStorage(ctx) + if err != nil { + return nil, xerrors.Errorf("getting local storage: %w", err) + } + + acceptables := map[harmonytask.TaskID]bool{} + + for _, t := range ids { + acceptables[t] = true + } + + for _, t := range tasks { + if _, ok := acceptables[t.TaskID]; !ok { + continue + } + + for _, l := range ls { + if string(l.ID) == t.StorageID { + return &t.TaskID, nil + } + } + } + + return nil, nil +} + +func (f *FinalizeTask) TypeDetails() harmonytask.TaskTypeDetails { + return harmonytask.TaskTypeDetails{ + Max: f.max, + Name: "Finalize", + Cost: resources.Resources{ + Cpu: 1, + Gpu: 0, + Ram: 100 << 20, + }, + MaxFailures: 10, + } +} + +func (f *FinalizeTask) Adder(taskFunc harmonytask.AddTaskFunc) { + f.sp.pollers[pollerFinalize].Set(taskFunc) +} + +var _ harmonytask.TaskInterface = &FinalizeTask{} diff --git a/curiosrc/seal/task_movestorage.go b/curiosrc/seal/task_movestorage.go new file mode 100644 index 00000000000..6037a390dc7 --- /dev/null +++ b/curiosrc/seal/task_movestorage.go @@ -0,0 +1,176 @@ +package seal + +import ( + "context" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/curiosrc/ffi" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +type MoveStorageTask struct { + sp *SealPoller + sc *ffi.SealCalls + db *harmonydb.DB + + max int +} + +func NewMoveStorageTask(sp *SealPoller, sc *ffi.SealCalls, db *harmonydb.DB, max int) *MoveStorageTask { + return &MoveStorageTask{ + max: max, + sp: sp, + sc: sc, + db: db, + } +} + +func (m *MoveStorageTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + var tasks []struct { + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + RegSealProof int64 `db:"reg_seal_proof"` + } + + ctx := context.Background() + + err = m.db.Select(ctx, &tasks, ` + SELECT sp_id, sector_number, reg_seal_proof FROM sectors_sdr_pipeline WHERE task_id_move_storage = $1`, taskID) + if err != nil { + return false, xerrors.Errorf("getting task: %w", err) + } + if len(tasks) != 1 { + return false, xerrors.Errorf("expected one task") + } + task := tasks[0] + + sector := storiface.SectorRef{ + ID: abi.SectorID{ + Miner: abi.ActorID(task.SpID), + Number: abi.SectorNumber(task.SectorNumber), + }, + ProofType: abi.RegisteredSealProof(task.RegSealProof), + } + + err = m.sc.MoveStorage(ctx, sector, &taskID) + if err != nil { + return false, xerrors.Errorf("moving storage: %w", err) + } + + _, err = m.db.Exec(ctx, `UPDATE sectors_sdr_pipeline SET after_move_storage = true WHERE task_id_move_storage = $1`, taskID) + if err != nil { + return false, xerrors.Errorf("updating task: %w", err) + } + + return true, nil +} + +func (m *MoveStorageTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + + ctx := context.Background() + /* + + var tasks []struct { + TaskID harmonytask.TaskID `db:"task_id_finalize"` + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + StorageID string `db:"storage_id"` + } + + indIDs := make([]int64, len(ids)) + for i, id := range ids { + indIDs[i] = int64(id) + } + err := m.db.Select(ctx, &tasks, ` + select p.task_id_move_storage, p.sp_id, p.sector_number, l.storage_id from sectors_sdr_pipeline p + inner join sector_location l on p.sp_id=l.miner_id and p.sector_number=l.sector_num + where task_id_move_storage in ($1) and l.sector_filetype=4`, indIDs) + if err != nil { + return nil, xerrors.Errorf("getting tasks: %w", err) + } + + ls, err := m.sc.LocalStorage(ctx) + if err != nil { + return nil, xerrors.Errorf("getting local storage: %w", err) + } + + acceptables := map[harmonytask.TaskID]bool{} + + for _, t := range ids { + acceptables[t] = true + } + + for _, t := range tasks { + + } + + todo some smarts + * yield a schedule cycle/s if we have moves already in progress + */ + + //// + ls, err := m.sc.LocalStorage(ctx) + if err != nil { + return nil, xerrors.Errorf("getting local storage: %w", err) + } + var haveStorage bool + for _, l := range ls { + if l.CanStore { + haveStorage = true + break + } + } + + if !haveStorage { + return nil, nil + } + + id := ids[0] + return &id, nil +} + +func (m *MoveStorageTask) TypeDetails() harmonytask.TaskTypeDetails { + ssize := abi.SectorSize(32 << 30) // todo task details needs taskID to get correct sector size + if isDevnet { + ssize = abi.SectorSize(2 << 20) + } + + return harmonytask.TaskTypeDetails{ + Max: m.max, + Name: "MoveStorage", + Cost: resources.Resources{ + Cpu: 1, + Gpu: 0, + Ram: 128 << 20, + Storage: m.sc.Storage(m.taskToSector, storiface.FTNone, storiface.FTCache|storiface.FTSealed|storiface.FTUnsealed, ssize, storiface.PathStorage), + }, + MaxFailures: 10, + } +} + +func (m *MoveStorageTask) taskToSector(id harmonytask.TaskID) (ffi.SectorRef, error) { + var refs []ffi.SectorRef + + err := m.db.Select(context.Background(), &refs, `SELECT sp_id, sector_number, reg_seal_proof FROM sectors_sdr_pipeline WHERE task_id_move_storage = $1`, id) + if err != nil { + return ffi.SectorRef{}, xerrors.Errorf("getting sector ref: %w", err) + } + + if len(refs) != 1 { + return ffi.SectorRef{}, xerrors.Errorf("expected 1 sector ref, got %d", len(refs)) + } + + return refs[0], nil +} + +func (m *MoveStorageTask) Adder(taskFunc harmonytask.AddTaskFunc) { + m.sp.pollers[pollerMoveStorage].Set(taskFunc) +} + +var _ harmonytask.TaskInterface = &MoveStorageTask{} diff --git a/curiosrc/seal/task_porep.go b/curiosrc/seal/task_porep.go new file mode 100644 index 00000000000..58e307bc020 --- /dev/null +++ b/curiosrc/seal/task_porep.go @@ -0,0 +1,216 @@ +package seal + +import ( + "bytes" + "context" + "strings" + + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/curiosrc/ffi" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +type PoRepAPI interface { + ChainHead(context.Context) (*types.TipSet, error) + StateGetRandomnessFromBeacon(context.Context, crypto.DomainSeparationTag, abi.ChainEpoch, []byte, types.TipSetKey) (abi.Randomness, error) +} + +type PoRepTask struct { + db *harmonydb.DB + api PoRepAPI + sp *SealPoller + sc *ffi.SealCalls + + max int +} + +func NewPoRepTask(db *harmonydb.DB, api PoRepAPI, sp *SealPoller, sc *ffi.SealCalls, maxPoRep int) *PoRepTask { + return &PoRepTask{ + db: db, + api: api, + sp: sp, + sc: sc, + max: maxPoRep, + } +} + +func (p *PoRepTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + ctx := context.Background() + + var sectorParamsArr []struct { + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + RegSealProof abi.RegisteredSealProof `db:"reg_seal_proof"` + TicketEpoch abi.ChainEpoch `db:"ticket_epoch"` + TicketValue []byte `db:"ticket_value"` + SeedEpoch abi.ChainEpoch `db:"seed_epoch"` + SealedCID string `db:"tree_r_cid"` + UnsealedCID string `db:"tree_d_cid"` + } + + err = p.db.Select(ctx, §orParamsArr, ` + SELECT sp_id, sector_number, reg_seal_proof, ticket_epoch, ticket_value, seed_epoch, tree_r_cid, tree_d_cid + FROM sectors_sdr_pipeline + WHERE task_id_porep = $1`, taskID) + if err != nil { + return false, err + } + if len(sectorParamsArr) != 1 { + return false, xerrors.Errorf("expected 1 sector params, got %d", len(sectorParamsArr)) + } + sectorParams := sectorParamsArr[0] + + sealed, err := cid.Parse(sectorParams.SealedCID) + if err != nil { + return false, xerrors.Errorf("failed to parse sealed cid: %w", err) + } + + unsealed, err := cid.Parse(sectorParams.UnsealedCID) + if err != nil { + return false, xerrors.Errorf("failed to parse unsealed cid: %w", err) + } + + ts, err := p.api.ChainHead(ctx) + if err != nil { + return false, xerrors.Errorf("failed to get chain head: %w", err) + } + + maddr, err := address.NewIDAddress(uint64(sectorParams.SpID)) + if err != nil { + return false, xerrors.Errorf("failed to create miner address: %w", err) + } + + buf := new(bytes.Buffer) + if err := maddr.MarshalCBOR(buf); err != nil { + return false, xerrors.Errorf("failed to marshal miner address: %w", err) + } + + rand, err := p.api.StateGetRandomnessFromBeacon(ctx, crypto.DomainSeparationTag_InteractiveSealChallengeSeed, sectorParams.SeedEpoch, buf.Bytes(), ts.Key()) + if err != nil { + return false, xerrors.Errorf("failed to get randomness for computing seal proof: %w", err) + } + + sr := storiface.SectorRef{ + ID: abi.SectorID{ + Miner: abi.ActorID(sectorParams.SpID), + Number: abi.SectorNumber(sectorParams.SectorNumber), + }, + ProofType: sectorParams.RegSealProof, + } + + // COMPUTE THE PROOF! + + proof, err := p.sc.PoRepSnark(ctx, sr, sealed, unsealed, sectorParams.TicketValue, abi.InteractiveSealRandomness(rand)) + if err != nil { + end, err := p.recoverErrors(ctx, sectorParams.SpID, sectorParams.SectorNumber, err) + if err != nil { + return false, xerrors.Errorf("recover errors: %w", err) + } + if end { + // done, but the error handling has stored a different than success state + return true, nil + } + + return false, xerrors.Errorf("failed to compute seal proof: %w", err) + } + + // store success! + n, err := p.db.Exec(ctx, `UPDATE sectors_sdr_pipeline + SET after_porep = TRUE, seed_value = $3, porep_proof = $4 + WHERE sp_id = $1 AND sector_number = $2`, + sectorParams.SpID, sectorParams.SectorNumber, []byte(rand), proof) + if err != nil { + return false, xerrors.Errorf("store sdr success: updating pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("store sdr success: updated %d rows", n) + } + + return true, nil +} + +func (p *PoRepTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + // todo sort by priority + + id := ids[0] + return &id, nil +} + +func (p *PoRepTask) TypeDetails() harmonytask.TaskTypeDetails { + res := harmonytask.TaskTypeDetails{ + Max: p.max, + Name: "PoRep", + Cost: resources.Resources{ + Cpu: 1, + Gpu: 1, + Ram: 50 << 30, // todo correct value + MachineID: 0, + }, + MaxFailures: 5, + Follows: nil, + } + + if isDevnet { + res.Cost.Ram = 1 << 30 + } + + return res +} + +func (p *PoRepTask) Adder(taskFunc harmonytask.AddTaskFunc) { + p.sp.pollers[pollerPoRep].Set(taskFunc) +} + +func (p *PoRepTask) recoverErrors(ctx context.Context, spid, snum int64, cerr error) (end bool, err error) { + const ( + // rust-fil-proofs error strings + // https://github.com/filecoin-project/rust-fil-proofs/blob/3f018b51b6327b135830899d237a7ba181942d7e/storage-proofs-porep/src/stacked/vanilla/proof.rs#L454C1-L463 + errstrInvalidCommD = "Invalid comm_d detected at challenge_index" + errstrInvalidCommR = "Invalid comm_r detected at challenge_index" + errstrInvalidEncoding = "Invalid encoding proof generated at layer" + ) + + if cerr == nil { + return false, xerrors.Errorf("nil error") + } + + switch { + case strings.Contains(cerr.Error(), errstrInvalidCommD): + fallthrough + case strings.Contains(cerr.Error(), errstrInvalidCommR): + // todo: it might be more optimal to just retry the Trees compute first. + // Invalid CommD/R likely indicates a problem with the data computed in that step + // For now for simplicity just retry the whole thing + fallthrough + case strings.Contains(cerr.Error(), errstrInvalidEncoding): + n, err := p.db.Exec(ctx, `UPDATE sectors_sdr_pipeline + SET after_porep = FALSE, after_sdr = FALSE, after_tree_d = FALSE, + after_tree_r = FALSE, after_tree_c = FALSE + WHERE sp_id = $1 AND sector_number = $2`, + spid, snum) + if err != nil { + return false, xerrors.Errorf("store sdr success: updating pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("store sdr success: updated %d rows", n) + } + + return true, nil + + default: + // if end is false the original error will be returned by the caller + return false, nil + } +} + +var _ harmonytask.TaskInterface = &PoRepTask{} diff --git a/curiosrc/seal/task_sdr.go b/curiosrc/seal/task_sdr.go new file mode 100644 index 00000000000..4c1164e0581 --- /dev/null +++ b/curiosrc/seal/task_sdr.go @@ -0,0 +1,239 @@ +package seal + +import ( + "bytes" + "context" + + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-commp-utils/nonffi" + "github.com/filecoin-project/go-commp-utils/zerocomm" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/policy" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/curiosrc/ffi" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +var isDevnet = build.BlockDelaySecs < 30 + +type SDRAPI interface { + ChainHead(context.Context) (*types.TipSet, error) + StateGetRandomnessFromTickets(context.Context, crypto.DomainSeparationTag, abi.ChainEpoch, []byte, types.TipSetKey) (abi.Randomness, error) +} + +type SDRTask struct { + api SDRAPI + db *harmonydb.DB + sp *SealPoller + + sc *ffi.SealCalls + + max int +} + +func NewSDRTask(api SDRAPI, db *harmonydb.DB, sp *SealPoller, sc *ffi.SealCalls, maxSDR int) *SDRTask { + return &SDRTask{ + api: api, + db: db, + sp: sp, + sc: sc, + max: maxSDR, + } +} + +func (s *SDRTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + ctx := context.Background() + + var sectorParamsArr []struct { + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + RegSealProof abi.RegisteredSealProof `db:"reg_seal_proof"` + } + + err = s.db.Select(ctx, §orParamsArr, ` + SELECT sp_id, sector_number, reg_seal_proof + FROM sectors_sdr_pipeline + WHERE task_id_sdr = $1`, taskID) + if err != nil { + return false, xerrors.Errorf("getting sector params: %w", err) + } + + if len(sectorParamsArr) != 1 { + return false, xerrors.Errorf("expected 1 sector params, got %d", len(sectorParamsArr)) + } + sectorParams := sectorParamsArr[0] + + var pieces []struct { + PieceIndex int64 `db:"piece_index"` + PieceCID string `db:"piece_cid"` + PieceSize int64 `db:"piece_size"` + } + + err = s.db.Select(ctx, &pieces, ` + SELECT piece_index, piece_cid, piece_size + FROM sectors_sdr_initial_pieces + WHERE sp_id = $1 AND sector_number = $2 ORDER BY piece_index ASC`, sectorParams.SpID, sectorParams.SectorNumber) + if err != nil { + return false, xerrors.Errorf("getting pieces: %w", err) + } + + ssize, err := sectorParams.RegSealProof.SectorSize() + if err != nil { + return false, xerrors.Errorf("getting sector size: %w", err) + } + + var commd cid.Cid + + if len(pieces) > 0 { + pieceInfos := make([]abi.PieceInfo, len(pieces)) + for i, p := range pieces { + c, err := cid.Parse(p.PieceCID) + if err != nil { + return false, xerrors.Errorf("parsing piece cid: %w", err) + } + + pieceInfos[i] = abi.PieceInfo{ + Size: abi.PaddedPieceSize(p.PieceSize), + PieceCID: c, + } + } + + commd, err = nonffi.GenerateUnsealedCID(sectorParams.RegSealProof, pieceInfos) + if err != nil { + return false, xerrors.Errorf("computing CommD: %w", err) + } + } else { + commd = zerocomm.ZeroPieceCommitment(abi.PaddedPieceSize(ssize).Unpadded()) + } + + sref := storiface.SectorRef{ + ID: abi.SectorID{ + Miner: abi.ActorID(sectorParams.SpID), + Number: abi.SectorNumber(sectorParams.SectorNumber), + }, + ProofType: sectorParams.RegSealProof, + } + + // get ticket + maddr, err := address.NewIDAddress(uint64(sectorParams.SpID)) + if err != nil { + return false, xerrors.Errorf("getting miner address: %w", err) + } + + // FAIL: api may be down + // FAIL-RESP: rely on harmony retry + ticket, ticketEpoch, err := s.getTicket(ctx, maddr) + if err != nil { + return false, xerrors.Errorf("getting ticket: %w", err) + } + + // do the SDR!! + + // FAIL: storage may not have enough space + // FAIL-RESP: rely on harmony retry + + // LATEFAIL: compute error in sdr + // LATEFAIL-RESP: Check in Trees task should catch this; Will retry computing + // Trees; After one retry, it should return the sector to the + // SDR stage; max number of retries should be configurable + + err = s.sc.GenerateSDR(ctx, taskID, sref, ticket, commd) + if err != nil { + return false, xerrors.Errorf("generating sdr: %w", err) + } + + // store success! + n, err := s.db.Exec(ctx, `UPDATE sectors_sdr_pipeline + SET after_sdr = true, ticket_epoch = $3, ticket_value = $4 + WHERE sp_id = $1 AND sector_number = $2`, + sectorParams.SpID, sectorParams.SectorNumber, ticketEpoch, []byte(ticket)) + if err != nil { + return false, xerrors.Errorf("store sdr success: updating pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("store sdr success: updated %d rows", n) + } + + return true, nil +} + +func (s *SDRTask) getTicket(ctx context.Context, maddr address.Address) (abi.SealRandomness, abi.ChainEpoch, error) { + ts, err := s.api.ChainHead(ctx) + if err != nil { + return nil, 0, xerrors.Errorf("getting chain head: %w", err) + } + + ticketEpoch := ts.Height() - policy.SealRandomnessLookback + buf := new(bytes.Buffer) + if err := maddr.MarshalCBOR(buf); err != nil { + return nil, 0, xerrors.Errorf("marshaling miner address: %w", err) + } + + rand, err := s.api.StateGetRandomnessFromTickets(ctx, crypto.DomainSeparationTag_SealRandomness, ticketEpoch, buf.Bytes(), ts.Key()) + if err != nil { + return nil, 0, xerrors.Errorf("getting randomness from tickets: %w", err) + } + + return abi.SealRandomness(rand), ticketEpoch, nil +} + +func (s *SDRTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + id := ids[0] + return &id, nil +} + +func (s *SDRTask) TypeDetails() harmonytask.TaskTypeDetails { + ssize := abi.SectorSize(32 << 30) // todo task details needs taskID to get correct sector size + if isDevnet { + ssize = abi.SectorSize(2 << 20) + } + + res := harmonytask.TaskTypeDetails{ + Max: s.max, + Name: "SDR", + Cost: resources.Resources{ // todo offset for prefetch? + Cpu: 4, // todo multicore sdr + Gpu: 0, + Ram: 54 << 30, + Storage: s.sc.Storage(s.taskToSector, storiface.FTCache, storiface.FTNone, ssize, storiface.PathSealing), + }, + MaxFailures: 2, + Follows: nil, + } + + if isDevnet { + res.Cost.Ram = 1 << 30 + } + + return res +} + +func (s *SDRTask) Adder(taskFunc harmonytask.AddTaskFunc) { + s.sp.pollers[pollerSDR].Set(taskFunc) +} + +func (s *SDRTask) taskToSector(id harmonytask.TaskID) (ffi.SectorRef, error) { + var refs []ffi.SectorRef + + err := s.db.Select(context.Background(), &refs, `SELECT sp_id, sector_number, reg_seal_proof FROM sectors_sdr_pipeline WHERE task_id_sdr = $1`, id) + if err != nil { + return ffi.SectorRef{}, xerrors.Errorf("getting sector ref: %w", err) + } + + if len(refs) != 1 { + return ffi.SectorRef{}, xerrors.Errorf("expected 1 sector ref, got %d", len(refs)) + } + + return refs[0], nil +} + +var _ harmonytask.TaskInterface = &SDRTask{} diff --git a/curiosrc/seal/task_submit_commit.go b/curiosrc/seal/task_submit_commit.go new file mode 100644 index 00000000000..d7f133db71c --- /dev/null +++ b/curiosrc/seal/task_submit_commit.go @@ -0,0 +1,178 @@ +package seal + +import ( + "bytes" + "context" + + "golang.org/x/xerrors" + + "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/builtin" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/curiosrc/message" + "github.com/filecoin-project/lotus/curiosrc/multictladdr" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + "github.com/filecoin-project/lotus/storage/ctladdr" +) + +type SubmitCommitAPI interface { + ChainHead(context.Context) (*types.TipSet, error) + StateMinerInfo(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) + StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (big.Int, error) + StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) + ctladdr.NodeApi +} + +type SubmitCommitTask struct { + sp *SealPoller + db *harmonydb.DB + api SubmitCommitAPI + + sender *message.Sender + as *multictladdr.MultiAddressSelector + + maxFee types.FIL +} + +func NewSubmitCommitTask(sp *SealPoller, db *harmonydb.DB, api SubmitCommitAPI, sender *message.Sender, as *multictladdr.MultiAddressSelector, maxFee types.FIL) *SubmitCommitTask { + return &SubmitCommitTask{ + sp: sp, + db: db, + api: api, + sender: sender, + as: as, + + maxFee: maxFee, + } +} + +func (s *SubmitCommitTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + ctx := context.Background() + + var sectorParamsArr []struct { + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + Proof []byte `db:"porep_proof"` + } + + err = s.db.Select(ctx, §orParamsArr, ` + SELECT sp_id, sector_number, porep_proof + FROM sectors_sdr_pipeline + WHERE task_id_commit_msg = $1`, taskID) + if err != nil { + return false, xerrors.Errorf("getting sector params: %w", err) + } + + if len(sectorParamsArr) != 1 { + return false, xerrors.Errorf("expected 1 sector params, got %d", len(sectorParamsArr)) + } + sectorParams := sectorParamsArr[0] + + maddr, err := address.NewIDAddress(uint64(sectorParams.SpID)) + if err != nil { + return false, xerrors.Errorf("getting miner address: %w", err) + } + + params := miner.ProveCommitSectorParams{ + SectorNumber: abi.SectorNumber(sectorParams.SectorNumber), + Proof: sectorParams.Proof, + } + + enc := new(bytes.Buffer) + if err := params.MarshalCBOR(enc); err != nil { + return false, xerrors.Errorf("could not serialize commit params: %w", err) + } + + ts, err := s.api.ChainHead(ctx) + if err != nil { + return false, xerrors.Errorf("getting chain head: %w", err) + } + + mi, err := s.api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return false, xerrors.Errorf("getting miner info: %w", err) + } + + pci, err := s.api.StateSectorPreCommitInfo(ctx, maddr, abi.SectorNumber(sectorParams.SectorNumber), ts.Key()) + if err != nil { + return false, xerrors.Errorf("getting precommit info: %w", err) + } + if pci == nil { + return false, xerrors.Errorf("precommit info not found on chain") + } + + collateral, err := s.api.StateMinerInitialPledgeCollateral(ctx, maddr, pci.Info, ts.Key()) + if err != nil { + return false, xerrors.Errorf("getting initial pledge collateral: %w", err) + } + + collateral = big.Sub(collateral, pci.PreCommitDeposit) + if collateral.LessThan(big.Zero()) { + collateral = big.Zero() + } + + a, _, err := s.as.AddressFor(ctx, s.api, maddr, mi, api.CommitAddr, collateral, big.Zero()) + if err != nil { + return false, xerrors.Errorf("getting address for precommit: %w", err) + } + + msg := &types.Message{ + To: maddr, + From: a, + Method: builtin.MethodsMiner.ProveCommitSector, // todo ddo provecommit3 + Params: enc.Bytes(), + Value: collateral, // todo config for pulling from miner balance!! + } + + mss := &api.MessageSendSpec{ + MaxFee: abi.TokenAmount(s.maxFee), + } + + mcid, err := s.sender.Send(ctx, msg, mss, "commit") + if err != nil { + return false, xerrors.Errorf("pushing message to mpool: %w", err) + } + + _, err = s.db.Exec(ctx, `UPDATE sectors_sdr_pipeline SET commit_msg_cid = $1, after_commit_msg = TRUE WHERE sp_id = $2 AND sector_number = $3`, mcid, sectorParams.SpID, sectorParams.SectorNumber) + if err != nil { + return false, xerrors.Errorf("updating commit_msg_cid: %w", err) + } + + _, err = s.db.Exec(ctx, `INSERT INTO message_waits (signed_message_cid) VALUES ($1)`, mcid) + if err != nil { + return false, xerrors.Errorf("inserting into message_waits: %w", err) + } + + return true, nil +} + +func (s *SubmitCommitTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + id := ids[0] + return &id, nil +} + +func (s *SubmitCommitTask) TypeDetails() harmonytask.TaskTypeDetails { + return harmonytask.TaskTypeDetails{ + Max: 128, + Name: "CommitSubmit", + Cost: resources.Resources{ + Cpu: 0, + Gpu: 0, + Ram: 1 << 20, + }, + MaxFailures: 16, + } +} + +func (s *SubmitCommitTask) Adder(taskFunc harmonytask.AddTaskFunc) { + s.sp.pollers[pollerCommitMsg].Set(taskFunc) +} + +var _ harmonytask.TaskInterface = &SubmitCommitTask{} diff --git a/curiosrc/seal/task_submit_precommit.go b/curiosrc/seal/task_submit_precommit.go new file mode 100644 index 00000000000..d42bcbe0d6c --- /dev/null +++ b/curiosrc/seal/task_submit_precommit.go @@ -0,0 +1,300 @@ +package seal + +import ( + "bytes" + "context" + + "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" + "github.com/filecoin-project/go-state-types/builtin" + miner12 "github.com/filecoin-project/go-state-types/builtin/v12/miner" + "github.com/filecoin-project/go-state-types/network" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/actors/policy" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/curiosrc/message" + "github.com/filecoin-project/lotus/curiosrc/multictladdr" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + "github.com/filecoin-project/lotus/storage/ctladdr" +) + +type SubmitPrecommitTaskApi interface { + ChainHead(context.Context) (*types.TipSet, error) + StateMinerPreCommitDepositForPower(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (big.Int, error) + StateMinerInfo(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) + StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error) + ctladdr.NodeApi +} + +type SubmitPrecommitTask struct { + sp *SealPoller + db *harmonydb.DB + api SubmitPrecommitTaskApi + sender *message.Sender + as *multictladdr.MultiAddressSelector + + maxFee types.FIL +} + +func NewSubmitPrecommitTask(sp *SealPoller, db *harmonydb.DB, api SubmitPrecommitTaskApi, sender *message.Sender, as *multictladdr.MultiAddressSelector, maxFee types.FIL) *SubmitPrecommitTask { + return &SubmitPrecommitTask{ + sp: sp, + db: db, + api: api, + sender: sender, + as: as, + + maxFee: maxFee, + } +} + +func (s *SubmitPrecommitTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + ctx := context.Background() + + // 1. Load sector info + + var sectorParamsArr []struct { + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + RegSealProof abi.RegisteredSealProof `db:"reg_seal_proof"` + TicketEpoch abi.ChainEpoch `db:"ticket_epoch"` + SealedCID string `db:"tree_r_cid"` + UnsealedCID string `db:"tree_d_cid"` + } + + err = s.db.Select(ctx, §orParamsArr, ` + SELECT sp_id, sector_number, reg_seal_proof, ticket_epoch, tree_r_cid, tree_d_cid + FROM sectors_sdr_pipeline + WHERE task_id_precommit_msg = $1`, taskID) + if err != nil { + return false, xerrors.Errorf("getting sector params: %w", err) + } + + if len(sectorParamsArr) != 1 { + return false, xerrors.Errorf("expected 1 sector params, got %d", len(sectorParamsArr)) + } + sectorParams := sectorParamsArr[0] + + maddr, err := address.NewIDAddress(uint64(sectorParams.SpID)) + if err != nil { + return false, xerrors.Errorf("getting miner address: %w", err) + } + + sealedCID, err := cid.Parse(sectorParams.SealedCID) + if err != nil { + return false, xerrors.Errorf("parsing sealed CID: %w", err) + } + + unsealedCID, err := cid.Parse(sectorParams.UnsealedCID) + if err != nil { + return false, xerrors.Errorf("parsing unsealed CID: %w", err) + } + + // 2. Prepare message params + + head, err := s.api.ChainHead(ctx) + if err != nil { + return false, xerrors.Errorf("getting chain head: %w", err) + } + + params := miner.PreCommitSectorBatchParams2{} + + expiration := sectorParams.TicketEpoch + miner12.MaxSectorExpirationExtension + + params.Sectors = append(params.Sectors, miner.SectorPreCommitInfo{ + SealProof: sectorParams.RegSealProof, + SectorNumber: abi.SectorNumber(sectorParams.SectorNumber), + SealedCID: sealedCID, + SealRandEpoch: sectorParams.TicketEpoch, + Expiration: expiration, + }) + + { + var pieces []struct { + PieceIndex int64 `db:"piece_index"` + PieceCID string `db:"piece_cid"` + PieceSize int64 `db:"piece_size"` + + F05DealID int64 `db:"f05_deal_id"` + F05DealEndEpoch int64 `db:"f05_deal_end_epoch"` + F05DealStartEpoch int64 `db:"f05_deal_start_epoch"` + } + + err = s.db.Select(ctx, &pieces, ` + SELECT piece_index, piece_cid, piece_size, f05_deal_id, f05_deal_end_epoch, f05_deal_start_epoch + FROM sectors_sdr_initial_pieces + WHERE sp_id = $1 AND sector_number = $2 ORDER BY piece_index ASC`, sectorParams.SpID, sectorParams.SectorNumber) + if err != nil { + return false, xerrors.Errorf("getting pieces: %w", err) + } + + if len(pieces) > 1 { + return false, xerrors.Errorf("too many pieces") // todo support multiple pieces + } + + if len(pieces) > 0 { + params.Sectors[0].UnsealedCid = &unsealedCID + params.Sectors[0].Expiration = abi.ChainEpoch(pieces[0].F05DealEndEpoch) + + if abi.ChainEpoch(pieces[0].F05DealStartEpoch) < head.Height() { + // deal start epoch is in the past, can't precommit this sector anymore + _, perr := s.db.Exec(ctx, `UPDATE sectors_sdr_pipeline + SET failed = TRUE, failed_at = NOW(), failed_reason = 'past-start-epoch', failed_reason_msg = 'precommit: start epoch is in the past' + WHERE task_id_precommit_msg = $1`, taskID) + if perr != nil { + return false, xerrors.Errorf("persisting precommit start epoch expiry: %w", perr) + } + return true, xerrors.Errorf("deal start epoch is in the past") + } + + for _, p := range pieces { + params.Sectors[0].DealIDs = append(params.Sectors[0].DealIDs, abi.DealID(p.F05DealID)) + } + } + } + + nv, err := s.api.StateNetworkVersion(ctx, types.EmptyTSK) + if err != nil { + return false, xerrors.Errorf("getting network version: %w", err) + } + av, err := actorstypes.VersionForNetwork(nv) + if err != nil { + return false, xerrors.Errorf("failed to get actors version: %w", err) + } + msd, err := policy.GetMaxProveCommitDuration(av, sectorParams.RegSealProof) + if err != nil { + return false, xerrors.Errorf("failed to get max prove commit duration: %w", err) + } + + if minExpiration := sectorParams.TicketEpoch + policy.MaxPreCommitRandomnessLookback + msd + miner.MinSectorExpiration; params.Sectors[0].Expiration < minExpiration { + params.Sectors[0].Expiration = minExpiration + } + + // 3. Check precommit + + { + record, err := s.checkPrecommit(ctx, params) + if err != nil { + if record { + _, perr := s.db.Exec(ctx, `UPDATE sectors_sdr_pipeline + SET failed = TRUE, failed_at = NOW(), failed_reason = 'precommit-check', failed_reason_msg = $1 + WHERE task_id_precommit_msg = $2`, err.Error(), taskID) + if perr != nil { + return false, xerrors.Errorf("persisting precommit check error: %w", perr) + } + } + + return record, xerrors.Errorf("checking precommit: %w", err) + } + } + + // 4. Prepare and send message + + var pbuf bytes.Buffer + if err := params.MarshalCBOR(&pbuf); err != nil { + return false, xerrors.Errorf("serializing params: %w", err) + } + + collateral, err := s.api.StateMinerPreCommitDepositForPower(ctx, maddr, params.Sectors[0], types.EmptyTSK) + if err != nil { + return false, xerrors.Errorf("getting precommit deposit: %w", err) + } + + mi, err := s.api.StateMinerInfo(ctx, maddr, types.EmptyTSK) + if err != nil { + return false, xerrors.Errorf("getting miner info: %w", err) + } + + a, _, err := s.as.AddressFor(ctx, s.api, maddr, mi, api.PreCommitAddr, collateral, big.Zero()) + if err != nil { + return false, xerrors.Errorf("getting address for precommit: %w", err) + } + + msg := &types.Message{ + To: maddr, + From: a, + Method: builtin.MethodsMiner.PreCommitSectorBatch2, + Params: pbuf.Bytes(), + Value: collateral, // todo config for pulling from miner balance!! + } + + mss := &api.MessageSendSpec{ + MaxFee: abi.TokenAmount(s.maxFee), + } + + mcid, err := s.sender.Send(ctx, msg, mss, "precommit") + if err != nil { + return false, xerrors.Errorf("sending message: %w", err) + } + + // set precommit_msg_cid + _, err = s.db.Exec(ctx, `UPDATE sectors_sdr_pipeline + SET precommit_msg_cid = $1, after_precommit_msg = TRUE + WHERE task_id_precommit_msg = $2`, mcid, taskID) + if err != nil { + return false, xerrors.Errorf("updating precommit_msg_cid: %w", err) + } + + _, err = s.db.Exec(ctx, `INSERT INTO message_waits (signed_message_cid) VALUES ($1)`, mcid) + if err != nil { + return false, xerrors.Errorf("inserting into message_waits: %w", err) + } + + return true, nil +} + +func (s *SubmitPrecommitTask) checkPrecommit(ctx context.Context, params miner.PreCommitSectorBatchParams2) (record bool, err error) { + if len(params.Sectors) != 1 { + return false, xerrors.Errorf("expected 1 sector") + } + + preCommitInfo := params.Sectors[0] + + head, err := s.api.ChainHead(ctx) + if err != nil { + return false, xerrors.Errorf("getting chain head: %w", err) + } + height := head.Height() + + //never commit P2 message before, check ticket expiration + ticketEarliest := height - policy.MaxPreCommitRandomnessLookback + + if preCommitInfo.SealRandEpoch < ticketEarliest { + return true, xerrors.Errorf("ticket expired: seal height: %d, head: %d", preCommitInfo.SealRandEpoch+policy.SealRandomnessLookback, height) + } + + return true, nil +} + +func (s *SubmitPrecommitTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + id := ids[0] + return &id, nil +} + +func (s *SubmitPrecommitTask) TypeDetails() harmonytask.TaskTypeDetails { + return harmonytask.TaskTypeDetails{ + Max: 1024, + Name: "PreCommitSubmit", + Cost: resources.Resources{ + Cpu: 0, + Gpu: 0, + Ram: 1 << 20, + }, + MaxFailures: 16, + } +} + +func (s *SubmitPrecommitTask) Adder(taskFunc harmonytask.AddTaskFunc) { + s.sp.pollers[pollerPrecommitMsg].Set(taskFunc) +} + +var _ harmonytask.TaskInterface = &SubmitPrecommitTask{} diff --git a/curiosrc/seal/task_trees.go b/curiosrc/seal/task_trees.go new file mode 100644 index 00000000000..7994c354aad --- /dev/null +++ b/curiosrc/seal/task_trees.go @@ -0,0 +1,326 @@ +package seal + +import ( + "context" + "io" + "net/http" + "net/url" + "strconv" + + "github.com/ipfs/go-cid" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-commp-utils/nonffi" + "github.com/filecoin-project/go-commp-utils/zerocomm" + "github.com/filecoin-project/go-padreader" + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/curiosrc/ffi" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/harmony/harmonytask" + "github.com/filecoin-project/lotus/lib/harmony/resources" + "github.com/filecoin-project/lotus/storage/pipeline/lib/nullreader" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +type TreesTask struct { + sp *SealPoller + db *harmonydb.DB + sc *ffi.SealCalls + + max int +} + +func NewTreesTask(sp *SealPoller, db *harmonydb.DB, sc *ffi.SealCalls, maxTrees int) *TreesTask { + return &TreesTask{ + sp: sp, + db: db, + sc: sc, + + max: maxTrees, + } +} + +func (t *TreesTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + ctx := context.Background() + + var sectorParamsArr []struct { + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + RegSealProof abi.RegisteredSealProof `db:"reg_seal_proof"` + } + + err = t.db.Select(ctx, §orParamsArr, ` + SELECT sp_id, sector_number, reg_seal_proof + FROM sectors_sdr_pipeline + WHERE task_id_tree_r = $1 AND task_id_tree_c = $1 AND task_id_tree_d = $1`, taskID) + if err != nil { + return false, xerrors.Errorf("getting sector params: %w", err) + } + + if len(sectorParamsArr) != 1 { + return false, xerrors.Errorf("expected 1 sector params, got %d", len(sectorParamsArr)) + } + sectorParams := sectorParamsArr[0] + + var pieces []struct { + PieceIndex int64 `db:"piece_index"` + PieceCID string `db:"piece_cid"` + PieceSize int64 `db:"piece_size"` + + DataUrl *string `db:"data_url"` + DataHeaders *[]byte `db:"data_headers"` + DataRawSize *int64 `db:"data_raw_size"` + } + + err = t.db.Select(ctx, &pieces, ` + SELECT piece_index, piece_cid, piece_size, data_url, data_headers, data_raw_size + FROM sectors_sdr_initial_pieces + WHERE sp_id = $1 AND sector_number = $2 ORDER BY piece_index ASC`, sectorParams.SpID, sectorParams.SectorNumber) + if err != nil { + return false, xerrors.Errorf("getting pieces: %w", err) + } + + ssize, err := sectorParams.RegSealProof.SectorSize() + if err != nil { + return false, xerrors.Errorf("getting sector size: %w", err) + } + + var commd cid.Cid + var dataReader io.Reader + var unpaddedData bool + + var closers []io.Closer + defer func() { + for _, c := range closers { + if err := c.Close(); err != nil { + log.Errorw("error closing piece reader", "error", err) + } + } + }() + + if len(pieces) > 0 { + pieceInfos := make([]abi.PieceInfo, len(pieces)) + pieceReaders := make([]io.Reader, len(pieces)) + + for i, p := range pieces { + // make pieceInfo + c, err := cid.Parse(p.PieceCID) + if err != nil { + return false, xerrors.Errorf("parsing piece cid: %w", err) + } + + pieceInfos[i] = abi.PieceInfo{ + Size: abi.PaddedPieceSize(p.PieceSize), + PieceCID: c, + } + + // make pieceReader + if p.DataUrl != nil { + dataUrl := *p.DataUrl + + goUrl, err := url.Parse(dataUrl) + if err != nil { + return false, xerrors.Errorf("parsing data URL: %w", err) + } + + if goUrl.Scheme == "pieceref" { + // url is to a piece reference + + refNum, err := strconv.ParseInt(goUrl.Opaque, 10, 64) + if err != nil { + return false, xerrors.Errorf("parsing piece reference number: %w", err) + } + + // get pieceID + var pieceID []struct { + PieceID storiface.PieceNumber `db:"piece_id"` + } + err = t.db.Select(ctx, &pieceID, `SELECT piece_id FROM parked_piece_refs WHERE ref_id = $1`, refNum) + if err != nil { + return false, xerrors.Errorf("getting pieceID: %w", err) + } + + if len(pieceID) != 1 { + return false, xerrors.Errorf("expected 1 pieceID, got %d", len(pieceID)) + } + + pr, err := t.sc.PieceReader(ctx, pieceID[0].PieceID) + if err != nil { + return false, xerrors.Errorf("getting piece reader: %w", err) + } + + closers = append(closers, pr) + + pieceReaders[i], _ = padreader.New(pr, uint64(*p.DataRawSize)) + } else { + pieceReaders[i], _ = padreader.New(&UrlPieceReader{ + Url: dataUrl, + RawSize: *p.DataRawSize, + }, uint64(*p.DataRawSize)) + } + + } else { // padding piece (w/o fr32 padding, added in TreeD) + pieceReaders[i] = nullreader.NewNullReader(abi.PaddedPieceSize(p.PieceSize).Unpadded()) + } + } + + commd, err = nonffi.GenerateUnsealedCID(sectorParams.RegSealProof, pieceInfos) + if err != nil { + return false, xerrors.Errorf("computing CommD: %w", err) + } + + dataReader = io.MultiReader(pieceReaders...) + unpaddedData = true + } else { + commd = zerocomm.ZeroPieceCommitment(abi.PaddedPieceSize(ssize).Unpadded()) + dataReader = nullreader.NewNullReader(abi.UnpaddedPieceSize(ssize)) + unpaddedData = false // nullreader includes fr32 zero bits + } + + sref := storiface.SectorRef{ + ID: abi.SectorID{ + Miner: abi.ActorID(sectorParams.SpID), + Number: abi.SectorNumber(sectorParams.SectorNumber), + }, + ProofType: sectorParams.RegSealProof, + } + + // D / R / C + sealed, unsealed, err := t.sc.TreeDRC(ctx, &taskID, sref, commd, abi.PaddedPieceSize(ssize), dataReader, unpaddedData) + if err != nil { + return false, xerrors.Errorf("computing tree d, r and c: %w", err) + } + + // todo synth porep + + // todo porep challenge check + + n, err := t.db.Exec(ctx, `UPDATE sectors_sdr_pipeline + SET after_tree_r = true, after_tree_c = true, after_tree_d = true, tree_r_cid = $3, tree_d_cid = $4 + WHERE sp_id = $1 AND sector_number = $2`, + sectorParams.SpID, sectorParams.SectorNumber, sealed, unsealed) + if err != nil { + return false, xerrors.Errorf("store sdr-trees success: updating pipeline: %w", err) + } + if n != 1 { + return false, xerrors.Errorf("store sdr-trees success: updated %d rows", n) + } + + return true, nil +} + +func (t *TreesTask) CanAccept(ids []harmonytask.TaskID, engine *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + id := ids[0] + return &id, nil +} + +func (t *TreesTask) TypeDetails() harmonytask.TaskTypeDetails { + ssize := abi.SectorSize(32 << 30) // todo task details needs taskID to get correct sector size + if isDevnet { + ssize = abi.SectorSize(2 << 20) + } + + return harmonytask.TaskTypeDetails{ + Max: t.max, + Name: "SDRTrees", + Cost: resources.Resources{ + Cpu: 1, + Gpu: 1, + Ram: 8000 << 20, // todo + Storage: t.sc.Storage(t.taskToSector, storiface.FTSealed, storiface.FTCache, ssize, storiface.PathSealing), + }, + MaxFailures: 3, + Follows: nil, + } +} + +func (t *TreesTask) Adder(taskFunc harmonytask.AddTaskFunc) { + t.sp.pollers[pollerTrees].Set(taskFunc) +} + +func (t *TreesTask) taskToSector(id harmonytask.TaskID) (ffi.SectorRef, error) { + var refs []ffi.SectorRef + + err := t.db.Select(context.Background(), &refs, `SELECT sp_id, sector_number, reg_seal_proof FROM sectors_sdr_pipeline WHERE task_id_tree_r = $1`, id) + if err != nil { + return ffi.SectorRef{}, xerrors.Errorf("getting sector ref: %w", err) + } + + if len(refs) != 1 { + return ffi.SectorRef{}, xerrors.Errorf("expected 1 sector ref, got %d", len(refs)) + } + + return refs[0], nil +} + +type UrlPieceReader struct { + Url string + RawSize int64 // the exact number of bytes read, if we read more or less that's an error + + readSoFar int64 + closed bool + active io.ReadCloser // auto-closed on EOF +} + +func (u *UrlPieceReader) Read(p []byte) (n int, err error) { + // Check if we have already read the required amount of data + if u.readSoFar >= u.RawSize { + return 0, io.EOF + } + + // If 'active' is nil, initiate the HTTP request + if u.active == nil { + resp, err := http.Get(u.Url) + if err != nil { + return 0, err + } + + // Set 'active' to the response body + u.active = resp.Body + } + + // Calculate the maximum number of bytes we can read without exceeding RawSize + toRead := u.RawSize - u.readSoFar + if int64(len(p)) > toRead { + p = p[:toRead] + } + + n, err = u.active.Read(p) + + // Update the number of bytes read so far + u.readSoFar += int64(n) + + // If the number of bytes read exceeds RawSize, return an error + if u.readSoFar > u.RawSize { + return n, xerrors.New("read beyond the specified RawSize") + } + + // If EOF is reached, close the reader + if err == io.EOF { + cerr := u.active.Close() + u.closed = true + if cerr != nil { + log.Errorf("error closing http piece reader: %s", cerr) + } + + // if we're below the RawSize, return an unexpected EOF error + if u.readSoFar < u.RawSize { + log.Errorw("unexpected EOF", "readSoFar", u.readSoFar, "rawSize", u.RawSize, "url", u.Url) + return n, io.ErrUnexpectedEOF + } + } + + return n, err +} + +func (u *UrlPieceReader) Close() error { + if !u.closed { + u.closed = true + return u.active.Close() + } + + return nil +} + +var _ harmonytask.TaskInterface = &TreesTask{} diff --git a/curiosrc/seal/task_trees_test.go b/curiosrc/seal/task_trees_test.go new file mode 100644 index 00000000000..b65ddd4e858 --- /dev/null +++ b/curiosrc/seal/task_trees_test.go @@ -0,0 +1,74 @@ +package seal + +import ( + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" +) + +// TestUrlPieceReader_Read tests various scenarios of reading data from UrlPieceReader +func TestUrlPieceReader_Read(t *testing.T) { + // Create a test server + testData := "This is a test string." + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, err := io.WriteString(w, testData) + require.NoError(t, err) + })) + defer ts.Close() + + tests := []struct { + name string + rawSize int64 + expected string + expectError bool + expectEOF bool + }{ + {"ReadExact", int64(len(testData)), testData, false, true}, + {"ReadLess", 10, testData[:10], false, false}, + {"ReadMore", int64(len(testData)) + 10, "", true, false}, + } + + for _, tt := range tests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + reader := UrlPieceReader{ + Url: ts.URL, + RawSize: tt.rawSize, + } + buffer, err := io.ReadAll(&reader) + if err != nil { + if (err != io.EOF && !tt.expectError) || (err == io.EOF && !tt.expectEOF) { + t.Errorf("Read() error = %v, expectError %v, expectEOF %v", err, tt.expectError, tt.expectEOF) + } + } else { + if got := string(buffer); got != tt.expected { + t.Errorf("Read() got = %v, expected %v", got, tt.expected) + } + } + }) + } +} + +// TestUrlPieceReader_Read_Error tests the error handling of UrlPieceReader +func TestUrlPieceReader_Read_Error(t *testing.T) { + // Simulate a server that returns an error + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Error(w, "error", http.StatusInternalServerError) + })) + defer ts.Close() + + reader := UrlPieceReader{ + Url: ts.URL, + RawSize: 100, + } + buffer := make([]byte, 200) + + _, err := reader.Read(buffer) + if err == nil { + t.Errorf("Expected an error, but got nil") + } +} diff --git a/curiosrc/web/api/apihelper/apihelper.go b/curiosrc/web/api/apihelper/apihelper.go new file mode 100644 index 00000000000..07c7898e86d --- /dev/null +++ b/curiosrc/web/api/apihelper/apihelper.go @@ -0,0 +1,19 @@ +package apihelper + +import ( + "net/http" + "runtime/debug" + + logging "github.com/ipfs/go-log/v2" +) + +var log = logging.Logger("lp/web/apihelper") + +func OrHTTPFail(w http.ResponseWriter, err error) { + if err != nil { + w.WriteHeader(500) + _, _ = w.Write([]byte(err.Error())) + log.Errorw("http fail", "err", err, "stack", string(debug.Stack())) + panic(err) + } +} diff --git a/curiosrc/web/api/config/config.go b/curiosrc/web/api/config/config.go new file mode 100644 index 00000000000..6f9598f7fad --- /dev/null +++ b/curiosrc/web/api/config/config.go @@ -0,0 +1,179 @@ +package config + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "reflect" + "time" + + "github.com/BurntSushi/toml" + "github.com/gorilla/mux" + "github.com/invopop/jsonschema" + + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/curiosrc/web/api/apihelper" + "github.com/filecoin-project/lotus/node/config" +) + +type cfg struct { + *deps.Deps +} + +func Routes(r *mux.Router, deps *deps.Deps) { + c := &cfg{deps} + // At menu.html: + r.Methods("GET").Path("/layers").HandlerFunc(c.getLayers) + r.Methods("GET").Path("/topo").HandlerFunc(c.topo) + + // At edit.html: + r.Methods("GET").Path("/schema").HandlerFunc(getSch) + r.Methods("GET").Path("/layers/{layer}").HandlerFunc(c.getLayer) + r.Methods("POST").Path("/layers/{layer}").HandlerFunc(c.setLayer) + r.Methods("GET").Path("/default").HandlerFunc(c.def) +} +func getSch(w http.ResponseWriter, r *http.Request) { + ref := jsonschema.Reflector{ + Mapper: func(i reflect.Type) *jsonschema.Schema { + if i == reflect.TypeOf(config.Duration(time.Second)) { + return &jsonschema.Schema{ + Type: "string", + Format: "duration", + } + } + return nil + }, + } + sch := ref.Reflect(config.CurioConfig{}) + // add comments + for k, doc := range config.Doc { + item, ok := sch.Definitions[k] + if !ok { + continue + } + for _, line := range doc { + item, ok := item.Properties.Get(line.Name) + if !ok { + continue + } + if line.Comment != "" { + extra := make(map[string]any) + type options struct { + InfoText string `json:"infoText"` + } + opt := options{ + InfoText: line.Comment, + } + extra["options"] = opt + item.Extras = extra + } + } + } + + var allOpt func(s *jsonschema.Schema) + allOpt = func(s *jsonschema.Schema) { + s.Required = []string{} + for _, v := range s.Definitions { + v.Required = []string{} + + allOpt(v) + } + } + allOpt(sch) + + apihelper.OrHTTPFail(w, json.NewEncoder(w).Encode(sch)) +} + +func (c *cfg) getLayers(w http.ResponseWriter, r *http.Request) { + var layers []string + apihelper.OrHTTPFail(w, c.DB.Select(context.Background(), &layers, `SELECT title FROM harmony_config ORDER BY title`)) + apihelper.OrHTTPFail(w, json.NewEncoder(w).Encode(layers)) +} + +func (c *cfg) getLayer(w http.ResponseWriter, r *http.Request) { + var layer string + apihelper.OrHTTPFail(w, c.DB.QueryRow(context.Background(), `SELECT config FROM harmony_config WHERE title = $1`, mux.Vars(r)["layer"]).Scan(&layer)) + + // Read the TOML into a struct + configStruct := map[string]any{} // NOT CurioConfig b/c we want to preserve unsets + _, err := toml.Decode(layer, &configStruct) + apihelper.OrHTTPFail(w, err) + + // Encode the struct as JSON + jsonData, err := json.Marshal(configStruct) + apihelper.OrHTTPFail(w, err) + + // Write the JSON response + w.Header().Set("Content-Type", "application/json") + _, err = w.Write(jsonData) + apihelper.OrHTTPFail(w, err) +} + +func (c *cfg) setLayer(w http.ResponseWriter, r *http.Request) { + layer := mux.Vars(r)["layer"] + var configStruct map[string]any + dec := json.NewDecoder(r.Body) + dec.UseNumber() // JSON lib by default treats number is float64() + apihelper.OrHTTPFail(w, dec.Decode(&configStruct)) + + //Encode the struct as TOML + var tomlData bytes.Buffer + err := toml.NewEncoder(&tomlData).Encode(configStruct) + apihelper.OrHTTPFail(w, err) + + configStr := tomlData.String() + + // Generate a full commented string if this is base layer + if layer == "base" { + // Parse the into CurioConfig TOML + curioCfg := config.DefaultCurioConfig() + _, err = deps.LoadConfigWithUpgrades(tomlData.String(), curioCfg) + apihelper.OrHTTPFail(w, err) + cb, err := config.ConfigUpdate(curioCfg, config.DefaultCurioConfig(), config.Commented(true), config.DefaultKeepUncommented(), config.NoEnv()) + apihelper.OrHTTPFail(w, err) + configStr = string(cb) + } + + //Write the TOML to the database + _, err = c.DB.Exec(context.Background(), `INSERT INTO harmony_config (title, config) VALUES ($1, $2) ON CONFLICT (title) DO UPDATE SET config = $2`, layer, configStr) + apihelper.OrHTTPFail(w, err) +} + +func (c *cfg) topo(w http.ResponseWriter, r *http.Request) { + var topology []struct { + Server string `db:"server"` + CPU int `db:"cpu"` + GPU int `db:"gpu"` + RAM int `db:"ram"` + LayersCSV string `db:"layers"` + TasksCSV string `db:"tasks"` + } + apihelper.OrHTTPFail(w, c.DB.Select(context.Background(), &topology, ` + SELECT + m.host_and_port as server, + cpu, gpu, ram, layers, tasks + FROM harmony_machines m JOIN harmony_machine_details d ON m.id=d.machine_id + ORDER BY server`)) + w.Header().Set("Content-Type", "application/json") + apihelper.OrHTTPFail(w, json.NewEncoder(w).Encode(topology)) +} + +func (c *cfg) def(w http.ResponseWriter, r *http.Request) { + cb, err := config.ConfigUpdate(config.DefaultCurioConfig(), nil, config.Commented(false), config.DefaultKeepUncommented(), config.NoEnv()) + apihelper.OrHTTPFail(w, err) + + // Read the TOML into a struct + configStruct := map[string]any{} // NOT CurioConfig b/c we want to preserve unsets + _, err = toml.Decode(string(cb), &configStruct) + apihelper.OrHTTPFail(w, err) + + // Encode the struct as JSON + jsonData, err := json.Marshal(configStruct) + apihelper.OrHTTPFail(w, err) + + // Write the JSON response + w.Header().Set("Content-Type", "application/json") + _, err = w.Write(jsonData) + apihelper.OrHTTPFail(w, err) +} diff --git a/curiosrc/web/api/debug/debug.go b/curiosrc/web/api/debug/debug.go new file mode 100644 index 00000000000..c0e89ab8e29 --- /dev/null +++ b/curiosrc/web/api/debug/debug.go @@ -0,0 +1,229 @@ +// Package debug provides the API for various debug endpoints in curio. +package debug + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "sort" + "sync" + "time" + + "github.com/BurntSushi/toml" + "github.com/gorilla/mux" + logging "github.com/ipfs/go-log/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/lotus/build" + cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/cmd/curio/deps" +) + +var log = logging.Logger("curio/web/debug") + +type debug struct { + *deps.Deps +} + +func Routes(r *mux.Router, deps *deps.Deps) { + d := debug{deps} + r.HandleFunc("/chain-state-sse", d.chainStateSSE) +} + +type rpcInfo struct { + Address string + CLayers []string + Reachable bool + SyncState string + Version string +} + +func (d *debug) chainStateSSE(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + w.Header().Set("Content-Type", "text/event-stream") + w.Header().Set("Cache-Control", "no-cache") + w.Header().Set("Connection", "keep-alive") + + ctx := r.Context() + + for { + + type minimalApiInfo struct { + Apis struct { + ChainApiInfo []string + } + } + + rpcInfos := map[string]minimalApiInfo{} // config name -> api info + confNameToAddr := map[string]string{} // config name -> api address + + err := forEachConfig[minimalApiInfo](d, func(name string, info minimalApiInfo) error { + if len(info.Apis.ChainApiInfo) == 0 { + return nil + } + + rpcInfos[name] = info + + for _, addr := range info.Apis.ChainApiInfo { + ai := cliutil.ParseApiInfo(addr) + confNameToAddr[name] = ai.Addr + } + + return nil + }) + if err != nil { + log.Errorw("getting api info", "error", err) + return + } + + dedup := map[string]bool{} // for dedup by address + + infos := map[string]rpcInfo{} // api address -> rpc info + var infosLk sync.Mutex + + var wg sync.WaitGroup + for _, info := range rpcInfos { + ai := cliutil.ParseApiInfo(info.Apis.ChainApiInfo[0]) + if dedup[ai.Addr] { + continue + } + dedup[ai.Addr] = true + wg.Add(1) + go func() { + defer wg.Done() + var clayers []string + for layer, a := range confNameToAddr { + if a == ai.Addr { + clayers = append(clayers, layer) + } + } + + myinfo := rpcInfo{ + Address: ai.Addr, + Reachable: false, + CLayers: clayers, + } + defer func() { + infosLk.Lock() + defer infosLk.Unlock() + infos[ai.Addr] = myinfo + }() + da, err := ai.DialArgs("v1") + if err != nil { + log.Warnw("DialArgs", "error", err) + return + } + + ah := ai.AuthHeader() + + v1api, closer, err := client.NewFullNodeRPCV1(ctx, da, ah) + if err != nil { + log.Warnf("Not able to establish connection to node with addr: %s", ai.Addr) + return + } + defer closer() + + ver, err := v1api.Version(ctx) + if err != nil { + log.Warnw("Version", "error", err) + return + } + + head, err := v1api.ChainHead(ctx) + if err != nil { + log.Warnw("ChainHead", "error", err) + return + } + + var syncState string + switch { + case time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs*3/2): // within 1.5 epochs + syncState = "ok" + case time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs*5): // within 5 epochs + syncState = fmt.Sprintf("slow (%s behind)", time.Since(time.Unix(int64(head.MinTimestamp()), 0)).Truncate(time.Second)) + default: + syncState = fmt.Sprintf("behind (%s behind)", time.Since(time.Unix(int64(head.MinTimestamp()), 0)).Truncate(time.Second)) + } + + myinfo = rpcInfo{ + Address: ai.Addr, + CLayers: clayers, + Reachable: true, + Version: ver.Version, + SyncState: syncState, + } + }() + } + wg.Wait() + + var infoList []rpcInfo + for _, i := range infos { + infoList = append(infoList, i) + } + sort.Slice(infoList, func(i, j int) bool { + return infoList[i].Address < infoList[j].Address + }) + + fmt.Fprintf(w, "data: ") + err = json.NewEncoder(w).Encode(&infoList) + if err != nil { + log.Warnw("json encode", "error", err) + return + } + fmt.Fprintf(w, "\n\n") + if f, ok := w.(http.Flusher); ok { + f.Flush() + } + + time.Sleep(time.Duration(build.BlockDelaySecs) * time.Second) + + select { // stop running if there is reader. + case <-ctx.Done(): + return + default: + } + } +} + +func forEachConfig[T any](a *debug, cb func(name string, v T) error) error { + confs, err := a.loadConfigs(context.Background()) + if err != nil { + return err + } + + for name, tomlStr := range confs { // todo for-each-config + var info T + if err := toml.Unmarshal([]byte(tomlStr), &info); err != nil { + return xerrors.Errorf("unmarshaling %s config: %w", name, err) + } + + if err := cb(name, info); err != nil { + return xerrors.Errorf("cb: %w", err) + } + } + + return nil +} + +func (d *debug) loadConfigs(ctx context.Context) (map[string]string, error) { + //err := db.QueryRow(cctx.Context, `SELECT config FROM harmony_config WHERE title=$1`, layer).Scan(&text) + + rows, err := d.DB.Query(ctx, `SELECT title, config FROM harmony_config`) + if err != nil { + return nil, xerrors.Errorf("getting db configs: %w", err) + } + + configs := make(map[string]string) + for rows.Next() { + var title, config string + if err := rows.Scan(&title, &config); err != nil { + return nil, xerrors.Errorf("scanning db configs: %w", err) + } + configs[title] = config + } + + return configs, nil +} diff --git a/curiosrc/web/api/routes.go b/curiosrc/web/api/routes.go new file mode 100644 index 00000000000..cf56257ee92 --- /dev/null +++ b/curiosrc/web/api/routes.go @@ -0,0 +1,17 @@ +// Package api provides the HTTP API for the lotus curio web gui. +package api + +import ( + "github.com/gorilla/mux" + + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/curiosrc/web/api/config" + "github.com/filecoin-project/lotus/curiosrc/web/api/debug" + "github.com/filecoin-project/lotus/curiosrc/web/api/sector" +) + +func Routes(r *mux.Router, deps *deps.Deps) { + debug.Routes(r.PathPrefix("/debug").Subrouter(), deps) + config.Routes(r.PathPrefix("/config").Subrouter(), deps) + sector.Routes(r.PathPrefix("/sector").Subrouter(), deps) +} diff --git a/curiosrc/web/api/sector/sector.go b/curiosrc/web/api/sector/sector.go new file mode 100644 index 00000000000..e3b4b3c158d --- /dev/null +++ b/curiosrc/web/api/sector/sector.go @@ -0,0 +1,378 @@ +package sector + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "sync" + "time" + + "github.com/docker/go-units" + "github.com/gorilla/mux" + "github.com/samber/lo" + + "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/big" + "github.com/filecoin-project/go-state-types/builtin/v9/market" + + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/cli/spcli" + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/curiosrc/web/api/apihelper" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +const verifiedPowerGainMul = 9 + +type cfg struct { + *deps.Deps +} + +func Routes(r *mux.Router, deps *deps.Deps) { + c := &cfg{deps} + // At menu.html: + r.Methods("GET").Path("/all").HandlerFunc(c.getSectors) + r.Methods("POST").Path("/terminate").HandlerFunc(c.terminateSectors) +} + +func (c *cfg) terminateSectors(w http.ResponseWriter, r *http.Request) { + var in []struct { + MinerID int + Sector int + } + apihelper.OrHTTPFail(w, json.NewDecoder(r.Body).Decode(&in)) + toDel := map[int][]int{} + for _, s := range in { + toDel[s.MinerID] = append(toDel[s.MinerID], s.Sector) + } + + for minerInt, sectors := range toDel { + maddr, err := address.NewIDAddress(uint64(minerInt)) + apihelper.OrHTTPFail(w, err) + mi, err := c.Full.StateMinerInfo(r.Context(), maddr, types.EmptyTSK) + apihelper.OrHTTPFail(w, err) + _, err = spcli.TerminateSectors(r.Context(), c.Full, maddr, sectors, mi.Worker) + apihelper.OrHTTPFail(w, err) + for _, sectorNumber := range sectors { + id := abi.SectorID{Miner: abi.ActorID(minerInt), Number: abi.SectorNumber(sectorNumber)} + apihelper.OrHTTPFail(w, c.Stor.Remove(r.Context(), id, storiface.FTAll, true, nil)) + } + } +} + +func (c *cfg) getSectors(w http.ResponseWriter, r *http.Request) { + // TODO get sector info from chain and from database, then fold them together + // and return the result. + type sector struct { + MinerID int64 `db:"miner_id"` + SectorNum int64 `db:"sector_num"` + SectorFiletype int `db:"sector_filetype" json:"-"` // Useless? + HasSealed bool + HasUnsealed bool + HasSnap bool + ExpiresAt abi.ChainEpoch // map to Duration + IsOnChain bool + IsFilPlus bool + SealInfo string + Proving bool + Flag bool + DealWeight string + Deals string + //StorageID string `db:"storage_id"` // map to serverName + // Activation abi.ChainEpoch // map to time.Time. advanced view only + // DealIDs []abi.DealID // advanced view only + //ExpectedDayReward abi.TokenAmount + //SealProof abi.RegisteredSealProof + } + + type piece struct { + Size int64 `db:"piece_size"` + DealID uint64 `db:"f05_deal_id"` + Proposal json.RawMessage `db:"f05_deal_proposal"` + Manifest json.RawMessage `db:"direct_piece_activation_manifest"` + Miner int64 `db:"sp_id"` + Sector int64 `db:"sector_number"` + } + var sectors []sector + var pieces []piece + apihelper.OrHTTPFail(w, c.DB.Select(r.Context(), §ors, `SELECT + miner_id, sector_num, SUM(sector_filetype) as sector_filetype + FROM sector_location WHERE sector_filetype != 32 + GROUP BY miner_id, sector_num + ORDER BY miner_id, sector_num`)) + minerToAddr := map[int64]address.Address{} + head, err := c.Full.ChainHead(r.Context()) + apihelper.OrHTTPFail(w, err) + + type sectorID struct { + mID int64 + sNum uint64 + } + sectorIdx := map[sectorID]int{} + for i, s := range sectors { + sectors[i].HasSealed = s.SectorFiletype&int(storiface.FTSealed) != 0 || s.SectorFiletype&int(storiface.FTUpdate) != 0 + sectors[i].HasUnsealed = s.SectorFiletype&int(storiface.FTUnsealed) != 0 + sectors[i].HasSnap = s.SectorFiletype&int(storiface.FTUpdate) != 0 + sectorIdx[sectorID{s.MinerID, uint64(s.SectorNum)}] = i + if _, ok := minerToAddr[s.MinerID]; !ok { + minerToAddr[s.MinerID], err = address.NewIDAddress(uint64(s.MinerID)) + apihelper.OrHTTPFail(w, err) + } + } + + // Get all pieces + apihelper.OrHTTPFail(w, c.DB.Select(r.Context(), &pieces, `SELECT + sp_id, sector_number, piece_size, f05_deal_id, f05_deal_proposal, direct_piece_activation_manifest + FROM sectors_sdr_initial_pieces + ORDER BY sp_id, sector_number`)) + pieceIndex := map[sectorID][]int{} + for i, piece := range pieces { + piece := piece + cur := pieceIndex[sectorID{mID: piece.Miner, sNum: uint64(piece.Sector)}] + pieceIndex[sectorID{mID: piece.Miner, sNum: uint64(piece.Sector)}] = append(cur, i) + } + + for minerID, maddr := range minerToAddr { + onChainInfo, err := c.getCachedSectorInfo(w, r, maddr, head.Key()) + apihelper.OrHTTPFail(w, err) + for _, chainy := range onChainInfo { + st := chainy.onChain + if i, ok := sectorIdx[sectorID{minerID, uint64(st.SectorNumber)}]; ok { + sectors[i].IsOnChain = true + sectors[i].ExpiresAt = st.Expiration + sectors[i].IsFilPlus = st.VerifiedDealWeight.GreaterThan(st.DealWeight) + if ss, err := st.SealProof.SectorSize(); err == nil { + sectors[i].SealInfo = ss.ShortString() + } + sectors[i].Proving = chainy.active + if st.Expiration < head.Height() { + sectors[i].Flag = true // Flag expired sectors + } + + dw, vp := .0, .0 + f05, ddo := 0, 0 + var pi []piece + if j, ok := pieceIndex[sectorID{sectors[i].MinerID, uint64(sectors[i].SectorNum)}]; ok { + for _, k := range j { + pi = append(pi, pieces[k]) + } + } + estimate := st.Expiration-st.Activation <= 0 || sectors[i].HasSnap + if estimate { + for _, p := range pi { + if p.Proposal != nil { + var prop *market.DealProposal + apihelper.OrHTTPFail(w, json.Unmarshal(p.Proposal, &prop)) + dw += float64(prop.PieceSize) + if prop.VerifiedDeal { + vp += float64(prop.PieceSize) * verifiedPowerGainMul + } + f05++ + } + if p.Manifest != nil { + var pam *miner.PieceActivationManifest + apihelper.OrHTTPFail(w, json.Unmarshal(p.Manifest, &pam)) + dw += float64(pam.Size) + if pam.VerifiedAllocationKey != nil { + vp += float64(pam.Size) * verifiedPowerGainMul + } + ddo++ + } + } + } else { + rdw := big.Add(st.DealWeight, st.VerifiedDealWeight) + dw = float64(big.Div(rdw, big.NewInt(int64(st.Expiration-st.Activation))).Uint64()) + vp = float64(big.Div(big.Mul(st.VerifiedDealWeight, big.NewInt(verifiedPowerGainMul)), big.NewInt(int64(st.Expiration-st.Activation))).Uint64()) + for _, deal := range st.DealIDs { + + if deal > 0 { + f05++ + } + } + // DDO info is not on chain + for _, piece := range pieces { + if piece.Manifest != nil { + //var pam *miner.PieceActivationManifest + //apihelper.OrHTTPFail(w, json.Unmarshal(piece.Manifest, pam)) + //dw += float64(pam.Size) + //if pam.VerifiedAllocationKey != nil { + // vp += float64(pam.Size) * verifiedPowerGainMul + //} + ddo++ + } + } + } + sectors[i].DealWeight = "CC" + if dw > 0 { + sectors[i].DealWeight = fmt.Sprintf("%s", units.BytesSize(dw)) + } + if vp > 0 { + sectors[i].DealWeight = fmt.Sprintf("%s", units.BytesSize(vp)) + } + sectors[i].Deals = fmt.Sprintf("Market: %d, DDO: %d", f05, ddo) + } else { + // sector is on chain but not in db + s := sector{ + MinerID: minerID, + SectorNum: int64(chainy.onChain.SectorNumber), + IsOnChain: true, + ExpiresAt: chainy.onChain.Expiration, + IsFilPlus: chainy.onChain.VerifiedDealWeight.GreaterThan(chainy.onChain.DealWeight), + Proving: chainy.active, + Flag: true, // All such sectors should be flagged to be terminated + } + if ss, err := chainy.onChain.SealProof.SectorSize(); err == nil { + s.SealInfo = ss.ShortString() + } + sectors = append(sectors, s) + } + /* + info, err := c.Full.StateSectorGetInfo(r.Context(), minerToAddr[s], abi.SectorNumber(uint64(sectors[i].SectorNum)), headKey) + if err != nil { + sectors[i].IsValid = false + continue + }*/ + } + } + + // Add deal details to sectors which are not on chain + for i := range sectors { + if !sectors[i].IsOnChain { + var pi []piece + dw, vp := .0, .0 + f05, ddo := 0, 0 + + // Find if there are any deals for this sector + if j, ok := pieceIndex[sectorID{sectors[i].MinerID, uint64(sectors[i].SectorNum)}]; ok { + for _, k := range j { + pi = append(pi, pieces[k]) + } + } + + if len(pi) > 0 { + for _, piece := range pi { + if piece.Proposal != nil { + var prop *market.DealProposal + apihelper.OrHTTPFail(w, json.Unmarshal(piece.Proposal, &prop)) + dw += float64(prop.PieceSize) + if prop.VerifiedDeal { + vp += float64(prop.PieceSize) * verifiedPowerGainMul + } + f05++ + } + if piece.Manifest != nil { + var pam *miner.PieceActivationManifest + apihelper.OrHTTPFail(w, json.Unmarshal(piece.Manifest, &pam)) + dw += float64(pam.Size) + if pam.VerifiedAllocationKey != nil { + vp += float64(pam.Size) * verifiedPowerGainMul + } + ddo++ + } + } + } + if dw > 0 { + sectors[i].DealWeight = fmt.Sprintf("%s", units.BytesSize(dw)) + } else if vp > 0 { + sectors[i].DealWeight = fmt.Sprintf("%s", units.BytesSize(vp)) + } else { + sectors[i].DealWeight = "CC" + } + sectors[i].Deals = fmt.Sprintf("Market: %d, DDO: %d", f05, ddo) + } + } + apihelper.OrHTTPFail(w, json.NewEncoder(w).Encode(map[string]any{"data": sectors})) +} + +type sectorInfo struct { + onChain *miner.SectorOnChainInfo + active bool +} + +type sectorCacheEntry struct { + sectors []sectorInfo + loading chan struct{} + time.Time +} + +const cacheTimeout = 30 * time.Minute + +var mx sync.Mutex +var sectorInfoCache = map[address.Address]sectorCacheEntry{} + +// getCachedSectorInfo returns the sector info for the given miner address, +// either from the cache or by querying the chain. +// Cache can be invalidated by setting the "sector_refresh" cookie to "true". +// This is thread-safe. +// Parallel requests share the chain's first response. +func (c *cfg) getCachedSectorInfo(w http.ResponseWriter, r *http.Request, maddr address.Address, headKey types.TipSetKey) ([]sectorInfo, error) { + mx.Lock() + v, ok := sectorInfoCache[maddr] + mx.Unlock() + + if ok && v.loading != nil { + <-v.loading + mx.Lock() + v, ok = sectorInfoCache[maddr] + mx.Unlock() + } + + shouldRefreshCookie, found := lo.Find(r.Cookies(), func(item *http.Cookie) bool { return item.Name == "sector_refresh" }) + shouldRefresh := found && shouldRefreshCookie.Value == "true" + w.Header().Set("Set-Cookie", "sector_refresh=; Max-Age=0; Path=/") + + if !ok || time.Since(v.Time) > cacheTimeout || shouldRefresh { + v = sectorCacheEntry{nil, make(chan struct{}), time.Now()} + mx.Lock() + sectorInfoCache[maddr] = v + mx.Unlock() + + // Intentionally not using the context from the request, as this is a cache + onChainInfo, err := c.Full.StateMinerSectors(context.Background(), maddr, nil, headKey) + if err != nil { + mx.Lock() + delete(sectorInfoCache, maddr) + close(v.loading) + mx.Unlock() + return nil, err + } + active, err := c.Full.StateMinerActiveSectors(context.Background(), maddr, headKey) + if err != nil { + mx.Lock() + delete(sectorInfoCache, maddr) + close(v.loading) + mx.Unlock() + return nil, err + } + activebf := bitfield.New() + for i := range active { + activebf.Set(uint64(active[i].SectorNumber)) + } + infos := make([]sectorInfo, len(onChainInfo)) + for i, info := range onChainInfo { + info := info + set, err := activebf.IsSet(uint64(info.SectorNumber)) + if err != nil { + mx.Lock() + delete(sectorInfoCache, maddr) + close(v.loading) + mx.Unlock() + return nil, err + } + infos[i] = sectorInfo{ + onChain: info, + active: set, + } + } + mx.Lock() + sectorInfoCache[maddr] = sectorCacheEntry{infos, nil, time.Now()} + close(v.loading) + mx.Unlock() + return infos, nil + } + return v.sectors, nil +} diff --git a/curiosrc/web/hapi/robust_rpc.go b/curiosrc/web/hapi/robust_rpc.go new file mode 100644 index 00000000000..c10b43a03f3 --- /dev/null +++ b/curiosrc/web/hapi/robust_rpc.go @@ -0,0 +1,102 @@ +package hapi + +import ( + "context" + "time" + + lru "github.com/hashicorp/golang-lru/v2" + blocks "github.com/ipfs/go-block-format" + + "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/chain/store" + cliutil "github.com/filecoin-project/lotus/cli/util" + "github.com/filecoin-project/lotus/lib/must" +) + +var ChainBlockCache = must.One(lru.New[blockstore.MhString, blocks.Block](4096)) + +func (a *app) watchRpc() { + ticker := time.NewTicker(watchInterval) + for { + err := a.updateRpc(context.TODO()) + if err != nil { + log.Errorw("updating rpc info", "error", err) + } + select { + case <-ticker.C: + } + } +} + +type minimalApiInfo struct { + Apis struct { + ChainApiInfo []string + } +} + +func (a *app) updateRpc(ctx context.Context) error { + rpcInfos := map[string]minimalApiInfo{} // config name -> api info + confNameToAddr := map[string]string{} // config name -> api address + + err := forEachConfig[minimalApiInfo](a, func(name string, info minimalApiInfo) error { + if len(info.Apis.ChainApiInfo) == 0 { + return nil + } + + rpcInfos[name] = info + + for _, addr := range info.Apis.ChainApiInfo { + ai := cliutil.ParseApiInfo(addr) + confNameToAddr[name] = ai.Addr + } + + return nil + }) + if err != nil { + return err + } + + apiInfos := map[string][]byte{} // api address -> token + + // for dedup by address + for _, info := range rpcInfos { + ai := cliutil.ParseApiInfo(info.Apis.ChainApiInfo[0]) + apiInfos[ai.Addr] = ai.Token + } + + a.rpcInfoLk.Lock() + + // todo improve this shared rpc logic + if a.workingApi == nil { + for addr, token := range apiInfos { + ai := cliutil.APIInfo{ + Addr: addr, + Token: token, + } + + da, err := ai.DialArgs("v1") + if err != nil { + continue + } + + ah := ai.AuthHeader() + + v1api, closer, err := client.NewFullNodeRPCV1(ctx, da, ah) + if err != nil { + continue + } + go func() { + <-ctx.Done() + closer() + }() + + a.workingApi = v1api + a.stor = store.ActorStore(ctx, blockstore.NewReadCachedBlockstore(blockstore.NewAPIBlockstore(a.workingApi), ChainBlockCache)) + } + } + + a.rpcInfoLk.Unlock() + + return nil +} diff --git a/curiosrc/web/hapi/routes.go b/curiosrc/web/hapi/routes.go new file mode 100644 index 00000000000..61724ec0ae5 --- /dev/null +++ b/curiosrc/web/hapi/routes.go @@ -0,0 +1,58 @@ +package hapi + +import ( + "embed" + "text/template" + + "github.com/gorilla/mux" + logging "github.com/ipfs/go-log/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/cmd/curio/deps" +) + +//go:embed web/* +var templateFS embed.FS + +func Routes(r *mux.Router, deps *deps.Deps) error { + t, err := makeTemplate().ParseFS(templateFS, "web/*") + if err != nil { + return xerrors.Errorf("parse templates: %w", err) + } + + a := &app{ + db: deps.DB, + t: t, + } + + go a.watchRpc() + go a.watchActor() + + // index page (simple info) + r.HandleFunc("/simpleinfo/actorsummary", a.actorSummary) + r.HandleFunc("/simpleinfo/machines", a.indexMachines) + r.HandleFunc("/simpleinfo/tasks", a.indexTasks) + r.HandleFunc("/simpleinfo/taskhistory", a.indexTasksHistory) + r.HandleFunc("/simpleinfo/pipeline-porep", a.indexPipelinePorep) + + // pipeline-porep page + r.HandleFunc("/pipeline-porep/sectors", a.pipelinePorepSectors) + + // node info page + r.HandleFunc("/node/{id}", a.nodeInfo) + + // sector info page + r.HandleFunc("/sector/{sp}/{id}", a.sectorInfo) + return nil +} + +func makeTemplate() *template.Template { + return template.New("").Funcs(template.FuncMap{ + "toHumanBytes": func(b int64) string { + return types.SizeStr(types.NewInt(uint64(b))) + }, + }) +} + +var log = logging.Logger("curio/web") diff --git a/curiosrc/web/hapi/simpleinfo.go b/curiosrc/web/hapi/simpleinfo.go new file mode 100644 index 00000000000..287e11233fd --- /dev/null +++ b/curiosrc/web/hapi/simpleinfo.go @@ -0,0 +1,857 @@ +package hapi + +import ( + "bytes" + "context" + "fmt" + "net/http" + "os" + "sort" + "strconv" + "strings" + "sync" + "text/template" + "time" + + "github.com/gorilla/mux" + "github.com/samber/lo" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/api/v1api" + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/must" + "github.com/filecoin-project/lotus/storage/paths" + "github.com/filecoin-project/lotus/storage/sealer/storiface" +) + +type app struct { + db *harmonydb.DB + t *template.Template + + rpcInfoLk sync.Mutex + workingApi v1api.FullNode + stor adt.Store + + actorInfoLk sync.Mutex + actorInfos []actorInfo +} + +type actorInfo struct { + Address string + CLayers []string + + QualityAdjustedPower string + RawBytePower string + + ActorBalance, ActorAvailable, WorkerBalance string + + Win1, Win7, Win30 int64 + + Deadlines []actorDeadline +} + +type actorDeadline struct { + Empty bool + Current bool + Proven bool + PartFaulty bool + Faulty bool +} + +func (a *app) actorSummary(w http.ResponseWriter, r *http.Request) { + a.actorInfoLk.Lock() + defer a.actorInfoLk.Unlock() + + a.executeTemplate(w, "actor_summary", a.actorInfos) +} + +func (a *app) indexMachines(w http.ResponseWriter, r *http.Request) { + s, err := a.clusterMachineSummary(r.Context()) + if err != nil { + log.Errorf("cluster machine summary: %v", err) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + a.executeTemplate(w, "cluster_machines", s) +} + +func (a *app) indexTasks(w http.ResponseWriter, r *http.Request) { + s, err := a.clusterTaskSummary(r.Context()) + if err != nil { + log.Errorf("cluster task summary: %v", err) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + a.executeTemplate(w, "cluster_tasks", s) +} + +func (a *app) indexTasksHistory(w http.ResponseWriter, r *http.Request) { + s, err := a.clusterTaskHistorySummary(r.Context()) + if err != nil { + log.Errorf("cluster task history summary: %v", err) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + a.executeTemplate(w, "cluster_task_history", s) +} + +func (a *app) indexPipelinePorep(w http.ResponseWriter, r *http.Request) { + s, err := a.porepPipelineSummary(r.Context()) + if err != nil { + log.Errorf("porep pipeline summary: %v", err) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + a.executeTemplate(w, "pipeline_porep", s) +} + +func (a *app) nodeInfo(writer http.ResponseWriter, request *http.Request) { + params := mux.Vars(request) + + id, ok := params["id"] + if !ok { + http.Error(writer, "missing id", http.StatusBadRequest) + return + } + + intid, err := strconv.ParseInt(id, 10, 64) + if err != nil { + http.Error(writer, "invalid id", http.StatusBadRequest) + return + } + + mi, err := a.clusterNodeInfo(request.Context(), intid) + if err != nil { + log.Errorf("machine info: %v", err) + http.Error(writer, "internal server error", http.StatusInternalServerError) + return + } + + a.executePageTemplate(writer, "node_info", "Node Info", mi) +} + +func (a *app) sectorInfo(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + + id, ok := params["id"] + if !ok { + http.Error(w, "missing id", http.StatusBadRequest) + return + } + + intid, err := strconv.ParseInt(id, 10, 64) + if err != nil { + http.Error(w, "invalid id", http.StatusBadRequest) + return + } + + sp, ok := params["sp"] + if !ok { + http.Error(w, "missing sp", http.StatusBadRequest) + return + } + + maddr, err := address.NewFromString(sp) + if err != nil { + http.Error(w, "invalid sp", http.StatusBadRequest) + return + } + + spid, err := address.IDFromAddress(maddr) + if err != nil { + http.Error(w, "invalid sp", http.StatusBadRequest) + return + } + + ctx := r.Context() + var tasks []PipelineTask + + err = a.db.Select(ctx, &tasks, `SELECT + sp_id, sector_number, + create_time, + task_id_sdr, after_sdr, + task_id_tree_d, after_tree_d, + task_id_tree_c, after_tree_c, + task_id_tree_r, after_tree_r, + task_id_precommit_msg, after_precommit_msg, + after_precommit_msg_success, seed_epoch, + task_id_porep, porep_proof, after_porep, + task_id_finalize, after_finalize, + task_id_move_storage, after_move_storage, + task_id_commit_msg, after_commit_msg, + after_commit_msg_success, + failed, failed_reason + FROM sectors_sdr_pipeline WHERE sp_id = $1 AND sector_number = $2`, spid, intid) + if err != nil { + http.Error(w, xerrors.Errorf("failed to fetch pipeline task info: %w", err).Error(), http.StatusInternalServerError) + return + } + + if len(tasks) == 0 { + http.Error(w, "sector not found", http.StatusInternalServerError) + return + } + + head, err := a.workingApi.ChainHead(ctx) + if err != nil { + http.Error(w, xerrors.Errorf("failed to fetch chain head: %w", err).Error(), http.StatusInternalServerError) + return + } + epoch := head.Height() + + mbf, err := a.getMinerBitfields(ctx, maddr, a.stor) + if err != nil { + http.Error(w, xerrors.Errorf("failed to load miner bitfields: %w", err).Error(), http.StatusInternalServerError) + return + } + + task := tasks[0] + + afterSeed := task.SeedEpoch != nil && *task.SeedEpoch <= int64(epoch) + + var sectorLocations []struct { + CanSeal, CanStore bool + FileType storiface.SectorFileType `db:"sector_filetype"` + StorageID string `db:"storage_id"` + Urls string `db:"urls"` + } + + err = a.db.Select(ctx, §orLocations, `SELECT p.can_seal, p.can_store, l.sector_filetype, l.storage_id, p.urls FROM sector_location l + JOIN storage_path p ON l.storage_id = p.storage_id + WHERE l.sector_num = $1 and l.miner_id = $2 ORDER BY p.can_seal, p.can_store, l.storage_id`, intid, spid) + if err != nil { + http.Error(w, xerrors.Errorf("failed to fetch sector locations: %w", err).Error(), http.StatusInternalServerError) + return + } + + type fileLocations struct { + StorageID string + Urls []string + } + + type locationTable struct { + PathType *string + PathTypeRowSpan int + + FileType *string + FileTypeRowSpan int + + Locations []fileLocations + } + locs := []locationTable{} + + for i, loc := range sectorLocations { + loc := loc + + urlList := strings.Split(loc.Urls, paths.URLSeparator) + + fLoc := fileLocations{ + StorageID: loc.StorageID, + Urls: urlList, + } + + var pathTypeStr *string + var fileTypeStr *string + pathTypeRowSpan := 1 + fileTypeRowSpan := 1 + + pathType := "None" + if loc.CanSeal && loc.CanStore { + pathType = "Seal/Store" + } else if loc.CanSeal { + pathType = "Seal" + } else if loc.CanStore { + pathType = "Store" + } + pathTypeStr = &pathType + + fileType := loc.FileType.String() + fileTypeStr = &fileType + + if i > 0 { + prevNonNilPathTypeLoc := i - 1 + for prevNonNilPathTypeLoc > 0 && locs[prevNonNilPathTypeLoc].PathType == nil { + prevNonNilPathTypeLoc-- + } + if *locs[prevNonNilPathTypeLoc].PathType == *pathTypeStr { + pathTypeRowSpan = 0 + pathTypeStr = nil + locs[prevNonNilPathTypeLoc].PathTypeRowSpan++ + // only if we have extended path type we may need to extend file type + + prevNonNilFileTypeLoc := i - 1 + for prevNonNilFileTypeLoc > 0 && locs[prevNonNilFileTypeLoc].FileType == nil { + prevNonNilFileTypeLoc-- + } + if *locs[prevNonNilFileTypeLoc].FileType == *fileTypeStr { + fileTypeRowSpan = 0 + fileTypeStr = nil + locs[prevNonNilFileTypeLoc].FileTypeRowSpan++ + } + } + } + + locTable := locationTable{ + PathType: pathTypeStr, + PathTypeRowSpan: pathTypeRowSpan, + FileType: fileTypeStr, + FileTypeRowSpan: fileTypeRowSpan, + Locations: []fileLocations{fLoc}, + } + + locs = append(locs, locTable) + + } + + // TaskIDs + taskIDs := map[int64]struct{}{} + var htasks []taskSummary + { + // get non-nil task IDs + appendNonNil := func(id *int64) { + if id != nil { + taskIDs[*id] = struct{}{} + } + } + appendNonNil(task.TaskSDR) + appendNonNil(task.TaskTreeD) + appendNonNil(task.TaskTreeC) + appendNonNil(task.TaskTreeR) + appendNonNil(task.TaskPrecommitMsg) + appendNonNil(task.TaskPoRep) + appendNonNil(task.TaskFinalize) + appendNonNil(task.TaskMoveStorage) + appendNonNil(task.TaskCommitMsg) + + if len(taskIDs) > 0 { + ids := lo.Keys(taskIDs) + + var dbtasks []struct { + OwnerID *string `db:"owner_id"` + HostAndPort *string `db:"host_and_port"` + TaskID int64 `db:"id"` + Name string `db:"name"` + UpdateTime time.Time `db:"update_time"` + } + err = a.db.Select(ctx, &dbtasks, `SELECT t.owner_id, hm.host_and_port, t.id, t.name, t.update_time FROM harmony_task t LEFT JOIN curio.harmony_machines hm ON hm.id = t.owner_id WHERE t.id = ANY($1)`, ids) + if err != nil { + http.Error(w, fmt.Sprintf("failed to fetch task names: %v", err), http.StatusInternalServerError) + return + } + + for _, tn := range dbtasks { + htasks = append(htasks, taskSummary{ + Name: tn.Name, + SincePosted: time.Since(tn.UpdateTime.Local()).Round(time.Second).String(), + Owner: tn.HostAndPort, + OwnerID: tn.OwnerID, + ID: tn.TaskID, + }) + } + } + } + + mi := struct { + SectorNumber int64 + PipelinePoRep sectorListEntry + + Locations []locationTable + Tasks []taskSummary + }{ + SectorNumber: intid, + PipelinePoRep: sectorListEntry{ + PipelineTask: tasks[0], + AfterSeed: afterSeed, + + ChainAlloc: must.One(mbf.alloc.IsSet(uint64(task.SectorNumber))), + ChainSector: must.One(mbf.sectorSet.IsSet(uint64(task.SectorNumber))), + ChainActive: must.One(mbf.active.IsSet(uint64(task.SectorNumber))), + ChainUnproven: must.One(mbf.unproven.IsSet(uint64(task.SectorNumber))), + ChainFaulty: must.One(mbf.faulty.IsSet(uint64(task.SectorNumber))), + }, + + Locations: locs, + Tasks: htasks, + } + + a.executePageTemplate(w, "sector_info", "Sector Info", mi) +} + +var templateDev = os.Getenv("CURIO_WEB_DEV") == "1" + +func (a *app) executeTemplate(w http.ResponseWriter, name string, data interface{}) { + if templateDev { + fs := os.DirFS("./curiosrc/web/hapi/web") + a.t = template.Must(makeTemplate().ParseFS(fs, "*")) + } + if err := a.t.ExecuteTemplate(w, name, data); err != nil { + log.Errorf("execute template %s: %v", name, err) + http.Error(w, "internal server error", http.StatusInternalServerError) + } +} + +func (a *app) executePageTemplate(w http.ResponseWriter, name, title string, data interface{}) { + if templateDev { + fs := os.DirFS("./curiosrc/web/hapi/web") + a.t = template.Must(makeTemplate().ParseFS(fs, "*")) + } + var contentBuf bytes.Buffer + if err := a.t.ExecuteTemplate(&contentBuf, name, data); err != nil { + log.Errorf("execute template %s: %v", name, err) + http.Error(w, "internal server error", http.StatusInternalServerError) + } + a.executeTemplate(w, "root", map[string]interface{}{ + "PageTitle": title, + "Content": contentBuf.String(), + }) +} + +type machineRecentTask struct { + TaskName string + Success int64 + Fail int64 +} + +type machineSummary struct { + Address string + ID int64 + SinceContact string + + RecentTasks []*machineRecentTask +} + +type taskSummary struct { + Name string + SincePosted string + Owner, OwnerID *string + ID int64 +} + +type taskHistorySummary struct { + Name string + TaskID int64 + + Posted, Start, Queued, Took string + + Result bool + Err string + + CompletedBy string +} + +func (a *app) clusterMachineSummary(ctx context.Context) ([]machineSummary, error) { + // First get task summary for tasks completed in the last 24 hours + // NOTE: This query uses harmony_task_history_work_index, task history may get big + tsrows, err := a.db.Query(ctx, `SELECT hist.completed_by_host_and_port, hist.name, hist.result, count(1) FROM harmony_task_history hist + WHERE hist.work_end > now() - INTERVAL '1 day' + GROUP BY hist.completed_by_host_and_port, hist.name, hist.result + ORDER BY completed_by_host_and_port ASC`) + if err != nil { + return nil, err + } + defer tsrows.Close() + + // Map of machine -> task -> recent task + taskSummaries := map[string]map[string]*machineRecentTask{} + + for tsrows.Next() { + var taskName string + var result bool + var count int64 + var machine string + + if err := tsrows.Scan(&machine, &taskName, &result, &count); err != nil { + return nil, err + } + + if _, ok := taskSummaries[machine]; !ok { + taskSummaries[machine] = map[string]*machineRecentTask{} + } + + if _, ok := taskSummaries[machine][taskName]; !ok { + taskSummaries[machine][taskName] = &machineRecentTask{TaskName: taskName} + } + + if result { + taskSummaries[machine][taskName].Success = count + } else { + taskSummaries[machine][taskName].Fail = count + } + } + + // Then machine summary + rows, err := a.db.Query(ctx, "SELECT id, host_and_port, last_contact FROM harmony_machines order by host_and_port asc") + if err != nil { + return nil, err // Handle error + } + defer rows.Close() + + var summaries []machineSummary + for rows.Next() { + var m machineSummary + var lastContact time.Time + + if err := rows.Scan(&m.ID, &m.Address, &lastContact); err != nil { + return nil, err // Handle error + } + + m.SinceContact = time.Since(lastContact).Round(time.Second).String() + + // Add recent tasks + if ts, ok := taskSummaries[m.Address]; ok { + for _, t := range ts { + m.RecentTasks = append(m.RecentTasks, t) + } + sort.Slice(m.RecentTasks, func(i, j int) bool { + return m.RecentTasks[i].TaskName < m.RecentTasks[j].TaskName + }) + } + + summaries = append(summaries, m) + } + return summaries, nil +} + +func (a *app) clusterTaskSummary(ctx context.Context) ([]taskSummary, error) { + rows, err := a.db.Query(ctx, "SELECT t.id, t.name, t.update_time, t.owner_id, hm.host_and_port FROM harmony_task t LEFT JOIN curio.harmony_machines hm ON hm.id = t.owner_id ORDER BY t.update_time ASC, t.owner_id") + if err != nil { + return nil, err // Handle error + } + defer rows.Close() + + var summaries []taskSummary + for rows.Next() { + var t taskSummary + var posted time.Time + + if err := rows.Scan(&t.ID, &t.Name, &posted, &t.OwnerID, &t.Owner); err != nil { + return nil, err // Handle error + } + + t.SincePosted = time.Since(posted).Round(time.Second).String() + + summaries = append(summaries, t) + } + return summaries, nil +} + +func (a *app) clusterTaskHistorySummary(ctx context.Context) ([]taskHistorySummary, error) { + rows, err := a.db.Query(ctx, "SELECT id, name, task_id, posted, work_start, work_end, result, err, completed_by_host_and_port FROM harmony_task_history ORDER BY work_end DESC LIMIT 15") + if err != nil { + return nil, err // Handle error + } + defer rows.Close() + + var summaries []taskHistorySummary + for rows.Next() { + var t taskHistorySummary + var posted, start, end time.Time + + if err := rows.Scan(&t.TaskID, &t.Name, &t.TaskID, &posted, &start, &end, &t.Result, &t.Err, &t.CompletedBy); err != nil { + return nil, err // Handle error + } + + t.Posted = posted.Local().Round(time.Second).Format("02 Jan 06 15:04") + t.Start = start.Local().Round(time.Second).Format("02 Jan 06 15:04") + //t.End = end.Local().Round(time.Second).Format("02 Jan 06 15:04") + + t.Queued = start.Sub(posted).Round(time.Second).String() + if t.Queued == "0s" { + t.Queued = start.Sub(posted).Round(time.Millisecond).String() + } + + t.Took = end.Sub(start).Round(time.Second).String() + if t.Took == "0s" { + t.Took = end.Sub(start).Round(time.Millisecond).String() + } + + summaries = append(summaries, t) + } + return summaries, nil +} + +type porepPipelineSummary struct { + Actor string + + CountSDR int + CountTrees int + CountPrecommitMsg int + CountWaitSeed int + CountPoRep int + CountCommitMsg int + CountDone int + CountFailed int +} + +func (a *app) porepPipelineSummary(ctx context.Context) ([]porepPipelineSummary, error) { + rows, err := a.db.Query(ctx, ` + SELECT + sp_id, + COUNT(*) FILTER (WHERE after_sdr = false) as CountSDR, + COUNT(*) FILTER (WHERE (after_tree_d = false OR after_tree_c = false OR after_tree_r = false) AND after_sdr = true) as CountTrees, + COUNT(*) FILTER (WHERE after_tree_r = true and after_precommit_msg = false) as CountPrecommitMsg, + COUNT(*) FILTER (WHERE after_precommit_msg_success = false AND after_precommit_msg = true) as CountWaitSeed, + COUNT(*) FILTER (WHERE after_porep = false AND after_precommit_msg_success = true) as CountPoRep, + COUNT(*) FILTER (WHERE after_commit_msg_success = false AND after_porep = true) as CountCommitMsg, + COUNT(*) FILTER (WHERE after_commit_msg_success = true) as CountDone, + COUNT(*) FILTER (WHERE failed = true) as CountFailed + FROM + sectors_sdr_pipeline + GROUP BY sp_id`) + if err != nil { + return nil, xerrors.Errorf("query: %w", err) + } + defer rows.Close() + + var summaries []porepPipelineSummary + for rows.Next() { + var summary porepPipelineSummary + if err := rows.Scan(&summary.Actor, &summary.CountSDR, &summary.CountTrees, &summary.CountPrecommitMsg, &summary.CountWaitSeed, &summary.CountPoRep, &summary.CountCommitMsg, &summary.CountDone, &summary.CountFailed); err != nil { + return nil, xerrors.Errorf("scan: %w", err) + } + summary.Actor = "f0" + summary.Actor + + summaries = append(summaries, summary) + } + return summaries, nil +} + +type machineInfo struct { + Info struct { + Host string + ID int64 + LastContact string + CPU int64 + Memory int64 + GPU int64 + } + + // Storage + Storage []struct { + ID string + Weight int64 + MaxStorage int64 + CanSeal bool + CanStore bool + Groups string + AllowTo string + AllowTypes string + DenyTypes string + Capacity int64 + Available int64 + FSAvailable int64 + Reserved int64 + Used int64 + AllowMiners string + DenyMiners string + LastHeartbeat time.Time + HeartbeatErr *string + + UsedPercent float64 + ReservedPercent float64 + } + + /*TotalStorage struct { + MaxStorage int64 + UsedStorage int64 + + MaxSealStorage int64 + UsedSealStorage int64 + + MaxStoreStorage int64 + UsedStoreStorage int64 + }*/ + + // Tasks + RunningTasks []struct { + ID int64 + Task string + Posted string + + PoRepSector, PoRepSectorSP *int64 + } + + FinishedTasks []struct { + ID int64 + Task string + Posted string + Start string + Queued string + Took string + Outcome string + Message string + } +} + +func (a *app) clusterNodeInfo(ctx context.Context, id int64) (*machineInfo, error) { + rows, err := a.db.Query(ctx, "SELECT id, host_and_port, last_contact, cpu, ram, gpu FROM harmony_machines WHERE id=$1 ORDER BY host_and_port ASC", id) + if err != nil { + return nil, err // Handle error + } + defer rows.Close() + + var summaries []machineInfo + if rows.Next() { + var m machineInfo + var lastContact time.Time + + if err := rows.Scan(&m.Info.ID, &m.Info.Host, &lastContact, &m.Info.CPU, &m.Info.Memory, &m.Info.GPU); err != nil { + return nil, err + } + + m.Info.LastContact = time.Since(lastContact).Round(time.Second).String() + + summaries = append(summaries, m) + } + + if len(summaries) == 0 { + return nil, xerrors.Errorf("machine not found") + } + + // query storage info + rows2, err := a.db.Query(ctx, "SELECT storage_id, weight, max_storage, can_seal, can_store, groups, allow_to, allow_types, deny_types, capacity, available, fs_available, reserved, used, allow_miners, deny_miners, last_heartbeat, heartbeat_err FROM storage_path WHERE urls LIKE '%' || $1 || '%'", summaries[0].Info.Host) + if err != nil { + return nil, err + } + + defer rows2.Close() + + for rows2.Next() { + var s struct { + ID string + Weight int64 + MaxStorage int64 + CanSeal bool + CanStore bool + Groups string + AllowTo string + AllowTypes string + DenyTypes string + Capacity int64 + Available int64 + FSAvailable int64 + Reserved int64 + Used int64 + AllowMiners string + DenyMiners string + LastHeartbeat time.Time + HeartbeatErr *string + + UsedPercent float64 + ReservedPercent float64 + } + if err := rows2.Scan(&s.ID, &s.Weight, &s.MaxStorage, &s.CanSeal, &s.CanStore, &s.Groups, &s.AllowTo, &s.AllowTypes, &s.DenyTypes, &s.Capacity, &s.Available, &s.FSAvailable, &s.Reserved, &s.Used, &s.AllowMiners, &s.DenyMiners, &s.LastHeartbeat, &s.HeartbeatErr); err != nil { + return nil, err + } + + s.UsedPercent = float64(s.Capacity-s.FSAvailable) * 100 / float64(s.Capacity) + s.ReservedPercent = float64(s.Capacity-(s.FSAvailable+s.Reserved))*100/float64(s.Capacity) - s.UsedPercent + + summaries[0].Storage = append(summaries[0].Storage, s) + } + + // tasks + rows3, err := a.db.Query(ctx, "SELECT id, name, posted_time FROM harmony_task WHERE owner_id=$1", summaries[0].Info.ID) + if err != nil { + return nil, err + } + + defer rows3.Close() + + for rows3.Next() { + var t struct { + ID int64 + Task string + Posted string + + PoRepSector *int64 + PoRepSectorSP *int64 + } + + var posted time.Time + if err := rows3.Scan(&t.ID, &t.Task, &posted); err != nil { + return nil, err + } + t.Posted = time.Since(posted).Round(time.Second).String() + + { + // try to find in the porep pipeline + rows4, err := a.db.Query(ctx, `SELECT sp_id, sector_number FROM sectors_sdr_pipeline + WHERE task_id_sdr=$1 + OR task_id_tree_d=$1 + OR task_id_tree_c=$1 + OR task_id_tree_r=$1 + OR task_id_precommit_msg=$1 + OR task_id_porep=$1 + OR task_id_commit_msg=$1 + OR task_id_finalize=$1 + OR task_id_move_storage=$1 + `, t.ID) + if err != nil { + return nil, err + } + + if rows4.Next() { + var spid int64 + var sector int64 + if err := rows4.Scan(&spid, §or); err != nil { + return nil, err + } + t.PoRepSector = §or + t.PoRepSectorSP = &spid + } + + rows4.Close() + } + + summaries[0].RunningTasks = append(summaries[0].RunningTasks, t) + } + + rows5, err := a.db.Query(ctx, `SELECT name, task_id, posted, work_start, work_end, result, err FROM harmony_task_history WHERE completed_by_host_and_port = $1 ORDER BY work_end DESC LIMIT 15`, summaries[0].Info.Host) + if err != nil { + return nil, err + } + defer rows5.Close() + + for rows5.Next() { + var ft struct { + ID int64 + Task string + Posted string + Start string + Queued string + Took string + Outcome string + + Message string + } + + var posted, start, end time.Time + var result bool + if err := rows5.Scan(&ft.Task, &ft.ID, &posted, &start, &end, &result, &ft.Message); err != nil { + return nil, err + } + + ft.Outcome = "Success" + if !result { + ft.Outcome = "Failed" + } + + // Format the times and durations + ft.Posted = posted.Format("02 Jan 06 15:04 MST") + ft.Start = start.Format("02 Jan 06 15:04 MST") + ft.Queued = fmt.Sprintf("%s", start.Sub(posted).Round(time.Second).String()) + ft.Took = fmt.Sprintf("%s", end.Sub(start).Round(time.Second)) + + summaries[0].FinishedTasks = append(summaries[0].FinishedTasks, ft) + } + + return &summaries[0], nil +} diff --git a/curiosrc/web/hapi/simpleinfo_pipeline_porep.go b/curiosrc/web/hapi/simpleinfo_pipeline_porep.go new file mode 100644 index 00000000000..a37cd14ab28 --- /dev/null +++ b/curiosrc/web/hapi/simpleinfo_pipeline_porep.go @@ -0,0 +1,195 @@ +package hapi + +import ( + "context" + "net/http" + "time" + + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" + + "github.com/filecoin-project/lotus/chain/actors/adt" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/must" +) + +type PipelineTask struct { + SpID int64 `db:"sp_id"` + SectorNumber int64 `db:"sector_number"` + + CreateTime time.Time `db:"create_time"` + + TaskSDR *int64 `db:"task_id_sdr"` + AfterSDR bool `db:"after_sdr"` + + TaskTreeD *int64 `db:"task_id_tree_d"` + AfterTreeD bool `db:"after_tree_d"` + + TaskTreeC *int64 `db:"task_id_tree_c"` + AfterTreeC bool `db:"after_tree_c"` + + TaskTreeR *int64 `db:"task_id_tree_r"` + AfterTreeR bool `db:"after_tree_r"` + + TaskPrecommitMsg *int64 `db:"task_id_precommit_msg"` + AfterPrecommitMsg bool `db:"after_precommit_msg"` + + AfterPrecommitMsgSuccess bool `db:"after_precommit_msg_success"` + SeedEpoch *int64 `db:"seed_epoch"` + + TaskPoRep *int64 `db:"task_id_porep"` + PoRepProof []byte `db:"porep_proof"` + AfterPoRep bool `db:"after_porep"` + + TaskFinalize *int64 `db:"task_id_finalize"` + AfterFinalize bool `db:"after_finalize"` + + TaskMoveStorage *int64 `db:"task_id_move_storage"` + AfterMoveStorage bool `db:"after_move_storage"` + + TaskCommitMsg *int64 `db:"task_id_commit_msg"` + AfterCommitMsg bool `db:"after_commit_msg"` + + AfterCommitMsgSuccess bool `db:"after_commit_msg_success"` + + Failed bool `db:"failed"` + FailedReason string `db:"failed_reason"` +} + +type sectorListEntry struct { + PipelineTask + + Address address.Address + CreateTime string + AfterSeed bool + + ChainAlloc, ChainSector, ChainActive, ChainUnproven, ChainFaulty bool +} + +type minerBitfields struct { + alloc, sectorSet, active, unproven, faulty bitfield.BitField +} + +func (a *app) pipelinePorepSectors(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + var tasks []PipelineTask + + err := a.db.Select(ctx, &tasks, `SELECT + sp_id, sector_number, + create_time, + task_id_sdr, after_sdr, + task_id_tree_d, after_tree_d, + task_id_tree_c, after_tree_c, + task_id_tree_r, after_tree_r, + task_id_precommit_msg, after_precommit_msg, + after_precommit_msg_success, seed_epoch, + task_id_porep, porep_proof, after_porep, + task_id_finalize, after_finalize, + task_id_move_storage, after_move_storage, + task_id_commit_msg, after_commit_msg, + after_commit_msg_success, + failed, failed_reason + FROM sectors_sdr_pipeline order by sp_id, sector_number`) // todo where constrain list + if err != nil { + http.Error(w, xerrors.Errorf("failed to fetch pipeline tasks: %w", err).Error(), http.StatusInternalServerError) + return + } + + head, err := a.workingApi.ChainHead(ctx) + if err != nil { + http.Error(w, xerrors.Errorf("failed to fetch chain head: %w", err).Error(), http.StatusInternalServerError) + return + } + epoch := head.Height() + + minerBitfieldCache := map[address.Address]minerBitfields{} + + sectorList := make([]sectorListEntry, 0, len(tasks)) + for _, task := range tasks { + task := task + + task.CreateTime = task.CreateTime.Local() + + addr, err := address.NewIDAddress(uint64(task.SpID)) + if err != nil { + http.Error(w, xerrors.Errorf("failed to create actor address: %w", err).Error(), http.StatusInternalServerError) + return + } + + mbf, ok := minerBitfieldCache[addr] + if !ok { + mbf, err := a.getMinerBitfields(ctx, addr, a.stor) + if err != nil { + http.Error(w, xerrors.Errorf("failed to load miner bitfields: %w", err).Error(), http.StatusInternalServerError) + return + } + minerBitfieldCache[addr] = mbf + } + + afterSeed := task.SeedEpoch != nil && *task.SeedEpoch <= int64(epoch) + + sectorList = append(sectorList, sectorListEntry{ + PipelineTask: task, + Address: addr, + CreateTime: task.CreateTime.Format(time.DateTime), + AfterSeed: afterSeed, + + ChainAlloc: must.One(mbf.alloc.IsSet(uint64(task.SectorNumber))), + ChainSector: must.One(mbf.sectorSet.IsSet(uint64(task.SectorNumber))), + ChainActive: must.One(mbf.active.IsSet(uint64(task.SectorNumber))), + ChainUnproven: must.One(mbf.unproven.IsSet(uint64(task.SectorNumber))), + ChainFaulty: must.One(mbf.faulty.IsSet(uint64(task.SectorNumber))), + }) + } + + a.executeTemplate(w, "pipeline_porep_sectors", sectorList) +} + +func (a *app) getMinerBitfields(ctx context.Context, addr address.Address, stor adt.Store) (minerBitfields, error) { + act, err := a.workingApi.StateGetActor(ctx, addr, types.EmptyTSK) + if err != nil { + return minerBitfields{}, xerrors.Errorf("failed to load actor: %w", err) + } + + mas, err := miner.Load(stor, act) + if err != nil { + return minerBitfields{}, xerrors.Errorf("failed to load miner actor: %w", err) + } + + activeSectors, err := miner.AllPartSectors(mas, miner.Partition.ActiveSectors) + if err != nil { + return minerBitfields{}, xerrors.Errorf("failed to load active sectors: %w", err) + } + + allSectors, err := miner.AllPartSectors(mas, miner.Partition.AllSectors) + if err != nil { + return minerBitfields{}, xerrors.Errorf("failed to load all sectors: %w", err) + } + + unproved, err := miner.AllPartSectors(mas, miner.Partition.UnprovenSectors) + if err != nil { + return minerBitfields{}, xerrors.Errorf("failed to load unproven sectors: %w", err) + } + + faulty, err := miner.AllPartSectors(mas, miner.Partition.FaultySectors) + if err != nil { + return minerBitfields{}, xerrors.Errorf("failed to load faulty sectors: %w", err) + } + + alloc, err := mas.GetAllocatedSectors() + if err != nil { + return minerBitfields{}, xerrors.Errorf("failed to load allocated sectors: %w", err) + } + + return minerBitfields{ + alloc: *alloc, + sectorSet: allSectors, + active: activeSectors, + unproven: unproved, + faulty: faulty, + }, nil +} diff --git a/curiosrc/web/hapi/watch_actor.go b/curiosrc/web/hapi/watch_actor.go new file mode 100644 index 00000000000..51e1f51e74d --- /dev/null +++ b/curiosrc/web/hapi/watch_actor.go @@ -0,0 +1,286 @@ +package hapi + +import ( + "context" + "sort" + "time" + + "github.com/BurntSushi/toml" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" +) + +const watchInterval = time.Second * 10 + +func (a *app) watchActor() { + ticker := time.NewTicker(watchInterval) + for { + err := a.updateActor(context.TODO()) + if err != nil { + log.Errorw("updating rpc info", "error", err) + } + select { + case <-ticker.C: + } + } +} + +type minimalActorInfo struct { + Addresses []struct { + MinerAddresses []string + } +} + +var startedAt = time.Now() + +func (a *app) updateActor(ctx context.Context) error { + a.rpcInfoLk.Lock() + api := a.workingApi + a.rpcInfoLk.Unlock() + + stor := store.ActorStore(ctx, blockstore.NewReadCachedBlockstore(blockstore.NewAPIBlockstore(a.workingApi), ChainBlockCache)) + + if api == nil { + if time.Since(startedAt) > time.Second*10 { + log.Warnw("no working api yet") + } + return nil + } + + var actorInfos []actorInfo + + confNameToAddr := map[address.Address][]string{} // address -> config names + + err := forEachConfig[minimalActorInfo](a, func(name string, info minimalActorInfo) error { + for _, aset := range info.Addresses { + for _, addr := range aset.MinerAddresses { + a, err := address.NewFromString(addr) + if err != nil { + return xerrors.Errorf("parsing address: %w", err) + } + confNameToAddr[a] = append(confNameToAddr[a], name) + } + } + + return nil + }) + if err != nil { + return err + } + + wins, err := a.spWins(ctx) + if err != nil { + return xerrors.Errorf("getting sp wins: %w", err) + } + + for addr, cnames := range confNameToAddr { + p, err := api.StateMinerPower(ctx, addr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner power: %w", err) + } + + dls, err := api.StateMinerDeadlines(ctx, addr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting deadlines: %w", err) + } + + mact, err := api.StateGetActor(ctx, addr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting actor: %w", err) + } + + mas, err := miner.Load(stor, mact) + if err != nil { + return err + } + + outDls := []actorDeadline{} + + for dlidx := range dls { + p, err := api.StateMinerPartitions(ctx, addr, uint64(dlidx), types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting partition: %w", err) + } + + dl := actorDeadline{ + Empty: false, + Current: false, // todo + Proven: false, + PartFaulty: false, + Faulty: false, + } + + var live, faulty uint64 + + for _, part := range p { + l, err := part.LiveSectors.Count() + if err != nil { + return xerrors.Errorf("getting live sectors: %w", err) + } + live += l + + f, err := part.FaultySectors.Count() + if err != nil { + return xerrors.Errorf("getting faulty sectors: %w", err) + } + faulty += f + } + + dl.Empty = live == 0 + dl.Proven = live > 0 && faulty == 0 + dl.PartFaulty = faulty > 0 + dl.Faulty = faulty > 0 && faulty == live + + outDls = append(outDls, dl) + } + + pd, err := api.StateMinerProvingDeadline(ctx, addr, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting proving deadline: %w", err) + } + + if len(outDls) != 48 { + return xerrors.Errorf("expected 48 deadlines, got %d", len(outDls)) + } + + outDls[pd.Index].Current = true + + avail, err := mas.AvailableBalance(mact.Balance) + if err != nil { + return xerrors.Errorf("getting available balance: %w", err) + } + + mi, err := mas.Info() + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + wbal, err := api.WalletBalance(ctx, mi.Worker) + if err != nil { + return xerrors.Errorf("getting worker balance: %w", err) + } + + sort.Strings(cnames) + + actorInfos = append(actorInfos, actorInfo{ + Address: addr.String(), + CLayers: cnames, + QualityAdjustedPower: types.DeciStr(p.MinerPower.QualityAdjPower), + RawBytePower: types.DeciStr(p.MinerPower.RawBytePower), + Deadlines: outDls, + + ActorBalance: types.FIL(mact.Balance).Short(), + ActorAvailable: types.FIL(avail).Short(), + WorkerBalance: types.FIL(wbal).Short(), + + Win1: wins[addr].Win1, // note: zero values are fine here + Win7: wins[addr].Win7, + Win30: wins[addr].Win30, + }) + } + + sort.Slice(actorInfos, func(i, j int) bool { + return actorInfos[i].Address < actorInfos[j].Address + }) + + a.actorInfoLk.Lock() + a.actorInfos = actorInfos + a.actorInfoLk.Unlock() + + return nil +} + +func (a *app) loadConfigs(ctx context.Context) (map[string]string, error) { + rows, err := a.db.Query(ctx, `SELECT title, config FROM harmony_config`) + if err != nil { + return nil, xerrors.Errorf("getting db configs: %w", err) + } + + configs := make(map[string]string) + for rows.Next() { + var title, config string + if err := rows.Scan(&title, &config); err != nil { + return nil, xerrors.Errorf("scanning db configs: %w", err) + } + configs[title] = config + } + + return configs, nil +} + +type wins struct { + SpID int64 `db:"sp_id"` + Win1 int64 `db:"win1"` + Win7 int64 `db:"win7"` + Win30 int64 `db:"win30"` +} + +func (a *app) spWins(ctx context.Context) (map[address.Address]wins, error) { + var w []wins + + // note: this query uses mining_tasks_won_sp_id_base_compute_time_index + err := a.db.Select(ctx, &w, `WITH wins AS ( + SELECT + sp_id, + base_compute_time, + won + FROM + mining_tasks + WHERE + won = true + AND base_compute_time > NOW() - INTERVAL '30 days' + ) + + SELECT + sp_id, + COUNT(*) FILTER (WHERE base_compute_time > NOW() - INTERVAL '1 day') AS "win1", + COUNT(*) FILTER (WHERE base_compute_time > NOW() - INTERVAL '7 days') AS "win7", + COUNT(*) FILTER (WHERE base_compute_time > NOW() - INTERVAL '30 days') AS "win30" + FROM + wins + GROUP BY + sp_id + ORDER BY + sp_id`) + if err != nil { + return nil, xerrors.Errorf("query win counts: %w", err) + } + + wm := make(map[address.Address]wins) + for _, wi := range w { + ma, err := address.NewIDAddress(uint64(wi.SpID)) + if err != nil { + return nil, xerrors.Errorf("parsing miner address: %w", err) + } + + wm[ma] = wi + } + + return wm, nil +} + +func forEachConfig[T any](a *app, cb func(name string, v T) error) error { + confs, err := a.loadConfigs(context.Background()) + if err != nil { + return err + } + + for name, tomlStr := range confs { + var info T + if err := toml.Unmarshal([]byte(tomlStr), &info); err != nil { + return xerrors.Errorf("unmarshaling %s config: %w", name, err) + } + + if err := cb(name, info); err != nil { + return xerrors.Errorf("cb: %w", err) + } + } + + return nil +} diff --git a/curiosrc/web/hapi/web/actor_summary.gohtml b/curiosrc/web/hapi/web/actor_summary.gohtml new file mode 100644 index 00000000000..bf577d802e0 --- /dev/null +++ b/curiosrc/web/hapi/web/actor_summary.gohtml @@ -0,0 +1,30 @@ +{{define "actor_summary"}} +{{range .}} + + {{.Address}} + + {{range .CLayers}} + {{.}} + {{end}} + + {{.QualityAdjustedPower}} + +
+ {{range .Deadlines}} +
+ {{end}} +
+ + {{.ActorBalance}} + {{.ActorAvailable}} + {{.WorkerBalance}} + + + + + +
1day:  {{.Win1}}
7day:  {{.Win7}}
30day: {{.Win30}}
+ + +{{end}} +{{end}} \ No newline at end of file diff --git a/curiosrc/web/hapi/web/chain_rpcs.gohtml b/curiosrc/web/hapi/web/chain_rpcs.gohtml new file mode 100644 index 00000000000..5705da39517 --- /dev/null +++ b/curiosrc/web/hapi/web/chain_rpcs.gohtml @@ -0,0 +1,15 @@ +{{define "chain_rpcs"}} +{{range .}} + + {{.Address}} + + {{range .CLayers}} + {{.}} + {{end}} + + {{if .Reachable}}ok{{else}}FAIL{{end}} + {{if eq "ok" .SyncState}}ok{{else}}{{.SyncState}}{{end}} + {{.Version}} + +{{end}} +{{end}} diff --git a/curiosrc/web/hapi/web/cluster_machines.gohtml b/curiosrc/web/hapi/web/cluster_machines.gohtml new file mode 100644 index 00000000000..5fb18b52c24 --- /dev/null +++ b/curiosrc/web/hapi/web/cluster_machines.gohtml @@ -0,0 +1,12 @@ +{{define "cluster_machines"}} +{{range .}} + + {{.Address}} + {{.ID}} + {{.SinceContact}} + {{range .RecentTasks}} + {{.TaskName}}:{{.Success}}{{if ne 0 .Fail}}({{.Fail}}){{end}} + {{end}} + +{{end}} +{{end}} diff --git a/curiosrc/web/hapi/web/cluster_task_history.gohtml b/curiosrc/web/hapi/web/cluster_task_history.gohtml new file mode 100644 index 00000000000..f95dbb2b26b --- /dev/null +++ b/curiosrc/web/hapi/web/cluster_task_history.gohtml @@ -0,0 +1,19 @@ +{{define "cluster_task_history"}} + {{range .}} + + {{.Name}} + {{.TaskID}} + {{.CompletedBy}} + {{.Posted}} + {{.Start}} + {{.Queued}} + {{.Took}} + {{if .Result}}success{{else}}error{{end}} + +
+ {{.Err}} +
+ + + {{end}} +{{end}} diff --git a/curiosrc/web/hapi/web/cluster_tasks.gohtml b/curiosrc/web/hapi/web/cluster_tasks.gohtml new file mode 100644 index 00000000000..b7b3faec0ef --- /dev/null +++ b/curiosrc/web/hapi/web/cluster_tasks.gohtml @@ -0,0 +1,10 @@ +{{define "cluster_tasks"}} + {{range .}} + + {{.Name}} + {{.ID}} + {{.SincePosted}} + {{if ne nil .OwnerID}}{{.Owner}}{{end}} + + {{end}} +{{end}} diff --git a/curiosrc/web/hapi/web/node_info.gohtml b/curiosrc/web/hapi/web/node_info.gohtml new file mode 100644 index 00000000000..16f60a47522 --- /dev/null +++ b/curiosrc/web/hapi/web/node_info.gohtml @@ -0,0 +1,100 @@ +{{define "node_info"}} +

Info

+ + + + + + + + + + + + + + + + + + + +
HostIDLast ContactCPUMemoryGPUDebug
{{.Info.Host}}{{.Info.ID}}{{.Info.LastContact}}{{.Info.CPU}}{{toHumanBytes .Info.Memory}}{{.Info.GPU}}[pprof]
+
+

Storage

+ + + + + + + + + + {{range .Storage}} + + + + + + + + + {{end}} + +
IDTypeCapacityAvailableReserved
{{.ID}} + {{if and (not .CanSeal) (not .CanStore)}}ReadOnly{{end}} + {{if and (.CanSeal) (not .CanStore)}}Seal{{end}} + {{if and (not .CanSeal) (.CanStore)}}Store{{end}} + {{if and (.CanSeal) (.CanStore)}}Seal+Store{{end}} + {{toHumanBytes .Capacity}}{{toHumanBytes .Available}}{{toHumanBytes .Reserved}} +
+
+
+
+
+
+

Tasks

+

Running

+ + + + + + + + {{range .RunningTasks}} + + + + + + + {{end}} +
IDTaskPostedSector
{{.ID}}{{.Task}}{{.Posted}}{{if ne nil .PoRepSector}}f0{{.PoRepSectorSP}}:{{.PoRepSector}}{{end}}
+

Recently Finished

+ + + + + + + + + + + + {{range .FinishedTasks}} + + + + + + + + + + + {{end}} +
IDTaskPostedStartQueuedTookOutcomeMessage
{{.ID}}{{.Task}}{{.Posted}}{{.Start}}{{.Queued}}{{.Took}}{{.Outcome}}{{.Message}}
+{{end}} diff --git a/curiosrc/web/hapi/web/pipeline_porep_sectors.gohtml b/curiosrc/web/hapi/web/pipeline_porep_sectors.gohtml new file mode 100644 index 00000000000..82f0ad19671 --- /dev/null +++ b/curiosrc/web/hapi/web/pipeline_porep_sectors.gohtml @@ -0,0 +1,200 @@ +{{define "sector_porep_state"}} + + + + + + + + + + + + + + + + + + + + + + + + + +
+
SDR
+
+ {{if .AfterSDR}}done{{else}} + {{if ne .TaskSDR nil}}T:{{.TaskSDR}}{{else}}--{{end}} + {{end}} +
+
+
TreeC
+
+ {{if .AfterTreeC}}done{{else}} + {{if ne .TaskTreeC nil}}T:{{.TaskTreeC}}{{else}}--{{end}} + {{end}} +
+
+
PComm Msg
+
+ {{if .AfterPrecommitMsg}}done{{else}} + {{if ne .TaskPrecommitMsg nil}}T:{{.TaskPrecommitMsg}}{{else}}--{{end}} + {{end}} +
+
+
PComm Wait
+
+ {{if .AfterPrecommitMsgSuccess}}done{{else}} + -- + {{end}} +
+
+
Wait Seed
+
+ {{if .AfterSeed}}done{{else}} + {{if ne .SeedEpoch nil}}@{{.SeedEpoch}}{{else}}--{{end}} + {{end}} +
+
+
PoRep
+
+ {{if .AfterPoRep}}done{{else}} + {{if ne .TaskPoRep nil}}T:{{.TaskPoRep}}{{else}}--{{end}} + {{end}} +
+
+
Clear Cache
+
+ {{if .AfterFinalize}}done{{else}} + {{if ne .TaskFinalize nil}}T:{{.TaskFinalize}}{{else}}--{{end}} + {{end}} +
+
+
Move Storage
+
+ {{if .AfterMoveStorage}}done{{else}} + {{if ne .TaskMoveStorage nil}}T:{{.TaskMoveStorage}}{{else}}--{{end}} + {{end}} +
+
+
On Chain
+
{{if .ChainSector}}yes{{else}}{{if .ChainAlloc}}allocated{{else}}no{{end}}{{end}}
+
+
TreeD
+
+ {{if .AfterTreeD}}done{{else}} + {{if ne .TaskTreeD nil}}T:{{.TaskTreeD}}{{else}}--{{end}} + {{end}} +
+
+
TreeR
+
+ {{if .AfterTreeR}}done{{else}} + {{if ne .TaskTreeR nil}}T:{{.TaskTreeR}}{{else}}--{{end}} + {{end}} +
+
+
Commit Msg
+
+ {{if .AfterCommitMsg}}done{{else}} + {{if ne .TaskCommitMsg nil}}T:{{.TaskCommitMsg}}{{else}}--{{end}} + {{end}} +
+
+
Commit Wait
+
+ {{if .AfterCommitMsgSuccess}}done{{else}} + -- + {{end}} +
+
+
Active
+
{{if .ChainActive}}yes{{else}} + {{if .ChainUnproven}}unproven{{else}} + {{if .ChainFaulty}}faulty{{else}}no{{end}} + {{end}} + {{end}} +
+
+{{end}} + +{{define "pipeline_porep_sectors"}} + {{range .}} + + {{.Address}} + {{.CreateTime}} + + {{template "sector_porep_state" .}} + + + DETAILS + + + + + {{.SectorNumber}} + + + {{end}} +{{end}} diff --git a/curiosrc/web/hapi/web/pipline_porep.gohtml b/curiosrc/web/hapi/web/pipline_porep.gohtml new file mode 100644 index 00000000000..5e7c7f7c63e --- /dev/null +++ b/curiosrc/web/hapi/web/pipline_porep.gohtml @@ -0,0 +1,15 @@ +{{define "pipeline_porep"}} + {{range .}} + + {{.Actor}} + {{.CountSDR}} + {{.CountTrees}} + {{.CountPrecommitMsg}} + {{.CountWaitSeed}} + {{.CountPoRep}} + {{.CountCommitMsg}} + {{.CountDone}} + {{.CountFailed}} + + {{end}} +{{end}} diff --git a/curiosrc/web/hapi/web/root.gohtml b/curiosrc/web/hapi/web/root.gohtml new file mode 100644 index 00000000000..114db6462c8 --- /dev/null +++ b/curiosrc/web/hapi/web/root.gohtml @@ -0,0 +1,26 @@ +{{define "root"}} + + + {{.PageTitle}} + + + + + + + + + +
+
+

{{.PageTitle}}

+
+
+
+
+ {{.Content}} +
+
+ + +{{end}} diff --git a/curiosrc/web/hapi/web/sector_info.gohtml b/curiosrc/web/hapi/web/sector_info.gohtml new file mode 100644 index 00000000000..afa96a9234a --- /dev/null +++ b/curiosrc/web/hapi/web/sector_info.gohtml @@ -0,0 +1,57 @@ +{{define "sector_info"}} +

Sector {{.SectorNumber}}

+
+

PoRep Pipeline

+ {{template "sector_porep_state" .PipelinePoRep}} +
+
+

Storage

+ + + + + + + + {{range .Locations}} + + {{if .PathType}} + + {{end}} + {{if .FileType}} + + {{end}} + + + + {{range $i, $loc := .Locations}} + {{if gt $i 0}} + + + + + {{end}} + {{end}} + {{end}} +
Path TypeFile TypePath IDHost
{{.PathType}}{{.FileType}}{{(index .Locations 0).StorageID}}{{range (index .Locations 0).Urls}}

{{.}}

{{end}}
{{$loc.StorageID}}{{range $loc.Urls}}

{{.}}

{{end}}
+
+
+

Tasks

+ + + + + + + + {{range .Tasks}} + + + + + + + {{end}} +
Task TypeTask IDPostedWorker
{{.Name}}{{.ID}}{{.SincePosted}}{{if ne nil .OwnerID}}{{.Owner}}{{end}}
+
+{{end}} diff --git a/curiosrc/web/srv.go b/curiosrc/web/srv.go new file mode 100644 index 00000000000..b16a9f9afcb --- /dev/null +++ b/curiosrc/web/srv.go @@ -0,0 +1,82 @@ +// Package web defines the HTTP web server for static files and endpoints. +package web + +import ( + "context" + "embed" + "io" + "io/fs" + "net" + "net/http" + "os" + "path" + "strings" + "time" + + "github.com/gorilla/mux" + "go.opencensus.io/tag" + + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/curiosrc/web/api" + "github.com/filecoin-project/lotus/curiosrc/web/hapi" + "github.com/filecoin-project/lotus/metrics" +) + +//go:embed static +var static embed.FS + +var basePath = "/static/" + +// An dev mode hack for no-restart changes to static and templates. +// You still need to recomplie the binary for changes to go code. +var webDev = os.Getenv("CURIO_WEB_DEV") == "1" + +func GetSrv(ctx context.Context, deps *deps.Deps) (*http.Server, error) { + mx := mux.NewRouter() + err := hapi.Routes(mx.PathPrefix("/hapi").Subrouter(), deps) + if err != nil { + return nil, err + } + api.Routes(mx.PathPrefix("/api").Subrouter(), deps) + + var static fs.FS = static + if webDev { + basePath = "" + static = os.DirFS("curiosrc/web/static") + } + + mx.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // If the request is for a directory, redirect to the index file. + if strings.HasSuffix(r.URL.Path, "/") { + r.URL.Path += "index.html" + } + + file, err := static.Open(path.Join(basePath, r.URL.Path)[1:]) + if err != nil { + w.WriteHeader(http.StatusNotFound) + _, _ = w.Write([]byte("404 Not Found")) + return + } + defer func() { _ = file.Close() }() + + fileInfo, err := file.Stat() + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte("500 Internal Server Error")) + return + } + + http.ServeContent(w, r, fileInfo.Name(), fileInfo.ModTime(), file.(io.ReadSeeker)) + }) + + return &http.Server{ + Handler: http.HandlerFunc(mx.ServeHTTP), + BaseContext: func(listener net.Listener) context.Context { + ctx, _ := tag.New(context.Background(), tag.Upsert(metrics.APIInterface, "curio")) + return ctx + }, + Addr: deps.Cfg.Subsystems.GuiAddress, + ReadTimeout: time.Minute * 3, + ReadHeaderTimeout: time.Minute * 3, // lint + }, nil +} diff --git a/curiosrc/web/static/chain-connectivity.mjs b/curiosrc/web/static/chain-connectivity.mjs new file mode 100644 index 00000000000..bf4c80f04ce --- /dev/null +++ b/curiosrc/web/static/chain-connectivity.mjs @@ -0,0 +1,59 @@ +import { LitElement, html, css } from 'https://cdn.jsdelivr.net/gh/lit/dist@3/all/lit-all.min.js'; +window.customElements.define('chain-connectivity', class MyElement extends LitElement { + constructor() { + super(); + this.data = []; + this.loadData(); + } + loadData() { + const eventSource = new EventSource('/api/debug/chain-state-sse'); + eventSource.onmessage = (event) => { + this.data = JSON.parse(event.data); + super.requestUpdate(); + }; + eventSource.onerror = (error) => { + console.error('Error:', error); + loadData(); + }; + }; + + static get styles() { + return [css` + :host { + box-sizing: border-box; /* Don't forgert this to include padding/border inside width calculation */ + } + .success { + color: green; + } + .warning { + color: yellow; + } + .error { + color: red; + } + `]; + } + render = () => html` + + + + + + + + + + + + + ${this.data.map(item => html` + + + + + + + `)} + +
RPC AddressReachabilitySync StatusVersion
${item.Address}${item.Reachable ? html`ok` : html`FAIL`}${item.SyncState === "ok" ? html`ok` : html`${item.SyncState}`}${item.Version}
` +}); diff --git a/curiosrc/web/static/config/edit.html b/curiosrc/web/static/config/edit.html new file mode 100644 index 00000000000..2802316a980 --- /dev/null +++ b/curiosrc/web/static/config/edit.html @@ -0,0 +1,160 @@ + + + + JSON Schema Editor + + + + + + + + + +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+
+
+ + diff --git a/curiosrc/web/static/config/index.html b/curiosrc/web/static/config/index.html new file mode 100644 index 00000000000..769929e53a3 --- /dev/null +++ b/curiosrc/web/static/config/index.html @@ -0,0 +1,97 @@ + + + + + Configuration Editor + + + + + + + + +
+
+
+
+

Configuration Editor

+

Click on a layer to edit its configuration

+ +
+
+
+
+
+ + + \ No newline at end of file diff --git a/curiosrc/web/static/favicon.svg b/curiosrc/web/static/favicon.svg new file mode 100644 index 00000000000..91f132959f2 --- /dev/null +++ b/curiosrc/web/static/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/curiosrc/web/static/index.html b/curiosrc/web/static/index.html new file mode 100644 index 00000000000..0d734d6b7cb --- /dev/null +++ b/curiosrc/web/static/index.html @@ -0,0 +1,201 @@ + + + + Curio Cluster Overview + + + + + + + +
+
+
+
+

Chain Connectivity

+ +
+
+
+
+
+ +
+
+
+

Cluster Machines

+ + + + + + + + + + + +
HostIDLast ContactTasks (24h)
+
+
+
+
+
+ +
+
+
+

PoRep Pipeline

+ + + + + + + + + + + + + + + + +
AddressSDRTreesPrecommit MsgWait SeedPoRepCommit MsgDoneFailed
+
+
+
+
+
+ +
+
+
+

Actor Summary

+ + + + + + + + + + + + + + + +
AddressConfig Layers AvailableQaPDeadlinesBalanceAvailableWorkerWins
+
+
+
+
+
+ + +
+
+
+

Recently Finished Tasks

+ + + + + + + + + + + + + + + + +
NameIDExecutorPostedStartQueuedTookOutcomeMessage
+
+
+
+
+
+ +
+
+
+

Cluster Tasks

+ + + + + + + + + + + +
TaskIDPostedOwner
+
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/curiosrc/web/static/pipeline_porep.html b/curiosrc/web/static/pipeline_porep.html new file mode 100644 index 00000000000..c609aea6f69 --- /dev/null +++ b/curiosrc/web/static/pipeline_porep.html @@ -0,0 +1,98 @@ + + + Lotus Provider PoRep Pipeline + + + + + + + + + +
+
+

Lotus Provider PoRep Pipeline

+
+
+
+
+
+
+
+

Sectors

+ + + + + + + + + + +
Sector IDCreate TimeState
+
+
+
+
+
+ + \ No newline at end of file diff --git a/curiosrc/web/static/sector/index.html b/curiosrc/web/static/sector/index.html new file mode 100644 index 00000000000..9ac5559cd4a --- /dev/null +++ b/curiosrc/web/static/sector/index.html @@ -0,0 +1,129 @@ + + + + + Sector List + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + + +
Loading...
+
+
+
+
+ + + + \ No newline at end of file diff --git a/curiosrc/web/static/ux/curio-ux.mjs b/curiosrc/web/static/ux/curio-ux.mjs new file mode 100644 index 00000000000..0b883d1d777 --- /dev/null +++ b/curiosrc/web/static/ux/curio-ux.mjs @@ -0,0 +1,100 @@ +import {LitElement, css, html} from 'https://cdn.jsdelivr.net/gh/lit/dist@3/all/lit-all.min.js'; + +//import 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.esm.js'; + + +class CurioUX extends LitElement { + static styles = css` +\ .curio-slot { + } + :host { + display: block; + margin: 2px 3px; + } + + `; + connectedCallback() { + super.connectedCallback(); + //"https://unpkg.com/@cds/core/global.min.css", + //"https://unpkg.com/@cds/city/css/bundles/default.min.css", + //"https://unpkg.com/@cds/core/styles/theme.dark.min.css", + //"https://unpkg.com/@clr/ui/clr-ui.min.css", + + document.head.innerHTML += ` + + + + + +` + + document.documentElement.lang = 'en'; + + // how Bootstrap & DataTables expect dark mode declared. + document.documentElement.classList.add('dark'); + + this.messsage = this.getCookieMessage(); + } + + render() { + return html` +
+ + + ${this.message? html``: html``} + +
+ + `; + } + + getCookieMessage() { + const name = 'message'; + const cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i++) { + const cookie = cookies[i].trim(); + if (cookie.startsWith(name + '=')) { + var val = cookie.substring(name.length + 1); + document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; + return val; + } + } + return null; + } + +}; + +customElements.define('curio-ux', CurioUX); \ No newline at end of file diff --git a/curiosrc/web/static/ux/main.css b/curiosrc/web/static/ux/main.css new file mode 100644 index 00000000000..c73002ff6e1 --- /dev/null +++ b/curiosrc/web/static/ux/main.css @@ -0,0 +1,53 @@ +@import url('https://fonts.cdnfonts.com/css/metropolis-2'); + +html { + min-height: 100vh; + background: rgb(11, 22, 34); + padding: 0; +} +body { + margin: 0; + padding: 3px 4px; + background: rgb(11, 22, 34); +} +curio-ux { + /* To resemble Clarity Design */ + color: rgb(227, 234, 237); + font-family: Metropolis, monospace; + font-weight: 400; + background: rgb(11, 22, 34); +} + + +.app-head { + width: 100%; +} +.head-left { + display: inline-block; +} +.head-right { + display: inline-block; + float: right; +} + +a { + text-decoration: none; +} + +a:link, a:visited { + color: #adf7ad; +} + +a:hover { + color: #88cc60; +} + +.success { + color: greenyellow; +} +.warning { + color: yellow; +} +.error { + color: red; +} diff --git a/provider/lpwindow/compute_do.go b/curiosrc/window/compute_do.go similarity index 99% rename from provider/lpwindow/compute_do.go rename to curiosrc/window/compute_do.go index 7089ceb027e..fcde14d82f6 100644 --- a/provider/lpwindow/compute_do.go +++ b/curiosrc/window/compute_do.go @@ -1,4 +1,4 @@ -package lpwindow +package window import ( "bytes" @@ -24,7 +24,7 @@ import ( "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" - types "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/storage/sealer" "github.com/filecoin-project/lotus/storage/sealer/storiface" ) @@ -202,7 +202,7 @@ func (t *WdPostTask) DoPartition(ctx context.Context, ts *types.TipSet, maddr ad Proofs: postOut, ChallengedSectors: sinfos, Prover: abi.ActorID(mid), - }); err != nil { + }); err != nil { // revive:disable-line:empty-block /*log.Errorw("window post verification failed", "post", postOut, "error", err) time.Sleep(5 * time.Second) continue todo retry loop */ @@ -337,7 +337,7 @@ func (t *WdPostTask) sectorsForProof(ctx context.Context, maddr address.Address, } func (t *WdPostTask) generateWindowPoSt(ctx context.Context, ppt abi.RegisteredPoStProof, minerID abi.ActorID, sectorInfo []proof.ExtendedSectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, error) { - var retErr error = nil + var retErr error randomness[31] &= 0x3f out := make([]proof.PoStProof, 0) diff --git a/provider/lpwindow/compute_task.go b/curiosrc/window/compute_task.go similarity index 91% rename from provider/lpwindow/compute_task.go rename to curiosrc/window/compute_task.go index e9d5827040c..541a2d5e2c1 100644 --- a/provider/lpwindow/compute_task.go +++ b/curiosrc/window/compute_task.go @@ -1,4 +1,4 @@ -package lpwindow +package window import ( "bytes" @@ -22,20 +22,20 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/curiosrc/chainsched" "github.com/filecoin-project/lotus/lib/harmony/harmonydb" "github.com/filecoin-project/lotus/lib/harmony/harmonytask" "github.com/filecoin-project/lotus/lib/harmony/resources" "github.com/filecoin-project/lotus/lib/harmony/taskhelp" "github.com/filecoin-project/lotus/lib/promise" "github.com/filecoin-project/lotus/node/modules/dtypes" - "github.com/filecoin-project/lotus/provider/chainsched" "github.com/filecoin-project/lotus/storage/sealer" "github.com/filecoin-project/lotus/storage/sealer/sealtasks" "github.com/filecoin-project/lotus/storage/sealer/storiface" "github.com/filecoin-project/lotus/storage/wdpost" ) -var log = logging.Logger("lpwindow") +var log = logging.Logger("curio/window") var EpochsPerDeadline = miner.WPoStProvingPeriod() / abi.ChainEpoch(miner.WPoStPeriodDeadlines) @@ -70,7 +70,7 @@ type WdPostTask struct { windowPoStTF promise.Promise[harmonytask.AddTaskFunc] - actors []dtypes.MinerAddress + actors map[dtypes.MinerAddress]bool max int } @@ -86,9 +86,8 @@ func NewWdPostTask(db *harmonydb.DB, faultTracker sealer.FaultTracker, prover ProverPoSt, verifier storiface.Verifier, - - pcs *chainsched.ProviderChainSched, - actors []dtypes.MinerAddress, + pcs *chainsched.CurioChainSched, + actors map[dtypes.MinerAddress]bool, max int, ) (*WdPostTask, error) { t := &WdPostTask{ @@ -103,8 +102,10 @@ func NewWdPostTask(db *harmonydb.DB, max: max, } - if err := pcs.AddHandler(t.processHeadChange); err != nil { - return nil, err + if pcs != nil { + if err := pcs.AddHandler(t.processHeadChange); err != nil { + return nil, err + } } return t, nil @@ -134,11 +135,34 @@ func (t *WdPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done deadline := wdpost.NewDeadlineInfo(abi.ChainEpoch(pps), dlIdx, head.Height()) - if deadline.PeriodElapsed() { + var testTask *int + isTestTask := func() bool { + if testTask != nil { + return *testTask > 0 + } + + testTask = new(int) + err := t.db.QueryRow(context.Background(), `SELECT COUNT(*) FROM harmony_test WHERE task_id = $1`, taskID).Scan(testTask) + if err != nil { + log.Errorf("WdPostTask.Do() failed to queryRow: %v", err) + return false + } + + return *testTask > 0 + } + + if deadline.PeriodElapsed() && !isTestTask() { log.Errorf("WdPost removed stale task: %v %v", taskID, deadline) return true, nil } + if deadline.Challenge > head.Height() { + if isTestTask() { + deadline = wdpost.NewDeadlineInfo(abi.ChainEpoch(pps)-deadline.WPoStProvingPeriod, dlIdx, head.Height()-deadline.WPoStProvingPeriod) + log.Warnw("Test task is in the future, adjusting to past", "taskID", taskID, "deadline", deadline) + } + } + maddr, err := address.NewIDAddress(spID) if err != nil { log.Errorf("WdPostTask.Do() failed to NewIDAddress: %v", err) @@ -162,11 +186,7 @@ func (t *WdPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done return false, xerrors.Errorf("marshaling PoSt: %w", err) } - testTaskIDCt := 0 - if err = t.db.QueryRow(context.Background(), `SELECT COUNT(*) FROM harmony_test WHERE task_id = $1`, taskID).Scan(&testTaskIDCt); err != nil { - return false, xerrors.Errorf("querying for test task: %w", err) - } - if testTaskIDCt == 1 { + if isTestTask() { // Do not send test tasks to the chain but to harmony_test & stdout. data, err := json.MarshalIndent(map[string]any{ @@ -242,7 +262,6 @@ func (t *WdPostTask) CanAccept(ids []harmonytask.TaskID, te *harmonytask.TaskEng PartitionIndex uint64 dlInfo *dline.Info `pgx:"-"` - openTs *types.TipSet } var tasks []wdTaskDef @@ -264,13 +283,9 @@ func (t *WdPostTask) CanAccept(ids []harmonytask.TaskID, te *harmonytask.TaskEng tasks[i].dlInfo = wdpost.NewDeadlineInfo(tasks[i].ProvingPeriodStart, tasks[i].DeadlineIndex, ts.Height()) if tasks[i].dlInfo.PeriodElapsed() { + // note: Those may be test tasks return &tasks[i].TaskID, nil } - - tasks[i].openTs, err = t.api.ChainGetTipSetAfterHeight(context.Background(), tasks[i].dlInfo.Open, ts.Key()) - if err != nil { - return nil, xerrors.Errorf("getting task open tipset: %w", err) - } } // todo fix the block below @@ -356,7 +371,7 @@ func (t *WdPostTask) Adder(taskFunc harmonytask.AddTaskFunc) { } func (t *WdPostTask) processHeadChange(ctx context.Context, revert, apply *types.TipSet) error { - for _, act := range t.actors { + for act := range t.actors { maddr := address.Address(act) aid, err := address.IDFromAddress(maddr) diff --git a/provider/lpwindow/faults_simple.go b/curiosrc/window/faults_simple.go similarity index 98% rename from provider/lpwindow/faults_simple.go rename to curiosrc/window/faults_simple.go index d43e8ee196a..64f5e86506c 100644 --- a/provider/lpwindow/faults_simple.go +++ b/curiosrc/window/faults_simple.go @@ -1,4 +1,4 @@ -package lpwindow +package window import ( "context" @@ -110,7 +110,7 @@ func (m *SimpleFaultTracker) CheckProvable(ctx context.Context, pp abi.Registere if !locked { log.Warnw("CheckProvable Sector FAULT: can't acquire read lock", "sector", sector) - addBad(sector.ID, fmt.Sprint("can't acquire read lock")) + addBad(sector.ID, "can't acquire read lock") return } diff --git a/provider/lpwindow/recover_task.go b/curiosrc/window/recover_task.go similarity index 93% rename from provider/lpwindow/recover_task.go rename to curiosrc/window/recover_task.go index 12f8522b545..1ed110978c1 100644 --- a/provider/lpwindow/recover_task.go +++ b/curiosrc/window/recover_task.go @@ -1,4 +1,4 @@ -package lpwindow +package window import ( "context" @@ -15,27 +15,27 @@ import ( "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/curiosrc/chainsched" + "github.com/filecoin-project/lotus/curiosrc/message" + "github.com/filecoin-project/lotus/curiosrc/multictladdr" "github.com/filecoin-project/lotus/lib/harmony/harmonydb" "github.com/filecoin-project/lotus/lib/harmony/harmonytask" "github.com/filecoin-project/lotus/lib/harmony/resources" "github.com/filecoin-project/lotus/lib/promise" "github.com/filecoin-project/lotus/node/modules/dtypes" - "github.com/filecoin-project/lotus/provider/chainsched" - "github.com/filecoin-project/lotus/provider/lpmessage" - "github.com/filecoin-project/lotus/storage/ctladdr" "github.com/filecoin-project/lotus/storage/sealer" "github.com/filecoin-project/lotus/storage/wdpost" ) type WdPostRecoverDeclareTask struct { - sender *lpmessage.Sender + sender *message.Sender db *harmonydb.DB api WdPostRecoverDeclareTaskApi faultTracker sealer.FaultTracker maxDeclareRecoveriesGasFee types.FIL - as *ctladdr.AddressSelector - actors []dtypes.MinerAddress + as *multictladdr.MultiAddressSelector + actors map[dtypes.MinerAddress]bool startCheckTF promise.Promise[harmonytask.AddTaskFunc] } @@ -57,15 +57,15 @@ type WdPostRecoverDeclareTaskApi interface { StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error) } -func NewWdPostRecoverDeclareTask(sender *lpmessage.Sender, +func NewWdPostRecoverDeclareTask(sender *message.Sender, db *harmonydb.DB, api WdPostRecoverDeclareTaskApi, faultTracker sealer.FaultTracker, - as *ctladdr.AddressSelector, - pcs *chainsched.ProviderChainSched, + as *multictladdr.MultiAddressSelector, + pcs *chainsched.CurioChainSched, maxDeclareRecoveriesGasFee types.FIL, - actors []dtypes.MinerAddress) (*WdPostRecoverDeclareTask, error) { + actors map[dtypes.MinerAddress]bool) (*WdPostRecoverDeclareTask, error) { t := &WdPostRecoverDeclareTask{ sender: sender, db: db, @@ -77,8 +77,10 @@ func NewWdPostRecoverDeclareTask(sender *lpmessage.Sender, actors: actors, } - if err := pcs.AddHandler(t.processHeadChange); err != nil { - return nil, err + if pcs != nil { + if err := pcs.AddHandler(t.processHeadChange); err != nil { + return nil, err + } } return t, nil @@ -235,7 +237,7 @@ func (w *WdPostRecoverDeclareTask) Adder(taskFunc harmonytask.AddTaskFunc) { func (w *WdPostRecoverDeclareTask) processHeadChange(ctx context.Context, revert, apply *types.TipSet) error { tf := w.startCheckTF.Val(ctx) - for _, act := range w.actors { + for act := range w.actors { maddr := address.Address(act) aid, err := address.IDFromAddress(maddr) diff --git a/provider/lpwindow/submit_task.go b/curiosrc/window/submit_task.go similarity index 91% rename from provider/lpwindow/submit_task.go rename to curiosrc/window/submit_task.go index 72f2499f665..330fd050902 100644 --- a/provider/lpwindow/submit_task.go +++ b/curiosrc/window/submit_task.go @@ -1,4 +1,4 @@ -package lpwindow +package window import ( "bytes" @@ -15,13 +15,13 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/curiosrc/chainsched" + "github.com/filecoin-project/lotus/curiosrc/message" + "github.com/filecoin-project/lotus/curiosrc/multictladdr" "github.com/filecoin-project/lotus/lib/harmony/harmonydb" "github.com/filecoin-project/lotus/lib/harmony/harmonytask" "github.com/filecoin-project/lotus/lib/harmony/resources" "github.com/filecoin-project/lotus/lib/promise" - "github.com/filecoin-project/lotus/provider/chainsched" - "github.com/filecoin-project/lotus/provider/lpmessage" - "github.com/filecoin-project/lotus/storage/ctladdr" "github.com/filecoin-project/lotus/storage/wdpost" ) @@ -42,17 +42,17 @@ type WdPoStSubmitTaskApi interface { } type WdPostSubmitTask struct { - sender *lpmessage.Sender + sender *message.Sender db *harmonydb.DB api WdPoStSubmitTaskApi maxWindowPoStGasFee types.FIL - as *ctladdr.AddressSelector + as *multictladdr.MultiAddressSelector submitPoStTF promise.Promise[harmonytask.AddTaskFunc] } -func NewWdPostSubmitTask(pcs *chainsched.ProviderChainSched, send *lpmessage.Sender, db *harmonydb.DB, api WdPoStSubmitTaskApi, maxWindowPoStGasFee types.FIL, as *ctladdr.AddressSelector) (*WdPostSubmitTask, error) { +func NewWdPostSubmitTask(pcs *chainsched.CurioChainSched, send *message.Sender, db *harmonydb.DB, api WdPoStSubmitTaskApi, maxWindowPoStGasFee types.FIL, as *multictladdr.MultiAddressSelector) (*WdPostSubmitTask, error) { res := &WdPostSubmitTask{ sender: send, db: db, @@ -62,8 +62,10 @@ func NewWdPostSubmitTask(pcs *chainsched.ProviderChainSched, send *lpmessage.Sen as: as, } - if err := pcs.AddHandler(res.processHeadChange); err != nil { - return nil, err + if pcs != nil { + if err := pcs.AddHandler(res.processHeadChange); err != nil { + return nil, err + } } return res, nil @@ -248,7 +250,7 @@ type MsgPrepAPI interface { StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error) } -func preparePoStMessage(w MsgPrepAPI, as *ctladdr.AddressSelector, maddr address.Address, msg *types.Message, maxFee abi.TokenAmount) (*types.Message, *api.MessageSendSpec, error) { +func preparePoStMessage(w MsgPrepAPI, as *multictladdr.MultiAddressSelector, maddr address.Address, msg *types.Message, maxFee abi.TokenAmount) (*types.Message, *api.MessageSendSpec, error) { mi, err := w.StateMinerInfo(context.Background(), maddr, types.EmptyTSK) if err != nil { return nil, nil, xerrors.Errorf("error getting miner info: %w", err) @@ -292,7 +294,7 @@ func preparePoStMessage(w MsgPrepAPI, as *ctladdr.AddressSelector, maddr address goodFunds := big.Add(minGasFeeMsg.RequiredFunds(), minGasFeeMsg.Value) minFunds := big.Min(big.Add(minGasFeeMsg.RequiredFunds(), minGasFeeMsg.Value), goodFunds) - from, _, err := as.AddressFor(context.Background(), w, mi, api.PoStAddr, goodFunds, minFunds) + from, _, err := as.AddressFor(context.Background(), w, maddr, mi, api.PoStAddr, goodFunds, minFunds) if err != nil { return nil, nil, xerrors.Errorf("error getting address: %w", err) } diff --git a/provider/lpwinning/winning_task.go b/curiosrc/winning/winning_task.go similarity index 90% rename from provider/lpwinning/winning_task.go rename to curiosrc/winning/winning_task.go index 907b594fd01..920a7339422 100644 --- a/provider/lpwinning/winning_task.go +++ b/curiosrc/winning/winning_task.go @@ -1,4 +1,4 @@ -package lpwinning +package winning import ( "bytes" @@ -32,7 +32,7 @@ import ( "github.com/filecoin-project/lotus/storage/sealer/storiface" ) -var log = logging.Logger("lpwinning") +var log = logging.Logger("curio/winning") type WinPostTask struct { max int @@ -42,7 +42,7 @@ type WinPostTask struct { verifier storiface.Verifier api WinPostAPI - actors []dtypes.MinerAddress + actors map[dtypes.MinerAddress]bool mineTF promise.Promise[harmonytask.AddTaskFunc] } @@ -70,7 +70,7 @@ type ProverWinningPoSt interface { GenerateWinningPoSt(ctx context.Context, ppt abi.RegisteredPoStProof, minerID abi.ActorID, sectorInfo []storiface.PostSectorChallenge, randomness abi.PoStRandomness) ([]prooftypes.PoStProof, error) } -func NewWinPostTask(max int, db *harmonydb.DB, prover ProverWinningPoSt, verifier storiface.Verifier, api WinPostAPI, actors []dtypes.MinerAddress) *WinPostTask { +func NewWinPostTask(max int, db *harmonydb.DB, prover ProverWinningPoSt, verifier storiface.Verifier, api WinPostAPI, actors map[dtypes.MinerAddress]bool) *WinPostTask { t := &WinPostTask{ max: max, db: db, @@ -107,13 +107,13 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don // First query to fetch from mining_tasks err = t.db.QueryRow(ctx, `SELECT sp_id, epoch, base_compute_time FROM mining_tasks WHERE task_id = $1`, taskID).Scan(&details.SpID, &details.Epoch, &details.CompTime) if err != nil { - return false, err + return false, xerrors.Errorf("query mining base info fail: %w", err) } // Second query to fetch from mining_base_block rows, err := t.db.Query(ctx, `SELECT block_cid FROM mining_base_block WHERE task_id = $1`, taskID) if err != nil { - return false, err + return false, xerrors.Errorf("query mining base blocks fail: %w", err) } defer rows.Close() @@ -126,7 +126,7 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don } if err := rows.Err(); err != nil { - return false, err + return false, xerrors.Errorf("query mining base blocks fail (rows.Err): %w", err) } // construct base @@ -156,13 +156,18 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don ComputeTime: details.CompTime, } - persistNoWin := func() error { - _, err := t.db.Exec(ctx, `UPDATE mining_base_block SET no_win = true WHERE task_id = $1`, taskID) + persistNoWin := func() (bool, error) { + n, err := t.db.Exec(ctx, `UPDATE mining_base_block SET no_win = true WHERE task_id = $1`, taskID) if err != nil { - return xerrors.Errorf("marking base as not-won: %w", err) + return false, xerrors.Errorf("marking base as not-won: %w", err) + } + log.Debugw("persisted no-win", "rows", n) + + if n == 0 { + return false, xerrors.Errorf("persist no win: no rows updated") } - return nil + return true, nil } // ensure we have a beacon entry for the epoch we're mining on @@ -173,7 +178,7 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don }) // MAKE A MINING ATTEMPT!! - log.Debugw("attempting to mine a block", "tipset", types.LogCids(base.TipSet.Cids())) + log.Debugw("attempting to mine a block", "tipset", types.LogCids(base.TipSet.Cids()), "null-rounds", base.AddRounds) mbi, err := t.api.MinerGetBaseInfo(ctx, maddr, round, base.TipSet.Key()) if err != nil { @@ -182,13 +187,13 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don if mbi == nil { // not eligible to mine on this base, we're done here log.Debugw("WinPoSt not eligible to mine on this base", "tipset", types.LogCids(base.TipSet.Cids())) - return true, persistNoWin() + return persistNoWin() } if !mbi.EligibleForMining { // slashed or just have no power yet, we're done here log.Debugw("WinPoSt not eligible for mining", "tipset", types.LogCids(base.TipSet.Cids())) - return true, persistNoWin() + return persistNoWin() } if len(mbi.Sectors) == 0 { @@ -217,10 +222,12 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don if eproof == nil { // not a winner, we're done here log.Debugw("WinPoSt not a winner", "tipset", types.LogCids(base.TipSet.Cids())) - return true, persistNoWin() + return persistNoWin() } } + log.Infow("WinPostTask won election", "tipset", types.LogCids(base.TipSet.Cids()), "miner", maddr, "round", round, "eproof", eproof) + // winning PoSt var wpostProof []prooftypes.PoStProof { @@ -272,6 +279,8 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don } } + log.Infow("WinPostTask winning PoSt computed", "tipset", types.LogCids(base.TipSet.Cids()), "miner", maddr, "round", round, "proofs", wpostProof) + ticket, err := t.computeTicket(ctx, maddr, &rbase, round, base.TipSet.MinTicket(), mbi) if err != nil { return false, xerrors.Errorf("scratching ticket failed: %w", err) @@ -283,6 +292,8 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don return false, xerrors.Errorf("failed to select messages for block: %w", err) } + log.Infow("WinPostTask selected messages", "tipset", types.LogCids(base.TipSet.Cids()), "miner", maddr, "round", round, "messages", len(msgs)) + // equivocation handling { // This next block exists to "catch" equivocating miners, @@ -353,6 +364,8 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don } } + log.Infow("WinPostTask base ready", "tipset", types.LogCids(base.TipSet.Cids()), "miner", maddr, "round", round, "ticket", ticket) + // block construction var blockMsg *types.BlockMsg { @@ -374,6 +387,8 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don } } + log.Infow("WinPostTask block ready", "tipset", types.LogCids(base.TipSet.Cids()), "miner", maddr, "round", round, "block", blockMsg.Header.Cid(), "timestamp", blockMsg.Header.Timestamp) + // persist in db { bhjson, err := json.Marshal(blockMsg.Header) @@ -391,11 +406,13 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don // wait until block timestamp { + log.Infow("WinPostTask waiting for block timestamp", "tipset", types.LogCids(base.TipSet.Cids()), "miner", maddr, "round", round, "block", blockMsg.Header.Cid(), "until", time.Unix(int64(blockMsg.Header.Timestamp), 0)) time.Sleep(time.Until(time.Unix(int64(blockMsg.Header.Timestamp), 0))) } // submit block!! { + log.Infow("WinPostTask submitting block", "tipset", types.LogCids(base.TipSet.Cids()), "miner", maddr, "round", round, "block", blockMsg.Header.Cid()) if err := t.api.SyncSubmitBlock(ctx, blockMsg); err != nil { return false, xerrors.Errorf("failed to submit block: %w", err) } @@ -484,7 +501,7 @@ func (mb MiningBase) baseTime() time.Time { } func (mb MiningBase) afterPropDelay() time.Time { - return mb.baseTime().Add(randTimeOffset(time.Second)) + return mb.baseTime().Add(time.Duration(build.PropagationDelaySecs) * time.Second).Add(randTimeOffset(time.Second)) } func (t *WinPostTask) mineBasic(ctx context.Context) { @@ -567,7 +584,7 @@ func (t *WinPostTask) mineBasic(ctx context.Context) { baseEpoch := workBase.TipSet.Height() - for _, act := range t.actors { + for act := range t.actors { spID, err := address.IDFromAddress(address.Address(act)) if err != nil { log.Errorf("failed to get spID from address %s: %s", act, err) @@ -650,7 +667,7 @@ func (t *WinPostTask) computeTicket(ctx context.Context, maddr address.Address, func randTimeOffset(width time.Duration) time.Duration { buf := make([]byte, 8) - rand.Reader.Read(buf) //nolint:errcheck + _, _ = rand.Reader.Read(buf) val := time.Duration(binary.BigEndian.Uint64(buf) % uint64(width)) return val - (width / 2) diff --git a/documentation/en/actor-events-api.md b/documentation/en/actor-events-api.md new file mode 100644 index 00000000000..801d101b59d --- /dev/null +++ b/documentation/en/actor-events-api.md @@ -0,0 +1,430 @@ +# Actor Events and Lotus APIs + +* [Background](#background) +* [ActorEvent structure](#actorevent-structure) +* [Querying Lotus for ActorEvents](#querying-lotus-for-actorevents) +* [Retrieving events from message receipts](#retrieving-events-from-message-receipts) +* [Current builtin actor event schemas](#current-builtin-actor-event-schemas) + * [Verified registry actor events](#verified-registry-actor-events) + * [Verifier balance](#verifier-balance) + * [Allocation](#allocation) + * [Allocation removed](#allocation-removed) + * [Claim](#claim) + * [Claim updated](#claim-updated) + * [Claim removed](#claim-removed) + * [Market actor events](#market-actor-events) + * [Deal published](#deal-published) + * [Deal activated](#deal-activated) + * [Deal terminated](#deal-terminated) + * [Deal completed](#deal-completed) + * [Miner actor events](#miner-actor-events) + * [Sector precommitted](#sector-precommitted) + * [Sector activated](#sector-activated) + * [Sector updated](#sector-updated) + * [Sector terminated](#sector-terminated) + +## Background + +Actor events are a fire-and-forget mechanism for actors in Filecoin to signal events that occur during execution of their methods to external observers. Actor events are intended to be used by tooling and applications that need to observe and react to events that occur within the chain. The events themselves are not stored in chain state, although a root CID for an array (AMT) of all events emitted for a single message is recorded on message receipts, which are themselves referenced as an array (AMT) in the `ParentMessageReceipts` in each `BlockHeader` of a tipset. A node may optionally retain historical events for querying, but this is not guaranteed and not essential as it does not affect the chain state. + +The FVM already has this capability and new events for builtin actors have been added to support a range of new features, starting at network version 22 with a focus on some information gaps for consumers of data onboarding activity insight due to the introduction of [Direct Data Onboarding (DDO)](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0076.md), plus some additional events related to data onboarding, deal lifecycles, sector lifecycles, and DataCap activity. Additional events are expected to be added in the future to support other features and use cases. + +Builtin actor events share basic similarities to the existing events emitted by user-programmed actors in FVM, but each have a specific schema that reflects their specific concerns. They also all use CBOR encoding for their values. There are also new APIs in Lotus to support querying for these events that bear some similarities to the existing FEVM `Eth*` APIs for querying events but are unique to builtin actors. + +## ActorEvent structure + +Introduced in [FIP-0049](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0049.md), events use a structured logging style of composition, containing a list of entries that define properties of the event. The log entries are described below as `EventEntry` and have the same schema for user-programmed and builtin actor events. `ActorEvent` is specifically for representing builtin actor events and includes the list of entries, the actor that emitted the event, and some metadata about the event. + +```ipldsch +type ActorEvent struct { + entries [EventEntry] # Event entries in log form. + emitter Address # Filecoin address of the actor that emitted this event. + # Reverted is set to true if the message that produced this event was reverted because of a + # network re-org in that case, the event should be considered as reverted as well. + reverted Bool + height ChainEpoch # Height of the tipset that contained the message that produced this event. + tipsetCid &Any # CID of the tipset that contained the message that produced this event. + msgCid &Any # CID of message that produced this event. +} + +type EventEntry struct { + flags Int # A bitmap conveying metadata or hints about this entry. + key String # The key of this entry. + codec Int # The value's IPLD codec. + value Bytes # The value of this entry as a byte string, encoded with 'codec'. +} +``` + +A `flags` field is used to convey metadata or hints about the entry, currently this is used to provide an indication of the suitability of that field for indexing. Suitability for indexing is only a hint, and typically relates to the queriability of the content of that field. + +* A `flag` of `0x00` indicates that neither the key nor value are suitable for indexing. +* A `flag` of `0x01` indicates that the key only is suitable for indexing. +* A `flag` of `0x02` indicates that the value is suitable for indexing. +* A `flag` of `0x03` indicates that both the key and value are suitable for indexing. + +Typically events contain entires that use either use `0x01` or `0x03` flags. + +The structured logging style of composition should be seen in contrast to an alternative representation as a plain map or struct where the keys represent the fields of the event and the values represent the values of those fields. Some entries may duplicate keys, in which case that particular field of the event could be represented as an array. Builtin actor events are sufficiently well defined that translation to such a format is possible, but left up to the user. + +## Querying Lotus for ActorEvents + +Two Lotus APIs are provided that can be used to obtain direct access to events stored on the node being queried (a node may not have all historical events stored and available for query): + +- **[`GetActorEventsRaw`](https://github.com/filecoin-project/lotus/blob/master/documentation/en/api-v1-unstable-methods.md#GetActorEventsRaw)** will return all available historical actor events that match a given *filter* argument. +- **[`SubscribeActorEventsRaw`](https://github.com/filecoin-project/lotus/blob/master/documentation/en/api-v1-unstable-methods.md#SubscribeActorEventsRaw)** will return a long-lived stream providing all available actor events that match a given *filter* argument as they are generated. Optionally also providing a list of historical events. This API is available via websocket from the Lotus API RPC. + +Both APIs take an `EventFilter` as an argument to determine which events to return. This event filter optionally comprises the following: + +- `fromEpoch` determines when to start looking for matching events, either an epoch (in hex form), the string `earliest` or `latest` . A node is not guaranteed to have historical blocks for a particular epoch however `earliest` is intended to provide events from the begining of the available list. +- `toEpoch` determines when to stop looking for matching events, either an epoch (in hex form), the string `earliest` or `latest`. +- `addresses` will match a list of addresses that an event comes *from* (currently just a builtin actor address). +- `fields` is a key to value mapping that matches specific event entries. Each field being matched is a property in the `fields` map and the value of that property is an array of maps, where each entry is a possible matching value for that entry. Each possible match contains a `codec` integer (currently just CBOR `0x51` for builtin actor events described in this document) and a `value` bytes blob (Base64 encoded) of the encoded field value (e.g. a Base64 encoded form of a CBOR encoded key string, such as an actor ID or an event ID). Matching first involves finding if an event’s entries contain one of the desired `key`s, then checking that one of the value matchers for that `key` field matches the value. Value matching is performed both on the `codec` and the `value` bytes. If an event’s entry is matched, the entire event is considered a match. This may be used to query for particular event types, such as `allocation`. +An example `fields` with a single matcher would look like: `"fields": { "abc": [{ "codec": 81, "value": "ZGRhdGE=" }]}` where the key being matched is `abc` with the CBOR codec (`0x51` = `81`) and value is the unicode string `data` encoded as CBOR (then encoded in Base64 to supply to the filter). +- `tipsetCid` matches a particular TipSet. If this is provided, both `fromBlock` and `toBlock` will be ignored. + +Described as an [IPLD Schema](https://ipld.io/docs/schemas/), the event filter is: + +```ipldsch +type EventFilter struct { + fromEpoch optional String + toEpoch optional String + addresses optional [Address] + fields optional {String:[ActorEventValue]} + tipsetCid optional &Any +} + +type Address string # Address of an actor + +type ActorEventValue struct { + codec Int # typically the CBOR codec (0x51) + value Bytes # typically the CBOR encoded value +} +``` + +## Retrieving events from message receipts + +The Lotus API `ChainGetEvents` can be used to retrieve events given an event root CID. This CID is attached to the message receipt that generated the events. The `StateSearchMsg` API can be used to retrieve the message receipt given a message CID, the receipt contains the `EventsRoot` CID. The events returned from `ChainGetEvents` contain roughly the same information as the `ActorEvent` structure, including the `EventEntry` log array. + +## Current builtin actor event schemas + +Schemas for currently implemented builtin actor events are provided below. They follow the log structure, where each line in the schema table represents an `EventEntry` in the `ActorEvent` entry list. For simplicity, the `flags` are presented as either `k` for `0x01` (index key) or `kv` for `0x03` (index key and value) and the `codec` is always `0x51` for builtin actors so is omitted. + +_Note that the "bigint" CBOR encoding format used below is the same as is used for encoding bigints on the Filecoin chain: a byte array representing a big-endian unsigned integer, compatible with the Golang `big.Int` byte representation, with a `0x00` (positive) or `0x01` (negative) prefix; with a zero-length array representing a value of `0`._ + +The following events are defined in FIP-0083. Additional events will be added here as they are accepted by FIP. + +### Verified registry actor events + +#### Verifier balance + +The `verifier-balance` event is emitted when the balance of a verifier is updated in the Verified Registry actor. + +| Key | Value | Flags | +|-------------|-------------------------------------|-------| +| `"$type"` | `"verifier-balance"` (string) | kv | +| `"verifier"`| (int) | kv | +| `"balance"` | (bigint) | k | + +In structured form, this event would look like: + +```ipldsch +type DataCap Bytes # A bigint representing a DataCap + +type VerifierBalanceEvent struct { + verifier Int + balance DataCap +} +``` + +#### Allocation + +The `allocation` event is emitted when a verified client allocates DataCap to a specific data piece and storage provider. + +| Key | Value | Flags | +| ------------ | ----------------------- | ----- | +| `"$type"` | `"allocation"` (string) | kv | +| `"id"` | (int) | kv | +| `"client"` | (int) | kv | +| `"provider"` | (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type AllocationEvent struct { + id Int + client Int + provider Int +} +``` + +#### Allocation removed + +The `allocation-removed` event is emitted when a DataCap allocation that is past its expiration epoch is removed. + +| Key | Value | Flags | +| ------------ | ------------------------------- | ----- | +| `"$type"` | `"allocation-removed"` (string) | kv | +| `"id"` | (int) | kv | +| `"client"` | (int) | kv | +| `"provider"` | (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type AllocationRemovedEvent struct { + id Int + client Int + provider Int +} +``` + +#### Claim + +The `claim` event is emitted when a client allocation is claimed by a storage provider after the corresponding verified data is provably committed to the chain. + +| Key | Value | Flags | +| ------------ | ----------------------- | ----- | +| `"$type"` | `"claim"` (string) | kv | +| `"id"` | (int) | kv | +| `"client"` | (int) | kv | +| `"provider"` | (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type ClaimEvent struct { + id Int + client Int + provider Int +} +``` + +#### Claim updated + +The `claim-updated` event is emitted when the term of an existing allocation is extended by the client. + +| Key | Value | Flags | +| ------------ | -------------------------- | ----- | +| `"$type"` | `"claim-updated"` (string) | kv | +| `"id"` | (int) | kv | +| `"client"` | (int) | kv | +| `"provider"` | (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type ClaimUpdatedEvent struct { + id Int + client Int + provider Int +} +``` + +#### Claim removed + +The `claim-removed` event is emitted when an expired claim is removed by the Verified Registry actor. + +| Key | Value | Flags | +| ------------ | -------------------------- | ----- | +| `"$type"` | `"claim-removed"` (string) | kv | +| `"id"` | (int) | kv | +| `"client"` | (int) | kv | +| `"provider"` | (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type ClaimRemovedEvent struct { + id Int + client Int + provider Int +} +``` + +### Market actor events + +The Market actor emits the following deal lifecycle events: + +#### Deal published + +The `deal-published` event is emitted for each new deal that is successfully published by a storage provider. + +| Key | Value | Flags | +| ----------- | --------------------------------- | ----- | +| `"$type"` | `"deal-published"` (string) | kv | +| `"id"` | (int) | kv | +| `"client"` | (int) | kv | +| `"provider"`| (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type DealPublishedEvent struct { + id Int + client Int + provider Int +} +``` + +#### Deal activated + +The `deal-activated` event is emitted for each deal that is successfully activated. + +| Key | Value | Flags | +| ------------ | --------------------------------- | ----- | +| `"$type"` | `"deal-activated"` (string) | kv | +| `"id"` | (int) | kv | +| `"client"` | (int) | kv | +| `"provider"` | (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type DealActivatedEvent struct { + id Int + client Int + provider Int +} +``` + +#### Deal terminated + +The `deal-terminated` event is emitted by the market actor cron job when it processes deals that were marked as terminated by the `OnMinerSectorsTerminate` method. + +[FIP-0074](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0074.md) ensures that terminated deals are processed immediately in the `OnMinerSectorsTerminate` method rather than being submitted for deferred processing to the market actor cron job. As of network version 22 this event will be emitted to indicate that a deal has been terminated for deals made after network version 22. + +| Key | Value | Flags | +| ----------- | --------------------------------- | ----- | +| `"$type"` | `"deal-terminated"` (string) | kv | +| `"id"` | (int) | kv | +| `"client"` | (int) | kv | +| `"provider"`| (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type DealTerminatedEvent struct { + id Int + client Int + provider Int +} +``` + +#### Deal completed + +The `deal-completed` event is emitted when a deal is marked as successfully complete by the Market actor cron job. The cron job will deem a deal to be successfully completed if it is past it’s end epoch without being slashed. + +[FIP-0074](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0074.md) ensures that the processing of completed deals is done as part of a method called by the storage provider thus making this event available to clients and also to ensure that storage providers pay the gas costs of processing deal completion and event emission. This applies to new deals made after network version 22. For deals made before network version 22, this event will be emitted by the market actor cron job. + +| Key | Value | Flags | +| ----------- | --------------------------------- | ----- | +| `"$type"` | `"deal-completed"` (string) | kv | +| `"id"` | (int) | kv | +| `"client"` | (int) | kv | +| `"provider"`| (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type DealCompletedEvent struct { + id Int + client Int + provider Int +} +``` + +### Miner actor events + +The Miner actor emits the following sector lifecycle events: + +#### Sector precommitted + +The `sector-precommitted` event is emitted for each new sector that is successfully pre-committed by a storage provider. + +| Key | Value | Flags | +| ---------- | -------------------------------- | ----- | +| `"$type"` | `"sector-precommitted"` (string) | kv | +| `"sector"` | (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type SectorPrecommittedEvent struct { + sector Int +} +``` + +#### Sector activated + +The `sector-activated` event is emitted for each pre-committed sector that is successfully activated by a storage provider. For now, sector activation corresponds 1:1 with prove-committing a sector but this can change in the future. + +| Key | Value | Flags | +| ---------------- | ------------------------------------------------------------- | ----- | +| `"$type"` | `"sector-activated"` (string) | kv | +| `"sector"` | (int) | kv | +| `"unsealed-cid"` | (nullable CID) (null means sector has no data) | kv | +| `"piece-cid"` | (CID) | kv | +| `"piece-size"` | (int) | k | + +_Note that both `"piece-cid"` and `"piece-size"` entries will be included for each piece in the sector, so the keys are repeated._ + +In structured form, this event would look like: + +```ipldsch +type PieceDescription struct { + cid &Any + size Int +} + +type SectorActivatedEvent struct { + sector Int + unsealedCid nullable &Any + pieces [PieceDescription] +} +``` + +#### Sector updated + +The `sector-updated` event is emitted for each CC sector that is updated to contained actual sealed data. + +| Key | Value | Flags | +| --------------- | ------------------------------------------------------------- | ----- | +| `"$type"` | `"sector-updated"` (string) | kv | +| `"sector"` | (int) | kv | +| `"unsealed-cid"`| (nullable CID) (null means sector has no data) | kv | +| `"piece-cid"` | (CID) | kv | +| `"piece-size"` | (int) | k | + +_Note that both `"piece-cid"` and `"piece-size"` entries will be included for each piece in the sector, so the keys are repeated._ + +In structured form, this event would look like: + +```ipldsch +type PieceDescription struct { + cid &Any + size Int +} + +type SectorUpdatedEvent struct { + sector Int + unsealedCid nullable &Any + pieces [PieceDescription] +} +``` + +#### Sector terminated + +The `sector-terminated` event is emitted for each sector that is marked as terminated by a storage provider. + +| Key | Value | Flags | +| ----------- | ------------------------------ | ----- | +| `"$type"` | `"sector-terminated"` (string) | kv | +| `"sector"` | (int) | kv | + +In structured form, this event would look like: + +```ipldsch +type SectorTerminatedEvent struct { + sector Int +} +``` diff --git a/documentation/en/api-v0-methods-curio.md b/documentation/en/api-v0-methods-curio.md new file mode 100644 index 00000000000..0bfe09af5cb --- /dev/null +++ b/documentation/en/api-v0-methods-curio.md @@ -0,0 +1,369 @@ +# Groups +* [](#) + * [Shutdown](#Shutdown) + * [Version](#Version) +* [Allocate](#Allocate) + * [AllocatePieceToSector](#AllocatePieceToSector) +* [Log](#Log) + * [LogList](#LogList) + * [LogSetLevel](#LogSetLevel) +* [Storage](#Storage) + * [StorageAddLocal](#StorageAddLocal) + * [StorageDetachLocal](#StorageDetachLocal) + * [StorageFindSector](#StorageFindSector) + * [StorageInfo](#StorageInfo) + * [StorageInit](#StorageInit) + * [StorageList](#StorageList) + * [StorageLocal](#StorageLocal) + * [StorageStat](#StorageStat) +## + + +### Shutdown +Trigger shutdown + + +Perms: admin + +Inputs: `null` + +Response: `{}` + +### Version + + +Perms: admin + +Inputs: `null` + +Response: `131840` + +## Allocate + + +### AllocatePieceToSector + + +Perms: write + +Inputs: +```json +[ + "f01234", + { + "PublishCid": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "DealID": 5432, + "DealProposal": { + "PieceCID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "PieceSize": 1032, + "VerifiedDeal": true, + "Client": "f01234", + "Provider": "f01234", + "Label": "", + "StartEpoch": 10101, + "EndEpoch": 10101, + "StoragePricePerEpoch": "0", + "ProviderCollateral": "0", + "ClientCollateral": "0" + }, + "DealSchedule": { + "StartEpoch": 10101, + "EndEpoch": 10101 + }, + "PieceActivationManifest": { + "CID": { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + "Size": 2032, + "VerifiedAllocationKey": null, + "Notify": null + }, + "KeepUnsealed": true + }, + 9, + { + "Scheme": "string value", + "Opaque": "string value", + "User": {}, + "Host": "string value", + "Path": "string value", + "RawPath": "string value", + "OmitHost": true, + "ForceQuery": true, + "RawQuery": "string value", + "Fragment": "string value", + "RawFragment": "string value" + }, + { + "Authorization": [ + "Bearer ey.." + ] + } +] +``` + +Response: +```json +{ + "Sector": 9, + "Offset": 1032 +} +``` + +## Log + + +### LogList + + +Perms: read + +Inputs: `null` + +Response: +```json +[ + "string value" +] +``` + +### LogSetLevel + + +Perms: admin + +Inputs: +```json +[ + "string value", + "string value" +] +``` + +Response: `{}` + +## Storage + + +### StorageAddLocal + + +Perms: admin + +Inputs: +```json +[ + "string value" +] +``` + +Response: `{}` + +### StorageDetachLocal + + +Perms: admin + +Inputs: +```json +[ + "string value" +] +``` + +Response: `{}` + +### StorageFindSector + + +Perms: admin + +Inputs: +```json +[ + { + "Miner": 1000, + "Number": 9 + }, + 1, + 34359738368, + true +] +``` + +Response: +```json +[ + { + "ID": "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + "URLs": [ + "string value" + ], + "BaseURLs": [ + "string value" + ], + "Weight": 42, + "CanSeal": true, + "CanStore": true, + "Primary": true, + "AllowTypes": [ + "string value" + ], + "DenyTypes": [ + "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" + ] + } +] +``` + +### StorageInfo + + +Perms: admin + +Inputs: +```json +[ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8" +] +``` + +Response: +```json +{ + "ID": "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + "URLs": [ + "string value" + ], + "Weight": 42, + "MaxStorage": 42, + "CanSeal": true, + "CanStore": true, + "Groups": [ + "string value" + ], + "AllowTo": [ + "string value" + ], + "AllowTypes": [ + "string value" + ], + "DenyTypes": [ + "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" + ] +} +``` + +### StorageInit + + +Perms: admin + +Inputs: +```json +[ + "string value", + { + "ID": "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8", + "Weight": 42, + "CanSeal": true, + "CanStore": true, + "MaxStorage": 42, + "Groups": [ + "string value" + ], + "AllowTo": [ + "string value" + ], + "AllowTypes": [ + "string value" + ], + "DenyTypes": [ + "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" + ] + } +] +``` + +Response: `{}` + +### StorageList + + +Perms: admin + +Inputs: `null` + +Response: +```json +{ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8": [ + { + "Miner": 1000, + "Number": 100, + "SectorFileType": 2 + } + ] +} +``` + +### StorageLocal + + +Perms: admin + +Inputs: `null` + +Response: +```json +{ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8": "/data/path" +} +``` + +### StorageStat + + +Perms: admin + +Inputs: +```json +[ + "76f1988b-ef30-4d7e-b3ec-9a627f4ba5a8" +] +``` + +Response: +```json +{ + "Capacity": 9, + "Available": 9, + "FSAvailable": 9, + "Reserved": 9, + "Max": 9, + "Used": 9 +} +``` + diff --git a/documentation/en/api-v0-methods-miner.md b/documentation/en/api-v0-methods-miner.md index b133930bc7c..802cd3ce591 100644 --- a/documentation/en/api-v0-methods-miner.md +++ b/documentation/en/api-v0-methods-miner.md @@ -3735,6 +3735,12 @@ Inputs: ], "DenyTypes": [ "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" ] }, { @@ -3782,7 +3788,8 @@ Inputs: [ 1, 34359738368, - "sealing" + "sealing", + 1000 ] ``` @@ -3809,6 +3816,12 @@ Response: ], "DenyTypes": [ "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" ] } ] @@ -3928,6 +3941,12 @@ Response: ], "DenyTypes": [ "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" ] } ] @@ -3954,6 +3973,7 @@ Response: 0, 1, 0, + 0, 0 ], "Read": [ @@ -3961,6 +3981,7 @@ Response: 3, 0, 0, + 0, 0 ] } @@ -4002,6 +4023,12 @@ Response: ], "DenyTypes": [ "string value" + ], + "AllowMiners": [ + "string value" + ], + "DenyMiners": [ + "string value" ] } ``` diff --git a/documentation/en/api-v0-methods-provider.md b/documentation/en/api-v0-methods-provider.md deleted file mode 100644 index fc4a2daf7b3..00000000000 --- a/documentation/en/api-v0-methods-provider.md +++ /dev/null @@ -1,25 +0,0 @@ -# Groups -* [](#) - * [Shutdown](#Shutdown) - * [Version](#Version) -## - - -### Shutdown - - -Perms: admin - -Inputs: `null` - -Response: `{}` - -### Version - - -Perms: admin - -Inputs: `null` - -Response: `131840` - diff --git a/documentation/en/api-v0-methods.md b/documentation/en/api-v0-methods.md index 19c3ca48195..9a8c4821b4b 100644 --- a/documentation/en/api-v0-methods.md +++ b/documentation/en/api-v0-methods.md @@ -5965,12 +5965,12 @@ Response: "InitialPledge": "0", "ExpectedDayReward": "0", "ExpectedStoragePledge": "0", - "ReplacedSectorAge": 10101, + "PowerBaseEpoch": 10101, "ReplacedDayReward": "0", "SectorKeyCID": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "SimpleQAPower": true + "Flags": 0 } ] ``` @@ -6445,12 +6445,12 @@ Response: "InitialPledge": "0", "ExpectedDayReward": "0", "ExpectedStoragePledge": "0", - "ReplacedSectorAge": 10101, + "PowerBaseEpoch": 10101, "ReplacedDayReward": "0", "SectorKeyCID": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "SimpleQAPower": true + "Flags": 0 } ] ``` @@ -6872,12 +6872,12 @@ Response: "InitialPledge": "0", "ExpectedDayReward": "0", "ExpectedStoragePledge": "0", - "ReplacedSectorAge": 10101, + "PowerBaseEpoch": 10101, "ReplacedDayReward": "0", "SectorKeyCID": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "SimpleQAPower": true + "Flags": 0 } ``` @@ -7594,7 +7594,7 @@ Inputs: Response: `"f01234"` ### WalletSetDefault -WalletSetDefault marks the given address as as the default one. +WalletSetDefault marks the given address as the default one. Perms: write diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index 33315e221e7..8dab4f35f3d 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -213,9 +213,6 @@ * [PaychVoucherCreate](#PaychVoucherCreate) * [PaychVoucherList](#PaychVoucherList) * [PaychVoucherSubmit](#PaychVoucherSubmit) -* [Raft](#Raft) - * [RaftLeader](#RaftLeader) - * [RaftState](#RaftState) * [Start](#Start) * [StartTime](#StartTime) * [State](#State) @@ -6251,33 +6248,6 @@ Response: } ``` -## Raft - - -### RaftLeader - - -Perms: read - -Inputs: `null` - -Response: `"12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf"` - -### RaftState - - -Perms: read - -Inputs: `null` - -Response: -```json -{ - "NonceMap": {}, - "MsgUuids": {} -} -``` - ## Start @@ -7683,12 +7653,12 @@ Response: "InitialPledge": "0", "ExpectedDayReward": "0", "ExpectedStoragePledge": "0", - "ReplacedSectorAge": 10101, + "PowerBaseEpoch": 10101, "ReplacedDayReward": "0", "SectorKeyCID": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "SimpleQAPower": true + "Flags": 0 } ] ``` @@ -8191,12 +8161,12 @@ Response: "InitialPledge": "0", "ExpectedDayReward": "0", "ExpectedStoragePledge": "0", - "ReplacedSectorAge": 10101, + "PowerBaseEpoch": 10101, "ReplacedDayReward": "0", "SectorKeyCID": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "SimpleQAPower": true + "Flags": 0 } ] ``` @@ -8572,12 +8542,12 @@ Response: "InitialPledge": "0", "ExpectedDayReward": "0", "ExpectedStoragePledge": "0", - "ReplacedSectorAge": 10101, + "PowerBaseEpoch": 10101, "ReplacedDayReward": "0", "SectorKeyCID": { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" }, - "SimpleQAPower": true + "Flags": 0 } ``` @@ -9314,7 +9284,7 @@ Inputs: Response: `"f01234"` ### WalletSetDefault -WalletSetDefault marks the given address as as the default one. +WalletSetDefault marks the given address as the default one. Perms: write diff --git a/documentation/en/cli-curio.md b/documentation/en/cli-curio.md new file mode 100644 index 00000000000..9f578154c7a --- /dev/null +++ b/documentation/en/cli-curio.md @@ -0,0 +1,563 @@ +# curio +``` +NAME: + curio - Filecoin decentralized storage network provider + +USAGE: + curio [global options] command [command options] [arguments...] + +VERSION: + 1.27.0 + +COMMANDS: + cli Execute cli commands + run Start a Curio process + stop Stop a running Curio process + config Manage node config by layers. The layer 'base' will always be applied at Curio start-up. + test Utility functions for testing + web Start Curio web interface + guided-setup Run the guided setup for migrating from lotus-miner to Curio or Creating a new Curio miner + seal Manage the sealing pipeline + market + fetch-params Fetch proving parameters + help, h Shows a list of commands or help for one command + +GLOBAL OPTIONS: + --color use color in display output (default: depends on output being a TTY) + --db-host value Command separated list of hostnames for yugabyte cluster (default: "127.0.0.1") [$CURIO_DB_HOST, $CURIO_HARMONYDB_HOSTS] + --db-name value (default: "yugabyte") [$CURIO_DB_NAME, $CURIO_HARMONYDB_NAME] + --db-user value (default: "yugabyte") [$CURIO_DB_USER, $CURIO_HARMONYDB_USERNAME] + --db-password value (default: "yugabyte") [$CURIO_DB_PASSWORD, $CURIO_HARMONYDB_PASSWORD] + --db-port value (default: "5433") [$CURIO_DB_PORT, $CURIO_HARMONYDB_PORT] + --repo-path value (default: "~/.curio") [$CURIO_REPO_PATH] + --vv enables very verbose mode, useful for debugging the CLI (default: false) + --help, -h show help + --version, -v print the version +``` + +## curio cli +``` +NAME: + curio cli - Execute cli commands + +USAGE: + curio cli command [command options] [arguments...] + +COMMANDS: + storage manage sector storage + log Manage logging + wait-api Wait for Curio api to come online + help, h Shows a list of commands or help for one command + +OPTIONS: + --machine value machine host:port (curio run --listen address) + --help, -h show help +``` + +### curio cli storage +``` +NAME: + curio cli storage - manage sector storage + +USAGE: + curio cli storage command [command options] [arguments...] + +DESCRIPTION: + Sectors can be stored across many filesystem paths. These + commands provide ways to manage the storage the miner will used to store sectors + long term for proving (references as 'store') as well as how sectors will be + stored while moving through the sealing pipeline (references as 'seal'). + +COMMANDS: + attach attach local storage path + detach detach local storage path + list list local storage paths + find find sector in the storage system + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` + +#### curio cli storage attach +``` +NAME: + curio cli storage attach - attach local storage path + +USAGE: + curio cli storage attach [command options] [path] + +DESCRIPTION: + Storage can be attached to the miner using this command. The storage volume + list is stored local to the miner in storage.json set in curio run. We do not + recommend manually modifying this value without further understanding of the + storage system. + + Each storage volume contains a configuration file which describes the + capabilities of the volume. When the '--init' flag is provided, this file will + be created using the additional flags. + + Weight + A high weight value means data will be more likely to be stored in this path + + Seal + Data for the sealing process will be stored here + + Store + Finalized sectors that will be moved here for long term storage and be proven + over time + + +OPTIONS: + --init initialize the path first (default: false) + --weight value (for init) path weight (default: 10) + --seal (for init) use path for sealing (default: false) + --store (for init) use path for long-term storage (default: false) + --max-storage value (for init) limit storage space for sectors (expensive for very large paths!) + --groups value [ --groups value ] path group names + --allow-to value [ --allow-to value ] path groups allowed to pull data from this path (allow all if not specified) + --help, -h show help +``` + +#### curio cli storage detach +``` +NAME: + curio cli storage detach - detach local storage path + +USAGE: + curio cli storage detach [command options] [path] + +OPTIONS: + --really-do-it (default: false) + --help, -h show help +``` + +#### curio cli storage list +``` +NAME: + curio cli storage list - list local storage paths + +USAGE: + curio cli storage list [command options] [arguments...] + +OPTIONS: + --local only list local storage paths (default: false) + --help, -h show help +``` + +#### curio cli storage find +``` +NAME: + curio cli storage find - find sector in the storage system + +USAGE: + curio cli storage find [command options] [miner address] [sector number] + +OPTIONS: + --help, -h show help +``` + +### curio cli log +``` +NAME: + curio cli log - Manage logging + +USAGE: + curio cli log command [command options] [arguments...] + +COMMANDS: + list List log systems + set-level Set log level + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` + +#### curio cli log list +``` +NAME: + curio cli log list - List log systems + +USAGE: + curio cli log list [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` + +#### curio cli log set-level +``` +NAME: + curio cli log set-level - Set log level + +USAGE: + curio cli log set-level [command options] [level] + +DESCRIPTION: + Set the log level for logging systems: + + The system flag can be specified multiple times. + + eg) log set-level --system chain --system chainxchg debug + + Available Levels: + debug + info + warn + error + + Environment Variables: + GOLOG_LOG_LEVEL - Default log level for all log systems + 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 [ --system value ] limit to log system + --help, -h show help +``` + +### curio cli wait-api +``` +NAME: + curio cli wait-api - Wait for Curio api to come online + +USAGE: + curio cli wait-api [command options] [arguments...] + +OPTIONS: + --timeout value duration to wait till fail (default: 30s) + --help, -h show help +``` + +## curio run +``` +NAME: + curio run - Start a Curio process + +USAGE: + curio run [command options] [arguments...] + +OPTIONS: + --listen value host address and port the worker api will listen on (default: "0.0.0.0:12300") [$LOTUS_WORKER_LISTEN] + --nosync don't check full-node sync status (default: false) + --manage-fdlimit manage open file limit (default: true) + --storage-json value path to json file containing storage config (default: "~/.curio/storage.json") + --journal value path to journal files (default: "~/.curio/") + --layers value, -l value, --layer value [ --layers value, -l value, --layer value ] list of layers to be interpreted (atop defaults). Default: base + --help, -h show help +``` + +## curio stop +``` +NAME: + curio stop - Stop a running Curio process + +USAGE: + curio stop [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` + +## curio config +``` +NAME: + curio config - Manage node config by layers. The layer 'base' will always be applied at Curio start-up. + +USAGE: + curio config command [command options] [arguments...] + +COMMANDS: + default, defaults Print default node config + set, add, update, create Set a config layer or the base by providing a filename or stdin. + get, cat, show Get a config layer by name. You may want to pipe the output to a file, or use 'less' + list, ls List config layers present in the DB. + interpret, view, stacked, stack Interpret stacked config layers by this version of curio, with system-generated comments. + remove, rm, del, delete Remove a named config layer. + edit edit a config layer + new-cluster Create new configuration for a new cluster + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` + +### curio config default +``` +NAME: + curio config default - Print default node config + +USAGE: + curio config default [command options] [arguments...] + +OPTIONS: + --no-comment don't comment default values (default: false) + --help, -h show help +``` + +### curio config set +``` +NAME: + curio config set - Set a config layer or the base by providing a filename or stdin. + +USAGE: + curio config set [command options] a layer's file name + +OPTIONS: + --title value title of the config layer (req'd for stdin) + --help, -h show help +``` + +### curio config get +``` +NAME: + curio config get - Get a config layer by name. You may want to pipe the output to a file, or use 'less' + +USAGE: + curio config get [command options] layer name + +OPTIONS: + --help, -h show help +``` + +### curio config list +``` +NAME: + curio config list - List config layers present in the DB. + +USAGE: + curio config list [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` + +### curio config interpret +``` +NAME: + curio config interpret - Interpret stacked config layers by this version of curio, with system-generated comments. + +USAGE: + curio config interpret [command options] a list of layers to be interpreted as the final config + +OPTIONS: + --layers value [ --layers value ] comma or space separated list of layers to be interpreted (base is always applied) + --help, -h show help +``` + +### curio config remove +``` +NAME: + curio config remove - Remove a named config layer. + +USAGE: + curio config remove [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` + +### curio config edit +``` +NAME: + curio config edit - edit a config layer + +USAGE: + curio config edit [command options] [layer name] + +OPTIONS: + --editor value editor to use (default: "vim") [$EDITOR] + --source value source config layer (default: ) + --allow-overwrite allow overwrite of existing layer if source is a different layer (default: false) + --no-source-diff save the whole config into the layer, not just the diff (default: false) + --no-interpret-source do not interpret source layer (default: true if --source is set) + --help, -h show help +``` + +### curio config new-cluster +``` +NAME: + curio config new-cluster - Create new configuration for a new cluster + +USAGE: + curio config new-cluster [command options] [SP actor address...] + +OPTIONS: + --help, -h show help +``` + +## curio test +``` +NAME: + curio test - Utility functions for testing + +USAGE: + curio test command [command options] [arguments...] + +COMMANDS: + window-post, wd, windowpost, wdpost Compute a proof-of-spacetime for a sector (requires the sector to be pre-sealed). These will not send to the chain. + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` + +### curio test window-post +``` +NAME: + curio test window-post - Compute a proof-of-spacetime for a sector (requires the sector to be pre-sealed). These will not send to the chain. + +USAGE: + curio test window-post command [command options] [arguments...] + +COMMANDS: + here, cli Compute WindowPoSt for performance and configuration testing. + task, scheduled, schedule, async, asynchronous Test the windowpost scheduler by running it on the next available curio. + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` + +#### curio test window-post here +``` +NAME: + curio test window-post here - Compute WindowPoSt for performance and configuration testing. + +USAGE: + curio test window-post here [command options] [deadline index] + +DESCRIPTION: + Note: This command is intended to be used to verify PoSt compute performance. + It will not send any messages to the chain. Since it can compute any deadline, output may be incorrectly timed for the chain. + +OPTIONS: + --deadline value deadline to compute WindowPoSt for (default: 0) + --layers value [ --layers value ] list of layers to be interpreted (atop defaults). Default: base + --storage-json value path to json file containing storage config (default: "~/.curio/storage.json") + --partition value partition to compute WindowPoSt for (default: 0) + --help, -h show help +``` + +#### curio test window-post task +``` +NAME: + curio test window-post task - Test the windowpost scheduler by running it on the next available curio. + +USAGE: + curio test window-post task [command options] [arguments...] + +OPTIONS: + --deadline value deadline to compute WindowPoSt for (default: 0) + --layers value [ --layers value ] list of layers to be interpreted (atop defaults). Default: base + --help, -h show help +``` + +## curio web +``` +NAME: + curio web - Start Curio web interface + +USAGE: + curio web [command options] [arguments...] + +DESCRIPTION: + Start an instance of Curio web interface. + This creates the 'web' layer if it does not exist, then calls run with that layer. + +OPTIONS: + --listen value Address to listen on (default: "127.0.0.1:4701") + --nosync don't check full-node sync status (default: false) + --layers value [ --layers value ] list of layers to be interpreted (atop defaults). Default: base + --help, -h show help +``` + +## curio guided-setup +``` +NAME: + curio guided-setup - Run the guided setup for migrating from lotus-miner to Curio or Creating a new Curio miner + +USAGE: + curio guided-setup [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` + +## curio seal +``` +NAME: + curio seal - Manage the sealing pipeline + +USAGE: + curio seal command [command options] [arguments...] + +COMMANDS: + start Start new sealing operations manually + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` + +### curio seal start +``` +NAME: + curio seal start - Start new sealing operations manually + +USAGE: + curio seal start [command options] [arguments...] + +OPTIONS: + --actor value Specify actor address to start sealing sectors for + --now Start sealing sectors for all actors now (not on schedule) (default: false) + --cc Start sealing new CC sectors (default: false) + --count value Number of sectors to start (default: 1) + --synthetic Use synthetic PoRep (default: false) + --layers value [ --layers value ] list of layers to be interpreted (atop defaults). Default: base + --help, -h show help +``` + +## curio market +``` +NAME: + curio market + +USAGE: + curio market command [command options] [arguments...] + +COMMANDS: + rpc-info + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` + +### curio market rpc-info +``` +NAME: + curio market rpc-info + +USAGE: + curio market rpc-info [command options] [arguments...] + +OPTIONS: + --layers value [ --layers value ] list of layers to be interpreted (atop defaults). Default: base + --help, -h show help +``` + +## curio fetch-params +``` +NAME: + curio fetch-params - Fetch proving parameters + +USAGE: + curio fetch-params [command options] [sectorSize] + +OPTIONS: + --help, -h show help +``` diff --git a/documentation/en/cli-lotus-miner.md b/documentation/en/cli-lotus-miner.md index 4a5ec05789c..b54508224c6 100644 --- a/documentation/en/cli-lotus-miner.md +++ b/documentation/en/cli-lotus-miner.md @@ -7,24 +7,23 @@ USAGE: lotus-miner [global options] command [command options] [arguments...] VERSION: - 1.26.2 + 1.27.0 COMMANDS: - init Initialize a lotus miner repo - run Start a lotus miner process - stop Stop a running lotus miner - config Manage node config - backup Create node metadata backup - version Print version - help, h Shows a list of commands or help for one command + init Initialize a lotus miner repo + run Start a lotus miner process + stop Stop a running lotus miner + config Manage node config + backup Create node metadata backup + auth Manage RPC permissions + log Manage logging + wait-api Wait for lotus api to come online + fetch-params Fetch proving parameters + version Print version + help, h Shows a list of commands or help for one command CHAIN: actor manipulate the miner actor info Print miner info - DEVELOPER: - auth Manage RPC permissions - log Manage logging - wait-api Wait for lotus api to come online - fetch-params Fetch proving parameters STORAGE: sectors interact with sector store proving View proving information @@ -66,6 +65,7 @@ OPTIONS: --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 + --confidence value number of block confirmations to wait for (default: 5) --help, -h show help ``` @@ -193,6 +193,150 @@ OPTIONS: --help, -h show help ``` +## lotus-miner auth +``` +NAME: + lotus-miner auth - Manage RPC permissions + +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 + +OPTIONS: + --help, -h show help +``` + +### lotus-miner auth create-token +``` +NAME: + lotus-miner auth create-token - Create token + +USAGE: + lotus-miner auth create-token [command options] [arguments...] + +OPTIONS: + --perm value permission to assign to the token, one of: read, write, sign, admin + --help, -h show help +``` + +### lotus-miner auth api-info +``` +NAME: + lotus-miner auth api-info - Get token with API info required to connect to this node + +USAGE: + lotus-miner auth api-info [command options] [arguments...] + +OPTIONS: + --perm value permission to assign to the token, one of: read, write, sign, admin + --help, -h show help +``` + +## lotus-miner log +``` +NAME: + lotus-miner log - Manage logging + +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 + +OPTIONS: + --help, -h show help +``` + +### lotus-miner log list +``` +NAME: + lotus-miner log list - List log systems + +USAGE: + lotus-miner log list [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` + +### lotus-miner log set-level +``` +NAME: + lotus-miner log set-level - Set log level + +USAGE: + lotus-miner log set-level [command options] [level] + +DESCRIPTION: + Set the log level for logging systems: + + The system flag can be specified multiple times. + + eg) log set-level --system chain --system chainxchg debug + + Available Levels: + debug + info + warn + error + + Environment Variables: + GOLOG_LOG_LEVEL - Default log level for all log systems + 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 [ --system value ] limit to log system + --help, -h show help +``` + +### lotus-miner log alerts +``` +NAME: + lotus-miner log alerts - Get alert states + +USAGE: + lotus-miner log alerts [command options] [arguments...] + +OPTIONS: + --all get all (active and inactive) alerts (default: false) + --help, -h show help +``` + +## lotus-miner wait-api +``` +NAME: + lotus-miner wait-api - Wait for lotus api to come online + +USAGE: + lotus-miner wait-api [command options] [arguments...] + +OPTIONS: + --timeout value duration to wait till fail (default: 30s) + --help, -h show help +``` + +## lotus-miner fetch-params +``` +NAME: + lotus-miner fetch-params - Fetch proving parameters + +USAGE: + lotus-miner fetch-params [command options] [sectorSize] + +OPTIONS: + --help, -h show help +``` + ## lotus-miner version ``` NAME: @@ -443,156 +587,6 @@ OPTIONS: --help, -h show help ``` -## lotus-miner auth -``` -NAME: - lotus-miner auth - Manage RPC permissions - -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 - -OPTIONS: - --help, -h show help -``` - -### lotus-miner auth create-token -``` -NAME: - lotus-miner auth create-token - Create token - -USAGE: - lotus-miner auth create-token [command options] [arguments...] - -OPTIONS: - --perm value permission to assign to the token, one of: read, write, sign, admin - --help, -h show help -``` - -### lotus-miner auth api-info -``` -NAME: - lotus-miner auth api-info - Get token with API info required to connect to this node - -USAGE: - lotus-miner auth api-info [command options] [arguments...] - -OPTIONS: - --perm value permission to assign to the token, one of: read, write, sign, admin - --help, -h show help -``` - -## lotus-miner log -``` -NAME: - lotus-miner log - Manage logging - -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 - -OPTIONS: - --help, -h show help -``` - -### lotus-miner log list -``` -NAME: - lotus-miner log list - List log systems - -USAGE: - lotus-miner log list [command options] [arguments...] - -OPTIONS: - --help, -h show help -``` - -### lotus-miner log set-level -``` -NAME: - lotus-miner log set-level - Set log level - -USAGE: - lotus-miner log set-level [command options] [level] - -DESCRIPTION: - Set the log level for logging systems: - - The system flag can be specified multiple times. - - eg) log set-level --system chain --system chainxchg debug - - Available Levels: - debug - info - warn - error - - Environment Variables: - GOLOG_LOG_LEVEL - Default log level for all log systems - 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 [ --system value ] limit to log system - --help, -h show help -``` - -### lotus-miner log alerts -``` -NAME: - lotus-miner log alerts - Get alert states - -USAGE: - lotus-miner log alerts [command options] [arguments...] - -OPTIONS: - --all get all (active and inactive) alerts (default: false) - --help, -h show help -``` - -## lotus-miner wait-api -``` -NAME: - lotus-miner wait-api - Wait for lotus api to come online - -USAGE: - lotus-miner wait-api [command options] [arguments...] - -CATEGORY: - DEVELOPER - -OPTIONS: - --timeout value duration to wait till fail (default: 30s) - --help, -h show help -``` - -## lotus-miner fetch-params -``` -NAME: - lotus-miner fetch-params - Fetch proving parameters - -USAGE: - lotus-miner fetch-params [command options] [sectorSize] - -CATEGORY: - DEVELOPER - -OPTIONS: - --help, -h show help -``` - ## lotus-miner sectors ``` NAME: @@ -1038,7 +1032,6 @@ OPTIONS: --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) - --actor value Specify the address of the miner to run this command --help, -h show help ``` diff --git a/documentation/en/cli-lotus-provider.md b/documentation/en/cli-lotus-provider.md index aed4a5d2abe..0fae817d2dd 100644 --- a/documentation/en/cli-lotus-provider.md +++ b/documentation/en/cli-lotus-provider.md @@ -7,7 +7,7 @@ USAGE: lotus-provider [global options] command [command options] [arguments...] VERSION: - 1.26.2 + 1.26.3 COMMANDS: run Start a lotus provider process diff --git a/documentation/en/cli-lotus-worker.md b/documentation/en/cli-lotus-worker.md index d2912590b4d..441ba14ab88 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.26.2 + 1.27.0 COMMANDS: run Start lotus worker diff --git a/documentation/en/cli-lotus.md b/documentation/en/cli-lotus.md index 1811fc0c4d0..a501dd732c9 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.26.2 + 1.27.0 COMMANDS: daemon Start a lotus daemon process @@ -1192,6 +1192,7 @@ COMMANDS: list-claims List claims available in verified registry actor or made by provider if specified remove-expired-allocations remove expired allocations (if no allocations are specified all eligible allocations are removed) remove-expired-claims remove expired claims (if no claims are specified all eligible claims are removed) + extend-claim extends claim expiration (TermMax) help, h Shows a list of commands or help for one command OPTIONS: @@ -1296,6 +1297,7 @@ USAGE: OPTIONS: --expired list only expired claims (default: false) + --json output results in json format (default: false) --help, -h show help ``` @@ -1325,6 +1327,28 @@ OPTIONS: --help, -h show help ``` +### lotus filplus extend-claim +``` +NAME: + lotus filplus extend-claim - extends claim expiration (TermMax) + +USAGE: + Extends claim expiration (TermMax). + If the client is original client then claim can be extended to maximum 5 years and no Datacap is required. + If the client id different then claim can be extended up to maximum 5 years from now and Datacap is required. + + +OPTIONS: + --term-max value, --tmax value The maximum period for which a provider can earn quality-adjusted power for the piece (epochs). Default is 5 years. (default: 5256000) + --client value the client address that will used to send the message + --all automatically extend TermMax of all claims for specified miner[s] to --term-max (default: 5 years from claim start epoch) (default: false) + --miner value, -m value, --provider value, -p value [ --miner value, -m value, --provider value, -p value ] storage provider address[es] + --assume-yes, -y, --yes automatic yes to prompts; assume 'yes' as answer to all prompts and run non-interactively (default: false) + --confidence value number of block confirmations to wait for (default: 5) + --batch-size value number of extend requests per batch. If set incorrectly, this will lead to out of gas error (default: 500) + --help, -h show help +``` + ## lotus paych ``` NAME: diff --git a/documentation/en/cli-sptool.md b/documentation/en/cli-sptool.md new file mode 100644 index 00000000000..3a53fe7a338 --- /dev/null +++ b/documentation/en/cli-sptool.md @@ -0,0 +1,474 @@ +# sptool +``` +NAME: + sptool - Manage Filecoin Miner Actor + +USAGE: + sptool [global options] command [command options] [arguments...] + +VERSION: + 1.27.0 + +COMMANDS: + actor Manage Filecoin Miner Actor Metadata + info Print miner actor info + sectors interact with sector store + proving View proving information + help, h Shows a list of commands or help for one command + +GLOBAL OPTIONS: + --log-level value (default: "info") + --actor value miner actor to manage [$SP_ADDRESS] + --help, -h show help + --version, -v print the version +``` + +## sptool actor +``` +NAME: + sptool actor - Manage Filecoin Miner Actor Metadata + +USAGE: + sptool 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 + new-miner Initializes a new miner actor + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` + +### sptool actor set-addresses +``` +NAME: + sptool actor set-addresses - set addresses that your miner can be publicly dialed on + +USAGE: + sptool actor set-addresses [command options] + +OPTIONS: + --from value optionally specify the account to send the message from + --gas-limit value set gas limit (default: 0) + --unset unset address (default: false) + --help, -h show help +``` + +### sptool actor withdraw +``` +NAME: + sptool actor withdraw - withdraw available balance to beneficiary + +USAGE: + sptool actor withdraw [command options] [amount (FIL)] + +OPTIONS: + --confidence value number of block confirmations to wait for (default: 5) + --beneficiary send withdraw message from the beneficiary address (default: false) + --help, -h show help +``` + +### sptool actor repay-debt +``` +NAME: + sptool actor repay-debt - pay down a miner's debt + +USAGE: + sptool actor repay-debt [command options] [amount (FIL)] + +OPTIONS: + --from value optionally specify the account to send funds from + --help, -h show help +``` + +### sptool actor set-peer-id +``` +NAME: + sptool actor set-peer-id - set the peer id of your miner + +USAGE: + sptool actor set-peer-id [command options] + +OPTIONS: + --gas-limit value set gas limit (default: 0) + --help, -h show help +``` + +### sptool actor set-owner +``` +NAME: + sptool actor 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) + +USAGE: + sptool actor set-owner [command options] [newOwnerAddress senderAddress] + +OPTIONS: + --really-do-it Actually send transaction performing the action (default: false) + --help, -h show help +``` + +### sptool actor control +``` +NAME: + sptool actor control - Manage control addresses + +USAGE: + sptool actor control command [command options] [arguments...] + +COMMANDS: + list Get currently set control addresses. Note: This excludes most roles as they are not known to the immediate chain state. + set Set control address(-es) + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` + +#### sptool actor control list +``` +NAME: + sptool actor control list - Get currently set control addresses. Note: This excludes most roles as they are not known to the immediate chain state. + +USAGE: + sptool actor control list [command options] [arguments...] + +OPTIONS: + --verbose (default: false) + --help, -h show help +``` + +#### sptool actor control set +``` +NAME: + sptool actor control set - Set control address(-es) + +USAGE: + sptool actor control set [command options] [...address] + +OPTIONS: + --really-do-it Actually send transaction performing the action (default: false) + --help, -h show help +``` + +### sptool actor propose-change-worker +``` +NAME: + sptool actor propose-change-worker - Propose a worker address change + +USAGE: + sptool actor propose-change-worker [command options] [address] + +OPTIONS: + --really-do-it Actually send transaction performing the action (default: false) + --help, -h show help +``` + +### sptool actor confirm-change-worker +``` +NAME: + sptool actor confirm-change-worker - Confirm a worker address change + +USAGE: + sptool actor confirm-change-worker [command options] [address] + +OPTIONS: + --really-do-it Actually send transaction performing the action (default: false) + --help, -h show help +``` + +### sptool actor compact-allocated +``` +NAME: + sptool actor compact-allocated - compact allocated sectors bitfield + +USAGE: + sptool actor compact-allocated [command options] [arguments...] + +OPTIONS: + --mask-last-offset value Mask sector IDs from 0 to 'highest_allocated - offset' (default: 0) + --mask-upto-n value Mask sector IDs from 0 to 'n' (default: 0) + --really-do-it Actually send transaction performing the action (default: false) + --help, -h show help +``` + +### sptool actor propose-change-beneficiary +``` +NAME: + sptool actor propose-change-beneficiary - Propose a beneficiary address change + +USAGE: + sptool actor propose-change-beneficiary [command options] [beneficiaryAddress quota expiration] + +OPTIONS: + --really-do-it Actually send transaction performing the action (default: false) + --overwrite-pending-change Overwrite the current beneficiary change proposal (default: false) + --actor value specify the address of miner actor + --help, -h show help +``` + +### sptool actor confirm-change-beneficiary +``` +NAME: + sptool actor confirm-change-beneficiary - Confirm a beneficiary address change + +USAGE: + sptool actor confirm-change-beneficiary [command options] [minerID] + +OPTIONS: + --really-do-it Actually send transaction performing the action (default: false) + --existing-beneficiary send confirmation from the existing beneficiary address (default: false) + --new-beneficiary send confirmation from the new beneficiary address (default: false) + --help, -h show help +``` + +### sptool actor new-miner +``` +NAME: + sptool actor new-miner - Initializes a new miner actor + +USAGE: + sptool actor new-miner [command options] [arguments...] + +OPTIONS: + --worker value, -w value worker key to use for new miner initialisation + --owner value, -o value owner key to use for new miner initialisation + --from value, -f value address to send actor(miner) creation message from + --sector-size value specify sector size to use for new miner initialisation + --help, -h show help +``` + +## sptool info +``` +NAME: + sptool info - Print miner actor info + +USAGE: + sptool info [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` + +## sptool sectors +``` +NAME: + sptool sectors - interact with sector store + +USAGE: + sptool sectors command [command options] [arguments...] + +COMMANDS: + status Get the seal status of a sector by its number + list List sectors + precommits Print on-chain precommit info + check-expire Inspect expiring sectors + expired Get or cleanup expired sectors + extend Extend expiring sectors while not exceeding each sector's max life + terminate Forcefully terminate a sector (WARNING: This means losing power and pay a one-time termination penalty(including collateral) for the terminated sector) + 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 +``` + +### sptool sectors status +``` +NAME: + sptool sectors status - Get the seal status of a sector by its number + +USAGE: + sptool sectors status [command options] + +OPTIONS: + --log, -l display event log (default: false) + --on-chain-info, -c show sector on chain info (default: false) + --partition-info, -p show partition related info (default: false) + --proof print snark proof bytes as hex (default: false) + --help, -h show help +``` + +### sptool sectors list +``` +NAME: + sptool sectors list - List sectors + +USAGE: + sptool sectors list [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` + +### sptool sectors precommits +``` +NAME: + sptool sectors precommits - Print on-chain precommit info + +USAGE: + sptool sectors precommits [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` + +### sptool sectors check-expire +``` +NAME: + sptool sectors check-expire - Inspect expiring sectors + +USAGE: + sptool sectors check-expire [command options] [arguments...] + +OPTIONS: + --cutoff value skip sectors whose current expiration is more than epochs from now, defaults to 60 days (default: 172800) + --help, -h show help +``` + +### sptool sectors expired +``` +NAME: + sptool sectors expired - Get or cleanup expired sectors + +USAGE: + sptool sectors expired [command options] [arguments...] + +OPTIONS: + --expired-epoch value epoch at which to check sector expirations (default: WinningPoSt lookback epoch) + --help, -h show help +``` + +### sptool sectors extend +``` +NAME: + sptool sectors extend - Extend expiring sectors while not exceeding each sector's max life + +USAGE: + sptool sectors extend [command options] + +OPTIONS: + --from value only consider sectors whose current expiration epoch is in the range of [from, to], defaults to: now + 120 (1 hour) (default: 0) + --to value only consider sectors whose current expiration epoch is in the range of [from, to], defaults to: now + 92160 (32 days) (default: 0) + --sector-file value provide a file containing one sector number in each line, ignoring above selecting criteria + --exclude value optionally provide a file containing excluding sectors + --extension value try to extend selected sectors by this number of epochs, defaults to 540 days (default: 1555200) + --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) + --drop-claims drop claims for sectors that can be extended, but only by dropping some of their verified power claims (default: false) + --tolerance value don't try to extend sectors by fewer than this number of epochs, defaults to 7 days (default: 20160) + --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 (default: 0) + --really-do-it pass this flag to really extend sectors, otherwise will only print out json representation of parameters (default: false) + --help, -h show help +``` + +### sptool sectors terminate +``` +NAME: + sptool sectors terminate - Forcefully terminate a sector (WARNING: This means losing power and pay a one-time termination penalty(including collateral) for the terminated sector) + +USAGE: + sptool sectors terminate [command options] [sectorNum1 sectorNum2 ...] + +OPTIONS: + --actor value specify the address of miner actor + --really-do-it pass this flag if you know what you are doing (default: false) + --from value specify the address to send the terminate message from + --help, -h show help +``` + +### sptool sectors compact-partitions +``` +NAME: + sptool sectors compact-partitions - removes dead sectors from partitions and reduces the number of partitions used if possible + +USAGE: + sptool sectors compact-partitions [command options] [arguments...] + +OPTIONS: + --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) + --help, -h show help +``` + +## sptool proving +``` +NAME: + sptool proving - View proving information + +USAGE: + sptool 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 + help, h Shows a list of commands or help for one command + +OPTIONS: + --help, -h show help +``` + +### sptool proving info +``` +NAME: + sptool proving info - View current state information + +USAGE: + sptool proving info [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` + +### sptool proving deadlines +``` +NAME: + sptool proving deadlines - View the current proving period deadlines information + +USAGE: + sptool proving deadlines [command options] [arguments...] + +OPTIONS: + --all, -a Count all sectors (only live sectors are counted by default) (default: false) + --help, -h show help +``` + +### sptool proving deadline +``` +NAME: + sptool proving deadline - View the current proving period deadline information by its index + +USAGE: + sptool proving deadline [command options] + +OPTIONS: + --sector-nums, -n Print sector/fault numbers belonging to this deadline (default: false) + --bitfield, -b Print partition bitfield stats (default: false) + --help, -h show help +``` + +### sptool proving faults +``` +NAME: + sptool proving faults - View the currently known proving faulty sectors information + +USAGE: + sptool proving faults [command options] [arguments...] + +OPTIONS: + --help, -h show help +``` diff --git a/documentation/en/data-onboarding-visibility.md b/documentation/en/data-onboarding-visibility.md new file mode 100644 index 00000000000..3225753dd1d --- /dev/null +++ b/documentation/en/data-onboarding-visibility.md @@ -0,0 +1,71 @@ +# Data Onboarding Visibility + +* [Introduction and background](#introduction-and-background) +* [DDO information flow](#ddo-information-flow) +* [Relevant message contents](#relevant-message-contents) +* [Relevant builtin actor events](#relevant-builtin-actor-events) + +## Introduction and background + +**Direct Data Onboarding** (DDO) as defined in **[FIP-0076](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0076.md)** provides an optional data onboarding path that is both gas-efficient and paves a path toward eventual smart contract mediated onboarding mechanisms. The existing market actor and market actor mediated onboarding pathway remains largely unchanged but is now optional; it is anticipated that the gas savings alone will see a significant shift away from use of the market actor. + +Historically, a large amount of tooling was built around Filecoin that makes use of the market actor (f05) to quantify various data-related metrics. A shift in behaviour toward data onboarding that bypasses the market actor requires adaption in order to have continuity with the some of the data-related metrics being collected. This will continue to be true as Filecoin evolves to enable onboarding mechanisms mediated by smart contracts. + +**Deal-lifecycle actor events** as defined in **[FIP-0083](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0083.md)** and detailed in [Actor Events and Lotus APIs](./actor-events-api.md) introduced the first batch of fire-and-forget externally observable events for builtin actors. The FVM already had this capability and these new first events for builtin actors were added to increase the visibility of information around data onboarding, particularly in light of the introduction of DDO which will require metrics gatherers to rely on mechanisms other than the market actor to collect data. + +Actor events are an optional method for gaining insight into data onboarding activities and data / storage lifecycles. Messages may also be used as a source of truth for data onboarding metrics, but are more complex to consume and may not be suitable for some workflows. For verified (Filecoin Plus) data, the verified registry actor (f06) should be used as the primary source of truth for data lifecycles; however FIP-0076 introduces the possibility of "sparkling data" which is not verified and not mediated through the builtin market actor or possibly any other actor. This data currently still requires piece commitments to be detailed as part of a miner's sector commitments, and so may be observed through messages and actor events that carry sector commitment piece manifests. + +## DDO information flow + +The most basic direct onboarding workflow as viewed by the chain is simply: + +- At PreCommit, an SP must specify a sector’s data commitment (unsealed CID, CommP) *(but does not need to specify the structure of that data nor any deals or verified allocations)*. +- At ProveCommit or ReplicaUpdate, an SP specifies the pieces of data (CommP and their size) comprising a sector in order to satisfy the data commitment. + +This basic form does not touch either the market actor or the verified registry actor. Importantly, it does not result in piece information being stored on chain, even though the ProveCommit message contains this information for the purpose of verifying the sector commitment. This is the most significant change from onboarding mechanics prior to network version 22. + +There are two possible additions to this flow: + +- Prior to PreCommit, an SP publishes a storage deal to the builtin market actor, in which case deal information exists on chain as it does with non-DDO deals today; then + - at ProveCommit, or ReplicaUpdate, the SP can notify an actor of the commitment. Currently this can only be the builtin market actor (in the future this may be a list of arbitrary user defined actors), in which case it will be used to activate a deal previously proposed on chain. +- At ProveCommit, or ReplicaUpdate, the SP can claim DataCap that was previously allocated by the client for a particular piece. + +💡 **The builtin market actor should not be used as single a source of truth regarding data onboarding activities.** The builtin market actor is only a source of truth for data onboarding mediated by the builtin market actor. + +💡 **The builtin market actor should not be used as a source of truth regarding verified claims and metrics related to FIL+ usage (size, clients, profiders).** The `VerifiedClaim` property of `DealState` has been removed from the builtin market actor. Instead, the verified registry should be used as the only source of truth regarding both allocations and claims. + +💡 **Sector data commitments and their constituent pieces are only stored on chain in the verified registry claims in the case of verified data (pieces) onboarded in any mechanism (DDO and/or builtin market actor).** Piece information for data onboarded that is not verified ("sparkling data") and not mediated through the builtin market actor will only appear in messages and actor events. Messages and actor events may be used as a source of truth for data sector commitments. + +## Relevant message contents + +Even though chain state is less informative for data onboarding not mediated through the builtin market actor, messages used for chain execution will continue to provide all relevant information and may be used to determine the number and size of pieces within a sector, as well as any DataCap claimed for specific pieces and therefore the client allocating the DataCap. + +The most important messages for this purpose are as follows: + +At ProveCommit, a [`ProveCommitSectors3`](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0076.md#provecommitsectors3) message will contain a `SectorActivations` property which is a list of `SectorActivationManifest`, one for each sector being activated. Within this per-sector manifest is a list of `Pieces` which details all of the pieces contributing to the sector commitment, each one is a `PieceActivationManifest` of the form: + +```ipldsch +type PieceActivationManifest struct { + CID &Any # Piece data commitment (CommP) + Size Int # Padded piece size + VerifiedAllocationKey nullable VerifiedAllocationKey # Identifies a verified allocation to be claimed + Notify DataActivationNotification # Notifications to be sent to other actors after activation +} +``` + +This manifest contains the piece commitment as well as an optional `VerifiedAllocationKey` which lists a client and an allocation to claim from the verified registry actor. + +At ReplicaUpdate, the [`ProveReplicaUpdates3`](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0076.md#provereplicaupdates3) message will contain a `SectorUpdates` property which is a list of `SectorUpdateManifest`, one for each sector being updated. This manifest mirrors the `SectorActivationManifest` for ProveCommit, containing a list of `Pieces` which may be similarly inspected for the relevant data. + +- **Pieces**: All piece information for each sector's data commitment may be collected from the piece manifests. +- **Verified data**: Claims may be cross-referenced with the verified registry state to access the details of the allocation, including piece information for the claim. The `StateGetClaim` Lotus API call provides this information. + +💡 Making use of the message contents directly is not a trivial activity. Messages need to be filtered by actor and method number, exit code needs to be checked from the receipt, and the parameters would need to be decoded according to the relevant schema for that message. Actor events exist to make this somewhat easier although may not be suitable for some workflows. + +## Relevant builtin actor events + +Depending on usage and data consumption workflow, consuming builtin actor events using the APIs detailed in [Actor Events and Lotus APIs](./actor-events-api.md), may be simpler and more suitable. The following events are relevant to DDO and may be used to determine the number and size of pieces within a sector, as well as any DataCap claimed for specific pieces and therefore the client allocating the DataCap. + +The [`sector-activated`](./actor-events-api.md#sector-activated) and [`sector-updated`](./actor-events-api.md#sector-updated) events are emitted by the miner actor and contain the piece information for each sector. This is submitted to the miner actor by the storage provider in the form of a piece manifest and is summarised as a list of pieces in the events. Both piece CID (CommP) and piece size are available in the event data. + +The [`claim`](./actor-events-api.md#claim) event is emitted by the verified registry actor and contains the client and provider for each claim. This event contains the claim ID which can be used to cross-reference with the verified registry state to access the details of the allocation, including piece information for the claim. The `StateGetClaim` Lotus API call provides this information. diff --git a/documentation/en/default-curio-config.toml b/documentation/en/default-curio-config.toml new file mode 100644 index 00000000000..afcb7608aa6 --- /dev/null +++ b/documentation/en/default-curio-config.toml @@ -0,0 +1,366 @@ +[Subsystems] + # EnableWindowPost enables window post to be executed on this curio instance. Each machine in the cluster + # with WindowPoSt enabled will also participate in the window post scheduler. It is possible to have multiple + # machines with WindowPoSt enabled which will provide redundancy, and in case of multiple partitions per deadline, + # will allow for parallel processing of partitions. + # + # It is possible to have instances handling both WindowPoSt and WinningPoSt, which can provide redundancy without + # the need for additional machines. In setups like this it is generally recommended to run + # partitionsPerDeadline+1 machines. + # + # type: bool + #EnableWindowPost = false + + # type: int + #WindowPostMaxTasks = 0 + + # EnableWinningPost enables winning post to be executed on this curio instance. + # Each machine in the cluster with WinningPoSt enabled will also participate in the winning post scheduler. + # It is possible to mix machines with WindowPoSt and WinningPoSt enabled, for details see the EnableWindowPost + # documentation. + # + # type: bool + #EnableWinningPost = false + + # type: int + #WinningPostMaxTasks = 0 + + # EnableParkPiece enables the "piece parking" task to run on this node. This task is responsible for fetching + # pieces from the network and storing them in the storage subsystem until sectors are sealed. This task is + # only applicable when integrating with boost, and should be enabled on nodes which will hold deal data + # from boost until sectors containing the related pieces have the TreeD/TreeR constructed. + # Note that future Curio implementations will have a separate task type for fetching pieces from the internet. + # + # type: bool + #EnableParkPiece = false + + # type: int + #ParkPieceMaxTasks = 0 + + # EnableSealSDR enables SDR tasks to run. SDR is the long sequential computation + # creating 11 layer files in sector cache directory. + # + # SDR is the first task in the sealing pipeline. It's inputs are just the hash of the + # unsealed data (CommD), sector number, miner id, and the seal proof type. + # It's outputs are the 11 layer files in the sector cache directory. + # + # In lotus-miner this was run as part of PreCommit1. + # + # type: bool + #EnableSealSDR = false + + # The maximum amount of SDR tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. + # + # type: int + #SealSDRMaxTasks = 0 + + # EnableSealSDRTrees enables the SDR pipeline tree-building task to run. + # This task handles encoding of unsealed data into last sdr layer and building + # of TreeR, TreeC and TreeD. + # + # This task runs after SDR + # TreeD is first computed with optional input of unsealed data + # TreeR is computed from replica, which is first computed as field + # addition of the last SDR layer and the bottom layer of TreeD (which is the unsealed data) + # TreeC is computed from the 11 SDR layers + # The 3 trees will later be used to compute the PoRep proof. + # + # In case of SyntheticPoRep challenges for PoRep will be pre-generated at this step, and trees and layers + # will be dropped. SyntheticPoRep works by pre-generating a very large set of challenges (~30GiB on disk) + # then using a small subset of them for the actual PoRep computation. This allows for significant scratch space + # saving between PreCommit and PoRep generation at the expense of more computation (generating challenges in this step) + # + # In lotus-miner this was run as part of PreCommit2 (TreeD was run in PreCommit1). + # Note that nodes with SDRTrees enabled will also answer to Finalize tasks, + # which just remove unneeded tree data after PoRep is computed. + # + # type: bool + #EnableSealSDRTrees = false + + # The maximum amount of SealSDRTrees tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. + # + # type: int + #SealSDRTreesMaxTasks = 0 + + # FinalizeMaxTasks is the maximum amount of finalize tasks that can run simultaneously. + # The finalize task is enabled on all machines which also handle SDRTrees tasks. Finalize ALWAYS runs on whichever + # machine holds sector cache files, as it removes unneeded tree data after PoRep is computed. + # Finalize will run in parallel with the SubmitCommitMsg task. + # + # type: int + #FinalizeMaxTasks = 0 + + # EnableSendPrecommitMsg enables the sending of precommit messages to the chain + # from this curio instance. + # This runs after SDRTrees and uses the output CommD / CommR (roots of TreeD / TreeR) for the message + # + # type: bool + #EnableSendPrecommitMsg = false + + # EnablePoRepProof enables the computation of the porep proof + # + # This task runs after interactive-porep seed becomes available, which happens 150 epochs (75min) after the + # precommit message lands on chain. This task should run on a machine with a GPU. Vanilla PoRep proofs are + # requested from the machine which holds sector cache files which most likely is the machine which ran the SDRTrees + # task. + # + # In lotus-miner this was Commit1 / Commit2 + # + # type: bool + #EnablePoRepProof = false + + # The maximum amount of PoRepProof tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. + # + # type: int + #PoRepProofMaxTasks = 0 + + # EnableSendCommitMsg enables the sending of commit messages to the chain + # from this curio instance. + # + # type: bool + #EnableSendCommitMsg = false + + # EnableMoveStorage enables the move-into-long-term-storage task to run on this curio instance. + # This tasks should only be enabled on nodes with long-term storage. + # + # The MoveStorage task is the last task in the sealing pipeline. It moves the sealed sector data from the + # SDRTrees machine into long-term storage. This task runs after the Finalize task. + # + # type: bool + #EnableMoveStorage = false + + # The maximum amount of MoveStorage tasks that can run simultaneously. Note that the maximum number of tasks will + # also be bounded by resources available on the machine. It is recommended that this value is set to a number which + # uses all available network (or disk) bandwidth on the machine without causing bottlenecks. + # + # type: int + #MoveStorageMaxTasks = 0 + + # BoostAdapters is a list of tuples of miner address and port/ip to listen for market (e.g. boost) requests. + # This interface is compatible with the lotus-miner RPC, implementing a subset needed for storage market operations. + # Strings should be in the format "actor:port" or "actor:ip:port". Default listen address is 0.0.0.0 + # Example: "f0123:32100", "f0123:127.0.0.1:32100". Multiple addresses can be specified. + # + # When a market node like boost gives Curio's market RPC a deal to placing into a sector, Curio will first store the + # deal data in a temporary location "Piece Park" before assigning it to a sector. This requires that at least one + # node in the cluster has the EnableParkPiece option enabled and has sufficient scratch space to store the deal data. + # This is different from lotus-miner which stored the deal data into an "unsealed" sector as soon as the deal was + # received. Deal data in PiecePark is accessed when the sector TreeD and TreeR are computed, but isn't needed for + # the initial SDR layers computation. Pieces in PiecePark are removed after all sectors referencing the piece are + # sealed. + # + # To get API info for boost configuration run 'curio market rpc-info' + # + # NOTE: All deal data will flow through this service, so it should be placed on a machine running boost or on + # a machine which handles ParkPiece tasks. + # + # type: []string + #BoostAdapters = [] + + # EnableWebGui enables the web GUI on this curio instance. The UI has minimal local overhead, but it should + # only need to be run on a single machine in the cluster. + # + # type: bool + #EnableWebGui = false + + # The address that should listen for Web GUI requests. + # + # type: string + #GuiAddress = ":4701" + + +[Fees] + # type: types.FIL + #DefaultMaxFee = "0.07 FIL" + + # type: types.FIL + #MaxPreCommitGasFee = "0.025 FIL" + + # type: types.FIL + #MaxCommitGasFee = "0.05 FIL" + + # type: types.FIL + #MaxTerminateGasFee = "0.5 FIL" + + # WindowPoSt is a high-value operation, so the default fee should be high. + # + # type: types.FIL + #MaxWindowPoStGasFee = "5 FIL" + + # type: types.FIL + #MaxPublishDealsFee = "0.05 FIL" + + [Fees.MaxPreCommitBatchGasFee] + # type: types.FIL + #Base = "0 FIL" + + # type: types.FIL + #PerSector = "0.02 FIL" + + [Fees.MaxCommitBatchGasFee] + # type: types.FIL + #Base = "0 FIL" + + # type: types.FIL + #PerSector = "0.03 FIL" + + +[[Addresses]] + #PreCommitControl = [] + + #CommitControl = [] + + #TerminateControl = [] + + #DisableOwnerFallback = false + + #DisableWorkerFallback = false + + #MinerAddresses = [] + + +[Proving] + # Maximum number of sector checks to run in parallel. (0 = unlimited) + # + # WARNING: Setting this value too high may make the node crash by running out of stack + # WARNING: Setting this value too low may make sector challenge reading much slower, resulting in failed PoSt due + # to late submission. + # + # After changing this option, confirm that the new value works in your setup by invoking + # 'lotus-miner proving compute window-post 0' + # + # type: int + #ParallelCheckLimit = 32 + + # Maximum amount of time a proving pre-check can take for a sector. If the check times out the sector will be skipped + # + # WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the + # test challenge took longer than this timeout + # WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this sector are + # blocked (e.g. in case of disconnected NFS mount) + # + # type: Duration + #SingleCheckTimeout = "10m0s" + + # Maximum amount of time a proving pre-check can take for an entire partition. If the check times out, sectors in + # the partition which didn't get checked on time will be skipped + # + # WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the + # test challenge took longer than this timeout + # WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this partition are + # blocked or slow + # + # type: Duration + #PartitionCheckTimeout = "20m0s" + + # Disable WindowPoSt provable sector readability checks. + # + # In normal operation, when preparing to compute WindowPoSt, lotus-miner will perform a round of reading challenges + # from all sectors to confirm that those sectors can be proven. Challenges read in this process are discarded, as + # we're only interested in checking that sector data can be read. + # + # When using builtin proof computation (no PoSt workers, and DisableBuiltinWindowPoSt is set to false), this process + # can save a lot of time and compute resources in the case that some sectors are not readable - this is caused by + # the builtin logic not skipping snark computation when some sectors need to be skipped. + # + # When using PoSt workers, this process is mostly redundant, with PoSt workers challenges will be read once, and + # if challenges for some sectors aren't readable, those sectors will just get skipped. + # + # Disabling sector pre-checks will slightly reduce IO load when proving sectors, possibly resulting in shorter + # time to produce window PoSt. In setups with good IO capabilities the effect of this option on proving time should + # be negligible. + # + # NOTE: It likely is a bad idea to disable sector pre-checks in setups with no PoSt workers. + # + # NOTE: Even when this option is enabled, recovering sectors will be checked before recovery declaration message is + # sent to the chain + # + # After changing this option, confirm that the new value works in your setup by invoking + # 'lotus-miner proving compute window-post 0' + # + # type: bool + #DisableWDPoStPreChecks = false + + # Maximum number of partitions to prove in a single SubmitWindowPoSt messace. 0 = network limit (3 in nv21) + # + # A single partition may contain up to 2349 32GiB sectors, or 2300 64GiB sectors. + # // + # Note that setting this value lower may result in less efficient gas use - more messages will be sent, + # to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) + # + # Setting this value above the network limit has no effect + # + # type: int + #MaxPartitionsPerPoStMessage = 0 + + # In some cases when submitting DeclareFaultsRecovered messages, + # there may be too many recoveries to fit in a BlockGasLimit. + # In those cases it may be necessary to set this value to something low (eg 1); + # Note that setting this value lower may result in less efficient gas use - more messages will be sent than needed, + # resulting in more total gas use (but each message will have lower gas limit) + # + # type: int + #MaxPartitionsPerRecoveryMessage = 0 + + # Enable single partition per PoSt Message for partitions containing recovery sectors + # + # In cases when submitting PoSt messages which contain recovering sectors, the default network limit may still be + # too high to fit in the block gas limit. In those cases, it becomes useful to only house the single partition + # with recovering sectors in the post message + # + # Note that setting this value lower may result in less efficient gas use - more messages will be sent, + # to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) + # + # type: bool + #SingleRecoveringPartitionPerPostMessage = false + + +[Ingest] + # Maximum number of sectors that can be queued waiting for SDR to start processing. + # 0 = unlimited + # Note: This mechanism will delay taking deal data from markets, providing backpressure to the market subsystem. + # The SDR queue includes deals which are in the process of entering the sealing pipeline - size of this queue + # will also impact the maximum number of ParkPiece tasks which can run concurrently. + # + # SDR queue is the first queue in the sealing pipeline, meaning that it should be used as the primary backpressure mechanism. + # + # type: int + #MaxQueueSDR = 8 + + # Maximum number of sectors that can be queued waiting for SDRTrees to start processing. + # 0 = unlimited + # Note: This mechanism will delay taking deal data from markets, providing backpressure to the market subsystem. + # In case of the trees tasks it is possible that this queue grows more than this limit, the backpressure is only + # applied to sectors entering the pipeline. + # + # type: int + #MaxQueueTrees = 0 + + # Maximum number of sectors that can be queued waiting for PoRep to start processing. + # 0 = unlimited + # Note: This mechanism will delay taking deal data from markets, providing backpressure to the market subsystem. + # Like with the trees tasks, it is possible that this queue grows more than this limit, the backpressure is only + # applied to sectors entering the pipeline. + # + # type: int + #MaxQueuePoRep = 0 + + +[Journal] + # Events of the form: "system1:event1,system1:event2[,...]" + # + # type: string + #DisabledEvents = "" + + +[Apis] + # RPC Secret for the storage subsystem. + # If integrating with lotus-miner this must match the value from + # cat ~/.lotusminer/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU | jq -r .PrivateKey + # + # type: string + #StorageRPCSecret = "" + diff --git a/documentation/en/default-lotus-config.toml b/documentation/en/default-lotus-config.toml index 3f3a6b1718d..8d3c6a427e8 100644 --- a/documentation/en/default-lotus-config.toml +++ b/documentation/en/default-lotus-config.toml @@ -129,22 +129,6 @@ [Client] - # type: bool - # env var: LOTUS_CLIENT_USEIPFS - #UseIpfs = false - - # type: bool - # env var: LOTUS_CLIENT_IPFSONLINEMODE - #IpfsOnlineMode = false - - # type: string - # env var: LOTUS_CLIENT_IPFSMADDR - #IpfsMAddr = "" - - # type: bool - # env var: LOTUS_CLIENT_IPFSUSEFORRETRIEVAL - #IpfsUseForRetrieval = false - # The maximum number of simultaneous data transfers between the client # and storage providers for storage deals # @@ -260,68 +244,6 @@ #HotstoreMaxSpaceSafetyBuffer = 50000000000 -[Cluster] - # EXPERIMENTAL. config to enabled node cluster with raft consensus - # - # type: bool - # env var: LOTUS_CLUSTER_CLUSTERMODEENABLED - #ClusterModeEnabled = false - - # A folder to store Raft's data. - # - # type: string - # env var: LOTUS_CLUSTER_DATAFOLDER - #DataFolder = "" - - # InitPeersetMultiAddr provides the list of initial cluster peers for new Raft - # peers (with no prior state). It is ignored when Raft was already - # initialized or when starting in staging mode. - # - # type: []string - # env var: LOTUS_CLUSTER_INITPEERSETMULTIADDR - #InitPeersetMultiAddr = [] - - # LeaderTimeout specifies how long to wait for a leader before - # failing an operation. - # - # type: Duration - # env var: LOTUS_CLUSTER_WAITFORLEADERTIMEOUT - #WaitForLeaderTimeout = "15s" - - # NetworkTimeout specifies how long before a Raft network - # operation is timed out - # - # type: Duration - # env var: LOTUS_CLUSTER_NETWORKTIMEOUT - #NetworkTimeout = "1m40s" - - # CommitRetries specifies how many times we retry a failed commit until - # we give up. - # - # type: int - # env var: LOTUS_CLUSTER_COMMITRETRIES - #CommitRetries = 1 - - # How long to wait between retries - # - # type: Duration - # env var: LOTUS_CLUSTER_COMMITRETRYDELAY - #CommitRetryDelay = "200ms" - - # BackupsRotate specifies the maximum number of Raft's DataFolder - # copies that we keep as backups (renaming) after cleanup. - # - # type: int - # env var: LOTUS_CLUSTER_BACKUPSROTATE - #BackupsRotate = 6 - - # Tracing enables propagation of contexts across binary boundaries. - # - # type: bool - # env var: LOTUS_CLUSTER_TRACING - #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. diff --git a/documentation/en/default-lotus-provider-config.toml b/documentation/en/default-lotus-provider-config.toml deleted file mode 100644 index 91606e503fd..00000000000 --- a/documentation/en/default-lotus-provider-config.toml +++ /dev/null @@ -1,209 +0,0 @@ -[Subsystems] - # type: bool - #EnableWindowPost = false - - # type: int - #WindowPostMaxTasks = 0 - - # type: bool - #EnableWinningPost = false - - # type: int - #WinningPostMaxTasks = 0 - - -[Fees] - # type: types.FIL - #DefaultMaxFee = "0.07 FIL" - - # type: types.FIL - #MaxPreCommitGasFee = "0.025 FIL" - - # type: types.FIL - #MaxCommitGasFee = "0.05 FIL" - - # type: types.FIL - #MaxTerminateGasFee = "0.5 FIL" - - # WindowPoSt is a high-value operation, so the default fee should be high. - # - # type: types.FIL - #MaxWindowPoStGasFee = "5 FIL" - - # type: types.FIL - #MaxPublishDealsFee = "0.05 FIL" - - [Fees.MaxPreCommitBatchGasFee] - # type: types.FIL - #Base = "0 FIL" - - # type: types.FIL - #PerSector = "0.02 FIL" - - [Fees.MaxCommitBatchGasFee] - # type: types.FIL - #Base = "0 FIL" - - # type: types.FIL - #PerSector = "0.03 FIL" - - -[Addresses] - # Addresses to send PreCommit messages from - # - # type: []string - #PreCommitControl = [] - - # Addresses to send Commit messages from - # - # type: []string - #CommitControl = [] - - # type: []string - #TerminateControl = [] - - # DisableOwnerFallback disables usage of the owner address for messages - # sent automatically - # - # type: bool - #DisableOwnerFallback = false - - # DisableWorkerFallback disables usage of the worker address for messages - # sent automatically, if control addresses are configured. - # A control address that doesn't have enough funds will still be chosen - # over the worker address if this flag is set. - # - # type: bool - #DisableWorkerFallback = false - - -[Proving] - # Maximum number of sector checks to run in parallel. (0 = unlimited) - # - # WARNING: Setting this value too high may make the node crash by running out of stack - # WARNING: Setting this value too low may make sector challenge reading much slower, resulting in failed PoSt due - # to late submission. - # - # After changing this option, confirm that the new value works in your setup by invoking - # 'lotus-miner proving compute window-post 0' - # - # type: int - #ParallelCheckLimit = 32 - - # Maximum amount of time a proving pre-check can take for a sector. If the check times out the sector will be skipped - # - # WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the - # test challenge took longer than this timeout - # WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this sector are - # blocked (e.g. in case of disconnected NFS mount) - # - # type: Duration - #SingleCheckTimeout = "10m0s" - - # Maximum amount of time a proving pre-check can take for an entire partition. If the check times out, sectors in - # the partition which didn't get checked on time will be skipped - # - # WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the - # test challenge took longer than this timeout - # WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this partition are - # blocked or slow - # - # type: Duration - #PartitionCheckTimeout = "20m0s" - - # Disable Window PoSt computation on the lotus-miner process even if no window PoSt workers are present. - # - # WARNING: If no windowPoSt workers are connected, window PoSt WILL FAIL resulting in faulty sectors which will need - # to be recovered. Before enabling this option, make sure your PoSt workers work correctly. - # - # After changing this option, confirm that the new value works in your setup by invoking - # 'lotus-miner proving compute window-post 0' - # - # type: bool - #DisableBuiltinWindowPoSt = false - - # Disable Winning PoSt computation on the lotus-miner process even if no winning PoSt workers are present. - # - # WARNING: If no WinningPoSt workers are connected, Winning PoSt WILL FAIL resulting in lost block rewards. - # Before enabling this option, make sure your PoSt workers work correctly. - # - # type: bool - #DisableBuiltinWinningPoSt = false - - # Disable WindowPoSt provable sector readability checks. - # - # In normal operation, when preparing to compute WindowPoSt, lotus-miner will perform a round of reading challenges - # from all sectors to confirm that those sectors can be proven. Challenges read in this process are discarded, as - # we're only interested in checking that sector data can be read. - # - # When using builtin proof computation (no PoSt workers, and DisableBuiltinWindowPoSt is set to false), this process - # can save a lot of time and compute resources in the case that some sectors are not readable - this is caused by - # the builtin logic not skipping snark computation when some sectors need to be skipped. - # - # When using PoSt workers, this process is mostly redundant, with PoSt workers challenges will be read once, and - # if challenges for some sectors aren't readable, those sectors will just get skipped. - # - # Disabling sector pre-checks will slightly reduce IO load when proving sectors, possibly resulting in shorter - # time to produce window PoSt. In setups with good IO capabilities the effect of this option on proving time should - # be negligible. - # - # NOTE: It likely is a bad idea to disable sector pre-checks in setups with no PoSt workers. - # - # NOTE: Even when this option is enabled, recovering sectors will be checked before recovery declaration message is - # sent to the chain - # - # After changing this option, confirm that the new value works in your setup by invoking - # 'lotus-miner proving compute window-post 0' - # - # type: bool - #DisableWDPoStPreChecks = false - - # Maximum number of partitions to prove in a single SubmitWindowPoSt messace. 0 = network limit (3 in nv21) - # - # A single partition may contain up to 2349 32GiB sectors, or 2300 64GiB sectors. - # // - # Note that setting this value lower may result in less efficient gas use - more messages will be sent, - # to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) - # - # Setting this value above the network limit has no effect - # - # type: int - #MaxPartitionsPerPoStMessage = 0 - - # In some cases when submitting DeclareFaultsRecovered messages, - # there may be too many recoveries to fit in a BlockGasLimit. - # In those cases it may be necessary to set this value to something low (eg 1); - # Note that setting this value lower may result in less efficient gas use - more messages will be sent than needed, - # resulting in more total gas use (but each message will have lower gas limit) - # - # type: int - #MaxPartitionsPerRecoveryMessage = 0 - - # Enable single partition per PoSt Message for partitions containing recovery sectors - # - # In cases when submitting PoSt messages which contain recovering sectors, the default network limit may still be - # too high to fit in the block gas limit. In those cases, it becomes useful to only house the single partition - # with recovering sectors in the post message - # - # Note that setting this value lower may result in less efficient gas use - more messages will be sent, - # to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) - # - # type: bool - #SingleRecoveringPartitionPerPostMessage = false - - -[Journal] - # Events of the form: "system1:event1,system1:event2[,...]" - # - # type: string - #DisabledEvents = "" - - -[Apis] - # RPC Secret for the storage subsystem. - # If integrating with lotus-miner this must match the value from - # cat ~/.lotusminer/keystore/MF2XI2BNNJ3XILLQOJUXMYLUMU | jq -r .PrivateKey - # - # type: string - #StorageRPCSecret = "" - diff --git a/documentation/misc/Building_a_network_skeleton.md b/documentation/misc/Building_a_network_skeleton.md new file mode 100644 index 00000000000..5aea6f706f8 --- /dev/null +++ b/documentation/misc/Building_a_network_skeleton.md @@ -0,0 +1,255 @@ +# Network Upgrade Skeleton in Lotus + +This guide will walk you through the process of creating a skeleton for a network upgrade in Lotus. The process involves making changes in multiple repositories in the following order: + +1. [`ref-fvm`](#ref-fvm-checklist) +2. [`filecoin-ffi`](#filecoin-ffi-checklist) +3. [`go-state-types`](#go-state-types-checklist) +4. [`lotus`](#lotus-checklist) + +Each repository has its own set of steps that need to be followed. This guide will provide detailed instructions for each repository. + +## Setup + +1. Clone the [ref-fvm](https://github.com/filecoin-project/ref-fvm.git) repository. + +2. Clone the [filecoin-ffi](https://github.com/filecoin-project/filecoin-ffi.git) repository. + +3. Clone the [go-state-types](https://github.com/filecoin-project/go-state-types) repository. + +4. In your Lotus repository, add `replace github.com/filecoin-project/go-state-types => ../go-state-types` to the very end of your Lotus `go.mod` file. + - This ensures that your local clone copy of `go-state-types` is used. Any changes you make there will be reflected in your Lotus project. + +## Ref-FVM Checklist + +1. Add support for the new network version in Ref-FVM: + + - In `fvm/Cargo.toml` add `nvXX-dev` as a feature flag in the [features]-section. + - In `fvm/src/gas/price_list.rs`, extend the `price_list_by_network_version` function to support the new network version with the `nvXX-dev` feature flag. + - In fvm/src/machine/default.rs, locate the new function within your machine context. You'll find a SUPPORTED_VERSIONS constant that sets the range of supported network versions. Update this range to include the new network version. Do this by replacing the existing feature flag nvXX-dev and NetworkVersion::VXX with the new ones corresponding to your new network version. + - In `shared/src/version/mod.rs`, in the `NetworkVersion` implementation, you will find a series of constants representing different network versions. To add a new network version, you need to declare a new constant: `pub const (VXX+1): Self = Self(XX+1);` + +You can take a look at [this Ref-FVM PR as a reference](https://github.com/filecoin-project/ref-fvm/pull/1929), which added the skeleton for network version 22. + +## Filecoin-FFI Checklist + +1. Update the `TryFrom` implementation for `EngineVersion` in `rust/src/fvm/engine.rs` + - Add the new network version number (XX+1) to the existing match arm for the network version. + +2. Patch the FVM-dependency (fvm3) in `rust/cargo.toml` to use the custom branch of the FVM created in the [Ref-FVM Checklist](#ref-fvm-checklist)) + - Add `features = ["your-ref-fvm-branch"]` to tell Cargo to use you Ref-FVM branch. + +You can take a look at this [Filecoin-FFI PR as a reference](https://github.com/filecoin-project/filecoin-ffi/pull/438), which added the skeleton for network version 22. + +## Go-State-Types Checklist + +1. Follow the [go-state-types actor version checklist](https://github.com/filecoin-project/go-state-types/blob/master/actors_version_checklist.md): + + - Copy `go-state-types/builtin/vX` to `go-state-types/builtin/v(X+1)`. + - Change all references from vX to v(X+1) in the new files. + - Add new network version to `network/version.go`. + - Add new actors version to `actors/version.go`. + - Add `Version(XX+1) Version = XX+1` as a constant. + - In `func VersionForNetwork` add `case network.Version(XX+1): return Version(XX+1), nil`. + - Add the new version to the gen step of the makefile. + - Add `$(GO_BIN) run ./builtin/v(XX+1)/gen/gen.go`. + +You can take a look at this [Go-State-Types PR as a reference](https://github.com/filecoin-project/go-state-types/pull/232), which added the skeleton for network version 22. + +## Lotus Checklist + +1. Import new actors: + + - Create a mock actor-bundle for the new network version. + - In `/build/actors` run `./pack.sh vXX+1 vXX.0.0` where XX is the current actor bundle version. + +2. Define upgrade heights in `build/params_`: + + - Update the following files: + - `params_2k.go` + - Set previous `UpgradeXxxxxHeight = abi.ChainEpoch(-xx-1)` + - Add `var UpgradeXxxxxHeight = abi.ChainEpoch(200)` + - Add `UpgradeXxxxxHeight = getUpgradeHeight("LOTUS_XXXXX_HEIGHT", UpgradeXXXXHeight)` + - Set `const GenesisNetworkVersion = network.VersionXX` where XX is the network version you are upgrading from. + - `params_butterfly.go` + - set previous upgrade to `var UpgradeXxxxxHeigh = abi.ChainEpoch(-xx-1)` + - Add comment with ?????? signaling that the new upgrade date is unkown + - Add `const UpgradeXxxxxHeight = 999999999999999` + - `params_calibnet.go` + - Add comment with `??????` signaling that the new upgrade date is unkown + - Add `const UpgradeXxxxxHeight = 999999999999999` + - `params_interop.go` + - set previous upgrade to `var UpgradeXxxxxHeigh = abi.ChainEpoch(-xx-1)` + - Add `const UpgradeXxxxxHeight = 50` + - `params_mainnet.go` + - Set previous upgrade to `const UpgradeXxxxxHeight = XX` + - Add comment with ???? signaling that the new upgrade date is unkown + - Add `var UpgradeXxxxxxHeight = abi.ChainEpoch(9999999999)` + - Change the `LOTUS_DISABLE_XXXX` env variable to the new network name + - `params_testground.go` + - Add `UpgradeXxxxxHeight abi.ChainEpoch = (-xx-1)` + +3. Generate adapters: + + - Update `gen/inlinegen-data.json`. + - Add `XX+1` to "actorVersions" and set "latestActorsVersion" to `XX+1`. + - Add `XX+1` to "networkVersions" and set "latestNetworkVersion" to `XX+1`. + + - Run `make actors-gen`. This generates the `/chain/actors/builtin/*` code, `/chain/actors/policy/policy.go` code, `/chain/actors/version.go`, and `/itest/kit/ensemble_opts_nv.go`. + +4. Update `chain/consensus/filcns/upgrades.go`. + - Import `nv(XX+1) "github.com/filecoin-project/go-state-types/builtin/v(XX+1)/migration`. + - Add Schedule. [^1] + - Add Migration. [^2] + +5. Add actorstype to the NewActorRegistry in `/chain/consensus/computestate.go`. + - Add `inv.Register(actorstypes.Version(XX+1), vm.ActorsVersionPredicate(actorstypes.Version(XX+1)), builtin.MakeRegistry(actorstypes.Version(XX+1))`. + +6. Add upgrade field to `api/types.go/ForkUpgradeParams`. + - Add `UpgradeXxxxxHeight abi.ChainEpoch` to `ForkUpgradeParams` struct. + +7. Add upgrade to `node/impl/full/state.go`. + - Add `UpgradeXxxxxHeight: build.UpgradeXxxxxHeight,`. + +8. Add network version to `chain/state/statetree.go`. + - Add `network.VersionXX+1` to `VersionForNetwork` function. + +9. Run `make gen`. + +10. Run `make docsgen-cli`. + +And you're done! This should create a network upgrade skeleton that you are able to run locally with your local go-state-types clones, and a mock Actors-bundle. This will allow you to: + +- Have a local developer network that starts at the current network version. +- Be able to see the Actor CIDs/Actor version for the mock v12-bundle through `lotus state actor-cids --network-version XX+1` +- Have a successful pre-migration. +- Complete Migration at upgrade epoch, but fail immidiately after the upgrade. + +You can take a look at this [Lotus PR as a reference](https://github.com/filecoin-project/lotus/pull/11432), which added the skeleton for network version 22. + +// TODO: Create a video-tutorial going through all the steps + +[^1]: Here is an example of how you can add a schedule: + + ```go + { + Height: build.UpgradeXxxxHeight, + Network: network.Version(XX+1), + Migration: UpgradeActorsV(XX+1), + PreMigrations: []stmgr.PreMigration{{ + PreMigration: PreUpgradeActors(VXX+1), + StartWithin: 120, + DontStartWithin: 15, + StopWithin: 10, + }}, + Expensive: true, + }, + ``` + + This schedule should be added to the `DefaultUpgradeSchedule` function, specifically within the `updates` array. + +[^2]: Here is an example of how you can add a migration: + + ```go + func PreUpgradeActorsV(XX+1)(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 = upgradeActorsV(XX+1)Common(ctx, sm, cache, lbRoot, epoch, lbts, config) + return err + } + + func UpgradeActorsV(XX+1)(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 2. + workerCount := MigrationMaxWorkerCount - 3 + if workerCount <= 0 { + workerCount = 1 + } + config := migration.Config{ + MaxWorkers: uint(workerCount), + JobQueueSize: 1000, + ResultQueueSize: 100, + ProgressLogPeriod: 10 * time.Second, + } + newRoot, err := upgradeActorsV(XX+1)Common(ctx, sm, cache, root, epoch, ts, config) + if err != nil { + return cid.Undef, xerrors.Errorf("migrating actors v11 state: %w", err) + } + return newRoot, nil + } + + func upgradeActorsV(XX+1)Common( + ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, + root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet, + config migration.Config, + ) (cid.Cid, error) { + writeStore := blockstore.NewAutobatch(ctx, sm.ChainStore().StateBlockstore(), units.GiB/4) + adtStore := store.ActorStore(ctx, writeStore) + // ensure that the manifest is loaded in the blockstore + if err := bundle.LoadBundles(ctx, writeStore, actorstypes.Version(XX+1)); err != nil { + return cid.Undef, xerrors.Errorf("failed to load manifest bundle: %w", err) + } + + // Load the state root. + var stateRoot types.StateRoot + if err := adtStore.Get(ctx, root, &stateRoot); err != nil { + return cid.Undef, xerrors.Errorf("failed to decode state root: %w", err) + } + + if stateRoot.Version != types.StateTreeVersion5 { + return cid.Undef, xerrors.Errorf( + "expected state root version 5 for actors v(XX+1) upgrade, got %d", + stateRoot.Version, + ) + } + + manifest, ok := actors.GetManifest(actorstypes.Version(XX+1)) + if !ok { + return cid.Undef, xerrors.Errorf("no manifest CID for v(XX+1) upgrade") + } + + // Perform the migration + newHamtRoot, err := nv(XX+1).MigrateStateTree(ctx, adtStore, manifest, stateRoot.Actors, epoch, config, + migrationLogger{}, cache) + if err != nil { + return cid.Undef, xerrors.Errorf("upgrading to actors v11: %w", err) + } + + // Persist the result. + newRoot, err := adtStore.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) + } + + // Persists the new tree and shuts down the flush worker + if err := writeStore.Flush(ctx); err != nil { + return cid.Undef, xerrors.Errorf("writeStore flush failed: %w", err) + } + + if err := writeStore.Shutdown(ctx); err != nil { + return cid.Undef, xerrors.Errorf("writeStore shutdown failed: %w", err) + } + + return newRoot, nil + } + ``` \ No newline at end of file diff --git a/documentation/misc/RELEASE_ISSUE_TEMPLATE.md b/documentation/misc/RELEASE_ISSUE_TEMPLATE.md index 42f44b95576..e26e06b326d 100644 --- a/documentation/misc/RELEASE_ISSUE_TEMPLATE.md +++ b/documentation/misc/RELEASE_ISSUE_TEMPLATE.md @@ -13,18 +13,12 @@ **Note for whoever is owning the release:** please capture notes as comments in this issue for anything you noticed that could be improved for future releases. There is a *Post Release* step below for incorporating changes back into the [RELEASE_ISSUE_TEMPLATE](https://github.com/filecoin-project/lotus/blob/master/documentation/misc/RELEASE_ISSUE_TEMPLATE.md), and this is easier done by collecting notes from along the way rather than just thinking about it at the end. -First steps: - - [ ] Set shell variables vX.Y.Z `export X=1 && export Y=24 && export Z=3` - - [ ] FFI: Fork a new branch (`release/lotus-vX.Y.Z`) from the filecoin-ffi `master` branch: `git checkout master && git checkout -b release/lotus-v$X.$Y.$Z` - - [ ] FFI: Tag the head of `release/lotus-vX.Y.Z` as `vX.Y.Z-pre1`: `git tag -a v$X.$Y.$Z-pre1 -m"release"` - - [ ] Open and land a PR in lotus `master` that updates the FFI dependency to `vX.Y.Z-pre1` as cut in the previous step - - [ ] 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). - - [ ] Run `make gen && make docsgen-cli` before committing changes - +- [ ] 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). 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` needs to be updated to end with '-rcX' (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 @@ -32,55 +26,22 @@ First steps: - [ ] tag commit with `vX.Y.Z-rcN` - [ ] cut a pre-release [here](https://github.com/filecoin-project/lotus/releases/new?prerelease=true) -**Testing an RC**: - -- [ ] **Stage 0 - Automated Testing** - - Automated Testing - - [ ] CI: Ensure that all tests are passing. - - [ ] Testground tests - -- [ ] **Stage 1 - Internal Testing** - - Binaries - - [ ] Ensure the RC release has downloadable binaries - - Upgrade our testnet infra - - [ ] Wait 24 hours, confirm nodes stay in sync - - Upgrade our mainnet infra - - [ ] Subset of development full archival nodes - - [ ] Subset of bootstrappers (1 per region) - - [ ] Confirm nodes stay in sync - - Metrics report - - Block validation time - - Memory / CPU usage - - Number of goroutines - - IPLD block read latency - - Bandwidth usage - - [ ] If anything has worsened significantly, investigate + fix - - Confirm the following work (some combination of Testground / Calibnet / Mainnet / beta users) - - [ ] Seal a sector - - [ ] make a deal - - [ ] Submit a PoSt - - [ ] (optional) let a sector go faulty, and see it be recovered - -- [ ] **Stage 2 - Community Testing** - - [ ] Test with [SPX](https://github.com/filecoin-project/lotus/discussions/7461) fellows - - [ ] Work on documentations for new features, configuration changes and so on. - -- [ ] **Stage 3 - Community Prod Testing** - - [ ] Update the [CHANGELOG.md](https://github.com/filecoin-project/lotus/blob/master/CHANGELOG.md) to the state that can be used as release note. - - [ ] Invite the wider community through (link to the release issue) - +**Testing** + +Test the release candidate thoroughly, including automated and manual tests to ensure stability and functionality across various environments and scenarios. + **Stable Release** - [ ] Final preparation - [ ] Verify that version string in [`version.go`](https://github.com/filecoin-project/lotus/blob/master/build/version.go) has been updated. - [ ] Verify that codegen is up to date (`make gen && make docsgen-cli`) - [ ] Ensure that [CHANGELOG.md](https://github.com/filecoin-project/lotus/blob/master/CHANGELOG.md) is up to date - - [ ] Merge `release-vX.Y.Z` into the `releases` branch. - - [ ] Tag this merge commit (on the `releases` branch) with `vX.Y.Z` + - [ ] Open a pull request against the `releases` branch with a merge of `release-vX.Y.Z`. - [ ] Cut the release [here](https://github.com/filecoin-project/lotus/releases/new?prerelease=false&target=releases). - + - The target should be the `releases` branch. + - Either make the tag locally and push to the `releases` branch, or allow GitHub to create a new tag via the UI when the release is published. **Post-Release** - - [ ] Merge the `releases` branch back into `master`, ignoring the changes to `version.go` (keep the `-dev` version from master). Do NOT delete the `releases` branch when doing so! + - [ ] Open a pull request against the `master` branch with a merge of the `releases` branch. Conflict resolution should ignore the changes to `version.go` (keep the `-dev` version from master). Do NOT delete the `releases` branch when doing so! - [ ] Update [RELEASE_ISSUE_TEMPLATE.md](https://github.com/filecoin-project/lotus/blob/master/documentation/misc/RELEASE_ISSUE_TEMPLATE.md) with any improvements determined from this latest release iteration. - [ ] Create an issue using [RELEASE_ISSUE_TEMPLATE.md](https://github.com/filecoin-project/lotus/blob/master/documentation/misc/RELEASE_ISSUE_TEMPLATE.md) for the _next_ release. diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index b715c9403fa..ed08caaf877 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit b715c9403faf919e95fdc702cd651e842f18d890 +Subproject commit ed08caaf8778e1b6def83efd37fce41574214353 diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go index 13a12acfa72..218cc189da8 100644 --- a/gateway/proxy_eth.go +++ b/gateway/proxy_eth.go @@ -11,6 +11,7 @@ import ( "github.com/ipfs/go-cid" "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" @@ -26,6 +27,14 @@ func (gw *Node) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) return []ethtypes.EthAddress{}, nil } +func (gw *Node) EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) { + return gw.target.EthAddressToFilecoinAddress(ctx, ethAddress) +} + +func (gw *Node) FilecoinAddressToEthAddress(ctx context.Context, filecoinAddress address.Address) (ethtypes.EthAddress, error) { + return gw.target.FilecoinAddressToEthAddress(ctx, filecoinAddress) +} + func (gw *Node) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) { if err := gw.limit(ctx, chainRateLimitTokens); err != nil { return 0, err @@ -81,7 +90,7 @@ func (gw *Node) checkEthBlockParam(ctx context.Context, blkParam ethtypes.EthBlo return err } - var num ethtypes.EthUint64 = 0 + var num ethtypes.EthUint64 if blkParam.PredefinedBlock != nil { if *blkParam.PredefinedBlock == "earliest" { return fmt.Errorf("block param \"earliest\" is not supported") diff --git a/gen/bundle/bundle.go b/gen/bundle/bundle.go index f57ced15b43..64c13ec32c5 100644 --- a/gen/bundle/bundle.go +++ b/gen/bundle/bundle.go @@ -9,7 +9,7 @@ import ( "github.com/filecoin-project/lotus/build" ) -var tmpl *template.Template = template.Must(template.New("actor-metadata").Parse(` +var tmpl = template.Must(template.New("actor-metadata").Parse(` // WARNING: This file has automatically been generated package build diff --git a/go.mod b/go.mod index 4623f942b80..cc63a9c3852 100644 --- a/go.mod +++ b/go.mod @@ -12,18 +12,20 @@ require ( 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/KarpelesLab/reflink v1.0.1 github.com/Kubuxu/imtui v0.0.0-20210401140320-41663d68d0fa github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 github.com/buger/goterm v1.0.3 + github.com/charmbracelet/lipgloss v0.10.0 github.com/chzyer/readline v1.5.1 github.com/containerd/cgroups v1.1.0 github.com/coreos/go-systemd/v22 v22.5.0 github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.2007.4 github.com/docker/go-units v0.5.0 - github.com/drand/drand v1.5.7 - github.com/drand/kyber v1.2.0 + github.com/drand/drand v1.5.11 + github.com/drand/kyber v1.3.0 github.com/dustin/go-humanize v1.0.1 github.com/elastic/go-elasticsearch/v7 v7.14.0 github.com/elastic/go-sysinfo v1.7.0 @@ -33,13 +35,13 @@ require ( github.com/filecoin-project/dagstore v0.5.2 github.com/filecoin-project/filecoin-ffi v0.30.4-0.20220519234331-bfd1f5f9fe38 github.com/filecoin-project/go-address v1.1.0 - github.com/filecoin-project/go-amt-ipld/v4 v4.2.0 + github.com/filecoin-project/go-amt-ipld/v4 v4.3.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 github.com/filecoin-project/go-commp-utils/nonffi v0.0.0-20220905160352-62059082a837 github.com/filecoin-project/go-crypto v0.0.1 - github.com/filecoin-project/go-data-transfer/v2 v2.0.0-rc7 + github.com/filecoin-project/go-data-transfer/v2 v2.0.0-rc8 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.28.3 @@ -47,11 +49,10 @@ require ( github.com/filecoin-project/go-jsonrpc v0.3.1 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.13.1 + github.com/filecoin-project/go-state-types v0.13.3 github.com/filecoin-project/go-statemachine v1.0.3 github.com/filecoin-project/go-statestore v0.2.0 github.com/filecoin-project/go-storedcounter v0.1.0 - github.com/filecoin-project/kubo-api-client v0.27.0 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 @@ -67,22 +68,21 @@ require ( github.com/georgysavva/scany/v2 v2.0.0 github.com/go-openapi/spec v0.19.11 github.com/golang/mock v1.6.0 - github.com/google/uuid v1.5.0 + github.com/google/go-cmp v0.6.0 + github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.1 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-hclog v1.3.0 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/golang-lru/arc/v2 v2.0.5 + github.com/hashicorp/golang-lru/arc/v2 v2.0.7 github.com/hashicorp/golang-lru/v2 v2.0.7 - github.com/hashicorp/raft v1.3.10 - github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea github.com/icza/backscanner v0.0.0-20210726202459-ac2ffc679f94 github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab + github.com/invopop/jsonschema v0.12.0 github.com/ipfs/bbloom v0.0.4 - github.com/ipfs/boxo v0.18.0 + github.com/ipfs/boxo v0.20.0 github.com/ipfs/go-block-format v0.2.0 github.com/ipfs/go-cid v0.4.1 github.com/ipfs/go-cidutil v0.1.0 @@ -91,7 +91,7 @@ require ( 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.16.0 + github.com/ipfs/go-graphsync v0.17.0 github.com/ipfs/go-ipfs-blocksutil v0.0.1 github.com/ipfs/go-ipld-cbor v0.1.0 github.com/ipfs/go-ipld-format v0.6.0 @@ -99,7 +99,7 @@ require ( github.com/ipfs/go-metrics-interface v0.0.1 github.com/ipfs/go-metrics-prometheus v0.0.2 github.com/ipfs/go-unixfsnode v1.9.0 - github.com/ipld/go-car v0.6.1 + github.com/ipld/go-car v0.6.2 github.com/ipld/go-car/v2 v2.13.1 github.com/ipld/go-codec-dagpb v1.6.0 github.com/ipld/go-ipld-prime v0.21.0 @@ -111,64 +111,64 @@ require ( 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.33.2 - github.com/libp2p/go-libp2p-consensus v0.0.1 - github.com/libp2p/go-libp2p-gorpc v0.6.0 + github.com/libp2p/go-libp2p v0.34.1 github.com/libp2p/go-libp2p-kad-dht v0.25.2 - github.com/libp2p/go-libp2p-pubsub v0.10.0 - github.com/libp2p/go-libp2p-raft v0.4.0 + github.com/libp2p/go-libp2p-pubsub v0.11.0 github.com/libp2p/go-libp2p-record v0.2.0 github.com/libp2p/go-libp2p-routing-helpers v0.7.3 github.com/libp2p/go-maddr-filter v0.1.0 github.com/libp2p/go-msgio v0.3.0 + github.com/manifoldco/promptui v0.9.0 github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-sqlite3 v1.14.16 github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 + github.com/minio/sha256-simd v1.0.1 github.com/mitchellh/go-homedir v1.1.0 github.com/multiformats/go-base32 v0.1.0 - github.com/multiformats/go-multiaddr v0.12.3 + github.com/multiformats/go-multiaddr v0.12.4 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multibase v0.2.0 github.com/multiformats/go-multicodec v0.9.0 github.com/multiformats/go-multihash v0.2.3 github.com/multiformats/go-varint v0.0.7 github.com/open-rpc/meta-schema v0.0.0-20201029221707-1b72ef2ea333 - github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 github.com/pkg/errors v0.9.1 github.com/polydawn/refmt v0.89.0 - github.com/prometheus/client_golang v1.18.0 + github.com/prometheus/client_golang v1.19.1 github.com/puzpuzpuz/xsync/v2 v2.4.0 github.com/raulk/clock v1.1.0 github.com/raulk/go-watchdog v1.3.0 github.com/samber/lo v1.39.0 github.com/stretchr/testify v1.9.0 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/triplewz/poseidon v0.0.0-20220525065023-a7cdb0e183e7 + github.com/triplewz/poseidon v0.0.0-20230828015038-79d8165c88ed github.com/urfave/cli/v2 v2.25.5 github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba - github.com/whyrusleeping/cbor-gen v0.1.0 - github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4 + github.com/whyrusleeping/cbor-gen v0.1.1 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 + github.com/yugabyte/pgx/v5 v5.5.3-yb-2 + github.com/zondax/ledger-filecoin-go v0.11.1 github.com/zyedidia/generic v1.2.1 go.opencensus.io v0.24.0 - go.opentelemetry.io/otel v1.21.0 + go.opentelemetry.io/otel v1.26.0 go.opentelemetry.io/otel/bridge/opencensus v0.39.0 go.opentelemetry.io/otel/exporters/jaeger v1.14.0 - go.opentelemetry.io/otel/sdk v1.21.0 + go.opentelemetry.io/otel/sdk v1.26.0 go.uber.org/atomic v1.11.0 - go.uber.org/fx v1.20.1 + go.uber.org/fx v1.21.1 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.19.0 - golang.org/x/exp v0.0.0-20240213143201-ec583247a57a - golang.org/x/net v0.21.0 - golang.org/x/sync v0.6.0 - golang.org/x/sys v0.17.0 - golang.org/x/term v0.17.0 + golang.org/x/crypto v0.23.0 + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 + golang.org/x/net v0.25.0 + golang.org/x/sync v0.7.0 + golang.org/x/sys v0.20.0 + golang.org/x/term v0.20.0 + golang.org/x/text v0.15.0 golang.org/x/time v0.5.0 - golang.org/x/tools v0.18.0 + golang.org/x/tools v0.21.0 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 gopkg.in/cheggaaa/pb.v1 v1.0.28 gotest.tools v2.2.0+incompatible @@ -182,14 +182,14 @@ require ( github.com/StackExchange/wmi v1.2.1 // indirect github.com/akavel/rsrc v0.8.0 // indirect github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect - github.com/armon/go-metrics v0.3.9 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bep/debounce v1.2.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect - github.com/boltdb/bolt v1.3.1 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cilium/ebpf v0.9.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668 // indirect @@ -197,7 +197,7 @@ require ( 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.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/drand/kyber-bls12381 v0.3.1 // indirect @@ -219,30 +219,26 @@ require ( github.com/go-openapi/jsonpointer v0.19.3 // indirect github.com/go-openapi/jsonreference v0.19.4 // indirect github.com/go-openapi/swag v0.19.11 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.1.2 // indirect + github.com/golang/glog v1.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect + github.com/google/pprof v0.0.0-20240509144519-723abb6459b7 // indirect github.com/hannahhoward/cbor-gen-for v0.0.0-20230214144701-5d17c9d5243c // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-msgpack v0.5.5 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/iancoleman/orderedmap v0.1.0 // indirect github.com/ipfs/go-bitfield v1.1.0 // indirect - github.com/ipfs/go-blockservice v0.5.1 // indirect - github.com/ipfs/go-ipfs-blockstore v1.3.0 // indirect - github.com/ipfs/go-ipfs-cmds v0.10.0 // indirect + github.com/ipfs/go-blockservice v0.5.2 // indirect + github.com/ipfs/go-ipfs-blockstore v1.3.1 // indirect github.com/ipfs/go-ipfs-delay v0.0.1 // indirect - github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect - github.com/ipfs/go-ipfs-exchange-interface v0.2.0 // indirect + github.com/ipfs/go-ipfs-ds-help v1.1.1 // indirect + github.com/ipfs/go-ipfs-exchange-interface v0.2.1 // indirect github.com/ipfs/go-ipfs-pq v0.0.3 // indirect github.com/ipfs/go-ipfs-util v0.0.3 // indirect github.com/ipfs/go-ipld-legacy v0.2.1 // indirect @@ -250,12 +246,12 @@ require ( github.com/ipfs/go-log v1.0.5 // indirect github.com/ipfs/go-merkledag v0.11.0 // indirect github.com/ipfs/go-peertaskqueue v0.8.1 // indirect - github.com/ipfs/go-verifcid v0.0.2 // indirect + github.com/ipfs/go-verifcid v0.0.3 // 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/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/puddle/v2 v2.2.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect @@ -265,7 +261,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect - github.com/klauspost/compress v1.17.6 // indirect + github.com/klauspost/compress v1.17.8 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect @@ -277,74 +273,91 @@ require ( github.com/libp2p/go-netroute v0.2.1 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.1 // indirect - github.com/lucasb-eyer/go-colorful v1.0.3 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/magefile/mage v1.9.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-runewidth v0.0.10 // indirect - github.com/miekg/dns v1.1.58 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/miekg/dns v1.1.59 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect - github.com/minio/sha256-simd v1.0.1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multistream v0.5.0 // indirect github.com/nikkolasg/hexjson v0.1.0 // indirect github.com/nkovacs/streamquote v1.0.0 // indirect - github.com/onsi/ginkgo/v2 v2.15.0 // indirect + github.com/onsi/ginkgo/v2 v2.17.3 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect + github.com/pion/datachannel v1.5.6 // indirect + github.com/pion/dtls/v2 v2.2.11 // indirect + github.com/pion/ice/v2 v2.3.24 // indirect + github.com/pion/interceptor v0.1.29 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/mdns v0.0.12 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.14 // indirect + github.com/pion/rtp v1.8.6 // indirect + github.com/pion/sctp v1.8.16 // indirect + github.com/pion/sdp/v3 v3.0.9 // indirect + github.com/pion/srtp/v2 v2.0.18 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/transport/v2 v2.2.5 // indirect + github.com/pion/turn/v2 v2.1.6 // indirect + github.com/pion/webrtc/v3 v3.2.40 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.6.0 // indirect - github.com/prometheus/common v0.47.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.53.0 // indirect + github.com/prometheus/procfs v0.15.0 // indirect github.com/prometheus/statsd_exporter v0.22.7 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.42.0 // indirect - github.com/quic-go/webtransport-go v0.6.0 // indirect - github.com/rivo/uniseg v0.1.0 // indirect - github.com/rs/cors v1.7.0 // indirect + github.com/quic-go/quic-go v0.44.0 // indirect + github.com/quic-go/webtransport-go v0.8.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v2.18.12+incompatible // indirect github.com/sirupsen/logrus v1.9.2 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/tidwall/gjson v1.14.4 // indirect github.com/twmb/murmur3 v1.1.6 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.0.1 // indirect - github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // 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 v1.21.0 // indirect + github.com/zondax/hid v0.9.2 // indirect + github.com/zondax/ledger-go v0.14.3 // indirect + go.opentelemetry.io/otel/metric v1.26.0 // indirect go.opentelemetry.io/otel/sdk/metric v0.39.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.26.0 // indirect go.uber.org/dig v1.17.1 // indirect go.uber.org/mock v0.4.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect - golang.org/x/mod v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect - gonum.org/v1/gonum v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect - google.golang.org/grpc v1.60.1 // indirect - google.golang.org/protobuf v1.32.0 // indirect + golang.org/x/mod v0.17.0 // indirect + gonum.org/v1/gonum v0.15.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect + google.golang.org/grpc v1.64.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect - lukechampine.com/blake3 v1.2.1 // indirect + lukechampine.com/blake3 v1.3.0 // indirect ) +// https://github.com/magik6k/reflink/commit/cff5a40f3eeca17f44fc95a57ff3878e5ac761dc +// https://github.com/KarpelesLab/reflink/pull/2 +replace github.com/KarpelesLab/reflink => github.com/magik6k/reflink v1.0.2-patch1 + replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi replace github.com/filecoin-project/test-vectors => ./extern/test-vectors - -replace github.com/triplewz/poseidon => github.com/magik6k/poseidon v0.0.0-neptune diff --git a/go.sum b/go.sum index 4fe32e664f7..4de7bda1496 100644 --- a/go.sum +++ b/go.sum @@ -49,8 +49,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.3.0 h1:Ws8e5YmnrGEHzZEzg0YvK/7COGYtTC5PbaH9oSSbgfA= github.com/BurntSushi/toml v1.3.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 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/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= @@ -83,6 +81,7 @@ github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= +github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= @@ -105,14 +104,15 @@ github.com/ardanlabs/darwin/v2 v2.0.0/go.mod h1:MubZ2e9DAYGaym0mClSOi183NYahrrfK github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg= -github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= -github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -124,10 +124,6 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r 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/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= @@ -135,22 +131,34 @@ github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcug github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= -github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd v0.24.0 h1:gL3uHE/IaFj6fcZSu03SvqPMSx7s/dPzfpG/atRwWdo= +github.com/btcsuite/btcd v0.24.0/go.mod h1:K4IDc1593s8jKXIF7yS7yCTSxrknB9z0STzc2j6XgE4= +github.com/btcsuite/btcd/btcec/v2 v2.1.3 h1:xM/n3yIhHAhHy04z4i43C8p4ehixJZMsnrVJkgl+MTE= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= +github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= +github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JGkIguV40SvRY1uliPX8ifOvi6ICsFCw= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3SkEwmHoWBmX1DNXhXZqlTpq6s4tyJGc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/goterm v1.0.3 h1:7V/HeAQHrzPk/U4BvyH2g9u+xbUW9nr4yRPyG59W4fM= github.com/buger/goterm v1.0.3/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -158,8 +166,10 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s= +github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= @@ -173,10 +183,10 @@ github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38 github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4= github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs= github.com/cockroachdb/cockroach-go/v2 v2.2.0/go.mod h1:u3MiKYGupPPjkn3ozknpMUpxPaNLTFWAya419/zv6eI= @@ -220,8 +230,9 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e h1:lj77EKYUpYXTd8CD/+QMIf8b6OIOTsfEBSXiAzuEHTU= github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e/go.mod h1:3ZQK6DMPSz/QZ73jlWxBtUhNA8xZx7LzUFSq/OfP8vk= @@ -246,10 +257,10 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUn 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/drand v1.5.7 h1:5f2D5aH1nEfVI9S6tl2p9bgIDMZ92oltmiY12Kh+eYU= -github.com/drand/drand v1.5.7/go.mod h1:jrJ0244yOHNL5V04vazk3mFatjAWm3i6dg6URWwgbXk= -github.com/drand/kyber v1.2.0 h1:22SbBxsKbgQnJUoyYKIfG909PhBsj0vtANeu4BX5xgE= -github.com/drand/kyber v1.2.0/go.mod h1:6TqFlCc7NGOiNVTF9pF2KcDRfllPd9XOkExuG5Xtwfo= +github.com/drand/drand v1.5.11 h1:7sskUTCsX2lgFiWdGvPh3/P0ZDQKi1lCtI7RQKK010k= +github.com/drand/drand v1.5.11/go.mod h1:TvJjCJ/s4Usn4pKRpDC0N1QaCwSt3YC8fRqhZdpOUU0= +github.com/drand/kyber v1.3.0 h1:TVd7+xoRgKQ4Ck1viNLPFy6IWhuZM36Bq6zDXD8Asls= +github.com/drand/kyber v1.3.0/go.mod h1:f+mNHjiGT++CuueBrpeMhFNdKZAsy0tu03bKq9D5LPA= github.com/drand/kyber-bls12381 v0.3.1 h1:KWb8l/zYTP5yrvKTgvhOrk2eNPscbMiUOIeWBnmUxGo= github.com/drand/kyber-bls12381 v0.3.1/go.mod h1:H4y9bLPu7KZA/1efDg+jtJ7emKx+ro3PU7/jWUVt140= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -280,11 +291,10 @@ github.com/etclabscore/go-openrpc-reflect v0.0.36 h1:kSqNB2U8RVoW4si+4fsv13NGNkR github.com/etclabscore/go-openrpc-reflect v0.0.36/go.mod h1:0404Ky3igAasAOpyj1eESjstTyneBAIk5PgJFbK4s5E= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/filecoin-project/dagstore v0.5.2 h1:Nd6oXdnolbbVhpMpkYT5PJHOjQp4OBSntHpMV5pxj3c= github.com/filecoin-project/dagstore v0.5.2/go.mod h1:mdqKzYrRBHf1pRMthYfMv3n37oOw0Tkx7+TxPt240M0= github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= @@ -297,8 +307,9 @@ github.com/filecoin-project/go-amt-ipld/v3 v3.0.0/go.mod h1:Qa95YNAbtoVCTSVtX38a github.com/filecoin-project/go-amt-ipld/v3 v3.1.0 h1:ZNJ9tEG5bE72vBWYiuh5bkxJVM3ViHNOmQ7qew9n6RE= github.com/filecoin-project/go-amt-ipld/v3 v3.1.0/go.mod h1:UjM2QhDFrrjD5s1CdnkJkat4ga+LqZBZgTMniypABRo= github.com/filecoin-project/go-amt-ipld/v4 v4.0.0/go.mod h1:gF053YQ4BIpzTNDoEwHZas7U3oAwncDVGvOHyY8oDpE= -github.com/filecoin-project/go-amt-ipld/v4 v4.2.0 h1:DQTXQwMXxaetd+lhZGODjt5qC1WYT7tMAlYrWqI/fwI= github.com/filecoin-project/go-amt-ipld/v4 v4.2.0/go.mod h1:0eDVF7pROvxrsxvLJx+SJZXqRaXXcEPUcgb/rG0zGU4= +github.com/filecoin-project/go-amt-ipld/v4 v4.3.0 h1:bY42N1gR0DqrLMCKUPzX1VhYVgXaETQm0Um4ohvyEP8= +github.com/filecoin-project/go-amt-ipld/v4 v4.3.0/go.mod h1:39Ep/yBbF6xN94WevLG9qSbglBJepHa5zeEbAE1pYsc= github.com/filecoin-project/go-bitfield v0.2.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-bitfield v0.2.3/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-bitfield v0.2.4 h1:uZ7MeE+XfM5lqrHJZ93OnhQKc/rveW8p9au0C68JPgk= @@ -313,8 +324,8 @@ github.com/filecoin-project/go-commp-utils/nonffi v0.0.0-20220905160352-62059082 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-crypto v0.0.1 h1:AcvpSGGCgjaY8y1az6AMfKQWreF/pWO2JJGLl6gCq6o= github.com/filecoin-project/go-crypto v0.0.1/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= -github.com/filecoin-project/go-data-transfer/v2 v2.0.0-rc7 h1:v+zJS5B6pA3ptWZS4t8tbt1Hz9qENnN4nVr1w99aSWc= -github.com/filecoin-project/go-data-transfer/v2 v2.0.0-rc7/go.mod h1:V3Y4KbttaCwyg1gwkP7iai8CbQx4mZUGjd3h9GZWLKE= +github.com/filecoin-project/go-data-transfer/v2 v2.0.0-rc8 h1:EWC89lM/tJAjyzaxZ624clq3oyHLoLjISfoyG+WIu9s= +github.com/filecoin-project/go-data-transfer/v2 v2.0.0-rc8/go.mod h1:mK3/NbSljx3Kr335+IXEe8gcdEPA2eZXJaNhodK9bAI= 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= @@ -346,9 +357,9 @@ github.com/filecoin-project/go-state-types v0.0.0-20201102161440-c8033295a1fc/go github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psSz5dy4B5awOJ/E7P2Saeep8g= 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.10/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= -github.com/filecoin-project/go-state-types v0.11.2-0.20230712101859-8f37624fa540/go.mod h1:SyNPwTsU7I22gL2r0OAPcImvLoTVfgRwdK/Y5rR1zz8= -github.com/filecoin-project/go-state-types v0.13.1 h1:4CivvlcHAIoAtFFVVlZtokynaMQu5XLXGoTKhQkfG1I= github.com/filecoin-project/go-state-types v0.13.1/go.mod h1:cHpOPup9H1g2T29dKHAjC2sc7/Ef5ypjuW9A3I+e9yY= +github.com/filecoin-project/go-state-types v0.13.3 h1:9JPkC0E6HDtfHbaOIrFiCDzT/Z0jRTb9En4Y4Ci/b3w= +github.com/filecoin-project/go-state-types v0.13.3/go.mod h1:cHpOPup9H1g2T29dKHAjC2sc7/Ef5ypjuW9A3I+e9yY= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v1.0.3 h1:N07o6alys+V1tNoSTi4WuuoeNC4erS/6jE74+NsgQuk= github.com/filecoin-project/go-statemachine v1.0.3/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54= @@ -357,8 +368,6 @@ 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/kubo-api-client v0.27.0 h1:rQNbReJCCQ8L107VIQR0qjAlEqdDQRYOhDKYcKGcnPI= -github.com/filecoin-project/kubo-api-client v0.27.0/go.mod h1:1+geFlaV8oJRJ4IlVTqL3QC3T1f5N0aGSptErrtcMQs= 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= @@ -454,8 +463,8 @@ github.com/go-openapi/swag v0.19.11 h1:RFTu/dlFySpyVvJDfp/7674JY4SDglYWKztbiIGFp github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= 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= @@ -480,8 +489,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -516,8 +525,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -557,15 +566,16 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20240509144519-723abb6459b7 h1:velgFPYr1X9TDwLIfkV7fWqsFlf7TeP11M/7kPd/dVI= +github.com/google/pprof v0.0.0-20240509144519-723abb6459b7/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -611,26 +621,16 @@ github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyN github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v1.3.0 h1:G0ACM8Z2WilWgPv3Vdzwm3V0BQu/kSmrkVtpe1fy9do= -github.com/hashicorp/go-hclog v1.3.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= @@ -639,18 +639,14 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw= -github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU= +github.com/hashicorp/golang-lru/arc/v2 v2.0.7 h1:QxkVTxwColcduO+LP7eJO56r2hFiG8zEbfAAzRv52KQ= +github.com/hashicorp/golang-lru/arc/v2 v2.0.7/go.mod h1:Pe7gBlGdc8clY5LJ0LpJXMt5AmgmWNH1g+oFFVUHOEc= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/raft v1.3.10 h1:LR5QZX1VQd0DFWZfeCwWawyeKfpS/Tm1yjnJIY5X4Tw= -github.com/hashicorp/raft v1.3.10/go.mod h1:J8naEwc6XaaCfts7+28whSeRvCqTd6e20BlCU3LtEO4= -github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea h1:xykPFhrBAS2J0VBzVa5e80b5ZtYuNQtgXjN40qBZlD4= -github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= @@ -672,11 +668,13 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt 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= github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.18.0 h1:MOL9/AgoV3e7jlVMInicaSdbgralfqSsbkc31dZ9tmw= -github.com/ipfs/boxo v0.18.0/go.mod h1:pIZgTWdm3k3pLF9Uq6MB8JEcW07UDwNJjlXW1HELW80= +github.com/ipfs/boxo v0.20.0 h1:umUl7q1v5g5AX8FPLTnZBvvagLmT+V0Tt61EigP81ec= +github.com/ipfs/boxo v0.20.0/go.mod h1:mwttn53Eibgska2DhVIj7ln3UViq7MVHRxOMb+ehSDM= github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA= github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU= github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= @@ -691,8 +689,8 @@ github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNi github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= 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= -github.com/ipfs/go-blockservice v0.5.1 h1:9pAtkyKAz/skdHTh0kH8VulzWp+qmSDD0aI17TYP/s0= -github.com/ipfs/go-blockservice v0.5.1/go.mod h1:VpMblFEqG67A/H2sHKAemeH9vlURVavlysbdUI632yk= +github.com/ipfs/go-blockservice v0.5.2 h1:in9Bc+QcXwd1apOVM7Un9t8tixPKdaHQFdLSUM1Xgk8= +github.com/ipfs/go-blockservice v0.5.2/go.mod h1:VpMblFEqG67A/H2sHKAemeH9vlURVavlysbdUI632yk= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -742,33 +740,32 @@ github.com/ipfs/go-ds-measure v0.2.0/go.mod h1:SEUD/rE2PwRa4IQEC5FuNAmjJCyYObZr9 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.16.0 h1:0BX7whXlV13Y9FZ/jRg+xaGHaGYbtGxGppKD6tncw6k= -github.com/ipfs/go-graphsync v0.16.0/go.mod h1:WfbMW3hhmX5GQEQ+KJxsFzVJVBKgC5szfrYK7Zc7xIM= +github.com/ipfs/go-graphsync v0.17.0 h1:1gh10v94G/vSGzfApVtbZSvSKkK906Y+2sRqewjDTm4= +github.com/ipfs/go-graphsync v0.17.0/go.mod h1:HXHiTRIw3wrN3InMwdV+IzpBAtreEf/KqFlEibhfVgo= 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= github.com/ipfs/go-ipfs-blockstore v1.1.2/go.mod h1:w51tNR9y5+QXB0wkNcHt4O2aSZjTdqaEWaQdSxEyUOY= github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE= -github.com/ipfs/go-ipfs-blockstore v1.3.0 h1:m2EXaWgwTzAfsmt5UdJ7Is6l4gJcaM/A12XwJyvYvMM= -github.com/ipfs/go-ipfs-blockstore v1.3.0/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE= +github.com/ipfs/go-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ= +github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= -github.com/ipfs/go-ipfs-cmds v0.10.0 h1:ZB4+RgYaH4UARfJY0uLKl5UXgApqnRjKbuCiJVcErYk= -github.com/ipfs/go-ipfs-cmds v0.10.0/go.mod h1:sX5d7jkCft9XLPnkgEfXY0z2UBOB5g6fh/obBS0enJE= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= -github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= +github.com/ipfs/go-ipfs-ds-help v1.1.1 h1:B5UJOH52IbcfS56+Ul+sv8jnIV10lbjLF5eOO0C66Nw= +github.com/ipfs/go-ipfs-ds-help v1.1.1/go.mod h1:75vrVCkSdSFidJscs8n4W+77AtTpCIAdDGAwjitJMIo= github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= github.com/ipfs/go-ipfs-exchange-interface v0.1.0/go.mod h1:ych7WPlyHqFvCi/uQI48zLZuAWVP5iTQPXEfVaw5WEI= -github.com/ipfs/go-ipfs-exchange-interface v0.2.0 h1:8lMSJmKogZYNo2jjhUs0izT+dck05pqUw4mWNW9Pw6Y= -github.com/ipfs/go-ipfs-exchange-interface v0.2.0/go.mod h1:z6+RhJuDQbqKguVyslSOuVDhqF9JtTrO3eptSAiW2/Y= +github.com/ipfs/go-ipfs-exchange-interface v0.2.1 h1:jMzo2VhLKSHbVe+mHNzYgs95n0+t0Q69GQ5WhRDZV/s= +github.com/ipfs/go-ipfs-exchange-interface v0.2.1/go.mod h1:MUsYn6rKbG6CTtsDp+lKJPmVt3ZrCViNyH3rfPGsZ2E= github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= github.com/ipfs/go-ipfs-exchange-offline v0.1.1/go.mod h1:vTiBRIbzSwDD0OWm+i3xeT0mO7jG2cbJYatp3HPk5XY= github.com/ipfs/go-ipfs-exchange-offline v0.3.0 h1:c/Dg8GDPzixGd0MC8Jh6mjOwU57uYokgWRFidfvEkuA= @@ -851,11 +848,11 @@ github.com/ipfs/go-unixfs v0.4.5/go.mod h1:BIznJNvt/gEx/ooRMI4Us9K8+qeGO7vx1ohnb github.com/ipfs/go-unixfsnode v1.9.0 h1:ubEhQhr22sPAKO2DNsyVBW7YB/zA8Zkif25aBvz8rc8= github.com/ipfs/go-unixfsnode v1.9.0/go.mod h1:HxRu9HYHOjK6HUqFBAi++7DVoWAHn0o4v/nZ/VA+0g8= 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/go-verifcid v0.0.3 h1:gmRKccqhWDocCRkC+a59g5QW7uJw5bpX9HWBevXa0zs= +github.com/ipfs/go-verifcid v0.0.3/go.mod h1:gcCtGniVzelKrbk9ooUSX/pM3xlH73fZZJDzQJRvOUw= github.com/ipld/go-car v0.1.0/go.mod h1:RCWzaUh2i4mOEkB3W45Vc+9jnS/M6Qay5ooytiBHl3g= -github.com/ipld/go-car v0.6.1 h1:blWbEHf1j62JMWFIqWE//YR0m7k5ZMw0AuUOU5hjrH8= -github.com/ipld/go-car v0.6.1/go.mod h1:oEGXdwp6bmxJCZ+rARSkDliTeYnVzv3++eXajZ+Bmr8= +github.com/ipld/go-car v0.6.2 h1:Hlnl3Awgnq8icK+ze3iRghk805lu8YNq3wlREDTF2qc= +github.com/ipld/go-car v0.6.2/go.mod h1:oEGXdwp6bmxJCZ+rARSkDliTeYnVzv3++eXajZ+Bmr8= github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI= github.com/ipld/go-car/v2 v2.13.1 h1:KnlrKvEPEzr5IZHKTXLAEub+tPrzeAFQVRlSQvuxBO4= github.com/ipld/go-car/v2 v2.13.1/go.mod h1:QkdjjFNGit2GIkpQ953KBwowuoukoM75nP/JI1iDJdo= @@ -890,12 +887,12 @@ github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6 github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.4.1 h1:oKfB/FhuVtit1bBM3zNRRsZ925ZkMN3HXL+LgLUM9lE= github.com/jackc/pgx/v5 v5.4.1/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY= -github.com/jackc/puddle/v2 v2.2.0 h1:RdcDk92EJBuBS55nQMMYFXTxwstHug4jkhT5pq8VxPk= -github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -922,17 +919,17 @@ github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8 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.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= -github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -953,13 +950,15 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= -github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= 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.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/koalacxr/quantile v0.0.1 h1:wAW+SQ286Erny9wOjVww96t8ws+x5Zj6AKHDULUK+o0= @@ -1012,8 +1011,8 @@ github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xS github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= -github.com/libp2p/go-libp2p v0.33.2 h1:vCdwnFxoGOXMKmaGHlDSnL4bM3fQeW8pgIa9DECnb40= -github.com/libp2p/go-libp2p v0.33.2/go.mod h1:zTeppLuCvUIkT118pFVzA8xzP/p2dJYOMApCkFh0Yww= +github.com/libp2p/go-libp2p v0.34.1 h1:fxn9vyLo7vJcXQRNvdRbyPjbzuQgi2UiqC8hEbn8a18= +github.com/libp2p/go-libp2p v0.34.1/go.mod h1:snyJQix4ET6Tj+LeI0VPjjxTtdWpeOhYt5lEY0KirkQ= github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= @@ -1029,8 +1028,6 @@ 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-consensus v0.0.1 h1:jcVbHRZLwTXU9iT/mPi+Lx4/OrIzq3bU1TbZNhYFCV8= -github.com/libp2p/go-libp2p-consensus v0.0.1/go.mod h1:+9Wrfhc5QOqWB0gXI0m6ARlkHfdJpcFXmRU0WoHz4Mo= github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= @@ -1059,8 +1056,6 @@ github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFT github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= -github.com/libp2p/go-libp2p-gorpc v0.6.0 h1:Z3ODCzbKe+2lUtEjRc+W+l8Olj63r68G5w1wrQ9ZsOw= -github.com/libp2p/go-libp2p-gorpc v0.6.0/go.mod h1:jGTsI/yn1xL/9VupJ+DIXo8ExobWDKjwVdjNAfhFKxk= github.com/libp2p/go-libp2p-gostream v0.6.0 h1:QfAiWeQRce6pqnYfmIVWJFXNdDyfiR/qkCnjyaZUPYU= github.com/libp2p/go-libp2p-gostream v0.6.0/go.mod h1:Nywu0gYZwfj7Jc91PQvbGU8dIpqbQQkjWgDuOrFaRdA= github.com/libp2p/go-libp2p-kad-dht v0.25.2 h1:FOIk9gHoe4YRWXTu8SY9Z1d0RILol0TrtApsMDPjAVQ= @@ -1088,11 +1083,9 @@ github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRj github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= -github.com/libp2p/go-libp2p-pubsub v0.10.0 h1:wS0S5FlISavMaAbxyQn3dxMOe2eegMfswM471RuHJwA= -github.com/libp2p/go-libp2p-pubsub v0.10.0/go.mod h1:1OxbaT/pFRO5h+Dpze8hdHQ63R0ke55XTs6b6NwLLkw= +github.com/libp2p/go-libp2p-pubsub v0.11.0 h1:+JvS8Kty0OiyUiN0i8H5JbaCgjnJTRnTHe4rU88dLFc= +github.com/libp2p/go-libp2p-pubsub v0.11.0/go.mod h1:QEb+hEV9WL9wCiUAnpY29FZR6W3zK8qYlaml8R4q6gQ= github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= -github.com/libp2p/go-libp2p-raft v0.4.0 h1:2atEs7/FWH35bRiLh8gTejGh5NA9u4eG7BXjpf/B+Z4= -github.com/libp2p/go-libp2p-raft v0.4.0/go.mod h1:qJCYtFBTbip2wngLxFeAb9o52XmAPi2vSIQ4hV7IpSA= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= 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= @@ -1200,15 +1193,16 @@ github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5 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/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/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magefile/mage v1.9.0 h1:t3AU2wNwehMCW97vuqQLtw6puppWXHO+O2MHo5a50XE= github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magik6k/poseidon v0.0.0-neptune h1:Dfz15iiYGGE9Esvn8pZFlbiiCrHuyZDxm6LGXQfaf9c= -github.com/magik6k/poseidon v0.0.0-neptune/go.mod h1:QYG1d0B4YZD7TgF6qZndTTu4rxUGFCCZAQRDanDj+9c= +github.com/magik6k/reflink v1.0.2-patch1 h1:NXSgQugcESI8Z/jBtuAI83YsZuRauY9i9WOyOnJ7Vns= +github.com/magik6k/reflink v1.0.2-patch1/go.mod h1:WGkTOKNjd1FsJKBw3mu4JvrPEDJyJJ+JPtxBkbPoCok= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -1217,6 +1211,8 @@ github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= +github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= 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= @@ -1226,15 +1222,12 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO 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= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -1242,8 +1235,10 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 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-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -1253,8 +1248,8 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= +github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -1291,6 +1286,10 @@ github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 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/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= @@ -1309,8 +1308,8 @@ github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= 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.12.3 h1:hVBXvPRcKG0w80VinQ23P5t7czWgg65BmIvQKjDydU8= -github.com/multiformats/go-multiaddr v0.12.3/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= +github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc= +github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= 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= @@ -1376,8 +1375,9 @@ github.com/nikkolasg/hexjson v0.1.0 h1:Cgi1MSZVQFoJKYeRpBNEcdF3LB+Zo4fYKsDz7h8uJ github.com/nikkolasg/hexjson v0.1.0/go.mod h1:fbGbWFZ0FmJMFbpCMtJpwb0tudVxSSZ+Es2TsCg57cA= github.com/nkovacs/streamquote v1.0.0 h1:PmVIV08Zlx2lZK5fFZlMZ04eHcDTIFJCv/5/0twVUow= github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -1386,18 +1386,19 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU= +github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 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.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE= +github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= 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= @@ -1421,8 +1422,6 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -1432,6 +1431,50 @@ github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+ github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= +github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= +github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= +github.com/pion/ice/v2 v2.3.24 h1:RYgzhH/u5lH0XO+ABatVKCtRd+4U1GEaCXSMjNr13tI= +github.com/pion/ice/v2 v2.3.24/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= +github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= +github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= +github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= +github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= +github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= +github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= +github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= +github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= +github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= +github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= +github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= +github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= +github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= +github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= +github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= +github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= +github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= +github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -1453,37 +1496,35 @@ github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 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/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= 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= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= +github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1495,33 +1536,33 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/procfs v0.15.0 h1:A82kmvXJq2jTu5YUhSGNlYoxh85zLnKgPz4bMZgI5Ek= +github.com/prometheus/procfs v0.15.0/go.mod h1:Y0RJ/Y5g5wJpkTisOtqwDSo4HwhGmLB4VQSw2sQJLHk= github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/puzpuzpuz/xsync/v2 v2.4.0 h1:5sXAMHrtx1bg9nbRZTOn8T4MkWe5V+o8yKRH02Eznag= github.com/puzpuzpuz/xsync/v2 v2.4.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM= -github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= -github.com/quic-go/webtransport-go v0.6.0 h1:CvNsKqc4W2HljHJnoT+rMmbRJybShZ0YPFDD3NxaZLY= -github.com/quic-go/webtransport-go v0.6.0/go.mod h1:9KjU4AEBqEQidGHNDkZrb8CAa1abRaosM2yGOyiikEc= +github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= +github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= +github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= +github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -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/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -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= github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -1618,9 +1659,10 @@ 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.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= @@ -1640,7 +1682,8 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 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/triplewz/poseidon v0.0.0-20230828015038-79d8165c88ed h1:C8H2ql+vCBhEi7d3vMBBbdCAKv9s/thfPyLEuSvFpMU= +github.com/triplewz/poseidon v0.0.0-20230828015038-79d8165c88ed/go.mod h1:QYG1d0B4YZD7TgF6qZndTTu4rxUGFCCZAQRDanDj+9c= 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.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= @@ -1648,8 +1691,6 @@ github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMW github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -1676,8 +1717,6 @@ github.com/weaveworks/common v0.0.0-20230531151736-e2613bee6b73 h1:CMM9+/AgM77va github.com/weaveworks/common v0.0.0-20230531151736-e2613bee6b73/go.mod h1:rgbeLfJUtEr+G74cwFPR1k/4N0kDeaeSv/qhUNE4hm8= github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M= github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= -github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= -github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba h1:X4n8JG2e2biEZZXdBKt9HX7DN3bYGFUqljqqy0DqgnY= github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba/go.mod h1:CHQnYnQUEPydYCwuy8lmTHfGmdw9TKrhWV0xLx8l0oM= github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= @@ -1696,8 +1735,9 @@ 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.1.0 h1:Jneeq3V5enErVcuL0NKEbD1Gi+iOvEeFhXOV1S1Fc6g= github.com/whyrusleeping/cbor-gen v0.1.0/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= +github.com/whyrusleeping/cbor-gen v0.1.1 h1:eKfcJIoxivjMtwfCfmJAqSF56MHcWqyIScXwaC1VBgw= +github.com/whyrusleeping/cbor-gen v0.1.1/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= 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= @@ -1705,13 +1745,13 @@ github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= -github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4 h1:NwiwjQDB3CzQ5XH0rdMh1oQqzJH7O2PSLWxif/w3zsY= -github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4/go.mod h1:K+EVq8d5QcQ2At5VECsA+SNZvWefyBXh8TnIsxo1OvQ= github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= 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= @@ -1726,17 +1766,20 @@ github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542/go.mod h1:7T39/ZM github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yugabyte/pgx/v5 v5.5.3-yb-2 h1:SDk2waZb2o6dSLYqk+vq0Ur2jnIv+X2A+P+QPR1UThU= +github.com/yugabyte/pgx/v5 v5.5.3-yb-2/go.mod h1:2SxizGfDY7UDCRTtbI/xd98C/oGN7S/3YoGF8l9gx/c= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -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= -github.com/zondax/ledger-go v0.12.1 h1:hYRcyznPRJp+5mzF2sazTLP2nGvGjYDD2VzhHhFomLU= -github.com/zondax/ledger-go v0.12.1/go.mod h1:KatxXrVDzgWwbssUWsF5+cOJHXPvzQ09YSlzGNuhOEo= +github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= +github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zondax/ledger-filecoin-go v0.11.1 h1:sNfst9L7ntZN5LfLL+rtScKWVBmLiask33QIne+WcxE= +github.com/zondax/ledger-filecoin-go v0.11.1/go.mod h1:pr9sUKUUyJ8epZ/np3vlixq6J8aawlWRwzUwsTsfPNw= +github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= +github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= github.com/zyedidia/generic v1.2.1 h1:Zv5KS/N2m0XZZiuLS82qheRG4X1o5gsWreGb0hR7XDc= github.com/zyedidia/generic v1.2.1/go.mod h1:ly2RBz4mnz1yeuVbQA/VFwGjK3mnHGRj1JuoG336Bis= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= @@ -1760,24 +1803,24 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= +go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= go.opentelemetry.io/otel/bridge/opencensus v0.39.0 h1:YHivttTaDhbZIHuPlg1sWsy2P5gj57vzqPfkHItgbwQ= go.opentelemetry.io/otel/bridge/opencensus v0.39.0/go.mod h1:vZ4537pNjFDXEx//WldAR6Ro2LC8wwmFC76njAXwNPE= go.opentelemetry.io/otel/exporters/jaeger v1.14.0 h1:CjbUNd4iN2hHmWekmOqZ+zSCU+dzZppG8XsV+A3oc8Q= go.opentelemetry.io/otel/exporters/jaeger v1.14.0/go.mod h1:4Ay9kk5vELRrbg5z4cpP9EtmQRFap2Wb0woPG4lujZA= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= +go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= 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.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= -go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8= +go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= +go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= 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= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1787,8 +1830,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk= -go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg= +go.uber.org/fx v1.21.1 h1:RqBh3cYdzZS0uqwVeEjOX2p73dddLpym315myy/Bpb0= +go.uber.org/fx v1.21.1/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= go.uber.org/goleak v1.0.0/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.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -1837,7 +1880,6 @@ golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8U 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= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1852,9 +1894,15 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= 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= @@ -1868,8 +1916,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-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= 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= @@ -1896,8 +1944,8 @@ 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.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1960,9 +2008,15 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 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= @@ -1987,8 +2041,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= @@ -2074,12 +2128,11 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/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-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/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-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2088,20 +2141,33 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2112,8 +2178,11 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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= @@ -2181,16 +2250,16 @@ 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.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= -gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= +gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= +gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= 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= @@ -2253,12 +2322,12 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 h1:OPXtXn7fNMaXwO3JvOmF1QyTc00jsSFFz1vXXBOdCDo= -google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto/googleapis/api v0.0.0-20240515191416-fc5f0ca64291 h1:4HZJ3Xv1cmrJ+0aFo304Zn79ur1HMxptAE7aCPNLSqc= +google.golang.org/genproto/googleapis/api v0.0.0-20240515191416-fc5f0ca64291/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -2281,8 +2350,8 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -2298,8 +2367,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ 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/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2349,8 +2418,8 @@ howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqp howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/itests/cli_test.go b/itests/cli_test.go index a323c0863d4..d2a0876356b 100644 --- a/itests/cli_test.go +++ b/itests/cli_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/clicommands" "github.com/filecoin-project/lotus/itests/kit" ) @@ -23,5 +23,5 @@ func TestClient(t *testing.T) { blockTime := 5 * time.Millisecond client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) - kit.RunClientTest(t, cli.Commands, client) + kit.RunClientTest(t, clicommands.Commands, client) } diff --git a/itests/curio_test.go b/itests/curio_test.go new file mode 100644 index 00000000000..997352dd359 --- /dev/null +++ b/itests/curio_test.go @@ -0,0 +1,67 @@ +package itests + +import ( + "context" + "testing" + "time" + + "github.com/docker/go-units" + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/abi" + + "github.com/filecoin-project/lotus/cli/spcli" + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/node/config" + "github.com/filecoin-project/lotus/node/impl" +) + +func TestCurioNewActor(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + full, miner, esemble := kit.EnsembleMinimal(t, + kit.LatestActorsAt(-1), + kit.MockProofs(), + kit.WithSectorIndexDB(), + ) + + esemble.Start() + blockTime := 100 * time.Millisecond + esemble.BeginMining(blockTime) + + db := miner.BaseAPI.(*impl.StorageMinerAPI).HarmonyDB + + var titles []string + err := db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + require.NoError(t, err) + require.NotEmpty(t, titles) + require.NotContains(t, titles, "base") + + addr := miner.OwnerKey.Address + sectorSizeInt, err := units.RAMInBytes("8MiB") + require.NoError(t, err) + + maddr, err := spcli.CreateStorageMiner(ctx, full, addr, addr, addr, abi.SectorSize(sectorSizeInt), 0) + require.NoError(t, err) + + err = deps.CreateMinerConfig(ctx, full, db, []string{maddr.String()}, "FULL NODE API STRING") + require.NoError(t, err) + + err = db.Select(ctx, &titles, `SELECT title FROM harmony_config WHERE LENGTH(config) > 0`) + require.NoError(t, err) + require.Contains(t, titles, "base") + baseCfg := config.DefaultCurioConfig() + var baseText string + + err = db.QueryRow(ctx, "SELECT config FROM harmony_config WHERE title='base'").Scan(&baseText) + require.NoError(t, err) + _, err = deps.LoadConfigWithUpgrades(baseText, baseCfg) + require.NoError(t, err) + + require.NotNil(t, baseCfg.Addresses) + require.GreaterOrEqual(t, len(baseCfg.Addresses), 1) + + require.Contains(t, baseCfg.Addresses[0].MinerAddresses, maddr.String()) +} diff --git a/itests/direct_data_onboard_verified_test.go b/itests/direct_data_onboard_verified_test.go index df87a48a98f..8d3d9fef78c 100644 --- a/itests/direct_data_onboard_verified_test.go +++ b/itests/direct_data_onboard_verified_test.go @@ -37,6 +37,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin/verifreg" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet/key" + "github.com/filecoin-project/lotus/cli" "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/lib/must" "github.com/filecoin-project/lotus/storage/pipeline/piece" @@ -762,3 +763,124 @@ func epochPtr(ei int64) *abi.ChainEpoch { ep := abi.ChainEpoch(ei) return &ep } + +func TestVerifiedDDOExtendClaim(t *testing.T) { + kit.QuietMiningLogs() + + var ( + blocktime = 2 * time.Millisecond + ctx = context.Background() + ) + + rootKey, err := key.GenerateKey(types.KTSecp256k1) + require.NoError(t, err) + + verifierKey, err := key.GenerateKey(types.KTSecp256k1) + require.NoError(t, err) + + verifiedClientKey1, err := key.GenerateKey(types.KTBLS) + require.NoError(t, err) + + verifiedClientKey2, err := key.GenerateKey(types.KTBLS) + require.NoError(t, err) + + unverifiedClient, err := key.GenerateKey(types.KTBLS) + require.NoError(t, err) + + bal, err := types.ParseFIL("100fil") + require.NoError(t, err) + + client, miner, ens := kit.EnsembleMinimal(t, kit.ThroughRPC(), + kit.RootVerifier(rootKey, abi.NewTokenAmount(bal.Int64())), + kit.Account(verifierKey, abi.NewTokenAmount(bal.Int64())), + kit.Account(verifiedClientKey1, abi.NewTokenAmount(bal.Int64())), + kit.Account(verifiedClientKey2, abi.NewTokenAmount(bal.Int64())), + kit.Account(unverifiedClient, abi.NewTokenAmount(bal.Int64())), + ) + + /* --- Start mining --- */ + + ens.InterconnectAll().BeginMiningMustPost(blocktime) + + minerId, err := address.IDFromAddress(miner.ActorAddr) + require.NoError(t, err) + + /* --- Setup verified registry and clients and allocate datacap to client */ + + _, verifiedClientAddrses := ddoVerifiedSetupVerifiedClient(ctx, t, client, rootKey, verifierKey, []*key.Key{verifiedClientKey1, verifiedClientKey2}) + verifiedClientAddr1 := verifiedClientAddrses[0] + verifiedClientAddr2 := verifiedClientAddrses[1] + + /* --- Prepare piece for onboarding --- */ + + pieceSize := abi.PaddedPieceSize(2048).Unpadded() + pieceData := make([]byte, pieceSize) + _, _ = rand.Read(pieceData) + + dc, err := miner.ComputeDataCid(ctx, pieceSize, bytes.NewReader(pieceData)) + require.NoError(t, err) + + /* --- Allocate datacap for the piece by the verified client --- */ + clientId, allocationId := ddoVerifiedSetupAllocations(ctx, t, client, minerId, dc, verifiedClientAddr1, 0, builtin.EpochsInYear*3) + + /* --- Onboard the piece --- */ + + _, _ = ddoVerifiedOnboardPiece(ctx, t, miner, clientId, allocationId, dc, pieceData) + + oldclaim, err := client.StateGetClaim(ctx, miner.ActorAddr, verifreg.ClaimId(allocationId), types.EmptyTSK) + require.NoError(t, err) + require.NotNil(t, oldclaim) + + prov := cli.ProvInfo{ + Addr: miner.ActorAddr, + ID: abi.ActorID(minerId), + } + + pcm := make(map[verifregtypes13.ClaimId]cli.ProvInfo) + pcm[verifregtypes13.ClaimId(allocationId)] = prov + + // Extend claim with same client + msgs, err := cli.CreateExtendClaimMsg(ctx, client.FullNode, pcm, []string{}, verifiedClientAddr1, (builtin.EpochsInYear*3)+3000, false, true, 100) + require.NoError(t, err) + require.NotNil(t, msgs) + require.Len(t, msgs, 1) + + smsg, err := client.MpoolPushMessage(ctx, msgs[0], nil) + require.NoError(t, err) + + wait, err := client.StateWaitMsg(ctx, smsg.Cid(), 1, 2000, true) + require.NoError(t, err) + require.True(t, wait.Receipt.ExitCode.IsSuccess()) + + newclaim, err := client.StateGetClaim(ctx, miner.ActorAddr, verifreg.ClaimId(allocationId), types.EmptyTSK) + require.NoError(t, err) + require.NotNil(t, newclaim) + require.EqualValues(t, newclaim.TermMax-oldclaim.TermMax, 3000) + + // Extend claim with non-verified client | should fail + _, err = cli.CreateExtendClaimMsg(ctx, client.FullNode, pcm, []string{}, unverifiedClient.Address, verifregtypes13.MaximumVerifiedAllocationTerm, false, true, 100) + require.ErrorContains(t, err, "does not have any datacap") + + // Extend all claim with verified client + msgs, err = cli.CreateExtendClaimMsg(ctx, client.FullNode, nil, []string{miner.ActorAddr.String()}, verifiedClientAddr2, verifregtypes13.MaximumVerifiedAllocationTerm, true, true, 100) + require.NoError(t, err) + require.Len(t, msgs, 1) + smsg, err = client.MpoolPushMessage(ctx, msgs[0], nil) + require.NoError(t, err) + wait, err = client.StateWaitMsg(ctx, smsg.Cid(), 1, 2000, true) + require.NoError(t, err) + require.True(t, wait.Receipt.ExitCode.IsSuccess()) + + // Extend all claims with lower TermMax + msgs, err = cli.CreateExtendClaimMsg(ctx, client.FullNode, pcm, []string{}, verifiedClientAddr2, builtin.EpochsInYear*4, false, true, 100) + require.NoError(t, err) + require.Nil(t, msgs) + + newclaim, err = client.StateGetClaim(ctx, miner.ActorAddr, verifreg.ClaimId(allocationId), types.EmptyTSK) + require.NoError(t, err) + require.NotNil(t, newclaim) + + // TODO: check "claim-updated" event + // New TermMax should be more than 5 years + require.Greater(t, int(newclaim.TermMax), verifregtypes13.MaximumVerifiedAllocationTerm) +} diff --git a/itests/eth_block_hash_test.go b/itests/eth_block_hash_test.go index b582c84e346..e7da435bad6 100644 --- a/itests/eth_block_hash_test.go +++ b/itests/eth_block_hash_test.go @@ -11,6 +11,8 @@ import ( "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/itests/kit" ) @@ -24,44 +26,60 @@ import ( 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 := 250 * time.Millisecond + 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(5))) - defer cancel() + { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + n1.WaitTillChain(ctx, kit.HeightAtLeast(abi.ChainEpoch(5))) + 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(), 5*time.Minute) - n2.WaitTillChain(ctx, kit.BlocksMinedByAll(m1.ActorAddr, m2.ActorAddr)) - defer cancel() + { + // find the first tipset where all miners mined a block. + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + n2.WaitTillChain(ctx, kit.BlocksMinedByAll(m1.ActorAddr, m2.ActorAddr)) + cancel() + } head, err := n2.ChainHead(context.Background()) require.NoError(t, err) + ctx := context.Background() + // let the chain run a little bit longer to minimise the chance of reorgs n2.WaitTillChain(ctx, kit.HeightAtLeast(head.Height()+50)) + tsk := head.Key() for i := 1; i <= int(head.Height()); i++ { hex := fmt.Sprintf("0x%x", i) + ts, err := n2.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(i), tsk) + require.NoError(t, err) + ethBlockA, err := n2.EthGetBlockByNumber(ctx, hex, true) // Cannot use static ErrFullRound error for comparison since it gets reserialized as a JSON RPC error. if err != nil && strings.Contains(err.Error(), "null round") { + require.Less(t, ts.Height(), abi.ChainEpoch(i), "did not expect a tipset at epoch %d", i) continue } require.NoError(t, err) + require.Equal(t, ts.Height(), abi.ChainEpoch(i), "expected a tipset at epoch %i", i) ethBlockB, err := n2.EthGetBlockByHash(ctx, ethBlockA.Hash, true) require.NoError(t, err) require.Equal(t, ethBlockA, ethBlockB) + + numBlocks := len(ts.Blocks()) + expGasLimit := ethtypes.EthUint64(int64(numBlocks) * build.BlockGasLimit) + require.Equal(t, expGasLimit, ethBlockB.GasLimit) } } diff --git a/itests/eth_filter_test.go b/itests/eth_filter_test.go index 9212e60fc01..114a4c2550a 100644 --- a/itests/eth_filter_test.go +++ b/itests/eth_filter_test.go @@ -137,6 +137,41 @@ func TestEthNewPendingTransactionFilter(t *testing.T) { } } +func TestEthNewHeadsSubSimple(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) + + // install filter + subId, err := client.EthSubscribe(ctx, res.Wrap[jsonrpc.RawParams](json.Marshal(ethtypes.EthSubscribeParams{EventType: "newHeads"})).Assert(require.NoError)) + require.NoError(err) + + err = client.EthSubRouter.AddSub(ctx, subId, func(ctx context.Context, resp *ethtypes.EthSubscriptionResponse) error { + rs := *resp + block, ok := rs.Result.(map[string]interface{}) + require.True(ok) + blockNumber, ok := block["number"].(string) + require.True(ok) + + blk, err := client.EthGetBlockByNumber(ctx, blockNumber, false) + require.NoError(err) + require.NotNil(blk) + fmt.Printf("block: %v\n", blk) + // block hashes should match + require.Equal(block["hash"], blk.Hash.String()) + + return nil + }) + require.NoError(err) + time.Sleep(2 * time.Second) +} + func TestEthNewPendingTransactionSub(t *testing.T) { require := require.New(t) @@ -544,7 +579,7 @@ func TestTxReceiptBloom(t *testing.T) { kit.MockProofs(), kit.ThroughRPC()) ens.InterconnectAll().BeginMining(blockTime) - logging.SetLogLevel("fullnode", "DEBUG") + _ = logging.SetLogLevel("fullnode", "DEBUG") ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() diff --git a/itests/eth_hash_lookup_test.go b/itests/eth_hash_lookup_test.go index 0a2c11d3cf1..5edd61d4e8f 100644 --- a/itests/eth_hash_lookup_test.go +++ b/itests/eth_hash_lookup_test.go @@ -296,7 +296,7 @@ func TestTransactionHashLookupSecpFilecoinMessage(t *testing.T) { require.Equal(t, ethtypes.EthBytes(expected), chainTx.Input) } -// TestTransactionHashLookupSecpFilecoinMessage tests to see if lotus can find a Secp Filecoin Message using the transaction hash +// TestTransactionHashLookupNonexistentMessage tests to see if lotus can find a Secp Filecoin Message using the transaction hash func TestTransactionHashLookupNonexistentMessage(t *testing.T) { kit.QuietMiningLogs() diff --git a/itests/gas_estimation_test.go b/itests/gas_estimation_test.go index 24013c8855b..1f3372afec5 100644 --- a/itests/gas_estimation_test.go +++ b/itests/gas_estimation_test.go @@ -125,7 +125,7 @@ func TestEstimateInclusion(t *testing.T) { // Mutate the last byte to get a new address of the same length. toBytes := msg.To.Bytes() - toBytes[len(toBytes)-1] += 1 //nolint:golint + toBytes[len(toBytes)-1] += 1 // revive:disable-line:increment-decrement newAddr, err := address.NewFromBytes(toBytes) require.NoError(t, err) @@ -158,7 +158,7 @@ func TestEstimateInclusion(t *testing.T) { msg.Nonce = 2 msg.To = msg.From - msg.GasLimit -= 1 //nolint:golint + msg.GasLimit -= 1 // revive:disable-line:increment-decrement smsg, err = client.WalletSignMessage(ctx, client.DefaultKey.Address, msg) require.NoError(t, err) diff --git a/itests/gateway_test.go b/itests/gateway_test.go index d20b3bd1a09..2dc4e1034d5 100644 --- a/itests/gateway_test.go +++ b/itests/gateway_test.go @@ -24,7 +24,7 @@ import ( "github.com/filecoin-project/lotus/api/client" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/clicommands" "github.com/filecoin-project/lotus/gateway" "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/itests/multisig" @@ -231,7 +231,7 @@ func TestGatewayCLIDealFlow(t *testing.T) { ctx := context.Background() nodes := startNodesWithFunds(ctx, t, blocktime, maxLookbackCap, maxStateWaitLookbackLimit) - kit.RunClientTest(t, cli.Commands, nodes.lite) + kit.RunClientTest(t, clicommands.Commands, nodes.lite) } type testNodes struct { diff --git a/itests/harmonytask_test.go b/itests/harmonytask_test.go index ab54cbef42f..94024e3e12e 100644 --- a/itests/harmonytask_test.go +++ b/itests/harmonytask_test.go @@ -32,18 +32,18 @@ func withDbSetup(t *testing.T, f func(*kit.TestMiner)) { kit.MockProofs(), kit.WithSectorIndexDB(), ) - logging.SetLogLevel("harmonytask", "debug") + _ = logging.SetLogLevel("harmonytask", "debug") f(miner) } -func (t *task1) Do(tID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { +func (t *task1) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { if !stillOwned() { return false, errors.New("Why not still owned?") } t.myPersonalTableLock.Lock() defer t.myPersonalTableLock.Unlock() - t.WorkCompleted = append(t.WorkCompleted, fmt.Sprintf("taskResult%d", t.myPersonalTable[tID])) + t.WorkCompleted = append(t.WorkCompleted, fmt.Sprintf("taskResult%d", t.myPersonalTable[taskID])) return true, nil } func (t *task1) CanAccept(list []harmonytask.TaskID, e *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { @@ -90,7 +90,7 @@ func TestHarmonyTasks(t *testing.T) { e, err := harmonytask.New(cdb, []harmonytask.TaskInterface{t1}, "test:1") require.NoError(t, err) time.Sleep(time.Second) // do the work. FLAKYNESS RISK HERE. - e.GracefullyTerminate(time.Minute) + e.GracefullyTerminate() expected := []string{"taskResult56", "taskResult73"} sort.Strings(t1.WorkCompleted) require.Equal(t, expected, t1.WorkCompleted, "unexpected results") @@ -104,8 +104,8 @@ type passthru struct { adder func(add harmonytask.AddTaskFunc) } -func (t *passthru) Do(tID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { - return t.do(tID, stillOwned) +func (t *passthru) Do(taskID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + return t.do(taskID, stillOwned) } func (t *passthru) CanAccept(list []harmonytask.TaskID, e *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { return t.canAccept(list, e) @@ -173,8 +173,8 @@ func TestHarmonyTasksWith2PartiesPolling(t *testing.T) { worker, err := harmonytask.New(cdb, []harmonytask.TaskInterface{workerParty}, "test:2") require.NoError(t, err) time.Sleep(time.Second) // do the work. FLAKYNESS RISK HERE. - sender.GracefullyTerminate(time.Second * 5) - worker.GracefullyTerminate(time.Second * 5) + sender.GracefullyTerminate() + worker.GracefullyTerminate() sort.Strings(dest) require.Equal(t, []string{"A", "B"}, dest) }) @@ -204,7 +204,7 @@ func TestWorkStealing(t *testing.T) { worker, err := harmonytask.New(cdb, []harmonytask.TaskInterface{fooLetterSaver(t, cdb, &dest)}, "test:2") require.ErrorIs(t, err, nil) time.Sleep(time.Second) // do the work. FLAKYNESS RISK HERE. - worker.GracefullyTerminate(time.Second * 5) + worker.GracefullyTerminate() require.Equal(t, []string{"M"}, dest) }) } @@ -243,8 +243,8 @@ func TestTaskRetry(t *testing.T) { rcv, err := harmonytask.New(cdb, []harmonytask.TaskInterface{fails2xPerMsg}, "test:2") require.NoError(t, err) time.Sleep(time.Second) - sender.GracefullyTerminate(time.Hour) - rcv.GracefullyTerminate(time.Hour) + sender.GracefullyTerminate() + rcv.GracefullyTerminate() sort.Strings(dest) require.Equal(t, []string{"A", "B"}, dest) type hist struct { @@ -264,3 +264,40 @@ func TestTaskRetry(t *testing.T) { {2, false, "error: intentional 'error'"}}, res) }) } + +func TestBoredom(t *testing.T) { + //t.Parallel() + withDbSetup(t, func(m *kit.TestMiner) { + cdb := m.BaseAPI.(*impl.StorageMinerAPI).HarmonyDB + harmonytask.POLL_DURATION = time.Millisecond * 100 + var taskID harmonytask.TaskID + var ran bool + boredParty := &passthru{ + dtl: harmonytask.TaskTypeDetails{ + Name: "boredTest", + Max: -1, + Cost: resources.Resources{}, + IAmBored: func(add harmonytask.AddTaskFunc) error { + add(func(tID harmonytask.TaskID, tx *harmonydb.Tx) (bool, error) { + taskID = tID + return true, nil + }) + return nil + }, + }, + canAccept: func(list []harmonytask.TaskID, e *harmonytask.TaskEngine) (*harmonytask.TaskID, error) { + require.Equal(t, harmonytask.WorkSourceIAmBored, e.WorkOrigin) + return &list[0], nil + }, + do: func(tID harmonytask.TaskID, stillOwned func() bool) (done bool, err error) { + require.Equal(t, taskID, tID) + ran = true + return true, nil + }, + } + ht, err := harmonytask.New(cdb, []harmonytask.TaskInterface{boredParty}, "test:1") + require.NoError(t, err) + require.Eventually(t, func() bool { return ran }, time.Second, time.Millisecond*100) + ht.GracefullyTerminate() + }) +} diff --git a/itests/kit/blockminer.go b/itests/kit/blockminer.go index bd527910d79..40d23a6cdf0 100644 --- a/itests/kit/blockminer.go +++ b/itests/kit/blockminer.go @@ -256,8 +256,6 @@ func (bm *BlockMiner) MineBlocksMustPost(ctx context.Context, blocktime time.Dur } func (bm *BlockMiner) MineBlocks(ctx context.Context, blocktime time.Duration) { - time.Sleep(time.Second) - // wrap context in a cancellable context. ctx, bm.cancel = context.WithCancel(ctx) @@ -278,8 +276,11 @@ func (bm *BlockMiner) MineBlocks(ctx context.Context, blocktime time.Duration) { default: } + now := time.Duration(time.Now().UnixNano()) + delay := blocktime - (now % blocktime) + select { - case <-time.After(blocktime): + case <-time.After(delay): case <-ctx.Done(): return } diff --git a/itests/kit/client.go b/itests/kit/client.go index f7e4657603e..18e4259e4e8 100644 --- a/itests/kit/client.go +++ b/itests/kit/client.go @@ -141,7 +141,10 @@ func createRandomFile(rseed, size int) ([]byte, string, error) { size = 1600 } data := make([]byte, size) - rand.New(rand.NewSource(int64(rseed))).Read(data) + _, err := rand.New(rand.NewSource(int64(rseed))).Read(data) + if err != nil { + return nil, "", err + } dir, err := os.MkdirTemp(os.TempDir(), "test-make-deal-") if err != nil { diff --git a/itests/kit/ensemble.go b/itests/kit/ensemble.go index ee17df23750..d635f98d4c1 100644 --- a/itests/kit/ensemble.go +++ b/itests/kit/ensemble.go @@ -20,6 +20,7 @@ import ( "github.com/libp2p/go-libp2p/core/peer" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" "github.com/stretchr/testify/require" + "github.com/urfave/cli/v2" "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" @@ -45,6 +46,9 @@ import ( "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet/key" + "github.com/filecoin-project/lotus/cmd/curio/deps" + "github.com/filecoin-project/lotus/cmd/curio/rpc" + "github.com/filecoin-project/lotus/cmd/curio/tasks" "github.com/filecoin-project/lotus/cmd/lotus-seed/seed" "github.com/filecoin-project/lotus/cmd/lotus-worker/sealworker" "github.com/filecoin-project/lotus/gateway" @@ -120,15 +124,17 @@ type Ensemble struct { options *ensembleOpts inactive struct { - fullnodes []*TestFullNode - miners []*TestMiner - workers []*TestWorker + fullnodes []*TestFullNode + providernodes []*TestProviderNode + miners []*TestMiner + workers []*TestWorker } active struct { - fullnodes []*TestFullNode - miners []*TestMiner - workers []*TestWorker - bms map[*TestMiner]*BlockMiner + fullnodes []*TestFullNode + providernodes []*TestProviderNode + miners []*TestMiner + workers []*TestWorker + bms map[*TestMiner]*BlockMiner } genesis struct { version network.Version @@ -221,6 +227,20 @@ func (n *Ensemble) FullNode(full *TestFullNode, opts ...NodeOpt) *Ensemble { return n } +// FullNode enrolls a new Provider node. +func (n *Ensemble) Provider(lp *TestProviderNode, opts ...NodeOpt) *Ensemble { + options := DefaultNodeOpts + for _, o := range opts { + err := o(&options) + require.NoError(n.t, err) + } + + *lp = TestProviderNode{t: n.t, options: options, Deps: &deps.Deps{}} + + n.inactive.providernodes = append(n.inactive.providernodes, lp) + return n +} + // Miner enrolls a new miner, using the provided full node for chain // interactions. func (n *Ensemble) MinerEnroll(minerNode *TestMiner, full *TestFullNode, opts ...NodeOpt) *Ensemble { @@ -689,11 +709,9 @@ func (n *Ensemble) Start() *Ensemble { var mineBlock = make(chan lotusminer.MineReq) - copy := *m.FullNode - copy.FullNode = modules.MakeUuidWrapper(copy.FullNode) - m.FullNode = © - - //m.FullNode.FullNode = modules.MakeUuidWrapper(fn.FullNode) + minerCopy := *m.FullNode + minerCopy.FullNode = modules.MakeUuidWrapper(minerCopy.FullNode) + m.FullNode = &minerCopy opts := []node.Option{ node.StorageMiner(&m.StorageMiner, cfg.Subsystems), @@ -702,8 +720,6 @@ func (n *Ensemble) Start() *Ensemble { node.Test(), node.If(m.options.disableLibp2p, node.MockHost(n.mn)), - //node.Override(new(v1api.RawFullNodeAPI), func() api.FullNode { return modules.MakeUuidWrapper(m.FullNode) }), - //node.Override(new(v1api.RawFullNodeAPI), modules.MakeUuidWrapper), node.Override(new(v1api.RawFullNodeAPI), m.FullNode), node.Override(new(*lotusminer.Miner), lotusminer.NewTestMiner(mineBlock, m.ActorAddr)), @@ -886,6 +902,28 @@ func (n *Ensemble) Start() *Ensemble { // to active, so clear the slice. n.inactive.workers = n.inactive.workers[:0] + for _, p := range n.inactive.providernodes { + + // TODO setup config with options + err := p.Deps.PopulateRemainingDeps(context.Background(), &cli.Context{}, false) + require.NoError(n.t, err) + + shutdownChan := make(chan struct{}) + taskEngine, err := tasks.StartTasks(ctx, p.Deps) + if err != nil { + return nil + } + defer taskEngine.GracefullyTerminate() + + err = rpc.ListenAndServe(ctx, p.Deps, shutdownChan) // Monitor for shutdown. + require.NoError(n.t, err) + finishCh := node.MonitorShutdown(shutdownChan) //node.ShutdownHandler{Component: "rpc server", StopFunc: rpcStopper}, + //node.ShutdownHandler{Component: "provider", StopFunc: stop}, + + <-finishCh + + n.active.providernodes = append(n.active.providernodes, p) + } // --------------------- // MISC // --------------------- diff --git a/itests/kit/ensemble_presets.go b/itests/kit/ensemble_presets.go index 3ec39cf9095..68b85fde025 100644 --- a/itests/kit/ensemble_presets.go +++ b/itests/kit/ensemble_presets.go @@ -101,6 +101,21 @@ func EnsembleOneTwo(t *testing.T, opts ...interface{}) (*TestFullNode, *TestMine return &full, &one, &two, ens } +// EnsembleProvider creates and starts an Ensemble with a single full node and a single provider. +// It does not interconnect nodes nor does it begin mining. +func EnsembleProvider(t *testing.T, opts ...interface{}) (*TestFullNode, *TestProviderNode, *Ensemble) { + opts = append(opts, WithAllSubsystems()) + + eopts, nopts := siftOptions(t, opts) + + var ( + full TestFullNode + provider TestProviderNode + ) + ens := NewEnsemble(t, eopts...).FullNode(&full, nopts...).Provider(&provider, nopts...).Start() + return &full, &provider, ens +} + func siftOptions(t *testing.T, opts []interface{}) (eopts []EnsembleOpt, nopts []NodeOpt) { for _, v := range opts { switch o := v.(type) { diff --git a/itests/kit/node_full.go b/itests/kit/node_full.go index 3e80ed68869..c36f05a7592 100644 --- a/itests/kit/node_full.go +++ b/itests/kit/node_full.go @@ -22,6 +22,7 @@ import ( "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/cmd/curio/deps" "github.com/filecoin-project/lotus/gateway" "github.com/filecoin-project/lotus/node" ) @@ -54,6 +55,17 @@ type TestFullNode struct { options nodeOpts } +// TestProviderNode represents a Provider node enrolled in an Ensemble. +type TestProviderNode struct { + v1api.CurioStruct + + t *testing.T + + *deps.Deps + + options nodeOpts +} + func MergeFullNodes(fullNodes []*TestFullNode) *TestFullNode { var wrappedFullNode TestFullNode var fns api.FullNodeStruct diff --git a/itests/migration_test.go b/itests/migration_test.go index 68991a579a9..e19aaf45f74 100644 --- a/itests/migration_test.go +++ b/itests/migration_test.go @@ -584,7 +584,7 @@ func TestMigrationNV18(t *testing.T) { // check the EthZeroAddress ethZeroAddr, err := (ethtypes.EthAddress{}).ToFilecoinAddress() require.NoError(t, err) - ethZeroAddrID, err := newStateTree.LookupID(ethZeroAddr) + ethZeroAddrID, err := newStateTree.LookupIDAddress(ethZeroAddr) require.NoError(t, err) ethZeroActor, err := newStateTree.GetActor(ethZeroAddrID) require.NoError(t, err) diff --git a/itests/mpool_msg_uuid_test.go b/itests/mpool_msg_uuid_test.go index 3eb30a6f6eb..c821337a803 100644 --- a/itests/mpool_msg_uuid_test.go +++ b/itests/mpool_msg_uuid_test.go @@ -34,7 +34,7 @@ func TestMsgWithoutUuidWithMaxFee(t *testing.T) { To: node.DefaultKey.Address, Value: big.Div(bal, big.NewInt(2)), } - smHalfBal, err := node.MpoolPushMessage(ctx, msgHalfBal, &api.MessageSendSpec{MaxFee: abi.TokenAmount(config.DefaultDefaultMaxFee)}) + smHalfBal, err := node.MpoolPushMessage(ctx, msgHalfBal, &api.MessageSendSpec{MaxFee: abi.TokenAmount(config.DefaultDefaultMaxFee())}) require.NoError(t, err) mLookup, err := node.StateWaitMsg(ctx, smHalfBal.Cid(), 3, api.LookbackNoLimit, true) require.NoError(t, err) @@ -45,7 +45,7 @@ func TestMsgWithoutUuidWithMaxFee(t *testing.T) { To: node.DefaultKey.Address, Value: big.Div(bal, big.NewInt(4)), } - smQuarterBal, err := node.MpoolPushMessage(ctx, msgQuarterBal, &api.MessageSendSpec{MaxFee: abi.TokenAmount(config.DefaultDefaultMaxFee)}) + smQuarterBal, err := node.MpoolPushMessage(ctx, msgQuarterBal, &api.MessageSendSpec{MaxFee: abi.TokenAmount(config.DefaultDefaultMaxFee())}) require.NoError(t, err) require.Equal(t, msgQuarterBal.Value, smQuarterBal.Message.Value) diff --git a/itests/mpool_push_with_uuid_test.go b/itests/mpool_push_with_uuid_test.go index 6b94dbad191..21f11f62599 100644 --- a/itests/mpool_push_with_uuid_test.go +++ b/itests/mpool_push_with_uuid_test.go @@ -35,7 +35,7 @@ func TestMpoolPushWithoutUuidWithMaxFee(t *testing.T) { To: client15.DefaultKey.Address, Value: big.Div(bal, big.NewInt(2)), } - smHalfBal, err := client15.MpoolPushMessage(ctx, msgHalfBal, &api.MessageSendSpec{MaxFee: abi.TokenAmount(config.DefaultDefaultMaxFee)}) + smHalfBal, err := client15.MpoolPushMessage(ctx, msgHalfBal, &api.MessageSendSpec{MaxFee: abi.TokenAmount(config.DefaultDefaultMaxFee())}) require.NoError(t, err) mLookup, err := client15.StateWaitMsg(ctx, smHalfBal.Cid(), 3, api.LookbackNoLimit, true) require.NoError(t, err) @@ -46,7 +46,7 @@ func TestMpoolPushWithoutUuidWithMaxFee(t *testing.T) { To: client15.DefaultKey.Address, Value: big.Div(bal, big.NewInt(4)), } - smcid, err := client15.MpoolPushMessage(ctx, msgQuarterBal, &api.MessageSendSpec{MaxFee: abi.TokenAmount(config.DefaultDefaultMaxFee)}) + smcid, err := client15.MpoolPushMessage(ctx, msgQuarterBal, &api.MessageSendSpec{MaxFee: abi.TokenAmount(config.DefaultDefaultMaxFee())}) require.NoError(t, err) mLookup, err = client15.StateWaitMsg(ctx, smcid.Cid(), 3, api.LookbackNoLimit, true) require.NoError(t, err) diff --git a/itests/multisig/suite.go b/itests/multisig/suite.go index 9a81d0bf99d..61ca68d5e9e 100644 --- a/itests/multisig/suite.go +++ b/itests/multisig/suite.go @@ -13,14 +13,14 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/clicommands" "github.com/filecoin-project/lotus/itests/kit" ) func RunMultisigTests(t *testing.T, client *kit.TestFullNode) { // Create mock CLI ctx := context.Background() - mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull) + mockCLI := kit.NewMockCLI(ctx, t, clicommands.Commands, api.NodeFull) clientCLI := mockCLI.Client(client.ListenAddr) // Create some wallets on the node to use for testing multisig diff --git a/itests/path_type_filters_test.go b/itests/path_type_filters_test.go index c668976ac2d..a2e2049323b 100644 --- a/itests/path_type_filters_test.go +++ b/itests/path_type_filters_test.go @@ -15,6 +15,7 @@ import ( ) func TestPathTypeFilters(t *testing.T) { + kit.QuietMiningLogs() runTest := func(t *testing.T, name string, asserts func(t *testing.T, ctx context.Context, miner *kit.TestMiner, run func())) { t.Run(name, func(t *testing.T) { diff --git a/itests/paych_cli_test.go b/itests/paych_cli_test.go index f86f5d8deca..1079aade9fb 100644 --- a/itests/paych_cli_test.go +++ b/itests/paych_cli_test.go @@ -25,7 +25,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/cli/clicommands" "github.com/filecoin-project/lotus/itests/kit" ) @@ -51,7 +51,7 @@ func TestPaymentChannelsBasic(t *testing.T) { creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull) + mockCLI := kit.NewMockCLI(ctx, t, clicommands.Commands, api.NodeFull) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr) @@ -126,7 +126,7 @@ func TestPaymentChannelStatus(t *testing.T) { creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull) + mockCLI := kit.NewMockCLI(ctx, t, clicommands.Commands, api.NodeFull) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) // creator: paych status-by-from-to @@ -212,7 +212,7 @@ func TestPaymentChannelVouchers(t *testing.T) { creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull) + mockCLI := kit.NewMockCLI(ctx, t, clicommands.Commands, api.NodeFull) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr) @@ -350,7 +350,7 @@ func TestPaymentChannelVoucherCreateShortfall(t *testing.T) { creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime) // Create mock CLI - mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull) + mockCLI := kit.NewMockCLI(ctx, t, clicommands.Commands, api.NodeFull) creatorCLI := mockCLI.Client(paymentCreator.ListenAddr) // creator: paych add-funds diff --git a/itests/raft_messagesigner_test.go b/itests/raft_messagesigner_test.go deleted file mode 100644 index 220da96996b..00000000000 --- a/itests/raft_messagesigner_test.go +++ /dev/null @@ -1,577 +0,0 @@ -package itests - -import ( - "context" - "crypto/rand" - "fmt" - "reflect" - "testing" - "time" - - "github.com/google/uuid" - gorpc "github.com/libp2p/go-libp2p-gorpc" - libp2pcrypto "github.com/libp2p/go-libp2p/core/crypto" - "github.com/libp2p/go-libp2p/core/peer" - "github.com/stretchr/testify/require" - - "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/chain/messagesigner" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/itests/kit" - consensus "github.com/filecoin-project/lotus/lib/consensus/raft" - "github.com/filecoin-project/lotus/node" - "github.com/filecoin-project/lotus/node/config" - "github.com/filecoin-project/lotus/node/impl" - "github.com/filecoin-project/lotus/node/modules" -) - -func generatePrivKey() (*kit.Libp2p, error) { - privkey, _, err := libp2pcrypto.GenerateEd25519Key(rand.Reader) - if err != nil { - return nil, err - } - - peerId, err := peer.IDFromPrivateKey(privkey) - if err != nil { - return nil, err - } - - return &kit.Libp2p{PeerID: peerId, PrivKey: privkey}, nil -} - -func getRaftState(ctx context.Context, t *testing.T, node *kit.TestFullNode) *api.RaftStateData { - raftState, err := node.RaftState(ctx) - require.NoError(t, err) - return raftState -} - -func setup(ctx context.Context, t *testing.T, node0 *kit.TestFullNode, node1 *kit.TestFullNode, node2 *kit.TestFullNode, miner *kit.TestMiner) *kit.Ensemble { - - blockTime := 1 * time.Second - - pkey0, _ := generatePrivKey() - pkey1, _ := generatePrivKey() - pkey2, _ := generatePrivKey() - - pkeys := []*kit.Libp2p{pkey0, pkey1, pkey2} - initPeerSet := []string{} - for _, pkey := range pkeys { - initPeerSet = append(initPeerSet, "/p2p/"+pkey.PeerID.String()) - } - - //initPeerSet := []peer.ID{pkey0.PeerID, pkey1.PeerID, pkey2.PeerID} - - raftOps := kit.ConstructorOpts( - node.Override(new(*gorpc.Client), modules.NewRPCClient), - node.Override(new(*consensus.ClusterRaftConfig), func() *consensus.ClusterRaftConfig { - cfg := consensus.DefaultClusterRaftConfig() - cfg.InitPeerset = initPeerSet - return cfg - }), - node.Override(new(*consensus.Consensus), consensus.NewConsensusWithRPCClient(false)), - node.Override(new(*messagesigner.MessageSignerConsensus), messagesigner.NewMessageSignerConsensus), - node.Override(new(messagesigner.MsgSigner), func(ms *messagesigner.MessageSignerConsensus) *messagesigner.MessageSignerConsensus { return ms }), - node.Override(new(*modules.RPCHandler), modules.NewRPCHandler), - node.Override(node.GoRPCServer, modules.NewRPCServer), - ) - //raftOps := kit.ConstructorOpts() - - ens := kit.NewEnsemble(t).FullNode(node0, raftOps, kit.ThroughRPC()).FullNode(node1, raftOps, kit.ThroughRPC()).FullNode(node2, raftOps, kit.ThroughRPC()) - node0.AssignPrivKey(pkey0) - node1.AssignPrivKey(pkey1) - node2.AssignPrivKey(pkey2) - - nodes := []*kit.TestFullNode{node0, node1, node2} - wrappedFullNode := kit.MergeFullNodes(nodes) - - ens.MinerEnroll(miner, wrappedFullNode, kit.WithAllSubsystems(), kit.ThroughRPC()) - ens.Start() - - // Import miner wallet to all nodes - addr0, err := node0.WalletImport(ctx, &miner.OwnerKey.KeyInfo) - require.NoError(t, err) - addr1, err := node1.WalletImport(ctx, &miner.OwnerKey.KeyInfo) - require.NoError(t, err) - addr2, err := node2.WalletImport(ctx, &miner.OwnerKey.KeyInfo) - require.NoError(t, err) - - fmt.Println(addr0, addr1, addr2) - - ens.InterconnectAll() - - ens.AddInactiveMiner(miner) - ens.Start() - - ens.InterconnectAll().BeginMining(blockTime) - - return ens -} - -func TestRaftState(t *testing.T) { - - kit.QuietMiningLogs() - ctx := context.Background() - - var ( - node0 kit.TestFullNode - node1 kit.TestFullNode - node2 kit.TestFullNode - miner kit.TestMiner - ) - - setup(ctx, t, &node0, &node1, &node2, &miner) - - fmt.Println(node0.WalletList(context.Background())) - fmt.Println(node1.WalletList(context.Background())) - fmt.Println(node2.WalletList(context.Background())) - - bal, err := node0.WalletBalance(ctx, node0.DefaultKey.Address) - require.NoError(t, err) - - msgHalfBal := &types.Message{ - From: miner.OwnerKey.Address, - To: node0.DefaultKey.Address, - Value: big.Div(bal, big.NewInt(2)), - } - - mu := uuid.New() - smHalfBal, err := node0.MpoolPushMessage(ctx, msgHalfBal, &api.MessageSendSpec{ - MsgUuid: mu, - }) - require.NoError(t, err) - mLookup, err := node0.StateWaitMsg(ctx, smHalfBal.Cid(), 3, api.LookbackNoLimit, true) - require.NoError(t, err) - require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode) - - rstate0 := getRaftState(ctx, t, &node0) - rstate1 := getRaftState(ctx, t, &node1) - rstate2 := getRaftState(ctx, t, &node2) - - require.EqualValues(t, rstate0, rstate1) - require.EqualValues(t, rstate0, rstate2) -} - -func TestRaftStateLeaderDisconnects(t *testing.T) { - - kit.QuietMiningLogs() - ctx := context.Background() - - var ( - node0 kit.TestFullNode - node1 kit.TestFullNode - node2 kit.TestFullNode - miner kit.TestMiner - ) - - nodes := []*kit.TestFullNode{&node0, &node1, &node2} - - setup(ctx, t, &node0, &node1, &node2, &miner) - - peerToNode := make(map[peer.ID]*kit.TestFullNode) - for _, n := range nodes { - peerToNode[n.Pkey.PeerID] = n - } - - bal, err := node0.WalletBalance(ctx, node0.DefaultKey.Address) - require.NoError(t, err) - - msgHalfBal := &types.Message{ - From: miner.OwnerKey.Address, - To: node0.DefaultKey.Address, - Value: big.Div(bal, big.NewInt(2)), - } - mu := uuid.New() - smHalfBal, err := node0.MpoolPushMessage(ctx, msgHalfBal, &api.MessageSendSpec{ - MsgUuid: mu, - }) - require.NoError(t, err) - mLookup, err := node0.StateWaitMsg(ctx, smHalfBal.Cid(), 3, api.LookbackNoLimit, true) - require.NoError(t, err) - require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode) - - rstate0 := getRaftState(ctx, t, &node0) - rstate1 := getRaftState(ctx, t, &node1) - rstate2 := getRaftState(ctx, t, &node2) - - require.True(t, reflect.DeepEqual(rstate0, rstate1)) - require.True(t, reflect.DeepEqual(rstate0, rstate2)) - - leader, err := node1.RaftLeader(ctx) - require.NoError(t, err) - leaderNode := peerToNode[leader] - - err = leaderNode.Stop(ctx) - require.NoError(t, err) - oldLeaderNode := leaderNode - - time.Sleep(5 * time.Second) - - newLeader := leader - for _, n := range nodes { - if n != leaderNode { - newLeader, err = n.RaftLeader(ctx) - require.NoError(t, err) - require.NotEqual(t, newLeader, leader) - } - } - - require.NotEqual(t, newLeader, leader) - leaderNode = peerToNode[newLeader] - - msg2 := &types.Message{ - From: miner.OwnerKey.Address, - To: leaderNode.DefaultKey.Address, - Value: big.NewInt(100000), - } - mu2 := uuid.New() - signedMsg2, err := leaderNode.MpoolPushMessage(ctx, msg2, &api.MessageSendSpec{ - MsgUuid: mu2, - }) - require.NoError(t, err) - mLookup, err = leaderNode.StateWaitMsg(ctx, signedMsg2.Cid(), 3, api.LookbackNoLimit, true) - require.NoError(t, err) - require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode) - - rstate := getRaftState(ctx, t, leaderNode) - - for _, n := range nodes { - if n != oldLeaderNode { - rs := getRaftState(ctx, t, n) - require.True(t, reflect.DeepEqual(rs, rstate)) - } - } -} - -func TestRaftStateMiner(t *testing.T) { - - kit.QuietMiningLogs() - ctx := context.Background() - - var ( - node0 kit.TestFullNode - node1 kit.TestFullNode - node2 kit.TestFullNode - miner kit.TestMiner - ) - - setup(ctx, t, &node0, &node1, &node2, &miner) - - fmt.Println(node0.WalletList(context.Background())) - fmt.Println(node1.WalletList(context.Background())) - fmt.Println(node2.WalletList(context.Background())) - - bal, err := node0.WalletBalance(ctx, node0.DefaultKey.Address) - require.NoError(t, err) - - msgHalfBal := &types.Message{ - From: miner.OwnerKey.Address, - To: node0.DefaultKey.Address, - Value: big.Div(bal, big.NewInt(2)), - } - mu := uuid.New() - smHalfBal, err := miner.FullNode.MpoolPushMessage(ctx, msgHalfBal, &api.MessageSendSpec{ - MsgUuid: mu, - }) - require.NoError(t, err) - mLookup, err := node0.StateWaitMsg(ctx, smHalfBal.Cid(), 3, api.LookbackNoLimit, true) - require.NoError(t, err) - require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode) - - rstate0 := getRaftState(ctx, t, &node0) - rstate1 := getRaftState(ctx, t, &node1) - rstate2 := getRaftState(ctx, t, &node2) - - require.EqualValues(t, rstate0, rstate1) - require.EqualValues(t, rstate0, rstate2) -} - -func TestRaftStateLeaderDisconnectsMiner(t *testing.T) { - - kit.QuietMiningLogs() - ctx := context.Background() - - var ( - node0 kit.TestFullNode - node1 kit.TestFullNode - node2 kit.TestFullNode - miner kit.TestMiner - ) - - nodes := []*kit.TestFullNode{&node0, &node1, &node2} - - setup(ctx, t, &node0, &node1, &node2, &miner) - - peerToNode := make(map[peer.ID]*kit.TestFullNode) - for _, n := range nodes { - peerToNode[n.Pkey.PeerID] = n - } - - leader, err := node0.RaftLeader(ctx) - require.NoError(t, err) - leaderNode := peerToNode[leader] - - // Take leader node down - err = leaderNode.Stop(ctx) - require.NoError(t, err) - oldLeaderNode := leaderNode - - time.Sleep(5 * time.Second) - - newLeader := leader - for _, n := range nodes { - if n != leaderNode { - newLeader, err = n.RaftLeader(ctx) - require.NoError(t, err) - require.NotEqual(t, newLeader, leader) - } - } - - require.NotEqual(t, newLeader, leader) - leaderNode = peerToNode[newLeader] - - msg2 := &types.Message{ - From: miner.OwnerKey.Address, - To: node0.DefaultKey.Address, - Value: big.NewInt(100000), - } - mu2 := uuid.New() - - signedMsg2, err := miner.FullNode.MpoolPushMessage(ctx, msg2, &api.MessageSendSpec{ - MaxFee: abi.TokenAmount(config.DefaultDefaultMaxFee), - MsgUuid: mu2, - }) - require.NoError(t, err) - - mLookup, err := leaderNode.StateWaitMsg(ctx, signedMsg2.Cid(), 3, api.LookbackNoLimit, true) - require.NoError(t, err) - require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode) - - rstate := getRaftState(ctx, t, leaderNode) - - for _, n := range nodes { - if n != oldLeaderNode { - rs := getRaftState(ctx, t, n) - require.True(t, reflect.DeepEqual(rs, rstate)) - } - } -} - -// Miner sends message on leader -// Leader disconnects -// Call StateWaitMsg on new leader -func TestLeaderDisconnectsCheckMsgStateOnNewLeader(t *testing.T) { - - kit.QuietMiningLogs() - ctx := context.Background() - - var ( - node0 kit.TestFullNode - node1 kit.TestFullNode - node2 kit.TestFullNode - miner kit.TestMiner - ) - - nodes := []*kit.TestFullNode{&node0, &node1, &node2} - - setup(ctx, t, &node0, &node1, &node2, &miner) - - peerToNode := make(map[peer.ID]*kit.TestFullNode) - for _, n := range nodes { - peerToNode[n.Pkey.PeerID] = n - } - - bal, err := node0.WalletBalance(ctx, node0.DefaultKey.Address) - require.NoError(t, err) - - msgHalfBal := &types.Message{ - From: miner.OwnerKey.Address, - To: node0.DefaultKey.Address, - Value: big.Div(bal, big.NewInt(2)), - } - mu := uuid.New() - smHalfBal, err := miner.FullNode.MpoolPushMessage(ctx, msgHalfBal, &api.MessageSendSpec{ - MsgUuid: mu, - }) - require.NoError(t, err) - - leader, err := node0.RaftLeader(ctx) - require.NoError(t, err) - leaderNode := peerToNode[leader] - - // Take leader node down - err = leaderNode.Stop(ctx) - require.NoError(t, err) - oldLeaderNode := leaderNode - - time.Sleep(5 * time.Second) - - // Check if all active nodes update their leader - newLeader := leader - for _, n := range nodes { - if n != leaderNode { - newLeader, err = n.RaftLeader(ctx) - require.NoError(t, err) - require.NotEqual(t, newLeader, leader) - } - } - - require.NotEqual(t, newLeader, leader) - leaderNode = peerToNode[newLeader] - - mLookup, err := leaderNode.StateWaitMsg(ctx, smHalfBal.Cid(), 3, api.LookbackNoLimit, true) - require.NoError(t, err) - require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode) - - rstate := getRaftState(ctx, t, leaderNode) - - // Check if Raft state is consistent on all active nodes - for _, n := range nodes { - if n != oldLeaderNode { - rs := getRaftState(ctx, t, n) - require.True(t, reflect.DeepEqual(rs, rstate)) - } - } -} - -func TestChainStoreSync(t *testing.T) { - - kit.QuietMiningLogs() - ctx := context.Background() - - var ( - node0 kit.TestFullNode - node1 kit.TestFullNode - node2 kit.TestFullNode - miner kit.TestMiner - ) - - nodes := []*kit.TestFullNode{&node0, &node1, &node2} - - setup(ctx, t, &node0, &node1, &node2, &miner) - - peerToNode := make(map[peer.ID]*kit.TestFullNode) - for _, n := range nodes { - peerToNode[n.Pkey.PeerID] = n - } - - bal, err := node0.WalletBalance(ctx, node0.DefaultKey.Address) - require.NoError(t, err) - - leader, err := node0.RaftLeader(ctx) - require.NoError(t, err) - leaderNode := peerToNode[leader] - - msgHalfBal := &types.Message{ - From: miner.OwnerKey.Address, - To: node0.DefaultKey.Address, - Value: big.Div(bal, big.NewInt(2)), - } - mu := uuid.New() - smHalfBal, err := miner.FullNode.MpoolPushMessage(ctx, msgHalfBal, &api.MessageSendSpec{ - MsgUuid: mu, - }) - require.NoError(t, err) - - for _, n := range nodes { - fmt.Println(n != leaderNode) - if n != leaderNode { - mLookup, err := n.StateWaitMsg(ctx, smHalfBal.Cid(), 3, api.LookbackNoLimit, true) - require.NoError(t, err) - require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode) - //break - } - } -} - -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 - - kit.QuietMiningLogs() - ctx := context.Background() - - var ( - node0 kit.TestFullNode - node1 kit.TestFullNode - node2 kit.TestFullNode - node3 kit.TestFullNode - miner kit.TestMiner - ) - - pkey0, _ := generatePrivKey() - pkey1, _ := generatePrivKey() - pkey2, _ := generatePrivKey() - - pkeys := []*kit.Libp2p{pkey0, pkey1, pkey2} - initPeerSet := []string{} - for _, pkey := range pkeys { - initPeerSet = append(initPeerSet, "/p2p/"+pkey.PeerID.String()) - } - - raftOps := kit.ConstructorOpts( - node.Override(new(*gorpc.Client), modules.NewRPCClient), - node.Override(new(*consensus.ClusterRaftConfig), func() *consensus.ClusterRaftConfig { - cfg := consensus.DefaultClusterRaftConfig() - cfg.InitPeerset = initPeerSet - return cfg - }), - node.Override(new(*consensus.Consensus), consensus.NewConsensusWithRPCClient(false)), - node.Override(new(*messagesigner.MessageSignerConsensus), messagesigner.NewMessageSignerConsensus), - node.Override(new(messagesigner.MsgSigner), func(ms *messagesigner.MessageSignerConsensus) *messagesigner.MessageSignerConsensus { return ms }), - node.Override(new(*modules.RPCHandler), modules.NewRPCHandler), - node.Override(node.GoRPCServer, modules.NewRPCServer), - ) - //raftOps := kit.ConstructorOpts() - - 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) - node1.AssignPrivKey(pkey1) - node2.AssignPrivKey(pkey2) - - nodes := []*kit.TestFullNode{&node0, &node1, &node2} - wrappedFullNode := kit.MergeFullNodes(nodes) - - ens.MinerEnroll(&miner, wrappedFullNode, kit.WithAllSubsystems(), kit.ThroughRPC()) - ens.Start() - - // Import miner wallet to all nodes - addr0, err := node0.WalletImport(ctx, &miner.OwnerKey.KeyInfo) - require.NoError(t, err) - addr1, err := node1.WalletImport(ctx, &miner.OwnerKey.KeyInfo) - require.NoError(t, err) - addr2, err := node2.WalletImport(ctx, &miner.OwnerKey.KeyInfo) - require.NoError(t, err) - - fmt.Println(addr0, addr1, addr2) - - ens.InterconnectAll() - - ens.AddInactiveMiner(&miner) - ens.Start() - - ens.InterconnectAll().BeginMining(blockTime) - - leader, err := node0.RaftLeader(ctx) - require.NoError(t, err) - - client := node3.FullNode.(*impl.FullNodeAPI).RaftAPI.MessageSigner.Consensus.RpcClient - method := "MpoolPushMessage" - - msg := &types.Message{ - From: miner.OwnerKey.Address, - To: node0.DefaultKey.Address, - Value: big.NewInt(100000), - } - msgWhole := &api.MpoolMessageWhole{Msg: msg} - var ret types.SignedMessage - - err = client.CallContext(ctx, leader, "Consensus", method, msgWhole, &ret) - require.True(t, gorpc.IsAuthorizationError(err)) - -} diff --git a/itests/splitstore_test.go b/itests/splitstore_test.go index ea59faf2a9f..ff2a60a3e99 100644 --- a/itests/splitstore_test.go +++ b/itests/splitstore_test.go @@ -413,9 +413,8 @@ func (g *Garbager) Exists(ctx context.Context, c cid.Cid) bool { } else if err != nil { g.t.Fatalf("ChainReadObj failure on existence check: %s", err) return false // unreachable - } else { - return true } + return true } func (g *Garbager) newPeerID(ctx context.Context) abi.ChainEpoch { diff --git a/journal/alerting/alerts.go b/journal/alerting/alerts.go index 290d06e2aa7..1d6dd0a5c01 100644 --- a/journal/alerting/alerts.go +++ b/journal/alerting/alerts.go @@ -95,7 +95,7 @@ func (a *Alerting) update(at AlertType, message interface{}, upd func(Alert, jso }{ AlertError: err.Error(), }) - log.Errorw("marshaling marshaling error failed", "type", at, "error", err) + log.Errorw("marshaling error failed", "type", at, "error", err) } a.alerts[at] = upd(alert, rawMsg) diff --git a/journal/fsjournal/fs.go b/journal/fsjournal/fs.go index b2eb946fd75..5a74fbfc643 100644 --- a/journal/fsjournal/fs.go +++ b/journal/fsjournal/fs.go @@ -7,6 +7,7 @@ import ( "path/filepath" logging "github.com/ipfs/go-log/v2" + "github.com/mitchellh/go-homedir" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/build" @@ -41,6 +42,11 @@ func OpenFSJournal(lr repo.LockedRepo, disabled journal.DisabledEvents) (journal } func OpenFSJournalPath(path string, disabled journal.DisabledEvents) (journal.Journal, error) { + path, err := homedir.Expand(path) + if err != nil { + return nil, xerrors.Errorf("failed to expand repo path: %w", err) + } + dir := filepath.Join(path, "journal") if err := os.MkdirAll(dir, 0755); err != nil { return nil, fmt.Errorf("failed to mk directory %s for file journal: %w", dir, err) diff --git a/lib/consensus/raft/config.go b/lib/consensus/raft/config.go deleted file mode 100644 index bdd82c10815..00000000000 --- a/lib/consensus/raft/config.go +++ /dev/null @@ -1,135 +0,0 @@ -package consensus - -import ( - "io" - "path/filepath" - "time" - - hraft "github.com/hashicorp/raft" - "golang.org/x/xerrors" - - "github.com/filecoin-project/lotus/node/config" - "github.com/filecoin-project/lotus/node/repo" -) - -// Configuration defaults -var ( - DefaultDataSubFolder = "raft-cluster" - DefaultWaitForLeaderTimeout = 15 * time.Second - DefaultCommitRetries = 1 - DefaultNetworkTimeout = 100 * time.Second - DefaultCommitRetryDelay = 200 * time.Millisecond - DefaultBackupsRotate = 6 -) - -// ClusterRaftConfig allows to configure the Raft Consensus component for the node cluster. -type ClusterRaftConfig struct { - // config to enabled node cluster with raft consensus - ClusterModeEnabled bool - // A folder to store Raft's data. - DataFolder string - // InitPeerset provides the list of initial cluster peers for new Raft - // peers (with no prior state). It is ignored when Raft was already - // initialized or when starting in staging mode. - InitPeerset []string - // LeaderTimeout specifies how long to wait for a leader before - // failing an operation. - WaitForLeaderTimeout time.Duration - // NetworkTimeout specifies how long before a Raft network - // operation is timed out - NetworkTimeout time.Duration - // CommitRetries specifies how many times we retry a failed commit until - // we give up. - CommitRetries int - // How long to wait between retries - CommitRetryDelay time.Duration - // BackupsRotate specifies the maximum number of Raft's DataFolder - // copies that we keep as backups (renaming) after cleanup. - BackupsRotate int - // A Hashicorp Raft's configuration object. - RaftConfig *hraft.Config - - // Tracing enables propagation of contexts across binary boundaries. - Tracing bool -} - -func DefaultClusterRaftConfig() *ClusterRaftConfig { - var cfg ClusterRaftConfig - cfg.DataFolder = "" // empty so it gets omitted - cfg.InitPeerset = []string{} - cfg.WaitForLeaderTimeout = DefaultWaitForLeaderTimeout - cfg.NetworkTimeout = DefaultNetworkTimeout - cfg.CommitRetries = DefaultCommitRetries - cfg.CommitRetryDelay = DefaultCommitRetryDelay - cfg.BackupsRotate = DefaultBackupsRotate - cfg.RaftConfig = hraft.DefaultConfig() - - // These options are imposed over any Default Raft Config. - cfg.RaftConfig.ShutdownOnRemove = false - cfg.RaftConfig.LocalID = "will_be_set_automatically" - - // Set up logging - cfg.RaftConfig.LogOutput = io.Discard - return &cfg -} - -func NewClusterRaftConfig(userRaftConfig *config.UserRaftConfig) *ClusterRaftConfig { - var cfg ClusterRaftConfig - cfg.DataFolder = userRaftConfig.DataFolder - cfg.InitPeerset = userRaftConfig.InitPeersetMultiAddr - cfg.WaitForLeaderTimeout = time.Duration(userRaftConfig.WaitForLeaderTimeout) - cfg.NetworkTimeout = time.Duration(userRaftConfig.NetworkTimeout) - cfg.CommitRetries = userRaftConfig.CommitRetries - cfg.CommitRetryDelay = time.Duration(userRaftConfig.CommitRetryDelay) - cfg.BackupsRotate = userRaftConfig.BackupsRotate - - // Keep this to be default hraft config for now - cfg.RaftConfig = hraft.DefaultConfig() - - // These options are imposed over any Default Raft Config. - cfg.RaftConfig.ShutdownOnRemove = false - cfg.RaftConfig.LocalID = "will_be_set_automatically" - - // Set up logging - cfg.RaftConfig.LogOutput = io.Discard - - return &cfg - -} - -// 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") - } - if cfg.WaitForLeaderTimeout <= 0 { - return xerrors.Errorf("wait_for_leader_timeout <= 0") - } - - if cfg.NetworkTimeout <= 0 { - return xerrors.Errorf("network_timeout <= 0") - } - - if cfg.CommitRetries < 0 { - return xerrors.Errorf("commit_retries is invalid") - } - - if cfg.CommitRetryDelay <= 0 { - return xerrors.Errorf("commit_retry_delay is invalid") - } - - if cfg.BackupsRotate <= 0 { - return xerrors.Errorf("backups_rotate should be larger than 0") - } - - return hraft.ValidateConfig(cfg.RaftConfig) -} - -// GetDataFolder returns the Raft data folder that we are using. -func (cfg *ClusterRaftConfig) GetDataFolder(repo repo.LockedRepo) string { - if cfg.DataFolder == "" { - return filepath.Join(repo.Path(), DefaultDataSubFolder) - } - return filepath.Join(repo.Path(), cfg.DataFolder) -} diff --git a/lib/consensus/raft/consensus.go b/lib/consensus/raft/consensus.go deleted file mode 100644 index d74f200fab1..00000000000 --- a/lib/consensus/raft/consensus.go +++ /dev/null @@ -1,512 +0,0 @@ -// Package raft implements a Consensus component for IPFS Cluster which uses -// Raft (go-libp2p-raft). -package consensus - -import ( - "bytes" - "context" - "errors" - "fmt" - "sort" - "time" - - "github.com/google/uuid" - "golang.org/x/exp/slices" - - addr "github.com/filecoin-project/go-address" - - "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/lib/addrutil" - "github.com/filecoin-project/lotus/node/repo" - - //ds "github.com/ipfs/go-datastore" - logging "github.com/ipfs/go-log/v2" - consensus "github.com/libp2p/go-libp2p-consensus" - rpc "github.com/libp2p/go-libp2p-gorpc" - libp2praft "github.com/libp2p/go-libp2p-raft" - host "github.com/libp2p/go-libp2p/core/host" - peer "github.com/libp2p/go-libp2p/core/peer" -) - -var logger = logging.Logger("raft") - -type RaftState struct { - NonceMap api.NonceMapType - MsgUuids api.MsgUuidMapType - - // TODO: add comment explaining why this is needed - // We need a reference to the messagepool in the raft state in order to - // sync messages that have been sent by the leader node - // Miner calls StateWaitMsg after MpoolPushMessage to check if the message has - // landed on chain. This check requires the message be stored in the local chainstore - // If a leadernode goes down after sending a message to the chain and is replaced by - // another node, the other node needs to have this message in its chainstore for the - // above check to succeed. - - // This is because the miner only stores signed CIDs but the message received from in a - // block will be unsigned (for BLS). Hence, the process relies on the node to store the - // signed message which holds a copy of the unsigned message to properly perform all the - // needed checks - Mpool *messagepool.MessagePool -} - -func newRaftState(mpool *messagepool.MessagePool) *RaftState { - return &RaftState{ - NonceMap: make(map[addr.Address]uint64), - MsgUuids: make(map[uuid.UUID]*types.SignedMessage), - Mpool: mpool, - } -} - -type ConsensusOp struct { - Nonce uint64 `codec:"nonce,omitempty"` - Uuid uuid.UUID `codec:"uuid,omitempty"` - Addr addr.Address `codec:"addr,omitempty"` - SignedMsg *types.SignedMessage `codec:"signedMsg,omitempty"` -} - -func (c ConsensusOp) ApplyTo(state consensus.State) (consensus.State, error) { - s := state.(*RaftState) - s.NonceMap[c.Addr] = c.Nonce - if c.SignedMsg != nil { - - // Deep copy to tmp - var buffer bytes.Buffer - err := c.SignedMsg.MarshalCBOR(&buffer) - if err != nil { - return nil, err - } - tmp, err := types.DecodeSignedMessage(buffer.Bytes()) - if err != nil { - return nil, err - } - s.MsgUuids[c.Uuid] = tmp - - _, err = s.Mpool.Push(context.TODO(), tmp, false) - // Since this is only meant to keep messages in sync, ignore any error which - // shows the message already exists in the mpool - if err != nil && !api.ErrorIsIn(err, []error{messagepool.ErrExistingNonce}) { - return nil, err - } - } - - return s, nil -} - -var _ consensus.Op = &ConsensusOp{} - -// Consensus handles the work of keeping a shared-state between -// the peers of a Lotus Cluster, as well as modifying that state and -// applying any updates in a thread-safe manner. -type Consensus struct { - ctx context.Context - cancel func() - config *ClusterRaftConfig - - host host.Host - - consensus consensus.OpLogConsensus - actor consensus.Actor - raft *raftWrapper - state *RaftState - - RpcClient *rpc.Client - rpcReady chan struct{} - readyCh chan struct{} - - peerSet []peer.ID - repo repo.LockedRepo -} - -// NewConsensus builds a new ClusterConsensus component using Raft. -// -// Raft saves state snapshots regularly and persists log data in a bolt -// datastore. Therefore, unless memory usage is a concern, it is recommended -// to use an in-memory go-datastore as store parameter. -// -// The staging parameter controls if the Raft peer should start in -// staging mode (used when joining a new Raft peerset with other peers). -func NewConsensus(host host.Host, cfg *ClusterRaftConfig, mpool *messagepool.MessagePool, repo repo.LockedRepo, staging bool) (*Consensus, error) { - err := ValidateConfig(cfg) - if err != nil { - return nil, err - } - - ctx, cancel := context.WithCancel(context.Background()) - - logger.Debug("starting Consensus and waiting for a leader...") - state := newRaftState(mpool) - - consensus := libp2praft.NewOpLog(state, &ConsensusOp{}) - - raft, err := newRaftWrapper(host, cfg, consensus.FSM(), repo, staging) - if err != nil { - logger.Error("error creating raft: ", err) - cancel() - return nil, err - } - actor := libp2praft.NewActor(raft.raft) - consensus.SetActor(actor) - - 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) - - // Add peer to address book - host.Peerstore().AddAddrs(addrInfo.ID, addrInfo.Addrs, time.Hour*100) - } - - cc := &Consensus{ - ctx: ctx, - cancel: cancel, - config: cfg, - host: host, - consensus: consensus, - actor: actor, - state: state, - raft: raft, - peerSet: peers, - rpcReady: make(chan struct{}, 1), - readyCh: make(chan struct{}, 1), - repo: repo, - } - - go cc.finishBootstrap() - return cc, nil - -} - -// TODO: Merge with NewConsensus and remove the rpcReady chan -func NewConsensusWithRPCClient(staging bool) func(host host.Host, - cfg *ClusterRaftConfig, - rpcClient *rpc.Client, - mpool *messagepool.MessagePool, - repo repo.LockedRepo, -) (*Consensus, error) { - - return func(host host.Host, cfg *ClusterRaftConfig, rpcClient *rpc.Client, mpool *messagepool.MessagePool, repo repo.LockedRepo) (*Consensus, error) { - cc, err := NewConsensus(host, cfg, mpool, repo, staging) - if err != nil { - return nil, err - } - cc.RpcClient = rpcClient - cc.rpcReady <- struct{}{} - return cc, nil - } -} - -// WaitForSync waits for a leader and for the state to be up to date, then returns. -func (cc *Consensus) WaitForSync(ctx context.Context) error { - - leaderCtx, cancel := context.WithTimeout(ctx, cc.config.WaitForLeaderTimeout) - defer cancel() - - // 1 - wait for leader - // 2 - wait until we are a Voter - // 3 - wait until last index is applied - - // From raft docs: - - // once a staging server receives enough log entries to be sufficiently - // caught up to the leader's log, the leader will invoke a membership - // change to change the Staging server to a Voter - - // Thus, waiting to be a Voter is a guarantee that we have a reasonable - // up to date state. Otherwise, we might return too early (see - // https://github.com/ipfs-cluster/ipfs-cluster/issues/378) - - _, err := cc.raft.WaitForLeader(leaderCtx) - if err != nil { - return errors.New("error waiting for leader: " + err.Error()) - } - - err = cc.raft.WaitForVoter(ctx) - if err != nil { - return errors.New("error waiting to become a Voter: " + err.Error()) - } - - err = cc.raft.WaitForUpdates(ctx) - if err != nil { - return errors.New("error waiting for consensus updates: " + err.Error()) - } - return nil -} - -// waits until there is a consensus leader and syncs the state -// to the tracker. If errors happen, this will return and never -// signal the component as Ready. -func (cc *Consensus) finishBootstrap() { - // wait until we have RPC to perform any actions. - select { - case <-cc.ctx.Done(): - return - case <-cc.rpcReady: - } - - // Sometimes bootstrap is a no-Op. It only applies when - // no state exists and staging=false. - _, err := cc.raft.Bootstrap() - if err != nil { - return - } - - logger.Debugf("Bootstrap finished") - err = cc.WaitForSync(cc.ctx) - if err != nil { - return - } - logger.Debug("Raft state is now up to date") - logger.Debug("consensus ready") - cc.readyCh <- struct{}{} -} - -// Shutdown stops the component so it will not process any -// more updates. The underlying consensus is permanently -// shutdown, along with the libp2p transport. -func (cc *Consensus) Shutdown(ctx context.Context) error { - - logger.Info("stopping Consensus component") - - // Raft Shutdown - err := cc.raft.Shutdown(ctx) - if err != nil { - logger.Error(err) - } - - cc.cancel() - close(cc.rpcReady) - return nil -} - -// Ready returns a channel which is signaled when the Consensus -// algorithm has finished bootstrapping and is ready to use -func (cc *Consensus) Ready(ctx context.Context) <-chan struct{} { - return cc.readyCh -} - -// IsTrustedPeer returns true. In Raft we trust all peers. -func (cc *Consensus) IsTrustedPeer(ctx context.Context, p peer.ID) bool { - return slices.Contains(cc.peerSet, p) -} - -// Trust is a no-Op. -func (cc *Consensus) Trust(ctx context.Context, pid peer.ID) error { return nil } - -// Distrust is a no-Op. -func (cc *Consensus) Distrust(ctx context.Context, pid peer.ID) error { return nil } - -// returns true if the operation was redirected to the leader -// note that if the leader just dissappeared, the rpc call will -// fail because we haven't heard that it's gone. -func (cc *Consensus) RedirectToLeader(method string, arg interface{}, ret interface{}) (bool, error) { - ctx := cc.ctx - - var finalErr error - - // Retry redirects - for i := 0; i <= cc.config.CommitRetries; i++ { - logger.Debugf("redirect try %d", i) - leader, err := cc.Leader(ctx) - - // No leader, wait for one - if err != nil { - logger.Warn("there seems to be no leader. Waiting for one") - rctx, cancel := context.WithTimeout(ctx, cc.config.WaitForLeaderTimeout) - defer cancel() - pidstr, err := cc.raft.WaitForLeader(rctx) - - // means we timed out waiting for a leader - // we don't retry in this case - if err != nil { - return false, fmt.Errorf("timed out waiting for leader: %s", err) - } - leader, err = peer.Decode(pidstr) - if err != nil { - return false, err - } - } - - logger.Infof("leader: %s, curr host: %s, peerSet: %s", leader, cc.host.ID(), cc.peerSet) - - // We are the leader. Do not redirect - if leader == cc.host.ID() { - return false, nil - } - - logger.Debugf("redirecting %s to leader: %s", method, leader) - finalErr = cc.RpcClient.CallContext( - ctx, - leader, - "Consensus", - method, - arg, - ret, - ) - if finalErr != nil { - logger.Errorf("retrying to redirect request to leader: %s", finalErr) - time.Sleep(2 * cc.config.RaftConfig.HeartbeatTimeout) - continue - } - break - } - - // We tried to redirect, but something happened - return true, finalErr -} - -// commit submits a cc.consensus commit. It retries upon failures. -func (cc *Consensus) Commit(ctx context.Context, op *ConsensusOp) error { - - var finalErr error - for i := 0; i <= cc.config.CommitRetries; i++ { - logger.Debugf("attempt #%d: committing %+v", i, op) - - // this means we are retrying - if finalErr != nil { - logger.Errorf("retrying upon failed commit (retry %d): %s ", - i, finalErr) - } - - // Being here means we are the LEADER. We can commit. - // now commit the changes to our state - _, finalErr = cc.consensus.CommitOp(op) - if finalErr != nil { - goto RETRY - } - - RETRY: - time.Sleep(cc.config.CommitRetryDelay) - } - return finalErr -} - -// AddPeer adds a new peer to participate in this consensus. It will -// forward the operation to the leader if this is not it. -func (cc *Consensus) AddPeer(ctx context.Context, pid peer.ID) error { - var finalErr error - for i := 0; i <= cc.config.CommitRetries; i++ { - logger.Debugf("attempt #%d: AddPeer %s", i, pid) - if finalErr != nil { - logger.Errorf("retrying to add peer. Attempt #%d failed: %s", i, finalErr) - } - ok, err := cc.RedirectToLeader("AddPeer", pid, struct{}{}) - if err != nil || ok { - return err - } - // Being here means we are the leader and can commit - finalErr = cc.raft.AddPeer(ctx, pid) - if finalErr != nil { - time.Sleep(cc.config.CommitRetryDelay) - continue - } - logger.Infof("peer added to Raft: %s", pid) - break - } - return finalErr -} - -// RmPeer removes a peer from this consensus. It will -// forward the operation to the leader if this is not it. -func (cc *Consensus) RmPeer(ctx context.Context, pid peer.ID) error { - var finalErr error - for i := 0; i <= cc.config.CommitRetries; i++ { - logger.Debugf("attempt #%d: RmPeer %s", i, pid) - if finalErr != nil { - logger.Errorf("retrying to remove peer. Attempt #%d failed: %s", i, finalErr) - } - ok, err := cc.RedirectToLeader("RmPeer", pid, struct{}{}) - if err != nil || ok { - return err - } - // Being here means we are the leader and can commit - finalErr = cc.raft.RemovePeer(ctx, pid.String()) - if finalErr != nil { - time.Sleep(cc.config.CommitRetryDelay) - continue - } - logger.Infof("peer removed from Raft: %s", pid) - break - } - return finalErr -} - -// RaftState retrieves the current consensus RaftState. It may error if no RaftState has -// been agreed upon or the state is not consistent. The returned RaftState is the -// last agreed-upon RaftState known by this node. No writes are allowed, as all -// writes to the shared state should happen through the Consensus component -// methods. -func (cc *Consensus) State(ctx context.Context) (*RaftState, error) { - st, err := cc.consensus.GetLogHead() - if err == libp2praft.ErrNoState { - return newRaftState(nil), nil - } - - if err != nil { - return nil, err - } - state, ok := st.(*RaftState) - if !ok { - return nil, errors.New("wrong state type") - } - return state, nil -} - -// Leader returns the peerID of the Leader of the -// cluster. It returns an error when there is no leader. -func (cc *Consensus) Leader(ctx context.Context) (peer.ID, error) { - // Note the hard-dependency on raft here... - raftactor := cc.actor.(*libp2praft.Actor) - return raftactor.Leader() -} - -// Clean removes the Raft persisted state. -func (cc *Consensus) Clean(ctx context.Context) error { - //return CleanupRaft(cc.config) - return nil -} - -//Rollback replaces the current agreed-upon -//state with the state provided. Only the consensus leader -//can perform this operation. -//func (cc *Consensus) Rollback(state RaftState) error { -// // This is unused. It *might* be used for upgrades. -// // There is rather untested magic in libp2p-raft's FSM() -// // to make this possible. -// return cc.consensus.Rollback(state) -//} - -// Peers return the current list of peers in the consensus. -// The list will be sorted alphabetically. -func (cc *Consensus) Peers(ctx context.Context) ([]peer.ID, error) { - - peers := []peer.ID{} - raftPeers, err := cc.raft.Peers(ctx) - if err != nil { - return nil, fmt.Errorf("cannot retrieve list of peers: %s", err) - } - - sort.Strings(raftPeers) - - for _, p := range raftPeers { - id, err := peer.Decode(p) - if err != nil { - panic("could not decode peer") - } - peers = append(peers, id) - } - return peers, nil -} - -func (cc *Consensus) IsLeader(ctx context.Context) bool { - leader, _ := cc.Leader(ctx) - return leader == cc.host.ID() -} diff --git a/lib/consensus/raft/interfaces.go b/lib/consensus/raft/interfaces.go deleted file mode 100644 index 2b77d1ebe52..00000000000 --- a/lib/consensus/raft/interfaces.go +++ /dev/null @@ -1,41 +0,0 @@ -package consensus - -import ( - "context" - - consensus "github.com/libp2p/go-libp2p-consensus" - "github.com/libp2p/go-libp2p/core/peer" -) - -type ConsensusAPI interface { - // Returns a channel to signal that the consensus layer is ready - // allowing the main component to wait for it during start. - Ready(context.Context) <-chan struct{} - - AddPeer(context.Context, peer.ID) error - RmPeer(context.Context, peer.ID) error - State(context.Context) (consensus.State, error) - // Provide a node which is responsible to perform - // specific tasks which must only run in 1 cluster peer. - Leader(context.Context) (peer.ID, error) - // Only returns when the consensus state has all log - // updates applied to it. - WaitForSync(context.Context) error - // Clean removes all consensus data. - Clean(context.Context) error - // Peers returns the peerset participating in the Consensus. - Peers(context.Context) ([]peer.ID, error) - // IsTrustedPeer returns true if the given peer is "trusted". - // This will grant access to more rpc endpoints and a - // non-trusted one. This should be fast as it will be - // called repeatedly for every remote RPC request. - IsTrustedPeer(context.Context, peer.ID) bool - // Trust marks a peer as "trusted". - Trust(context.Context, peer.ID) error - // Distrust removes a peer from the "trusted" set. - Distrust(context.Context, peer.ID) error - // Returns true if current node is the cluster leader - IsLeader(ctx context.Context) bool - - Shutdown(context.Context) error -} diff --git a/lib/consensus/raft/raft.go b/lib/consensus/raft/raft.go deleted file mode 100644 index 8541e6f87a4..00000000000 --- a/lib/consensus/raft/raft.go +++ /dev/null @@ -1,563 +0,0 @@ -package consensus - -import ( - "context" - "errors" - "fmt" - "os" - "path/filepath" - "time" - - "github.com/hashicorp/go-hclog" - hraft "github.com/hashicorp/raft" - raftboltdb "github.com/hashicorp/raft-boltdb" - "github.com/ipfs/go-log/v2" - p2praft "github.com/libp2p/go-libp2p-raft" - host "github.com/libp2p/go-libp2p/core/host" - peer "github.com/libp2p/go-libp2p/core/peer" - "go.uber.org/multierr" - "go.uber.org/zap" - - "github.com/filecoin-project/lotus/lib/addrutil" - "github.com/filecoin-project/lotus/node/repo" -) - -var raftLogger = log.Logger("raft-cluster") - -// ErrWaitingForSelf is returned when we are waiting for ourselves to depart -// the peer set, which won't happen -var errWaitingForSelf = errors.New("waiting for ourselves to depart") - -// RaftMaxSnapshots indicates how many snapshots to keep in the consensus data -// folder. -// TODO: Maybe include this in Config. Not sure how useful it is to touch -// this anyways. -var RaftMaxSnapshots = 5 - -// RaftLogCacheSize is the maximum number of logs to cache in-memory. -// This is used to reduce disk I/O for the recently committed entries. -var RaftLogCacheSize = 512 - -// How long we wait for updates during shutdown before snapshotting -var waitForUpdatesShutdownTimeout = 5 * time.Second -var waitForUpdatesInterval = 400 * time.Millisecond - -// How many times to retry snapshotting when shutting down -var maxShutdownSnapshotRetries = 5 - -// raftWrapper wraps the hraft.Raft object and related things like the -// different stores used or the hraft.Configuration. -// Its methods provide functionality for working with Raft. -type raftWrapper struct { - ctx context.Context - cancel context.CancelFunc - raft *hraft.Raft - config *ClusterRaftConfig - host host.Host - serverConfig hraft.Configuration - transport *hraft.NetworkTransport - snapshotStore hraft.SnapshotStore - logStore hraft.LogStore - stableStore hraft.StableStore - boltdb *raftboltdb.BoltStore - repo repo.LockedRepo - staging bool -} - -// newRaftWrapper creates a Raft instance and initializes -// everything leaving it ready to use. Note, that Bootstrap() should be called -// to make sure the raft instance is usable. -func newRaftWrapper( - host host.Host, - cfg *ClusterRaftConfig, - fsm hraft.FSM, - repo repo.LockedRepo, - staging bool, -) (*raftWrapper, error) { - - raftW := &raftWrapper{} - raftW.config = cfg - raftW.host = host - raftW.staging = staging - raftW.repo = repo - // Set correct LocalID - cfg.RaftConfig.LocalID = hraft.ServerID(host.ID().String()) - - df := cfg.GetDataFolder(repo) - err := makeDataFolder(df) - if err != nil { - return nil, err - } - - err = raftW.makeServerConfig() - if err != nil { - return nil, err - } - - err = raftW.makeTransport() - if err != nil { - return nil, err - } - - err = raftW.makeStores() - if err != nil { - return nil, err - } - - raftLogger.Debug("creating Raft") - raftW.raft, err = hraft.NewRaft( - cfg.RaftConfig, - fsm, - raftW.logStore, - raftW.stableStore, - raftW.snapshotStore, - raftW.transport, - ) - if err != nil { - raftLogger.Error("initializing raft: ", err) - return nil, err - } - - raftW.ctx, raftW.cancel = context.WithCancel(context.Background()) - - return raftW, nil -} - -// makeDataFolder creates the folder that is meant to store Raft data. Ensures -// we always set 0700 mode. -func makeDataFolder(folder string) error { - return os.MkdirAll(folder, 0700) -} - -func (rw *raftWrapper) makeTransport() (err error) { - raftLogger.Debug("creating libp2p Raft transport") - rw.transport, err = p2praft.NewLibp2pTransport( - rw.host, - rw.config.NetworkTimeout, - ) - return err -} - -func (rw *raftWrapper) makeStores() error { - raftLogger.Debug("creating BoltDB store") - df := rw.config.GetDataFolder(rw.repo) - store, err := raftboltdb.NewBoltStore(filepath.Join(df, "raft.db")) - if err != nil { - return err - } - - // wraps the store in a LogCache to improve performance. - // See consul/agent/consul/server.go - cacheStore, err := hraft.NewLogCache(RaftLogCacheSize, store) - if err != nil { - return err - } - - raftLogger.Debug("creating raft snapshot store") - snapstore, err := hraft.NewFileSnapshotStoreWithLogger( - df, - RaftMaxSnapshots, - hclog.FromStandardLogger(zap.NewStdLog(log.Logger("raft-snapshot").SugaredLogger.Desugar()), hclog.DefaultOptions), - ) - if err != nil { - return err - } - - rw.logStore = cacheStore - rw.stableStore = store - rw.snapshotStore = snapstore - rw.boltdb = store - return nil -} - -// Bootstrap calls BootstrapCluster on the Raft instance with a valid -// Configuration (generated from InitPeerset) when Raft has no state -// and we are not setting up a staging peer. It returns if Raft -// was boostrapped (true) and an error. -func (rw *raftWrapper) Bootstrap() (bool, error) { - logger.Debug("checking for existing raft states") - hasState, err := hraft.HasExistingState( - rw.logStore, - rw.stableStore, - rw.snapshotStore, - ) - if err != nil { - return false, err - } - - if hasState { - logger.Debug("raft cluster is already initialized") - - // Inform the user that we are working with a pre-existing peerset - logger.Info("existing Raft state found! raft.InitPeerset will be ignored") - cf := rw.raft.GetConfiguration() - if err := cf.Error(); err != nil { - logger.Debug(err) - return false, err - } - currentCfg := cf.Configuration() - srvs := "" - for _, s := range currentCfg.Servers { - srvs += fmt.Sprintf(" %s\n", s.ID) - } - - logger.Debugf("Current Raft Peerset:\n%s\n", srvs) - return false, nil - } - - if rw.staging { - logger.Debug("staging servers do not need initialization") - logger.Info("peer is ready to join a cluster") - return false, nil - } - - voters := "" - for _, s := range rw.serverConfig.Servers { - voters += fmt.Sprintf(" %s\n", s.ID) - } - - logger.Infof("initializing raft cluster with the following voters:\n%s\n", voters) - - future := rw.raft.BootstrapCluster(rw.serverConfig) - if err := future.Error(); err != nil { - logger.Error("bootstrapping cluster: ", err) - return true, err - } - return true, nil -} - -// create Raft servers configuration. The result is used -// by Bootstrap() when it proceeds to Bootstrap. -func (rw *raftWrapper) makeServerConfig() error { - peers := []peer.ID{} - addrInfos, err := addrutil.ParseAddresses(context.Background(), rw.config.InitPeerset) - if err != nil { - return err - } - for _, addrInfo := range addrInfos { - peers = append(peers, addrInfo.ID) - } - rw.serverConfig = makeServerConf(append(peers, rw.host.ID())) - return nil -} - -// creates a server configuration with all peers as Voters. -func makeServerConf(peers []peer.ID) hraft.Configuration { - sm := make(map[string]struct{}) - - servers := make([]hraft.Server, 0) - - // Servers are peers + self. We avoid duplicate entries below - for _, pid := range peers { - p := pid.String() - _, ok := sm[p] - if !ok { // avoid dups - sm[p] = struct{}{} - servers = append(servers, hraft.Server{ - Suffrage: hraft.Voter, - ID: hraft.ServerID(p), - Address: hraft.ServerAddress(p), - }) - } - } - return hraft.Configuration{Servers: servers} -} - -// WaitForLeader holds until Raft says we have a leader. -// Returns if ctx is canceled. -func (rw *raftWrapper) WaitForLeader(ctx context.Context) (string, error) { - ticker := time.NewTicker(time.Second / 2) - for { - select { - case <-ticker.C: - if l := rw.raft.Leader(); l != "" { - logger.Debug("waitForleaderTimer") - logger.Infof("Current Raft Leader: %s", l) - ticker.Stop() - return string(l), nil - } - case <-ctx.Done(): - return "", ctx.Err() - } - } -} - -func (rw *raftWrapper) WaitForVoter(ctx context.Context) error { - logger.Debug("waiting until we are promoted to a voter") - - pid := hraft.ServerID(rw.host.ID().String()) - for { - select { - case <-ctx.Done(): - return ctx.Err() - default: - logger.Debugf("%s: get configuration", pid) - configFuture := rw.raft.GetConfiguration() - if err := configFuture.Error(); err != nil { - return err - } - - if isVoter(pid, configFuture.Configuration()) { - return nil - } - logger.Debugf("%s: not voter yet", pid) - - time.Sleep(waitForUpdatesInterval) - } - } -} - -func isVoter(srvID hraft.ServerID, cfg hraft.Configuration) bool { - for _, server := range cfg.Servers { - if server.ID == srvID && server.Suffrage == hraft.Voter { - return true - } - } - return false -} - -// WaitForUpdates holds until Raft has synced to the last index in the log -func (rw *raftWrapper) WaitForUpdates(ctx context.Context) error { - - logger.Debug("Raft state is catching up to the latest known version. Please wait...") - for { - select { - case <-ctx.Done(): - return ctx.Err() - default: - lai := rw.raft.AppliedIndex() - li := rw.raft.LastIndex() - logger.Debugf("current Raft index: %d/%d", - lai, li) - if lai == li { - return nil - } - time.Sleep(waitForUpdatesInterval) - } - } -} - -func (rw *raftWrapper) WaitForPeer(ctx context.Context, pid string, depart bool) error { - - for { - select { - case <-ctx.Done(): - return ctx.Err() - default: - peers, err := rw.Peers(ctx) - if err != nil { - return err - } - - if len(peers) == 1 && pid == peers[0] && depart { - return errWaitingForSelf - } - - found := find(peers, pid) - - // departing - if depart && !found { - return nil - } - - // joining - if !depart && found { - return nil - } - - time.Sleep(50 * time.Millisecond) - } - } -} - -// Snapshot tells Raft to take a snapshot. -func (rw *raftWrapper) Snapshot() error { - future := rw.raft.Snapshot() - err := future.Error() - if err != nil && err.Error() != hraft.ErrNothingNewToSnapshot.Error() { - return err - } - return nil -} - -// snapshotOnShutdown attempts to take a snapshot before a shutdown. -// Snapshotting might fail if the raft applied index is not the last index. -// This waits for the updates and tries to take a snapshot when the -// applied index is up to date. -// It will retry if the snapshot still fails, in case more updates have arrived. -// If waiting for updates times-out, it will not try anymore, since something -// is wrong. This is a best-effort solution as there is no way to tell Raft -// to stop processing entries because we want to take a snapshot before -// shutting down. -func (rw *raftWrapper) snapshotOnShutdown() error { - var err error - for i := 0; i < maxShutdownSnapshotRetries; i++ { - ctx, cancel := context.WithTimeout(context.Background(), waitForUpdatesShutdownTimeout) - err = rw.WaitForUpdates(ctx) - cancel() - if err != nil { - logger.Warn("timed out waiting for state updates before shutdown. Snapshotting may fail") - return rw.Snapshot() - } - - err = rw.Snapshot() - if err == nil { - return nil // things worked - } - - // There was an error - err = errors.New("could not snapshot raft: " + err.Error()) - logger.Warnf("retrying to snapshot (%d/%d)...", i+1, maxShutdownSnapshotRetries) - } - return err -} - -// Shutdown shutdown Raft and closes the BoltDB. -func (rw *raftWrapper) Shutdown(ctx context.Context) error { - - rw.cancel() - - var finalErr error - - err := rw.snapshotOnShutdown() - if err != nil { - finalErr = multierr.Append(finalErr, err) - } - - future := rw.raft.Shutdown() - err = future.Error() - if err != nil { - finalErr = multierr.Append(finalErr, err) - } - - err = rw.boltdb.Close() // important! - if err != nil { - finalErr = multierr.Append(finalErr, err) - } - - return finalErr -} - -// AddPeer adds a peer to Raft -func (rw *raftWrapper) AddPeer(ctx context.Context, peerId peer.ID) error { - - // Check that we don't have it to not waste - // log entries if so. - peers, err := rw.Peers(ctx) - if err != nil { - return err - } - if find(peers, peerId.String()) { - logger.Infof("%s is already a raft peerStr", peerId.String()) - return nil - } - - err = rw.host.Connect(ctx, peer.AddrInfo{ID: peerId}) - if err != nil { - return err - } - - future := rw.raft.AddVoter( - hraft.ServerID(peerId.String()), - hraft.ServerAddress(peerId.String()), - 0, - 0, - ) // TODO: Extra cfg value? - err = future.Error() - if err != nil { - logger.Error("raft cannot add peer: ", err) - } - return err -} - -// RemovePeer removes a peer from Raft -func (rw *raftWrapper) RemovePeer(ctx context.Context, peer string) error { - // Check that we have it to not waste - // log entries if we don't. - peers, err := rw.Peers(ctx) - if err != nil { - return err - } - if !find(peers, peer) { - logger.Infof("%s is not among raft peers", peer) - return nil - } - - if len(peers) == 1 && peers[0] == peer { - return errors.New("cannot remove ourselves from a 1-peer cluster") - } - - rmFuture := rw.raft.RemoveServer( - hraft.ServerID(peer), - 0, - 0, - ) - err = rmFuture.Error() - if err != nil { - logger.Error("raft cannot remove peer: ", err) - return err - } - - return nil -} - -// Leader returns Raft's leader. It may be an empty string if -// there is no leader or it is unknown. -func (rw *raftWrapper) Leader(ctx context.Context) string { - return string(rw.raft.Leader()) -} - -func (rw *raftWrapper) Peers(ctx context.Context) ([]string, error) { - ids := make([]string, 0) - - configFuture := rw.raft.GetConfiguration() - if err := configFuture.Error(); err != nil { - return nil, err - } - - for _, server := range configFuture.Configuration().Servers { - ids = append(ids, string(server.ID)) - } - - return ids, nil -} - -// CleanupRaft moves the current data folder to a backup location -//func CleanupRaft(cfg *Config) error { -// dataFolder := cfg.GetDataFolder() -// keep := cfg.BackupsRotate -// -// meta, _, err := latestSnapshot(dataFolder) -// if meta == nil && err == nil { -// // no snapshots at all. Avoid creating backups -// // from empty state folders. -// logger.Infof("cleaning empty Raft data folder (%s)", dataFolder) -// os.RemoveAll(dataFolder) -// return nil -// } -// -// logger.Infof("cleaning and backing up Raft data folder (%s)", dataFolder) -// dbh := newDataBackupHelper(dataFolder, keep) -// err = dbh.makeBackup() -// if err != nil { -// logger.Warn(err) -// logger.Warn("the state could not be cleaned properly") -// logger.Warn("manual intervention may be needed before starting cluster again") -// } -// return nil -//} - -// only call when Raft is shutdown -func (rw *raftWrapper) Clean() error { - //return CleanupRaft(rw.config) - return nil -} - -func find(s []string, elem string) bool { - for _, selem := range s { - if selem == elem { - return true - } - } - return false -} diff --git a/lib/harmony/harmonydb/harmonydb.go b/lib/harmony/harmonydb/harmonydb.go index 0fed176d232..56b5acdfee2 100644 --- a/lib/harmony/harmonydb/harmonydb.go +++ b/lib/harmony/harmonydb/harmonydb.go @@ -10,12 +10,14 @@ import ( "sort" "strconv" "strings" + "sync" + "sync/atomic" "time" logging "github.com/ipfs/go-log/v2" - "github.com/jackc/pgx/v5" - "github.com/jackc/pgx/v5/pgconn" - "github.com/jackc/pgx/v5/pgxpool" + "github.com/yugabyte/pgx/v5" + "github.com/yugabyte/pgx/v5/pgconn" + "github.com/yugabyte/pgx/v5/pgxpool" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/node/config" @@ -33,6 +35,8 @@ type DB struct { cfg *pgxpool.Config schema string hostnames []string + BTFPOnce sync.Once + BTFP atomic.Uintptr // BeginTransactionFramePointer } var logger = logging.Logger("harmonydb") @@ -80,7 +84,7 @@ func New(hosts []string, username, password, database, port string, itestID ITes } } - schema := "lotus" + schema := "curio" if itest != "" { schema = "itest_" + itest } diff --git a/lib/harmony/harmonydb/sql/20230706.sql b/lib/harmony/harmonydb/sql/20230706-itest_scratch.sql similarity index 100% rename from lib/harmony/harmonydb/sql/20230706.sql rename to lib/harmony/harmonydb/sql/20230706-itest_scratch.sql diff --git a/lib/harmony/harmonydb/sql/20230712.sql b/lib/harmony/harmonydb/sql/20230712-sector_index.sql similarity index 100% rename from lib/harmony/harmonydb/sql/20230712.sql rename to lib/harmony/harmonydb/sql/20230712-sector_index.sql diff --git a/lib/harmony/harmonydb/sql/20230719.sql b/lib/harmony/harmonydb/sql/20230719-harmony.sql similarity index 100% rename from lib/harmony/harmonydb/sql/20230719.sql rename to lib/harmony/harmonydb/sql/20230719-harmony.sql diff --git a/lib/harmony/harmonydb/sql/20230823.sql b/lib/harmony/harmonydb/sql/20230823-wdpost.sql similarity index 100% rename from lib/harmony/harmonydb/sql/20230823.sql rename to lib/harmony/harmonydb/sql/20230823-wdpost.sql diff --git a/lib/harmony/harmonydb/sql/20230919.sql b/lib/harmony/harmonydb/sql/20230919-config.sql similarity index 100% rename from lib/harmony/harmonydb/sql/20230919.sql rename to lib/harmony/harmonydb/sql/20230919-config.sql diff --git a/lib/harmony/harmonydb/sql/20231103.sql b/lib/harmony/harmonydb/sql/20231103-chain_sends.sql similarity index 100% rename from lib/harmony/harmonydb/sql/20231103.sql rename to lib/harmony/harmonydb/sql/20231103-chain_sends.sql diff --git a/lib/harmony/harmonydb/sql/20231110.sql b/lib/harmony/harmonydb/sql/20231110-mining_tasks.sql similarity index 100% rename from lib/harmony/harmonydb/sql/20231110.sql rename to lib/harmony/harmonydb/sql/20231110-mining_tasks.sql diff --git a/lib/harmony/harmonydb/sql/20231113.sql b/lib/harmony/harmonydb/sql/20231113-harmony_taskhistory_oops.sql similarity index 100% rename from lib/harmony/harmonydb/sql/20231113.sql rename to lib/harmony/harmonydb/sql/20231113-harmony_taskhistory_oops.sql diff --git a/lib/harmony/harmonydb/sql/20231217-sdr-pipeline.sql b/lib/harmony/harmonydb/sql/20231217-sdr-pipeline.sql new file mode 100644 index 00000000000..31f10313968 --- /dev/null +++ b/lib/harmony/harmonydb/sql/20231217-sdr-pipeline.sql @@ -0,0 +1,135 @@ +-- NOTE: task_ids can be the same between different task types and between different sectors +-- e.g. SN-supraseal doing 128 sdr/TreeC/TreeR with the same task_id + +create table sectors_sdr_pipeline ( + sp_id bigint not null, + sector_number bigint not null, + + -- at request time + create_time timestamp not null default current_timestamp, + reg_seal_proof int not null, + + -- sdr + ticket_epoch bigint, + ticket_value bytea, + + task_id_sdr bigint, + after_sdr bool not null default false, + + -- tree D + tree_d_cid text, -- commd from treeD compute, should match comm_d_cid + + task_id_tree_d bigint, + after_tree_d bool not null default false, + + -- tree C + task_id_tree_c bigint, + after_tree_c bool not null default false, + + -- tree R + tree_r_cid text, -- commr from treeR compute + + task_id_tree_r bigint, + after_tree_r bool not null default false, + + -- precommit message sending + precommit_msg_cid text, + + task_id_precommit_msg bigint, + after_precommit_msg bool not null default false, + + -- precommit message wait + seed_epoch bigint, + precommit_msg_tsk bytea, + after_precommit_msg_success bool not null default false, + + -- seed + seed_value bytea, + + -- Commit (PoRep snark) + task_id_porep bigint, + porep_proof bytea, + after_porep bool not null default false, + + -- Finalize (trim cache) + task_id_finalize bigint, + after_finalize bool not null default false, + + -- MoveStorage (move data to storage) + task_id_move_storage bigint, + after_move_storage bool not null default false, + + -- Commit message sending + commit_msg_cid text, + + task_id_commit_msg bigint, + after_commit_msg bool not null default false, + + -- Commit message wait + commit_msg_tsk bytea, + after_commit_msg_success bool not null default false, + + -- Failure handling + failed bool not null default false, + failed_at timestamp, + failed_reason varchar(20) not null default '', + failed_reason_msg text not null default '', + + -- foreign key + -- note: those foreign keys are a part of the retry mechanism. If a task + -- fails due to retry limit, it will drop the assigned task_id, and the + -- poller will reassign the task to a new node if it deems the task is + -- still valid to be retried. + foreign key (task_id_sdr) references harmony_task (id) on delete set null, + foreign key (task_id_tree_d) references harmony_task (id) on delete set null, + foreign key (task_id_tree_c) references harmony_task (id) on delete set null, + foreign key (task_id_tree_r) references harmony_task (id) on delete set null, + foreign key (task_id_precommit_msg) references harmony_task (id) on delete set null, + foreign key (task_id_porep) references harmony_task (id) on delete set null, + foreign key (task_id_finalize) references harmony_task (id) on delete set null, + foreign key (task_id_move_storage) references harmony_task (id) on delete set null, + foreign key (task_id_commit_msg) references harmony_task (id) on delete set null, + + -- constraints + primary key (sp_id, sector_number) +); + +create table sectors_sdr_initial_pieces ( + sp_id bigint not null, + sector_number bigint not null, + + piece_index bigint not null, + piece_cid text not null, + piece_size bigint not null, -- padded size + + -- data source + data_url text not null, + data_headers jsonb not null default '{}', + data_raw_size bigint not null, + data_delete_on_finalize bool not null, + + -- deal info + f05_publish_cid text, + f05_deal_id bigint, + f05_deal_proposal jsonb, + f05_deal_start_epoch bigint, + f05_deal_end_epoch bigint, + + -- ddo deal info + -- added in 20240402-sdr-pipeline-ddo-deal-info.sql + -- direct_start_epoch bigint, + -- direct_end_epoch bigint, + -- direct_piece_activation_manifest jsonb, + + -- foreign key + foreign key (sp_id, sector_number) references sectors_sdr_pipeline (sp_id, sector_number) on delete cascade, + + primary key (sp_id, sector_number, piece_index) +); + +comment on column sectors_sdr_initial_pieces.piece_size is 'padded size of the piece'; + +create table sectors_allocated_numbers ( + sp_id bigint not null primary key, + allocated jsonb not null +); diff --git a/lib/harmony/harmonydb/sql/20231225-message-waits.sql b/lib/harmony/harmonydb/sql/20231225-message-waits.sql new file mode 100644 index 00000000000..4143f3a56e9 --- /dev/null +++ b/lib/harmony/harmonydb/sql/20231225-message-waits.sql @@ -0,0 +1,13 @@ +create table message_waits ( + signed_message_cid text primary key, + waiter_machine_id int references harmony_machines (id) on delete set null, + + executed_tsk_cid text, + executed_tsk_epoch bigint, + executed_msg_cid text, + executed_msg_data jsonb, + + executed_rcpt_exitcode bigint, + executed_rcpt_return bytea, + executed_rcpt_gas_used bigint +) diff --git a/lib/harmony/harmonydb/sql/20240212-common-layers.sql b/lib/harmony/harmonydb/sql/20240212-common-layers.sql new file mode 100644 index 00000000000..cf72e175023 --- /dev/null +++ b/lib/harmony/harmonydb/sql/20240212-common-layers.sql @@ -0,0 +1,42 @@ +INSERT INTO harmony_config (title, config) VALUES + ('post', ' + [Subsystems] + EnableWindowPost = true + EnableWinningPost = true + '), + + ('gui', ' + [Subsystems] + EnableWebGui = true + '), + + ('seal', ' + [Subsystems] + EnableSealSDR = true + EnableSealSDRTrees = true + EnableSendPrecommitMsg = true + EnablePoRepProof = true + EnableSendCommitMsg = true + EnableMoveStorage = true + '), + + ('seal-gpu', ' + [Subsystems] + EnableSealSDRTrees = true + EnableSendPrecommitMsg = true + '), + ('seal-snark', ' + [Subsystems] + EnablePoRepProof = true + EnableSendCommitMsg = true + '), + ('sdr', ' + [Subsystems] + EnableSealSDR = true + '), + + ('storage', ' + [Subsystems] + EnableMoveStorage = true + ') + ON CONFLICT (title) DO NOTHING; -- SPs may have these names defined already. \ No newline at end of file diff --git a/lib/harmony/harmonydb/sql/20240228-piece-park.sql b/lib/harmony/harmonydb/sql/20240228-piece-park.sql new file mode 100644 index 00000000000..9ee6b447f39 --- /dev/null +++ b/lib/harmony/harmonydb/sql/20240228-piece-park.sql @@ -0,0 +1,35 @@ +create table parked_pieces ( + id bigserial primary key, + created_at timestamp default current_timestamp, + + piece_cid text not null, + piece_padded_size bigint not null, + piece_raw_size bigint not null, + + complete boolean not null default false, + task_id bigint default null, + + cleanup_task_id bigint default null, + + foreign key (task_id) references harmony_task (id) on delete set null, + foreign key (cleanup_task_id) references harmony_task (id) on delete set null, + unique (piece_cid) +); + +/* + * This table is used to keep track of the references to the parked pieces + * so that we can delete them when they are no longer needed. + * + * All references into the parked_pieces table should be done through this table. + * + * data_url is optional for refs which also act as data sources. + */ +create table parked_piece_refs ( + ref_id bigserial primary key, + piece_id bigint not null, + + data_url text, + data_headers jsonb not null default '{}', + + foreign key (piece_id) references parked_pieces(id) on delete cascade +); diff --git a/lib/harmony/harmonydb/sql/20240317-web-summary-index.sql b/lib/harmony/harmonydb/sql/20240317-web-summary-index.sql new file mode 100644 index 00000000000..28902448d05 --- /dev/null +++ b/lib/harmony/harmonydb/sql/20240317-web-summary-index.sql @@ -0,0 +1,7 @@ +/* Used for webui clusterMachineSummary */ +CREATE INDEX harmony_task_history_work_index + ON harmony_task_history (completed_by_host_and_port ASC, name ASC, result ASC, work_end DESC); + +/* Used for webui actorSummary sp wins */ +CREATE INDEX mining_tasks_won_sp_id_base_compute_time_index + ON mining_tasks (won ASC, sp_id ASC, base_compute_time DESC); diff --git a/lib/harmony/harmonydb/sql/20240401-storage-miner-filter.sql b/lib/harmony/harmonydb/sql/20240401-storage-miner-filter.sql new file mode 100644 index 00000000000..27cecafe68d --- /dev/null +++ b/lib/harmony/harmonydb/sql/20240401-storage-miner-filter.sql @@ -0,0 +1,2 @@ +ALTER TABLE storage_path ADD COLUMN IF NOT EXISTS allow_miners varchar DEFAULT ''; +ALTER TABLE storage_path ADD COLUMN IF NOT EXISTS deny_miners varchar DEFAULT ''; -- comma separated list of miner addresses \ No newline at end of file diff --git a/lib/harmony/harmonydb/sql/20240402-sdr-pipeline-ddo-deal-info.sql b/lib/harmony/harmonydb/sql/20240402-sdr-pipeline-ddo-deal-info.sql new file mode 100644 index 00000000000..2230ef57492 --- /dev/null +++ b/lib/harmony/harmonydb/sql/20240402-sdr-pipeline-ddo-deal-info.sql @@ -0,0 +1,8 @@ +ALTER TABLE sectors_sdr_initial_pieces + ADD COLUMN direct_start_epoch BIGINT; + +ALTER TABLE sectors_sdr_initial_pieces + ADD COLUMN direct_end_epoch BIGINT; + +ALTER TABLE sectors_sdr_initial_pieces + ADD COLUMN direct_piece_activation_manifest JSONB; diff --git a/lib/harmony/harmonydb/sql/20240404-machine_detail.sql b/lib/harmony/harmonydb/sql/20240404-machine_detail.sql new file mode 100644 index 00000000000..ae6de095124 --- /dev/null +++ b/lib/harmony/harmonydb/sql/20240404-machine_detail.sql @@ -0,0 +1,12 @@ +CREATE TABLE harmony_machine_details ( + id SERIAL PRIMARY KEY, + tasks TEXT, + layers TEXT, + startup_time TIMESTAMP, + miners TEXT, + machine_id INTEGER, + FOREIGN KEY (machine_id) REFERENCES harmony_machines(id) ON DELETE CASCADE +); + +CREATE UNIQUE INDEX machine_details_machine_id ON harmony_machine_details(machine_id); + diff --git a/lib/harmony/harmonydb/sql/20240416-harmony_singleton_task.sql b/lib/harmony/harmonydb/sql/20240416-harmony_singleton_task.sql new file mode 100644 index 00000000000..d565cfa4702 --- /dev/null +++ b/lib/harmony/harmonydb/sql/20240416-harmony_singleton_task.sql @@ -0,0 +1,8 @@ +create table harmony_task_singletons ( + task_name varchar(255) not null, + task_id bigint, + last_run_time timestamp, + + primary key (task_name), + foreign key (task_id) references harmony_task (id) on delete set null +); diff --git a/lib/harmony/harmonydb/sql/20240417-sector_index_gc.sql b/lib/harmony/harmonydb/sql/20240417-sector_index_gc.sql new file mode 100644 index 00000000000..e9771d9f31c --- /dev/null +++ b/lib/harmony/harmonydb/sql/20240417-sector_index_gc.sql @@ -0,0 +1,13 @@ +create table sector_path_url_liveness ( + storage_id text, + url text, + + last_checked timestamp not null, + last_live timestamp, + last_dead timestamp, + last_dead_reason text, + + primary key (storage_id, url), + + foreign key (storage_id) references storage_path (storage_id) on delete cascade +) diff --git a/lib/harmony/harmonydb/userfuncs.go b/lib/harmony/harmonydb/userfuncs.go index 788ca4a34e5..1f39504b81e 100644 --- a/lib/harmony/harmonydb/userfuncs.go +++ b/lib/harmony/harmonydb/userfuncs.go @@ -3,13 +3,19 @@ package harmonydb import ( "context" "errors" + "fmt" + "runtime" + "time" - "github.com/georgysavva/scany/v2/pgxscan" + "github.com/georgysavva/scany/v2/dbscan" "github.com/jackc/pgerrcode" - "github.com/jackc/pgx/v5" - "github.com/jackc/pgx/v5/pgconn" + "github.com/samber/lo" + "github.com/yugabyte/pgx/v5" + "github.com/yugabyte/pgx/v5/pgconn" ) +var errTx = errors.New("cannot use a non-transaction func in a transaction") + // rawStringOnly is _intentionally_private_ to force only basic strings in SQL queries. // In any package, raw strings will satisfy compilation. Ex: // @@ -22,6 +28,9 @@ type rawStringOnly string // Note, for CREATE & DROP please keep these permanent and express // them in the ./sql/ files (next number). func (db *DB) Exec(ctx context.Context, sql rawStringOnly, arguments ...any) (count int, err error) { + if db.usedInTransaction() { + return 0, errTx + } res, err := db.pgx.Exec(ctx, string(sql), arguments...) return int(res.RowsAffected()), err } @@ -34,7 +43,7 @@ type Qry interface { Values() ([]any, error) } -// Query offers Next/Err/Close/Scan/Values/StructScan +// Query offers Next/Err/Close/Scan/Values type Query struct { Qry } @@ -55,17 +64,28 @@ type Query struct { // fmt.Println(id, name) // } func (db *DB) Query(ctx context.Context, sql rawStringOnly, arguments ...any) (*Query, error) { + if db.usedInTransaction() { + return &Query{}, errTx + } q, err := db.pgx.Query(ctx, string(sql), arguments...) return &Query{q}, err } + +// StructScan allows scanning a single row into a struct. +// This improves efficiency of processing large result sets +// by avoiding the need to allocate a slice of structs. func (q *Query) StructScan(s any) error { - return pgxscan.ScanRow(s, q.Qry.(pgx.Rows)) + return dbscan.ScanRow(s, dbscanRows{q.Qry.(pgx.Rows)}) } type Row interface { Scan(...any) error } +type rowErr struct{} + +func (rowErr) Scan(_ ...any) error { return errTx } + // QueryRow gets 1 row using column order matching. // This is a timesaver for the special case of wanting the first row returned only. // EX: @@ -74,9 +94,26 @@ type Row interface { // var ID = 123 // err := db.QueryRow(ctx, "SELECT name, pet FROM users WHERE ID=?", ID).Scan(&name, &pet) func (db *DB) QueryRow(ctx context.Context, sql rawStringOnly, arguments ...any) Row { + if db.usedInTransaction() { + return rowErr{} + } return db.pgx.QueryRow(ctx, string(sql), arguments...) } +type dbscanRows struct { + pgx.Rows +} + +func (d dbscanRows) Close() error { + d.Rows.Close() + return nil +} +func (d dbscanRows) Columns() ([]string, error) { + return lo.Map(d.Rows.FieldDescriptions(), func(fd pgconn.FieldDescription, _ int) string { + return fd.Name + }), nil +} + /* Select multiple rows into a slice using name matching Ex: @@ -92,7 +129,15 @@ Ex: err := db.Select(ctx, &users, "SELECT name, id, tel_no FROM customers WHERE pet=?", pet) */ func (db *DB) Select(ctx context.Context, sliceOfStructPtr any, sql rawStringOnly, arguments ...any) error { - return pgxscan.Select(ctx, db.pgx, sliceOfStructPtr, string(sql), arguments...) + if db.usedInTransaction() { + return errTx + } + rows, err := db.pgx.Query(ctx, string(sql), arguments...) + if err != nil { + return err + } + defer rows.Close() + return dbscan.ScanAll(sliceOfStructPtr, dbscanRows{rows}) } type Tx struct { @@ -100,10 +145,73 @@ type Tx struct { ctx context.Context } +// usedInTransaction is a helper to prevent nesting transactions +// & non-transaction calls in transactions. It only checks 20 frames. +// Fast: This memory should all be in CPU Caches. +func (db *DB) usedInTransaction() bool { + var framePtrs = (&[20]uintptr{})[:] // 20 can be stack-local (no alloc) + framePtrs = framePtrs[:runtime.Callers(3, framePtrs)] // skip past our caller. + return lo.Contains(framePtrs, db.BTFP.Load()) // Unsafe read @ beginTx overlap, but 'return false' is correct there. +} + +type TransactionOptions struct { + RetrySerializationError bool + InitialSerializationErrorRetryWait time.Duration +} + +type TransactionOption func(*TransactionOptions) + +func OptionRetry() TransactionOption { + return func(o *TransactionOptions) { + o.RetrySerializationError = true + } +} + +func OptionSerialRetryTime(d time.Duration) TransactionOption { + return func(o *TransactionOptions) { + o.InitialSerializationErrorRetryWait = d + } +} + // BeginTransaction is how you can access transactions using this library. // The entire transaction happens in the function passed in. // The return must be true or a rollback will occur. -func (db *DB) BeginTransaction(ctx context.Context, f func(*Tx) (commit bool, err error)) (didCommit bool, retErr error) { +// Be sure to test the error for IsErrSerialization() if you want to retry +// +// when there is a DB serialization error. +// +//go:noinline +func (db *DB) BeginTransaction(ctx context.Context, f func(*Tx) (commit bool, err error), opt ...TransactionOption) (didCommit bool, retErr error) { + db.BTFPOnce.Do(func() { + fp := make([]uintptr, 20) + runtime.Callers(1, fp) + db.BTFP.Store(fp[0]) + }) + if db.usedInTransaction() { + return false, errTx + } + + opts := TransactionOptions{ + RetrySerializationError: false, + InitialSerializationErrorRetryWait: 10 * time.Millisecond, + } + + for _, o := range opt { + o(&opts) + } + +retry: + comm, err := db.transactionInner(ctx, f) + if err != nil && opts.RetrySerializationError && IsErrSerialization(err) { + time.Sleep(opts.InitialSerializationErrorRetryWait) + opts.InitialSerializationErrorRetryWait *= 2 + goto retry + } + + return comm, err +} + +func (db *DB) transactionInner(ctx context.Context, f func(*Tx) (commit bool, err error)) (didCommit bool, retErr error) { tx, err := db.pgx.BeginTx(ctx, pgx.TxOptions{}) if err != nil { return false, err @@ -149,10 +257,20 @@ func (t *Tx) QueryRow(sql rawStringOnly, arguments ...any) Row { // Select in a transaction. func (t *Tx) Select(sliceOfStructPtr any, sql rawStringOnly, arguments ...any) error { - return pgxscan.Select(t.ctx, t.Tx, sliceOfStructPtr, string(sql), arguments...) + rows, err := t.Query(sql, arguments...) + if err != nil { + return fmt.Errorf("scany: query multiple result rows: %w", err) + } + defer rows.Close() + return dbscan.ScanAll(sliceOfStructPtr, dbscanRows{rows.Qry.(pgx.Rows)}) } func IsErrUniqueContraint(err error) bool { var e2 *pgconn.PgError return errors.As(err, &e2) && e2.Code == pgerrcode.UniqueViolation } + +func IsErrSerialization(err error) bool { + var e2 *pgconn.PgError + return errors.As(err, &e2) && e2.Code == pgerrcode.SerializationFailure +} diff --git a/lib/harmony/harmonytask/harmonytask.go b/lib/harmony/harmonytask/harmonytask.go index 7577c5cf564..0c66891d0c7 100644 --- a/lib/harmony/harmonytask/harmonytask.go +++ b/lib/harmony/harmonytask/harmonytask.go @@ -12,9 +12,10 @@ import ( ) // Consts (except for unit test) -var POLL_DURATION = time.Second * 3 // Poll for Work this frequently -var CLEANUP_FREQUENCY = 5 * time.Minute // Check for dead workers this often * everyone -var FOLLOW_FREQUENCY = 1 * time.Minute // Check for work to follow this often +var POLL_DURATION = time.Second * 3 // Poll for Work this frequently +var POLL_NEXT_DURATION = 100 * time.Millisecond // After scheduling a task, wait this long before scheduling another +var CLEANUP_FREQUENCY = 5 * time.Minute // Check for dead workers this often * everyone +var FOLLOW_FREQUENCY = 1 * time.Minute // Check for work to follow this often type TaskTypeDetails struct { // Max returns how many tasks this machine can run of this type. @@ -38,6 +39,12 @@ type TaskTypeDetails struct { // NOTE: if refatoring tasks, see if your task is // necessary. Ex: Is the sector state correct for your stage to run? Follows map[string]func(TaskID, AddTaskFunc) (bool, error) + + // IAmBored is called (when populated) when there's capacity but no work. + // Tasks added will be proposed to CanAccept() on this machine. + // CanAccept() can read taskEngine's WorkOrigin string to learn about a task. + // Ex: make new CC sectors, clean-up, or retrying pipelines that failed in later states. + IAmBored func(AddTaskFunc) error } // TaskInterface must be implemented in order to have a task used by harmonytask. @@ -96,17 +103,21 @@ type TaskInterface interface { type AddTaskFunc func(extraInfo func(TaskID, *harmonydb.Tx) (shouldCommit bool, seriousError error)) type TaskEngine struct { - ctx context.Context - handlers []*taskTypeHandler - db *harmonydb.DB - reg *resources.Reg - grace context.CancelFunc - taskMap map[string]*taskTypeHandler - ownerID int - follows map[string][]followStruct + // Static After New() + ctx context.Context + handlers []*taskTypeHandler + db *harmonydb.DB + reg *resources.Reg + grace context.CancelFunc + taskMap map[string]*taskTypeHandler + ownerID int + follows map[string][]followStruct + hostAndPort string + + // synchronous to the single-threaded poller lastFollowTime time.Time lastCleanup atomic.Value - hostAndPort string + WorkOrigin string } type followStruct struct { f func(TaskID, AddTaskFunc) (bool, error) @@ -176,8 +187,8 @@ func New( continue // not really fatal, but not great } } - if !h.considerWork(workSourceRecover, []TaskID{TaskID(w.ID)}) { - log.Error("Strange: Unable to accept previously owned task: ", w.ID, w.Name) + if !h.considerWork(WorkSourceRecover, []TaskID{TaskID(w.ID)}) { + log.Errorw("Strange: Unable to accept previously owned task", "id", w.ID, "type", w.Name) } } } @@ -192,32 +203,72 @@ func New( // GracefullyTerminate hangs until all present tasks have completed. // Call this to cleanly exit the process. As some processes are long-running, // passing a deadline will ignore those still running (to be picked-up later). -func (e *TaskEngine) GracefullyTerminate(deadline time.Duration) { +func (e *TaskEngine) GracefullyTerminate() { + + // call the cancel func to avoid picking up any new tasks. Running tasks have context.Background() + // Call shutdown to stop posting heartbeat to DB. e.grace() e.reg.Shutdown() - deadlineChan := time.NewTimer(deadline).C -top: - for _, h := range e.handlers { - if h.Count.Load() > 0 { - select { - case <-deadlineChan: - return - default: - time.Sleep(time.Millisecond) - goto top + + // If there are any Post tasks then wait till Timeout and check again + // When no Post tasks are active, break out of loop and call the shutdown function + for { + timeout := time.Millisecond + for _, h := range e.handlers { + if h.TaskTypeDetails.Name == "WinPost" && h.Count.Load() > 0 { + timeout = time.Second + log.Infof("node shutdown deferred for %f seconds", timeout.Seconds()) + continue + } + if h.TaskTypeDetails.Name == "WdPost" && h.Count.Load() > 0 { + timeout = time.Second * 3 + log.Infof("node shutdown deferred for %f seconds due to running WdPost task", timeout.Seconds()) + continue } + + if h.TaskTypeDetails.Name == "WdPostSubmit" && h.Count.Load() > 0 { + timeout = time.Second + log.Infof("node shutdown deferred for %f seconds due to running WdPostSubmit task", timeout.Seconds()) + continue + } + + if h.TaskTypeDetails.Name == "WdPostRecover" && h.Count.Load() > 0 { + timeout = time.Second + log.Infof("node shutdown deferred for %f seconds due to running WdPostRecover task", timeout.Seconds()) + continue + } + + // Test tasks for itest + if h.TaskTypeDetails.Name == "ThingOne" && h.Count.Load() > 0 { + timeout = time.Second + log.Infof("node shutdown deferred for %f seconds due to running itest task", timeout.Seconds()) + continue + } + } + if timeout > time.Millisecond { + time.Sleep(timeout) + continue } + break } + + return } func (e *TaskEngine) poller() { + nextWait := POLL_NEXT_DURATION for { select { - case <-time.NewTicker(POLL_DURATION).C: // Find work periodically + case <-time.After(nextWait): // Find work periodically case <-e.ctx.Done(): ///////////////////// Graceful exit return } - e.pollerTryAllWork() + nextWait = POLL_DURATION + + accepted := e.pollerTryAllWork() + if accepted { + nextWait = POLL_NEXT_DURATION + } if time.Since(e.lastFollowTime) > FOLLOW_FREQUENCY { e.followWorkInDB() } @@ -233,7 +284,7 @@ func (e *TaskEngine) followWorkInDB() { for fromName, srcs := range e.follows { var cList []int // Which work is done (that we follow) since we last checked? err := e.db.Select(e.ctx, &cList, `SELECT h.task_id FROM harmony_task_history - WHERE h.work_end>$1 AND h.name=$2`, lastFollowTime, fromName) + WHERE h.work_end>$1 AND h.name=$2`, lastFollowTime.UTC(), fromName) if err != nil { log.Error("Could not query DB: ", err) return @@ -266,13 +317,14 @@ func (e *TaskEngine) followWorkInDB() { } // pollerTryAllWork starts the next 1 task -func (e *TaskEngine) pollerTryAllWork() { +func (e *TaskEngine) pollerTryAllWork() bool { if time.Since(e.lastCleanup.Load().(time.Time)) > CLEANUP_FREQUENCY { e.lastCleanup.Store(time.Now()) resources.CleanupMachines(e.ctx, e.db) } for _, v := range e.handlers { - if v.AssertMachineHasCapacity() != nil { + if err := v.AssertMachineHasCapacity(); err != nil { + log.Debugf("skipped scheduling %s type tasks on due to %s", v.Name, err.Error()) continue } var unownedTasks []TaskID @@ -285,13 +337,41 @@ func (e *TaskEngine) pollerTryAllWork() { continue } if len(unownedTasks) > 0 { - accepted := v.considerWork(workSourcePoller, unownedTasks) + accepted := v.considerWork(WorkSourcePoller, unownedTasks) if accepted { - return // accept new work slowly and in priority order + return true // accept new work slowly and in priority order } log.Warn("Work not accepted for " + strconv.Itoa(len(unownedTasks)) + " " + v.Name + " task(s)") } } + // if no work was accepted, are we bored? Then find work in priority order. + for _, v := range e.handlers { + v := v + if v.AssertMachineHasCapacity() != nil { + continue + } + if v.TaskTypeDetails.IAmBored != nil { + var added []TaskID + err := v.TaskTypeDetails.IAmBored(func(extraInfo func(TaskID, *harmonydb.Tx) (shouldCommit bool, seriousError error)) { + v.AddTask(func(tID TaskID, tx *harmonydb.Tx) (shouldCommit bool, seriousError error) { + b, err := extraInfo(tID, tx) + if err == nil { + added = append(added, tID) + } + return b, err + }) + }) + if err != nil { + log.Error("IAmBored failed: ", err) + continue + } + if added != nil { // tiny chance a fail could make these bogus, but considerWork should then fail. + v.considerWork(WorkSourceIAmBored, added) + } + } + } + + return false } // ResourcesAvailable determines what resources are still unassigned. diff --git a/lib/harmony/harmonytask/singleton_task.go b/lib/harmony/harmonytask/singleton_task.go new file mode 100644 index 00000000000..72003341026 --- /dev/null +++ b/lib/harmony/harmonytask/singleton_task.go @@ -0,0 +1,52 @@ +package harmonytask + +import ( + "errors" + "time" + + "github.com/jackc/pgx/v5" + + "github.com/filecoin-project/lotus/lib/harmony/harmonydb" + "github.com/filecoin-project/lotus/lib/passcall" +) + +func SingletonTaskAdder(minInterval time.Duration, task TaskInterface) func(AddTaskFunc) error { + return passcall.Every(minInterval, func(add AddTaskFunc) error { + taskName := task.TypeDetails().Name + + add(func(taskID TaskID, tx *harmonydb.Tx) (shouldCommit bool, err error) { + var existingTaskID *int64 + var lastRunTime time.Time + + // Query to check the existing task entry + err = tx.QueryRow(`SELECT task_id, last_run_time FROM harmony_task_singletons WHERE task_name = $1`, taskName).Scan(&existingTaskID, &lastRunTime) + if err != nil { + if !errors.Is(err, pgx.ErrNoRows) { + return false, err // return error if query failed and it's not because of missing row + } + } + + now := time.Now().UTC() + // Determine if the task should run based on the absence of a record or outdated last_run_time + shouldRun := err == pgx.ErrNoRows || (existingTaskID == nil && lastRunTime.Add(minInterval).Before(now)) + if !shouldRun { + return false, nil + } + + // Conditionally insert or update the task entry + n, err := tx.Exec(` + INSERT INTO harmony_task_singletons (task_name, task_id, last_run_time) + VALUES ($1, $2, $3) + ON CONFLICT (task_name) DO UPDATE + SET task_id = COALESCE(harmony_task_singletons.task_id, $2), + last_run_time = $3 + WHERE harmony_task_singletons.task_id IS NULL + `, taskName, taskID, now) + if err != nil { + return false, err + } + return n > 0, nil + }) + return nil + }) +} diff --git a/lib/harmony/harmonytask/task_type_handler.go b/lib/harmony/harmonytask/task_type_handler.go index 34f7a5c3e31..a8c6e58b8fc 100644 --- a/lib/harmony/harmonytask/task_type_handler.go +++ b/lib/harmony/harmonytask/task_type_handler.go @@ -25,17 +25,15 @@ type taskTypeHandler struct { func (h *taskTypeHandler) AddTask(extra func(TaskID, *harmonydb.Tx) (bool, error)) { var tID TaskID + retryWait := time.Millisecond * 100 +retryAddTask: _, err := h.TaskEngine.db.BeginTransaction(h.TaskEngine.ctx, func(tx *harmonydb.Tx) (bool, error) { // create taskID (from DB) - _, err := tx.Exec(`INSERT INTO harmony_task (name, added_by, posted_time) - VALUES ($1, $2, CURRENT_TIMESTAMP) `, h.Name, h.TaskEngine.ownerID) + err := tx.QueryRow(`INSERT INTO harmony_task (name, added_by, posted_time) + VALUES ($1, $2, CURRENT_TIMESTAMP) RETURNING id`, h.Name, h.TaskEngine.ownerID).Scan(&tID) if err != nil { return false, fmt.Errorf("could not insert into harmonyTask: %w", err) } - err = tx.QueryRow("SELECT id FROM harmony_task ORDER BY update_time DESC LIMIT 1").Scan(&tID) - if err != nil { - return false, fmt.Errorf("Could not select ID: %v", err) - } return extra(tID, tx) }) @@ -44,14 +42,20 @@ func (h *taskTypeHandler) AddTask(extra func(TaskID, *harmonydb.Tx) (bool, error log.Debugf("addtask(%s) saw unique constraint, so it's added already.", h.Name) return } - log.Error("Could not add task. AddTasFunc failed: %v", err) + if harmonydb.IsErrSerialization(err) { + time.Sleep(retryWait) + retryWait *= 2 + goto retryAddTask + } + log.Errorw("Could not add task. AddTasFunc failed", "error", err, "type", h.Name) return } } const ( - workSourcePoller = "poller" - workSourceRecover = "recovered" + WorkSourcePoller = "poller" + WorkSourceRecover = "recovered" + WorkSourceIAmBored = "bored" ) // considerWork is called to attempt to start work on a task-id of this task type. @@ -81,8 +85,14 @@ top: return false } + h.TaskEngine.WorkOrigin = from + // 3. What does the impl say? +canAcceptAgain: tID, err := h.CanAccept(ids, h.TaskEngine) + + h.TaskEngine.WorkOrigin = "" + if err != nil { log.Error(err) return false @@ -92,16 +102,46 @@ top: return false } + releaseStorage := func() { + } + if h.TaskTypeDetails.Cost.Storage != nil { + if err = h.TaskTypeDetails.Cost.Storage.Claim(int(*tID)); err != nil { + log.Infow("did not accept task", "task_id", strconv.Itoa(int(*tID)), "reason", "storage claim failed", "name", h.Name, "error", err) + + if len(ids) > 1 { + var tryAgain = make([]TaskID, 0, len(ids)-1) + for _, id := range ids { + if id != *tID { + tryAgain = append(tryAgain, id) + } + } + ids = tryAgain + goto canAcceptAgain + } + + return false + } + releaseStorage = func() { + if err := h.TaskTypeDetails.Cost.Storage.MarkComplete(int(*tID)); err != nil { + log.Errorw("Could not release storage", "error", err) + } + } + } + // if recovering we don't need to try to claim anything because those tasks are already claimed by us - if from != workSourceRecover { + if from != WorkSourceRecover { // 4. Can we claim the work for our hostname? ct, err := h.TaskEngine.db.Exec(h.TaskEngine.ctx, "UPDATE harmony_task SET owner_id=$1 WHERE id=$2 AND owner_id IS NULL", h.TaskEngine.ownerID, *tID) if err != nil { log.Error(err) + + releaseStorage() return false } if ct == 0 { log.Infow("did not accept task", "task_id", strconv.Itoa(int(*tID)), "reason", "already Taken", "name", h.Name) + releaseStorage() + var tryAgain = make([]TaskID, 0, len(ids)-1) for _, id := range ids { if id != *tID { @@ -131,6 +171,7 @@ top: } h.Count.Add(-1) + releaseStorage() h.recordCompletion(*tID, workStart, done, doErr) if done { for _, fs := range h.TaskEngine.follows[h.Name] { // Do we know of any follows for this task type? @@ -161,10 +202,12 @@ top: func (h *taskTypeHandler) recordCompletion(tID TaskID, workStart time.Time, done bool, doErr error) { workEnd := time.Now() - + retryWait := time.Millisecond * 100 +retryRecordCompletion: cm, err := h.TaskEngine.db.BeginTransaction(h.TaskEngine.ctx, func(tx *harmonydb.Tx) (bool, error) { var postedTime time.Time err := tx.QueryRow(`SELECT posted_time FROM harmony_task WHERE id=$1`, tID).Scan(&postedTime) + if err != nil { return false, fmt.Errorf("could not log completion: %w ", err) } @@ -176,6 +219,9 @@ func (h *taskTypeHandler) recordCompletion(tID TaskID, workStart time.Time, done return false, fmt.Errorf("could not log completion: %w", err) } result = "" + if doErr != nil { + result = "non-failing error: " + doErr.Error() + } } else { if doErr != nil { result = "error: " + doErr.Error() @@ -207,13 +253,18 @@ func (h *taskTypeHandler) recordCompletion(tID TaskID, workStart time.Time, done } _, err = tx.Exec(`INSERT INTO harmony_task_history (task_id, name, posted, work_start, work_end, result, completed_by_host_and_port, err) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, tID, h.Name, postedTime, workStart, workEnd, done, h.TaskEngine.hostAndPort, result) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, tID, h.Name, postedTime.UTC(), workStart.UTC(), workEnd.UTC(), done, h.TaskEngine.hostAndPort, result) if err != nil { return false, fmt.Errorf("could not write history: %w", err) } return true, nil }) if err != nil { + if harmonydb.IsErrSerialization(err) { + time.Sleep(retryWait) + retryWait *= 2 + goto retryRecordCompletion + } log.Error("Could not record transaction: ", err) return } @@ -234,5 +285,11 @@ func (h *taskTypeHandler) AssertMachineHasCapacity() error { if r.Gpu-h.Cost.Gpu < 0 { return errors.New("Did not accept " + h.Name + " task: out of available GPU") } + + if h.TaskTypeDetails.Cost.Storage != nil { + if !h.TaskTypeDetails.Cost.Storage.HasCapacity() { + return errors.New("Did not accept " + h.Name + " task: out of available Storage") + } + } return nil } diff --git a/lib/harmony/resources/getGPU.go b/lib/harmony/resources/getGPU.go index 9a73bcd0d96..62d5c091e11 100644 --- a/lib/harmony/resources/getGPU.go +++ b/lib/harmony/resources/getGPU.go @@ -4,13 +4,25 @@ package resources import ( + "os" + "strconv" "strings" ffi "github.com/filecoin-project/filecoin-ffi" ) func getGPUDevices() float64 { // GPU boolean + if nstr := os.Getenv("HARMONY_OVERRIDE_GPUS"); nstr != "" { + n, err := strconv.ParseFloat(nstr, 64) + if err != nil { + logger.Errorf("parsing HARMONY_OVERRIDE_GPUS failed: %+v", err) + } else { + return n + } + } + gpus, err := ffi.GetGPUDevices() + logger.Infow("GPUs", "list", gpus) if err != nil { logger.Errorf("getting gpu devices failed: %+v", err) } diff --git a/lib/harmony/resources/resources.go b/lib/harmony/resources/resources.go index b129496d8bd..33bc80d6fe7 100644 --- a/lib/harmony/resources/resources.go +++ b/lib/harmony/resources/resources.go @@ -9,8 +9,8 @@ import ( "sync/atomic" "time" + "github.com/elastic/go-sysinfo" logging "github.com/ipfs/go-log/v2" - "github.com/pbnjay/memory" "golang.org/x/sys/unix" "golang.org/x/xerrors" @@ -24,6 +24,19 @@ type Resources struct { Gpu float64 Ram uint64 MachineID int + Storage +} + +// Optional Storage management. +type Storage interface { + HasCapacity() bool + + // This allows some other system to claim space for this task. + Claim(taskID int) error + + // This allows some other system to consider the task done. + // It's up to the caller to remove the data, if that applies. + MarkComplete(taskID int) error } type Reg struct { Resources @@ -82,7 +95,7 @@ func Register(db *harmonydb.DB, hostnameAndPort string) (*Reg, error) { if reg.shutdown.Load() { return } - _, err := db.Exec(ctx, `UPDATE harmony_machines SET last_contact=CURRENT_TIMESTAMP`) + _, err := db.Exec(ctx, `UPDATE harmony_machines SET last_contact=CURRENT_TIMESTAMP where id=$1`, reg.MachineID) if err != nil { logger.Error("Cannot keepalive ", err) } @@ -118,13 +131,23 @@ func getResources() (res Resources, err error) { } } if found > 1 { - logger.Warn("lotus-provider's defaults are for running alone. Use task maximums or CGroups.") + logger.Warn("curio's defaults are for running alone. Use task maximums or CGroups.") } } + h, err := sysinfo.Host() + if err != nil { + return Resources{}, err + } + + mem, err := h.Memory() + if err != nil { + return Resources{}, err + } + res = Resources{ Cpu: runtime.NumCPU(), - Ram: memory.FreeMemory(), + Ram: mem.Available, Gpu: getGPUDevices(), } diff --git a/lib/passcall/every.go b/lib/passcall/every.go new file mode 100644 index 00000000000..f39543063dd --- /dev/null +++ b/lib/passcall/every.go @@ -0,0 +1,28 @@ +package passcall + +import ( + "sync" + "time" +) + +// Every is a helper function that will call the provided callback +// function at most once every `passEvery` duration. If the function is called +// more frequently than that, it will return nil and not call the callback. +func Every[P, R any](passInterval time.Duration, cb func(P) R) func(P) R { + var lastCall time.Time + var lk sync.Mutex + + return func(param P) R { + lk.Lock() + defer lk.Unlock() + + if time.Since(lastCall) < passInterval { + return *new(R) + } + + defer func() { + lastCall = time.Now() + }() + return cb(param) + } +} diff --git a/lib/promise/promise.go b/lib/promise/promise.go index 9b6a5e2b060..02e917ca121 100644 --- a/lib/promise/promise.go +++ b/lib/promise/promise.go @@ -45,3 +45,9 @@ func (p *Promise[T]) Val(ctx context.Context) T { return val } } + +func (p *Promise[T]) IsSet() bool { + p.mu.Lock() + defer p.mu.Unlock() + return p.done != nil +} diff --git a/lib/ulimit/ulimit_test.go b/lib/ulimit/ulimit_test.go index 071c6013c81..ad20feb1de9 100644 --- a/lib/ulimit/ulimit_test.go +++ b/lib/ulimit/ulimit_test.go @@ -46,8 +46,8 @@ func TestManageInvalidNFds(t *testing.T) { t.Logf("setting ulimit to %d, max %d, cur %d", value, rlimit.Max, rlimit.Cur) - if changed, new, err := ManageFdLimit(); err == nil { - t.Errorf("ManageFdLimit should return an error: changed %t, new: %d", changed, new) + if changed, isNew, err := ManageFdLimit(); err == nil { + t.Errorf("ManageFdLimit should return an error: changed %t, new: %d", changed, isNew) } else if err != nil { flag := strings.Contains(err.Error(), "failed to raise ulimit to LOTUS_FD_MAX") diff --git a/markets/dagstore/miner_api.go b/markets/dagstore/miner_api.go index 8a12097d5f2..773654af8ed 100644 --- a/markets/dagstore/miner_api.go +++ b/markets/dagstore/miner_api.go @@ -201,7 +201,5 @@ func (m *minerAPI) GetUnpaddedCARSize(ctx context.Context, pieceCid cid.Cid) (ui return 0, xerrors.Errorf("no storage deals found for piece %s", pieceCid) } - len := pieceInfo.Deals[0].Length - - return uint64(len), nil + return uint64(pieceInfo.Deals[0].Length), nil } diff --git a/markets/dagstore/miner_api_test.go b/markets/dagstore/miner_api_test.go index 08135b3a553..d13b098fc7f 100644 --- a/markets/dagstore/miner_api_test.go +++ b/markets/dagstore/miner_api_test.go @@ -129,9 +129,9 @@ func TestLotusAccessorGetUnpaddedCARSize(t *testing.T) { // Check that the data length is correct //stm: @MARKET_DAGSTORE_GET_UNPADDED_CAR_SIZE_001 - len, err := api.GetUnpaddedCARSize(ctx, cid1) + l, err := api.GetUnpaddedCARSize(ctx, cid1) require.NoError(t, err) - require.EqualValues(t, 10, len) + require.EqualValues(t, 10, l) } func TestThrottle(t *testing.T) { diff --git a/metrics/metrics.go b/metrics/metrics.go index 5d6ba79ec3b..85b9d82ec20 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -190,11 +190,11 @@ var ( RcmgrAllowPeer = stats.Int64("rcmgr/allow_peer", "Number of allowed peer connections", stats.UnitDimensionless) RcmgrBlockPeer = stats.Int64("rcmgr/block_peer", "Number of blocked peer connections", stats.UnitDimensionless) RcmgrAllowProto = stats.Int64("rcmgr/allow_proto", "Number of allowed streams attached to a protocol", stats.UnitDimensionless) - RcmgrBlockProto = stats.Int64("rcmgr/block_proto", "Number of blocked blocked streams attached to a protocol", stats.UnitDimensionless) - RcmgrBlockProtoPeer = stats.Int64("rcmgr/block_proto", "Number of blocked blocked streams attached to a protocol for a specific peer", stats.UnitDimensionless) + RcmgrBlockProto = stats.Int64("rcmgr/block_proto", "Number of blocked streams attached to a protocol", stats.UnitDimensionless) + RcmgrBlockProtoPeer = stats.Int64("rcmgr/block_proto", "Number of blocked streams attached to a protocol for a specific peer", stats.UnitDimensionless) RcmgrAllowSvc = stats.Int64("rcmgr/allow_svc", "Number of allowed streams attached to a service", stats.UnitDimensionless) - RcmgrBlockSvc = stats.Int64("rcmgr/block_svc", "Number of blocked blocked streams attached to a service", stats.UnitDimensionless) - RcmgrBlockSvcPeer = stats.Int64("rcmgr/block_svc", "Number of blocked blocked streams attached to a service for a specific peer", stats.UnitDimensionless) + RcmgrBlockSvc = stats.Int64("rcmgr/block_svc", "Number of blocked streams attached to a service", stats.UnitDimensionless) + RcmgrBlockSvcPeer = stats.Int64("rcmgr/block_svc", "Number of blocked streams attached to a service for a specific peer", stats.UnitDimensionless) RcmgrAllowMem = stats.Int64("rcmgr/allow_mem", "Number of allowed memory reservations", stats.UnitDimensionless) RcmgrBlockMem = stats.Int64("rcmgr/block_mem", "Number of blocked memory reservations", stats.UnitDimensionless) diff --git a/metrics/proxy/proxy.go b/metrics/proxy/proxy.go index 6885adfe958..1f0bd9672df 100644 --- a/metrics/proxy/proxy.go +++ b/metrics/proxy/proxy.go @@ -2,8 +2,10 @@ package proxy import ( "context" + "fmt" "reflect" + logging "github.com/ipfs/go-log/v2" "go.opencensus.io/tag" "github.com/filecoin-project/lotus/api" @@ -69,3 +71,41 @@ func proxy(in interface{}, outstr interface{}) { } } } + +var log = logging.Logger("api_proxy") + +func LoggingAPI[T, P any](a T) *P { + var out P + logProxy(a, &out) + return &out +} + +func logProxy(in interface{}, outstr interface{}) { + outs := api.GetInternalStructs(outstr) + for _, out := range outs { + rint := reflect.ValueOf(out).Elem() + ra := reflect.ValueOf(in) + + for f := 0; f < rint.NumField(); f++ { + field := rint.Type().Field(f) + fn := ra.MethodByName(field.Name) + + rint.Field(f).Set(reflect.MakeFunc(field.Type, func(args []reflect.Value) (results []reflect.Value) { + var wargs []interface{} + wargs = append(wargs, "method", field.Name) + + for i := 1; i < len(args); i++ { + wargs = append(wargs, fmt.Sprintf("arg%d", i), args[i].Interface()) + } + + res := fn.Call(args) + for i, r := range res { + wargs = append(wargs, fmt.Sprintf("ret%d", i), r.Interface()) + } + + log.Debugw("APICALL", wargs...) + return res + })) + } + } +} diff --git a/miner/miner.go b/miner/miner.go index d11e9d4aa04..4f27c53dbcd 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -53,7 +53,7 @@ type waitFunc func(ctx context.Context, baseTime uint64) (func(bool, abi.ChainEp func randTimeOffset(width time.Duration) time.Duration { buf := make([]byte, 8) - rand.Reader.Read(buf) //nolint:errcheck + _, _ = rand.Reader.Read(buf) val := time.Duration(binary.BigEndian.Uint64(buf) % uint64(width)) return val - (width / 2) diff --git a/node/builder.go b/node/builder.go index 128a99f8714..1cd4823d533 100644 --- a/node/builder.go +++ b/node/builder.go @@ -127,7 +127,6 @@ const ( SettlePaymentChannelsKey RunPeerTaggerKey SetupFallbackBlockstoresKey - GoRPCServer ConsensusReporterKey diff --git a/node/builder_chain.go b/node/builder_chain.go index 2d9c0ea2e54..0b40e4530c4 100644 --- a/node/builder_chain.go +++ b/node/builder_chain.go @@ -3,7 +3,6 @@ package node import ( "os" - gorpc "github.com/libp2p/go-libp2p-gorpc" "go.uber.org/fx" "golang.org/x/xerrors" @@ -32,7 +31,6 @@ import ( "github.com/filecoin-project/lotus/chain/wallet" ledgerwallet "github.com/filecoin-project/lotus/chain/wallet/ledger" "github.com/filecoin-project/lotus/chain/wallet/remotewallet" - raftcns "github.com/filecoin-project/lotus/lib/consensus/raft" "github.com/filecoin-project/lotus/lib/peermgr" "github.com/filecoin-project/lotus/markets/retrievaladapter" "github.com/filecoin-project/lotus/markets/storageadapter" @@ -185,7 +183,6 @@ func ConfigFullNode(c interface{}) Option { enableLibp2pNode := true // always enable libp2p for full nodes - ipfsMaddr := cfg.Client.IpfsMAddr return Options( ConfigCommon(&cfg.Common, enableLibp2pNode), @@ -231,13 +228,6 @@ func ConfigFullNode(c interface{}) Option { Override(new(dtypes.ClientBlockstore), modules.ClientBlockstore), - If(cfg.Client.UseIpfs, - Override(new(dtypes.ClientBlockstore), modules.IpfsClientBlockstore(ipfsMaddr, cfg.Client.IpfsOnlineMode)), - Override(new(storagemarket.BlockstoreAccessor), modules.IpfsStorageBlockstoreAccessor), - If(cfg.Client.IpfsUseForRetrieval, - Override(new(retrievalmarket.BlockstoreAccessor), modules.IpfsRetrievalBlockstoreAccessor), - ), - ), Override(new(dtypes.Graphsync), modules.Graphsync(cfg.Client.SimultaneousTransfersForStorage, cfg.Client.SimultaneousTransfersForRetrieval)), Override(new(retrievalmarket.RetrievalClient), modules.RetrievalClient(cfg.Client.OffChainRetrieval)), @@ -253,17 +243,6 @@ func ConfigFullNode(c interface{}) Option { Override(new(wallet.Default), wallet.NilDefault), ), - // Chain node cluster enabled - If(cfg.Cluster.ClusterModeEnabled, - Override(new(*gorpc.Client), modules.NewRPCClient), - Override(new(*raftcns.ClusterRaftConfig), raftcns.NewClusterRaftConfig(&cfg.Cluster)), - Override(new(*raftcns.Consensus), raftcns.NewConsensusWithRPCClient(false)), - Override(new(*messagesigner.MessageSignerConsensus), messagesigner.NewMessageSignerConsensus), - Override(new(messagesigner.MsgSigner), From(new(*messagesigner.MessageSignerConsensus))), - Override(new(*modules.RPCHandler), modules.NewRPCHandler), - Override(GoRPCServer, modules.NewRPCServer), - ), - // Actor event filtering support Override(new(events.EventHelperAPI), From(new(modules.EventHelperAPI))), Override(new(*filter.EventFilterManager), modules.EventFilterManager(cfg.Events)), diff --git a/node/config/def.go b/node/config/def.go index 7e06eba3a18..2dd4b77eb2f 100644 --- a/node/config/def.go +++ b/node/config/def.go @@ -77,17 +77,18 @@ func defCommon() Common { } } -var ( - DefaultDefaultMaxFee = types.MustParseFIL("0.07") - DefaultSimultaneousTransfers = uint64(20) -) +var DefaultSimultaneousTransfers = uint64(20) + +func DefaultDefaultMaxFee() types.FIL { + return types.MustParseFIL("0.07") +} // DefaultFullNode returns the default config func DefaultFullNode() *FullNode { return &FullNode{ Common: defCommon(), Fees: FeeConfig{ - DefaultMaxFee: DefaultDefaultMaxFee, + DefaultMaxFee: DefaultDefaultMaxFee(), }, Client: Client{ SimultaneousTransfersForStorage: DefaultSimultaneousTransfers, @@ -106,7 +107,6 @@ func DefaultFullNode() *FullNode { HotstoreMaxSpaceSafetyBuffer: 50_000_000_000, }, }, - Cluster: *DefaultUserRaftConfig(), Fevm: FevmConfig{ EnableEthRPC: false, EthTxHashMappingLifetimeDays: 0, @@ -328,33 +328,14 @@ const ( ResourceFilteringDisabled = ResourceFilteringStrategy("disabled") ) -var ( - DefaultDataSubFolder = "raft" - DefaultWaitForLeaderTimeout = 15 * time.Second - DefaultCommitRetries = 1 - DefaultNetworkTimeout = 100 * time.Second - DefaultCommitRetryDelay = 200 * time.Millisecond - DefaultBackupsRotate = 6 -) - -func DefaultUserRaftConfig() *UserRaftConfig { - var cfg UserRaftConfig - cfg.DataFolder = "" // empty so it gets omitted - cfg.InitPeersetMultiAddr = []string{} - cfg.WaitForLeaderTimeout = Duration(DefaultWaitForLeaderTimeout) - cfg.NetworkTimeout = Duration(DefaultNetworkTimeout) - cfg.CommitRetries = DefaultCommitRetries - cfg.CommitRetryDelay = Duration(DefaultCommitRetryDelay) - cfg.BackupsRotate = DefaultBackupsRotate - - return &cfg -} - -func DefaultLotusProvider() *LotusProviderConfig { - return &LotusProviderConfig{ - Subsystems: ProviderSubsystemsConfig{}, - Fees: LotusProviderFees{ - DefaultMaxFee: DefaultDefaultMaxFee, +func DefaultCurioConfig() *CurioConfig { + return &CurioConfig{ + Subsystems: CurioSubsystemsConfig{ + GuiAddress: ":4701", + BoostAdapters: []string{}, + }, + Fees: CurioFees{ + DefaultMaxFee: DefaultDefaultMaxFee(), MaxPreCommitGasFee: types.MustParseFIL("0.025"), MaxCommitGasFee: types.MustParseFIL("0.05"), @@ -371,15 +352,21 @@ func DefaultLotusProvider() *LotusProviderConfig { MaxWindowPoStGasFee: types.MustParseFIL("5"), MaxPublishDealsFee: types.MustParseFIL("0.05"), }, - Addresses: LotusProviderAddresses{ + Addresses: []CurioAddresses{{ PreCommitControl: []string{}, CommitControl: []string{}, TerminateControl: []string{}, - }, - Proving: ProvingConfig{ + MinerAddresses: []string{}, + }}, + Proving: CurioProvingConfig{ ParallelCheckLimit: 32, PartitionCheckTimeout: Duration(20 * time.Minute), SingleCheckTimeout: Duration(10 * time.Minute), }, + Ingest: CurioIngestConfig{ + MaxQueueSDR: 8, // default to 8 sectors before sdr + MaxQueueTrees: 0, // default don't use this limit + MaxQueuePoRep: 0, // default don't use this limit + }, } } diff --git a/node/config/doc_gen.go b/node/config/doc_gen.go index 929f1576653..74549163e71 100644 --- a/node/config/doc_gen.go +++ b/node/config/doc_gen.go @@ -87,82 +87,531 @@ your node if metadata log is disabled`, }, "Client": { { - Name: "UseIpfs", + Name: "SimultaneousTransfersForStorage", + Type: "uint64", + + Comment: `The maximum number of simultaneous data transfers between the client +and storage providers for storage deals`, + }, + { + Name: "SimultaneousTransfersForRetrieval", + Type: "uint64", + + Comment: `The maximum number of simultaneous data transfers between the client +and storage providers for retrieval deals`, + }, + { + Name: "OffChainRetrieval", + Type: "bool", + + Comment: `Require that retrievals perform no on-chain operations. Paid retrievals +without existing payment channels with available funds will fail instead +of automatically performing on-chain operations.`, + }, + }, + "Common": { + { + Name: "API", + Type: "API", + + Comment: ``, + }, + { + Name: "Backup", + Type: "Backup", + + Comment: ``, + }, + { + Name: "Logging", + Type: "Logging", + + Comment: ``, + }, + { + Name: "Libp2p", + Type: "Libp2p", + + Comment: ``, + }, + { + Name: "Pubsub", + Type: "Pubsub", + + Comment: ``, + }, + }, + "CurioAddresses": { + { + Name: "PreCommitControl", + Type: "[]string", + + Comment: `Addresses to send PreCommit messages from`, + }, + { + Name: "CommitControl", + Type: "[]string", + + Comment: `Addresses to send Commit messages from`, + }, + { + Name: "TerminateControl", + Type: "[]string", + + Comment: ``, + }, + { + Name: "DisableOwnerFallback", + Type: "bool", + + Comment: `DisableOwnerFallback disables usage of the owner address for messages +sent automatically`, + }, + { + Name: "DisableWorkerFallback", + Type: "bool", + + Comment: `DisableWorkerFallback disables usage of the worker address for messages +sent automatically, if control addresses are configured. +A control address that doesn't have enough funds will still be chosen +over the worker address if this flag is set.`, + }, + { + Name: "MinerAddresses", + Type: "[]string", + + Comment: `MinerAddresses are the addresses of the miner actors to use for sending messages`, + }, + }, + "CurioConfig": { + { + Name: "Subsystems", + Type: "CurioSubsystemsConfig", + + Comment: ``, + }, + { + Name: "Fees", + Type: "CurioFees", + + Comment: ``, + }, + { + Name: "Addresses", + Type: "[]CurioAddresses", + + Comment: `Addresses of wallets per MinerAddress (one of the fields).`, + }, + { + Name: "Proving", + Type: "CurioProvingConfig", + + Comment: ``, + }, + { + Name: "Ingest", + Type: "CurioIngestConfig", + + Comment: ``, + }, + { + Name: "Journal", + Type: "JournalConfig", + + Comment: ``, + }, + { + Name: "Apis", + Type: "ApisConfig", + + Comment: ``, + }, + }, + "CurioFees": { + { + Name: "DefaultMaxFee", + Type: "types.FIL", + + Comment: ``, + }, + { + Name: "MaxPreCommitGasFee", + Type: "types.FIL", + + Comment: ``, + }, + { + Name: "MaxCommitGasFee", + Type: "types.FIL", + + Comment: ``, + }, + { + Name: "MaxPreCommitBatchGasFee", + Type: "BatchFeeConfig", + + Comment: `maxBatchFee = maxBase + maxPerSector * nSectors`, + }, + { + Name: "MaxCommitBatchGasFee", + Type: "BatchFeeConfig", + + Comment: ``, + }, + { + Name: "MaxTerminateGasFee", + Type: "types.FIL", + + Comment: ``, + }, + { + Name: "MaxWindowPoStGasFee", + Type: "types.FIL", + + Comment: `WindowPoSt is a high-value operation, so the default fee should be high.`, + }, + { + Name: "MaxPublishDealsFee", + Type: "types.FIL", + + Comment: ``, + }, + }, + "CurioIngestConfig": { + { + Name: "MaxQueueSDR", + Type: "int", + + Comment: `Maximum number of sectors that can be queued waiting for SDR to start processing. +0 = unlimited +Note: This mechanism will delay taking deal data from markets, providing backpressure to the market subsystem. +The SDR queue includes deals which are in the process of entering the sealing pipeline - size of this queue +will also impact the maximum number of ParkPiece tasks which can run concurrently. + +SDR queue is the first queue in the sealing pipeline, meaning that it should be used as the primary backpressure mechanism.`, + }, + { + Name: "MaxQueueTrees", + Type: "int", + + Comment: `Maximum number of sectors that can be queued waiting for SDRTrees to start processing. +0 = unlimited +Note: This mechanism will delay taking deal data from markets, providing backpressure to the market subsystem. +In case of the trees tasks it is possible that this queue grows more than this limit, the backpressure is only +applied to sectors entering the pipeline.`, + }, + { + Name: "MaxQueuePoRep", + Type: "int", + + Comment: `Maximum number of sectors that can be queued waiting for PoRep to start processing. +0 = unlimited +Note: This mechanism will delay taking deal data from markets, providing backpressure to the market subsystem. +Like with the trees tasks, it is possible that this queue grows more than this limit, the backpressure is only +applied to sectors entering the pipeline.`, + }, + }, + "CurioProvingConfig": { + { + Name: "ParallelCheckLimit", + Type: "int", + + Comment: `Maximum number of sector checks to run in parallel. (0 = unlimited) + +WARNING: Setting this value too high may make the node crash by running out of stack +WARNING: Setting this value too low may make sector challenge reading much slower, resulting in failed PoSt due +to late submission. + +After changing this option, confirm that the new value works in your setup by invoking +'lotus-miner proving compute window-post 0'`, + }, + { + Name: "SingleCheckTimeout", + Type: "Duration", + + Comment: `Maximum amount of time a proving pre-check can take for a sector. If the check times out the sector will be skipped + +WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the +test challenge took longer than this timeout +WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this sector are +blocked (e.g. in case of disconnected NFS mount)`, + }, + { + Name: "PartitionCheckTimeout", + Type: "Duration", + + Comment: `Maximum amount of time a proving pre-check can take for an entire partition. If the check times out, sectors in +the partition which didn't get checked on time will be skipped + +WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the +test challenge took longer than this timeout +WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this partition are +blocked or slow`, + }, + { + Name: "DisableWDPoStPreChecks", Type: "bool", + Comment: `Disable WindowPoSt provable sector readability checks. + +In normal operation, when preparing to compute WindowPoSt, lotus-miner will perform a round of reading challenges +from all sectors to confirm that those sectors can be proven. Challenges read in this process are discarded, as +we're only interested in checking that sector data can be read. + +When using builtin proof computation (no PoSt workers, and DisableBuiltinWindowPoSt is set to false), this process +can save a lot of time and compute resources in the case that some sectors are not readable - this is caused by +the builtin logic not skipping snark computation when some sectors need to be skipped. + +When using PoSt workers, this process is mostly redundant, with PoSt workers challenges will be read once, and +if challenges for some sectors aren't readable, those sectors will just get skipped. + +Disabling sector pre-checks will slightly reduce IO load when proving sectors, possibly resulting in shorter +time to produce window PoSt. In setups with good IO capabilities the effect of this option on proving time should +be negligible. + +NOTE: It likely is a bad idea to disable sector pre-checks in setups with no PoSt workers. + +NOTE: Even when this option is enabled, recovering sectors will be checked before recovery declaration message is +sent to the chain + +After changing this option, confirm that the new value works in your setup by invoking +'lotus-miner proving compute window-post 0'`, + }, + { + Name: "MaxPartitionsPerPoStMessage", + Type: "int", + + Comment: `Maximum number of partitions to prove in a single SubmitWindowPoSt messace. 0 = network limit (3 in nv21) + +A single partition may contain up to 2349 32GiB sectors, or 2300 64GiB sectors. +// +Note that setting this value lower may result in less efficient gas use - more messages will be sent, +to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) + +Setting this value above the network limit has no effect`, + }, + { + Name: "MaxPartitionsPerRecoveryMessage", + Type: "int", + + Comment: `In some cases when submitting DeclareFaultsRecovered messages, +there may be too many recoveries to fit in a BlockGasLimit. +In those cases it may be necessary to set this value to something low (eg 1); +Note that setting this value lower may result in less efficient gas use - more messages will be sent than needed, +resulting in more total gas use (but each message will have lower gas limit)`, + }, + { + Name: "SingleRecoveringPartitionPerPostMessage", + Type: "bool", + + Comment: `Enable single partition per PoSt Message for partitions containing recovery sectors + +In cases when submitting PoSt messages which contain recovering sectors, the default network limit may still be +too high to fit in the block gas limit. In those cases, it becomes useful to only house the single partition +with recovering sectors in the post message + +Note that setting this value lower may result in less efficient gas use - more messages will be sent, +to prove each deadline, resulting in more total gas use (but each message will have lower gas limit)`, + }, + }, + "CurioSubsystemsConfig": { + { + Name: "EnableWindowPost", + Type: "bool", + + Comment: `EnableWindowPost enables window post to be executed on this curio instance. Each machine in the cluster +with WindowPoSt enabled will also participate in the window post scheduler. It is possible to have multiple +machines with WindowPoSt enabled which will provide redundancy, and in case of multiple partitions per deadline, +will allow for parallel processing of partitions. + +It is possible to have instances handling both WindowPoSt and WinningPoSt, which can provide redundancy without +the need for additional machines. In setups like this it is generally recommended to run +partitionsPerDeadline+1 machines.`, + }, + { + Name: "WindowPostMaxTasks", + Type: "int", + + Comment: ``, + }, + { + Name: "EnableWinningPost", + Type: "bool", + + Comment: `EnableWinningPost enables winning post to be executed on this curio instance. +Each machine in the cluster with WinningPoSt enabled will also participate in the winning post scheduler. +It is possible to mix machines with WindowPoSt and WinningPoSt enabled, for details see the EnableWindowPost +documentation.`, + }, + { + Name: "WinningPostMaxTasks", + Type: "int", + + Comment: ``, + }, + { + Name: "EnableParkPiece", + Type: "bool", + + Comment: `EnableParkPiece enables the "piece parking" task to run on this node. This task is responsible for fetching +pieces from the network and storing them in the storage subsystem until sectors are sealed. This task is +only applicable when integrating with boost, and should be enabled on nodes which will hold deal data +from boost until sectors containing the related pieces have the TreeD/TreeR constructed. +Note that future Curio implementations will have a separate task type for fetching pieces from the internet.`, + }, + { + Name: "ParkPieceMaxTasks", + Type: "int", + Comment: ``, }, { - Name: "IpfsOnlineMode", + Name: "EnableSealSDR", Type: "bool", - Comment: ``, + Comment: `EnableSealSDR enables SDR tasks to run. SDR is the long sequential computation +creating 11 layer files in sector cache directory. + +SDR is the first task in the sealing pipeline. It's inputs are just the hash of the +unsealed data (CommD), sector number, miner id, and the seal proof type. +It's outputs are the 11 layer files in the sector cache directory. + +In lotus-miner this was run as part of PreCommit1.`, }, { - Name: "IpfsMAddr", - Type: "string", + Name: "SealSDRMaxTasks", + Type: "int", - Comment: ``, + Comment: `The maximum amount of SDR tasks that can run simultaneously. Note that the maximum number of tasks will +also be bounded by resources available on the machine.`, }, { - Name: "IpfsUseForRetrieval", + Name: "EnableSealSDRTrees", Type: "bool", - Comment: ``, + Comment: `EnableSealSDRTrees enables the SDR pipeline tree-building task to run. +This task handles encoding of unsealed data into last sdr layer and building +of TreeR, TreeC and TreeD. + +This task runs after SDR +TreeD is first computed with optional input of unsealed data +TreeR is computed from replica, which is first computed as field +addition of the last SDR layer and the bottom layer of TreeD (which is the unsealed data) +TreeC is computed from the 11 SDR layers +The 3 trees will later be used to compute the PoRep proof. + +In case of SyntheticPoRep challenges for PoRep will be pre-generated at this step, and trees and layers +will be dropped. SyntheticPoRep works by pre-generating a very large set of challenges (~30GiB on disk) +then using a small subset of them for the actual PoRep computation. This allows for significant scratch space +saving between PreCommit and PoRep generation at the expense of more computation (generating challenges in this step) + +In lotus-miner this was run as part of PreCommit2 (TreeD was run in PreCommit1). +Note that nodes with SDRTrees enabled will also answer to Finalize tasks, +which just remove unneeded tree data after PoRep is computed.`, }, { - Name: "SimultaneousTransfersForStorage", - Type: "uint64", + Name: "SealSDRTreesMaxTasks", + Type: "int", - Comment: `The maximum number of simultaneous data transfers between the client -and storage providers for storage deals`, + Comment: `The maximum amount of SealSDRTrees tasks that can run simultaneously. Note that the maximum number of tasks will +also be bounded by resources available on the machine.`, }, { - Name: "SimultaneousTransfersForRetrieval", - Type: "uint64", + Name: "FinalizeMaxTasks", + Type: "int", - Comment: `The maximum number of simultaneous data transfers between the client -and storage providers for retrieval deals`, + Comment: `FinalizeMaxTasks is the maximum amount of finalize tasks that can run simultaneously. +The finalize task is enabled on all machines which also handle SDRTrees tasks. Finalize ALWAYS runs on whichever +machine holds sector cache files, as it removes unneeded tree data after PoRep is computed. +Finalize will run in parallel with the SubmitCommitMsg task.`, }, { - Name: "OffChainRetrieval", + Name: "EnableSendPrecommitMsg", Type: "bool", - Comment: `Require that retrievals perform no on-chain operations. Paid retrievals -without existing payment channels with available funds will fail instead -of automatically performing on-chain operations.`, + Comment: `EnableSendPrecommitMsg enables the sending of precommit messages to the chain +from this curio instance. +This runs after SDRTrees and uses the output CommD / CommR (roots of TreeD / TreeR) for the message`, }, - }, - "Common": { { - Name: "API", - Type: "API", + Name: "EnablePoRepProof", + Type: "bool", - Comment: ``, + Comment: `EnablePoRepProof enables the computation of the porep proof + +This task runs after interactive-porep seed becomes available, which happens 150 epochs (75min) after the +precommit message lands on chain. This task should run on a machine with a GPU. Vanilla PoRep proofs are +requested from the machine which holds sector cache files which most likely is the machine which ran the SDRTrees +task. + +In lotus-miner this was Commit1 / Commit2`, }, { - Name: "Backup", - Type: "Backup", + Name: "PoRepProofMaxTasks", + Type: "int", - Comment: ``, + Comment: `The maximum amount of PoRepProof tasks that can run simultaneously. Note that the maximum number of tasks will +also be bounded by resources available on the machine.`, }, { - Name: "Logging", - Type: "Logging", + Name: "EnableSendCommitMsg", + Type: "bool", - Comment: ``, + Comment: `EnableSendCommitMsg enables the sending of commit messages to the chain +from this curio instance.`, }, { - Name: "Libp2p", - Type: "Libp2p", + Name: "EnableMoveStorage", + Type: "bool", - Comment: ``, + Comment: `EnableMoveStorage enables the move-into-long-term-storage task to run on this curio instance. +This tasks should only be enabled on nodes with long-term storage. + +The MoveStorage task is the last task in the sealing pipeline. It moves the sealed sector data from the +SDRTrees machine into long-term storage. This task runs after the Finalize task.`, }, { - Name: "Pubsub", - Type: "Pubsub", + Name: "MoveStorageMaxTasks", + Type: "int", - Comment: ``, + Comment: `The maximum amount of MoveStorage tasks that can run simultaneously. Note that the maximum number of tasks will +also be bounded by resources available on the machine. It is recommended that this value is set to a number which +uses all available network (or disk) bandwidth on the machine without causing bottlenecks.`, + }, + { + Name: "BoostAdapters", + Type: "[]string", + + Comment: `BoostAdapters is a list of tuples of miner address and port/ip to listen for market (e.g. boost) requests. +This interface is compatible with the lotus-miner RPC, implementing a subset needed for storage market operations. +Strings should be in the format "actor:port" or "actor:ip:port". Default listen address is 0.0.0.0 +Example: "f0123:32100", "f0123:127.0.0.1:32100". Multiple addresses can be specified. + +When a market node like boost gives Curio's market RPC a deal to placing into a sector, Curio will first store the +deal data in a temporary location "Piece Park" before assigning it to a sector. This requires that at least one +node in the cluster has the EnableParkPiece option enabled and has sufficient scratch space to store the deal data. +This is different from lotus-miner which stored the deal data into an "unsealed" sector as soon as the deal was +received. Deal data in PiecePark is accessed when the sector TreeD and TreeR are computed, but isn't needed for +the initial SDR layers computation. Pieces in PiecePark are removed after all sectors referencing the piece are +sealed. + +To get API info for boost configuration run 'curio market rpc-info' + +NOTE: All deal data will flow through this service, so it should be placed on a machine running boost or on +a machine which handles ParkPiece tasks.`, + }, + { + Name: "EnableWebGui", + Type: "bool", + + Comment: `EnableWebGui enables the web GUI on this curio instance. The UI has minimal local overhead, but it should +only need to be run on a single machine in the cluster.`, + }, + { + Name: "GuiAddress", + Type: "string", + + Comment: `The address that should listen for Web GUI requests.`, }, }, "DAGStoreConfig": { @@ -502,12 +951,6 @@ Set to 0 to keep all mappings`, Comment: ``, }, - { - Name: "Cluster", - Type: "UserRaftConfig", - - Comment: ``, - }, { Name: "Fevm", Type: "FevmConfig", @@ -703,136 +1146,6 @@ closed by the connection manager.`, Comment: `SubsystemLevels specify per-subsystem log levels`, }, }, - "LotusProviderAddresses": { - { - Name: "PreCommitControl", - Type: "[]string", - - Comment: `Addresses to send PreCommit messages from`, - }, - { - Name: "CommitControl", - Type: "[]string", - - Comment: `Addresses to send Commit messages from`, - }, - { - Name: "TerminateControl", - Type: "[]string", - - Comment: ``, - }, - { - Name: "DisableOwnerFallback", - Type: "bool", - - Comment: `DisableOwnerFallback disables usage of the owner address for messages -sent automatically`, - }, - { - Name: "DisableWorkerFallback", - Type: "bool", - - Comment: `DisableWorkerFallback disables usage of the worker address for messages -sent automatically, if control addresses are configured. -A control address that doesn't have enough funds will still be chosen -over the worker address if this flag is set.`, - }, - { - Name: "MinerAddresses", - Type: "[]string", - - Comment: `MinerAddresses are the addresses of the miner actors to use for sending messages`, - }, - }, - "LotusProviderConfig": { - { - Name: "Subsystems", - Type: "ProviderSubsystemsConfig", - - Comment: ``, - }, - { - Name: "Fees", - Type: "LotusProviderFees", - - Comment: ``, - }, - { - Name: "Addresses", - Type: "LotusProviderAddresses", - - Comment: ``, - }, - { - Name: "Proving", - Type: "ProvingConfig", - - Comment: ``, - }, - { - Name: "Journal", - Type: "JournalConfig", - - Comment: ``, - }, - { - Name: "Apis", - Type: "ApisConfig", - - Comment: ``, - }, - }, - "LotusProviderFees": { - { - Name: "DefaultMaxFee", - Type: "types.FIL", - - Comment: ``, - }, - { - Name: "MaxPreCommitGasFee", - Type: "types.FIL", - - Comment: ``, - }, - { - Name: "MaxCommitGasFee", - Type: "types.FIL", - - Comment: ``, - }, - { - Name: "MaxPreCommitBatchGasFee", - Type: "BatchFeeConfig", - - Comment: `maxBatchFee = maxBase + maxPerSector * nSectors`, - }, - { - Name: "MaxCommitBatchGasFee", - Type: "BatchFeeConfig", - - Comment: ``, - }, - { - Name: "MaxTerminateGasFee", - Type: "types.FIL", - - Comment: ``, - }, - { - Name: "MaxWindowPoStGasFee", - Type: "types.FIL", - - Comment: `WindowPoSt is a high-value operation, so the default fee should be high.`, - }, - { - Name: "MaxPublishDealsFee", - Type: "types.FIL", - - Comment: ``, - }, - }, "MinerAddressConfig": { { Name: "PreCommitControl", @@ -1002,32 +1315,6 @@ When disabled and no external block producers are configured, all potential block rewards will be missed!`, }, }, - "ProviderSubsystemsConfig": { - { - Name: "EnableWindowPost", - Type: "bool", - - Comment: ``, - }, - { - Name: "WindowPostMaxTasks", - Type: "int", - - Comment: ``, - }, - { - Name: "EnableWinningPost", - Type: "bool", - - Comment: ``, - }, - { - Name: "WinningPostMaxTasks", - Type: "int", - - Comment: ``, - }, - }, "ProvingConfig": { { Name: "ParallelCheckLimit", @@ -1718,68 +2005,6 @@ HotstoreMaxSpaceTarget - HotstoreMaxSpaceSafetyBuffer`, Comment: ``, }, }, - "UserRaftConfig": { - { - Name: "ClusterModeEnabled", - Type: "bool", - - Comment: `EXPERIMENTAL. config to enabled node cluster with raft consensus`, - }, - { - Name: "DataFolder", - Type: "string", - - Comment: `A folder to store Raft's data.`, - }, - { - Name: "InitPeersetMultiAddr", - Type: "[]string", - - Comment: `InitPeersetMultiAddr provides the list of initial cluster peers for new Raft -peers (with no prior state). It is ignored when Raft was already -initialized or when starting in staging mode.`, - }, - { - Name: "WaitForLeaderTimeout", - Type: "Duration", - - Comment: `LeaderTimeout specifies how long to wait for a leader before -failing an operation.`, - }, - { - Name: "NetworkTimeout", - Type: "Duration", - - Comment: `NetworkTimeout specifies how long before a Raft network -operation is timed out`, - }, - { - Name: "CommitRetries", - Type: "int", - - Comment: `CommitRetries specifies how many times we retry a failed commit until -we give up.`, - }, - { - Name: "CommitRetryDelay", - Type: "Duration", - - Comment: `How long to wait between retries`, - }, - { - Name: "BackupsRotate", - Type: "int", - - Comment: `BackupsRotate specifies the maximum number of Raft's DataFolder -copies that we keep as backups (renaming) after cleanup.`, - }, - { - Name: "Tracing", - Type: "bool", - - Comment: `Tracing enables propagation of contexts across binary boundaries.`, - }, - }, "Wallet": { { Name: "RemoteBackend", diff --git a/node/config/load.go b/node/config/load.go index 354d3b3cb2b..1d5a8745851 100644 --- a/node/config/load.go +++ b/node/config/load.go @@ -4,13 +4,17 @@ import ( "bytes" "fmt" "io" + "math/big" "os" "reflect" "regexp" + "sort" "strings" "unicode" "github.com/BurntSushi/toml" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/kelseyhightower/envconfig" "golang.org/x/xerrors" ) @@ -388,13 +392,28 @@ func ConfigUpdate(cfgCur, cfgDef interface{}, opts ...UpdateCfgOpt) ([]byte, err } // sanity-check that the updated config parses the same way as the current one + if cfgDef != nil { cfgUpdated, err := FromReader(strings.NewReader(nodeStr), cfgDef) if err != nil { return nil, xerrors.Errorf("parsing updated config: %w", err) } - if !reflect.DeepEqual(cfgCur, cfgUpdated) { + opts := []cmp.Option{ + // This equality function compares big.Int + cmpopts.IgnoreUnexported(big.Int{}), + cmp.Comparer(func(x, y []string) bool { + tx, ty := reflect.TypeOf(x), reflect.TypeOf(y) + if tx.Kind() == reflect.Slice && ty.Kind() == reflect.Slice && tx.Elem().Kind() == reflect.String && ty.Elem().Kind() == reflect.String { + sort.Strings(x) + sort.Strings(y) + return strings.Join(x, "\n") == strings.Join(y, "\n") + } + return false + }), + } + + if !cmp.Equal(cfgUpdated, cfgCur, opts...) { return nil, xerrors.Errorf("updated config didn't match current config") } } diff --git a/node/config/load_test.go b/node/config/load_test.go index 2edef259bc6..2eeacb7d5b3 100644 --- a/node/config/load_test.go +++ b/node/config/load_test.go @@ -53,7 +53,7 @@ func TestParitalConfig(t *testing.T) { f, err := os.CreateTemp("", "config-*.toml") fname := f.Name() - assert.NoError(err, "tmp file shold not error") + assert.NoError(err, "tmp file should not error") _, err = f.WriteString(cfgString) assert.NoError(err, "writing to tmp file should not error") err = f.Close() diff --git a/node/config/storage.go b/node/config/storage.go index ac5d57de8b4..a6a8868dd3d 100644 --- a/node/config/storage.go +++ b/node/config/storage.go @@ -8,12 +8,18 @@ import ( "os" "path" + "github.com/mitchellh/go-homedir" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/storage/sealer/storiface" ) func StorageFromFile(path string, def *storiface.StorageConfig) (*storiface.StorageConfig, error) { + path, err := homedir.Expand(path) + if err != nil { + return nil, xerrors.Errorf("expanding storage config path: %w", err) + } + file, err := os.Open(path) switch { case os.IsNotExist(err): @@ -40,6 +46,11 @@ func StorageFromReader(reader io.Reader) (*storiface.StorageConfig, error) { } func WriteStorageFile(filePath string, config storiface.StorageConfig) error { + filePath, err := homedir.Expand(filePath) + if err != nil { + return xerrors.Errorf("expanding storage config path: %w", err) + } + b, err := json.MarshalIndent(config, "", " ") if err != nil { return xerrors.Errorf("marshaling storage config: %w", err) diff --git a/node/config/types.go b/node/config/types.go index ecb946f5dea..c15df320fa9 100644 --- a/node/config/types.go +++ b/node/config/types.go @@ -26,7 +26,6 @@ type FullNode struct { Wallet Wallet Fees FeeConfig Chainstore Chainstore - Cluster UserRaftConfig Fevm FevmConfig Events EventsConfig Index IndexConfig @@ -67,12 +66,15 @@ type StorageMiner struct { HarmonyDB HarmonyDB } -type LotusProviderConfig struct { - Subsystems ProviderSubsystemsConfig +type CurioConfig struct { + Subsystems CurioSubsystemsConfig - Fees LotusProviderFees - Addresses LotusProviderAddresses - Proving ProvingConfig + Fees CurioFees + + // Addresses of wallets per MinerAddress (one of the fields). + Addresses []CurioAddresses + Proving CurioProvingConfig + Ingest CurioIngestConfig Journal JournalConfig Apis ApisConfig } @@ -92,11 +94,138 @@ type JournalConfig struct { DisabledEvents string } -type ProviderSubsystemsConfig struct { - EnableWindowPost bool - WindowPostMaxTasks int +type CurioSubsystemsConfig struct { + // EnableWindowPost enables window post to be executed on this curio instance. Each machine in the cluster + // with WindowPoSt enabled will also participate in the window post scheduler. It is possible to have multiple + // machines with WindowPoSt enabled which will provide redundancy, and in case of multiple partitions per deadline, + // will allow for parallel processing of partitions. + // + // It is possible to have instances handling both WindowPoSt and WinningPoSt, which can provide redundancy without + // the need for additional machines. In setups like this it is generally recommended to run + // partitionsPerDeadline+1 machines. + EnableWindowPost bool + WindowPostMaxTasks int + + // EnableWinningPost enables winning post to be executed on this curio instance. + // Each machine in the cluster with WinningPoSt enabled will also participate in the winning post scheduler. + // It is possible to mix machines with WindowPoSt and WinningPoSt enabled, for details see the EnableWindowPost + // documentation. EnableWinningPost bool WinningPostMaxTasks int + + // EnableParkPiece enables the "piece parking" task to run on this node. This task is responsible for fetching + // pieces from the network and storing them in the storage subsystem until sectors are sealed. This task is + // only applicable when integrating with boost, and should be enabled on nodes which will hold deal data + // from boost until sectors containing the related pieces have the TreeD/TreeR constructed. + // Note that future Curio implementations will have a separate task type for fetching pieces from the internet. + EnableParkPiece bool + ParkPieceMaxTasks int + + // EnableSealSDR enables SDR tasks to run. SDR is the long sequential computation + // creating 11 layer files in sector cache directory. + // + // SDR is the first task in the sealing pipeline. It's inputs are just the hash of the + // unsealed data (CommD), sector number, miner id, and the seal proof type. + // It's outputs are the 11 layer files in the sector cache directory. + // + // In lotus-miner this was run as part of PreCommit1. + EnableSealSDR bool + + // The maximum amount of SDR tasks that can run simultaneously. Note that the maximum number of tasks will + // also be bounded by resources available on the machine. + SealSDRMaxTasks int + + // EnableSealSDRTrees enables the SDR pipeline tree-building task to run. + // This task handles encoding of unsealed data into last sdr layer and building + // of TreeR, TreeC and TreeD. + // + // This task runs after SDR + // TreeD is first computed with optional input of unsealed data + // TreeR is computed from replica, which is first computed as field + // addition of the last SDR layer and the bottom layer of TreeD (which is the unsealed data) + // TreeC is computed from the 11 SDR layers + // The 3 trees will later be used to compute the PoRep proof. + // + // In case of SyntheticPoRep challenges for PoRep will be pre-generated at this step, and trees and layers + // will be dropped. SyntheticPoRep works by pre-generating a very large set of challenges (~30GiB on disk) + // then using a small subset of them for the actual PoRep computation. This allows for significant scratch space + // saving between PreCommit and PoRep generation at the expense of more computation (generating challenges in this step) + // + // In lotus-miner this was run as part of PreCommit2 (TreeD was run in PreCommit1). + // Note that nodes with SDRTrees enabled will also answer to Finalize tasks, + // which just remove unneeded tree data after PoRep is computed. + EnableSealSDRTrees bool + + // The maximum amount of SealSDRTrees tasks that can run simultaneously. Note that the maximum number of tasks will + // also be bounded by resources available on the machine. + SealSDRTreesMaxTasks int + + // FinalizeMaxTasks is the maximum amount of finalize tasks that can run simultaneously. + // The finalize task is enabled on all machines which also handle SDRTrees tasks. Finalize ALWAYS runs on whichever + // machine holds sector cache files, as it removes unneeded tree data after PoRep is computed. + // Finalize will run in parallel with the SubmitCommitMsg task. + FinalizeMaxTasks int + + // EnableSendPrecommitMsg enables the sending of precommit messages to the chain + // from this curio instance. + // This runs after SDRTrees and uses the output CommD / CommR (roots of TreeD / TreeR) for the message + EnableSendPrecommitMsg bool + + // EnablePoRepProof enables the computation of the porep proof + // + // This task runs after interactive-porep seed becomes available, which happens 150 epochs (75min) after the + // precommit message lands on chain. This task should run on a machine with a GPU. Vanilla PoRep proofs are + // requested from the machine which holds sector cache files which most likely is the machine which ran the SDRTrees + // task. + // + // In lotus-miner this was Commit1 / Commit2 + EnablePoRepProof bool + + // The maximum amount of PoRepProof tasks that can run simultaneously. Note that the maximum number of tasks will + // also be bounded by resources available on the machine. + PoRepProofMaxTasks int + + // EnableSendCommitMsg enables the sending of commit messages to the chain + // from this curio instance. + EnableSendCommitMsg bool + + // EnableMoveStorage enables the move-into-long-term-storage task to run on this curio instance. + // This tasks should only be enabled on nodes with long-term storage. + // + // The MoveStorage task is the last task in the sealing pipeline. It moves the sealed sector data from the + // SDRTrees machine into long-term storage. This task runs after the Finalize task. + EnableMoveStorage bool + + // The maximum amount of MoveStorage tasks that can run simultaneously. Note that the maximum number of tasks will + // also be bounded by resources available on the machine. It is recommended that this value is set to a number which + // uses all available network (or disk) bandwidth on the machine without causing bottlenecks. + MoveStorageMaxTasks int + + // BoostAdapters is a list of tuples of miner address and port/ip to listen for market (e.g. boost) requests. + // This interface is compatible with the lotus-miner RPC, implementing a subset needed for storage market operations. + // Strings should be in the format "actor:port" or "actor:ip:port". Default listen address is 0.0.0.0 + // Example: "f0123:32100", "f0123:127.0.0.1:32100". Multiple addresses can be specified. + // + // When a market node like boost gives Curio's market RPC a deal to placing into a sector, Curio will first store the + // deal data in a temporary location "Piece Park" before assigning it to a sector. This requires that at least one + // node in the cluster has the EnableParkPiece option enabled and has sufficient scratch space to store the deal data. + // This is different from lotus-miner which stored the deal data into an "unsealed" sector as soon as the deal was + // received. Deal data in PiecePark is accessed when the sector TreeD and TreeR are computed, but isn't needed for + // the initial SDR layers computation. Pieces in PiecePark are removed after all sectors referencing the piece are + // sealed. + // + // To get API info for boost configuration run 'curio market rpc-info' + // + // NOTE: All deal data will flow through this service, so it should be placed on a machine running boost or on + // a machine which handles ParkPiece tasks. + BoostAdapters []string + + // EnableWebGui enables the web GUI on this curio instance. The UI has minimal local overhead, but it should + // only need to be run on a single machine in the cluster. + EnableWebGui bool + + // The address that should listen for Web GUI requests. + GuiAddress string } type DAGStoreConfig struct { @@ -562,7 +691,7 @@ type MinerFeeConfig struct { MaximizeWindowPoStFeeCap bool } -type LotusProviderFees struct { +type CurioFees struct { DefaultMaxFee types.FIL MaxPreCommitGasFee types.FIL MaxCommitGasFee types.FIL @@ -594,7 +723,7 @@ type MinerAddressConfig struct { DisableWorkerFallback bool } -type LotusProviderAddresses struct { +type CurioAddresses struct { // Addresses to send PreCommit messages from PreCommitControl []string // Addresses to send Commit messages from @@ -614,6 +743,115 @@ type LotusProviderAddresses struct { MinerAddresses []string } +type CurioProvingConfig struct { + // Maximum number of sector checks to run in parallel. (0 = unlimited) + // + // WARNING: Setting this value too high may make the node crash by running out of stack + // WARNING: Setting this value too low may make sector challenge reading much slower, resulting in failed PoSt due + // to late submission. + // + // After changing this option, confirm that the new value works in your setup by invoking + // 'lotus-miner proving compute window-post 0' + ParallelCheckLimit int + + // Maximum amount of time a proving pre-check can take for a sector. If the check times out the sector will be skipped + // + // WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the + // test challenge took longer than this timeout + // WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this sector are + // blocked (e.g. in case of disconnected NFS mount) + SingleCheckTimeout Duration + + // Maximum amount of time a proving pre-check can take for an entire partition. If the check times out, sectors in + // the partition which didn't get checked on time will be skipped + // + // WARNING: Setting this value too low risks in sectors being skipped even though they are accessible, just reading the + // test challenge took longer than this timeout + // WARNING: Setting this value too high risks missing PoSt deadline in case IO operations related to this partition are + // blocked or slow + PartitionCheckTimeout Duration + + // Disable WindowPoSt provable sector readability checks. + // + // In normal operation, when preparing to compute WindowPoSt, lotus-miner will perform a round of reading challenges + // from all sectors to confirm that those sectors can be proven. Challenges read in this process are discarded, as + // we're only interested in checking that sector data can be read. + // + // When using builtin proof computation (no PoSt workers, and DisableBuiltinWindowPoSt is set to false), this process + // can save a lot of time and compute resources in the case that some sectors are not readable - this is caused by + // the builtin logic not skipping snark computation when some sectors need to be skipped. + // + // When using PoSt workers, this process is mostly redundant, with PoSt workers challenges will be read once, and + // if challenges for some sectors aren't readable, those sectors will just get skipped. + // + // Disabling sector pre-checks will slightly reduce IO load when proving sectors, possibly resulting in shorter + // time to produce window PoSt. In setups with good IO capabilities the effect of this option on proving time should + // be negligible. + // + // NOTE: It likely is a bad idea to disable sector pre-checks in setups with no PoSt workers. + // + // NOTE: Even when this option is enabled, recovering sectors will be checked before recovery declaration message is + // sent to the chain + // + // After changing this option, confirm that the new value works in your setup by invoking + // 'lotus-miner proving compute window-post 0' + DisableWDPoStPreChecks bool + + // Maximum number of partitions to prove in a single SubmitWindowPoSt messace. 0 = network limit (3 in nv21) + // + // A single partition may contain up to 2349 32GiB sectors, or 2300 64GiB sectors. + // // + // Note that setting this value lower may result in less efficient gas use - more messages will be sent, + // to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) + // + // Setting this value above the network limit has no effect + MaxPartitionsPerPoStMessage int + + // Maximum number of partitions to declare in a single DeclareFaultsRecovered message. 0 = no limit. + + // In some cases when submitting DeclareFaultsRecovered messages, + // there may be too many recoveries to fit in a BlockGasLimit. + // In those cases it may be necessary to set this value to something low (eg 1); + // Note that setting this value lower may result in less efficient gas use - more messages will be sent than needed, + // resulting in more total gas use (but each message will have lower gas limit) + MaxPartitionsPerRecoveryMessage int + + // Enable single partition per PoSt Message for partitions containing recovery sectors + // + // In cases when submitting PoSt messages which contain recovering sectors, the default network limit may still be + // too high to fit in the block gas limit. In those cases, it becomes useful to only house the single partition + // with recovering sectors in the post message + // + // Note that setting this value lower may result in less efficient gas use - more messages will be sent, + // to prove each deadline, resulting in more total gas use (but each message will have lower gas limit) + SingleRecoveringPartitionPerPostMessage bool +} + +type CurioIngestConfig struct { + // Maximum number of sectors that can be queued waiting for SDR to start processing. + // 0 = unlimited + // Note: This mechanism will delay taking deal data from markets, providing backpressure to the market subsystem. + // The SDR queue includes deals which are in the process of entering the sealing pipeline - size of this queue + // will also impact the maximum number of ParkPiece tasks which can run concurrently. + // + // SDR queue is the first queue in the sealing pipeline, meaning that it should be used as the primary backpressure mechanism. + MaxQueueSDR int + + // Maximum number of sectors that can be queued waiting for SDRTrees to start processing. + // 0 = unlimited + // Note: This mechanism will delay taking deal data from markets, providing backpressure to the market subsystem. + // In case of the trees tasks it is possible that this queue grows more than this limit, the backpressure is only + // applied to sectors entering the pipeline. + MaxQueueTrees int + + // Maximum number of sectors that can be queued waiting for PoRep to start processing. + // 0 = unlimited + // Note: This mechanism will delay taking deal data from markets, providing backpressure to the market subsystem. + // Like with the trees tasks, it is possible that this queue grows more than this limit, the backpressure is only + // applied to sectors entering the pipeline. + MaxQueuePoRep int +} + // API contains configs for API endpoint type API struct { // Binding address for the Lotus API @@ -728,10 +966,6 @@ type Splitstore struct { // // Full Node type Client struct { - UseIpfs bool - IpfsOnlineMode bool - IpfsMAddr string - IpfsUseForRetrieval bool // The maximum number of simultaneous data transfers between the client // and storage providers for storage deals SimultaneousTransfersForStorage uint64 @@ -755,33 +989,6 @@ type FeeConfig struct { DefaultMaxFee types.FIL } -type UserRaftConfig struct { - // EXPERIMENTAL. config to enabled node cluster with raft consensus - ClusterModeEnabled bool - // A folder to store Raft's data. - DataFolder string - // InitPeersetMultiAddr provides the list of initial cluster peers for new Raft - // peers (with no prior state). It is ignored when Raft was already - // initialized or when starting in staging mode. - InitPeersetMultiAddr []string - // LeaderTimeout specifies how long to wait for a leader before - // failing an operation. - WaitForLeaderTimeout Duration - // NetworkTimeout specifies how long before a Raft network - // operation is timed out - NetworkTimeout Duration - // CommitRetries specifies how many times we retry a failed commit until - // we give up. - CommitRetries int - // How long to wait between retries - CommitRetryDelay Duration - // BackupsRotate specifies the maximum number of Raft's DataFolder - // copies that we keep as backups (renaming) after cleanup. - BackupsRotate int - // 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. diff --git a/node/health.go b/node/health.go index 1be11921c0c..90ba38378ac 100644 --- a/node/health.go +++ b/node/health.go @@ -48,7 +48,7 @@ func NewLiveHandler(api lapi.FullNode) *HealthHandler { var ( countdown int32 headCh <-chan []*lapi.HeadChange - backoff time.Duration = minbackoff + backoff = minbackoff err error ) minutely := time.NewTicker(time.Minute) @@ -66,10 +66,9 @@ func NewLiveHandler(api lapi.FullNode) *HealthHandler { } backoff = nextbackoff continue - } else { - healthlog.Infof("started ChainNotify channel") - backoff = minbackoff } + healthlog.Infof("started ChainNotify channel") + backoff = minbackoff } select { case <-minutely.C: diff --git a/node/hello/hello.go b/node/hello/hello.go index e05b8a48287..cd1645d3e1a 100644 --- a/node/hello/hello.go +++ b/node/hello/hello.go @@ -29,6 +29,7 @@ import ( const ProtocolID = "/fil/hello/1.0.0" var log = logging.Logger("hello") +var streamDeadline = 10 * time.Second type HelloMessage struct { HeaviestTipSet []cid.Cid @@ -70,11 +71,15 @@ func NewHelloService(h host.Host, cs *store.ChainStore, syncer *chain.Syncer, co func (hs *Service) HandleStream(s inet.Stream) { var hmsg HelloMessage + _ = s.SetReadDeadline(time.Now().Add(streamDeadline)) if err := cborutil.ReadCborRPC(s, &hmsg); err != nil { + _ = s.SetReadDeadline(time.Time{}) log.Infow("failed to read hello message, disconnecting", "error", err) _ = s.Conn().Close() return } + _ = s.SetReadDeadline(time.Time{}) + arrived := build.Clock.Now() log.Debugw("genesis from hello", @@ -95,9 +100,11 @@ func (hs *Service) HandleStream(s inet.Stream) { TArrival: arrived.UnixNano(), TSent: sent.UnixNano(), } + _ = s.SetWriteDeadline(time.Now().Add(streamDeadline)) if err := cborutil.WriteCborRPC(s, msg); err != nil { log.Debugf("error while responding to latency: %v", err) } + _ = s.SetWriteDeadline(time.Time{}) }() protos, err := hs.h.Peerstore().GetProtocols(s.Conn().RemotePeer()) @@ -155,9 +162,12 @@ func (hs *Service) SayHello(ctx context.Context, pid peer.ID) error { log.Debug("Sending hello message: ", hts.Cids(), hts.Height(), gen.Cid()) t0 := build.Clock.Now() + _ = s.SetWriteDeadline(time.Now().Add(streamDeadline)) if err := cborutil.WriteCborRPC(s, hmsg); err != nil { + _ = s.SetWriteDeadline(time.Time{}) return xerrors.Errorf("writing rpc to peer: %w", err) } + _ = s.SetWriteDeadline(time.Time{}) if err := s.CloseWrite(); err != nil { log.Warnw("CloseWrite err", "error", err) } diff --git a/node/impl/full.go b/node/impl/full.go index 5343bcf0de6..527a5538436 100644 --- a/node/impl/full.go +++ b/node/impl/full.go @@ -34,7 +34,6 @@ type FullNodeAPI struct { full.MsigAPI full.WalletAPI full.SyncAPI - full.RaftAPI full.EthAPI full.ActorEventsAPI @@ -120,12 +119,4 @@ func (n *FullNodeAPI) NodeStatus(ctx context.Context, inclChainStatus bool) (sta return status, nil } -func (n *FullNodeAPI) RaftState(ctx context.Context) (*api.RaftStateData, error) { - return n.RaftAPI.GetRaftState(ctx) -} - -func (n *FullNodeAPI) RaftLeader(ctx context.Context) (peer.ID, error) { - return n.RaftAPI.Leader(ctx) -} - var _ api.FullNode = &FullNodeAPI{} diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 1d6b8e566fa..ce677978028 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -644,8 +644,8 @@ func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, skipo bw := bufio.NewWriterSize(w, 1<<20) err := a.Chain.Export(ctx, ts, nroots, skipoldmsgs, bw) - bw.Flush() //nolint:errcheck // it is a write to a pipe - w.CloseWithError(err) //nolint:errcheck // it is a pipe + _ = bw.Flush() // it is a write to a pipe + _ = w.CloseWithError(err) // it is a pipe }() go func() { diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go index 9685898c0a5..1c191afba09 100644 --- a/node/impl/full/dummy.go +++ b/node/impl/full/dummy.go @@ -190,7 +190,7 @@ func (e *EthModuleDummy) EthTraceReplayBlockTransactions(ctx context.Context, bl var _ EthModuleAPI = &EthModuleDummy{} var _ EthEventAPI = &EthModuleDummy{} -var ErrActorEventModuleDisabled = errors.New("module disabled, enable with Fevm.EnableActorEventsAPI") +var ErrActorEventModuleDisabled = errors.New("module disabled, enable with Events.EnableActorEventsAPI") type ActorEventDummy struct{} diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 5c3fcac960d..e7aeafa9085 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -424,15 +424,7 @@ func (a *EthModule) EthGetTransactionReceiptLimited(ctx context.Context, txHash return nil, xerrors.Errorf("failed to convert %s into an Eth Txn: %w", txHash, err) } - var events []types.Event - if rct := msgLookup.Receipt; rct.EventsRoot != nil { - events, err = a.ChainAPI.ChainGetEvents(ctx, *rct.EventsRoot) - if err != nil { - return nil, xerrors.Errorf("failed get events for %s", txHash) - } - } - - receipt, err := newEthTxReceipt(ctx, tx, msgLookup, events, a.Chain, a.StateAPI) + receipt, err := newEthTxReceipt(ctx, tx, msgLookup, a.ChainAPI, a.StateAPI) if err != nil { return nil, xerrors.Errorf("failed to convert %s into an Eth Receipt: %w", txHash, err) } diff --git a/node/impl/full/eth_events.go b/node/impl/full/eth_events.go index 81ecef64bfa..7baba1e81e1 100644 --- a/node/impl/full/eth_events.go +++ b/node/impl/full/eth_events.go @@ -121,6 +121,10 @@ func ethFilterResultFromEvents(ctx context.Context, evs []*filter.CollectedEvent if err != nil { return nil, err } + if log.TransactionHash == ethtypes.EmptyEthHash { + // We've garbage collected the message, ignore the events and continue. + continue + } c, err := ev.TipSetKey.Cid() if err != nil { return nil, err @@ -250,6 +254,8 @@ type ethSubscription struct { sendQueueLen int toSend *queue.Queue[[]byte] sendCond chan struct{} + + lastSentTipset *types.TipSetKey } func (e *ethSubscription) addFilter(ctx context.Context, f filter.Filter) { @@ -337,12 +343,27 @@ func (e *ethSubscription) start(ctx context.Context) { e.send(ctx, r) } case *types.TipSet: - ev, err := newEthBlockFromFilecoinTipSet(ctx, vt, true, e.Chain, e.StateAPI) - if err != nil { - break + // Skip processing for tipset at epoch 0 as it has no parent + if vt.Height() == 0 { + continue + } + // Check if the parent has already been processed + parentTipSetKey := vt.Parents() + if e.lastSentTipset != nil && (*e.lastSentTipset) == parentTipSetKey { + continue + } + parentTipSet, loadErr := e.Chain.LoadTipSet(ctx, parentTipSetKey) + if loadErr != nil { + log.Warnw("failed to load parent tipset", "tipset", parentTipSetKey, "error", loadErr) + continue + } + ethBlock, ethBlockErr := newEthBlockFromFilecoinTipSet(ctx, parentTipSet, true, e.Chain, e.StateAPI) + if ethBlockErr != nil { + continue } - e.send(ctx, ev) + e.send(ctx, ethBlock) + e.lastSentTipset = &parentTipSetKey case *types.SignedMessage: // mpool txid evs, err := ethFilterResultFromMessages([]*types.SignedMessage{vt}) if err != nil { diff --git a/node/impl/full/eth_utils.go b/node/impl/full/eth_utils.go index 04e8e497086..a4b1c66bb84 100644 --- a/node/impl/full/eth_utils.go +++ b/node/impl/full/eth_utils.go @@ -22,6 +22,7 @@ import ( "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/actors/builtin" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -91,9 +92,8 @@ func getTipsetByEthBlockNumberOrHash(ctx context.Context, chain *store.ChainStor return nil, fmt.Errorf("cannot get parent tipset") } return parent, nil - } else { - return nil, fmt.Errorf("unknown predefined block %s", *predefined) } + return nil, fmt.Errorf("unknown predefined block %s", *predefined) } if blkParam.BlockNumber != nil { @@ -224,7 +224,7 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx return ethtypes.EthBlock{}, xerrors.Errorf("failed to load state-tree root %q: %w", stRoot, err) } - block := ethtypes.NewEthBlock(len(msgs) > 0) + block := ethtypes.NewEthBlock(len(msgs) > 0, len(ts.Blocks())) gasUsed := int64(0) for i, msg := range msgs { @@ -297,7 +297,7 @@ func executeTipset(ctx context.Context, ts *types.TipSet, cs *store.ChainStore, 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{ +var panicErrorCodes = map[uint64]string{ 0x00: "Panic()", 0x01: "Assert()", 0x11: "ArithmeticOverflow()", @@ -391,11 +391,13 @@ func lookupEthAddress(addr address.Address, st *state.StateTree) (ethtypes.EthAd } // Otherwise, resolve the ID addr. - idAddr, err := st.LookupID(addr) + idAddr, err := st.LookupIDAddress(addr) if err != nil { return ethtypes.EthAddress{}, err } + // revive:disable:empty-block easier to grok when the cases are explicit + // Lookup on the target actor and try to get an f410 address. if actor, err := st.GetActor(idAddr); errors.Is(err, types.ErrActorNotFound) { // Not found -> use a masked ID address @@ -455,9 +457,9 @@ func ethTxHashFromSignedMessage(smsg *types.SignedMessage) (ethtypes.EthHash, er return tx.TxHash() } else if smsg.Signature.Type == crypto.SigTypeSecp256k1 { return ethtypes.EthHashFromCid(smsg.Cid()) - } else { // BLS message - return ethtypes.EthHashFromCid(smsg.Message.Cid()) } + // else BLS message + return ethtypes.EthHashFromCid(smsg.Message.Cid()) } func newEthTxFromSignedMessage(smsg *types.SignedMessage, st *state.StateTree) (ethtypes.EthTx, error) { @@ -525,9 +527,6 @@ func ethTxFromNativeMessage(msg *types.Message, st *state.StateTree) (ethtypes.E } to = revertedEthAddress } - toPtr := &to - - // Finally, convert the input parameters to "solidity ABI". // For empty, we use "0" as the codec. Otherwise, we use CBOR for message // parameters. @@ -536,31 +535,11 @@ func ethTxFromNativeMessage(msg *types.Message, st *state.StateTree) (ethtypes.E codec = uint64(multicodec.Cbor) } - // We try to decode the input as an EVM method invocation and/or a contract creation. If - // that fails, we encode the "native" parameters as Solidity ABI. - var input []byte - switch msg.Method { - case builtintypes.MethodsEVM.InvokeContract, builtintypes.MethodsEAM.CreateExternal: - inp, err := decodePayload(msg.Params, codec) - if err == nil { - // If this is a valid "create external", unset the "to" address. - if msg.Method == builtintypes.MethodsEAM.CreateExternal { - toPtr = nil - } - input = []byte(inp) - break - } - // Yeah, we're going to ignore errors here because the user can send whatever they - // want and may send garbage. - fallthrough - default: - input = encodeFilecoinParamsAsABI(msg.Method, codec, msg.Params) - } - - return ethtypes.EthTx{ - To: toPtr, + // We decode as a native call first. + ethTx := ethtypes.EthTx{ + To: &to, From: from, - Input: input, + Input: encodeFilecoinParamsAsABI(msg.Method, codec, msg.Params), Nonce: ethtypes.EthUint64(msg.Nonce), ChainID: ethtypes.EthUint64(build.Eip155ChainId), Value: ethtypes.EthBigInt(msg.Value), @@ -569,7 +548,25 @@ func ethTxFromNativeMessage(msg *types.Message, st *state.StateTree) (ethtypes.E MaxFeePerGas: ethtypes.EthBigInt(msg.GasFeeCap), MaxPriorityFeePerGas: ethtypes.EthBigInt(msg.GasPremium), AccessList: []ethtypes.EthHash{}, - }, nil + } + + // Then we try to see if it's "special". If we fail, we ignore the error and keep treating + // it as a native message. Unfortunately, the user is free to send garbage that may not + // properly decode. + if msg.Method == builtintypes.MethodsEVM.InvokeContract { + // try to decode it as a contract invocation first. + if inp, err := decodePayload(msg.Params, codec); err == nil { + ethTx.Input = []byte(inp) + } + } else if msg.To == builtin.EthereumAddressManagerActorAddr && msg.Method == builtintypes.MethodsEAM.CreateExternal { + // Then, try to decode it as a contract deployment from an EOA. + if inp, err := decodePayload(msg.Params, codec); err == nil { + ethTx.Input = []byte(inp) + ethTx.To = nil + } + } + + return ethTx, nil } func getSignedMessage(ctx context.Context, cs *store.ChainStore, msgCid cid.Cid) (*types.SignedMessage, error) { @@ -659,7 +656,7 @@ func newEthTxFromMessageLookup(ctx context.Context, msgLookup *api.MsgLookup, tx return tx, nil } -func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLookup, events []types.Event, cs *store.ChainStore, sa StateAPI) (api.EthTxReceipt, error) { +func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLookup, ca ChainAPI, sa StateAPI) (api.EthTxReceipt, error) { var ( transactionIndex ethtypes.EthUint64 blockHash ethtypes.EthHash @@ -700,7 +697,7 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook receipt.CumulativeGasUsed = ethtypes.EmptyEthInt // TODO: avoid loading the tipset twice (once here, once when we convert the message to a txn) - ts, err := cs.GetTipSetFromKey(ctx, lookup.TipSet) + ts, err := ca.Chain.GetTipSetFromKey(ctx, lookup.TipSet) if err != nil { return api.EthTxReceipt{}, xerrors.Errorf("failed to lookup tipset %s when constructing the eth txn receipt: %w", lookup.TipSet, err) } @@ -711,7 +708,7 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook } // The tx is located in the parent tipset - parentTs, err := cs.LoadTipSet(ctx, ts.Parents()) + parentTs, err := ca.Chain.LoadTipSet(ctx, ts.Parents()) if err != nil { return api.EthTxReceipt{}, xerrors.Errorf("failed to lookup tipset %s when constructing the eth txn receipt: %w", ts.Parents(), err) } @@ -736,6 +733,24 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook receipt.ContractAddress = &addr } + var events []types.Event + if rct := lookup.Receipt; rct.EventsRoot != nil { + events, err = ca.ChainGetEvents(ctx, *rct.EventsRoot) + if err != nil { + // Fore-recompute, we must have enabled the Event APIs after computing this + // tipset. + if _, _, err := sa.StateManager.RecomputeTipSetState(ctx, ts); err != nil { + + return api.EthTxReceipt{}, xerrors.Errorf("failed get events: %w", err) + } + // Try again + events, err = ca.ChainGetEvents(ctx, *rct.EventsRoot) + if err != nil { + return api.EthTxReceipt{}, xerrors.Errorf("failed get events: %w", err) + } + } + } + if len(events) > 0 { receipt.Logs = make([]ethtypes.EthLog, 0, len(events)) for i, evt := range events { @@ -803,8 +818,8 @@ func encodeAsABIHelper(param1 uint64, param2 uint64, data []byte) []byte { if len(data)%EVM_WORD_SIZE != 0 { totalWords++ } - len := totalWords * EVM_WORD_SIZE - buf := make([]byte, len) + sz := totalWords * EVM_WORD_SIZE + buf := make([]byte, sz) offset := 0 // Below, we use copy instead of "appending" to preserve all the zero padding. for _, arg := range staticArgs { diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index addcc41be43..fac48a3508f 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -44,8 +44,6 @@ type MpoolAPI struct { WalletAPI GasAPI - RaftAPI - MessageSigner messagesigner.MsgSigner PushLocks *dtypes.MpoolLocker @@ -145,20 +143,6 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spe msg = &cp inMsg := *msg - // Redirect to leader if current node is not leader. A single non raft based node is always the leader - if !a.RaftAPI.IsLeader(ctx) { - var signedMsg types.SignedMessage - redirected, err := a.RaftAPI.RedirectToLeader(ctx, "MpoolPushMessage", api.MpoolMessageWhole{Msg: msg, Spec: spec}, &signedMsg) - if err != nil { - return nil, err - } - // It's possible that the current node became the leader between the check and the redirect - // In that case, continue with rest of execution and only return signedMsg if something was redirected - if redirected { - return &signedMsg, nil - } - } - // Generate spec and uuid if not available in the message if spec == nil { spec = &api.MessageSendSpec{ diff --git a/node/impl/full/raft.go b/node/impl/full/raft.go deleted file mode 100644 index 8d665ddd502..00000000000 --- a/node/impl/full/raft.go +++ /dev/null @@ -1,50 +0,0 @@ -package full - -import ( - "context" - - "github.com/libp2p/go-libp2p/core/peer" - "go.uber.org/fx" - "golang.org/x/xerrors" - - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/messagesigner" -) - -type RaftAPI struct { - fx.In - - MessageSigner *messagesigner.MessageSignerConsensus `optional:"true"` -} - -func (r *RaftAPI) GetRaftState(ctx context.Context) (*api.RaftStateData, error) { - if r.MessageSigner == nil { - return nil, xerrors.Errorf("raft consensus not enabled. Please check your configuration") - } - raftState, err := r.MessageSigner.GetRaftState(ctx) - if err != nil { - return nil, err - } - return &api.RaftStateData{NonceMap: raftState.NonceMap, MsgUuids: raftState.MsgUuids}, nil -} - -func (r *RaftAPI) Leader(ctx context.Context) (peer.ID, error) { - if r.MessageSigner == nil { - return "", xerrors.Errorf("raft consensus not enabled. Please check your configuration") - } - return r.MessageSigner.Leader(ctx) -} - -func (r *RaftAPI) IsLeader(ctx context.Context) bool { - if r.MessageSigner == nil { - return true - } - return r.MessageSigner.IsLeader(ctx) -} - -func (r *RaftAPI) RedirectToLeader(ctx context.Context, method string, arg interface{}, ret interface{}) (bool, error) { - if r.MessageSigner == nil { - return false, xerrors.Errorf("raft consensus not enabled. Please check your configuration") - } - return r.MessageSigner.RedirectToLeader(ctx, method, arg, ret) -} diff --git a/node/impl/full/state.go b/node/impl/full/state.go index dda8898325f..6a4f6d5537e 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -486,7 +486,7 @@ func (m *StateModule) StateLookupID(ctx context.Context, addr address.Address, t return address.Undef, xerrors.Errorf("loading tipset %s: %w", tsk, err) } - ret, err := m.StateManager.LookupID(ctx, addr, ts) + ret, err := m.StateManager.LookupIDAddress(ctx, addr, ts) if err != nil && xerrors.Is(err, types.ErrActorNotFound) { return address.Undef, &api.ErrActorNotFound{} } @@ -965,9 +965,8 @@ func (a *StateAPI) StateComputeDataCID(ctx context.Context, maddr address.Addres return a.stateComputeDataCIDv1(ctx, maddr, sectorType, deals, tsk) } else if nv < network.Version21 { return a.stateComputeDataCIDv2(ctx, maddr, sectorType, deals, tsk) - } else { - return a.stateComputeDataCIDv3(ctx, maddr, sectorType, deals, tsk) } + return a.stateComputeDataCIDv3(ctx, maddr, sectorType, deals, tsk) } func (a *StateAPI) stateComputeDataCIDv1(ctx context.Context, maddr address.Address, sectorType abi.RegisteredSealProof, deals []abi.DealID, tsk types.TipSetKey) (cid.Cid, error) { diff --git a/node/impl/net/net.go b/node/impl/net/net.go index 5341092ce28..7e9a3f8655f 100644 --- a/node/impl/net/net.go +++ b/node/impl/net/net.go @@ -11,7 +11,7 @@ import ( "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" - basichost "github.com/libp2p/go-libp2p/p2p/host/basic" + "github.com/libp2p/go-libp2p/p2p/host/autonat" "github.com/libp2p/go-libp2p/p2p/net/conngater" "github.com/libp2p/go-libp2p/p2p/net/swarm" "github.com/libp2p/go-libp2p/p2p/protocol/ping" @@ -135,8 +135,12 @@ func (a *NetAPI) NetFindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, err return a.Router.FindPeer(ctx, p) } +type autoNatGetter interface { + GetAutoNat() autonat.AutoNAT +} + func (a *NetAPI) NetAutoNatStatus(context.Context) (i api.NatInfo, err error) { - autonat := a.RawHost.(*basichost.BasicHost).GetAutoNat() + autonat := a.RawHost.(autoNatGetter).GetAutoNat() if autonat == nil { return api.NatInfo{ diff --git a/node/impl/storminer.go b/node/impl/storminer.go index 90248a355a4..bd482494017 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -1377,15 +1377,15 @@ func (sm *StorageMinerAPI) RuntimeSubsystems(context.Context) (res api.MinerSubs } func (sm *StorageMinerAPI) ActorWithdrawBalance(ctx context.Context, amount abi.TokenAmount) (cid.Cid, error) { - return sm.withdrawBalance(ctx, amount, true) + return WithdrawBalance(ctx, sm.Full, sm.Miner.Address(), amount, true) } func (sm *StorageMinerAPI) BeneficiaryWithdrawBalance(ctx context.Context, amount abi.TokenAmount) (cid.Cid, error) { - return sm.withdrawBalance(ctx, amount, false) + return WithdrawBalance(ctx, sm.Full, sm.Miner.Address(), amount, false) } -func (sm *StorageMinerAPI) withdrawBalance(ctx context.Context, amount abi.TokenAmount, fromOwner bool) (cid.Cid, error) { - available, err := sm.Full.StateMinerAvailableBalance(ctx, sm.Miner.Address(), types.EmptyTSK) +func WithdrawBalance(ctx context.Context, full api.FullNode, maddr address.Address, amount abi.TokenAmount, fromOwner bool) (cid.Cid, error) { + available, err := full.StateMinerAvailableBalance(ctx, maddr, types.EmptyTSK) if err != nil { return cid.Undef, xerrors.Errorf("Error getting miner balance: %w", err) } @@ -1405,7 +1405,7 @@ func (sm *StorageMinerAPI) withdrawBalance(ctx context.Context, amount abi.Token return cid.Undef, err } - mi, err := sm.Full.StateMinerInfo(ctx, sm.Miner.Address(), types.EmptyTSK) + mi, err := full.StateMinerInfo(ctx, maddr, types.EmptyTSK) if err != nil { return cid.Undef, xerrors.Errorf("Error getting miner's owner address: %w", err) } @@ -1417,8 +1417,8 @@ func (sm *StorageMinerAPI) withdrawBalance(ctx context.Context, amount abi.Token sender = mi.Beneficiary } - smsg, err := sm.Full.MpoolPushMessage(ctx, &types.Message{ - To: sm.Miner.Address(), + smsg, err := full.MpoolPushMessage(ctx, &types.Message{ + To: maddr, From: sender, Value: types.NewInt(0), Method: builtintypes.MethodsMiner.WithdrawBalance, diff --git a/node/modules/actorevent.go b/node/modules/actorevent.go index d92da1940a9..78ac5b18b84 100644 --- a/node/modules/actorevent.go +++ b/node/modules/actorevent.go @@ -6,6 +6,7 @@ import ( "time" "go.uber.org/fx" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" @@ -105,7 +106,7 @@ func EventFilterManager(cfg config.EventsConfig) func(helpers.MetricsCtx, repo.L if cfg.DatabasePath == "" { sqlitePath, err := r.SqlitePath() if err != nil { - return nil, err + return nil, xerrors.Errorf("failed to resolve event index database path: %w", err) } dbPath = filepath.Join(sqlitePath, "events.db") } else { @@ -115,7 +116,7 @@ func EventFilterManager(cfg config.EventsConfig) func(helpers.MetricsCtx, repo.L var err error eventIndex, err = filter.NewEventIndex(ctx, dbPath, chainapi.Chain) if err != nil { - return nil, err + return nil, xerrors.Errorf("failed to initialize event index database: %w", err) } lc.Append(fx.Hook{ diff --git a/node/modules/ipfs.go b/node/modules/ipfs.go deleted file mode 100644 index cb9deb6fde1..00000000000 --- a/node/modules/ipfs.go +++ /dev/null @@ -1,50 +0,0 @@ -package modules - -import ( - bstore "github.com/ipfs/boxo/blockstore" - "github.com/multiformats/go-multiaddr" - "go.uber.org/fx" - "golang.org/x/xerrors" - - "github.com/filecoin-project/go-fil-markets/retrievalmarket" - "github.com/filecoin-project/go-fil-markets/storagemarket" - - "github.com/filecoin-project/lotus/blockstore" - "github.com/filecoin-project/lotus/markets/retrievaladapter" - "github.com/filecoin-project/lotus/markets/storageadapter" - "github.com/filecoin-project/lotus/node/modules/dtypes" - "github.com/filecoin-project/lotus/node/modules/helpers" -) - -func IpfsStorageBlockstoreAccessor(ipfsBlockstore dtypes.ClientBlockstore) storagemarket.BlockstoreAccessor { - return storageadapter.NewFixedBlockstoreAccessor(bstore.Blockstore(ipfsBlockstore)) -} - -func IpfsRetrievalBlockstoreAccessor(ipfsBlockstore dtypes.ClientBlockstore) retrievalmarket.BlockstoreAccessor { - return retrievaladapter.NewFixedBlockstoreAccessor(bstore.Blockstore(ipfsBlockstore)) -} - -// IpfsClientBlockstore returns a ClientBlockstore implementation backed by an IPFS node. -// If ipfsMaddr is empty, a local IPFS node is assumed considering IPFS_PATH configuration. -// If ipfsMaddr is not empty, it will connect to the remote IPFS node with the provided multiaddress. -// The flag useForRetrieval indicates if the IPFS node will also be used for storing retrieving deals. -func IpfsClientBlockstore(ipfsMaddr string, onlineMode bool) func(helpers.MetricsCtx, fx.Lifecycle, dtypes.ClientImportMgr) (dtypes.ClientBlockstore, error) { - return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, localStore dtypes.ClientImportMgr) (dtypes.ClientBlockstore, error) { - var err error - var ipfsbs blockstore.BasicBlockstore - if ipfsMaddr != "" { - var ma multiaddr.Multiaddr - ma, err = multiaddr.NewMultiaddr(ipfsMaddr) - if err != nil { - return nil, xerrors.Errorf("parsing ipfs multiaddr: %w", err) - } - ipfsbs, err = blockstore.NewRemoteIPFSBlockstore(helpers.LifecycleCtx(mctx, lc), ma, onlineMode) - } else { - ipfsbs, err = blockstore.NewLocalIPFSBlockstore(helpers.LifecycleCtx(mctx, lc), onlineMode) - } - if err != nil { - return nil, xerrors.Errorf("constructing ipfs blockstore: %w", err) - } - return blockstore.WrapIDStore(ipfsbs), nil - } -} diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index 2b3efce6c44..408ab17a63e 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -594,7 +594,7 @@ func (trw *tracerWrapper) Trace(evt *pubsub_pb.TraceEvent) { msgsRPC := evt.GetRecvRPC().GetMeta().GetMessages() // check if any of the messages we are sending belong to a trackable topic - var validTopic bool = false + var validTopic = false for _, topic := range msgsRPC { if trw.traceMessage(topic.GetTopic()) { validTopic = true @@ -602,7 +602,7 @@ func (trw *tracerWrapper) Trace(evt *pubsub_pb.TraceEvent) { } } // track if the Iwant / Ihave messages are from a valid Topic - var validIhave bool = false + var validIhave = false for _, msgs := range ihave { if trw.traceMessage(msgs.GetTopic()) { validIhave = true @@ -630,7 +630,7 @@ func (trw *tracerWrapper) Trace(evt *pubsub_pb.TraceEvent) { msgsRPC := evt.GetSendRPC().GetMeta().GetMessages() // check if any of the messages we are sending belong to a trackable topic - var validTopic bool = false + var validTopic = false for _, topic := range msgsRPC { if trw.traceMessage(topic.GetTopic()) { validTopic = true @@ -638,7 +638,7 @@ func (trw *tracerWrapper) Trace(evt *pubsub_pb.TraceEvent) { } } // track if the Iwant / Ihave messages are from a valid Topic - var validIhave bool = false + var validIhave = false for _, msgs := range ihave { if trw.traceMessage(msgs.GetTopic()) { validIhave = true diff --git a/node/modules/lp2p/rcmgr.go b/node/modules/lp2p/rcmgr.go index f2b2849863e..75a09068cc7 100644 --- a/node/modules/lp2p/rcmgr.go +++ b/node/modules/lp2p/rcmgr.go @@ -15,19 +15,22 @@ import ( "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager" + ma "github.com/multiformats/go-multiaddr" + madns "github.com/multiformats/go-multiaddr-dns" "github.com/prometheus/client_golang/prometheus" "go.opencensus.io/stats" "go.opencensus.io/tag" "go.uber.org/fx" "github.com/filecoin-project/lotus/metrics" + "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/repo" ) var rcmgrMetricsOnce sync.Once -func ResourceManager(connMgrHi uint) func(lc fx.Lifecycle, repo repo.LockedRepo) (network.ResourceManager, error) { - return func(lc fx.Lifecycle, repo repo.LockedRepo) (network.ResourceManager, error) { +func ResourceManager(connMgrHi uint) func(lc fx.Lifecycle, repo repo.LockedRepo, bs dtypes.BootstrapPeers) (network.ResourceManager, error) { + return func(lc fx.Lifecycle, repo repo.LockedRepo, bs dtypes.BootstrapPeers) (network.ResourceManager, error) { isFullNode := repo.RepoType().Type() == "FullNode" envvar := os.Getenv("LOTUS_RCMGR") if (isFullNode && envvar == "0") || // only set NullResourceManager if envvar is explicitly "0" @@ -38,7 +41,7 @@ func ResourceManager(connMgrHi uint) func(lc fx.Lifecycle, repo repo.LockedRepo) log.Info("libp2p resource manager is enabled") // enable debug logs for rcmgr - logging.SetLogLevel("rcmgr", "debug") + _ = logging.SetLogLevel("rcmgr", "debug") // Adjust default defaultLimits // - give it more memory, up to 4G, min of 1G @@ -133,6 +136,20 @@ func ResourceManager(connMgrHi uint) func(lc fx.Lifecycle, repo repo.LockedRepo) opts = append(opts, rcmgr.WithTrace(traceFile)) } + resolver := madns.DefaultResolver + var bootstrapperMaddrs []ma.Multiaddr + for _, pi := range bs { + for _, addr := range pi.Addrs { + resolved, err := resolver.Resolve(context.Background(), addr) + if err != nil { + continue + } + bootstrapperMaddrs = append(bootstrapperMaddrs, resolved...) + } + } + + opts = append(opts, rcmgr.WithAllowlistedMultiaddrs(bootstrapperMaddrs)) + mgr, err := rcmgr.NewResourceManager(limiter, opts...) if err != nil { return nil, fmt.Errorf("error creating resource manager: %w", err) diff --git a/node/modules/rpc.go b/node/modules/rpc.go deleted file mode 100644 index d76949737e2..00000000000 --- a/node/modules/rpc.go +++ /dev/null @@ -1,55 +0,0 @@ -package modules - -import ( - "context" - - rpc "github.com/libp2p/go-libp2p-gorpc" - "github.com/libp2p/go-libp2p/core/host" - "github.com/libp2p/go-libp2p/core/peer" - "github.com/libp2p/go-libp2p/core/protocol" - - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/types" - consensus "github.com/filecoin-project/lotus/lib/consensus/raft" - "github.com/filecoin-project/lotus/node/impl/full" -) - -type RPCHandler struct { - mpoolAPI full.MpoolAPI - cons *consensus.Consensus -} - -func NewRPCHandler(mpoolAPI full.MpoolAPI, cons *consensus.Consensus) *RPCHandler { - return &RPCHandler{mpoolAPI, cons} -} - -func (h *RPCHandler) MpoolPushMessage(ctx context.Context, msgWhole *api.MpoolMessageWhole, ret *types.SignedMessage) error { - signedMsg, err := h.mpoolAPI.MpoolPushMessage(ctx, msgWhole.Msg, msgWhole.Spec) - if err != nil { - return err - } - *ret = *signedMsg - return nil -} - -func (h *RPCHandler) AddPeer(ctx context.Context, pid peer.ID, ret *struct{}) error { - return h.cons.AddPeer(ctx, pid) -} - -// Add other consensus RPC calls here - -func NewRPCClient(host host.Host) *rpc.Client { - protocolID := protocol.ID("/rpc/lotus-chain/v0") - return rpc.NewClient(host, protocolID) -} - -func NewRPCServer(ctx context.Context, host host.Host, rpcHandler *RPCHandler) error { - - authF := func(pid peer.ID, svc, method string) bool { - return rpcHandler.cons.IsTrustedPeer(ctx, pid) - } - - protocolID := protocol.ID("/rpc/lotus-chain/v0") - rpcServer := rpc.NewServer(host, protocolID, rpc.WithAuthorizeFunc(authF)) - return rpcServer.RegisterName("Consensus", rpcHandler) -} diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index e27a497bbb6..1b9988b9563 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -820,7 +820,13 @@ func StorageAuth(ctx helpers.MetricsCtx, ca v0api.Common) (sealer.StorageAuth, e return sealer.StorageAuth(headers), nil } -func StorageAuthWithURL(apiInfo string) func(ctx helpers.MetricsCtx, ca v0api.Common) (sealer.StorageAuth, error) { +func StorageAuthWithURL(apiInfo string) interface{} { + if strings.HasPrefix(apiInfo, "harmony:") { + return func(ctx helpers.MetricsCtx, ca MinerStorageService) (sealer.StorageAuth, error) { + return StorageAuth(ctx, ca) + } + } + return func(ctx helpers.MetricsCtx, ca v0api.Common) (sealer.StorageAuth, error) { s := strings.Split(apiInfo, ":") if len(s) != 2 { diff --git a/node/modules/storageminer_svc.go b/node/modules/storageminer_svc.go index dec0453095a..17eb987ef39 100644 --- a/node/modules/storageminer_svc.go +++ b/node/modules/storageminer_svc.go @@ -8,6 +8,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/client" + "github.com/filecoin-project/lotus/api/v1api" cliutil "github.com/filecoin-project/lotus/cli/util" "github.com/filecoin-project/lotus/node/modules/helpers" "github.com/filecoin-project/lotus/storage/sectorblocks" @@ -18,8 +19,8 @@ type MinerStorageService api.StorageMiner var _ sectorblocks.SectorBuilder = *new(MinerSealingService) -func connectMinerService(apiInfo string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (api.StorageMiner, error) { - return func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (api.StorageMiner, error) { +func connectMinerService(apiInfo string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, fapi v1api.FullNode) (api.StorageMiner, error) { + return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, fapi v1api.FullNode) (api.StorageMiner, error) { ctx := helpers.LifecycleCtx(mctx, lc) info := cliutil.ParseApiInfo(apiInfo) addr, err := info.DialArgs("v0") @@ -55,16 +56,16 @@ func connectMinerService(apiInfo string) func(mctx helpers.MetricsCtx, lc fx.Lif } } -func ConnectSealingService(apiInfo string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (MinerSealingService, error) { - return func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (MinerSealingService, error) { +func ConnectSealingService(apiInfo string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, fapi v1api.FullNode) (MinerSealingService, error) { + return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, fapi v1api.FullNode) (MinerSealingService, error) { log.Info("Connecting sealing service to miner") - return connectMinerService(apiInfo)(mctx, lc) + return connectMinerService(apiInfo)(mctx, lc, fapi) } } -func ConnectStorageService(apiInfo string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (MinerStorageService, error) { - return func(mctx helpers.MetricsCtx, lc fx.Lifecycle) (MinerStorageService, error) { +func ConnectStorageService(apiInfo string) func(mctx helpers.MetricsCtx, lc fx.Lifecycle, fapi v1api.FullNode) (MinerStorageService, error) { + return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, fapi v1api.FullNode) (MinerStorageService, error) { log.Info("Connecting storage service to miner") - return connectMinerService(apiInfo)(mctx, lc) + return connectMinerService(apiInfo)(mctx, lc, fapi) } } diff --git a/node/repo/fsrepo.go b/node/repo/fsrepo.go index d8e41fb2bdf..ec35f8f3078 100644 --- a/node/repo/fsrepo.go +++ b/node/repo/fsrepo.go @@ -185,28 +185,28 @@ func (worker) APIInfoEnvVars() (primary string, fallbacks []string, deprecated [ return "WORKER_API_INFO", nil, nil } -type provider struct{} +type curio struct{} -var Provider provider +var Curio curio -func (provider) Type() string { - return "Provider" +func (curio) Type() string { + return "Curio" } -func (provider) Config() interface{} { +func (curio) Config() interface{} { return &struct{}{} } -func (provider) APIFlags() []string { - return []string{"provider-api-url"} +func (curio) APIFlags() []string { + return []string{"curio-api-url"} } -func (provider) RepoFlags() []string { - return []string{"provider-repo"} +func (curio) RepoFlags() []string { + return []string{"curio-repo"} } -func (provider) APIInfoEnvVars() (primary string, fallbacks []string, deprecated []string) { - return "PROVIDER_API_INFO", nil, nil +func (curio) APIInfoEnvVars() (primary string, fallbacks []string, deprecated []string) { + return "CURIO_API_INFO", nil, nil } var Wallet wallet @@ -288,7 +288,7 @@ func (fsr *FsRepo) Init(t RepoType) error { } log.Infof("Initializing repo at '%s'", fsr.path) - err = os.MkdirAll(fsr.path, 0755) //nolint: gosec + err = os.MkdirAll(fsr.path, 0755) if err != nil && !os.IsExist(err) { return err } diff --git a/node/repo/interface.go b/node/repo/interface.go index 328862b9214..11c965bf55c 100644 --- a/node/repo/interface.go +++ b/node/repo/interface.go @@ -28,7 +28,7 @@ const ( var ( ErrNoAPIEndpoint = errors.New("API not running (no endpoint)") ErrNoAPIToken = errors.New("API token not set") - ErrRepoAlreadyLocked = errors.New("repo is already locked (lotus daemon already running)") + ErrRepoAlreadyLocked = errors.New("repo is already locked (process is already running)") ErrClosedRepo = errors.New("repo is no longer open") // ErrInvalidBlockstoreDomain is returned by LockedRepo#Blockstore() when diff --git a/node/repo/repo_test.go b/node/repo/repo_test.go index c78afa9db3d..6390fe7d204 100644 --- a/node/repo/repo_test.go +++ b/node/repo/repo_test.go @@ -56,7 +56,7 @@ func basicTest(t *testing.T, repo Repo) { // mutate config and persist back to repo err = lrepo.SetConfig(func(c interface{}) { cfg := c.(*config.FullNode) - cfg.Client.IpfsMAddr = "duvall" + cfg.FaultReporter.ConsensusFaultReporterAddress = "duvall" }) assert.NoError(t, err) @@ -64,7 +64,7 @@ func basicTest(t *testing.T, repo Repo) { c2, err := lrepo.Config() require.NoError(t, err) cfg2 := c2.(*config.FullNode) - require.Equal(t, cfg2.Client.IpfsMAddr, "duvall") + require.Equal(t, cfg2.FaultReporter.ConsensusFaultReporterAddress, "duvall") err = lrepo.Close() assert.NoError(t, err, "should be able to close") diff --git a/node/rpc.go b/node/rpc.go index cacd33526c8..7a47d1b68ee 100644 --- a/node/rpc.go +++ b/node/rpc.go @@ -153,7 +153,7 @@ func MinerHandler(a api.StorageMiner, permissioned bool) (http.Handler, error) { rootMux := mux.NewRouter() // remote storage - { + if _, realImpl := a.(*impl.StorageMinerAPI); realImpl { m := mux.NewRouter() m.PathPrefix("/remote").HandlerFunc(a.(*impl.StorageMinerAPI).ServeRemote(permissioned)) diff --git a/provider/address.go b/provider/address.go deleted file mode 100644 index f69ca3fac60..00000000000 --- a/provider/address.go +++ /dev/null @@ -1,51 +0,0 @@ -package provider - -import ( - "golang.org/x/xerrors" - - "github.com/filecoin-project/go-address" - - "github.com/filecoin-project/lotus/node/config" - "github.com/filecoin-project/lotus/storage/ctladdr" -) - -func AddressSelector(addrConf *config.LotusProviderAddresses) func() (*ctladdr.AddressSelector, error) { - return func() (*ctladdr.AddressSelector, error) { - as := &ctladdr.AddressSelector{} - if addrConf == nil { - return as, nil - } - - as.DisableOwnerFallback = addrConf.DisableOwnerFallback - as.DisableWorkerFallback = addrConf.DisableWorkerFallback - - for _, s := range addrConf.PreCommitControl { - addr, err := address.NewFromString(s) - if err != nil { - return nil, xerrors.Errorf("parsing precommit control address: %w", err) - } - - as.PreCommitControl = append(as.PreCommitControl, addr) - } - - for _, s := range addrConf.CommitControl { - addr, err := address.NewFromString(s) - if err != nil { - return nil, xerrors.Errorf("parsing commit control address: %w", err) - } - - as.CommitControl = append(as.CommitControl, addr) - } - - for _, s := range addrConf.TerminateControl { - addr, err := address.NewFromString(s) - if err != nil { - return nil, xerrors.Errorf("parsing terminate control address: %w", err) - } - - as.TerminateControl = append(as.TerminateControl, addr) - } - - return as, nil - } -} diff --git a/provider/builder.go b/provider/builder.go deleted file mode 100644 index 81a1a7a0af0..00000000000 --- a/provider/builder.go +++ /dev/null @@ -1,50 +0,0 @@ -package provider - -import ( - "context" - "time" - - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/lib/harmony/harmonydb" - "github.com/filecoin-project/lotus/node/config" - dtypes "github.com/filecoin-project/lotus/node/modules/dtypes" - "github.com/filecoin-project/lotus/provider/chainsched" - "github.com/filecoin-project/lotus/provider/lpmessage" - "github.com/filecoin-project/lotus/provider/lpwindow" - "github.com/filecoin-project/lotus/storage/ctladdr" - "github.com/filecoin-project/lotus/storage/paths" - "github.com/filecoin-project/lotus/storage/sealer" - "github.com/filecoin-project/lotus/storage/sealer/storiface" -) - -//var log = logging.Logger("provider") - -func WindowPostScheduler(ctx context.Context, fc config.LotusProviderFees, pc config.ProvingConfig, - api api.FullNode, verif storiface.Verifier, lw *sealer.LocalWorker, sender *lpmessage.Sender, - as *ctladdr.AddressSelector, addresses []dtypes.MinerAddress, db *harmonydb.DB, - stor paths.Store, idx paths.SectorIndex, max int) (*lpwindow.WdPostTask, *lpwindow.WdPostSubmitTask, *lpwindow.WdPostRecoverDeclareTask, error) { - - chainSched := chainsched.New(api) - - // todo config - ft := lpwindow.NewSimpleFaultTracker(stor, idx, 32, 5*time.Second, 300*time.Second) - - computeTask, err := lpwindow.NewWdPostTask(db, api, ft, lw, verif, chainSched, addresses, max) - if err != nil { - return nil, nil, nil, err - } - - submitTask, err := lpwindow.NewWdPostSubmitTask(chainSched, sender, db, api, fc.MaxWindowPoStGasFee, as) - if err != nil { - return nil, nil, nil, err - } - - recoverTask, err := lpwindow.NewWdPostRecoverDeclareTask(sender, db, api, ft, as, chainSched, fc.MaxWindowPoStGasFee, addresses) - if err != nil { - return nil, nil, nil, err - } - - go chainSched.Run(ctx) - - return computeTask, submitTask, recoverTask, nil -} diff --git a/scripts/lotus-provider.service b/scripts/curio.service similarity index 55% rename from scripts/lotus-provider.service rename to scripts/curio.service index ddec181ba09..967a788fa81 100644 --- a/scripts/lotus-provider.service +++ b/scripts/curio.service @@ -1,11 +1,11 @@ [Unit] -Description=Lotus Provider +Description=Curio After=network.target After=lotus-daemon.service [Service] -ExecStart=/usr/local/bin/lotus-provider run -Environment=GOLOG_FILE="/var/log/lotus/provider.log" +ExecStart=/usr/local/bin/curio run +Environment=GOLOG_FILE="/var/log/curio/curio.log" Environment=GOLOG_LOG_FMT="json" LimitNOFILE=1000000 [Install] diff --git a/scripts/docker-lotus-entrypoint.sh b/scripts/docker-lotus-entrypoint.sh index de1dfbcc8f6..342121d9708 100755 --- a/scripts/docker-lotus-entrypoint.sh +++ b/scripts/docker-lotus-entrypoint.sh @@ -1,18 +1,21 @@ #!/usr/bin/env bash -if [ ! -z $DOCKER_LOTUS_IMPORT_SNAPSHOT ]; then +if [ ! -z "$DOCKER_LOTUS_IMPORT_SNAPSHOT" ]; then GATE="$LOTUS_PATH"/date_initialized # Don't init if already initialized. if [ ! -f "$GATE" ]; then echo importing minimal snapshot - /usr/local/bin/lotus daemon --import-snapshot "$DOCKER_LOTUS_IMPORT_SNAPSHOT" --halt-after-import + /usr/local/bin/lotus daemon \ + --import-snapshot "$DOCKER_LOTUS_IMPORT_SNAPSHOT" \ + --remove-existing-chain=false \ + --halt-after-import # Block future inits date > "$GATE" fi fi # import wallet, if provided -if [ ! -z $DOCKER_LOTUS_IMPORT_WALLET ]; then +if [ ! -z "$DOCKER_LOTUS_IMPORT_WALLET" ]; then /usr/local/bin/lotus-shed keyinfo import "$DOCKER_LOTUS_IMPORT_WALLET" fi diff --git a/scripts/fiximports b/scripts/fiximports deleted file mode 100755 index 360051676ee..00000000000 --- a/scripts/fiximports +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -go_files() { - find . -type f -name \*.go -not -name \*_cbor_gen.go | grep -v './extern/filecoin-ffi' | grep -v './extern/test-vectors' -} - -go_files | xargs -I '{}' sed -i.ifixbak -e '/import (/ { - :1 - $!N - s/\n\n/\'$'\n''/ - /)/!b1 -}' '{}' - -find . -type f -name \*.go.ifixbak | xargs rm - -go_files | xargs -I '{}' goimports -w -local "github.com/filecoin-project" '{}' -go_files | xargs -I '{}' goimports -w -local "github.com/filecoin-project/lotus" '{}' diff --git a/scripts/fiximports/main.go b/scripts/fiximports/main.go new file mode 100644 index 00000000000..427975855bc --- /dev/null +++ b/scripts/fiximports/main.go @@ -0,0 +1,92 @@ +package main + +import ( + "bytes" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "regexp" + "strings" + + "golang.org/x/tools/imports" +) + +var ( + // groupByPrefixes is the list of import prefixes that should _each_ be grouped separately. + // See: imports.LocalPrefix. + groupByPrefixes = []string{ + "github.com/filecoin-project", + "github.com/filecoin-project/lotus", + } + newline = []byte("\n") + importBlockRegex = regexp.MustCompile(`(?s)import\s*\((.*?)\)`) + consecutiveNewlinesRegex = regexp.MustCompile(`\n\s*\n`) +) + +func main() { + if err := filepath.Walk(".", func(path string, info fs.FileInfo, err error) error { + switch { + case err != nil: + return err + case // Skip the entire "./extern/..." directory and its contents. + strings.HasPrefix(path, "extern/"): + return filepath.SkipDir + case // Skip directories, generated cborgen go files and any other non-go files. + info.IsDir(), + strings.HasSuffix(info.Name(), "_cbor_gen.go"), + !strings.HasSuffix(info.Name(), ".go"): + return nil + } + return fixGoImports(path) + }); err != nil { + fmt.Printf("Error fixing go imports: %v\n", err) + os.Exit(1) + } +} + +func fixGoImports(path string) error { + sourceFile, err := os.OpenFile(path, os.O_RDWR, 0666) + if err != nil { + return err + } + defer func() { _ = sourceFile.Close() }() + + source, err := io.ReadAll(sourceFile) + if err != nil { + return err + } + formatted := collapseImportNewlines(source) + for _, prefix := range groupByPrefixes { + imports.LocalPrefix = prefix + formatted, err = imports.Process(path, formatted, nil) + if err != nil { + return err + } + } + if !bytes.Equal(source, formatted) { + if err := replaceFileContent(sourceFile, formatted); err != nil { + return err + } + } + return nil +} + +func replaceFileContent(target *os.File, replacement []byte) error { + if _, err := target.Seek(0, io.SeekStart); err != nil { + return err + } + written, err := target.Write(replacement) + if err != nil { + return err + } + return target.Truncate(int64(written)) +} + +func collapseImportNewlines(content []byte) []byte { + return importBlockRegex.ReplaceAllFunc(content, func(importBlock []byte) []byte { + // Replace consecutive newlines with a single newline within the import block + return consecutiveNewlinesRegex.ReplaceAll(importBlock, newline) + }) +} diff --git a/scripts/generate-lotus-cli.py b/scripts/generate-lotus-cli.py index 1e1fee9a61c..14e85cf9f03 100644 --- a/scripts/generate-lotus-cli.py +++ b/scripts/generate-lotus-cli.py @@ -51,8 +51,12 @@ def get_cmd_recursively(cur_cmd): for e in [ "LOTUS_PATH", "LOTUS_MARKETS_PATH", "LOTUS_MINER_PATH", "LOTUS_STORAGE_PATH", "LOTUS_WORKER_PATH", "WORKER_PATH", "LOTUS_PANIC_REPORT_PATH", "WALLET_PATH" ]: os.environ.pop(e, None) + # Set env var telling the binaries that we're generating docs + os.putenv("LOTUS_DOCS_GENERATION", "1") + os.putenv("LOTUS_VERSION_IGNORE_COMMIT", "1") generate_lotus_cli('lotus') generate_lotus_cli('lotus-miner') generate_lotus_cli('lotus-worker') - generate_lotus_cli('lotus-provider') \ No newline at end of file + generate_lotus_cli('curio') + generate_lotus_cli('sptool') diff --git a/scripts/lotus-daemon.service b/scripts/lotus-daemon.service index af35a027ca7..3f8ea014f0f 100644 --- a/scripts/lotus-daemon.service +++ b/scripts/lotus-daemon.service @@ -10,9 +10,13 @@ ExecStart=/usr/local/bin/lotus daemon Restart=always RestartSec=10 -MemoryAccounting=true -MemoryHigh=8G -MemoryMax=10G +# If running a node in a shared, memory constrained environment, enable MemoryAccounting to put +# pressure on allocations. This will slow the process down but keep it approximately within the +# limit specified. +#MemoryAccounting=true +#MemoryHigh=64G +#MemoryMax=96G + LimitNOFILE=8192:10240 [Install] diff --git a/scripts/publish-checksums.sh b/scripts/publish-checksums.sh index 346ca9b4cd8..8e5cdfe3500 100755 --- a/scripts/publish-checksums.sh +++ b/scripts/publish-checksums.sh @@ -9,6 +9,11 @@ if [ -z "${GITHUB_TOKEN}" ]; then exit 1 fi +if [ "$GITHUB_REF" != refs/tags/* ]; then + echo "$GITHUB_REF is not a tag, publish failed" + exit 1 +fi + REQUIRED=( "jq" "curl" @@ -18,12 +23,14 @@ do command -v "${REQUIRE}" >/dev/null 2>&1 || echo >&2 "'${REQUIRE}' must be installed" done +GITHUB_TAG="${GITHUB_REF#refs/tags/}" + #see if the release already exists by tag RELEASE_RESPONSE=` curl \ --fail \ --header "Authorization: token ${GITHUB_TOKEN}" \ - "https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/releases/tags/${CIRCLE_TAG}" + "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/tags/${GITHUB_TAG}" ` RELEASE_ID=`echo "${RELEASE_RESPONSE}" | jq '.id'` @@ -32,16 +39,16 @@ if [ "${RELEASE_ID}" = "null" ]; then COND_CREATE_DISCUSSION="" PRERELEASE=true - if [[ ${CIRCLE_TAG} =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + if [[ ${GITHUB_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}\", + \"tag_name\": \"${GITHUB_TAG}\", + \"target_commitish\": \"${GITHUB_SHA}\", ${COND_CREATE_DISCUSSION} - \"name\": \"${CIRCLE_TAG}\", + \"name\": \"${GITHUB_TAG}\", \"body\": \"\", \"prerelease\": ${PRERELEASE} }" @@ -54,7 +61,7 @@ if [ "${RELEASE_ID}" = "null" ]; then --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" + "https://api.github.com/repos/${GITHUB_REPOSITORY}/releases" ` else echo "release already exists" diff --git a/scripts/snap-lotus-entrypoint.sh b/scripts/snap-lotus-entrypoint.sh index a3ab04c5b34..68498da4a71 100755 --- a/scripts/snap-lotus-entrypoint.sh +++ b/scripts/snap-lotus-entrypoint.sh @@ -1,4 +1,4 @@ -LOTUS_IMPORT_SNAPSHOT="https://fil-chain-snapshots-fallback.s3.amazonaws.com/mainnet/minimal_finality_stateroots_latest.car" +LOTUS_IMPORT_SNAPSHOT="https://forest-archive.chainsafe.dev/latest/mainnet/" LOTUS_BINARY=$(dirname "$0")/lotus GATE="$LOTUS_PATH"/date_initialized if [ ! -f "$GATE" ]; then diff --git a/scripts/version-check.sh b/scripts/version-check.sh index 4f424ca0cab..20aeda4cc1f 100755 --- a/scripts/version-check.sh +++ b/scripts/version-check.sh @@ -32,8 +32,8 @@ function validate_lotus_version_matches_tag(){ _lotus_path=$1 -if [[ ! -z "${CIRCLE_TAG}" ]]; then - validate_lotus_version_matches_tag "${_lotus_path}" "${CIRCLE_TAG}" +if [[ "$GITHUB_REF" != refs/tags/* ]]; then + validate_lotus_version_matches_tag "${_lotus_path}" "${GITHUB_REF#refs/tags/}" else - echo "No CI tag found. Skipping version check." + echo "$GITHUB_REF is not a tag, skipping version check" fi diff --git a/storage/ctladdr/addresses.go b/storage/ctladdr/addresses.go index ee778cb38e6..3ffa4f41e09 100644 --- a/storage/ctladdr/addresses.go +++ b/storage/ctladdr/addresses.go @@ -82,10 +82,10 @@ func (as *AddressSelector) AddressFor(ctx context.Context, a NodeApi, mi api.Min addrs = append(addrs, mi.Owner) } - return pickAddress(ctx, a, mi, goodFunds, minFunds, addrs) + return PickAddress(ctx, a, mi, goodFunds, minFunds, addrs) } -func pickAddress(ctx context.Context, a NodeApi, mi api.MinerInfo, goodFunds, minFunds abi.TokenAmount, addrs []address.Address) (address.Address, abi.TokenAmount, error) { +func PickAddress(ctx context.Context, a NodeApi, mi api.MinerInfo, goodFunds, minFunds abi.TokenAmount, addrs []address.Address) (address.Address, abi.TokenAmount, error) { leastBad := mi.Worker bestAvail := minFunds diff --git a/storage/paths/db_index.go b/storage/paths/db_index.go index 1e4abfab14b..79239544533 100644 --- a/storage/paths/db_index.go +++ b/storage/paths/db_index.go @@ -24,6 +24,10 @@ import ( "github.com/filecoin-project/lotus/storage/sealer/storiface" ) +const NoMinerFilter = abi.ActorID(0) + +const URLSeparator = "," + var errAlreadyLocked = errors.New("already locked") type DBIndex struct { @@ -182,11 +186,10 @@ func (dbi *DBIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo, // Single transaction to attach storage which is not present in the DB _, err := dbi.harmonyDB.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { - var urls sql.NullString var storageId sql.NullString - err = dbi.harmonyDB.QueryRow(ctx, - "Select storage_id, urls FROM storage_path WHERE storage_id = $1", string(si.ID)).Scan(&storageId, &urls) + err = tx.QueryRow( + "SELECT storage_id, urls FROM storage_path WHERE storage_id = $1", string(si.ID)).Scan(&storageId, &urls) if err != nil && !strings.Contains(err.Error(), "no rows in result set") { return false, xerrors.Errorf("storage attach select fails: %v", err) } @@ -196,13 +199,13 @@ func (dbi *DBIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo, if storageId.Valid { var currUrls []string if urls.Valid { - currUrls = strings.Split(urls.String, ",") + currUrls = strings.Split(urls.String, URLSeparator) } currUrls = union(currUrls, si.URLs) - _, err = dbi.harmonyDB.Exec(ctx, - "UPDATE storage_path set urls=$1, weight=$2, max_storage=$3, can_seal=$4, can_store=$5, groups=$6, allow_to=$7, allow_types=$8, deny_types=$9 WHERE storage_id=$10", - strings.Join(currUrls, ","), + _, err = tx.Exec( + "UPDATE storage_path set urls=$1, weight=$2, max_storage=$3, can_seal=$4, can_store=$5, groups=$6, allow_to=$7, allow_types=$8, deny_types=$9, allow_miners=$10, deny_miners=$11, last_heartbeat=NOW() WHERE storage_id=$12", + strings.Join(currUrls, URLSeparator), si.Weight, si.MaxStorage, si.CanSeal, @@ -211,6 +214,8 @@ func (dbi *DBIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo, strings.Join(si.AllowTo, ","), strings.Join(si.AllowTypes, ","), strings.Join(si.DenyTypes, ","), + strings.Join(si.AllowMiners, ","), + strings.Join(si.DenyMiners, ","), si.ID) if err != nil { return false, xerrors.Errorf("storage attach UPDATE fails: %v", err) @@ -220,9 +225,9 @@ func (dbi *DBIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo, } // Insert storage id - _, err = dbi.harmonyDB.Exec(ctx, + _, err = tx.Exec( "INSERT INTO storage_path "+ - "Values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)", + "Values($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, NOW(), $16, $17)", si.ID, strings.Join(si.URLs, ","), si.Weight, @@ -238,17 +243,15 @@ func (dbi *DBIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo, st.FSAvailable, st.Reserved, st.Used, - time.Now()) + strings.Join(si.AllowMiners, ","), + strings.Join(si.DenyMiners, ",")) if err != nil { return false, xerrors.Errorf("StorageAttach insert fails: %v", err) } return true, nil - }) - if err != nil { - return err - } + }, harmonydb.OptionRetry()) - return nil + return err } func (dbi *DBIndex) StorageDetach(ctx context.Context, id storiface.ID, url string) error { @@ -276,7 +279,7 @@ func (dbi *DBIndex) StorageDetach(ctx context.Context, id storiface.ID, url stri } if len(modUrls) > 0 { - newUrls := strings.Join(modUrls, ",") + newUrls := strings.Join(modUrls, URLSeparator) _, err := dbi.harmonyDB.Exec(ctx, "UPDATE storage_path set urls=$1 WHERE storage_id=$2", newUrls, id) if err != nil { return err @@ -287,46 +290,53 @@ func (dbi *DBIndex) StorageDetach(ctx context.Context, id storiface.ID, url stri // Single transaction to drop storage path and sector decls which have this as a storage path _, err := dbi.harmonyDB.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { // Drop storage path completely - _, err = dbi.harmonyDB.Exec(ctx, "DELETE FROM storage_path WHERE storage_id=$1", id) + _, err = tx.Exec("DELETE FROM storage_path WHERE storage_id=$1", id) if err != nil { return false, err } // Drop all sectors entries which use this storage path - _, err = dbi.harmonyDB.Exec(ctx, "DELETE FROM sector_location WHERE storage_id=$1", id) + _, err = tx.Exec("DELETE FROM sector_location WHERE storage_id=$1", id) if err != nil { return false, err } return true, nil - }) + }, harmonydb.OptionRetry()) if err != nil { return err } log.Warnw("Dropping sector storage", "path", id) } - return nil + return err } func (dbi *DBIndex) StorageReportHealth(ctx context.Context, id storiface.ID, report storiface.HealthReport) error { - - var canSeal, canStore bool - err := dbi.harmonyDB.QueryRow(ctx, - "SELECT can_seal, can_store FROM storage_path WHERE storage_id=$1", id).Scan(&canSeal, &canStore) - if err != nil { - return xerrors.Errorf("Querying for storage id %s fails with err %v", id, err) - } - - _, err = dbi.harmonyDB.Exec(ctx, - "UPDATE storage_path set capacity=$1, available=$2, fs_available=$3, reserved=$4, used=$5, last_heartbeat=$6", + retryWait := time.Millisecond * 20 +retryReportHealth: + _, err := dbi.harmonyDB.Exec(ctx, + "UPDATE storage_path set capacity=$1, available=$2, fs_available=$3, reserved=$4, used=$5, last_heartbeat=NOW() where storage_id=$6", report.Stat.Capacity, report.Stat.Available, report.Stat.FSAvailable, report.Stat.Reserved, report.Stat.Used, - time.Now()) + id) + if err != nil { + //return xerrors.Errorf("updating storage health in DB fails with err: %v", err) + if harmonydb.IsErrSerialization(err) { + time.Sleep(retryWait) + retryWait *= 2 + goto retryReportHealth + } + return err + } + + var canSeal, canStore bool + err = dbi.harmonyDB.QueryRow(ctx, + "SELECT can_seal, can_store FROM storage_path WHERE storage_id=$1", id).Scan(&canSeal, &canStore) if err != nil { - return xerrors.Errorf("updating storage health in DB fails with err: %v", err) + return xerrors.Errorf("Querying for storage id %s fails with err %v", id, err) } if report.Stat.Capacity > 0 { @@ -375,7 +385,7 @@ func (dbi *DBIndex) StorageDeclareSector(ctx context.Context, storageID storifac _, err := dbi.harmonyDB.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { var currPrimary sql.NullBool - err = dbi.harmonyDB.QueryRow(ctx, + err = tx.QueryRow( "SELECT is_primary FROM sector_location WHERE miner_id=$1 and sector_num=$2 and sector_filetype=$3 and storage_id=$4", uint64(s.Miner), uint64(s.Number), int(ft), string(storageID)).Scan(&currPrimary) if err != nil && !strings.Contains(err.Error(), "no rows in result set") { @@ -385,7 +395,7 @@ func (dbi *DBIndex) StorageDeclareSector(ctx context.Context, storageID storifac // If storage id already exists for this sector, update primary if need be if currPrimary.Valid { if !currPrimary.Bool && primary { - _, err = dbi.harmonyDB.Exec(ctx, + _, err = tx.Exec( "UPDATE sector_location set is_primary = TRUE WHERE miner_id=$1 and sector_num=$2 and sector_filetype=$3 and storage_id=$4", s.Miner, s.Number, ft, storageID) if err != nil { @@ -395,7 +405,7 @@ func (dbi *DBIndex) StorageDeclareSector(ctx context.Context, storageID storifac log.Warnf("sector %v redeclared in %s", s, storageID) } } else { - _, err = dbi.harmonyDB.Exec(ctx, + _, err = tx.Exec( "INSERT INTO sector_location "+ "values($1, $2, $3, $4, $5)", s.Miner, s.Number, ft, storageID, primary) @@ -405,12 +415,9 @@ func (dbi *DBIndex) StorageDeclareSector(ctx context.Context, storageID storifac } return true, nil - }) - if err != nil { - return err - } + }, harmonydb.OptionRetry()) - return nil + return err } func (dbi *DBIndex) StorageDropSector(ctx context.Context, storageID storiface.ID, s abi.SectorID, ft storiface.SectorFileType) error { @@ -533,14 +540,16 @@ func (dbi *DBIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft st // 7. Storage path is part of the groups which are allowed from the storage paths which already hold the sector var rows []struct { - StorageId string - Urls string - Weight uint64 - CanSeal bool - CanStore bool - Groups string - AllowTypes string - DenyTypes string + StorageId string + Urls string + Weight uint64 + CanSeal bool + CanStore bool + Groups string + AllowTypes string + DenyTypes string + AllowMiners string + DenyMiners string } err = dbi.harmonyDB.Select(ctx, &rows, `SELECT storage_id, @@ -550,13 +559,15 @@ func (dbi *DBIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft st can_store, groups, allow_types, - deny_types + deny_types, + allow_miners, + deny_miners FROM storage_path WHERE can_seal=true and available >= $1 - and NOW()-last_heartbeat < $2 + and NOW()-($2 * INTERVAL '1 second') < last_heartbeat and heartbeat_err is null`, - spaceReq, SkippedHeartbeatThresh) + spaceReq, SkippedHeartbeatThresh.Seconds()) if err != nil { return nil, xerrors.Errorf("Selecting allowfetch storage paths from DB fails err: %v", err) } @@ -570,6 +581,16 @@ func (dbi *DBIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft st log.Debugf("not selecting on %s, not allowed by file type filters", row.StorageId) continue } + allowMiners := splitString(row.AllowMiners) + denyMiners := splitString(row.DenyMiners) + proceed, msg, err := MinerFilter(allowMiners, denyMiners, s.Miner) + if err != nil { + return nil, err + } + if !proceed { + log.Debugf("not allocating on %s, miner %s %s", row.StorageId, s.Miner.String(), msg) + continue + } if allowList != nil { groups := splitString(row.Groups) @@ -619,19 +640,21 @@ func (dbi *DBIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft st func (dbi *DBIndex) StorageInfo(ctx context.Context, id storiface.ID) (storiface.StorageInfo, error) { var qResults []struct { - Urls string - Weight uint64 - MaxStorage uint64 - CanSeal bool - CanStore bool - Groups string - AllowTo string - AllowTypes string - DenyTypes string + Urls string + Weight uint64 + MaxStorage uint64 + CanSeal bool + CanStore bool + Groups string + AllowTo string + AllowTypes string + DenyTypes string + AllowMiners string + DenyMiners string } err := dbi.harmonyDB.Select(ctx, &qResults, - "SELECT urls, weight, max_storage, can_seal, can_store, groups, allow_to, allow_types, deny_types "+ + "SELECT urls, weight, max_storage, can_seal, can_store, groups, allow_to, allow_types, deny_types, allow_miners, deny_miners "+ "FROM storage_path WHERE storage_id=$1", string(id)) if err != nil { return storiface.StorageInfo{}, xerrors.Errorf("StorageInfo query fails: %v", err) @@ -648,11 +671,13 @@ func (dbi *DBIndex) StorageInfo(ctx context.Context, id storiface.ID) (storiface sinfo.AllowTo = splitString(qResults[0].AllowTo) sinfo.AllowTypes = splitString(qResults[0].AllowTypes) sinfo.DenyTypes = splitString(qResults[0].DenyTypes) + sinfo.AllowMiners = splitString(qResults[0].AllowMiners) + sinfo.DenyMiners = splitString(qResults[0].DenyMiners) return sinfo, nil } -func (dbi *DBIndex) StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType) ([]storiface.StorageInfo, error) { +func (dbi *DBIndex) StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType, miner abi.ActorID) ([]storiface.StorageInfo, error) { var err error var spaceReq uint64 switch pathType { @@ -668,16 +693,18 @@ func (dbi *DBIndex) StorageBestAlloc(ctx context.Context, allocate storiface.Sec } var rows []struct { - StorageId string - Urls string - Weight uint64 - MaxStorage uint64 - CanSeal bool - CanStore bool - Groups string - AllowTo string - AllowTypes string - DenyTypes string + StorageId string + Urls string + Weight uint64 + MaxStorage uint64 + CanSeal bool + CanStore bool + Groups string + AllowTo string + AllowTypes string + DenyTypes string + AllowMiners string + DenyMiners string } err = dbi.harmonyDB.Select(ctx, &rows, @@ -690,15 +717,17 @@ func (dbi *DBIndex) StorageBestAlloc(ctx context.Context, allocate storiface.Sec groups, allow_to, allow_types, - deny_types + deny_types, + allow_miners, + deny_miners FROM storage_path WHERE available >= $1 - and NOW()-last_heartbeat < $2 - and heartbeat_err is null - and ($3 and can_seal = TRUE or $4 and can_store = TRUE) + and NOW()-($2 * INTERVAL '1 second') < last_heartbeat + and heartbeat_err = '' + and (($3 and can_seal = TRUE) or ($4 and can_store = TRUE)) order by (available::numeric * weight) desc`, spaceReq, - SkippedHeartbeatThresh, + SkippedHeartbeatThresh.Seconds(), pathType == storiface.PathSealing, pathType == storiface.PathStorage, ) @@ -707,18 +736,36 @@ func (dbi *DBIndex) StorageBestAlloc(ctx context.Context, allocate storiface.Sec } var result []storiface.StorageInfo + for _, row := range rows { + // Matching with 0 as a workaround to avoid having minerID + // present when calling TaskStorage.HasCapacity() + if miner != NoMinerFilter { + allowMiners := splitString(row.AllowMiners) + denyMiners := splitString(row.DenyMiners) + proceed, msg, err := MinerFilter(allowMiners, denyMiners, miner) + if err != nil { + return nil, err + } + if !proceed { + log.Debugf("not allocating on %s, miner %s %s", row.StorageId, miner.String(), msg) + continue + } + } + result = append(result, storiface.StorageInfo{ - ID: storiface.ID(row.StorageId), - URLs: splitString(row.Urls), - Weight: row.Weight, - MaxStorage: row.MaxStorage, - CanSeal: row.CanSeal, - CanStore: row.CanStore, - Groups: splitString(row.Groups), - AllowTo: splitString(row.AllowTo), - AllowTypes: splitString(row.AllowTypes), - DenyTypes: splitString(row.DenyTypes), + ID: storiface.ID(row.StorageId), + URLs: splitString(row.Urls), + Weight: row.Weight, + MaxStorage: row.MaxStorage, + CanSeal: row.CanSeal, + CanStore: row.CanStore, + Groups: splitString(row.Groups), + AllowTo: splitString(row.AllowTo), + AllowTypes: splitString(row.AllowTypes), + DenyTypes: splitString(row.DenyTypes), + AllowMiners: splitString(row.AllowMiners), + DenyMiners: splitString(row.DenyMiners), }) } @@ -750,7 +797,7 @@ func (dbi *DBIndex) lock(ctx context.Context, sector abi.SectorID, read storifac _, err := dbi.harmonyDB.BeginTransaction(ctx, func(tx *harmonydb.Tx) (commit bool, err error) { fts := (read | write).AllSet() - err = dbi.harmonyDB.Select(ctx, &rows, + err = tx.Select(&rows, `SELECT sector_filetype, read_ts, read_refs, write_ts FROM sector_location WHERE miner_id=$1 @@ -792,7 +839,7 @@ func (dbi *DBIndex) lock(ctx context.Context, sector abi.SectorID, read storifac } // Acquire write locks - _, err = dbi.harmonyDB.Exec(ctx, + _, err = tx.Exec( `UPDATE sector_location SET write_ts = NOW(), write_lock_owner = $1 WHERE miner_id=$2 @@ -807,7 +854,7 @@ func (dbi *DBIndex) lock(ctx context.Context, sector abi.SectorID, read storifac } // Acquire read locks - _, err = dbi.harmonyDB.Exec(ctx, + _, err = tx.Exec( `UPDATE sector_location SET read_ts = NOW(), read_refs = read_refs + 1 WHERE miner_id=$1 @@ -821,7 +868,7 @@ func (dbi *DBIndex) lock(ctx context.Context, sector abi.SectorID, read storifac } return true, nil - }) + }, harmonydb.OptionRetry()) if err != nil { return false, err } diff --git a/storage/paths/http_handler.go b/storage/paths/http_handler.go index 4d0539079b2..c828f600609 100644 --- a/storage/paths/http_handler.go +++ b/storage/paths/http_handler.go @@ -10,8 +10,8 @@ import ( "time" "github.com/gorilla/mux" + "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" - "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" @@ -55,6 +55,7 @@ func (handler *FetchHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { mux.HandleFunc("/remote/stat/{id}", handler.remoteStatFs).Methods("GET") mux.HandleFunc("/remote/vanilla/single", handler.generateSingleVanillaProof).Methods("POST") + mux.HandleFunc("/remote/vanilla/porep", handler.generatePoRepVanillaProof).Methods("POST") mux.HandleFunc("/remote/{type}/{id}/{spt}/allocated/{offset}/{size}", handler.remoteGetAllocated).Methods("GET") mux.HandleFunc("/remote/{type}/{id}", handler.remoteGetSector).Methods("GET") mux.HandleFunc("/remote/{type}/{id}", handler.remoteDeleteSector).Methods("DELETE") @@ -312,19 +313,31 @@ func (handler *FetchHandler) generateSingleVanillaProof(w http.ResponseWriter, r http.ServeContent(w, r, "", time.Time{}, bytes.NewReader(vanilla)) } -func FileTypeFromString(t string) (storiface.SectorFileType, error) { - switch t { - case storiface.FTUnsealed.String(): - return storiface.FTUnsealed, nil - case storiface.FTSealed.String(): - return storiface.FTSealed, nil - case storiface.FTCache.String(): - return storiface.FTCache, nil - case storiface.FTUpdate.String(): - return storiface.FTUpdate, nil - case storiface.FTUpdateCache.String(): - return storiface.FTUpdateCache, nil - default: - return 0, xerrors.Errorf("unknown sector file type: '%s'", t) +type PoRepVanillaParams struct { + Sector storiface.SectorRef + Sealed cid.Cid + Unsealed cid.Cid + Ticket abi.SealRandomness + Seed abi.InteractiveSealRandomness +} + +func (handler *FetchHandler) generatePoRepVanillaProof(w http.ResponseWriter, r *http.Request) { + var params PoRepVanillaParams + if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { + http.Error(w, err.Error(), 500) + return + } + + vanilla, err := handler.Local.GeneratePoRepVanillaProof(r.Context(), params.Sector, params.Sealed, params.Unsealed, params.Ticket, params.Seed) + if err != nil { + http.Error(w, err.Error(), 500) + return } + + w.Header().Set("Content-Type", "application/octet-stream") + http.ServeContent(w, r, "", time.Time{}, bytes.NewReader(vanilla)) +} + +func FileTypeFromString(t string) (storiface.SectorFileType, error) { + return storiface.TypeFromString(t) } diff --git a/storage/paths/index.go b/storage/paths/index.go index 49ee11e0960..e09b887e03d 100644 --- a/storage/paths/index.go +++ b/storage/paths/index.go @@ -14,6 +14,7 @@ import ( "go.opencensus.io/tag" "golang.org/x/xerrors" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" @@ -38,7 +39,7 @@ type SectorIndex interface { // part of storage-miner api StorageDropSector(ctx context.Context, storageID storiface.ID, s abi.SectorID, ft storiface.SectorFileType) error StorageFindSector(ctx context.Context, sector abi.SectorID, ft storiface.SectorFileType, ssize abi.SectorSize, allowFetch bool) ([]storiface.SectorStorageInfo, error) - StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType) ([]storiface.StorageInfo, error) + StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType, miner abi.ActorID) ([]storiface.StorageInfo, error) // atomically acquire locks on all sector file types. close ctx to unlock StorageLock(ctx context.Context, sector abi.SectorID, read storiface.SectorFileType, write storiface.SectorFileType) error @@ -61,6 +62,7 @@ type storageEntry struct { heartbeatErr error } +// MemIndex represents an in-memory index of storage sectors and storage entries. type MemIndex struct { *indexLocks lk sync.RWMutex @@ -206,6 +208,8 @@ func (i *MemIndex) StorageAttach(ctx context.Context, si storiface.StorageInfo, i.stores[si.ID].info.AllowTo = si.AllowTo i.stores[si.ID].info.AllowTypes = allow i.stores[si.ID].info.DenyTypes = deny + i.stores[si.ID].info.AllowMiners = si.AllowMiners + i.stores[si.ID].info.DenyMiners = si.DenyMiners return nil } @@ -476,8 +480,10 @@ func (i *MemIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft sto Primary: isprimary[id], - AllowTypes: st.info.AllowTypes, - DenyTypes: st.info.DenyTypes, + AllowTypes: st.info.AllowTypes, + DenyTypes: st.info.DenyTypes, + AllowMiners: st.info.AllowMiners, + DenyMiners: st.info.DenyMiners, }) } @@ -492,6 +498,16 @@ func (i *MemIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft sto continue } + proceed, msg, err := MinerFilter(st.info.AllowMiners, st.info.DenyMiners, s.Miner) + if err != nil { + return nil, err + } + + if !proceed { + log.Debugf("not allocating on %s, miner %s %s", st.info.ID, s.Miner.String(), msg) + continue + } + if spaceReq > uint64(st.fsi.Available) { log.Debugf("not selecting on %s, out of space (available: %d, need: %d)", st.info.ID, st.fsi.Available, spaceReq) continue @@ -555,8 +571,10 @@ func (i *MemIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft sto Primary: false, - AllowTypes: st.info.AllowTypes, - DenyTypes: st.info.DenyTypes, + AllowTypes: st.info.AllowTypes, + DenyTypes: st.info.DenyTypes, + AllowMiners: st.info.AllowMiners, + DenyMiners: st.info.DenyMiners, }) } } @@ -564,6 +582,21 @@ func (i *MemIndex) StorageFindSector(ctx context.Context, s abi.SectorID, ft sto return out, nil } +// StorageInfo retrieves the storage information for a given storage ID. +// +// The method first acquires a read lock on the MemIndex to ensure thread-safety. +// It then checks if the storage ID exists in the stores map. If not, it returns +// an error indicating that the sector store was not found. +// +// Finally, it returns the storage information of the selected storage. +// +// Parameters: +// - ctx: the context.Context object for cancellation and timeouts +// - id: the ID of the storage to retrieve information for +// +// Returns: +// - storiface.StorageInfo: the storage information of the selected storage ID +// - error: an error indicating any issues encountered during the process func (i *MemIndex) StorageInfo(ctx context.Context, id storiface.ID) (storiface.StorageInfo, error) { i.lk.RLock() defer i.lk.RUnlock() @@ -576,7 +609,33 @@ func (i *MemIndex) StorageInfo(ctx context.Context, id storiface.ID) (storiface. return *si.info, nil } -func (i *MemIndex) StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType) ([]storiface.StorageInfo, error) { +// StorageBestAlloc selects the best available storage options for allocating +// a sector file. It takes into account the allocation type (sealing or storage), +// sector size, and path type (sealing or storage). +// +// The method first estimates the required space for the allocation based on the +// sector size and path type. It then iterates through all available storage options +// and filters out those that cannot be used for the given path type. It also filters +// out storage options that do not have enough available space or have not received +// heartbeats within a certain threshold. +// +// The remaining storage options are sorted based on their available space and weight, +// with higher availability and weight being prioritized. The method then returns +// the information of the selected storage options. +// +// If no suitable storage options are found, it returns an error indicating that +// no good path is available. +// +// Parameters: +// - ctx: the context.Context object for cancellation and timeouts +// - allocate: the type of allocation (sealing or storage) +// - ssize: the size of the sector file +// - pathType: the path type (sealing or storage) +// +// Returns: +// - []storiface.StorageInfo: the information of the selected storage options +// - error: an error indicating any issues encountered during the process +func (i *MemIndex) StorageBestAlloc(ctx context.Context, allocate storiface.SectorFileType, ssize abi.SectorSize, pathType storiface.PathType, miner abi.ActorID) ([]storiface.StorageInfo, error) { i.lk.RLock() defer i.lk.RUnlock() @@ -604,6 +663,16 @@ func (i *MemIndex) StorageBestAlloc(ctx context.Context, allocate storiface.Sect continue } + proceed, msg, err := MinerFilter(p.info.AllowMiners, p.info.DenyMiners, miner) + if err != nil { + return nil, err + } + + if !proceed { + log.Debugf("not allocating on %s, miner %s %s", p.info.ID, miner.String(), msg) + continue + } + if spaceReq > uint64(p.fsi.Available) { log.Debugf("not allocating on %s, out of space (available: %d, need: %d)", p.info.ID, p.fsi.Available, spaceReq) continue @@ -661,3 +730,38 @@ func (i *MemIndex) FindSector(id abi.SectorID, typ storiface.SectorFileType) ([] } var _ SectorIndex = &MemIndex{} + +func MinerFilter(allowMiners, denyMiners []string, miner abi.ActorID) (bool, string, error) { + checkMinerInList := func(minersList []string, miner abi.ActorID) (bool, error) { + for _, m := range minersList { + minerIDStr := m + maddr, err := address.NewFromString(minerIDStr) + if err != nil { + return false, xerrors.Errorf("parsing miner address: %w", err) + } + mid, err := address.IDFromAddress(maddr) + if err != nil { + return false, xerrors.Errorf("converting miner address to ID: %w", err) + } + if abi.ActorID(mid) == miner { + return true, nil + } + } + return false, nil + } + + if len(allowMiners) > 0 { + found, err := checkMinerInList(allowMiners, miner) + if err != nil || !found { + return false, "not allowed", err + } + } + + if len(denyMiners) > 0 { + found, err := checkMinerInList(denyMiners, miner) + if err != nil || found { + return false, "denied", err + } + } + return true, "", nil +} diff --git a/storage/paths/index_test.go b/storage/paths/index_test.go index 96e17ce7db0..328717bb40d 100644 --- a/storage/paths/index_test.go +++ b/storage/paths/index_test.go @@ -15,7 +15,7 @@ import ( ) func init() { - logging.SetLogLevel("stores", "DEBUG") + _ = logging.SetLogLevel("stores", "DEBUG") } func newTestStorage() storiface.StorageInfo { @@ -152,3 +152,61 @@ func TestFindAllow(t *testing.T) { } } } + +func TestStorageBestAlloc(t *testing.T) { + idx := NewMemIndex(nil) + + dummyStorageInfo := storiface.StorageInfo{ + ID: storiface.ID("dummy"), + CanSeal: true, + CanStore: true, + URLs: []string{"http://localhost:9999/"}, + Weight: 10, + AllowMiners: []string{ + "t001", + }, + } + + dummyFsStat := fsutil.FsStat{ + Capacity: 10000000000, + Available: 7000000000, + Reserved: 100000000, + Used: 3000000000, + } + + err := idx.StorageAttach(context.Background(), dummyStorageInfo, dummyFsStat) + require.NoError(t, err) + + t.Run("PathSealing", func(t *testing.T) { + result, err := idx.StorageBestAlloc(context.Background(), storiface.FTUnsealed, 123, storiface.PathSealing, 1) + require.Equal(t, err, nil) + require.NotNil(t, result) + require.Equal(t, len(result), 1) + require.Equal(t, result[0].ID, dummyStorageInfo.ID) + }) + + t.Run("PathStorage", func(t *testing.T) { + result, err := idx.StorageBestAlloc(context.Background(), storiface.FTUnsealed, 123, storiface.PathStorage, 1) + require.Equal(t, err, nil) + require.NotNil(t, result) + require.Equal(t, len(result), 1) + require.Equal(t, result[0].ID, dummyStorageInfo.ID) + }) + + t.Run("NotAllowedMiner", func(t *testing.T) { + _, err := idx.StorageBestAlloc(context.Background(), storiface.FTUnsealed, 123, storiface.PathSealing, 2) + require.Error(t, err) + }) + + t.Run("NoAvailableSpace", func(t *testing.T) { + bigSectorSize := abi.SectorSize(10000000000) + _, err := idx.StorageBestAlloc(context.Background(), storiface.FTUnsealed, bigSectorSize, storiface.PathSealing, 1) + require.Error(t, err) + }) + + t.Run("AllowedMiner", func(t *testing.T) { + _, err := idx.StorageBestAlloc(context.Background(), storiface.FTUnsealed, 123, storiface.PathSealing, 1) + require.NoError(t, err) + }) + +} diff --git a/storage/paths/interface.go b/storage/paths/interface.go index d96135de8f2..d3dce8886d4 100644 --- a/storage/paths/interface.go +++ b/storage/paths/interface.go @@ -4,6 +4,8 @@ import ( "context" "io" + "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/storage/sealer/fsutil" @@ -33,7 +35,7 @@ type PartialFileHandler interface { //go:generate go run github.com/golang/mock/mockgen -destination=mocks/store.go -package=mocks . Store type Store interface { - AcquireSector(ctx context.Context, s storiface.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, sealing storiface.PathType, op storiface.AcquireMode) (paths storiface.SectorPaths, stores storiface.SectorPaths, err error) + AcquireSector(ctx context.Context, s storiface.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, sealing storiface.PathType, op storiface.AcquireMode, opts ...storiface.AcquireOption) (paths storiface.SectorPaths, stores storiface.SectorPaths, err error) Remove(ctx context.Context, s abi.SectorID, types storiface.SectorFileType, force bool, keepIn []storiface.ID) error // like remove, but doesn't remove the primary sector copy, nor the last @@ -41,11 +43,12 @@ type Store interface { RemoveCopies(ctx context.Context, s abi.SectorID, types storiface.SectorFileType) error // move sectors into storage - MoveStorage(ctx context.Context, s storiface.SectorRef, types storiface.SectorFileType) error + MoveStorage(ctx context.Context, s storiface.SectorRef, types storiface.SectorFileType, opts ...storiface.AcquireOption) error FsStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, error) Reserve(ctx context.Context, sid storiface.SectorRef, ft storiface.SectorFileType, storageIDs storiface.SectorPaths, overheadTab map[storiface.SectorFileType]int) (func(), error) GenerateSingleVanillaProof(ctx context.Context, minerID abi.ActorID, si storiface.PostSectorChallenge, ppt abi.RegisteredPoStProof) ([]byte, error) + GeneratePoRepVanillaProof(ctx context.Context, sr storiface.SectorRef, sealed, unsealed cid.Cid, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness) ([]byte, error) } diff --git a/storage/paths/local.go b/storage/paths/local.go index 577d4dbe008..244def37726 100644 --- a/storage/paths/local.go +++ b/storage/paths/local.go @@ -7,9 +7,11 @@ import ( "math/rand" "os" "path/filepath" + "runtime" "sync" "time" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" ffi "github.com/filecoin-project/filecoin-ffi" @@ -44,57 +46,113 @@ type Local struct { localLk sync.RWMutex } +type sectorFile struct { + sid abi.SectorID + ft storiface.SectorFileType +} + type path struct { local string // absolute local path maxStorage uint64 reserved int64 - reservations map[abi.SectorID]storiface.SectorFileType + reservations map[sectorFile]int64 +} + +// statExistingSectorForReservation is optional parameter for stat method +// which will make it take into account existing sectors when calculating +// available space for new reservations +type statExistingSectorForReservation struct { + id abi.SectorID + ft storiface.SectorFileType + overhead int64 } -func (p *path) stat(ls LocalStorage) (fsutil.FsStat, error) { +func (p *path) stat(ls LocalStorage, newReserve ...statExistingSectorForReservation) (stat fsutil.FsStat, newResvOnDisk int64, err error) { start := time.Now() - stat, err := ls.Stat(p.local) + stat, err = ls.Stat(p.local) if err != nil { - return fsutil.FsStat{}, xerrors.Errorf("stat %s: %w", p.local, err) + return fsutil.FsStat{}, 0, xerrors.Errorf("stat %s: %w", p.local, err) } stat.Reserved = p.reserved + var newReserveOnDisk int64 - for id, ft := range p.reservations { - for _, fileType := range storiface.PathTypes { - if fileType&ft == 0 { - continue + accountExistingFiles := func(id abi.SectorID, fileType storiface.SectorFileType, overhead int64) (int64, error) { + sp := p.sectorPath(id, fileType) + + used, err := ls.DiskUsage(sp) + if err == os.ErrNotExist { + p, ferr := tempFetchDest(sp, false) + if ferr != nil { + return 0, ferr } - sp := p.sectorPath(id, fileType) + used, err = ls.DiskUsage(p) + } + if err != nil { + // we don't care about 'not exist' errors, as storage can be + // reserved before any files are written, so this error is not + // unexpected + if !os.IsNotExist(err) { + log.Warnf("getting disk usage of '%s': %+v", p.sectorPath(id, fileType), err) + } + return 0, nil + } - used, err := ls.DiskUsage(sp) - if err == os.ErrNotExist { - p, ferr := tempFetchDest(sp, false) - if ferr != nil { - return fsutil.FsStat{}, ferr - } + log.Debugw("accounting existing files", "id", id, "fileType", fileType, "path", sp, "used", used, "overhead", overhead) + return used, nil + } - used, err = ls.DiskUsage(p) + for id, oh := range p.reservations { + onDisk, err := accountExistingFiles(id.sid, id.ft, oh) + if err != nil { + return fsutil.FsStat{}, 0, err + } + if onDisk > oh { + log.Warnw("reserved space on disk is greater than expected", "id", id.sid, "fileType", id.ft, "onDisk", onDisk, "oh", oh) + onDisk = oh + } + + stat.Reserved -= onDisk + } + for _, reservation := range newReserve { + for _, fileType := range reservation.ft.AllSet() { + log.Debugw("accounting existing files for new reservation", "id", reservation.id, "fileType", fileType, "overhead", reservation.overhead) + + resID := sectorFile{reservation.id, fileType} + + if _, has := p.reservations[resID]; has { + // already accounted for + continue } + + onDisk, err := accountExistingFiles(reservation.id, fileType, reservation.overhead) if err != nil { - // we don't care about 'not exist' errors, as storage can be - // reserved before any files are written, so this error is not - // unexpected - if !os.IsNotExist(err) { - log.Warnf("getting disk usage of '%s': %+v", p.sectorPath(id, fileType), err) - } - continue + return fsutil.FsStat{}, 0, err + } + if onDisk > reservation.overhead { + log.Warnw("reserved space on disk is greater than expected (new resv)", "id", reservation.id, "fileType", fileType, "onDisk", onDisk, "oh", reservation.overhead) + onDisk = reservation.overhead } - stat.Reserved -= used + newReserveOnDisk += onDisk } } if stat.Reserved < 0 { - log.Warnf("negative reserved storage: p.reserved=%d, reserved: %d", p.reserved, stat.Reserved) + //log.Warnf("negative reserved storage: p.reserved=%d, reserved: %d", p.reserved, stat.Reserved) + var jsonReservations []map[string]interface{} + for id, res := range p.reservations { + jsonReservations = append(jsonReservations, map[string]interface{}{ + "id": id.sid, + "ft": id.ft, + "res": res, + }) + } + + log.Warnw("negative reserved storage", "reserved", stat.Reserved, "origResv", p.reserved, "reservations", len(p.reservations), "newReserveOnDisk", newReserveOnDisk, "reservations", jsonReservations) stat.Reserved = 0 } @@ -106,7 +164,7 @@ func (p *path) stat(ls LocalStorage) (fsutil.FsStat, error) { if p.maxStorage > 0 { used, err := ls.DiskUsage(p.local) if err != nil { - return fsutil.FsStat{}, err + return fsutil.FsStat{}, 0, err } stat.Max = int64(p.maxStorage) @@ -126,7 +184,7 @@ func (p *path) stat(ls LocalStorage) (fsutil.FsStat, error) { log.Warnw("slow storage stat", "took", time.Now().Sub(start), "reservations", len(p.reservations)) } - return stat, err + return stat, newReserveOnDisk, err } func (p *path) sectorPath(sid abi.SectorID, fileType storiface.SectorFileType) string { @@ -171,25 +229,27 @@ func (st *Local) OpenPath(ctx context.Context, p string) error { maxStorage: meta.MaxStorage, reserved: 0, - reservations: map[abi.SectorID]storiface.SectorFileType{}, + reservations: map[sectorFile]int64{}, } - fst, err := out.stat(st.localStorage) + fst, _, err := out.stat(st.localStorage) if err != nil { return err } err = st.index.StorageAttach(ctx, storiface.StorageInfo{ - ID: meta.ID, - URLs: st.urls, - Weight: meta.Weight, - MaxStorage: meta.MaxStorage, - CanSeal: meta.CanSeal, - CanStore: meta.CanStore, - Groups: meta.Groups, - AllowTo: meta.AllowTo, - AllowTypes: meta.AllowTypes, - DenyTypes: meta.DenyTypes, + ID: meta.ID, + URLs: st.urls, + Weight: meta.Weight, + MaxStorage: meta.MaxStorage, + CanSeal: meta.CanSeal, + CanStore: meta.CanStore, + Groups: meta.Groups, + AllowTo: meta.AllowTo, + AllowTypes: meta.AllowTypes, + DenyTypes: meta.DenyTypes, + AllowMiners: meta.AllowMiners, + DenyMiners: meta.DenyMiners, }, fst) if err != nil { return xerrors.Errorf("declaring storage in index: %w", err) @@ -256,7 +316,7 @@ func (st *Local) Redeclare(ctx context.Context, filterId *storiface.ID, dropMiss return xerrors.Errorf("unmarshalling storage metadata for %s: %w", p.local, err) } - fst, err := p.stat(st.localStorage) + fst, _, err := p.stat(st.localStorage) if err != nil { return err } @@ -270,16 +330,18 @@ func (st *Local) Redeclare(ctx context.Context, filterId *storiface.ID, dropMiss } err = st.index.StorageAttach(ctx, storiface.StorageInfo{ - ID: id, - URLs: st.urls, - Weight: meta.Weight, - MaxStorage: meta.MaxStorage, - CanSeal: meta.CanSeal, - CanStore: meta.CanStore, - Groups: meta.Groups, - AllowTo: meta.AllowTo, - AllowTypes: meta.AllowTypes, - DenyTypes: meta.DenyTypes, + ID: id, + URLs: st.urls, + Weight: meta.Weight, + MaxStorage: meta.MaxStorage, + CanSeal: meta.CanSeal, + CanStore: meta.CanStore, + Groups: meta.Groups, + AllowTo: meta.AllowTo, + AllowTypes: meta.AllowTypes, + DenyTypes: meta.DenyTypes, + AllowMiners: meta.AllowMiners, + DenyMiners: meta.DenyMiners, }, fst) if err != nil { return xerrors.Errorf("redeclaring storage in index: %w", err) @@ -380,7 +442,7 @@ func (st *Local) reportStorage(ctx context.Context) { toReport := map[storiface.ID]storiface.HealthReport{} for id, p := range st.paths { - stat, err := p.stat(st.localStorage) + stat, _, err := p.stat(st.localStorage) r := storiface.HealthReport{Stat: stat} if err != nil { r.Err = err.Error() @@ -398,26 +460,28 @@ func (st *Local) reportStorage(ctx context.Context) { } } -func (st *Local) Reserve(ctx context.Context, sid storiface.SectorRef, ft storiface.SectorFileType, storageIDs storiface.SectorPaths, overheadTab map[storiface.SectorFileType]int) (func(), error) { - ssize, err := sid.ProofType.SectorSize() +func (st *Local) Reserve(ctx context.Context, sid storiface.SectorRef, ft storiface.SectorFileType, storageIDs storiface.SectorPaths, overheadTab map[storiface.SectorFileType]int) (release func(), err error) { + var ssize abi.SectorSize + ssize, err = sid.ProofType.SectorSize() if err != nil { return nil, err } + release = func() {} st.localLk.Lock() - done := func() {} - deferredDone := func() { done() } defer func() { st.localLk.Unlock() - deferredDone() - }() - - for _, fileType := range storiface.PathTypes { - if fileType&ft == 0 { - continue + if err != nil { + release() + release = func() {} + } else { + release = DoubleCallWrap(release) } + }() + for _, fileType := range ft.AllSet() { + fileType := fileType id := storiface.ID(storiface.PathByType(storageIDs, fileType)) p, ok := st.paths[id] @@ -425,41 +489,59 @@ func (st *Local) Reserve(ctx context.Context, sid storiface.SectorRef, ft storif return nil, errPathNotFound } - stat, err := p.stat(st.localStorage) + overhead := int64(overheadTab[fileType]) * int64(ssize) / storiface.FSOverheadDen + + stat, resvOnDisk, err := p.stat(st.localStorage, statExistingSectorForReservation{sid.ID, fileType, overhead}) if err != nil { return nil, xerrors.Errorf("getting local storage stat: %w", err) } - overhead := int64(overheadTab[fileType]) * int64(ssize) / storiface.FSOverheadDen + if overhead-resvOnDisk < 0 { + log.Errorw("negative overhead vs on-disk data", "overhead", overhead, "on-disk", resvOnDisk, "id", id, "sector", sid, "fileType", fileType) + resvOnDisk = overhead + } - if stat.Available < overhead { + if stat.Available < overhead-resvOnDisk { return nil, storiface.Err(storiface.ErrTempAllocateSpace, xerrors.Errorf("can't reserve %d bytes in '%s' (id:%s), only %d available", overhead, p.local, id, stat.Available)) } - p.reserved += overhead - p.reservations[sid.ID] |= fileType + resID := sectorFile{sid.ID, fileType} + + log.Debugw("reserve add", "id", id, "sector", sid, "fileType", fileType, "overhead", overhead, "reserved-before", p.reserved, "reserved-after", p.reserved+overhead) - prevDone := done - saveFileType := fileType - done = func() { - prevDone() + p.reserved += overhead + p.reservations[resID] = overhead + old_r := release + release = func() { + old_r() st.localLk.Lock() defer st.localLk.Unlock() - + log.Debugw("reserve release", "id", id, "sector", sid, "fileType", fileType, "overhead", overhead, "reserved-before", p.reserved, "reserved-after", p.reserved-overhead) p.reserved -= overhead - p.reservations[sid.ID] ^= saveFileType - if p.reservations[sid.ID] == storiface.FTNone { - delete(p.reservations, sid.ID) - } + delete(p.reservations, resID) } } - deferredDone = func() {} - return done, nil + return } -func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, pathType storiface.PathType, op storiface.AcquireMode) (storiface.SectorPaths, storiface.SectorPaths, error) { +// DoubleCallWrap wraps a function to make sure it's not called twice +func DoubleCallWrap(f func()) func() { + var stack []byte + return func() { + curStack := make([]byte, 20480) + curStack = curStack[:runtime.Stack(curStack, false)] + if len(stack) > 0 { + log.Warnf("double call from:\n%s\nBut originally from:", curStack, stack) + return + } + stack = curStack + f() + } +} + +func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, pathType storiface.PathType, op storiface.AcquireMode, opts ...storiface.AcquireOption) (storiface.SectorPaths, storiface.SectorPaths, error) { if existing|allocate != existing^allocate { return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.New("can't both find and allocate a sector") } @@ -475,14 +557,41 @@ func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, exi var out storiface.SectorPaths var storageIDs storiface.SectorPaths + allocPathOk := func(canSeal, canStore bool, allowTypes, denyTypes, allowMiners, denyMiners []string, fileType storiface.SectorFileType, miner abi.ActorID) (bool, error) { + if (pathType == storiface.PathSealing) && !canSeal { + return false, nil + } + + if (pathType == storiface.PathStorage) && !canStore { + return false, nil + } + + if !fileType.Allowed(allowTypes, denyTypes) { + return false, nil + } + proceed, _, err := MinerFilter(allowMiners, denyMiners, miner) + if err != nil { + return false, err + } + if !proceed { + return false, nil + } + + return true, nil + } + + // First find existing files for _, fileType := range storiface.PathTypes { - if fileType&existing == 0 { + // also try to find existing sectors if we're allocating + if fileType&(existing|allocate) == 0 { continue } si, err := st.index.StorageFindSector(ctx, sid.ID, fileType, ssize, false) if err != nil { - log.Warnf("finding existing sector %d(t:%d) failed: %+v", sid, fileType, err) + if fileType&existing != 0 { + log.Warnf("finding existing sector %d(t:%d) failed: %+v", sid, fileType, err) + } continue } @@ -496,21 +605,34 @@ func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, exi continue } + if allocate.Has(fileType) { + ok, err := allocPathOk(info.CanSeal, info.CanStore, info.AllowTypes, info.DenyTypes, info.AllowMiners, info.DenyMiners, fileType, sid.ID.Miner) + if err != nil { + log.Debug(err) + continue + } + if !ok { + continue // allocate request for a path of different type + } + } + spath := p.sectorPath(sid.ID, fileType) storiface.SetPathByType(&out, fileType, spath) storiface.SetPathByType(&storageIDs, fileType, string(info.ID)) - existing ^= fileType + existing = existing.Unset(fileType) + allocate = allocate.Unset(fileType) break } } + // Then allocate for allocation requests for _, fileType := range storiface.PathTypes { if fileType&allocate == 0 { continue } - sis, err := st.index.StorageBestAlloc(ctx, fileType, ssize, pathType) + sis, err := st.index.StorageBestAlloc(ctx, fileType, ssize, pathType, sid.ID.Miner) if err != nil { return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.Errorf("finding best storage for allocating : %w", err) } @@ -528,15 +650,14 @@ func (st *Local) AcquireSector(ctx context.Context, sid storiface.SectorRef, exi continue } - if (pathType == storiface.PathSealing) && !si.CanSeal { - continue - } + alloc, err := allocPathOk(si.CanSeal, si.CanStore, si.AllowTypes, si.DenyTypes, si.AllowMiners, si.DenyMiners, fileType, sid.ID.Miner) - if (pathType == storiface.PathStorage) && !si.CanStore { + if err != nil { + log.Debug(err) continue } - if !fileType.Allowed(si.AllowTypes, si.DenyTypes) { + if !alloc { continue } @@ -591,6 +712,8 @@ func (st *Local) Remove(ctx context.Context, sid abi.SectorID, typ storiface.Sec return xerrors.New("delete expects one file type") } + log.Debugw("Remove called", "sid", sid, "type", typ, "force", force, "keepIn", keepIn) + si, err := st.index.StorageFindSector(ctx, sid, typ, 0, false) if err != nil { return xerrors.Errorf("finding existing sector %d(t:%d) failed: %w", sid, typ, err) @@ -667,7 +790,7 @@ func (st *Local) removeSector(ctx context.Context, sid abi.SectorID, typ storifa } spath := p.sectorPath(sid, typ) - log.Infof("remove %s", spath) + log.Infow("remove", "path", spath, "id", sid, "type", typ, "storage", storage) if err := os.RemoveAll(spath); err != nil { log.Errorf("removing sector (%v) from %s: %+v", sid, spath, err) @@ -678,22 +801,36 @@ func (st *Local) removeSector(ctx context.Context, sid abi.SectorID, typ storifa return nil } -func (st *Local) MoveStorage(ctx context.Context, s storiface.SectorRef, types storiface.SectorFileType) error { - dest, destIds, err := st.AcquireSector(ctx, s, storiface.FTNone, types, storiface.PathStorage, storiface.AcquireMove) - if err != nil { - return xerrors.Errorf("acquire dest storage: %w", err) +func (st *Local) MoveStorage(ctx context.Context, s storiface.SectorRef, types storiface.SectorFileType, opts ...storiface.AcquireOption) error { + settings := storiface.AcquireSettings{ + // If into is nil then we're expecting the data to be there already, but make sure here + Into: nil, + } + for _, o := range opts { + o(&settings) + } + + var err error + var dest, destIds storiface.SectorPaths + if settings.Into == nil { + dest, destIds, err = st.AcquireSector(ctx, s, storiface.FTNone, types, storiface.PathStorage, storiface.AcquireMove) + if err != nil { + return xerrors.Errorf("acquire dest storage: %w", err) + } + } else { + // destination from settings + dest = settings.Into.Paths + destIds = settings.Into.IDs } + // note: this calls allocate on types - if data is already in paths of correct type, + // the returned paths are guaranteed to be the same as dest src, srcIds, err := st.AcquireSector(ctx, s, types, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove) if err != nil { return xerrors.Errorf("acquire src storage: %w", err) } - for _, fileType := range storiface.PathTypes { - if fileType&types == 0 { - continue - } - + for _, fileType := range types.AllSet() { sst, err := st.index.StorageInfo(ctx, storiface.ID(storiface.PathByType(srcIds, fileType))) if err != nil { return xerrors.Errorf("failed to get source storage info: %w", err) @@ -746,7 +883,8 @@ func (st *Local) FsStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, er return fsutil.FsStat{}, errPathNotFound } - return p.stat(st.localStorage) + stat, _, err := p.stat(st.localStorage) + return stat, err } func (st *Local) GenerateSingleVanillaProof(ctx context.Context, minerID abi.ActorID, si storiface.PostSectorChallenge, ppt abi.RegisteredPoStProof) ([]byte, error) { @@ -809,4 +947,27 @@ func (st *Local) GenerateSingleVanillaProof(ctx context.Context, minerID abi.Act } } +func (st *Local) GeneratePoRepVanillaProof(ctx context.Context, sr storiface.SectorRef, sealed, unsealed cid.Cid, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness) ([]byte, error) { + src, _, err := st.AcquireSector(ctx, sr, storiface.FTSealed|storiface.FTCache, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove) + if err != nil { + return nil, xerrors.Errorf("acquire sector: %w", err) + } + + if src.Sealed == "" || src.Cache == "" { + return nil, errPathNotFound + } + + ssize, err := sr.ProofType.SectorSize() + if err != nil { + return nil, xerrors.Errorf("getting sector size: %w", err) + } + + secPiece := []abi.PieceInfo{{ + Size: abi.PaddedPieceSize(ssize), + PieceCID: unsealed, + }} + + return ffi.SealCommitPhase1(sr.ProofType, sealed, unsealed, src.Cache, src.Sealed, sr.ID.Number, sr.ID.Miner, ticket, seed, secPiece) +} + var _ Store = &Local{} diff --git a/storage/paths/mocks/index.go b/storage/paths/mocks/index.go index 6fdcb03b9ec..1835661ff5c 100644 --- a/storage/paths/mocks/index.go +++ b/storage/paths/mocks/index.go @@ -54,18 +54,18 @@ func (mr *MockSectorIndexMockRecorder) StorageAttach(arg0, arg1, arg2 interface{ } // StorageBestAlloc mocks base method. -func (m *MockSectorIndex) StorageBestAlloc(arg0 context.Context, arg1 storiface.SectorFileType, arg2 abi.SectorSize, arg3 storiface.PathType) ([]storiface.StorageInfo, error) { +func (m *MockSectorIndex) StorageBestAlloc(arg0 context.Context, arg1 storiface.SectorFileType, arg2 abi.SectorSize, arg3 storiface.PathType, arg4 abi.ActorID) ([]storiface.StorageInfo, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StorageBestAlloc", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "StorageBestAlloc", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].([]storiface.StorageInfo) ret1, _ := ret[1].(error) return ret0, ret1 } // StorageBestAlloc indicates an expected call of StorageBestAlloc. -func (mr *MockSectorIndexMockRecorder) StorageBestAlloc(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockSectorIndexMockRecorder) StorageBestAlloc(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageBestAlloc", reflect.TypeOf((*MockSectorIndex)(nil).StorageBestAlloc), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StorageBestAlloc", reflect.TypeOf((*MockSectorIndex)(nil).StorageBestAlloc), arg0, arg1, arg2, arg3, arg4) } // StorageDeclareSector mocks base method. diff --git a/storage/paths/mocks/store.go b/storage/paths/mocks/store.go index 72be4832378..1224e6b571f 100644 --- a/storage/paths/mocks/store.go +++ b/storage/paths/mocks/store.go @@ -9,6 +9,7 @@ import ( reflect "reflect" gomock "github.com/golang/mock/gomock" + cid "github.com/ipfs/go-cid" abi "github.com/filecoin-project/go-state-types/abi" @@ -40,9 +41,13 @@ func (m *MockStore) EXPECT() *MockStoreMockRecorder { } // AcquireSector mocks base method. -func (m *MockStore) AcquireSector(arg0 context.Context, arg1 storiface.SectorRef, arg2, arg3 storiface.SectorFileType, arg4 storiface.PathType, arg5 storiface.AcquireMode) (storiface.SectorPaths, storiface.SectorPaths, error) { +func (m *MockStore) AcquireSector(arg0 context.Context, arg1 storiface.SectorRef, arg2, arg3 storiface.SectorFileType, arg4 storiface.PathType, arg5 storiface.AcquireMode, arg6 ...storiface.AcquireOption) (storiface.SectorPaths, storiface.SectorPaths, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AcquireSector", arg0, arg1, arg2, arg3, arg4, arg5) + varargs := []interface{}{arg0, arg1, arg2, arg3, arg4, arg5} + for _, a := range arg6 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "AcquireSector", varargs...) ret0, _ := ret[0].(storiface.SectorPaths) ret1, _ := ret[1].(storiface.SectorPaths) ret2, _ := ret[2].(error) @@ -50,9 +55,10 @@ func (m *MockStore) AcquireSector(arg0 context.Context, arg1 storiface.SectorRef } // AcquireSector indicates an expected call of AcquireSector. -func (mr *MockStoreMockRecorder) AcquireSector(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) AcquireSector(arg0, arg1, arg2, arg3, arg4, arg5 interface{}, arg6 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcquireSector", reflect.TypeOf((*MockStore)(nil).AcquireSector), arg0, arg1, arg2, arg3, arg4, arg5) + varargs := append([]interface{}{arg0, arg1, arg2, arg3, arg4, arg5}, arg6...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcquireSector", reflect.TypeOf((*MockStore)(nil).AcquireSector), varargs...) } // FsStat mocks base method. @@ -70,6 +76,21 @@ func (mr *MockStoreMockRecorder) FsStat(arg0, arg1 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FsStat", reflect.TypeOf((*MockStore)(nil).FsStat), arg0, arg1) } +// GeneratePoRepVanillaProof mocks base method. +func (m *MockStore) GeneratePoRepVanillaProof(arg0 context.Context, arg1 storiface.SectorRef, arg2, arg3 cid.Cid, arg4 abi.SealRandomness, arg5 abi.InteractiveSealRandomness) ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GeneratePoRepVanillaProof", arg0, arg1, arg2, arg3, arg4, arg5) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GeneratePoRepVanillaProof indicates an expected call of GeneratePoRepVanillaProof. +func (mr *MockStoreMockRecorder) GeneratePoRepVanillaProof(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GeneratePoRepVanillaProof", reflect.TypeOf((*MockStore)(nil).GeneratePoRepVanillaProof), arg0, arg1, arg2, arg3, arg4, arg5) +} + // GenerateSingleVanillaProof mocks base method. func (m *MockStore) GenerateSingleVanillaProof(arg0 context.Context, arg1 abi.ActorID, arg2 storiface.PostSectorChallenge, arg3 abi.RegisteredPoStProof) ([]byte, error) { m.ctrl.T.Helper() @@ -86,17 +107,22 @@ func (mr *MockStoreMockRecorder) GenerateSingleVanillaProof(arg0, arg1, arg2, ar } // MoveStorage mocks base method. -func (m *MockStore) MoveStorage(arg0 context.Context, arg1 storiface.SectorRef, arg2 storiface.SectorFileType) error { +func (m *MockStore) MoveStorage(arg0 context.Context, arg1 storiface.SectorRef, arg2 storiface.SectorFileType, arg3 ...storiface.AcquireOption) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MoveStorage", arg0, arg1, arg2) + varargs := []interface{}{arg0, arg1, arg2} + for _, a := range arg3 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "MoveStorage", varargs...) ret0, _ := ret[0].(error) return ret0 } // MoveStorage indicates an expected call of MoveStorage. -func (mr *MockStoreMockRecorder) MoveStorage(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockStoreMockRecorder) MoveStorage(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MoveStorage", reflect.TypeOf((*MockStore)(nil).MoveStorage), arg0, arg1, arg2) + varargs := append([]interface{}{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MoveStorage", reflect.TypeOf((*MockStore)(nil).MoveStorage), varargs...) } // Remove mocks base method. diff --git a/storage/paths/remote.go b/storage/paths/remote.go index 0b7563bb251..ab27548632c 100644 --- a/storage/paths/remote.go +++ b/storage/paths/remote.go @@ -17,6 +17,7 @@ import ( "time" "github.com/hashicorp/go-multierror" + "github.com/ipfs/go-cid" "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" @@ -92,11 +93,28 @@ func NewRemote(local Store, index SectorIndex, auth http.Header, fetchLimit int, } } -func (r *Remote) AcquireSector(ctx context.Context, s storiface.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, pathType storiface.PathType, op storiface.AcquireMode) (storiface.SectorPaths, storiface.SectorPaths, error) { +func (r *Remote) AcquireSector(ctx context.Context, s storiface.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, pathType storiface.PathType, op storiface.AcquireMode, opts ...storiface.AcquireOption) (storiface.SectorPaths, storiface.SectorPaths, error) { if existing|allocate != existing^allocate { return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.New("can't both find and allocate a sector") } + settings := storiface.AcquireSettings{ + // Into will tell us which paths things should be fetched into or allocated in. + Into: nil, + } + for _, o := range opts { + o(&settings) + } + + if settings.Into != nil { + if !allocate.IsNone() { + return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.New("cannot specify Into with allocate") + } + if !settings.Into.HasAllSet(existing) { + return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.New("Into has to have all existing paths") + } + } + // First make sure that no other goroutines are trying to fetch this sector; // wait if there are any. for { @@ -133,47 +151,47 @@ func (r *Remote) AcquireSector(ctx context.Context, s storiface.SectorRef, exist } var toFetch storiface.SectorFileType - for _, fileType := range storiface.PathTypes { - if fileType&existing == 0 { - continue - } - + for _, fileType := range existing.AllSet() { if storiface.PathByType(paths, fileType) == "" { toFetch |= fileType } } // get a list of paths to fetch data into. Note: file type filters will apply inside this call. - fetchPaths, ids, err := r.local.AcquireSector(ctx, s, storiface.FTNone, toFetch, pathType, op) - if err != nil { - return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.Errorf("allocate local sector for fetching: %w", err) - } - - overheadTable := storiface.FSOverheadSeal - if pathType == storiface.PathStorage { - overheadTable = storiface.FsOverheadFinalized - } + var fetchPaths, fetchIDs storiface.SectorPaths - // If any path types weren't found in local storage, try fetching them + if settings.Into == nil { + // fetching without existing reservation, so allocate paths and create a reservation + fetchPaths, fetchIDs, err = r.local.AcquireSector(ctx, s, storiface.FTNone, toFetch, pathType, op) + if err != nil { + return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.Errorf("allocate local sector for fetching: %w", err) + } - // First reserve storage - releaseStorage, err := r.local.Reserve(ctx, s, toFetch, ids, overheadTable) - if err != nil { - return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.Errorf("reserving storage space: %w", err) - } - defer releaseStorage() + log.Debugw("Fetching sector data without existing reservation", "sector", s, "toFetch", toFetch, "fetchPaths", fetchPaths, "fetchIDs", fetchIDs) - for _, fileType := range storiface.PathTypes { - if fileType&existing == 0 { - continue + overheadTable := storiface.FSOverheadSeal + if pathType == storiface.PathStorage { + overheadTable = storiface.FsOverheadFinalized } - if storiface.PathByType(paths, fileType) != "" { - continue + // If any path types weren't found in local storage, try fetching them + + // First reserve storage + releaseStorage, err := r.local.Reserve(ctx, s, toFetch, fetchIDs, overheadTable) + if err != nil { + return storiface.SectorPaths{}, storiface.SectorPaths{}, xerrors.Errorf("reserving storage space: %w", err) } + defer releaseStorage() + } else { + fetchPaths = settings.Into.Paths + fetchIDs = settings.Into.IDs + log.Debugw("Fetching sector data with existing reservation", "sector", s, "toFetch", toFetch, "fetchPaths", fetchPaths, "fetchIDs", fetchIDs) + } + + for _, fileType := range toFetch.AllSet() { dest := storiface.PathByType(fetchPaths, fileType) - storageID := storiface.PathByType(ids, fileType) + storageID := storiface.PathByType(fetchIDs, fileType) url, err := r.acquireFromRemote(ctx, s.ID, fileType, dest) if err != nil { @@ -307,14 +325,14 @@ func (r *Remote) checkAllocated(ctx context.Context, url string, spt abi.Registe } } -func (r *Remote) MoveStorage(ctx context.Context, s storiface.SectorRef, types storiface.SectorFileType) error { +func (r *Remote) MoveStorage(ctx context.Context, s storiface.SectorRef, types storiface.SectorFileType, opts ...storiface.AcquireOption) error { // Make sure we have the data local - _, _, err := r.AcquireSector(ctx, s, types, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove) + _, _, err := r.AcquireSector(ctx, s, types, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove, opts...) if err != nil { return xerrors.Errorf("acquire src storage (remote): %w", err) } - return r.local.MoveStorage(ctx, s, types) + return r.local.MoveStorage(ctx, s, types, opts...) } func (r *Remote) Remove(ctx context.Context, sid abi.SectorID, typ storiface.SectorFileType, force bool, keepIn []storiface.ID) error { @@ -397,16 +415,30 @@ func (r *Remote) FsStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, er return fsutil.FsStat{}, xerrors.Errorf("no known URLs for remote storage %s", id) } - rl, err := url.Parse(si.URLs[0]) + for _, urlStr := range si.URLs { + out, err := r.StatUrl(ctx, urlStr, id) + if err != nil { + log.Warnw("stat url failed", "url", urlStr, "error", err) + continue + } + + return out, nil + } + + return fsutil.FsStat{}, xerrors.Errorf("all endpoints failed for remote storage %s", id) +} + +func (r *Remote) StatUrl(ctx context.Context, urlStr string, id storiface.ID) (fsutil.FsStat, error) { + rl, err := url.Parse(urlStr) if err != nil { - return fsutil.FsStat{}, xerrors.Errorf("failed to parse url: %w", err) + return fsutil.FsStat{}, xerrors.Errorf("parsing URL: %w", err) } rl.Path = gopath.Join(rl.Path, "stat", string(id)) req, err := http.NewRequest("GET", rl.String(), nil) if err != nil { - return fsutil.FsStat{}, xerrors.Errorf("request: %w", err) + return fsutil.FsStat{}, xerrors.Errorf("creating request failed: %w", err) } req.Header = r.auth req = req.WithContext(ctx) @@ -415,28 +447,22 @@ func (r *Remote) FsStat(ctx context.Context, id storiface.ID) (fsutil.FsStat, er if err != nil { return fsutil.FsStat{}, xerrors.Errorf("do request: %w", err) } - switch resp.StatusCode { - case 200: - break - case 404: - return fsutil.FsStat{}, errPathNotFound - case 500: - b, err := io.ReadAll(resp.Body) - if err != nil { - return fsutil.FsStat{}, xerrors.Errorf("fsstat: got http 500, then failed to read the error: %w", err) - } - return fsutil.FsStat{}, xerrors.Errorf("fsstat: got http 500: %s", string(b)) + if resp.StatusCode == 200 { + var out fsutil.FsStat + if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { + _ = resp.Body.Close() + return fsutil.FsStat{}, xerrors.Errorf("decoding response failed: %w", err) + } + _ = resp.Body.Close() + return out, nil // Successfully decoded, return the result } - var out fsutil.FsStat - if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { - return fsutil.FsStat{}, xerrors.Errorf("decoding fsstat: %w", err) - } + // non-200 status code + b, _ := io.ReadAll(resp.Body) // Best-effort read the body for logging + _ = resp.Body.Close() - defer resp.Body.Close() // nolint - - return out, nil + return fsutil.FsStat{}, xerrors.Errorf("endpoint failed %s: %d %s", rl.String(), resp.StatusCode, string(b)) } func (r *Remote) readRemote(ctx context.Context, url string, offset, size abi.PaddedPieceSize) (io.ReadCloser, error) { @@ -744,6 +770,48 @@ func (r *Remote) Reader(ctx context.Context, s storiface.SectorRef, offset, size return nil, nil } +// ReaderSeq creates a simple sequential reader for a file. Does not work for +// file types which are a directory (e.g. FTCache). +func (r *Remote) ReaderSeq(ctx context.Context, s storiface.SectorRef, ft storiface.SectorFileType) (io.ReadCloser, error) { + paths, _, err := r.local.AcquireSector(ctx, s, ft, storiface.FTNone, storiface.PathStorage, storiface.AcquireMove) + if err != nil { + return nil, xerrors.Errorf("acquire local: %w", err) + } + + path := storiface.PathByType(paths, ft) + if path != "" { + return os.Open(path) + } + + si, err := r.index.StorageFindSector(ctx, s.ID, ft, 0, false) + if err != nil { + log.Debugf("Reader, did not find file on any of the workers %s (%s)", path, ft.String()) + return nil, err + } + + if len(si) == 0 { + return nil, xerrors.Errorf("failed to read sector %v from remote(%d): %w", s, ft, storiface.ErrSectorNotFound) + } + + sort.Slice(si, func(i, j int) bool { + return si[i].Weight > si[j].Weight + }) + + for _, info := range si { + for _, url := range info.URLs { + rd, err := r.readRemote(ctx, url, 0, 0) + if err != nil { + log.Warnw("reading from remote", "url", url, "error", err) + continue + } + + return rd, err + } + } + + return nil, xerrors.Errorf("failed to read sector %v from remote(%d): %w", s, ft, storiface.ErrSectorNotFound) +} + func (r *Remote) Reserve(ctx context.Context, sid storiface.SectorRef, ft storiface.SectorFileType, storageIDs storiface.SectorPaths, overheadTab map[storiface.SectorFileType]int) (func(), error) { log.Warnf("reserve called on remote store, sectorID: %v", sid.ID) return func() { @@ -782,13 +850,17 @@ func (r *Remote) GenerateSingleVanillaProof(ctx context.Context, minerID abi.Act return nil, err } + merr := xerrors.Errorf("sector not found") + for _, info := range si { for _, u := range info.BaseURLs { url := fmt.Sprintf("%s/vanilla/single", u) req, err := http.NewRequest("POST", url, strings.NewReader(string(jreq))) if err != nil { - return nil, xerrors.Errorf("request: %w", err) + merr = multierror.Append(merr, xerrors.Errorf("request: %w", err)) + log.Warnw("GenerateSingleVanillaProof request failed", "url", url, "error", err) + continue } if r.auth != nil { @@ -798,7 +870,9 @@ func (r *Remote) GenerateSingleVanillaProof(ctx context.Context, minerID abi.Act resp, err := http.DefaultClient.Do(req) if err != nil { - return nil, xerrors.Errorf("do request: %w", err) + merr = multierror.Append(merr, xerrors.Errorf("do request: %w", err)) + log.Warnw("GenerateSingleVanillaProof do request failed", "url", url, "error", err) + continue } if resp.StatusCode != http.StatusOK { @@ -808,14 +882,18 @@ func (r *Remote) GenerateSingleVanillaProof(ctx context.Context, minerID abi.Act } body, err := io.ReadAll(resp.Body) if err != nil { - return nil, xerrors.Errorf("resp.Body ReadAll: %w", err) + merr = multierror.Append(merr, xerrors.Errorf("resp.Body ReadAll: %w", err)) + log.Warnw("GenerateSingleVanillaProof read response body failed", "url", url, "error", err) + continue } if err := resp.Body.Close(); err != nil { log.Error("response close: ", err) } - return nil, xerrors.Errorf("non-200 code from %s: '%s'", url, strings.TrimSpace(string(body))) + merr = multierror.Append(merr, xerrors.Errorf("non-200 code from %s: '%s'", url, strings.TrimSpace(string(body)))) + log.Warnw("GenerateSingleVanillaProof non-200 code from remote", "code", resp.StatusCode, "url", url, "body", string(body)) + continue } body, err := io.ReadAll(resp.Body) @@ -824,17 +902,109 @@ func (r *Remote) GenerateSingleVanillaProof(ctx context.Context, minerID abi.Act log.Error("response close: ", err) } - return nil, xerrors.Errorf("resp.Body ReadAll: %w", err) + merr = multierror.Append(merr, xerrors.Errorf("resp.Body ReadAll: %w", err)) + log.Warnw("GenerateSingleVanillaProof read response body failed", "url", url, "error", err) + continue } + _ = resp.Body.Close() + return body, nil } } - return nil, xerrors.Errorf("sector not found") + return nil, merr } -var _ Store = &Remote{} +func (r *Remote) GeneratePoRepVanillaProof(ctx context.Context, sr storiface.SectorRef, sealed, unsealed cid.Cid, ticket abi.SealRandomness, seed abi.InteractiveSealRandomness) ([]byte, error) { + // Attempt to generate the proof locally first + p, err := r.local.GeneratePoRepVanillaProof(ctx, sr, sealed, unsealed, ticket, seed) + if err != errPathNotFound { + return p, err + } + + // Define the file types to look for based on the sector's state + ft := storiface.FTSealed | storiface.FTCache + + // Find sector information + si, err := r.index.StorageFindSector(ctx, sr.ID, ft, 0, false) + if err != nil { + return nil, xerrors.Errorf("finding sector %d failed: %w", sr.ID, err) + } + + // Prepare request parameters + requestParams := PoRepVanillaParams{ + Sector: sr, + Sealed: sealed, + Unsealed: unsealed, + Ticket: ticket, + Seed: seed, + } + jreq, err := json.Marshal(requestParams) + if err != nil { + return nil, err + } + + merr := xerrors.Errorf("sector not found") + + // Iterate over all found sector locations + for _, info := range si { + for _, u := range info.BaseURLs { + url := fmt.Sprintf("%s/vanilla/porep", u) + + // Create and send the request + req, err := http.NewRequest("POST", url, strings.NewReader(string(jreq))) + if err != nil { + merr = multierror.Append(merr, xerrors.Errorf("request: %w", err)) + log.Warnw("GeneratePoRepVanillaProof request failed", "url", url, "error", err) + continue + } + + // Set auth headers if available + if r.auth != nil { + req.Header = r.auth.Clone() + } + req = req.WithContext(ctx) + + // Execute the request + resp, err := http.DefaultClient.Do(req) + if err != nil { + merr = multierror.Append(merr, xerrors.Errorf("do request: %w", err)) + log.Warnw("GeneratePoRepVanillaProof do request failed", "url", url, "error", err) + continue + } + + // Handle non-OK status codes + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + _ = resp.Body.Close() + + if resp.StatusCode == http.StatusNotFound { + log.Debugw("reading vanilla proof from remote not-found response", "url", url, "store", info.ID) + continue + } + + merr = multierror.Append(merr, xerrors.Errorf("non-200 code from %s: '%s'", url, strings.TrimSpace(string(body)))) + log.Warnw("GeneratePoRepVanillaProof non-200 code from remote", "code", resp.StatusCode, "url", url, "body", string(body)) + continue + } + + // Read the response body + body, err := io.ReadAll(resp.Body) + if err != nil { + merr = multierror.Append(merr, xerrors.Errorf("resp.Body ReadAll: %w", err)) + log.Warnw("GeneratePoRepVanillaProof read response body failed", "url", url, "error", err) + } + _ = resp.Body.Close() + + // Return the proof if successful + return body, nil + } + } + + // Return the accumulated error if the proof was not generated + return nil, merr +} type funcCloser func() error diff --git a/storage/pipeline/commit_batch.go b/storage/pipeline/commit_batch.go index d702d307884..ba09ef38f50 100644 --- a/storage/pipeline/commit_batch.go +++ b/storage/pipeline/commit_batch.go @@ -16,6 +16,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" + verifregtypes "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-state-types/proof" @@ -46,6 +47,7 @@ type CommitBatcherApi interface { StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (big.Int, error) StateNetworkVersion(ctx context.Context, tsk types.TipSetKey) (network.Version, error) StateMinerAvailableBalance(context.Context, address.Address, types.TipSetKey) (big.Int, error) + StateGetAllocation(ctx context.Context, clientAddr address.Address, allocationId verifregtypes.AllocationId, tsk types.TipSetKey) (*verifregtypes.Allocation, error) // Address selector WalletBalance(context.Context, address.Address) (types.BigInt, error) @@ -348,6 +350,11 @@ func (b *CommitBatcher) processBatchV2(cfg sealiface.Config, sectors []abi.Secto infos := make([]proof.AggregateSealVerifyInfo, 0, total) collateral := big.Zero() + mid, err := address.IDFromAddress(b.maddr) + if err != nil { + return nil, err + } + for _, sector := range sectors { if b.todo[sector].DealIDPrecommit { // can't process sectors precommitted with deal IDs with ProveCommitSectors2 @@ -364,6 +371,20 @@ func (b *CommitBatcher) processBatchV2(cfg sealiface.Config, sectors []abi.Secto collateral = big.Add(collateral, sc) + manifest := b.todo[sector].ActivationManifest + if len(manifest.Pieces) > 0 { + precomitInfo, err := b.api.StateSectorPreCommitInfo(b.mctx, b.maddr, sector, ts.Key()) + if err != nil { + res.FailedSectors[sector] = err.Error() + continue + } + err = b.allocationCheck(manifest.Pieces, precomitInfo, abi.ActorID(mid), ts) + if err != nil { + res.FailedSectors[sector] = err.Error() + continue + } + } + params.SectorActivations = append(params.SectorActivations, b.todo[sector].ActivationManifest) params.SectorProofs = append(params.SectorProofs, b.todo[sector].Proof) @@ -449,9 +470,9 @@ func (b *CommitBatcher) processBatchV2(cfg sealiface.Config, sectors []abi.Secto _, err = simulateMsgGas(b.mctx, b.api, from, b.maddr, builtin.MethodsMiner.ProveCommitSectors3, needFunds, maxFee, enc.Bytes()) if err != nil && (!api.ErrorIsIn(err, []error{&api.ErrOutOfGas{}}) || len(sectors) < miner.MinAggregatedSectors*2) { - log.Errorf("simulating CommitBatch message failed (%x): %s", enc.Bytes(), err) + log.Errorf("simulating CommitBatch %s", err) res.Error = err.Error() - return []sealiface.CommitBatchRes{res}, xerrors.Errorf("simulating CommitBatch message failed: %w", err) + return []sealiface.CommitBatchRes{res}, xerrors.Errorf("simulating CommitBatch %w", err) } msgTooLarge := len(enc.Bytes()) > (messagepool.MaxMessageSize - 128) @@ -590,9 +611,9 @@ func (b *CommitBatcher) processBatchV1(cfg sealiface.Config, sectors []abi.Secto _, err = simulateMsgGas(b.mctx, b.api, from, b.maddr, builtin.MethodsMiner.ProveCommitAggregate, needFunds, maxFee, enc.Bytes()) if err != nil && (!api.ErrorIsIn(err, []error{&api.ErrOutOfGas{}}) || len(sectors) < miner.MinAggregatedSectors*2) { - log.Errorf("simulating CommitBatch message failed (%x): %s", enc.Bytes(), err) + log.Errorf("simulating CommitBatch %s", err) res.Error = err.Error() - return []sealiface.CommitBatchRes{res}, xerrors.Errorf("simulating CommitBatch message failed: %w", err) + return []sealiface.CommitBatchRes{res}, xerrors.Errorf("simulating CommitBatch %w", err) } // If we're out of gas, split the batch in half and evaluate again @@ -841,7 +862,7 @@ func (b *CommitBatcher) getCommitCutoff(si SectorInfo) (time.Time, error) { } av, err := actorstypes.VersionForNetwork(nv) if err != nil { - log.Errorf("unsupported network vrsion: %s", err) + log.Errorf("unsupported network version: %s", err) return time.Now(), err } mpcd, err := policy.GetMaxProveCommitDuration(av, si.SectorType) @@ -901,3 +922,38 @@ func (b *CommitBatcher) aggregateProofType(nv network.Version) (abi.RegisteredAg } return abi.RegisteredAggregationProof_SnarkPackV2, nil } + +func (b *CommitBatcher) allocationCheck(Pieces []miner.PieceActivationManifest, precomitInfo *miner.SectorPreCommitOnChainInfo, miner abi.ActorID, ts *types.TipSet) error { + for _, p := range Pieces { + p := p + // skip pieces not claiming an allocation + if p.VerifiedAllocationKey == nil { + continue + } + addr, err := address.NewIDAddress(uint64(p.VerifiedAllocationKey.Client)) + if err != nil { + return err + } + + alloc, err := b.api.StateGetAllocation(b.mctx, addr, verifregtypes.AllocationId(p.VerifiedAllocationKey.ID), ts.Key()) + if err != nil { + return err + } + if alloc == nil { + return xerrors.Errorf("no allocation found for piece %s with allocation ID %d", p.CID.String(), p.VerifiedAllocationKey.ID) + } + if alloc.Provider != miner { + return xerrors.Errorf("provider id mismatch for piece %s: expected %d and found %d", p.CID.String(), miner, alloc.Provider) + } + if alloc.Size != p.Size { + return xerrors.Errorf("size mismatch for piece %s: expected %d and found %d", p.CID.String(), p.Size, alloc.Size) + } + if precomitInfo.Info.Expiration < ts.Height()+alloc.TermMin { + return xerrors.Errorf("sector expiration %d is before than allocation TermMin %d for piece %s", precomitInfo.Info.Expiration, ts.Height()+alloc.TermMin, p.CID.String()) + } + if precomitInfo.Info.Expiration > ts.Height()+alloc.TermMax { + return xerrors.Errorf("sector expiration %d is later than allocation TermMax %d for piece %s", precomitInfo.Info.Expiration, ts.Height()+alloc.TermMax, p.CID.String()) + } + } + return nil +} diff --git a/storage/pipeline/fsm_events.go b/storage/pipeline/fsm_events.go index 94cd53e829d..63ebdb9d5b6 100644 --- a/storage/pipeline/fsm_events.go +++ b/storage/pipeline/fsm_events.go @@ -21,7 +21,7 @@ type mutator interface { // globalMutator is an event which can apply in every state type globalMutator interface { - // applyGlobal applies the event to the state. If if returns true, + // applyGlobal applies the event to the state. If it returns true, // event processing should be interrupted applyGlobal(state *SectorInfo) bool } diff --git a/storage/pipeline/input.go b/storage/pipeline/input.go index 6d41f7e81b3..8862380d8f6 100644 --- a/storage/pipeline/input.go +++ b/storage/pipeline/input.go @@ -655,7 +655,6 @@ func (m *Sealing) updateInput(ctx context.Context, sp abi.RegisteredSealProof) e log.Debugw("updateInput matching done", "matches", len(matches), "toAssign", len(toAssign), "assigned", assigned, "openSectors", len(m.openSectors), "pieces", len(m.pendingPieces)) if len(toAssign) > 0 { - log.Errorf("we are trying to create a new sector with open sectors %v", m.openSectors) if err := m.tryGetDealSector(ctx, sp, getExpirationCached); err != nil { log.Errorw("Failed to create a new sector for deals", "error", err) } diff --git a/storage/pipeline/mocks/api.go b/storage/pipeline/mocks/api.go index a4f1cd9ef0f..3990f1a2fd3 100644 --- a/storage/pipeline/mocks/api.go +++ b/storage/pipeline/mocks/api.go @@ -16,14 +16,15 @@ import ( bitfield "github.com/filecoin-project/go-bitfield" abi "github.com/filecoin-project/go-state-types/abi" big "github.com/filecoin-project/go-state-types/big" - miner "github.com/filecoin-project/go-state-types/builtin/v9/miner" + miner "github.com/filecoin-project/go-state-types/builtin/v13/miner" + miner0 "github.com/filecoin-project/go-state-types/builtin/v9/miner" verifreg "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" crypto "github.com/filecoin-project/go-state-types/crypto" dline "github.com/filecoin-project/go-state-types/dline" network "github.com/filecoin-project/go-state-types/network" api "github.com/filecoin-project/lotus/api" - miner0 "github.com/filecoin-project/lotus/chain/actors/builtin/miner" + miner1 "github.com/filecoin-project/lotus/chain/actors/builtin/miner" types "github.com/filecoin-project/lotus/chain/types" ) @@ -350,7 +351,7 @@ func (mr *MockSealingAPIMockRecorder) StateMinerInfo(arg0, arg1, arg2 interface{ } // StateMinerInitialPledgeCollateral mocks base method. -func (m *MockSealingAPI) StateMinerInitialPledgeCollateral(arg0 context.Context, arg1 address.Address, arg2 miner.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { +func (m *MockSealingAPI) StateMinerInitialPledgeCollateral(arg0 context.Context, arg1 address.Address, arg2 miner0.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateMinerInitialPledgeCollateral", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(big.Int) @@ -380,7 +381,7 @@ func (mr *MockSealingAPIMockRecorder) StateMinerPartitions(arg0, arg1, arg2, arg } // StateMinerPreCommitDepositForPower mocks base method. -func (m *MockSealingAPI) StateMinerPreCommitDepositForPower(arg0 context.Context, arg1 address.Address, arg2 miner.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { +func (m *MockSealingAPI) StateMinerPreCommitDepositForPower(arg0 context.Context, arg1 address.Address, arg2 miner0.SectorPreCommitInfo, arg3 types.TipSetKey) (big.Int, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateMinerPreCommitDepositForPower", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(big.Int) @@ -470,10 +471,10 @@ func (mr *MockSealingAPIMockRecorder) StateSectorGetInfo(arg0, arg1, arg2, arg3 } // StateSectorPartition mocks base method. -func (m *MockSealingAPI) StateSectorPartition(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner0.SectorLocation, error) { +func (m *MockSealingAPI) StateSectorPartition(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner1.SectorLocation, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateSectorPartition", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(*miner0.SectorLocation) + ret0, _ := ret[0].(*miner1.SectorLocation) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -485,10 +486,10 @@ func (mr *MockSealingAPIMockRecorder) StateSectorPartition(arg0, arg1, arg2, arg } // StateSectorPreCommitInfo mocks base method. -func (m *MockSealingAPI) StateSectorPreCommitInfo(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner.SectorPreCommitOnChainInfo, error) { +func (m *MockSealingAPI) StateSectorPreCommitInfo(arg0 context.Context, arg1 address.Address, arg2 abi.SectorNumber, arg3 types.TipSetKey) (*miner0.SectorPreCommitOnChainInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StateSectorPreCommitInfo", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(*miner.SectorPreCommitOnChainInfo) + ret0, _ := ret[0].(*miner0.SectorPreCommitOnChainInfo) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/storage/pipeline/mocks/mock_commit_batcher.go b/storage/pipeline/mocks/mock_commit_batcher.go index 431a47c73d9..e2fce1eca01 100644 --- a/storage/pipeline/mocks/mock_commit_batcher.go +++ b/storage/pipeline/mocks/mock_commit_batcher.go @@ -14,6 +14,7 @@ import ( abi "github.com/filecoin-project/go-state-types/abi" big "github.com/filecoin-project/go-state-types/big" miner "github.com/filecoin-project/go-state-types/builtin/v9/miner" + verifreg "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" network "github.com/filecoin-project/go-state-types/network" api "github.com/filecoin-project/lotus/api" @@ -103,6 +104,21 @@ func (mr *MockCommitBatcherApiMockRecorder) StateAccountKey(arg0, arg1, arg2 int return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateAccountKey", reflect.TypeOf((*MockCommitBatcherApi)(nil).StateAccountKey), arg0, arg1, arg2) } +// StateGetAllocation mocks base method. +func (m *MockCommitBatcherApi) StateGetAllocation(arg0 context.Context, arg1 address.Address, arg2 verifreg.AllocationId, arg3 types.TipSetKey) (*verifreg.Allocation, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateGetAllocation", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*verifreg.Allocation) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// StateGetAllocation indicates an expected call of StateGetAllocation. +func (mr *MockCommitBatcherApiMockRecorder) StateGetAllocation(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateGetAllocation", reflect.TypeOf((*MockCommitBatcherApi)(nil).StateGetAllocation), arg0, arg1, arg2, arg3) +} + // StateLookupID mocks base method. func (m *MockCommitBatcherApi) StateLookupID(arg0 context.Context, arg1 address.Address, arg2 types.TipSetKey) (address.Address, error) { m.ctrl.T.Helper() diff --git a/storage/pipeline/precommit_batch.go b/storage/pipeline/precommit_batch.go index 099988010db..55bead59037 100644 --- a/storage/pipeline/precommit_batch.go +++ b/storage/pipeline/precommit_batch.go @@ -291,7 +291,7 @@ func (b *PreCommitBatcher) processPreCommitBatch(cfg sealiface.Config, bf abi.To if err != nil && (!api.ErrorIsIn(err, []error{&api.ErrOutOfGas{}}) || len(entries) == 1) { res.Error = err.Error() - return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("simulating PreCommitBatch message failed: %w", err) + return []sealiface.PreCommitBatchRes{res}, xerrors.Errorf("simulating PreCommitBatch %w", err) } // If we're out of gas, split the batch in half and evaluate again diff --git a/storage/pipeline/states_replica_update.go b/storage/pipeline/states_replica_update.go index a0d92891cd2..85e3fabee79 100644 --- a/storage/pipeline/states_replica_update.go +++ b/storage/pipeline/states_replica_update.go @@ -174,6 +174,7 @@ func (m *Sealing) handleSubmitReplicaUpdate(ctx statemachine.Context, sector Sec nv, err := m.Api.StateNetworkVersion(ctx.Context(), ts.Key()) if err != nil { log.Errorf("failed to get network version: %+v", err) + return ctx.Send(SectorSubmitReplicaUpdateFailed{}) } pams, deals, err := m.processPieces(ctx.Context(), sector, nv >= network.Version22) diff --git a/storage/pipeline/utils.go b/storage/pipeline/utils.go index 4b99a5beadd..ac519b6acef 100644 --- a/storage/pipeline/utils.go +++ b/storage/pipeline/utils.go @@ -1,7 +1,9 @@ package sealing import ( + "bytes" "context" + "fmt" "math/bits" "github.com/ipfs/go-cid" @@ -105,7 +107,17 @@ func simulateMsgGas(ctx context.Context, sa interface { Params: params, } - return sa.GasEstimateMessageGas(ctx, &msg, nil, types.EmptyTSK) + var b bytes.Buffer + err := msg.MarshalCBOR(&b) + if err != nil { + return nil, xerrors.Errorf("failed to unmarshal the signed message: %w", err) + } + + gmsg, err := sa.GasEstimateMessageGas(ctx, &msg, nil, types.EmptyTSK) + if err != nil { + err = fmt.Errorf("message %x failed: %w", b.Bytes(), err) + } + return gmsg, err } func sendMsg(ctx context.Context, sa interface { diff --git a/storage/sealer/README.md b/storage/sealer/README.md index 83fa3ea5f01..b90a9ebd0b7 100644 --- a/storage/sealer/README.md +++ b/storage/sealer/README.md @@ -1,7 +1,6 @@ # sector-storage [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) -[![CircleCI](https://circleci.com/gh/filecoin-project/sector-storage.svg?style=svg)](https://circleci.com/gh/filecoin-project/sector-storage) [![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) > a concrete implementation of the [specs-storage](https://github.com/filecoin-project/specs-storage) interface @@ -35,7 +34,7 @@ The Local store implements SectorProvider for paths mounted in the local filesystem. Paths can be shared between nodes, and support shared filesystems such as NFS. -stores.Local implements all native filesystem-related operations +stores.Local implements all native filesystem-related operations ### `paths.Remote` diff --git a/storage/sealer/ffiwrapper/basicfs/fs.go b/storage/sealer/ffiwrapper/basicfs/fs.go index 4fd8e271fdf..47c7f526e32 100644 --- a/storage/sealer/ffiwrapper/basicfs/fs.go +++ b/storage/sealer/ffiwrapper/basicfs/fs.go @@ -39,6 +39,9 @@ func (b *Provider) AcquireSector(ctx context.Context, id storiface.SectorRef, ex if err := os.Mkdir(filepath.Join(b.Root, storiface.FTUpdateCache.String()), 0755); err != nil && !os.IsExist(err) { // nolint return storiface.SectorPaths{}, nil, err } + if err := os.Mkdir(filepath.Join(b.Root, storiface.FTPiece.String()), 0755); err != nil && !os.IsExist(err) { // nolint + return storiface.SectorPaths{}, nil, err + } done := func() {} diff --git a/storage/sealer/ffiwrapper/sealer_cgo.go b/storage/sealer/ffiwrapper/sealer_cgo.go index 04e8916658c..f1613033150 100644 --- a/storage/sealer/ffiwrapper/sealer_cgo.go +++ b/storage/sealer/ffiwrapper/sealer_cgo.go @@ -520,7 +520,7 @@ func (sb *Sealer) regenerateSectorKey(ctx context.Context, sector storiface.Sect // prepare SDR params commp, err := commcid.CIDToDataCommitmentV1(keyDataCid) if err != nil { - return xerrors.Errorf("computing commP: %w", err) + return xerrors.Errorf("computing commK: %w", err) } replicaID, err := sector.ProofType.ReplicaId(sector.ID.Miner, sector.ID.Number, ticket, commp) diff --git a/storage/sealer/ffiwrapper/sealer_test.go b/storage/sealer/ffiwrapper/sealer_test.go index 59821e795a0..250d057e33f 100644 --- a/storage/sealer/ffiwrapper/sealer_test.go +++ b/storage/sealer/ffiwrapper/sealer_test.go @@ -37,7 +37,7 @@ import ( ) func init() { - logging.SetLogLevel("*", "DEBUG") //nolint: errcheck + _ = logging.SetLogLevel("*", "DEBUG") } var sealProofType = abi.RegisteredSealProof_StackedDrg2KiBV1 diff --git a/storage/sealer/fr32/fr32.go b/storage/sealer/fr32/fr32.go index 6f5be65b766..83a20597fa0 100644 --- a/storage/sealer/fr32/fr32.go +++ b/storage/sealer/fr32/fr32.go @@ -69,6 +69,10 @@ func Pad(in, out []byte) { pad(in, out) } +func PadSingle(in, out []byte) { + pad(in, out) +} + func pad(in, out []byte) { chunks := len(out) / 128 for chunk := 0; chunk < chunks; chunk++ { diff --git a/storage/sealer/manager.go b/storage/sealer/manager.go index 41b3a1b397a..00514c79eda 100644 --- a/storage/sealer/manager.go +++ b/storage/sealer/manager.go @@ -356,7 +356,7 @@ func (m *Manager) SectorsUnsealPiece(ctx context.Context, sector storiface.Secto // selector will schedule the Unseal task on a worker that either already has the sealed sector files or has space in // one of it's sealing scratch spaces to store them after fetching them from another worker. - selector := newExistingSelector(m.index, sector.ID, storiface.FTSealed|storiface.FTCache, true) + selector := newExistingSelector(m.index, sector.ID, storiface.FTSealed|storiface.FTCache, sector.ID.Miner, true) log.Debugf("will schedule unseal for sector %d", sector.ID) err = m.sched.Schedule(ctx, sector, sealtasks.TTUnseal, selector, unsealFetch, func(ctx context.Context, w Worker) error { @@ -377,7 +377,7 @@ func (m *Manager) SectorsUnsealPiece(ctx context.Context, sector storiface.Secto } // get a selector for moving unsealed sector into long-term storage - fetchSel := newMoveSelector(m.index, sector.ID, storiface.FTUnsealed, storiface.PathStorage, !m.disallowRemoteFinalize) + fetchSel := newMoveSelector(m.index, sector.ID, storiface.FTUnsealed, storiface.PathStorage, sector.ID.Miner, !m.disallowRemoteFinalize) // move unsealed sector to long-term storage // Possible TODO: Add an option to not keep the unsealed sector in long term storage? @@ -431,9 +431,9 @@ func (m *Manager) AddPiece(ctx context.Context, sector storiface.SectorRef, exis var selector WorkerSelector var err error if len(existingPieces) == 0 { // new - selector = newAllocSelector(m.index, storiface.FTUnsealed, storiface.PathSealing) + selector = newAllocSelector(m.index, storiface.FTUnsealed, storiface.PathSealing, sector.ID.Miner) } else { // use existing - selector = newExistingSelector(m.index, sector.ID, storiface.FTUnsealed, false) + selector = newExistingSelector(m.index, sector.ID, storiface.FTUnsealed, sector.ID.Miner, false) } var out abi.PieceInfo @@ -484,7 +484,7 @@ func (m *Manager) SealPreCommit1(ctx context.Context, sector storiface.SectorRef // TODO: also consider where the unsealed data sits - selector := newAllocSelector(m.index, storiface.FTCache|storiface.FTSealed, storiface.PathSealing) + selector := newAllocSelector(m.index, storiface.FTCache|storiface.FTSealed, storiface.PathSealing, sector.ID.Miner) err = m.sched.Schedule(ctx, sector, sealtasks.TTPreCommit1, selector, m.schedFetch(sector, storiface.FTUnsealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error { err := m.startWork(ctx, w, wk)(w.SealPreCommit1(ctx, sector, ticket, pieces)) @@ -533,7 +533,7 @@ func (m *Manager) SealPreCommit2(ctx context.Context, sector storiface.SectorRef return storiface.SectorCids{}, xerrors.Errorf("acquiring sector lock: %w", err) } - selector := newExistingSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, true) + selector := newExistingSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, sector.ID.Miner, true) err = m.sched.Schedule(ctx, sector, sealtasks.TTPreCommit2, selector, m.schedFetch(sector, storiface.FTCache|storiface.FTSealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error { err := m.startWork(ctx, w, wk)(w.SealPreCommit2(ctx, sector, phase1Out)) @@ -585,7 +585,7 @@ func (m *Manager) SealCommit1(ctx context.Context, sector storiface.SectorRef, t // NOTE: We set allowFetch to false in so that we always execute on a worker // with direct access to the data. We want to do that because this step is // generally very cheap / fast, and transferring data is not worth the effort - selector := newExistingSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, false) + selector := newExistingSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, sector.ID.Miner, false) err = m.sched.Schedule(ctx, sector, sealtasks.TTCommit1, selector, m.schedFetch(sector, storiface.FTCache|storiface.FTSealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error { err := m.startWork(ctx, w, wk)(w.SealCommit1(ctx, sector, ticket, seed, pieces, cids)) @@ -700,7 +700,7 @@ func (m *Manager) FinalizeSector(ctx context.Context, sector storiface.SectorRef // 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) + selector := newExistingSelector(m.index, sector.ID, storiface.FTCache, sector.ID.Miner, false) err = m.sched.Schedule(ctx, sector, sealtasks.TTFinalize, selector, m.schedFetch(sector, storiface.FTCache, cachePathType, storiface.AcquireMove), @@ -713,7 +713,7 @@ func (m *Manager) FinalizeSector(ctx context.Context, sector storiface.SectorRef } // get a selector for moving stuff into long-term storage - fetchSel := newMoveSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, storiface.PathStorage, !m.disallowRemoteFinalize) + fetchSel := newMoveSelector(m.index, sector.ID, storiface.FTCache|storiface.FTSealed, storiface.PathStorage, sector.ID.Miner, !m.disallowRemoteFinalize) // only move the unsealed file if it still exists and needs moving moveUnsealed := storiface.FTUnsealed @@ -769,7 +769,7 @@ func (m *Manager) FinalizeReplicaUpdate(ctx context.Context, sector storiface.Se // do the cache trimming wherever the likely still large cache lives. // we really don't want to move it. - selector := newExistingSelector(m.index, sector.ID, storiface.FTUpdateCache, false) + selector := newExistingSelector(m.index, sector.ID, storiface.FTUpdateCache, sector.ID.Miner, false) err := m.sched.Schedule(ctx, sector, sealtasks.TTFinalizeReplicaUpdate, selector, m.schedFetch(sector, storiface.FTCache|storiface.FTUpdateCache, pathType, storiface.AcquireMove), @@ -783,7 +783,7 @@ func (m *Manager) FinalizeReplicaUpdate(ctx context.Context, sector storiface.Se move := func(types storiface.SectorFileType) error { // get a selector for moving stuff into long-term storage - fetchSel := newMoveSelector(m.index, sector.ID, types, storiface.PathStorage, !m.disallowRemoteFinalize) + fetchSel := newMoveSelector(m.index, sector.ID, types, storiface.PathStorage, sector.ID.Miner, !m.disallowRemoteFinalize) err = m.sched.Schedule(ctx, sector, sealtasks.TTFetch, fetchSel, m.schedFetch(sector, types, storiface.PathStorage, storiface.AcquireMove), @@ -834,7 +834,7 @@ func (m *Manager) ReleaseUnsealed(ctx context.Context, sector storiface.SectorRe return nil } - selector := newExistingSelector(m.index, sector.ID, storiface.FTUnsealed, false) + selector := newExistingSelector(m.index, sector.ID, storiface.FTUnsealed, sector.ID.Miner, 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)) @@ -906,7 +906,7 @@ func (m *Manager) GenerateSectorKeyFromData(ctx context.Context, sector storifac // NOTE: We set allowFetch to false in so that we always execute on a worker // with direct access to the data. We want to do that because this step is // generally very cheap / fast, and transferring data is not worth the effort - selector := newExistingSelector(m.index, sector.ID, storiface.FTUnsealed|storiface.FTUpdate|storiface.FTUpdateCache|storiface.FTCache, true) + selector := newExistingSelector(m.index, sector.ID, storiface.FTUnsealed|storiface.FTUpdate|storiface.FTUpdateCache|storiface.FTCache, sector.ID.Miner, true) err = m.sched.Schedule(ctx, sector, sealtasks.TTRegenSectorKey, selector, m.schedFetch(sector, storiface.FTUpdate|storiface.FTUnsealed, storiface.PathSealing, storiface.AcquireMove), func(ctx context.Context, w Worker) error { err := m.startWork(ctx, w, wk)(w.GenerateSectorKeyFromData(ctx, sector, commD)) @@ -984,7 +984,7 @@ func (m *Manager) ReplicaUpdate(ctx context.Context, sector storiface.SectorRef, return storiface.ReplicaUpdateOut{}, xerrors.Errorf("acquiring sector lock: %w", err) } - selector := newAllocSelector(m.index, storiface.FTUpdate|storiface.FTUpdateCache, storiface.PathSealing) + selector := newAllocSelector(m.index, storiface.FTUpdate|storiface.FTUpdateCache, storiface.PathSealing, sector.ID.Miner) err = m.sched.Schedule(ctx, sector, sealtasks.TTReplicaUpdate, selector, m.schedFetch(sector, storiface.FTUnsealed|storiface.FTSealed|storiface.FTCache, storiface.PathSealing, storiface.AcquireCopy), func(ctx context.Context, w Worker) error { err := m.startWork(ctx, w, wk)(w.ReplicaUpdate(ctx, sector, pieces)) @@ -1035,7 +1035,7 @@ func (m *Manager) ProveReplicaUpdate1(ctx context.Context, sector storiface.Sect // NOTE: We set allowFetch to false in so that we always execute on a worker // with direct access to the data. We want to do that because this step is // generally very cheap / fast, and transferring data is not worth the effort - selector := newExistingSelector(m.index, sector.ID, storiface.FTUpdate|storiface.FTUpdateCache, false) + selector := newExistingSelector(m.index, sector.ID, storiface.FTUpdate|storiface.FTUpdateCache, sector.ID.Miner, false) err = m.sched.Schedule(ctx, sector, sealtasks.TTProveReplicaUpdate1, selector, m.schedFetch(sector, storiface.FTSealed|storiface.FTCache|storiface.FTUpdate|storiface.FTUpdateCache, storiface.PathSealing, storiface.AcquireCopy), func(ctx context.Context, w Worker) error { @@ -1153,7 +1153,7 @@ func (m *Manager) DownloadSectorData(ctx context.Context, sector storiface.Secto ptype = storiface.PathStorage } - selector := newAllocSelector(m.index, toFetch, ptype) + selector := newAllocSelector(m.index, toFetch, ptype, sector.ID.Miner) err = m.sched.Schedule(ctx, sector, sealtasks.TTDownloadSector, selector, schedNop, func(ctx context.Context, w Worker) error { err := m.startWork(ctx, w, wk)(w.DownloadSectorData(ctx, sector, finalized, src)) diff --git a/storage/sealer/manager_post.go b/storage/sealer/manager_post.go index 27a71ef8caf..a1020d4b6c8 100644 --- a/storage/sealer/manager_post.go +++ b/storage/sealer/manager_post.go @@ -108,7 +108,7 @@ func dedupeSectorInfo(sectorInfo []proof.ExtendedSectorInfo) []proof.ExtendedSec } func (m *Manager) generateWindowPoSt(ctx context.Context, minerID abi.ActorID, ppt abi.RegisteredPoStProof, sectorInfo []proof.ExtendedSectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, error) { - var retErr error = nil + var retErr error randomness[31] &= 0x3f out := make([]proof.PoStProof, 0) diff --git a/storage/sealer/partialfile/partialfile.go b/storage/sealer/partialfile/partialfile.go index 4357f796d6d..f811f3349ed 100644 --- a/storage/sealer/partialfile/partialfile.go +++ b/storage/sealer/partialfile/partialfile.go @@ -64,7 +64,7 @@ func writeTrailer(maxPieceSize int64, w *os.File, r rlepluslazy.RunIterator) err func CreatePartialFile(maxPieceSize abi.PaddedPieceSize, path string) (*PartialFile, error) { f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644) // nolint if err != nil { - return nil, xerrors.Errorf("openning partial file '%s': %w", path, err) + return nil, xerrors.Errorf("opening partial file '%s': %w", path, err) } err = func() error { @@ -99,18 +99,40 @@ func CreatePartialFile(maxPieceSize abi.PaddedPieceSize, path string) (*PartialF func OpenPartialFile(maxPieceSize abi.PaddedPieceSize, path string) (*PartialFile, error) { f, err := os.OpenFile(path, os.O_RDWR, 0644) // nolint if err != nil { - return nil, xerrors.Errorf("openning partial file '%s': %w", path, err) + return nil, xerrors.Errorf("opening partial file '%s': %w", path, err) } - var rle rlepluslazy.RLE - err = func() error { - st, err := f.Stat() + st, err := f.Stat() + if err != nil { + return nil, xerrors.Errorf("stat '%s': %w", path, err) + } + if st.Size() < int64(maxPieceSize) { + return nil, xerrors.Errorf("sector file '%s' was smaller than the sector size %d < %d", path, st.Size(), maxPieceSize) + } + if st.Size() == int64(maxPieceSize) { + log.Debugw("no partial file trailer, assuming fully allocated", "path", path) + + allAlloc := &rlepluslazy.RunSliceIterator{Runs: []rlepluslazy.Run{{Val: true, Len: uint64(maxPieceSize)}}} + enc, err := rlepluslazy.EncodeRuns(allAlloc, []byte{}) if err != nil { - return xerrors.Errorf("stat '%s': %w", path, err) + return nil, xerrors.Errorf("encoding full allocation: %w", err) } - if st.Size() < int64(maxPieceSize) { - return xerrors.Errorf("sector file '%s' was smaller than the sector size %d < %d", path, st.Size(), maxPieceSize) + + rle, err := rlepluslazy.FromBuf(enc) + if err != nil { + return nil, xerrors.Errorf("decoding full allocation: %w", err) } + + return &PartialFile{ + maxPiece: maxPieceSize, + path: path, + allocated: rle, + file: f, + }, nil + } + + var rle rlepluslazy.RLE + err = func() error { // read trailer var tlen [4]byte _, err = f.ReadAt(tlen[:], st.Size()-int64(len(tlen))) diff --git a/storage/sealer/proofpaths/cachefiles.go b/storage/sealer/proofpaths/cachefiles.go index 24b29e9f5e7..628ab158565 100644 --- a/storage/sealer/proofpaths/cachefiles.go +++ b/storage/sealer/proofpaths/cachefiles.go @@ -2,11 +2,36 @@ package proofpaths import ( "fmt" + "regexp" "github.com/filecoin-project/go-state-types/abi" ) -var dataFilePrefix = "sc-02-data-" +const dataFilePrefix = "sc-02-data-" +const TreeDName = dataFilePrefix + "tree-d.dat" + +const TreeRLastPrefix = dataFilePrefix + "tree-r-last-" +const TreeCPrefix = dataFilePrefix + "tree-c-" + +func IsFileTreeD(baseName string) bool { + return baseName == TreeDName +} + +func IsFileTreeRLast(baseName string) bool { + // TreeRLastPrefix.dat + reg := fmt.Sprintf(`^%s\d+\.dat$`, TreeRLastPrefix) + return regexp.MustCompile(reg).MatchString(baseName) +} + +func IsFileTreeC(baseName string) bool { + // TreeCPrefix.dat + reg := fmt.Sprintf(`^%s\d+\.dat$`, TreeCPrefix) + return regexp.MustCompile(reg).MatchString(baseName) +} + +func IsTreeFile(baseName string) bool { + return IsFileTreeD(baseName) || IsFileTreeRLast(baseName) || IsFileTreeC(baseName) +} func LayerFileName(layer int) string { return fmt.Sprintf("%slayer-%d.dat", dataFilePrefix, layer) diff --git a/storage/sealer/sched_post.go b/storage/sealer/sched_post.go index c6bd8182976..4b9769d6820 100644 --- a/storage/sealer/sched_post.go +++ b/storage/sealer/sched_post.go @@ -56,7 +56,7 @@ func (ps *poStScheduler) MaybeAddWorker(wid storiface.WorkerID, tasks map[sealta func (ps *poStScheduler) delWorker(wid storiface.WorkerID) *WorkerHandle { ps.lk.Lock() defer ps.lk.Unlock() - var w *WorkerHandle = nil + var w *WorkerHandle if wh, ok := ps.workers[wid]; ok { w = wh delete(ps.workers, wid) diff --git a/storage/sealer/sched_test.go b/storage/sealer/sched_test.go index 03e947b8a54..a991ff3fde2 100644 --- a/storage/sealer/sched_test.go +++ b/storage/sealer/sched_test.go @@ -274,7 +274,7 @@ func TestSched(t *testing.T) { done := make(chan struct{}) rm.done[taskName] = done - sel := newAllocSelector(index, storiface.FTCache, storiface.PathSealing) + sel := newAllocSelector(index, storiface.FTCache, storiface.PathSealing, abi.ActorID(1000)) rm.wg.Add(1) go func() { diff --git a/storage/sealer/sched_worker.go b/storage/sealer/sched_worker.go index 35acd755d0e..b482be589c5 100644 --- a/storage/sealer/sched_worker.go +++ b/storage/sealer/sched_worker.go @@ -137,7 +137,7 @@ func (sw *schedWorker) handleWorker() { } // wait for more tasks to be assigned by the main scheduler or for the worker - // to finish precessing a task + // to finish processing a task update, pokeSched, ok := sw.waitForUpdates() if !ok { return diff --git a/storage/sealer/selector_alloc.go b/storage/sealer/selector_alloc.go index 130f74461f5..c2267f4eca0 100644 --- a/storage/sealer/selector_alloc.go +++ b/storage/sealer/selector_alloc.go @@ -16,13 +16,15 @@ type allocSelector struct { index paths.SectorIndex alloc storiface.SectorFileType ptype storiface.PathType + miner abi.ActorID } -func newAllocSelector(index paths.SectorIndex, alloc storiface.SectorFileType, ptype storiface.PathType) *allocSelector { +func newAllocSelector(index paths.SectorIndex, alloc storiface.SectorFileType, ptype storiface.PathType, miner abi.ActorID) *allocSelector { return &allocSelector{ index: index, alloc: alloc, ptype: ptype, + miner: miner, } } @@ -50,7 +52,7 @@ func (s *allocSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi return false, false, xerrors.Errorf("getting sector size: %w", err) } - best, err := s.index.StorageBestAlloc(ctx, s.alloc, ssize, s.ptype) + best, err := s.index.StorageBestAlloc(ctx, s.alloc, ssize, s.ptype, s.miner) if err != nil { return false, false, xerrors.Errorf("finding best alloc storage: %w", err) } diff --git a/storage/sealer/selector_existing.go b/storage/sealer/selector_existing.go index c1e082db8a5..86610862a1f 100644 --- a/storage/sealer/selector_existing.go +++ b/storage/sealer/selector_existing.go @@ -16,14 +16,16 @@ type existingSelector struct { index paths.SectorIndex sector abi.SectorID fileType storiface.SectorFileType + miner abi.ActorID allowFetch bool } -func newExistingSelector(index paths.SectorIndex, sector abi.SectorID, alloc storiface.SectorFileType, allowFetch bool) *existingSelector { +func newExistingSelector(index paths.SectorIndex, sector abi.SectorID, alloc storiface.SectorFileType, miner abi.ActorID, allowFetch bool) *existingSelector { return &existingSelector{ index: index, sector: sector, fileType: alloc, + miner: miner, allowFetch: allowFetch, } } diff --git a/storage/sealer/selector_move.go b/storage/sealer/selector_move.go index fde4b3c59cd..3f07a75deff 100644 --- a/storage/sealer/selector_move.go +++ b/storage/sealer/selector_move.go @@ -17,10 +17,11 @@ type moveSelector struct { sector abi.SectorID alloc storiface.SectorFileType destPtype storiface.PathType + miner abi.ActorID allowRemote bool } -func newMoveSelector(index paths.SectorIndex, sector abi.SectorID, alloc storiface.SectorFileType, destPtype storiface.PathType, allowRemote bool) *moveSelector { +func newMoveSelector(index paths.SectorIndex, sector abi.SectorID, alloc storiface.SectorFileType, destPtype storiface.PathType, miner abi.ActorID, allowRemote bool) *moveSelector { return &moveSelector{ index: index, sector: sector, @@ -67,7 +68,7 @@ func (s *moveSelector) Ok(ctx context.Context, task sealtasks.TaskType, spt abi. } } - best, err := s.index.StorageBestAlloc(ctx, s.alloc, ssize, s.destPtype) + best, err := s.index.StorageBestAlloc(ctx, s.alloc, ssize, s.destPtype, s.miner) if err != nil { return false, false, xerrors.Errorf("finding best dest storage: %w", err) } diff --git a/storage/sealer/storiface/filetype.go b/storage/sealer/storiface/filetype.go index ec3c5450cb3..0aa28861be0 100644 --- a/storage/sealer/storiface/filetype.go +++ b/storage/sealer/storiface/filetype.go @@ -8,22 +8,66 @@ import ( "github.com/filecoin-project/go-state-types/abi" ) +// FTUnsealed represents an unsealed sector file. +// FTSealed represents a sealed sector file. +// FTCache represents a cache sector file. +// FTUpdate represents an update sector file. +// FTUpdateCache represents an update cache sector file. +// FTPiece represents a Piece Park sector file. +// FileTypes represents the total number of file. +// +// The SectorFileType type is an integer type that represents different sector file. +// It has several methods to manipulate and query the file. +// The String method returns a string representation of the file. +// The Strings method returns a slice of string representations of all the file that are set in the receiver object. +// The AllSet method returns a slice of all the file that are set in the receiver object. +// The Has method checks whether a specific file type is set in the receiver object. +// The SealSpaceUse method calculates the space used by the receiver object in sealing a sector of a given size. +// The SubAllowed method removes selected file from the receiver object based on a list of allowed and denied file. +// The Unset method removes selected file from the receiver object. +// The AnyAllowed method checks whether any file in the receiver object are allowed based on a list of allowed and denied file. +// The Allowed method checks whether all file in the receiver object are allowed based on a list of allowed and denied file. +// The StoreSpaceUse method calculates the space used by the receiver object in storing a sector of a given size. +// The All method returns an array that represents which file are set in the receiver object. +// The IsNone method checks whether the receiver object represents no file. const ( + // "regular" sectors FTUnsealed SectorFileType = 1 << iota FTSealed FTCache + + // snap FTUpdate FTUpdateCache + // Piece Park + FTPiece + FileTypes = iota ) -var PathTypes = []SectorFileType{FTUnsealed, FTSealed, FTCache, FTUpdate, FTUpdateCache} - +// PathTypes is a slice of SectorFileType that represents different types of sector file paths. +// It contains the following types of sector file paths: +// - FTUnsealed: represents regular unsealed sectors +// - FTSealed: represents sealed sectors +// - FTCache: represents cache sectors +// - FTUpdate: represents snap sectors +// - FTUpdateCache: represents snap cache sectors +// - FTPiece: represents Piece Park sectors +var PathTypes = []SectorFileType{FTUnsealed, FTSealed, FTCache, FTUpdate, FTUpdateCache, FTPiece} + +// FTNone represents a sector file type of none. This constant is used in the StorageLock method to specify that a sector should not have any file locked. +// Example usage: +// err := m.index.StorageLock(ctx, sector.ID, storiface.FTNone, storiface.FTSealed|storiface.FTUnsealed|storiface.FTCache) const ( FTNone SectorFileType = 0 ) +// FTAll represents the combination of all available sector file. +// It is a variable of type SectorFileType. +// The value of FTAll is calculated by iterating over the PathTypes slice and using the |= operator to perform a bitwise OR operation on each path type. +// The result is assigned to the variable out and returned. +// FTAll is immediately invoked as a function using the anonymous function syntax, so the result is returned as soon as it is calculated. var FTAll = func() (out SectorFileType) { for _, pathType := range PathTypes { out |= pathType @@ -31,28 +75,43 @@ var FTAll = func() (out SectorFileType) { return out }() +// FSOverheadDen represents the constant value 10, which is used to calculate the overhead in various storage space utilization calculations. const FSOverheadDen = 10 +// FSOverheadSeal is a map that represents the overheads for different SectorFileType in sectors which are being sealed. var FSOverheadSeal = map[SectorFileType]int{ // 10x overheads FTUnsealed: FSOverheadDen, FTSealed: FSOverheadDen, FTUpdate: FSOverheadDen, FTUpdateCache: FSOverheadDen*2 + 1, FTCache: 141, // 11 layers + D(2x ssize) + C + R' + FTPiece: FSOverheadDen, } // sector size * disk / fs overhead. FSOverheadDen is like the unit of sector size +// FsOverheadFinalized is a map that represents the finalized overhead for different types of SectorFileType. +// The keys in the map are the SectorFileType values, and the values are integers representing the overhead. +// It is used to calculate the storage space usage for different types of sectors, as shown in the example below: +// The overhead value is retrieved from FsOverheadFinalized by using the SectorFileType value as the key. +// If the overhead value is not found in the map, an error is returned indicating that there is no finalized +// overhead information for the given sector type. var FsOverheadFinalized = map[SectorFileType]int{ FTUnsealed: FSOverheadDen, FTSealed: FSOverheadDen, FTUpdate: FSOverheadDen, FTUpdateCache: 1, FTCache: 1, + FTPiece: FSOverheadDen, } +// SectorFileType represents the type of a sector file +// TypeFromString converts a string to a SectorFileType type SectorFileType int +// TypeFromString converts a string representation of a SectorFileType to its corresponding value. +// It returns the SectorFileType and nil error if the string matches one of the existing types. +// If the string does not match any type, it returns 0 and an error. func TypeFromString(s string) (SectorFileType, error) { switch s { case "unsealed": @@ -65,11 +124,14 @@ func TypeFromString(s string) (SectorFileType, error) { return FTUpdate, nil case "update-cache": return FTUpdateCache, nil + case "piece": + return FTPiece, nil default: return 0, xerrors.Errorf("unknown sector file type '%s'", s) } } +// String returns a string representation of the SectorFileType. func (t SectorFileType) String() string { switch t { case FTUnsealed: @@ -82,11 +144,19 @@ func (t SectorFileType) String() string { return "update" case FTUpdateCache: return "update-cache" + case FTPiece: + return "piece" default: return fmt.Sprintf("", t, (t & ((1 << FileTypes) - 1)).Strings()) } } +// Strings returns a slice of strings representing the names of the SectorFileType values that are set in the receiver value. +// Example usage: +// +// fileType := SectorFileType(FTSealed | FTCache) +// names := fileType.Strings() // names = ["sealed", "cache"] +// fmt.Println(names) func (t SectorFileType) Strings() []string { var out []string for _, fileType := range PathTypes { @@ -99,6 +169,7 @@ func (t SectorFileType) Strings() []string { return out } +// AllSet returns a slice of SectorFileType values that are set in the SectorFileType receiver value func (t SectorFileType) AllSet() []SectorFileType { var out []SectorFileType for _, fileType := range PathTypes { @@ -111,10 +182,33 @@ func (t SectorFileType) AllSet() []SectorFileType { return out } +// Has checks if the SectorFileType has a specific singleType. func (t SectorFileType) Has(singleType SectorFileType) bool { return t&singleType == singleType } +// SealSpaceUse calculates the amount of space needed for sealing the sector +// based on the given sector size. It iterates over the different path types +// and calculates the space needed for each path type using the FSOverheadSeal +// map. The overhead value is multiplied by the sector size and divided by the +// FSOverheadDen constant. The total space needed is accumulated and returned. +// If there is no seal overhead information for a particular path type, an error +// is returned. +// +// Example usage: +// +// fileType := FTSealed | FTCache +// sectorSize := abi.SectorSize(32 << 20) // 32 MiB +// spaceNeeded, err := fileType.SealSpaceUse(sectorSize) +// +// Parameters: +// +// ssize: The size of the sector +// +// Returns: +// +// uint64: The amount of space needed for sealing the sector +// error: If there is no seal overhead information for a path type func (t SectorFileType) SealSpaceUse(ssize abi.SectorSize) (uint64, error) { var need uint64 for _, pathType := range PathTypes { @@ -133,6 +227,15 @@ func (t SectorFileType) SealSpaceUse(ssize abi.SectorSize) (uint64, error) { return need, nil } +// The method takes in two parameters: allowTypes and denyTypes, both of which are slices of strings. +// If allowTypes is not empty, the method sets a denyMask with all bits set to 1, and then iterates over each allowType, +// converting it to a SectorFileType using the TypeFromString function and unsetting the corresponding bit in the denyMask. +// If a string in allowTypes cannot be converted to a valid SectorFileType, it is ignored. +// After processing allowTypes, the method iterates over each denyType, converting it to a SectorFileType using the TypeFromString function +// and setting the corresponding bit in the denyMask. +// If a string in denyTypes cannot be converted to a valid SectorFileType, it is ignored. +// Finally, the method returns the bitwise AND of the original SectorFileType and the denyMask. +// The returned SectorFileType will only allow the types specified in allowTypes and exclude the types specified in denyTypes.` func (t SectorFileType) SubAllowed(allowTypes []string, denyTypes []string) SectorFileType { var denyMask SectorFileType // 1s deny @@ -162,14 +265,30 @@ func (t SectorFileType) SubAllowed(allowTypes []string, denyTypes []string) Sect return t & denyMask } +// Unset removes the specified sector file type(s) from the current SectorFileType value. +// It performs a bitwise AND operation between the current value and the bitwise complement of the toUnset value. +// The result is returned as a new SectorFileType value. +// Any bits that are set in toUnset will be cleared in the result. +// Usage: result = value.Unset(typesToUnset) +func (t SectorFileType) Unset(toUnset SectorFileType) SectorFileType { + return t &^ toUnset +} + +// AnyAllowed checks if the SectorFileType has any allowed types and no denied types. func (t SectorFileType) AnyAllowed(allowTypes []string, denyTypes []string) bool { return t.SubAllowed(allowTypes, denyTypes) != t } +// Allowed checks if the SectorFileType is allowed based on the given allowTypes and denyTypes. +// Returns true if the SectorFileType is allowed, otherwise false. func (t SectorFileType) Allowed(allowTypes []string, denyTypes []string) bool { return t.SubAllowed(allowTypes, denyTypes) == 0 } +// StoreSpaceUse calculates the space used for storing sectors of a specific file type. +// It takes the sector size as input and returns the total space needed in bytes and an error, if any. +// The calculation is based on the finalized overhead information for the file type. +// If the overhead information is not available for a particular file type, an error will be returned. func (t SectorFileType) StoreSpaceUse(ssize abi.SectorSize) (uint64, error) { var need uint64 for _, pathType := range PathTypes { @@ -188,6 +307,7 @@ func (t SectorFileType) StoreSpaceUse(ssize abi.SectorSize) (uint64, error) { return need, nil } +// All returns an array indicating whether each FileTypes flag is set in the SectorFileType. func (t SectorFileType) All() [FileTypes]bool { var out [FileTypes]bool @@ -198,6 +318,13 @@ func (t SectorFileType) All() [FileTypes]bool { return out } +// IsNone checks if the SectorFileType value is equal to zero. +// It returns true if the value is zero, indicating that the type is none. +func (t SectorFileType) IsNone() bool { + return t == 0 +} + +// SectorPaths represents the paths for different sector files. type SectorPaths struct { ID abi.SectorID @@ -206,8 +333,53 @@ type SectorPaths struct { Cache string Update string UpdateCache string + Piece string +} + +// HasAllSet checks if all paths of a SectorPaths struct are set for a given SectorFileType. +func (sp SectorPaths) HasAllSet(ft SectorFileType) bool { + for _, fileType := range ft.AllSet() { + if PathByType(sp, fileType) == "" { + return false + } + } + + return true } +// Subset returns a new instance of SectorPaths that contains only the paths specified by the filter SectorFileType. +// It iterates over each fileType in the filter, retrieves the corresponding path from the original SectorPaths instance, and sets it in the new instance. +// Finally, it sets the ID field of the new instance to be the same as the original instance. +func (sp SectorPaths) Subset(filter SectorFileType) SectorPaths { + var out SectorPaths + + for _, fileType := range filter.AllSet() { + SetPathByType(&out, fileType, PathByType(sp, fileType)) + } + + out.ID = sp.ID + + return out +} + +// ParseSectorID parses a sector ID from a given base name. +// It expects the format "s-t0%d-%d", where the first %d represents the miner ID +// and the second %d represents the sector number. +// +// Parameters: +// - baseName: The base name from which to parse the sector ID. +// +// Returns: +// - abi.SectorID: The parsed sector ID. +// - error: An error if parsing fails. +// +// Example usage: +// +// id, err := ParseSectorID(baseName) +// if err != nil { +// // handle error +// } +// // use id func ParseSectorID(baseName string) (abi.SectorID, error) { var n abi.SectorNumber var mid abi.ActorID @@ -226,10 +398,19 @@ func ParseSectorID(baseName string) (abi.SectorID, error) { }, nil } +// SectorName returns the name of a sector in the format "s-t0-" +// +// Parameters: +// - sid: The sector ID +// +// Returns: +// - The name of the sector as a string func SectorName(sid abi.SectorID) string { return fmt.Sprintf("s-t0%d-%d", sid.Miner, sid.Number) } +// PathByType returns the path associated with the specified fileType in the given SectorPaths. +// It panics if the requested path type is unknown. func PathByType(sps SectorPaths, fileType SectorFileType) string { switch fileType { case FTUnsealed: @@ -242,6 +423,8 @@ func PathByType(sps SectorPaths, fileType SectorFileType) string { return sps.Update case FTUpdateCache: return sps.UpdateCache + case FTPiece: + return sps.Piece } panic("requested unknown path type") @@ -259,5 +442,19 @@ func SetPathByType(sps *SectorPaths, fileType SectorFileType, p string) { sps.Update = p case FTUpdateCache: sps.UpdateCache = p + case FTPiece: + sps.Piece = p } } + +// PathsWithIDs represents paths and IDs for sector files. +type PathsWithIDs struct { + Paths SectorPaths + IDs SectorPaths +} + +// HasAllSet checks if all paths and IDs in PathsWithIDs have a corresponding path set for the specified SectorFileType. +// It returns true if all paths and IDs are set, and false otherwise. +func (p PathsWithIDs) HasAllSet(ft SectorFileType) bool { + return p.Paths.HasAllSet(ft) && p.IDs.HasAllSet(ft) +} diff --git a/storage/sealer/storiface/index.go b/storage/sealer/storiface/index.go index 653bd2fbae5..3bf69568741 100644 --- a/storage/sealer/storiface/index.go +++ b/storage/sealer/storiface/index.go @@ -86,6 +86,14 @@ type StorageInfo struct { // - "update-cache" // Any other value will generate a warning and be ignored. DenyTypes []string + + // AllowMiners lists miner IDs which are allowed to store their sector data into + // this path. If empty, all miner IDs are allowed + AllowMiners []string + + // DenyMiners lists miner IDs which are denied to store their sector data into + // this path + DenyMiners []string } type HealthReport struct { @@ -104,8 +112,10 @@ type SectorStorageInfo struct { Primary bool - AllowTypes []string - DenyTypes []string + AllowTypes []string + DenyTypes []string + AllowMiners []string + DenyMiners []string } type Decl struct { diff --git a/storage/sealer/storiface/paths.go b/storage/sealer/storiface/paths.go index 2cb4f34d30b..0f0eaeadffd 100644 --- a/storage/sealer/storiface/paths.go +++ b/storage/sealer/storiface/paths.go @@ -25,3 +25,15 @@ type SectorLock struct { type SectorLocks struct { Locks []SectorLock } + +type AcquireSettings struct { + Into *PathsWithIDs +} + +type AcquireOption func(*AcquireSettings) + +func AcquireInto(pathIDs PathsWithIDs) AcquireOption { + return func(settings *AcquireSettings) { + settings.Into = &pathIDs + } +} diff --git a/storage/sealer/storiface/storage.go b/storage/sealer/storiface/storage.go index fe4e1e2086a..143c3b5d560 100644 --- a/storage/sealer/storiface/storage.go +++ b/storage/sealer/storiface/storage.go @@ -20,6 +20,17 @@ type SectorRef struct { var NoSectorRef = SectorRef{} +// PieceNumber is a reference to a piece in the storage system; mapping between +// pieces in the storage system and piece CIDs is maintained by the storage index +type PieceNumber uint64 + +func (pn PieceNumber) Ref() SectorRef { + return SectorRef{ + ID: abi.SectorID{Miner: 0, Number: abi.SectorNumber(pn)}, + ProofType: abi.RegisteredSealProof_StackedDrg64GiBV1, // This only cares about TreeD which is the same for all sizes + } +} + type ProverPoSt interface { GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.ExtendedSectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, error) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, ppt abi.RegisteredPoStProof, sectorInfo []proof.ExtendedSectorInfo, randomness abi.PoStRandomness) (proof []proof.PoStProof, skipped []abi.SectorID, err error) @@ -214,4 +225,12 @@ type LocalStorageMeta struct { // - "update-cache" // Any other value will generate a warning and be ignored. DenyTypes []string + + // AllowMiners lists miner IDs which are allowed to store their sector data into + // this path. If empty, all miner IDs are allowed + AllowMiners []string + + // DenyMiners lists miner IDs which are denied to store their sector data into + // this path + DenyMiners []string } diff --git a/storage/sealer/worker_local.go b/storage/sealer/worker_local.go index 7fc49495597..417a15e62b1 100644 --- a/storage/sealer/worker_local.go +++ b/storage/sealer/worker_local.go @@ -28,8 +28,6 @@ import ( "github.com/filecoin-project/lotus/storage/sealer/storiface" ) -var pathTypes = []storiface.SectorFileType{storiface.FTUnsealed, storiface.FTSealed, storiface.FTCache, storiface.FTUpdate, storiface.FTUpdateCache} - type WorkerConfig struct { TaskTypes []sealtasks.TaskType NoSwap bool @@ -167,7 +165,7 @@ func (l *localWorkerPathProvider) AcquireSector(ctx context.Context, sector stor return paths, func() { releaseStorage() - for _, fileType := range pathTypes { + for _, fileType := range storiface.PathTypes { if fileType&allocate == 0 { continue } @@ -180,16 +178,16 @@ func (l *localWorkerPathProvider) AcquireSector(ctx context.Context, sector stor }, nil } +func (l *localWorkerPathProvider) AcquireSectorCopy(ctx context.Context, id storiface.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, ptype storiface.PathType) (storiface.SectorPaths, func(), error) { + return (&localWorkerPathProvider{w: l.w, op: storiface.AcquireCopy}).AcquireSector(ctx, id, existing, allocate, ptype) +} + func FFIExec(opts ...ffiwrapper.FFIWrapperOpt) func(l *LocalWorker) (storiface.Storage, error) { return func(l *LocalWorker) (storiface.Storage, error) { return ffiwrapper.New(&localWorkerPathProvider{w: l}, opts...) } } -func (l *localWorkerPathProvider) AcquireSectorCopy(ctx context.Context, id storiface.SectorRef, existing storiface.SectorFileType, allocate storiface.SectorFileType, ptype storiface.PathType) (storiface.SectorPaths, func(), error) { - return (&localWorkerPathProvider{w: l.w, op: storiface.AcquireCopy}).AcquireSector(ctx, id, existing, allocate, ptype) -} - type ReturnType string const ( diff --git a/storage/wdpost/wdpost_changehandler_test.go b/storage/wdpost/wdpost_changehandler_test.go index 44d0dfe6d02..c2d993bee9e 100644 --- a/storage/wdpost/wdpost_changehandler_test.go +++ b/storage/wdpost/wdpost_changehandler_test.go @@ -84,10 +84,10 @@ func (m *mockAPI) setDeadline(di *dline.Info) { } func (m *mockAPI) getDeadline(currentEpoch abi.ChainEpoch) *dline.Info { - close := minertypes.WPoStChallengeWindow - 1 + closeEpoch := minertypes.WPoStChallengeWindow - 1 dlIdx := uint64(0) - for close < currentEpoch { - close += minertypes.WPoStChallengeWindow + for closeEpoch < currentEpoch { + closeEpoch += minertypes.WPoStChallengeWindow dlIdx++ } return NewDeadlineInfo(0, dlIdx, currentEpoch) diff --git a/storage/wdpost/wdpost_run_faults.go b/storage/wdpost/wdpost_run_faults.go index 3a41cc4cce4..250be0c3ab7 100644 --- a/storage/wdpost/wdpost_run_faults.go +++ b/storage/wdpost/wdpost_run_faults.go @@ -23,7 +23,7 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) -var RecoveringSectorLimit uint64 = 0 +var RecoveringSectorLimit uint64 func init() { if rcl := os.Getenv("LOTUS_RECOVERING_SECTOR_LIMIT"); rcl != "" { diff --git a/storage/wdpost/wdpost_run_test.go b/storage/wdpost/wdpost_run_test.go index a3847a6f6bd..381f0e818bd 100644 --- a/storage/wdpost/wdpost_run_test.go +++ b/storage/wdpost/wdpost_run_test.go @@ -27,6 +27,7 @@ import ( "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/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/journal" @@ -73,13 +74,13 @@ func (m *mockStorageMinerAPI) StateMinerPartitions(ctx context.Context, a addres return m.partitions, nil } -func (m *mockStorageMinerAPI) StateMinerSectors(ctx context.Context, address address.Address, snos *bitfield.BitField, key types.TipSetKey) ([]*minertypes.SectorOnChainInfo, error) { - var sis []*minertypes.SectorOnChainInfo +func (m *mockStorageMinerAPI) StateMinerSectors(ctx context.Context, address address.Address, snos *bitfield.BitField, key types.TipSetKey) ([]*miner.SectorOnChainInfo, error) { + var sis []*miner.SectorOnChainInfo if snos == nil { panic("unsupported") } _ = snos.ForEach(func(i uint64) error { - sis = append(sis, &minertypes.SectorOnChainInfo{ + sis = append(sis, &miner.SectorOnChainInfo{ SectorNumber: abi.SectorNumber(i), }) return nil diff --git a/tools/stats/sync/sync.go b/tools/stats/sync/sync.go index c8db1c543be..5a925d4cbcc 100644 --- a/tools/stats/sync/sync.go +++ b/tools/stats/sync/sync.go @@ -91,7 +91,7 @@ type BufferedTipsetChannelApi interface { } // BufferedTipsetChannel returns an unbuffered channel of tipsets. Buffering occurs internally to handle revert -// ChainNotify changes. The returned channel can output tipsets at the same height twice if a reorg larger the the +// ChainNotify changes. The returned channel can output tipsets at the same height twice if a reorg larger the // provided `size` occurs. func BufferedTipsetChannel(ctx context.Context, api BufferedTipsetChannelApi, lastHeight abi.ChainEpoch, size int) (<-chan *types.TipSet, error) { chmain := make(chan *types.TipSet)