├── .cargo └── config.toml ├── .dockerignore ├── .github └── workflows │ ├── ci.yml │ ├── coverage.yml │ ├── deny.yml │ ├── release-check.yml │ ├── releaser.yml │ ├── tagpush.yml │ └── upload-release-assets.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── README.md ├── RELEASE.md ├── actors ├── account │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ ├── state.rs │ │ ├── testing.rs │ │ └── types.rs │ └── tests │ │ └── account_actor_test.rs ├── cron │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ ├── state.rs │ │ └── testing.rs │ └── tests │ │ └── cron_actor_test.rs ├── datacap │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ ├── state.rs │ │ ├── testing.rs │ │ └── types.rs │ └── tests │ │ ├── datacap_actor_test.rs │ │ └── harness │ │ └── mod.rs ├── eam │ ├── Cargo.toml │ ├── src │ │ ├── ext.rs │ │ └── lib.rs │ └── tests │ │ └── create.rs ├── ethaccount │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── types.rs │ └── tests │ │ ├── ethaccount_test.rs │ │ └── util.rs ├── evm │ ├── Cargo.toml │ ├── Makefile │ ├── README.md │ ├── precompile-testdata │ │ ├── LICENSE │ │ ├── README.md │ │ ├── blake2F.json │ │ ├── bn256Add.json │ │ ├── bn256Pairing.json │ │ ├── bn256ScalarMul.json │ │ ├── ecRecover.json │ │ ├── fail-blake2f.json │ │ ├── modexp.json │ │ └── modexp_eip2565.json │ ├── shared │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── address.rs │ │ │ ├── lib.rs │ │ │ └── uints.rs │ ├── src │ │ ├── ext.rs │ │ ├── interpreter │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── bytecode.rs │ │ │ ├── execution.rs │ │ │ ├── instructions │ │ │ │ ├── arithmetic.rs │ │ │ │ ├── bitwise.rs │ │ │ │ ├── boolean.rs │ │ │ │ ├── call.rs │ │ │ │ ├── context.rs │ │ │ │ ├── control.rs │ │ │ │ ├── ext.rs │ │ │ │ ├── hash.rs │ │ │ │ ├── lifecycle.rs │ │ │ │ ├── log_event.rs │ │ │ │ ├── memory.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── stack.rs │ │ │ │ ├── state.rs │ │ │ │ └── storage.rs │ │ │ ├── memory.rs │ │ │ ├── mod.rs │ │ │ ├── output.rs │ │ │ ├── precompiles │ │ │ │ ├── blake2f_impl.rs │ │ │ │ ├── evm.rs │ │ │ │ ├── fvm.rs │ │ │ │ └── mod.rs │ │ │ ├── stack.rs │ │ │ ├── system.rs │ │ │ └── test_util.rs │ │ ├── lib.rs │ │ ├── reader.rs │ │ ├── state.rs │ │ └── types.rs │ └── tests │ │ ├── asm.rs │ │ ├── basic.rs │ │ ├── calc.rs │ │ ├── call.rs │ │ ├── context_opcodes.rs │ │ ├── contracts │ │ ├── CallActorPrecompile.hex │ │ ├── CallActorPrecompile.sol │ │ ├── FeSimplecoin.fe │ │ ├── FilecoinFallback.hex │ │ ├── FilecoinFallback.sol │ │ ├── Lifecycle.hex │ │ ├── Lifecycle.sol │ │ ├── MCOPYTest.hex │ │ ├── MCOPYTest.sol │ │ ├── Recursive.hex │ │ ├── Recursive.sol │ │ ├── TransientStorageTest.hex │ │ ├── TransientStorageTest.sol │ │ ├── callvariants.eas │ │ ├── callvariants.hex │ │ ├── callvariants_body.eas │ │ ├── output │ │ │ └── FeSimplecoin │ │ │ │ ├── FeSimplecoin.bin │ │ │ │ └── FeSimplecoin_abi.json │ │ ├── recall_contract │ │ │ ├── README.md │ │ │ ├── implementation.hex │ │ │ └── proxy.hex │ │ ├── selfdestruct.hex │ │ ├── selfdestruct.sol │ │ ├── simplecoin.hex │ │ └── simplecoin.sol │ │ ├── create.rs │ │ ├── delegate_call.rs │ │ ├── env.rs │ │ ├── events.rs │ │ ├── ext_opcodes.rs │ │ ├── misc.rs │ │ ├── precompile.rs │ │ ├── revert.rs │ │ ├── selfdestruct.rs │ │ └── util.rs ├── init │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ ├── state.rs │ │ ├── testing.rs │ │ └── types.rs │ └── tests │ │ └── init_actor_test.rs ├── market │ ├── Cargo.toml │ ├── src │ │ ├── balance_table.rs │ │ ├── deal.rs │ │ ├── emit.rs │ │ ├── ext.rs │ │ ├── lib.rs │ │ ├── policy.rs │ │ ├── state.rs │ │ ├── testing.rs │ │ └── types.rs │ └── tests │ │ ├── activate_deal_failures.rs │ │ ├── batch_activate_deals.rs │ │ ├── cron_tick_deal_expiry.rs │ │ ├── cron_tick_deal_slashing.rs │ │ ├── cron_tick_timedout_deals.rs │ │ ├── deal_api_test.rs │ │ ├── deal_termination.rs │ │ ├── harness.rs │ │ ├── market_actor_legacy_tests.rs │ │ ├── market_actor_test.rs │ │ ├── on_miner_sectors_terminate.rs │ │ ├── publish_storage_deals_failures.rs │ │ ├── random_cron_epoch_during_publish.rs │ │ ├── sector_content_changed.rs │ │ ├── settle_deal_payments.rs │ │ ├── transient_marked_for_termination.rs │ │ └── verify_deals_for_activation_test.rs ├── miner │ ├── Cargo.toml │ ├── src │ │ ├── beneficiary.rs │ │ ├── bitfield_queue.rs │ │ ├── commd.rs │ │ ├── deadline_assignment.rs │ │ ├── deadline_info.rs │ │ ├── deadline_state.rs │ │ ├── deadlines.rs │ │ ├── emit.rs │ │ ├── expiration_queue.rs │ │ ├── expiration_queue │ │ │ └── tests.rs │ │ ├── ext.rs │ │ ├── internal_tests.rs │ │ ├── lib.rs │ │ ├── monies.rs │ │ ├── notifications.rs │ │ ├── partition_state.rs │ │ ├── policy.rs │ │ ├── quantize.rs │ │ ├── sector_map.rs │ │ ├── sectors.rs │ │ ├── state.rs │ │ ├── termination.rs │ │ ├── testing.rs │ │ ├── types.rs │ │ └── vesting_state.rs │ └── tests │ │ ├── aggregate_prove_commit.rs │ │ ├── apply_rewards.rs │ │ ├── change_beneficiary_test.rs │ │ ├── change_owner_address_test.rs │ │ ├── change_peer_id_test.rs │ │ ├── change_worker_address_test.rs │ │ ├── check_sector_proven_test.rs │ │ ├── compact_partitions_test.rs │ │ ├── compact_sector_numbers_tests.rs │ │ ├── confirm_update_worker_key_test.rs │ │ ├── daily_fees_test.rs │ │ ├── deadline_assignment.rs │ │ ├── deadline_cron.rs │ │ ├── deadline_cron_defers_stops_restarts.rs │ │ ├── deadline_helper.rs │ │ ├── deadline_state_test.rs │ │ ├── deadlines.rs │ │ ├── declare_faults.rs │ │ ├── declare_recoveries.rs │ │ ├── expected_reward_for_power_clampted_at_atto_fil_test.rs │ │ ├── expiration_queue.rs │ │ ├── exported_getters.rs │ │ ├── extend_sector_expiration_test.rs │ │ ├── fip0081_initial_pledge.rs │ │ ├── initial_pledge.rs │ │ ├── miner_actor_test_bitfield_queue.rs │ │ ├── miner_actor_test_commitment.rs │ │ ├── miner_actor_test_construction.rs │ │ ├── miner_actor_test_ctl_addrs.rs │ │ ├── miner_actor_test_partitions.rs │ │ ├── miner_actor_test_peer_info.rs │ │ ├── miner_actor_test_precommit_batch.rs │ │ ├── miner_actor_test_wpost.rs │ │ ├── monies_test.rs │ │ ├── pledge_penalty_for_termination.rs │ │ ├── policy_test.rs │ │ ├── precommit_deposit_and_initial_pledge_positive_test.rs │ │ ├── precommit_expiry.rs │ │ ├── precommitted_sector_stores.rs │ │ ├── prove_commit.rs │ │ ├── prove_commit2_failures_test.rs │ │ ├── prove_commit2_test.rs │ │ ├── prove_commit_niporep.rs │ │ ├── prove_replica_failures_test.rs │ │ ├── prove_replica_test.rs │ │ ├── record_skipped_faults.rs │ │ ├── repay_debt_test.rs │ │ ├── repay_debts.rs │ │ ├── report_consensus_fault.rs │ │ ├── sector_assignment.rs │ │ ├── sector_map_test.rs │ │ ├── sector_number_allocation.rs │ │ ├── sectors.rs │ │ ├── sectors_stores_test.rs │ │ ├── state_harness.rs │ │ ├── terminate_sectors_test.rs │ │ ├── termination_test.rs │ │ ├── types_test.rs │ │ ├── util.rs │ │ ├── vesting_add_locked_funds.rs │ │ ├── vesting_add_locked_funds_table.rs │ │ ├── vesting_unvested_funds.rs │ │ └── withdraw_balance.rs ├── multisig │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ ├── state.rs │ │ ├── testing.rs │ │ └── types.rs │ └── tests │ │ ├── multisig_actor_test.rs │ │ └── util.rs ├── paych │ ├── Cargo.toml │ ├── src │ │ ├── ext.rs │ │ ├── lib.rs │ │ ├── state.rs │ │ ├── testing.rs │ │ └── types.rs │ └── tests │ │ └── paych_actor_test.rs ├── placeholder │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── power │ ├── Cargo.toml │ ├── src │ │ ├── ext.rs │ │ ├── lib.rs │ │ ├── policy.rs │ │ ├── state.rs │ │ ├── testing.rs │ │ └── types.rs │ └── tests │ │ ├── harness │ │ └── mod.rs │ │ ├── power_actor_tests.rs │ │ └── types_test.rs ├── reward │ ├── Cargo.toml │ ├── src │ │ ├── expneg.rs │ │ ├── ext.rs │ │ ├── lib.rs │ │ ├── logic.rs │ │ ├── state.rs │ │ ├── testing.rs │ │ └── types.rs │ ├── testdata │ │ ├── TestBaselineReward.golden │ │ └── TestSimpleReward.golden │ └── tests │ │ └── reward_actor_test.rs ├── system │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── verifreg │ ├── Cargo.toml │ ├── src │ ├── emit.rs │ ├── expiration.rs │ ├── ext.rs │ ├── lib.rs │ ├── state.rs │ ├── testing.rs │ └── types.rs │ └── tests │ ├── harness │ └── mod.rs │ └── verifreg_actor_test.rs ├── build.rs ├── deny.toml ├── examples ├── README.md └── dummy.rs ├── integration_tests ├── Cargo.toml ├── macro │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── src │ ├── deals.rs │ ├── expects.rs │ ├── lib.rs │ ├── tests │ ├── authenticate_message_test.rs │ ├── batch_onboarding.rs │ ├── batch_onboarding_deals_test.rs │ ├── change_beneficiary_test.rs │ ├── change_owner_test.rs │ ├── commit_post_test.rs │ ├── datacap_tests.rs │ ├── evm_test.rs │ ├── extend_sectors_test.rs │ ├── init_test.rs │ ├── market_miner_withdrawal_test.rs │ ├── mod.rs │ ├── multisig_test.rs │ ├── power_scenario_tests.rs │ ├── prove_commit3_test.rs │ ├── prove_commit_niporep_test.rs │ ├── publish_deals_test.rs │ ├── replica_update3_test.rs │ ├── replica_update_test.rs │ ├── terminate_test.rs │ ├── verified_claim_test.rs │ ├── verifreg_remove_datacap_test.rs │ └── withdraw_balance_test.rs │ └── util │ ├── mod.rs │ └── workflows.rs ├── output └── .keep ├── runtime ├── Cargo.toml ├── build.rs ├── src │ ├── actor_error.rs │ ├── builtin │ │ ├── mod.rs │ │ ├── network.rs │ │ ├── reward │ │ │ ├── math.rs │ │ │ ├── mod.rs │ │ │ └── smooth │ │ │ │ ├── alpha_beta_filter.rs │ │ │ │ ├── mod.rs │ │ │ │ └── smooth_func.rs │ │ ├── shared.rs │ │ └── singletons.rs │ ├── dispatch.rs │ ├── lib.rs │ ├── runtime │ │ ├── actor_blockstore.rs │ │ ├── actor_code.rs │ │ ├── builtins.rs │ │ ├── empty.rs │ │ ├── fvm.rs │ │ ├── hash_algorithm.rs │ │ ├── mod.rs │ │ ├── policy.rs │ │ └── randomness.rs │ ├── test_blockstores.rs │ ├── test_utils.rs │ └── util │ │ ├── batch_return.rs │ │ ├── cbor.rs │ │ ├── downcast.rs │ │ ├── events.rs │ │ ├── map.rs │ │ ├── mapmap.rs │ │ ├── message_accumulator.rs │ │ ├── mod.rs │ │ ├── multimap.rs │ │ ├── set.rs │ │ └── set_multimap.rs └── tests │ ├── batch_return_test.rs │ ├── mapmap_test.rs │ ├── multimap_test.rs │ ├── set_multimap_test.rs │ ├── set_test.rs │ └── types_test.rs ├── rust-toolchain.toml ├── rustfmt.toml ├── scripts ├── docker-entrypoint.sh └── upload-release-assets.sh ├── src ├── lib.rs └── main.rs ├── state ├── Cargo.toml └── src │ ├── check.rs │ └── lib.rs ├── test_vm ├── Cargo.toml ├── src │ ├── constants.rs │ ├── lib.rs │ └── messaging.rs └── tests │ ├── README.md │ ├── all_tests.rs │ └── suite │ ├── authenticate_message_test.rs │ ├── batch_onboarding.rs │ ├── batch_onboarding_deals_test.rs │ ├── change_beneficiary_test.rs │ ├── change_owner_test.rs │ ├── commit_post_test.rs │ ├── datacap_tests.rs │ ├── evm_test.rs │ ├── extend_sectors_test.rs │ ├── init_test.rs │ ├── market_miner_withdrawal_test.rs │ ├── mod.rs │ ├── move_partitions_test.rs │ ├── multisig_test.rs │ ├── power_scenario_tests.rs │ ├── prove_commit3_test.rs │ ├── prove_commit_niporep_test.rs │ ├── publish_deals_test.rs │ ├── replica_update3_test.rs │ ├── replica_update_test.rs │ ├── terminate_test.rs │ ├── test_vm_test.rs │ ├── verified_claim_test.rs │ ├── verifreg_remove_datacap_test.rs │ └── withdraw_balance_test.rs └── vm_api ├── Cargo.toml └── src ├── builtin.rs ├── error.rs ├── lib.rs ├── trace.rs └── util ├── blockstore.rs └── mod.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = [ 3 | # Force unwrapping Result<_, Err>, especially for tests. 4 | "-D", "unused_must_use", 5 | ] 6 | 7 | [target.wasm32-unknown-unknown] 8 | rustflags = [ 9 | "-Ctarget-feature=+bulk-memory", 10 | "-Ctarget-feature=+crt-static", 11 | "-Ctarget-feature=+mutable-globals", 12 | "-Ctarget-feature=+sign-ext", 13 | "-Ctarget-feature=-reference-types", 14 | "-Ctarget-feature=-multivalue", 15 | "-Ctarget-feature=-atomics", 16 | "-Clink-arg=--export-table", 17 | ] 18 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous integration 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | merge_group: 9 | 10 | env: 11 | RUSTFLAGS: -Dwarnings 12 | CARGO_INCREMENTAL: 0 # Speeds up the build (no cache) and reduces disk space! 13 | 14 | jobs: 15 | rustfmt: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checking out 19 | uses: actions/checkout@v3 20 | - name: Running rustfmt 21 | run: make rustfmt 22 | 23 | check-clippy: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Checking out 27 | uses: actions/checkout@v3 28 | - name: Running clippy 29 | run: make check 30 | 31 | test: 32 | runs-on: ${{ fromJSON(github.repository == 'filecoin-project/builtin-actors' && '["self-hosted", "linux", "x64", "4xlarge"]' || '"ubuntu-latest"') }} 33 | steps: 34 | - name: Checking out 35 | uses: actions/checkout@v3 36 | - if: env.RUNNER_ENVIRONMENT != 'github-hosted' 37 | uses: dtolnay/rust-toolchain@stable 38 | - name: Installing the toolchain 39 | run: make toolchain 40 | - name: Install cargo-nextest 41 | uses: taiki-e/install-action@9903ab6feadaec33945de535fe9d181b91802a55 # v2.50.0 42 | with: 43 | tool: cargo-nextest 44 | - name: Running tests 45 | run: make test 46 | 47 | build: 48 | runs-on: ubuntu-latest 49 | strategy: 50 | matrix: 51 | network: [ 'mainnet', 'caterpillarnet', 'butterflynet', 'calibrationnet', 'devnet', 'testing', 'testing-fake-proofs' ] 52 | steps: 53 | - name: Checking out 54 | uses: actions/checkout@v3 55 | - name: Writing bundle 56 | env: 57 | BUILD_FIL_NETWORK: ${{ matrix.network }} 58 | run: | 59 | make bundle-repro 60 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: Coverage 2 | 3 | on: workflow_dispatch 4 | 5 | env: 6 | RUSTFLAGS: -Dwarnings 7 | CARGO_INCREMENTAL: 0 # Speeds up the build (no cache) and reduces disk space! 8 | 9 | jobs: 10 | coverage: 11 | runs-on: ubuntu-latest 12 | env: 13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | steps: 15 | - name: Checking out 16 | uses: actions/checkout@v3 17 | - name: Put LLVM tools into the PATH 18 | run: echo "$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin" >> $GITHUB_PATH 19 | - name: Install demangler 20 | run: sudo apt-get install -y rustfilt 21 | - name: Create coverage report 22 | env: 23 | # Make sure that each run of an executable creates a new profile file, 24 | # with the default name they would override each other. 25 | LLVM_PROFILE_FILE: "%m.profraw" 26 | RUSTFLAGS: "-Cinstrument-coverage" 27 | run: cargo test --workspace --exclude fil_builtin_actors_bundle 28 | - name: Merge profiling data 29 | # Do *not* use sparse output. It leads to more lines that are not taken 30 | # into account at all 31 | run: llvm-profdata merge --output=default.profdata $(find . -name '*.profraw') 32 | - name: Create HTML coverage report 33 | # The compiled files contain the coverage information. From running the 34 | # tests we don't know what those files are called, hence use all files 35 | # from the `./target/debug/deps` directory which don't have an extension. 36 | run: | 37 | OBJECT_OPTIONS=($(find ./target/debug/deps/* -name '*' -not -name '*\.*' -printf ' --object %p')) 38 | # Create HTML report of this project, we don't care about coverage of 39 | # dependencies 40 | llvm-cov show --Xdemangler=rustfilt --show-expansions --show-line-counts-or-regions --ignore-filename-regex=".cargo|.rustup|/rustc|./tests/" --format=html --output-dir=./llvm-show --instr-profile=default.profdata ${OBJECT_OPTIONS[@]} 41 | # Create file to be uploaded to codecov 42 | llvm-cov export --ignore-filename-regex=".cargo|.rustup|/rustc|./tests" --format=lcov --instr-profile=default.profdata ${OBJECT_OPTIONS[@]} > lcov.info 43 | - name: Archive code coverage results 44 | uses: actions/upload-artifact@v4 45 | with: 46 | name: code-coverage-report 47 | path: llvm-show/* 48 | - name: Upload coverage to Codecov 49 | uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 50 | with: 51 | files: lcov.info 52 | -------------------------------------------------------------------------------- /.github/workflows/deny.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run `cargo-deny`, checking for dependency issues related to licensing, known vulnerabilities, and more. 2 | # The configuration file is in [deny.toml](../../deny.toml). 3 | name: Cargo Deny 4 | on: 5 | push: 6 | branches: 7 | - master 8 | pull_request: 9 | merge_group: 10 | 11 | jobs: 12 | cargo-deny: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: EmbarkStudios/cargo-deny-action@v2 17 | with: 18 | rust-version: "1.81.0" 19 | -------------------------------------------------------------------------------- /.github/workflows/release-check.yml: -------------------------------------------------------------------------------- 1 | name: Release Checker 2 | 3 | on: 4 | pull_request_target: 5 | paths: ["Cargo.toml"] 6 | types: [ opened, synchronize, reopened, labeled, unlabeled ] 7 | workflow_dispatch: 8 | 9 | permissions: 10 | contents: write 11 | pull-requests: write 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.event.pull_request.head.ref || github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | release-check: 19 | uses: ipdxco/unified-github-workflows/.github/workflows/release-check.yml@v1.0 20 | with: 21 | sources: '["Cargo.toml"]' 22 | -------------------------------------------------------------------------------- /.github/workflows/releaser.yml: -------------------------------------------------------------------------------- 1 | name: Releaser 2 | 3 | on: 4 | push: 5 | paths: ["Cargo.toml"] 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: write 10 | 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.ref }}-${{ github.sha }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | # Create/update a draft release if this is a release creating push event 17 | draft: 18 | uses: ipdxco/unified-github-workflows/.github/workflows/releaser.yml@v1.0 19 | with: 20 | sources: '["Cargo.toml"]' 21 | draft: true 22 | # If a draft release was created/updated, build and upload release assets 23 | upload-release-assets: 24 | needs: [draft] 25 | if: fromJSON(needs.draft.outputs.json)['Cargo.toml'] 26 | uses: ./.github/workflows/upload-release-assets.yml 27 | with: 28 | release_id: ${{ fromJSON(needs.draft.outputs.json)['Cargo.toml'].id }} 29 | # If a draft release was created/update, publish the release 30 | releaser: 31 | needs: [draft, upload-release-assets] 32 | if: fromJSON(needs.draft.outputs.json)['Cargo.toml'] 33 | uses: ipdxco/unified-github-workflows/.github/workflows/releaser.yml@v1.0 34 | with: 35 | sources: '["Cargo.toml"]' 36 | draft: false 37 | secrets: 38 | UCI_GITHUB_TOKEN: ${{ secrets.UCI_GITHUB_TOKEN }} 39 | -------------------------------------------------------------------------------- /.github/workflows/tagpush.yml: -------------------------------------------------------------------------------- 1 | name: Tag Push Checker 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | permissions: 9 | contents: read 10 | issues: write 11 | 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.ref }} 14 | cancel-in-progress: true 15 | 16 | jobs: 17 | releaser: 18 | uses: ipdxco/unified-github-workflows/.github/workflows/tagpush.yml@v1.0 19 | -------------------------------------------------------------------------------- /.github/workflows/upload-release-assets.yml: -------------------------------------------------------------------------------- 1 | name: Upload Release Assets 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_id: 7 | description: 'The id of the release to upload the assets for' 8 | required: true 9 | type: string 10 | release_ref: 11 | description: 'The ref to build the release assets from' 12 | required: false 13 | type: string 14 | workflow_call: 15 | inputs: 16 | release_id: 17 | required: true 18 | type: string 19 | release_ref: 20 | required: false 21 | type: string 22 | 23 | permissions: 24 | contents: write 25 | 26 | jobs: 27 | upload-release-assets: 28 | runs-on: ubuntu-latest 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | network: [ 'mainnet', 'caterpillarnet', 'butterflynet', 'calibrationnet', 'devnet', 'testing', 'testing-fake-proofs' ] 35 | steps: 36 | - name: Checking out builtin-actors 37 | uses: actions/checkout@v4 38 | with: 39 | ref: ${{ inputs.release_ref || github.ref }} 40 | - name: Writing bundle 41 | env: 42 | BUILD_FIL_NETWORK: ${{ matrix.network }} 43 | run: | 44 | make bundle-repro 45 | - name: Upload release assets to GitHub Release 46 | env: 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | GITHUB_RELEASE_URL: ${{ github.api_url }}/repos/${{ github.repository }}/releases/${{ inputs.release_id }} 49 | BUILD_FIL_NETWORK: ${{ matrix.network }} 50 | run: | 51 | git checkout $GITHUB_REF -- scripts/upload-release-assets.sh 52 | ./scripts/upload-release-assets.sh 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | *.wat 3 | *.wasm 4 | .idea/ 5 | .vscode/ 6 | **/.DS_Store 7 | output/* 8 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.81.0-bookworm@sha256:7b7f7ae5e49819e708369d49925360bde2af4f1962842e75a14af17342f08262 2 | 3 | WORKDIR /usr/src/builtin-actors 4 | 5 | # Install the compiler. Unfortunately, the rust docker container doesn't actually contain the rust 6 | # compiler... 7 | COPY ./rust-toolchain.toml . 8 | RUN rustup show 9 | 10 | # Then checkout a clean copy of the repo. 11 | RUN --mount=type=bind,rw,target=/tmp/repo \ 12 | echo "Building $(git -C /tmp/repo rev-parse HEAD)" && \ 13 | git --git-dir /tmp/repo/.git --work-tree . checkout -f HEAD 14 | 15 | ENTRYPOINT ["./scripts/docker-entrypoint.sh"] 16 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 2 | 3 | http://www.apache.org/licenses/LICENSE-2.0 4 | 5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 6 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | This document describes the process for releasing a new version of the `builtin-actors` project. 4 | 5 | ## Current State 6 | 7 | 1. Create a pull request which updates the `workspace.package.version` in the [top-level `Cargo.toml` file](https://github.com/filecoin-project/builtin-actors/blob/master/Cargo.toml). 8 | - Title the PR `chore: release X.Y.Z` 9 | 2. On pull request creation, a [Release Checker](.github/workflows/release-check.yml) workflow will run. It will perform the following actions: 10 | 1. Extract the version from the top-level `Cargo.toml` file. 11 | 2. Check if a git tag for the version already exists. Continue only if it does not. 12 | 3. Create a draft GitHub release with the version as the tag. (A git tag with this version string will be created when the release is published.) 13 | 4. Comment on the pull request with a link to the draft release. 14 | 3. On pull request merge, a [Releaser](.github/workflows/releaser.yml) workflow will run. It will perform the following actions: 15 | 1. Extract the version from the top-level `Cargo.toml` file. 16 | 2. Check if a git tag for the version already exists. Continue only if it does not. 17 | 3. Check if a draft GitHub release with the version as the tag exists. Otherwise, create it. 18 | 4. Trigger the [Upload Release Assets](.github/workflows/upload-release-assets.yml) workflow to: 19 | 1. Build `builtin-actors.car`s for various networks. 20 | 2. Generate checksums for the built `builtin-actors.car`s. 21 | 3. Upload the built `builtin-actors.car`s and checksums as assets to the draft release. 22 | 5. Publish the draft release. Publishing the release creates the git tag. 23 | 24 | ## Known Limitations 25 | 26 | 1. Unless triggered manually, release assets will only be built after merging the release PR. 27 | -------------------------------------------------------------------------------- /actors/account/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_account" 3 | description = "Builtin account actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true } 18 | frc42_dispatch = { workspace = true } 19 | fvm_actor_utils = { workspace = true } 20 | fvm_shared = { workspace = true } 21 | serde = { workspace = true } 22 | num-traits = { workspace = true } 23 | num-derive = { workspace = true } 24 | fvm_ipld_blockstore = { workspace = true } 25 | fvm_ipld_encoding = { workspace = true } 26 | anyhow = { workspace = true } 27 | 28 | [dev-dependencies] 29 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 30 | 31 | [features] 32 | fil-actor = ["fil_actors_runtime/fil-actor"] 33 | -------------------------------------------------------------------------------- /actors/account/src/state.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use fvm_ipld_encoding::tuple::*; 5 | use fvm_shared::address::Address; 6 | 7 | /// State includes the address for the actor 8 | #[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone)] 9 | pub struct State { 10 | pub address: Address, 11 | } 12 | -------------------------------------------------------------------------------- /actors/account/src/testing.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_runtime::{FIRST_NON_SINGLETON_ADDR, MessageAccumulator}; 2 | use fvm_shared::address::{Address, Protocol}; 3 | 4 | use crate::State; 5 | 6 | pub struct StateSummary { 7 | pub pub_key_address: Address, 8 | } 9 | 10 | /// Checks internal invariants of account state. 11 | pub fn check_state_invariants( 12 | state: &State, 13 | id_address: &Address, 14 | ) -> (StateSummary, MessageAccumulator) { 15 | let acc = MessageAccumulator::default(); 16 | 17 | match id_address.id() { 18 | Ok(id) if id >= FIRST_NON_SINGLETON_ADDR => { 19 | acc.require( 20 | state.address.protocol() == Protocol::BLS 21 | || state.address.protocol() == Protocol::Secp256k1, 22 | format!("actor address {} must be BLS or SECP256K1 protocol", state.address), 23 | ); 24 | } 25 | Err(e) => acc.add(format!("error extracting actor ID from address: {e}")), 26 | _ => (), 27 | } 28 | 29 | (StateSummary { pub_key_address: state.address }, acc) 30 | } 31 | -------------------------------------------------------------------------------- /actors/account/src/types.rs: -------------------------------------------------------------------------------- 1 | use fvm_ipld_encoding::strict_bytes; 2 | use fvm_ipld_encoding::tuple::*; 3 | use fvm_shared::address::Address; 4 | 5 | #[derive(Debug, Serialize_tuple, Deserialize_tuple)] 6 | #[serde(transparent)] 7 | pub struct ConstructorParams { 8 | pub address: Address, 9 | } 10 | 11 | #[derive(Debug, Serialize_tuple, Deserialize_tuple)] 12 | #[serde(transparent)] 13 | pub struct PubkeyAddressReturn { 14 | pub address: Address, 15 | } 16 | 17 | #[derive(Debug, Serialize_tuple, Deserialize_tuple)] 18 | pub struct AuthenticateMessageParams { 19 | #[serde(with = "strict_bytes")] 20 | pub signature: Vec, 21 | #[serde(with = "strict_bytes")] 22 | pub message: Vec, 23 | } 24 | 25 | #[derive(Debug, Serialize_tuple, Deserialize_tuple)] 26 | #[serde(transparent)] 27 | pub struct AuthenticateMessageReturn { 28 | pub authenticated: bool, 29 | } 30 | -------------------------------------------------------------------------------- /actors/cron/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_cron" 3 | description = "Builtin cron actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true } 18 | fvm_shared = { workspace = true } 19 | num-traits = { workspace = true } 20 | num-derive = { workspace = true } 21 | log = { workspace = true } 22 | serde = { workspace = true } 23 | fvm_ipld_blockstore = { workspace = true } 24 | fvm_ipld_encoding = { workspace = true } 25 | 26 | [dev-dependencies] 27 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 28 | 29 | [features] 30 | fil-actor = ["fil_actors_runtime/fil-actor"] 31 | -------------------------------------------------------------------------------- /actors/cron/src/state.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use fvm_ipld_encoding::tuple::*; 5 | use fvm_shared::MethodNum; 6 | use fvm_shared::address::Address; 7 | 8 | /// Cron actor state which holds entries to call during epoch tick 9 | #[derive(Default, Serialize_tuple, Deserialize_tuple, Clone, Debug)] 10 | pub struct State { 11 | /// Entries is a set of actors (and corresponding methods) to call during EpochTick. 12 | pub entries: Vec, 13 | } 14 | 15 | #[derive(Clone, PartialEq, Eq, Debug, Serialize_tuple, Deserialize_tuple)] 16 | pub struct Entry { 17 | /// The actor to call (ID address) 18 | pub receiver: Address, 19 | /// The method number to call (must accept empty parameters) 20 | pub method_num: MethodNum, 21 | } 22 | -------------------------------------------------------------------------------- /actors/cron/src/testing.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_runtime::MessageAccumulator; 2 | use fvm_shared::address::Protocol; 3 | 4 | use crate::State; 5 | 6 | pub struct StateSummary { 7 | pub entry_count: usize, 8 | } 9 | 10 | pub fn check_state_invariants(state: &State) -> (StateSummary, MessageAccumulator) { 11 | let acc = MessageAccumulator::default(); 12 | 13 | state.entries.iter().enumerate().for_each(|(i, entry)| { 14 | acc.require( 15 | entry.receiver.protocol() == Protocol::ID, 16 | format!("entry {i} receiver address {} must be ID protocol", entry.receiver), 17 | ); 18 | acc.require( 19 | entry.method_num > 0, 20 | format!("entry {i} has invalid method number {}", entry.method_num), 21 | ); 22 | }); 23 | 24 | (StateSummary { entry_count: state.entries.len() }, acc) 25 | } 26 | -------------------------------------------------------------------------------- /actors/datacap/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_datacap" 3 | description = "Builtin data cap actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true} 18 | 19 | cid = { workspace = true } 20 | frc42_dispatch = { workspace = true } 21 | frc46_token = { workspace = true } 22 | fvm_actor_utils = { workspace = true } 23 | fvm_ipld_blockstore = { workspace = true } 24 | fvm_ipld_encoding = { workspace = true } 25 | fvm_ipld_hamt = { workspace = true } 26 | fvm_shared = { workspace = true } 27 | lazy_static = { workspace = true } 28 | num-derive = { workspace = true } 29 | num-traits = { workspace = true } 30 | serde = { workspace = true } 31 | log = { workspace = true } 32 | 33 | [dev-dependencies] 34 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 35 | [features] 36 | fil-actor = ["fil_actors_runtime/fil-actor"] 37 | 38 | -------------------------------------------------------------------------------- /actors/datacap/src/state.rs: -------------------------------------------------------------------------------- 1 | use frc46_token::token; 2 | use fvm_ipld_blockstore::Blockstore; 3 | use fvm_ipld_encoding::tuple::*; 4 | use fvm_shared::ActorID; 5 | use fvm_shared::address::Address; 6 | use fvm_shared::econ::TokenAmount; 7 | use fvm_shared::error::ExitCode; 8 | 9 | use fil_actors_runtime::{ActorError, AsActorError}; 10 | 11 | #[derive(Serialize_tuple, Deserialize_tuple)] 12 | pub struct State { 13 | pub governor: Address, 14 | pub token: token::state::TokenState, 15 | } 16 | 17 | impl State { 18 | pub fn new(store: &BS, governor: Address) -> Result { 19 | let token_state = token::state::TokenState::new(store) 20 | .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to create token state")?; 21 | Ok(State { governor, token: token_state }) 22 | } 23 | 24 | // Visible for testing 25 | pub fn balance( 26 | &self, 27 | bs: &BS, 28 | owner: ActorID, 29 | ) -> Result { 30 | self.token 31 | .get_balance(bs, owner) 32 | .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to get balance") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /actors/datacap/src/testing.rs: -------------------------------------------------------------------------------- 1 | use frc46_token::token::state::StateSummary; 2 | use fvm_ipld_blockstore::Blockstore; 3 | use fvm_shared::address::Protocol; 4 | 5 | use fil_actors_runtime::MessageAccumulator; 6 | 7 | use crate::{DATACAP_GRANULARITY, State}; 8 | 9 | /// Checks internal invariants of data cap token actor state. 10 | pub fn check_state_invariants( 11 | state: &State, 12 | store: &BS, 13 | ) -> (StateSummary, MessageAccumulator) { 14 | let acc = MessageAccumulator::default(); 15 | acc.require(state.governor.protocol() == Protocol::ID, "governor must be ID address"); 16 | let (summary, msgs) = state.token.check_invariants(store, DATACAP_GRANULARITY); 17 | for e in msgs { 18 | acc.add(e.to_string()); 19 | } 20 | (summary, acc) 21 | } 22 | -------------------------------------------------------------------------------- /actors/eam/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_eam" 3 | description = "Builtin Ethereum address manager actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm", "evm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | anyhow = { workspace = true } 18 | cid = { workspace = true } 19 | fil_actors_evm_shared = { workspace = true } 20 | fil_actors_runtime = { workspace = true } 21 | fvm_ipld_blockstore = { workspace = true } 22 | fvm_ipld_encoding = { workspace = true } 23 | fvm_shared = { workspace = true } 24 | log = { workspace = true } 25 | multihash = { workspace = true } 26 | num-derive = { workspace = true } 27 | num-traits = { workspace = true } 28 | serde = { workspace = true } 29 | hex-literal = { workspace = true } 30 | rlp = { workspace = true } 31 | 32 | [dev-dependencies] 33 | fil_actor_evm = { workspace = true} 34 | fil_actors_runtime = { workspace = true, features = ["test_utils"] } 35 | 36 | [features] 37 | fil-actor = ["fil_actors_runtime/fil-actor"] 38 | -------------------------------------------------------------------------------- /actors/eam/src/ext.rs: -------------------------------------------------------------------------------- 1 | use cid::Cid; 2 | use fvm_ipld_encoding::RawBytes; 3 | use fvm_ipld_encoding::tuple::*; 4 | use fvm_shared::address::Address; 5 | 6 | pub mod init { 7 | 8 | use super::*; 9 | 10 | pub const EXEC4_METHOD: u64 = 3; 11 | 12 | /// Init actor Exec4 Params 13 | #[derive(Serialize_tuple, Deserialize_tuple, Debug)] 14 | pub struct Exec4Params { 15 | pub code_cid: Cid, 16 | pub constructor_params: RawBytes, 17 | pub subaddress: RawBytes, 18 | } 19 | 20 | /// Init actor Exec4 Return value 21 | #[derive(Serialize_tuple, Deserialize_tuple, Debug)] 22 | pub struct Exec4Return { 23 | /// ID based address for created actor 24 | pub id_address: Address, 25 | /// Reorg safe address for actor 26 | pub robust_address: Address, 27 | } 28 | } 29 | 30 | pub mod evm { 31 | use super::*; 32 | use fil_actors_evm_shared::address::EthAddress; 33 | 34 | #[derive(Serialize_tuple, Deserialize_tuple, Clone)] 35 | pub struct ConstructorParams { 36 | /// The actor's "creator" (specified by the EAM). 37 | pub creator: EthAddress, 38 | /// The initcode that will construct the new EVM actor. 39 | pub initcode: RawBytes, 40 | } 41 | 42 | pub const RESURRECT_METHOD: u64 = 2; 43 | } 44 | 45 | pub mod account { 46 | pub const PUBKEY_ADDRESS_METHOD: u64 = 2; 47 | } 48 | -------------------------------------------------------------------------------- /actors/ethaccount/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_ethaccount" 3 | description = "Builtin Ethereum Externally Owned Address actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm", "evm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true } 18 | frc42_dispatch = { workspace = true } 19 | fvm_actor_utils = { workspace = true } 20 | serde = { workspace = true } 21 | fvm_ipld_encoding = { workspace = true } 22 | fvm_shared = { workspace = true } 23 | num-traits = { workspace = true } 24 | num-derive = { workspace = true } 25 | hex-literal = { workspace = true } 26 | 27 | [dev-dependencies] 28 | fil_actors_runtime = { workspace = true, features = ["test_utils"] } 29 | 30 | [features] 31 | fil-actor = ["fil_actors_runtime/fil-actor"] 32 | -------------------------------------------------------------------------------- /actors/ethaccount/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod types; 2 | 3 | use fvm_ipld_encoding::ipld_block::IpldBlock; 4 | use fvm_shared::address::Payload; 5 | use fvm_shared::{METHOD_CONSTRUCTOR, MethodNum}; 6 | use num_derive::FromPrimitive; 7 | 8 | use fil_actors_runtime::runtime::{ActorCode, Runtime}; 9 | use fil_actors_runtime::{ 10 | ActorError, EAM_ACTOR_ID, FIRST_EXPORTED_METHOD_NUMBER, SYSTEM_ACTOR_ADDR, actor_dispatch, 11 | actor_error, 12 | }; 13 | 14 | #[cfg(feature = "fil-actor")] 15 | fil_actors_runtime::wasm_trampoline!(EthAccountActor); 16 | 17 | /// Ethereum Account actor methods. 18 | #[derive(FromPrimitive)] 19 | #[repr(u64)] 20 | pub enum Method { 21 | Constructor = METHOD_CONSTRUCTOR, 22 | } 23 | 24 | /// Ethereum Account actor. 25 | pub struct EthAccountActor; 26 | 27 | impl EthAccountActor { 28 | /// Ethereum Account actor constructor. 29 | /// NOTE: This method is NOT currently called from anywhere, instead the FVM just deploys EthAccounts. 30 | pub fn constructor(rt: &impl Runtime) -> Result<(), ActorError> { 31 | rt.validate_immediate_caller_is(std::iter::once(&SYSTEM_ACTOR_ADDR))?; 32 | 33 | match rt 34 | .lookup_delegated_address(rt.message().receiver().id().unwrap()) 35 | .map(|a| *a.payload()) 36 | { 37 | Some(Payload::Delegated(da)) if da.namespace() == EAM_ACTOR_ID => {} 38 | Some(_) => { 39 | return Err(ActorError::illegal_argument( 40 | "invalid target for EthAccount creation".to_string(), 41 | )); 42 | } 43 | None => { 44 | return Err(ActorError::illegal_argument( 45 | "receiver must have a predictable address".to_string(), 46 | )); 47 | } 48 | } 49 | 50 | Ok(()) 51 | } 52 | 53 | // Always succeeds, accepting any transfers. 54 | pub fn fallback( 55 | rt: &impl Runtime, 56 | method: MethodNum, 57 | _: Option, 58 | ) -> Result, ActorError> { 59 | rt.validate_immediate_caller_accept_any()?; 60 | if method >= FIRST_EXPORTED_METHOD_NUMBER { 61 | Ok(None) 62 | } else { 63 | Err(actor_error!(unhandled_message; "invalid method: {}", method)) 64 | } 65 | } 66 | } 67 | 68 | impl ActorCode for EthAccountActor { 69 | type Methods = Method; 70 | 71 | fn name() -> &'static str { 72 | "EVMAccount" 73 | } 74 | 75 | actor_dispatch! { 76 | Constructor => constructor, 77 | _ => fallback, 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /actors/ethaccount/src/types.rs: -------------------------------------------------------------------------------- 1 | use fvm_ipld_encoding::strict_bytes; 2 | use fvm_ipld_encoding::tuple::*; 3 | 4 | #[derive(Debug, Serialize_tuple, Deserialize_tuple)] 5 | pub struct AuthenticateMessageParams { 6 | #[serde(with = "strict_bytes")] 7 | pub signature: Vec, 8 | #[serde(with = "strict_bytes")] 9 | pub message: Vec, 10 | } 11 | -------------------------------------------------------------------------------- /actors/ethaccount/tests/ethaccount_test.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | 3 | use crate::util::*; 4 | use fvm_actor_utils::receiver::UniversalReceiverParams; 5 | use fvm_ipld_encoding::RawBytes; 6 | use fvm_ipld_encoding::ipld_block::IpldBlock; 7 | use fvm_shared::address::Address; 8 | 9 | use fil_actor_ethaccount::{EthAccountActor, Method}; 10 | use fvm_shared::MethodNum; 11 | use fvm_shared::error::ExitCode; 12 | 13 | use fil_actors_runtime::SYSTEM_ACTOR_ADDR; 14 | use fil_actors_runtime::test_utils::{ 15 | ACCOUNT_ACTOR_CODE_ID, SYSTEM_ACTOR_CODE_ID, expect_abort_contains_message, 16 | }; 17 | 18 | #[test] 19 | fn no_delegated_cant_deploy() { 20 | let rt = new_runtime(); 21 | rt.expect_validate_caller_addr(vec![SYSTEM_ACTOR_ADDR]); 22 | rt.set_caller(*SYSTEM_ACTOR_CODE_ID, SYSTEM_ACTOR_ADDR); 23 | expect_abort_contains_message( 24 | ExitCode::USR_ILLEGAL_ARGUMENT, 25 | "receiver must have a predictable address", 26 | rt.call::(Method::Constructor as MethodNum, None), 27 | ); 28 | rt.verify(); 29 | } 30 | 31 | #[test] 32 | fn token_receiver() { 33 | let rt = setup(); 34 | 35 | rt.set_caller(*ACCOUNT_ACTOR_CODE_ID, Address::new_id(1234)); 36 | rt.expect_validate_caller_any(); 37 | let ret = rt 38 | .call::( 39 | frc42_dispatch::method_hash!("Receive"), 40 | IpldBlock::serialize_cbor(&UniversalReceiverParams { 41 | type_: 0, 42 | payload: RawBytes::new(vec![1, 2, 3]), 43 | }) 44 | .unwrap(), 45 | ) 46 | .unwrap(); 47 | assert!(ret.is_none()); 48 | } 49 | -------------------------------------------------------------------------------- /actors/ethaccount/tests/util.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | 3 | use fil_actor_ethaccount::{EthAccountActor, Method}; 4 | use fil_actors_runtime::EAM_ACTOR_ID; 5 | use fil_actors_runtime::SYSTEM_ACTOR_ADDR; 6 | use fil_actors_runtime::test_utils::{MockRuntime, SYSTEM_ACTOR_CODE_ID}; 7 | use fvm_shared::MethodNum; 8 | use fvm_shared::address::Address; 9 | 10 | pub const EOA: Address = Address::new_id(1000); 11 | 12 | pub fn new_runtime() -> MockRuntime { 13 | MockRuntime { 14 | receiver: EOA, 15 | caller: RefCell::new(SYSTEM_ACTOR_ADDR), 16 | caller_type: RefCell::new(*SYSTEM_ACTOR_CODE_ID), 17 | ..Default::default() 18 | } 19 | } 20 | 21 | #[allow(dead_code)] 22 | pub fn setup() -> MockRuntime { 23 | let rt = new_runtime(); 24 | rt.expect_validate_caller_addr(vec![SYSTEM_ACTOR_ADDR]); 25 | rt.set_caller(*SYSTEM_ACTOR_CODE_ID, SYSTEM_ACTOR_ADDR); 26 | rt.set_delegated_address( 27 | EOA.id().unwrap(), 28 | Address::new_delegated( 29 | EAM_ACTOR_ID, 30 | &hex_literal::hex!("FEEDFACECAFEBEEF000000000000000000000000"), 31 | ) 32 | .unwrap(), 33 | ); 34 | rt.call::(Method::Constructor as MethodNum, None).unwrap(); 35 | rt.verify(); 36 | rt 37 | } 38 | -------------------------------------------------------------------------------- /actors/evm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_evm" 3 | description = "Builtin EVM actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm", "evm"] 10 | exclude = ["/precompile-testdata", "/tests/measurements", "/tests/contracts"] 11 | 12 | [lib] 13 | ## lib is necessary for integration tests 14 | ## cdylib is necessary for Wasm build 15 | crate-type = ["cdylib", "lib"] 16 | 17 | [dependencies] 18 | fil_actors_runtime = { workspace = true } 19 | fvm_shared = { workspace = true } 20 | fvm_ipld_kamt = { workspace = true } 21 | serde = { workspace = true } 22 | num-traits = { workspace = true } 23 | num-derive = { workspace = true } 24 | cid = { workspace = true } 25 | anyhow = { workspace = true } 26 | log = { workspace = true } 27 | fvm_ipld_blockstore = { workspace = true } 28 | fvm_ipld_encoding = { workspace = true } 29 | multihash-codetable = { workspace = true } 30 | frc42_dispatch = { workspace = true } 31 | fil_actors_evm_shared = { workspace = true } 32 | hex = { workspace = true } 33 | hex-literal = { workspace = true } 34 | substrate-bn = { workspace = true } 35 | thiserror = { workspace = true } 36 | 37 | [dev-dependencies] 38 | hex = { workspace = true, features = ["serde"] } 39 | lazy_static = { workspace = true } 40 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 41 | etk-asm = { workspace = true } 42 | alloy-core = { workspace = true } 43 | serde_json = { workspace = true } 44 | rand = { workspace = true } 45 | once_cell = { workspace = true } 46 | 47 | 48 | [features] 49 | fil-actor = ["fil_actors_runtime/fil-actor"] 50 | -------------------------------------------------------------------------------- /actors/evm/Makefile: -------------------------------------------------------------------------------- 1 | TEST_CONTRACTS_DIR = tests/contracts 2 | TEST_CONTRACTS_SOL = $(shell find $(TEST_CONTRACTS_DIR) -type f -name "*.sol") 3 | TEST_CONTRACTS_HEX = $(TEST_CONTRACTS_SOL:.sol=.hex) 4 | 5 | MEASUREMENTS_DIR = tests/measurements 6 | MEASUREMENTS_JSON = $(shell find $(MEASUREMENTS_DIR) -type f -name "*.jsonline") 7 | MEASUREMENTS_PNG = $(MEASUREMENTS_JSON:.jsonline=.png) 8 | 9 | .PHONY: all 10 | all: \ 11 | test-contracts \ 12 | measure-storage-footprint \ 13 | plot-measurements 14 | 15 | # Compile all Solidity test contracts. 16 | # This could also be achieved with https://docs.rs/ethers/latest/ethers/solc/ 17 | .PHONY: test-contracts 18 | test-contracts: $(TEST_CONTRACTS_HEX) 19 | 20 | # Compile a Solidity test contract 21 | $(TEST_CONTRACTS_DIR)/%.hex: $(TEST_CONTRACTS_DIR)/%.sol | solc 22 | solc --bin $< | sed '4q;d' | tr -d '\n' > $@ 23 | 24 | $(TEST_CONTRACTS_DIR)/callvariants.hex: $(TEST_CONTRACTS_DIR)/callvariants.eas $(TEST_CONTRACTS_DIR)/callvariants_body.eas 25 | eas $(TEST_CONTRACTS_DIR)/callvariants.eas | tr -d '\n' > $(TEST_CONTRACTS_DIR)/callvariants.hex 26 | 27 | # Run storage footprint tests. 28 | .PHONY: measure-storage-footprint 29 | measure-storage-footprint: 30 | cargo test --test storage_footprint 31 | 32 | 33 | # Render measurement charts. 34 | .PHONY: plot-measurements 35 | plot-measurements: $(MEASUREMENTS_PNG) 36 | 37 | # Render a specfic plot if the data changed. 38 | $(MEASUREMENTS_DIR)/%.png: \ 39 | $(MEASUREMENTS_DIR)/%.jsonline \ 40 | $(MEASUREMENTS_DIR)/storage-footprint.plt \ 41 | $(MEASUREMENTS_DIR)/storage-footprint.sh \ 42 | | jq gnuplot 43 | cd $(MEASUREMENTS_DIR) && ./storage-footprint.sh $* 44 | 45 | 46 | # Requirements checks. 47 | 48 | .PHONY: solc 49 | solc: 50 | @if [ -z "$(shell which solc)" ]; then \ 51 | echo "Please install solc, the Solidity compiler. See https://github.com/crytic/solc-select"; \ 52 | exit 1; \ 53 | fi 54 | 55 | .PHONY: gnuplot 56 | gnuplot: 57 | @if [ -z "$(shell which gnuplot)" ]; then \ 58 | echo "Please install gnuplot. See http://www.gnuplot.info/"; \ 59 | exit 1; \ 60 | fi 61 | 62 | .PHONY: jq 63 | jq: 64 | @if [ -z "$(shell which jq)" ]; then \ 65 | echo "Please install jq. See https://stedolan.github.io/jq/"; \ 66 | exit 1; \ 67 | fi 68 | -------------------------------------------------------------------------------- /actors/evm/README.md: -------------------------------------------------------------------------------- 1 | # EVM 2 | 3 | The EVM actor is a Wasm implementation of the EVM bytecode interpreter, originally prototyped in https://github.com/filecoin-project/fvm-evm/ 4 | 5 | ## Testing 6 | 7 | The `tests` library contains integration tests, some of which use Solidity contracts. The compiled versions of these contracts are checked into [tests/contracts](./tests/contracts). To modify them, you will need to install the [solc](https://docs.soliditylang.org/en/latest/installing-solidity.html) and optionally [solc-select](https://github.com/crytic/solc-select), then from this directory run the following command to generate the new artifacts: 8 | 9 | ```shell 10 | make test-contracts 11 | ``` 12 | -------------------------------------------------------------------------------- /actors/evm/precompile-testdata/README.md: -------------------------------------------------------------------------------- 1 | # EVM Precompile Test Data 2 | 3 | These data files come from [go-ethereum](https://github.com/ethereum/go-ethereum/tree/master/core/vm/testdata/precompiles) and are therefore licensed under the LGPLv3. However, they're not included in published crates (they're excluded by cargo) or build artifacts. They're only loaded at runtime by a few unit tests, and therefore trivially meet the requirements of the LGPL. 4 | -------------------------------------------------------------------------------- /actors/evm/precompile-testdata/ecRecover.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Input": "a8b53bdf3306a35a7103ab5504a0c9b492295564b6202b1942a84ef300107281000000000000000000000000000000000000000000000000000000000000001b307835653165303366353363653138623737326363623030393366663731663366353366356337356237346463623331613835616138623838393262346538621122334455667788991011121314151617181920212223242526272829303132", 4 | "Expected": "", 5 | "Gas": 3000, 6 | "Name": "CallEcrecoverUnrecoverableKey", 7 | "NoBenchmark": false 8 | }, 9 | { 10 | "Input": "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549", 11 | "Expected": "000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", 12 | "Gas": 3000, 13 | "Name": "ValidKey", 14 | "NoBenchmark": false 15 | }, 16 | { 17 | "Input": "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c100000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549", 18 | "Expected": "", 19 | "Gas": 3000, 20 | "Name": "InvalidHighV-bits-1", 21 | "NoBenchmark": false 22 | }, 23 | { 24 | "Input": "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000001000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549", 25 | "Expected": "", 26 | "Gas": 3000, 27 | "Name": "InvalidHighV-bits-2", 28 | "NoBenchmark": false 29 | }, 30 | { 31 | "Input": "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000001000000000000000000000011c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549", 32 | "Expected": "", 33 | "Gas": 3000, 34 | "Name": "InvalidHighV-bits-3", 35 | "NoBenchmark": false 36 | } 37 | ] -------------------------------------------------------------------------------- /actors/evm/precompile-testdata/fail-blake2f.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Input": "", 4 | "ExpectedError": "invalid input length", 5 | "Name": "vector 0: empty input" 6 | }, 7 | { 8 | "Input": "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", 9 | "ExpectedError": "invalid input length", 10 | "Name": "vector 1: less than 213 bytes input" 11 | }, 12 | { 13 | "Input": "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", 14 | "ExpectedError": "invalid input length", 15 | "Name": "vector 2: more than 213 bytes input" 16 | }, 17 | { 18 | "Input": "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002", 19 | "ExpectedError": "invalid final flag", 20 | "Name": "vector 3: malformed final block indicator flag" 21 | } 22 | ] -------------------------------------------------------------------------------- /actors/evm/shared/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actors_evm_shared" 3 | description = "Shared libraries for the built-in EVM actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm", "evm"] 10 | 11 | [dependencies] 12 | serde = { workspace = true } 13 | fvm_shared = { workspace = true } 14 | fil_actors_runtime = { workspace = true } 15 | fvm_ipld_encoding = { workspace = true } 16 | uint = { workspace = true } 17 | hex = { workspace = true } 18 | -------------------------------------------------------------------------------- /actors/evm/shared/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod address; 2 | pub mod uints; 3 | -------------------------------------------------------------------------------- /actors/evm/src/ext.rs: -------------------------------------------------------------------------------- 1 | pub mod eam { 2 | use fil_actors_evm_shared::address::EthAddress; 3 | use fvm_ipld_encoding::{strict_bytes, tuple::*}; 4 | use fvm_shared::address::Address; 5 | 6 | pub const CREATE_METHOD_NUM: u64 = 2; 7 | pub const CREATE2_METHOD_NUM: u64 = 3; 8 | 9 | #[derive(Serialize_tuple, Deserialize_tuple, Clone)] 10 | pub struct CreateParams { 11 | #[serde(with = "strict_bytes")] 12 | pub code: Vec, 13 | pub nonce: u64, 14 | } 15 | 16 | #[derive(Serialize_tuple, Deserialize_tuple, Clone)] 17 | pub struct Create2Params { 18 | #[serde(with = "strict_bytes")] 19 | pub code: Vec, 20 | #[serde(with = "strict_bytes")] 21 | pub salt: [u8; 32], 22 | } 23 | 24 | #[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Copy, PartialEq, Eq)] 25 | pub struct CreateReturn { 26 | pub actor_id: u64, 27 | pub robust_address: Option
, 28 | pub eth_address: EthAddress, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /actors/evm/src/interpreter/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This is the EVM interpreter used in the Filecoin network. 4 | 5 | ## History 6 | 7 | This interpreter was incubated under [fvm-evm](https://github.com/filecoin-project/fvm-evm/). 8 | It was initially based on [evmodin](https://github.com/vorot93/evmodin) (whose [LICENSE](./LICENSE) has been transferred here), 9 | but has diverged significantly. 10 | 11 | ## Divergences 12 | 13 | This is a non-comprehensive list. 14 | 15 | - Because this interpreter does not service an Ethereum network, we were able to remove historical baggage and then 16 | tracking of which opcodes and precompiles were introduced at which forks. This interpreter supports the Berlin hardfork. 17 | - Removed support for continuations. We don't expect to use this feature in FVM. 18 | - Removed support for tracing. We may want to re-introduce this at some point proxying over to the debug::log syscall. 19 | - All instructions under instructions/ have been `#[inlined]`. 20 | - The Host trait has been removed and substituted by a System concrete type that uses the FVM SDK (and thus depends 21 | on the actor Wasm sandbox). We will likely need to restore this trait for unit testing purposes. 22 | - The Memory is now backed by BytesVec instead of a Vec; it exposes a method to grow it, but we need to check that it's 23 | being called from every possible point. 24 | - `Message#code_address` has been removed; we may need to reintroduce when we start handling delegate call. 25 | Bytecode processing has lost features, e.g. code padding (was it an implementation detail?), only-once jumpdest table 26 | derivation and persistence, etc. This is connected with the removal of continuations and other features. 27 | - Many code layout/structure changes and refactors. -------------------------------------------------------------------------------- /actors/evm/src/interpreter/bytecode.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Deref; 2 | 3 | use super::opcodes; 4 | 5 | #[derive(Clone, Debug)] 6 | pub struct Bytecode { 7 | code: Vec, 8 | jumpdest: Vec, 9 | } 10 | 11 | impl Bytecode { 12 | pub fn new(bytecode: Vec) -> Self { 13 | // only jumps to those addresses are valid. This is a security 14 | // feature by EVM to disallow jumps to arbitary code addresses. 15 | let mut jumpdest = vec![false; bytecode.len()]; 16 | let mut i = 0; 17 | while i < bytecode.len() { 18 | if bytecode[i] == opcodes::JUMPDEST { 19 | jumpdest[i] = true; 20 | i += 1; 21 | } else if bytecode[i] >= opcodes::PUSH1 && bytecode[i] <= opcodes::PUSH32 { 22 | i += (bytecode[i] - opcodes::PUSH1) as usize + 2; 23 | } else { 24 | i += 1; 25 | } 26 | } 27 | 28 | Self { code: bytecode, jumpdest } 29 | } 30 | 31 | /// Checks if the EVM is allowed to jump to this location. 32 | /// 33 | /// This location must begin with a JUMPDEST opcode that 34 | /// marks a valid jump destination 35 | pub fn valid_jump_destination(&self, offset: usize) -> bool { 36 | offset < self.jumpdest.len() && self.jumpdest[offset] 37 | } 38 | } 39 | 40 | impl Deref for Bytecode { 41 | type Target = [u8]; 42 | 43 | fn deref(&self) -> &Self::Target { 44 | &self.code 45 | } 46 | } 47 | 48 | impl AsRef<[u8]> for Bytecode { 49 | fn as_ref(&self) -> &[u8] { 50 | &self.code 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /actors/evm/src/interpreter/memory.rs: -------------------------------------------------------------------------------- 1 | use crate::EVM_WORD_SIZE; 2 | use std::ops::{Deref, DerefMut}; 3 | 4 | const PAGE_SIZE: usize = 4 * 1024; 5 | 6 | #[derive(Clone, Debug)] 7 | pub struct Memory(Vec); 8 | 9 | impl Deref for Memory { 10 | type Target = [u8]; 11 | 12 | fn deref(&self) -> &Self::Target { 13 | &self.0 14 | } 15 | } 16 | 17 | impl DerefMut for Memory { 18 | fn deref_mut(&mut self) -> &mut Self::Target { 19 | &mut self.0 20 | } 21 | } 22 | 23 | impl Default for Memory { 24 | fn default() -> Self { 25 | Self(Vec::with_capacity(PAGE_SIZE)) 26 | } 27 | } 28 | 29 | impl Memory { 30 | #[inline] 31 | /// Reserve extra pages of memory 32 | fn reserve_pages(&mut self, pages: usize) { 33 | self.0.reserve((PAGE_SIZE * pages) - self.0.len()); 34 | } 35 | 36 | #[inline] 37 | /// Grows memory to a new size, reserving extra pages as-needed. 38 | /// `new_size` may be unaligned. 39 | /// 40 | /// Do nothing if `new_size` doesn't grow memory. 41 | pub fn grow(&mut self, mut new_size: usize) { 42 | if new_size <= self.len() { 43 | return; 44 | } 45 | 46 | // Align to the next u256. 47 | // Guaranteed to not overflow. 48 | let alignment = new_size % EVM_WORD_SIZE; 49 | if alignment > 0 { 50 | new_size += EVM_WORD_SIZE - alignment; 51 | } 52 | 53 | // Reserve any new pages. 54 | let cap = self.0.capacity(); 55 | if new_size > cap { 56 | let required_pages = new_size.div_ceil(PAGE_SIZE); 57 | self.reserve_pages(required_pages); 58 | } 59 | 60 | debug_assert_eq!(new_size % 32, 0, "MSIZE depends that memory is aligned to 32 bytes"); 61 | // Grow to new aligned size. 62 | self.0.resize(new_size, 0); 63 | } 64 | } 65 | 66 | #[cfg(test)] 67 | mod tests { 68 | use super::*; 69 | 70 | #[test] 71 | fn grow() { 72 | let mut mem = Memory::default(); 73 | mem.grow(PAGE_SIZE * 2 + 1); 74 | assert_eq!(mem.len(), PAGE_SIZE * 2 + EVM_WORD_SIZE); 75 | assert_eq!(mem.0.capacity(), PAGE_SIZE * 3); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /actors/evm/src/interpreter/mod.rs: -------------------------------------------------------------------------------- 1 | mod bytecode; 2 | mod execution; 3 | mod instructions; 4 | mod memory; 5 | mod output; 6 | mod precompiles; 7 | mod stack; 8 | mod system; 9 | 10 | #[cfg(test)] 11 | pub mod test_util; 12 | 13 | pub use { 14 | bytecode::Bytecode, 15 | execution::{ExecutionState, execute, opcodes}, 16 | output::{Outcome, Output}, 17 | system::System, 18 | }; 19 | 20 | /// The kind of call-like instruction. 21 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] 22 | pub enum CallKind { 23 | Call, 24 | DelegateCall, 25 | StaticCall, 26 | } 27 | -------------------------------------------------------------------------------- /actors/evm/src/interpreter/output.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | #[derive(Debug, Clone, PartialEq, Eq, Default)] 4 | pub enum Outcome { 5 | #[default] 6 | Return, 7 | Revert, 8 | } 9 | 10 | /// Output of EVM execution. 11 | #[derive(Debug, Clone, PartialEq, Eq, Default)] 12 | pub struct Output { 13 | /// Indicates the "outcome" of the execution. 14 | pub outcome: Outcome, 15 | /// The return data. 16 | pub return_data: Vec, 17 | /// The final program counter (for debugging). 18 | pub pc: usize, 19 | } 20 | -------------------------------------------------------------------------------- /actors/evm/src/interpreter/test_util.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! evm_instruction { 3 | ($i:ident) => { 4 | $crate::interpreter::execution::opcodes::$i 5 | }; 6 | ($i:literal) => { 7 | $i 8 | }; 9 | ($i:expr) => { 10 | $i 11 | }; 12 | } 13 | 14 | #[macro_export] 15 | macro_rules! evm_unit_test { 16 | (($rt:ident) $init:block ($machine:ident) { $($inst:tt;)* } $($body:tt)*) => { 17 | use ::fil_actors_runtime::test_utils::MockRuntime; 18 | use ::fvm_shared::econ::TokenAmount; 19 | use $crate::interpreter::{execution::Machine, system::System, Output}; 20 | use $crate::{Bytecode, EthAddress, ExecutionState}; 21 | 22 | #[allow(unused_mut)] 23 | let mut $rt = MockRuntime::default(); 24 | $rt.in_call.replace(true); 25 | $init 26 | 27 | let mut state = ExecutionState::new( 28 | EthAddress::from_id(1000), 29 | EthAddress::from_id(1000), 30 | TokenAmount::from_atto(0), 31 | Vec::new(), 32 | ); 33 | 34 | let code = vec![$($crate::evm_instruction!($inst)),*]; 35 | 36 | let mut system = System::new(&$rt, false); 37 | let bytecode = Bytecode::new(code); 38 | #[allow(unused_mut)] 39 | let mut $machine = Machine { 40 | system: &mut system, 41 | state: &mut state, 42 | bytecode: &bytecode, 43 | pc: 0, 44 | output: Output::default(), 45 | }; 46 | 47 | $($body)* 48 | }; 49 | 50 | (($machine:ident) { $($inst:tt;)* } $($body:tt)*) => { 51 | use ::fil_actors_runtime::test_utils::MockRuntime; 52 | use ::fvm_shared::econ::TokenAmount; 53 | use $crate::interpreter::{execution::Machine, system::System, Output}; 54 | use $crate::{Bytecode, EthAddress, ExecutionState}; 55 | 56 | let rt = MockRuntime::default(); 57 | rt.in_call.replace(true); 58 | let mut state = ExecutionState::new( 59 | EthAddress::from_id(1000), 60 | EthAddress::from_id(1000), 61 | TokenAmount::from_atto(0), 62 | Vec::new(), 63 | ); 64 | 65 | let code = vec![$($crate::evm_instruction!($inst)),*]; 66 | 67 | let mut system = System::new(&rt, false); 68 | let bytecode = Bytecode::new(code); 69 | #[allow(unused_mut)] 70 | let mut $machine = Machine { 71 | system: &mut system, 72 | state: &mut state, 73 | bytecode: &bytecode, 74 | pc: 0, 75 | output: Output::default(), 76 | }; 77 | 78 | $($body)* 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /actors/evm/src/types.rs: -------------------------------------------------------------------------------- 1 | use cid::Cid; 2 | use fil_actors_evm_shared::address::EthAddress; 3 | use fil_actors_evm_shared::uints::U256; 4 | use fvm_ipld_encoding::RawBytes; 5 | use fvm_ipld_encoding::strict_bytes; 6 | use fvm_ipld_encoding::tuple::*; 7 | use fvm_shared::econ::TokenAmount; 8 | 9 | #[derive(Serialize_tuple, Deserialize_tuple)] 10 | pub struct ConstructorParams { 11 | /// The actor's "creator" (specified by the EAM). 12 | pub creator: EthAddress, 13 | /// The initcode that will construct the new EVM actor. 14 | pub initcode: RawBytes, 15 | } 16 | 17 | pub type ResurrectParams = ConstructorParams; 18 | 19 | #[derive(Default, Serialize_tuple, Deserialize_tuple)] 20 | #[serde(transparent)] 21 | pub struct InvokeContractParams { 22 | #[serde(with = "strict_bytes")] 23 | pub input_data: Vec, 24 | } 25 | 26 | #[derive(Serialize_tuple, Deserialize_tuple)] 27 | #[serde(transparent)] 28 | pub struct InvokeContractReturn { 29 | #[serde(with = "strict_bytes")] 30 | pub output_data: Vec, 31 | } 32 | 33 | #[derive(Serialize_tuple, Deserialize_tuple)] 34 | #[serde(transparent)] 35 | pub struct BytecodeReturn { 36 | pub code: Option, 37 | } 38 | 39 | #[derive(Serialize_tuple, Deserialize_tuple)] 40 | #[serde(transparent)] 41 | pub struct GetStorageAtReturn { 42 | pub storage: U256, 43 | } 44 | 45 | #[derive(Serialize_tuple, Deserialize_tuple)] 46 | pub struct DelegateCallParams { 47 | pub code: Cid, 48 | /// The contract invocation parameters 49 | #[serde(with = "strict_bytes")] 50 | pub input: Vec, 51 | /// The original caller's Eth address. 52 | pub caller: EthAddress, 53 | /// The value passed in the original call. 54 | pub value: TokenAmount, 55 | } 56 | 57 | #[derive(Serialize_tuple, Deserialize_tuple)] 58 | #[serde(transparent)] 59 | pub struct DelegateCallReturn { 60 | #[serde(with = "strict_bytes")] 61 | pub return_data: Vec, 62 | } 63 | 64 | #[derive(Serialize_tuple, Deserialize_tuple)] 65 | pub struct GetStorageAtParams { 66 | pub storage_key: U256, 67 | } 68 | -------------------------------------------------------------------------------- /actors/evm/tests/calc.rs: -------------------------------------------------------------------------------- 1 | mod asm; 2 | 3 | use fil_actors_evm_shared::uints::U256; 4 | 5 | mod util; 6 | 7 | #[allow(dead_code)] 8 | pub fn magic_calc_contract() -> Vec { 9 | let init = r#" 10 | push1 0x42 # magic value 11 | push1 0x00 # key of magic value 12 | sstore 13 | "#; 14 | let body = r#" 15 | # method dispatch: 16 | # - 0x00000000 -> magic value 17 | # - 0x00000001 -> ADD arg, magic value 18 | # - 0x00000002 -> MUL arg, magic value 19 | 20 | %dispatch_begin() 21 | %dispatch(0x00, get_magic) 22 | %dispatch(0x01, add_magic) 23 | %dispatch(0x02, mul_magic) 24 | %dispatch_end() 25 | 26 | #### method implementation 27 | get_magic: 28 | jumpdest 29 | push1 0x20 # length of return data 30 | push1 0x00 # key of magic 31 | sload 32 | push1 0x00 # return memory offset 33 | mstore 34 | push1 0x00 35 | return 36 | 37 | add_magic: 38 | jumpdest 39 | push1 0x20 # length of return data 40 | push1 0x04 41 | calldataload # arg1 42 | push1 0x00 # key of magic 43 | sload 44 | add 45 | push1 0x00 # return memory offset 46 | mstore 47 | push1 0x00 48 | return 49 | 50 | mul_magic: 51 | jumpdest 52 | push1 0x20 # length of return data 53 | push1 0x04 54 | calldataload # arg1 55 | push1 0x00 # key of magic 56 | sload 57 | mul 58 | push1 0x00 # return memory offset 59 | mstore 60 | push1 0x00 61 | return 62 | 63 | "#; 64 | 65 | asm::new_contract("magic-calc", init, body).unwrap() 66 | } 67 | 68 | #[test] 69 | fn test_magic_calc() { 70 | let contract = magic_calc_contract(); 71 | 72 | let rt = util::construct_and_verify(contract); 73 | 74 | // invoke contract -- get_magic 75 | let contract_params = vec![0u8; 32]; 76 | 77 | let result = util::invoke_contract(&rt, &contract_params); 78 | assert_eq!(U256::from_big_endian(&result), U256::from(0x42)); 79 | 80 | // invoke contract -- add_magic 81 | let mut contract_params = vec![0u8; 36]; 82 | contract_params[3] = 0x01; 83 | contract_params[35] = 0x01; 84 | 85 | let result = util::invoke_contract(&rt, &contract_params); 86 | assert_eq!(U256::from_big_endian(&result), U256::from(0x43)); 87 | 88 | // invoke contract -- mul_magic 89 | let mut contract_params = vec![0u8; 36]; 90 | contract_params[3] = 0x02; 91 | contract_params[35] = 0x02; 92 | 93 | let result = util::invoke_contract(&rt, &contract_params); 94 | assert_eq!(U256::from_big_endian(&result), U256::from(0x84)); 95 | } 96 | -------------------------------------------------------------------------------- /actors/evm/tests/contracts/CallActorPrecompile.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 MIT 2 | pragma solidity >=0.4.25 <=0.8.26; 3 | 4 | contract CallActorPrecompile { 5 | address constant CALL_ACTOR_ADDRESS = 0xfe00000000000000000000000000000000000003; 6 | address constant CALL_ACTOR_ID = 0xfe00000000000000000000000000000000000005; 7 | 8 | function call_actor_id(uint64 method, uint256 value, uint64 flags, uint64 codec, bytes calldata params, uint64 id) public returns (bool, int256, uint64, bytes memory) { 9 | (bool success, bytes memory data) = address(CALL_ACTOR_ID).delegatecall(abi.encode(method, value, flags, codec, params, id)); 10 | (int256 exit, uint64 return_codec, bytes memory return_value) = abi.decode(data, (int256, uint64, bytes)); 11 | return (success, exit, return_codec, return_value); 12 | } 13 | 14 | function call_actor_address(uint64 method, uint256 value, uint64 flags, uint64 codec, bytes calldata params, bytes calldata filAddress) public returns (bool, int256, uint64, bytes memory) { 15 | (bool success, bytes memory data) = address(CALL_ACTOR_ADDRESS).delegatecall(abi.encode(method, value, flags, codec, params, filAddress)); 16 | (int256 exit, uint64 return_codec, bytes memory return_value) = abi.decode(data, (int256, uint64, bytes)); 17 | return (success, exit, return_codec, return_value); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /actors/evm/tests/contracts/FeSimplecoin.fe: -------------------------------------------------------------------------------- 1 | struct Transfer { 2 | #indexed 3 | pub from: address 4 | #indexed 5 | pub to: address 6 | pub value: u256 7 | } 8 | 9 | contract FeSimplecoin { 10 | balances: Map 11 | 12 | pub fn __init__(mut self, ctx: Context) { 13 | self.balances[ctx.tx_origin()] = 10000; 14 | } 15 | 16 | pub fn sendCoin(mut self, mut ctx: Context, receiver: address, amount: u256) -> bool { 17 | if self.balances[ctx.msg_sender()] < amount { 18 | return false 19 | } 20 | self.balances[ctx.msg_sender()] -= amount; 21 | self.balances[receiver] += amount; 22 | ctx.emit(Transfer(from: ctx.msg_sender(), to: receiver, value: amount)); 23 | return true 24 | } 25 | 26 | pub fn getBalanceInEth(self, addr: address) -> u256 { 27 | return self.getBalance(addr) * 2; 28 | } 29 | 30 | pub fn getBalance(self, addr: address) -> u256 { 31 | return self.balances[addr]; 32 | } 33 | } -------------------------------------------------------------------------------- /actors/evm/tests/contracts/FilecoinFallback.hex: -------------------------------------------------------------------------------- 1 | 6080604052348015600e575f80fd5b506103c58061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063868e10c41461002d575b5f80fd5b61004760048036038101906100429190610245565b61005f565b60405161005693929190610353565b60405180910390f35b5f8060605f858590501415155f8767ffffffffffffffff1614151514610083575f80fd5b6104008767ffffffffffffffff16036100b2575f8060405180602001604052805f815250925092509250610195565b6104018767ffffffffffffffff1603610109575f60516040518060400160405280600681526020017f666f6f6261720000000000000000000000000000000000000000000000000000815250925092509250610195565b6104028767ffffffffffffffff160361013957602a5f60405180602001604052805f815250925092509250610195565b6104038767ffffffffffffffff160361019157602a60516040518060400160405280600681526020017f666f6f6261720000000000000000000000000000000000000000000000000000815250925092509250610195565b5f80fd5b9450945094915050565b5f80fd5b5f80fd5b5f67ffffffffffffffff82169050919050565b6101c3816101a7565b81146101cd575f80fd5b50565b5f813590506101de816101ba565b92915050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112610205576102046101e4565b5b8235905067ffffffffffffffff811115610222576102216101e8565b5b60208301915083600182028301111561023e5761023d6101ec565b5b9250929050565b5f805f806060858703121561025d5761025c61019f565b5b5f61026a878288016101d0565b945050602061027b878288016101d0565b935050604085013567ffffffffffffffff81111561029c5761029b6101a3565b5b6102a8878288016101f0565b925092505092959194509250565b5f63ffffffff82169050919050565b6102ce816102b6565b82525050565b6102dd816101a7565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f610325826102e3565b61032f81856102ed565b935061033f8185602086016102fd565b6103488161030b565b840191505092915050565b5f6060820190506103665f8301866102c5565b61037360208301856102d4565b8181036040830152610385818461031b565b905094935050505056fea264697066735822122029a1ff1d31ef76966f6c25bf2a1d3a4d4cd0809bc52b730c319e2d73ec84589c64736f6c634300081a0033 -------------------------------------------------------------------------------- /actors/evm/tests/contracts/FilecoinFallback.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 MIT 2 | pragma solidity >=0.4.25 <=0.8.26; 3 | 4 | contract FilecoinFallback { 5 | function handle_filecoin_method(uint64 method, uint64 codec, bytes calldata params) pure public returns (uint32, uint64, bytes memory) { 6 | require((codec == 0) == (params.length == 0)); 7 | if (method == 1024) { 8 | return ( 0, 0, bytes("") ); 9 | } else if (method == 1025) { 10 | return ( 0, 0x51, bytes("foobar") ); 11 | } else if (method == 1026) { 12 | return ( 42, 0, bytes("") ); 13 | } else if (method == 1027) { 14 | return ( 42, 0x51, bytes("foobar") ); 15 | } 16 | revert(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /actors/evm/tests/contracts/Lifecycle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 MIT 2 | pragma solidity >=0.8.26; 3 | 4 | contract Factory { 5 | function create(int32 value) public returns (address) { 6 | return address(new FactoryChild(value)); 7 | } 8 | 9 | function create2(bytes32 salt, int32 value) public returns (address) { 10 | return address(new FactoryChild{salt: salt}(value)); 11 | } 12 | } 13 | 14 | contract FactoryChild { 15 | int32 value; 16 | constructor(int32 arg) { 17 | if (arg < 0) { 18 | revert("create failed"); 19 | } 20 | value = arg; 21 | } 22 | function die() public { 23 | selfdestruct(payable(msg.sender)); 24 | } 25 | function dieRecursive() public { 26 | this.die(); 27 | value = 1234; 28 | } 29 | function get_value() public view returns (int32) { 30 | return value; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /actors/evm/tests/contracts/MCOPYTest.hex: -------------------------------------------------------------------------------- 1 | 6080604052348015600e575f80fd5b506103148061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063733580551461002d575b5f80fd5b61004760048036038101906100429190610217565b61005d565b60405161005491906102be565b60405180910390f35b60605f825167ffffffffffffffff81111561007b5761007a6100f3565b5b6040519080825280601f01601f1916602001820160405280156100ad5781602001600182028036833780820191505090505b509050825160208401602083018282825e50505080915050919050565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610129826100e3565b810181811067ffffffffffffffff82111715610148576101476100f3565b5b80604052505050565b5f61015a6100ca565b90506101668282610120565b919050565b5f67ffffffffffffffff821115610185576101846100f3565b5b61018e826100e3565b9050602081019050919050565b828183375f83830152505050565b5f6101bb6101b68461016b565b610151565b9050828152602081018484840111156101d7576101d66100df565b5b6101e284828561019b565b509392505050565b5f82601f8301126101fe576101fd6100db565b5b813561020e8482602086016101a9565b91505092915050565b5f6020828403121561022c5761022b6100d3565b5b5f82013567ffffffffffffffff811115610249576102486100d7565b5b610255848285016101ea565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6102908261025e565b61029a8185610268565b93506102aa818560208601610278565b6102b3816100e3565b840191505092915050565b5f6020820190508181035f8301526102d68184610286565b90509291505056fea2646970667358221220274eb01ab194472b72181214f64fcf3a1fa86680bc84eae6c8b993ede043339764736f6c634300081a0033 -------------------------------------------------------------------------------- /actors/evm/tests/contracts/MCOPYTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.26; 3 | 4 | contract MCOPYTest { 5 | function optimizedCopy(bytes memory data) public pure returns (bytes memory) { 6 | bytes memory result = new bytes(data.length); 7 | assembly { 8 | let length := mload(data) // Get the length of the input data 9 | let source := add(data, 0x20) // Point to the start of the data (skip the length) 10 | let destination := add(result, 0x20) // Point to the start of the result memory (skip the length) 11 | 12 | // Use MCOPY opcode directly for memory copying 13 | // destination: destination memory pointer 14 | // source: source memory pointer 15 | // length: number of bytes to copy 16 | mcopy(destination, source, length) 17 | } 18 | return result; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /actors/evm/tests/contracts/Recursive.hex: -------------------------------------------------------------------------------- 1 | 6080604052348015600e575f80fd5b506102918061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063e97dcb6214610038578063ea0f66b114610056575b5f80fd5b610040610074565b60405161004d91906101e9565b60405180910390f35b61005e610171565b60405161006b91906101e9565b60405180910390f35b5f805f9054906101000a900460ff1615610091576001905061016e565b60015f806101000a81548160ff0219169083151502179055505f3073ffffffffffffffffffffffffffffffffffffffff1663ea0f66b16040518163ffffffff1660e01b81526004016020604051808303815f875af11580156100f5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101199190610230565b90505f8163ffffffff1614610131578091505061016e565b5f8054906101000a900460ff1661014c57600491505061016e565b5f60019054906101000a900460ff1661016957600591505061016e565b5f9150505b90565b5f805f9054906101000a900460ff1661018d57600290506101c8565b5f60019054906101000a900460ff16156101aa57600390506101c8565b60015f60016101000a81548160ff0219169083151502179055505f90505b90565b5f63ffffffff82169050919050565b6101e3816101cb565b82525050565b5f6020820190506101fc5f8301846101da565b92915050565b5f80fd5b61020f816101cb565b8114610219575f80fd5b50565b5f8151905061022a81610206565b92915050565b5f6020828403121561024557610244610202565b5b5f6102528482850161021c565b9150509291505056fea26469706673582212201e223817e21f353ec490c8a8fc9a5f4b43f3c1ab1e5e4ea31b830dabb7035f6f64736f6c634300081a0033 -------------------------------------------------------------------------------- /actors/evm/tests/contracts/Recursive.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 MIT 2 | pragma solidity >=0.4.25 <=0.8.26; 3 | 4 | contract Recursive { 5 | bool a; 6 | bool b; 7 | 8 | function enter() public returns (uint32) { 9 | if (a) { 10 | return 1; 11 | } 12 | a = true; 13 | uint32 result = Recursive(address(this)).recurse(); 14 | if (result != 0) { 15 | return result; 16 | } 17 | 18 | if (!a) { 19 | return 4; 20 | } 21 | 22 | if (!b) { 23 | return 5; 24 | } 25 | return 0; 26 | } 27 | 28 | function recurse() public returns (uint32) { 29 | if (!a) { 30 | return 2; 31 | } 32 | if (b) { 33 | return 3; 34 | } 35 | b = true; 36 | return 0; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /actors/evm/tests/contracts/callvariants.eas: -------------------------------------------------------------------------------- 1 | # this is a multi-purpose contract for testing various scenarios of STATICCALL and DELEGATECALL 2 | 3 | # initialization: store the id address as a nonce at slot 0 4 | address 5 | push1 0x00 6 | sstore 7 | 8 | # contract code 9 | %push(body_end - body_begin) 10 | dup1 11 | %push(body_begin) 12 | push1 0x00 13 | codecopy 14 | push1 0x00 15 | return 16 | 17 | body_begin: 18 | %include("callvariants_body.eas") 19 | body_end: -------------------------------------------------------------------------------- /actors/evm/tests/contracts/callvariants.hex: -------------------------------------------------------------------------------- 1 | 306000556102408060106000396000f360003560e01c8060011460865780600214610208578060031460a65780600414610214578060051460c6578060061460ec578060071461010e578060081461013457806009146101565780600a146101965780600b146101bc5780600c146101565780600d146101e25780600e146101965780600f14610176578060101461023657600080fd5b60206000600260e01b600052600460006004355afa156102285760206000f35b60206000600460e01b600052600460006004355afa156102285760206000f35b60206000600660e01b600052602435600452602460006004355afa156102285760206000f35b60206000600260e01b6000526004600060006004355af1156102285760206000f35b60206000600860e01b600052602435600452602460006004355afa156102285760206000f35b60206000600460e01b6000526004600060006004355af1156102285760206000f35b60206000600260e01b600052600460006004355af4156102285760206000f35b60206000601060e01b600052600460006004355af4156102285760206000f35b60206000600460e01b600052600460006004355af4156102285760005460005260206000f35b60206000600c60e01b600052602435600452602460006004355afa156102285760206000f35b60206000600e60e01b600052602435600452602460006004355afa156102285760206000f35b60005460005260206000f35b63ffffff4260005560005460005260206000f35b63deadbeef6000526004601cfd5b3460005260206000f3 -------------------------------------------------------------------------------- /actors/evm/tests/contracts/output/FeSimplecoin/FeSimplecoin.bin: -------------------------------------------------------------------------------- 1 | 6103da803803906040518015610043575b828101604052393260005260006020526127106008600160fb1b03604060002060051c165561038e8061004c6000396000f35b50606061001056fe60003560e01c806390b98a11146100675780637bd703e8146100525763f8b2cb4f1461002757005b61003c61003736600319016102d7565b610282565b61004f61004761029a565b918252602090565b90f35b61003c61006236600319016102d7565b610230565b60431936016100ad575b6100896004358060a01c6100a0575b602435906100ba565b61004f61009461029a565b60ff9092168252602090565b6100a86102ac565b610080565b6100b56102ac565b610071565b6000929160ff816100d9336000526000602052604060002060ff191690565b8060051c549060f884199160031b1661010003011c1016806001146102275715610101575050565b6102089293508061018d6102039261014361012a336000526000602052604060002060ff191690565b8060051c549060f860ff199160031b1661010003011c90565b81811061021a575b03610164336000526000602052604060002060ff191690565b9060ff1960f88360031b16610100030191600019831b91829160051c931b169019825416179055565b6101ce816101ac61012a866000526000602052604060002060ff191690565b8119811161020d575b01610164856000526000602052604060002060ff191690565b6101d661032f565b9233849060409260018060601b0391828451169060601b17835260208301918251169060601b1790520152565b61034c565b600190565b610215610305565b6101b5565b610222610305565b61014b565b50600093505050565b610248906000526000602052604060002060ff191690565b8060051c549060f860ff199160031b1661010003011c806000190460021181151516610275575b60011b90565b61027d610305565b61026f565b61012a906000526000602052604060002060ff191690565b6040519081156102a657565b60609150565b5060246102b761029a565b80516001600160e01b0316632e36a70960e01b1781526101036004820152fd5b6020036102f8575b6004358060a01c6102ed5790565b6102f56102ac565b90565b6103006102ac565b6102df565b50602461031061029a565b80516001600160e01b0316634e487b7160e01b17815260116004820152fd5b604051908115610343575b60608201604052565b6060915061033a565b61035461029a565b604082015181527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60208084015160601c935160601c92a356 -------------------------------------------------------------------------------- /actors/evm/tests/contracts/output/FeSimplecoin/FeSimplecoin_abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "constructor", 4 | "name": "__init__", 5 | "inputs": [], 6 | "outputs": [], 7 | "stateMutability": "payable" 8 | }, 9 | { 10 | "type": "function", 11 | "name": "sendCoin", 12 | "inputs": [ 13 | { 14 | "name": "receiver", 15 | "type": "address" 16 | }, 17 | { 18 | "name": "amount", 19 | "type": "uint256" 20 | } 21 | ], 22 | "outputs": [ 23 | { 24 | "name": "", 25 | "type": "bool" 26 | } 27 | ], 28 | "stateMutability": "payable" 29 | }, 30 | { 31 | "type": "function", 32 | "name": "getBalanceInEth", 33 | "inputs": [ 34 | { 35 | "name": "addr", 36 | "type": "address" 37 | } 38 | ], 39 | "outputs": [ 40 | { 41 | "name": "", 42 | "type": "uint256" 43 | } 44 | ], 45 | "stateMutability": "view" 46 | }, 47 | { 48 | "type": "function", 49 | "name": "getBalance", 50 | "inputs": [ 51 | { 52 | "name": "addr", 53 | "type": "address" 54 | } 55 | ], 56 | "outputs": [ 57 | { 58 | "name": "", 59 | "type": "uint256" 60 | } 61 | ], 62 | "stateMutability": "view" 63 | }, 64 | { 65 | "type": "event", 66 | "name": "Transfer", 67 | "inputs": [ 68 | { 69 | "name": "from", 70 | "type": "address", 71 | "indexed": true 72 | }, 73 | { 74 | "name": "to", 75 | "type": "address", 76 | "indexed": true 77 | }, 78 | { 79 | "name": "value", 80 | "type": "uint256", 81 | "indexed": false 82 | } 83 | ], 84 | "anonymous": false 85 | }, 86 | { 87 | "type": "event", 88 | "name": "Context", 89 | "inputs": [], 90 | "anonymous": false 91 | } 92 | ] -------------------------------------------------------------------------------- /actors/evm/tests/contracts/recall_contract/README.md: -------------------------------------------------------------------------------- 1 | # Recall Contract 2 | 3 | This directory contains compiled copies of https://github.com/recallnet taken from mainnet contracts. 4 | 5 | - Proxy contract: 0xf0438cd20Fa4855997297A9C1299469CA10b58bf 6 | - Implementation contract: 0x1835374384AA51B169c0705DA26A84bB760F2B37 7 | 8 | We're using these to reproduce https://github.com/recallnet/contracts/issues/98 9 | 10 | These contracts are copyright 2025 the Recall Contributors, available under either the MIT or the Apache-2.0 license. 11 | -------------------------------------------------------------------------------- /actors/evm/tests/contracts/recall_contract/proxy.hex: -------------------------------------------------------------------------------- 1 | 60806040526102a88038038061001481610168565b92833981016040828203126101645781516001600160a01b03811692909190838303610164576020810151906001600160401b03821161016457019281601f8501121561016457835161006e610069826101a1565b610168565b9481865260208601936020838301011161016457815f926020809301865e86010152823b15610152577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a282511561013a575f8091610122945190845af43d15610132573d91610113610069846101a1565b9283523d5f602085013e6101bc565b505b604051608d908161021b8239f35b6060916101bc565b50505034156101245763b398979f60e01b5f5260045ffd5b634c9c8ce360e01b5f5260045260245ffd5b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761018d57604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161018d57601f01601f191660200190565b906101e057508051156101d157805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610211575b6101f1575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156101e956fe60806040525f8073ffffffffffffffffffffffffffffffffffffffff7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5416368280378136915af43d5f803e156053573d5ff35b3d5ffdfea2646970667358221220d84369ae6f98a27679b5d10b53558f46164239ede3a4126e04298270c4193fd364736f6c634300081a00330000000000000000000000001835374384aa51b169c0705da26a84bb760f2b3700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000044be13f47c000000000000000000000000b5fb4be02232b1bba4dc8f81dc24c26980de9e3c341bb76302c76fb57d6fe6c003c4fc68e56cbe5c5a4c04bedf1522a15c7e41a000000000000000000000000000000000000000000000000000000000 -------------------------------------------------------------------------------- /actors/evm/tests/contracts/selfdestruct.hex: -------------------------------------------------------------------------------- 1 | 6080604052348015600e575f80fd5b5060ee8061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106030575f3560e01c806335f46994146034578063901717d114603c575b5f80fd5b603a6056565b005b60426083565b604051604d919060a1565b60405180910390f35b73ff000000000000000000000000000000000003e973ffffffffffffffffffffffffffffffffffffffff16ff5b5f6001905090565b5f819050919050565b609b81608b565b82525050565b5f60208201905060b25f8301846094565b9291505056fea2646970667358221220e1c5c6f37e4c59a2d0f6c1a0761371f5d2c4b72f34400729206a3b385258805864736f6c634300081a0033 -------------------------------------------------------------------------------- /actors/evm/tests/contracts/selfdestruct.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract Selfdestruct { 5 | function die() public { 6 | selfdestruct( 7 | payable(address(0xFF000000000000000000000000000000000003E9)) 8 | ); 9 | } 10 | function one() pure public returns (uint256){ 11 | return 0x1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /actors/evm/tests/contracts/simplecoin.hex: -------------------------------------------------------------------------------- 1 | 6080604052348015600e575f80fd5b506127105f803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055506104f58061005f5f395ff3fe608060405234801561000f575f80fd5b506004361061003f575f3560e01c80637bd703e81461004357806390b98a1114610073578063f8b2cb4f146100a3575b5f80fd5b61005d600480360381019061005891906102f4565b6100d3565b60405161006a9190610337565b60405180910390f35b61008d6004803603810190610088919061037a565b6100f0565b60405161009a91906103d2565b60405180910390f35b6100bd60048036038101906100b891906102f4565b610251565b6040516100ca9190610337565b60405180910390f35b5f60026100df83610251565b6100e99190610418565b9050919050565b5f815f803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054101561013d575f905061024b565b815f803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546101889190610459565b92505081905550815f808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546101da919061048c565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161023e9190610337565b60405180910390a3600190505b92915050565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6102c38261029a565b9050919050565b6102d3816102b9565b81146102dd575f80fd5b50565b5f813590506102ee816102ca565b92915050565b5f6020828403121561030957610308610296565b5b5f610316848285016102e0565b91505092915050565b5f819050919050565b6103318161031f565b82525050565b5f60208201905061034a5f830184610328565b92915050565b6103598161031f565b8114610363575f80fd5b50565b5f8135905061037481610350565b92915050565b5f80604083850312156103905761038f610296565b5b5f61039d858286016102e0565b92505060206103ae85828601610366565b9150509250929050565b5f8115159050919050565b6103cc816103b8565b82525050565b5f6020820190506103e55f8301846103c3565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6104228261031f565b915061042d8361031f565b925082820261043b8161031f565b91508282048414831517610452576104516103eb565b5b5092915050565b5f6104638261031f565b915061046e8361031f565b9250828203905081811115610486576104856103eb565b5b92915050565b5f6104968261031f565b91506104a18361031f565b92508282019050808211156104b9576104b86103eb565b5b9291505056fea26469706673582212202d53e37145a27f2e3f473ea0fb7312d939f30efbca84d1c39140b2179359b1df64736f6c634300081a0033 -------------------------------------------------------------------------------- /actors/evm/tests/contracts/simplecoin.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.2; 3 | 4 | contract SimpleCoin { 5 | mapping(address => uint256) balances; 6 | 7 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 8 | 9 | constructor() { 10 | balances[tx.origin] = 10000; 11 | } 12 | 13 | function sendCoin(address receiver, uint256 amount) 14 | public 15 | returns (bool sufficient) 16 | { 17 | if (balances[msg.sender] < amount) return false; 18 | balances[msg.sender] -= amount; 19 | balances[receiver] += amount; 20 | emit Transfer(msg.sender, receiver, amount); 21 | return true; 22 | } 23 | 24 | function getBalanceInEth(address addr) public view returns (uint256) { 25 | return getBalance(addr) * 2; 26 | } 27 | 28 | function getBalance(address addr) public view returns (uint256) { 29 | return balances[addr]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /actors/evm/tests/revert.rs: -------------------------------------------------------------------------------- 1 | use fil_actor_evm as evm; 2 | use fvm_ipld_encoding::{BytesSer, RawBytes}; 3 | 4 | mod asm; 5 | mod util; 6 | 7 | #[test] 8 | fn test_revert() { 9 | let contract = asm::new_contract( 10 | "naked-revert", 11 | "", 12 | r#" 13 | %push(0xdeadbeef) 14 | push1 0x00 15 | mstore 16 | push1 0x04 17 | push1 0x1c # skip top 28 bytes 18 | revert 19 | "#, 20 | ) 21 | .unwrap(); 22 | 23 | let rt = util::construct_and_verify(contract); 24 | rt.expect_validate_caller_any(); 25 | 26 | let result = rt.call::(evm::Method::InvokeContract as u64, None); 27 | assert!(result.is_err()); 28 | let mut e = result.unwrap_err(); 29 | assert_eq!(e.exit_code(), evm::EVM_CONTRACT_REVERTED); 30 | assert_eq!( 31 | e.take_data().unwrap().data, 32 | RawBytes::serialize(BytesSer(&[0xde, 0xad, 0xbe, 0xef])).unwrap().bytes() 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /actors/init/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_init" 3 | description = "Builtin init actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true } 18 | frc42_dispatch = { workspace = true } 19 | fvm_shared = { workspace = true } 20 | fvm_ipld_hamt = { workspace = true } 21 | serde = { workspace = true } 22 | num-traits = { workspace = true } 23 | num-derive = { workspace = true } 24 | cid = { workspace = true } 25 | anyhow = { workspace = true } 26 | log = { workspace = true } 27 | fvm_ipld_blockstore = { workspace = true } 28 | fvm_ipld_encoding = { workspace = true } 29 | 30 | [dev-dependencies] 31 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 32 | 33 | [features] 34 | fil-actor = ["fil_actors_runtime/fil-actor"] 35 | -------------------------------------------------------------------------------- /actors/init/src/types.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use cid::Cid; 5 | use fvm_ipld_encoding::RawBytes; 6 | use fvm_ipld_encoding::tuple::*; 7 | use fvm_shared::address::Address; 8 | 9 | /// Init actor Constructor parameters 10 | #[derive(Serialize_tuple, Deserialize_tuple)] 11 | pub struct ConstructorParams { 12 | pub network_name: String, 13 | } 14 | 15 | /// Init actor Exec Params 16 | #[derive(Serialize_tuple, Deserialize_tuple)] 17 | pub struct ExecParams { 18 | pub code_cid: Cid, 19 | pub constructor_params: RawBytes, 20 | } 21 | 22 | /// Init actor Exec Return value 23 | #[derive(Debug, Serialize_tuple, Deserialize_tuple)] 24 | pub struct ExecReturn { 25 | /// ID based address for created actor 26 | pub id_address: Address, 27 | /// Reorg safe address for actor 28 | pub robust_address: Address, 29 | } 30 | 31 | /// Init actor Exec4 Params 32 | #[derive(Serialize_tuple, Deserialize_tuple)] 33 | pub struct Exec4Params { 34 | pub code_cid: Cid, 35 | pub constructor_params: RawBytes, 36 | pub subaddress: RawBytes, 37 | } 38 | 39 | /// Init actor Exec4 Return value 40 | pub type Exec4Return = ExecReturn; 41 | -------------------------------------------------------------------------------- /actors/market/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_market" 3 | description = "Builtin market actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true} 18 | 19 | anyhow = { workspace = true } 20 | cid = { workspace = true } 21 | frc42_dispatch = { workspace = true } 22 | frc46_token = { workspace = true } 23 | fvm_ipld_bitfield = { workspace = true } 24 | fvm_ipld_blockstore = { workspace = true } 25 | fvm_ipld_encoding = { workspace = true } 26 | fvm_ipld_hamt = { workspace = true } 27 | fvm_shared = { workspace = true } 28 | integer-encoding = { workspace = true } 29 | ipld-core = { workspace = true } 30 | log = { workspace = true } 31 | num-derive = { workspace = true } 32 | num-traits = { workspace = true } 33 | serde = { workspace = true } 34 | lazy_static = { workspace = true } 35 | multihash-codetable = { workspace = true } 36 | 37 | [dev-dependencies] 38 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 39 | fil_actor_power = { workspace = true } 40 | fil_actor_reward = { workspace = true } 41 | fil_actor_verifreg = { workspace = true } 42 | fvm_ipld_amt = { workspace = true } 43 | regex = { workspace = true } 44 | itertools = { workspace = true } 45 | 46 | [features] 47 | fil-actor = ["fil_actors_runtime/fil-actor"] 48 | -------------------------------------------------------------------------------- /actors/market/src/emit.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_runtime::runtime::Runtime; 2 | use fil_actors_runtime::{ActorError, EventBuilder}; 3 | use fvm_shared::ActorID; 4 | use fvm_shared::deal::DealID; 5 | 6 | /// Indicates a deal has been published. 7 | pub fn deal_published( 8 | rt: &impl Runtime, 9 | client: ActorID, 10 | provider: ActorID, 11 | deal_id: DealID, 12 | ) -> Result<(), ActorError> { 13 | rt.emit_event( 14 | &EventBuilder::new() 15 | .typ("deal-published") 16 | .with_parties(deal_id, client, provider) 17 | .build()?, 18 | ) 19 | } 20 | 21 | /// Indicates a deal has been activated. 22 | pub fn deal_activated( 23 | rt: &impl Runtime, 24 | deal_id: DealID, 25 | client: ActorID, 26 | provider: ActorID, 27 | ) -> Result<(), ActorError> { 28 | rt.emit_event( 29 | &EventBuilder::new() 30 | .typ("deal-activated") 31 | .with_parties(deal_id, client, provider) 32 | .build()?, 33 | ) 34 | } 35 | 36 | /// Indicates a deal has been terminated. 37 | pub fn deal_terminated( 38 | rt: &impl Runtime, 39 | deal_id: DealID, 40 | client: ActorID, 41 | provider: ActorID, 42 | ) -> Result<(), ActorError> { 43 | rt.emit_event( 44 | &EventBuilder::new() 45 | .typ("deal-terminated") 46 | .with_parties(deal_id, client, provider) 47 | .build()?, 48 | ) 49 | } 50 | 51 | /// Indicates a deal has been completed successfully. 52 | pub fn deal_completed( 53 | rt: &impl Runtime, 54 | deal_id: DealID, 55 | client: ActorID, 56 | provider: ActorID, 57 | ) -> Result<(), ActorError> { 58 | rt.emit_event( 59 | &EventBuilder::new() 60 | .typ("deal-completed") 61 | .with_parties(deal_id, client, provider) 62 | .build()?, 63 | ) 64 | } 65 | 66 | trait WithParties { 67 | fn with_parties(self, id: DealID, client: ActorID, provider: ActorID) -> EventBuilder; 68 | } 69 | 70 | impl WithParties for EventBuilder { 71 | fn with_parties(self, id: DealID, client: ActorID, provider: ActorID) -> EventBuilder { 72 | self.field_indexed("id", &id) 73 | .field_indexed("client", &client) 74 | .field_indexed("provider", &provider) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /actors/miner/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_miner" 3 | description = "Builtin miner actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | bitflags = { workspace = true } 18 | fil_actors_runtime = { workspace = true } 19 | frc42_dispatch = { workspace = true } 20 | fvm_shared = { workspace = true } 21 | fvm_ipld_bitfield = { workspace = true } 22 | fvm_ipld_amt = { workspace = true } 23 | fvm_ipld_hamt = { workspace = true } 24 | fvm_ipld_blockstore = { workspace = true } 25 | fvm_ipld_encoding = { workspace = true } 26 | serde = { workspace = true } 27 | cid = { workspace = true } 28 | anyhow = { workspace = true } 29 | multihash = { workspace = true } 30 | num-traits = { workspace = true } 31 | num-derive = { workspace = true } 32 | lazy_static = { workspace = true } 33 | log = { workspace = true } 34 | byteorder = { workspace = true } 35 | itertools = { workspace = true } 36 | multihash-codetable = { workspace = true } 37 | 38 | [dev-dependencies] 39 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 40 | fil_actor_account = { workspace = true } 41 | fil_actor_reward = { workspace = true } 42 | fil_actor_power = { workspace = true } 43 | fil_actor_market = { workspace = true } 44 | rand = { workspace = true } 45 | test-case = { workspace = true } 46 | hex-literal = { workspace = true } 47 | multihash-derive = { workspace = true } 48 | 49 | [features] 50 | fil-actor = ["fil_actors_runtime/fil-actor"] 51 | -------------------------------------------------------------------------------- /actors/miner/src/beneficiary.rs: -------------------------------------------------------------------------------- 1 | use fvm_ipld_encoding::tuple::*; 2 | use fvm_shared::address::Address; 3 | 4 | use fvm_shared::clock::ChainEpoch; 5 | use fvm_shared::econ::TokenAmount; 6 | use num_traits::Zero; 7 | use std::ops::Sub; 8 | 9 | #[derive(Debug, PartialEq, Eq, Clone, Serialize_tuple, Deserialize_tuple)] 10 | pub struct BeneficiaryTerm { 11 | /// The total amount the current beneficiary can withdraw. Monotonic, but reset when beneficiary changes. 12 | pub quota: TokenAmount, 13 | /// The amount of quota the current beneficiary has already withdrawn 14 | pub used_quota: TokenAmount, 15 | /// The epoch at which the beneficiary's rights expire and revert to the owner 16 | pub expiration: ChainEpoch, 17 | } 18 | 19 | impl Default for BeneficiaryTerm { 20 | fn default() -> BeneficiaryTerm { 21 | BeneficiaryTerm { 22 | quota: TokenAmount::zero(), 23 | expiration: 0, 24 | used_quota: TokenAmount::zero(), 25 | } 26 | } 27 | } 28 | 29 | impl BeneficiaryTerm { 30 | pub fn new( 31 | quota: TokenAmount, 32 | used_quota: TokenAmount, 33 | expiration: ChainEpoch, 34 | ) -> BeneficiaryTerm { 35 | BeneficiaryTerm { quota, expiration, used_quota } 36 | } 37 | 38 | /// Get the amount that the beneficiary has not yet withdrawn 39 | /// return 0 when expired 40 | /// return 0 when the usedQuota >= Quota for safe 41 | /// otherwise Return quota-used_quota 42 | pub fn available(&self, cur: ChainEpoch) -> TokenAmount { 43 | if self.expiration > cur { 44 | (&self.quota).sub(&self.used_quota).max(TokenAmount::zero()) 45 | } else { 46 | TokenAmount::zero() 47 | } 48 | } 49 | } 50 | 51 | #[derive(Debug, Clone, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)] 52 | pub struct PendingBeneficiaryChange { 53 | pub new_beneficiary: Address, 54 | pub new_quota: TokenAmount, 55 | pub new_expiration: ChainEpoch, 56 | pub approved_by_beneficiary: bool, 57 | pub approved_by_nominee: bool, 58 | } 59 | 60 | impl PendingBeneficiaryChange { 61 | pub fn new( 62 | new_beneficiary: Address, 63 | new_quota: TokenAmount, 64 | new_expiration: ChainEpoch, 65 | ) -> Self { 66 | PendingBeneficiaryChange { 67 | new_beneficiary, 68 | new_quota, 69 | new_expiration, 70 | approved_by_beneficiary: false, 71 | approved_by_nominee: false, 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /actors/miner/src/emit.rs: -------------------------------------------------------------------------------- 1 | use cid::Cid; 2 | use fil_actors_runtime::runtime::Runtime; 3 | use fil_actors_runtime::{ActorError, EventBuilder}; 4 | use fvm_shared::sector::SectorNumber; 5 | 6 | /// Indicates a sector has been pre-committed. 7 | pub fn sector_precommitted(rt: &impl Runtime, sector: SectorNumber) -> Result<(), ActorError> { 8 | rt.emit_event( 9 | &EventBuilder::new().typ("sector-precommitted").field_indexed("sector", §or).build()?, 10 | ) 11 | } 12 | 13 | /// Indicates a sector has been activated. 14 | pub fn sector_activated( 15 | rt: &impl Runtime, 16 | sector: SectorNumber, 17 | unsealed_cid: Option, 18 | pieces: &[(Cid, u64)], 19 | ) -> Result<(), ActorError> { 20 | rt.emit_event( 21 | &EventBuilder::new() 22 | .typ("sector-activated") 23 | .with_sector_info(sector, unsealed_cid, pieces) 24 | .build()?, 25 | ) 26 | } 27 | 28 | /// Indicates a sector has been updated. 29 | pub fn sector_updated( 30 | rt: &impl Runtime, 31 | sector: SectorNumber, 32 | unsealed_cid: Option, 33 | pieces: &[(Cid, u64)], 34 | ) -> Result<(), ActorError> { 35 | rt.emit_event( 36 | &EventBuilder::new() 37 | .typ("sector-updated") 38 | .with_sector_info(sector, unsealed_cid, pieces) 39 | .build()?, 40 | ) 41 | } 42 | 43 | /// Indicates a sector has been terminated. 44 | pub fn sector_terminated(rt: &impl Runtime, sector: SectorNumber) -> Result<(), ActorError> { 45 | rt.emit_event( 46 | &EventBuilder::new().typ("sector-terminated").field_indexed("sector", §or).build()?, 47 | ) 48 | } 49 | 50 | trait WithSectorInfo { 51 | fn with_sector_info( 52 | self, 53 | sector: SectorNumber, 54 | unsealed_cid: Option, 55 | pieces: &[(Cid, u64)], 56 | ) -> EventBuilder; 57 | } 58 | 59 | impl WithSectorInfo for EventBuilder { 60 | fn with_sector_info( 61 | self, 62 | sector: SectorNumber, 63 | unsealed_cid: Option, 64 | pieces: &[(Cid, u64)], 65 | ) -> EventBuilder { 66 | let mut event = 67 | self.field_indexed("sector", §or).field_indexed("unsealed-cid", &unsealed_cid); 68 | 69 | for piece in pieces { 70 | event = event.field_indexed("piece-cid", &piece.0).field("piece-size", &piece.1); 71 | } 72 | event 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /actors/miner/src/expiration_queue/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use crate::NO_QUANTIZATION; 5 | 6 | use super::*; 7 | use fil_actors_runtime::DealWeight; 8 | use fvm_shared::sector::StoragePower; 9 | 10 | #[test] 11 | fn test_expirations() { 12 | let quant = QuantSpec { unit: 10, offset: 3 }; 13 | let sectors = [ 14 | test_sector(7, 1, 0, 0, 0), 15 | test_sector(8, 2, 0, 0, 0), 16 | test_sector(14, 3, 0, 0, 0), 17 | test_sector(13, 4, 0, 0, 0), 18 | ]; 19 | let result = group_new_sectors_by_declared_expiration(SectorSize::_2KiB, §ors, quant); 20 | let expected = [ 21 | SectorEpochSet { 22 | epoch: 13, 23 | sectors: vec![1, 2, 4], 24 | power: PowerPair { 25 | raw: StoragePower::from(2048 * 3), 26 | qa: StoragePower::from(2048 * 3), 27 | }, 28 | pledge: Zero::zero(), 29 | daily_fee: Zero::zero(), 30 | }, 31 | SectorEpochSet { 32 | epoch: 23, 33 | sectors: vec![3], 34 | power: PowerPair { raw: StoragePower::from(2048), qa: StoragePower::from(2048) }, 35 | pledge: Zero::zero(), 36 | daily_fee: Zero::zero(), 37 | }, 38 | ]; 39 | assert_eq!(expected.len(), result.len()); 40 | for (i, ex) in expected.iter().enumerate() { 41 | assert_sector_set(ex, &result[i]); 42 | } 43 | } 44 | 45 | #[test] 46 | fn test_expirations_empty() { 47 | let sectors = Vec::new(); 48 | let result = 49 | group_new_sectors_by_declared_expiration(SectorSize::_2KiB, sectors, NO_QUANTIZATION); 50 | assert!(result.is_empty()); 51 | } 52 | 53 | fn assert_sector_set(expected: &SectorEpochSet, actual: &SectorEpochSet) { 54 | assert_eq!(expected.epoch, actual.epoch); 55 | assert_eq!(expected.sectors, actual.sectors); 56 | assert_eq!(expected.power, actual.power); 57 | assert_eq!(expected.pledge, actual.pledge); 58 | } 59 | 60 | fn test_sector( 61 | expiration: ChainEpoch, 62 | sector_number: SectorNumber, 63 | deal_weight: u64, 64 | verified_deal_weight: u64, 65 | initial_pledge: u64, 66 | ) -> SectorOnChainInfo { 67 | SectorOnChainInfo { 68 | expiration, 69 | sector_number, 70 | deal_weight: DealWeight::from(deal_weight), 71 | verified_deal_weight: DealWeight::from(verified_deal_weight), 72 | initial_pledge: TokenAmount::from_atto(initial_pledge), 73 | ..Default::default() 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /actors/miner/src/quantize.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2023 Protocol Labs 2 | // Copyright 2019-2022 ChainSafe Systems 3 | // SPDX-License-Identifier: Apache-2.0, MIT 4 | 5 | use fvm_shared::clock::ChainEpoch; 6 | 7 | /// Constant defining the [QuantSpec] which performs no quantization. 8 | pub const NO_QUANTIZATION: QuantSpec = QuantSpec { unit: 1, offset: 0 }; 9 | 10 | /// A spec for epoch quantization. 11 | #[derive(Copy, Clone)] 12 | pub struct QuantSpec { 13 | /// The unit of quantization 14 | pub unit: ChainEpoch, 15 | /// The offset from zero from which to base the modulus 16 | pub offset: ChainEpoch, 17 | } 18 | 19 | impl QuantSpec { 20 | /// Rounds `epoch` to the nearest exact multiple of the quantization unit offset by 21 | /// `offset % unit`, rounding up. 22 | /// 23 | /// This function is equivalent to `unit * ceil(epoch - (offset % unit) / unit) + (offsetSeed % unit)` 24 | /// with the variables/operations over real numbers instead of ints. 25 | /// 26 | /// Precondition: `unit >= 0` 27 | pub fn quantize_up(&self, epoch: ChainEpoch) -> ChainEpoch { 28 | let offset = self.offset % self.unit; 29 | 30 | let remainder = (epoch - offset) % self.unit; 31 | let quotient = (epoch - offset) / self.unit; 32 | 33 | // Don't round if epoch falls on a quantization epoch 34 | if remainder == 0 35 | // Negative truncating division rounds up 36 | || epoch - offset < 0 37 | { 38 | self.unit * quotient + offset 39 | } else { 40 | self.unit * (quotient + 1) + offset 41 | } 42 | } 43 | 44 | pub fn quantize_down(&self, epoch: ChainEpoch) -> ChainEpoch { 45 | let next = self.quantize_up(epoch); 46 | // QuantizeDown == QuantizeUp iff epoch is a fixed point of QuantizeUp 47 | if epoch == next { next } else { next - self.unit } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /actors/miner/src/termination.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use std::collections::BTreeMap; 5 | use std::ops::AddAssign; 6 | 7 | use fvm_ipld_bitfield::BitField; 8 | use fvm_shared::clock::ChainEpoch; 9 | 10 | #[derive(Default)] 11 | pub struct TerminationResult { 12 | /// Sectors maps epochs at which sectors expired, to bitfields of sector numbers. 13 | pub sectors: BTreeMap, 14 | pub partitions_processed: u64, 15 | pub sectors_processed: u64, 16 | } 17 | 18 | impl AddAssign for TerminationResult { 19 | #[allow(clippy::suspicious_op_assign_impl)] 20 | fn add_assign(&mut self, rhs: Self) { 21 | self.partitions_processed += rhs.partitions_processed; 22 | self.sectors_processed += rhs.sectors_processed; 23 | 24 | for (epoch, new_sectors) in rhs.sectors { 25 | self.sectors 26 | .entry(epoch) 27 | .and_modify(|sectors| *sectors |= &new_sectors) 28 | .or_insert(new_sectors); 29 | } 30 | } 31 | } 32 | 33 | impl TerminationResult { 34 | pub fn new() -> Self { 35 | Default::default() 36 | } 37 | 38 | /// Returns true if we're below the partition/sector limit. Returns false if 39 | /// we're at (or above) the limit. 40 | pub fn below_limit(&self, partition_limit: u64, sector_limit: u64) -> bool { 41 | self.partitions_processed < partition_limit && self.sectors_processed < sector_limit 42 | } 43 | 44 | pub fn is_empty(&self) -> bool { 45 | self.sectors_processed == 0 46 | } 47 | 48 | pub fn iter(&self) -> impl Iterator { 49 | // The btreemap is already sorted. 50 | self.sectors.iter().map(|(&epoch, bf)| (epoch, bf)) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /actors/miner/tests/change_peer_id_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actor_miner::{Actor, ChangePeerIDParams, GetPeerIDReturn, Method}; 2 | use fil_actors_runtime::test_utils::{ 3 | EVM_ACTOR_CODE_ID, MockRuntime, expect_abort_contains_message, 4 | }; 5 | use fvm_ipld_encoding::ipld_block::IpldBlock; 6 | use fvm_shared::error::ExitCode; 7 | 8 | mod util; 9 | 10 | use util::*; 11 | 12 | fn setup() -> (ActorHarness, MockRuntime) { 13 | let period_offset = 100; 14 | let precommit_epoch = 1; 15 | 16 | let h = ActorHarness::new(period_offset); 17 | let rt = h.new_runtime(); 18 | h.construct_and_verify(&rt); 19 | rt.balance.replace(BIG_BALANCE.clone()); 20 | rt.set_epoch(precommit_epoch); 21 | 22 | (h, rt) 23 | } 24 | 25 | #[test] 26 | fn successfully_change_peer_id() { 27 | let (h, rt) = setup(); 28 | let new_pid = b"cthulhu".to_vec(); 29 | h.change_peer_id(&rt, new_pid); 30 | 31 | h.check_state(&rt); 32 | } 33 | 34 | #[test] 35 | fn change_peer_id_restricted_correctly() { 36 | let (h, rt) = setup(); 37 | 38 | let new_id = b"cthulhu".to_vec(); 39 | 40 | let params = IpldBlock::serialize_cbor(&ChangePeerIDParams { new_id: new_id.clone() }).unwrap(); 41 | 42 | rt.set_caller(*EVM_ACTOR_CODE_ID, h.worker); 43 | 44 | // fail to call the unexported setter 45 | 46 | expect_abort_contains_message( 47 | ExitCode::USR_FORBIDDEN, 48 | "must be built-in", 49 | rt.call::(Method::ChangePeerID as u64, params.clone()), 50 | ); 51 | 52 | // call the exported setter 53 | 54 | rt.expect_validate_caller_addr(h.caller_addrs()); 55 | 56 | rt.call::(Method::ChangePeerIDExported as u64, params).unwrap(); 57 | 58 | // call the exported getter 59 | 60 | rt.expect_validate_caller_any(); 61 | let ret: GetPeerIDReturn = rt 62 | .call::(Method::GetPeerIDExported as u64, None) 63 | .unwrap() 64 | .unwrap() 65 | .deserialize() 66 | .unwrap(); 67 | rt.verify(); 68 | 69 | assert_eq!(new_id, ret.peer_id); 70 | 71 | h.check_state(&rt); 72 | } 73 | -------------------------------------------------------------------------------- /actors/miner/tests/check_sector_proven_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_runtime::test_utils::{MockRuntime, expect_abort}; 2 | use fvm_shared::error::ExitCode; 3 | 4 | mod util; 5 | use util::*; 6 | 7 | fn setup() -> (ActorHarness, MockRuntime) { 8 | let period_offset = 100; 9 | 10 | let h = ActorHarness::new(period_offset); 11 | let rt = h.new_runtime(); 12 | h.construct_and_verify(&rt); 13 | rt.balance.replace(BIG_BALANCE.clone()); 14 | 15 | (h, rt) 16 | } 17 | 18 | #[test] 19 | fn successfully_check_sector_is_proven() { 20 | let (mut h, rt) = setup(); 21 | 22 | let sectors = 23 | h.commit_and_prove_sectors(&rt, 1, DEFAULT_SECTOR_EXPIRATION, vec![vec![10]], true); 24 | h.check_sector_proven(&rt, sectors[0].sector_number).unwrap(); 25 | 26 | h.check_state(&rt); 27 | } 28 | 29 | #[test] 30 | fn fails_if_sector_is_not_found() { 31 | let (h, rt) = setup(); 32 | 33 | let result = h.check_sector_proven(&rt, 1); 34 | expect_abort(ExitCode::USR_NOT_FOUND, result); 35 | 36 | h.check_state(&rt); 37 | } 38 | -------------------------------------------------------------------------------- /actors/miner/tests/confirm_update_worker_key_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actor_miner::State; 2 | use fil_actors_runtime::{ 3 | runtime::{Runtime, RuntimePolicy}, 4 | test_utils::MockRuntime, 5 | }; 6 | use fvm_shared::address::Address; 7 | 8 | mod util; 9 | use util::*; 10 | 11 | const NEW_WORKER: Address = Address::new_id(999); 12 | 13 | fn setup() -> (ActorHarness, MockRuntime) { 14 | let period_offset = 100; 15 | let current_epoch = 5; 16 | 17 | let h = ActorHarness::new(period_offset); 18 | let rt = h.new_runtime(); 19 | h.construct_and_verify(&rt); 20 | rt.balance.replace(BIG_BALANCE.clone()); 21 | rt.set_epoch(current_epoch); 22 | 23 | (h, rt) 24 | } 25 | 26 | #[test] 27 | fn successfully_changes_the_worker_address() { 28 | let (h, rt) = setup(); 29 | 30 | let effective_epoch = *rt.epoch.borrow() + rt.policy().worker_key_change_delay; 31 | h.change_worker_address(&rt, NEW_WORKER, h.control_addrs.clone()).unwrap(); 32 | 33 | // confirm at effective epoch 34 | rt.set_epoch(effective_epoch); 35 | h.confirm_change_worker_address(&rt).unwrap(); 36 | 37 | let state: State = rt.get_state(); 38 | let info = state.get_info(rt.store()).unwrap(); 39 | 40 | assert_eq!(info.worker, NEW_WORKER); 41 | assert!(info.pending_worker_key.is_none()); 42 | 43 | h.check_state(&rt); 44 | } 45 | 46 | #[test] 47 | fn does_nothing_before_the_effective_date() { 48 | let (h, rt) = setup(); 49 | 50 | let effective_epoch = *rt.epoch.borrow() + rt.policy().worker_key_change_delay; 51 | h.change_worker_address(&rt, NEW_WORKER, h.control_addrs.clone()).unwrap(); 52 | 53 | // confirm right before the effective epoch 54 | rt.set_epoch(effective_epoch - 1); 55 | h.confirm_change_worker_address(&rt).unwrap(); 56 | 57 | let state: State = rt.get_state(); 58 | let info = state.get_info(rt.store()).unwrap(); 59 | 60 | assert_eq!(info.worker, h.worker); 61 | 62 | let pending_worker_key = info.pending_worker_key.unwrap(); 63 | assert_eq!(pending_worker_key.new_worker, NEW_WORKER); 64 | assert_eq!(pending_worker_key.effective_at, effective_epoch); 65 | 66 | h.check_state(&rt); 67 | } 68 | 69 | #[test] 70 | fn does_nothing_when_no_update_is_set() { 71 | let (h, rt) = setup(); 72 | 73 | h.confirm_change_worker_address(&rt).unwrap(); 74 | 75 | let state: State = rt.get_state(); 76 | let info = state.get_info(rt.store()).unwrap(); 77 | 78 | assert_eq!(info.worker, h.worker); 79 | assert!(info.pending_worker_key.is_none()); 80 | 81 | h.check_state(&rt); 82 | } 83 | -------------------------------------------------------------------------------- /actors/miner/tests/declare_faults.rs: -------------------------------------------------------------------------------- 1 | use fil_actor_miner::daily_fee_for_sectors; 2 | use fil_actor_miner::pledge_penalty_for_continued_fault; 3 | use fil_actor_miner::power_for_sectors; 4 | 5 | use fvm_shared::clock::ChainEpoch; 6 | use fvm_shared::econ::TokenAmount; 7 | 8 | use num_traits::Zero; 9 | 10 | mod util; 11 | use crate::util::*; 12 | 13 | // an expriration ~10 days greater than effective min expiration taking into account 30 days max 14 | // between pre and prove commit 15 | const DEFAULT_SECTOR_EXPIRATION: ChainEpoch = 220; 16 | 17 | const PERIOD_OFFSET: ChainEpoch = 100; 18 | 19 | #[test] 20 | fn declare_fault_pays_fee_at_window_post() { 21 | let big_rewards = TokenAmount::from_whole(1000); 22 | 23 | // Get sector into proving state 24 | let mut h = ActorHarness::new(PERIOD_OFFSET); 25 | let rt = h.new_runtime(); 26 | rt.set_balance(BIG_BALANCE.clone()); 27 | h.construct_and_verify(&rt); 28 | let all_sectors = 29 | h.commit_and_prove_sectors(&rt, 1, DEFAULT_SECTOR_EXPIRATION as u64, vec![], true); 30 | let pwr = power_for_sectors(h.sector_size, &all_sectors); 31 | 32 | // add lots of funds so penalties come from vesting funds 33 | h.apply_rewards(&rt, big_rewards, TokenAmount::zero()); 34 | 35 | // find deadline for sector 36 | let st = h.get_state(&rt); 37 | let (dl_idx, _) = st.find_sector(&rt.store, all_sectors[0].sector_number).unwrap(); 38 | 39 | // advance to first proving period and submit so we'll have time to declare the fault next cycle 40 | h.advance_and_submit_posts(&rt, &all_sectors); 41 | 42 | // Declare the sector as faulted 43 | h.declare_faults(&rt, &all_sectors); 44 | 45 | // faults are recorded in state 46 | let dl = h.get_deadline(&rt, dl_idx); 47 | assert_eq!(pwr, dl.faulty_power); 48 | 49 | // Skip to end of proving period. 50 | let mut dl_info = h.deadline(&rt); 51 | while dl_info.index != dl_idx { 52 | dl_info = h.advance_deadline(&rt, CronConfig::default()); 53 | } 54 | 55 | // faults are charged at ongoing rate and no additional power is removed 56 | let ongoing_pwr = power_for_sectors(h.sector_size, &all_sectors); 57 | let ongoing_penalty = pledge_penalty_for_continued_fault( 58 | &h.epoch_reward_smooth, 59 | &h.epoch_qa_power_smooth, 60 | &ongoing_pwr.qa, 61 | ); 62 | let burnt_funds = daily_fee_for_sectors(&all_sectors) + ongoing_penalty; 63 | h.advance_deadline( 64 | &rt, 65 | CronConfig { pledge_delta: -burnt_funds.clone(), burnt_funds, ..Default::default() }, 66 | ); 67 | h.check_state(&rt); 68 | } 69 | -------------------------------------------------------------------------------- /actors/miner/tests/expected_reward_for_power_clampted_at_atto_fil_test.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Neg; 2 | 3 | use fil_actor_miner::detail::expected_reward_for_power_clamped_at_atto_fil; 4 | use fil_actors_runtime::reward::FilterEstimate; 5 | use fvm_shared::bigint::{BigInt, Zero}; 6 | use fvm_shared::econ::TokenAmount; 7 | use fvm_shared::sector::StoragePower; 8 | 9 | #[test] 10 | fn expected_zero_valued_br_clamped_at_1_attofil() { 11 | let epoch_target_reward = BigInt::from(1u64 << 50); 12 | let zero_qa_power = StoragePower::zero(); 13 | let network_qa_power = StoragePower::from(1u64 << 10); 14 | let power_rate_of_change = StoragePower::from(1 << 10); 15 | let reward_estimate = FilterEstimate::new(epoch_target_reward, BigInt::zero()); 16 | let power_estimate = FilterEstimate::new(network_qa_power, power_rate_of_change); 17 | 18 | let br_clamped = expected_reward_for_power_clamped_at_atto_fil( 19 | &reward_estimate, 20 | &power_estimate, 21 | &zero_qa_power, 22 | 1, 23 | ); 24 | assert_eq!(TokenAmount::from_atto(1), br_clamped); 25 | } 26 | 27 | #[test] 28 | fn expected_negative_value_br_clamped_at_1_atto_fil() { 29 | let epoch_target_reward = BigInt::from(1u64 << 50); 30 | let qa_sector_power = StoragePower::from(1u64 << 36); 31 | let network_qa_power = StoragePower::from(1u64 << 10); 32 | let power_rate_of_change = StoragePower::from(1 << 10).neg(); 33 | let reward_estimate = FilterEstimate::new(epoch_target_reward, BigInt::zero()); 34 | let power_estimate = FilterEstimate::new(network_qa_power, power_rate_of_change); 35 | 36 | let four_br_clamped = expected_reward_for_power_clamped_at_atto_fil( 37 | &reward_estimate, 38 | &power_estimate, 39 | &qa_sector_power, 40 | 4, 41 | ); 42 | assert_eq!(TokenAmount::from_atto(1), four_br_clamped); 43 | } 44 | -------------------------------------------------------------------------------- /actors/miner/tests/initial_pledge.rs: -------------------------------------------------------------------------------- 1 | use fil_actor_miner::{Actor, InitialPledgeReturn, Method, State}; 2 | use fil_actors_runtime::test_utils::*; 3 | use fvm_shared::econ::TokenAmount; 4 | use util::{ActorHarness, DEFAULT_SECTOR_EXPIRATION}; 5 | mod util; 6 | 7 | fn setup() -> (ActorHarness, MockRuntime) { 8 | let big_balance = 20u128.pow(23); 9 | let period_offset = 100; 10 | let precommit_epoch = 1; 11 | 12 | let h = ActorHarness::new(period_offset); 13 | let rt = h.new_runtime(); 14 | h.construct_and_verify(&rt); 15 | rt.balance.replace(TokenAmount::from_atto(big_balance)); 16 | rt.set_epoch(precommit_epoch); 17 | 18 | (h, rt) 19 | } 20 | 21 | #[test] 22 | fn test_initial_pledge_method() { 23 | let (mut h, rt) = setup(); 24 | let _sector_info = 25 | h.commit_and_prove_sectors(&rt, 1, DEFAULT_SECTOR_EXPIRATION, Vec::new(), true); 26 | 27 | let st: State = rt.get_state(); 28 | 29 | rt.expect_validate_caller_any(); 30 | let ret: InitialPledgeReturn = rt 31 | .call::(Method::InitialPledgeExported as u64, None) 32 | .unwrap() 33 | .unwrap() 34 | .deserialize() 35 | .unwrap(); 36 | rt.verify(); 37 | 38 | assert!(st.initial_pledge.is_positive()); 39 | assert_eq!(st.initial_pledge, ret.initial_pledge); 40 | 41 | h.check_state(&rt); 42 | } 43 | -------------------------------------------------------------------------------- /actors/miner/tests/miner_actor_test_ctl_addrs.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_runtime::test_utils::*; 2 | 3 | mod util; 4 | 5 | #[test] 6 | fn test_control_addrs() { 7 | let rt = MockRuntime::default(); 8 | let h = util::ActorHarness::new(0); 9 | 10 | h.construct_and_verify(&rt); 11 | 12 | let (owner, worker, control_addrs) = h.get_control_addresses(&rt); 13 | assert_eq!(h.owner, owner); 14 | assert_eq!(h.worker, worker); 15 | assert_eq!(h.control_addrs, control_addrs); 16 | 17 | h.check_state(&rt); 18 | } 19 | -------------------------------------------------------------------------------- /actors/miner/tests/precommit_deposit_and_initial_pledge_positive_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actor_miner::{initial_pledge_for_power, pre_commit_deposit_for_power}; 2 | use fil_actors_runtime::reward::FilterEstimate; 3 | use fvm_shared::econ::TokenAmount; 4 | use fvm_shared::sector::StoragePower; 5 | use num_traits::zero; 6 | 7 | macro_rules! my_const { 8 | ($name:ident, $ret_type:ty, $value:expr) => { 9 | fn $name() -> $ret_type { 10 | $value 11 | } 12 | }; 13 | } 14 | 15 | my_const!(epoch_target_reward, TokenAmount, zero()); 16 | my_const!(qa_sector_power, StoragePower, StoragePower::from(1u64 << 36)); 17 | my_const!(network_qa_power, StoragePower, StoragePower::from(1u64 << 10)); 18 | my_const!(baseline_power, StoragePower, network_qa_power()); 19 | my_const!(power_rate_of_change, StoragePower, StoragePower::from(1u64 << 10)); 20 | my_const!( 21 | reward_estimate, 22 | FilterEstimate, 23 | FilterEstimate::new(epoch_target_reward().atto().clone(), zero()) 24 | ); 25 | my_const!( 26 | power_estimate, 27 | FilterEstimate, 28 | FilterEstimate::new(network_qa_power(), power_rate_of_change()) 29 | ); 30 | my_const!(circulating_supply, TokenAmount, zero()); 31 | 32 | #[test] 33 | fn initial_pledge_clamped_at_one_attofil() { 34 | // constant zero reward and zero circulating supply => IP = 0 35 | let initial_pledge = initial_pledge_for_power( 36 | &qa_sector_power(), 37 | &baseline_power(), 38 | &reward_estimate(), 39 | &power_estimate(), 40 | &circulating_supply(), 41 | // NOTE: setting this to zero preserves the original pledge definition (before baseline bug fix) 42 | // so these inputs configure the function to return the original pledge 43 | 0, 44 | 0, 45 | ); 46 | assert_eq!(TokenAmount::from_atto(1), initial_pledge); 47 | } 48 | 49 | #[test] 50 | fn precommit_deposit_is_clamped_at_one_attofil() { 51 | let precommit_deposit = 52 | pre_commit_deposit_for_power(&reward_estimate(), &power_estimate(), &qa_sector_power()); 53 | assert_eq!(TokenAmount::from_atto(1), precommit_deposit); 54 | } 55 | -------------------------------------------------------------------------------- /actors/miner/tests/precommit_expiry.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use fil_actors_runtime::runtime::Policy; 5 | use fvm_shared::clock::ChainEpoch; 6 | 7 | mod util; 8 | use util::*; 9 | 10 | mod state_harness; 11 | use state_harness::*; 12 | 13 | const PERIOD_OFFSET: ChainEpoch = 0; 14 | 15 | mod add_precommit_expiry { 16 | use super::*; 17 | 18 | #[test] 19 | fn simple_pre_commit_expiry_and_cleanup() { 20 | let policy = Policy::default(); 21 | let mut h = StateHarness::new_with_policy(&policy, PERIOD_OFFSET); 22 | 23 | h.add_pre_commit_clean_ups(&policy, Vec::from([(100, 1)])).unwrap(); 24 | 25 | let quant = h.quant_spec_every_deadline(&policy); 26 | BitFieldQueueExpectation::default() 27 | .add(quant.quantize_up(100), &[1]) 28 | .equals(&h.load_pre_commit_clean_ups(&policy)); 29 | 30 | h.add_pre_commit_clean_ups(&policy, Vec::from([(100, 2)])).unwrap(); 31 | BitFieldQueueExpectation::default() 32 | .add(quant.quantize_up(100), &[1, 2]) 33 | .equals(&h.load_pre_commit_clean_ups(&policy)); 34 | 35 | h.add_pre_commit_clean_ups(&policy, Vec::from([(200, 3)])).unwrap(); 36 | BitFieldQueueExpectation::default() 37 | .add(quant.quantize_up(100), &[1, 2]) 38 | .add(quant.quantize_up(200), &[3]) 39 | .equals(&h.load_pre_commit_clean_ups(&policy)); 40 | } 41 | 42 | #[test] 43 | fn batch_pre_commit_expiry() { 44 | let policy = Policy::default(); 45 | let mut h = StateHarness::new_with_policy(&policy, PERIOD_OFFSET); 46 | 47 | h.add_pre_commit_clean_ups(&policy, Vec::from([(100, 1), (200, 2), (200, 3)])).unwrap(); 48 | 49 | let quant = h.quant_spec_every_deadline(&policy); 50 | BitFieldQueueExpectation::default() 51 | .add(quant.quantize_up(100), &[1]) 52 | .add(quant.quantize_up(200), &[2, 3]) 53 | .equals(&h.load_pre_commit_clean_ups(&policy)); 54 | 55 | h.add_pre_commit_clean_ups( 56 | &policy, 57 | Vec::from([ 58 | (100, 1), // Redundant 59 | (200, 4), 60 | (300, 5), 61 | (300, 6), 62 | ]), 63 | ) 64 | .unwrap(); 65 | BitFieldQueueExpectation::default() 66 | .add(quant.quantize_up(100), &[1]) 67 | .add(quant.quantize_up(200), &[2, 3, 4]) 68 | .add(quant.quantize_up(300), &[5, 6]) 69 | .equals(&h.load_pre_commit_clean_ups(&policy)); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /actors/miner/tests/repay_debt_test.rs: -------------------------------------------------------------------------------- 1 | mod state_harness; 2 | use fvm_shared::econ::TokenAmount; 3 | use state_harness::*; 4 | 5 | use num_traits::Zero; 6 | 7 | #[test] 8 | fn repay_debt_in_priority_order() { 9 | let mut h = StateHarness::new(0); 10 | 11 | let current_balance = TokenAmount::from_atto(300u16); 12 | let fee = TokenAmount::from_atto(1000); 13 | 14 | h.st.apply_penalty(&fee).unwrap(); 15 | assert_eq!(h.st.fee_debt, fee); 16 | 17 | let (penalty_from_vesting, penalty_from_balance) = 18 | h.st.repay_partial_debt_in_priority_order(&h.store, 0, ¤t_balance).unwrap(); 19 | assert_eq!(penalty_from_vesting, current_balance); 20 | assert_eq!(penalty_from_balance, TokenAmount::zero()); 21 | 22 | let expected_debt = -(current_balance - fee); 23 | assert_eq!(expected_debt, h.st.fee_debt); 24 | 25 | let current_balance = TokenAmount::zero(); 26 | let fee = TokenAmount::from_atto(2050); 27 | h.st.apply_penalty(&fee).unwrap(); 28 | 29 | h.st.repay_partial_debt_in_priority_order(&h.store, 33, ¤t_balance).unwrap(); 30 | let expected_debt = expected_debt + fee; 31 | assert_eq!(expected_debt, h.st.fee_debt); 32 | } 33 | -------------------------------------------------------------------------------- /actors/miner/tests/vesting_add_locked_funds.rs: -------------------------------------------------------------------------------- 1 | use fil_actor_miner::VestSpec; 2 | use fvm_shared::bigint::Zero; 3 | use fvm_shared::econ::TokenAmount; 4 | 5 | mod state_harness; 6 | use state_harness::*; 7 | 8 | #[test] 9 | fn locked_funds_increases_with_sequential_calls() { 10 | let mut h = StateHarness::new(0); 11 | let vspec = VestSpec { initial_delay: 0, vest_period: 1, step_duration: 1, quantization: 1 }; 12 | 13 | let vest_start = 10; 14 | let vest_sum = TokenAmount::from_atto(100); 15 | 16 | h.add_locked_funds(vest_start, &vest_sum, &vspec).unwrap(); 17 | assert_eq!(vest_sum, h.st.locked_funds); 18 | 19 | h.add_locked_funds(vest_start, &vest_sum, &vspec).unwrap(); 20 | assert_eq!(vest_sum * 2, h.st.locked_funds); 21 | } 22 | 23 | #[test] 24 | fn vests_when_quantize_step_duration_and_vesting_period_are_coprime() { 25 | let mut h = StateHarness::new(0); 26 | let vspec = VestSpec { initial_delay: 0, vest_period: 27, step_duration: 5, quantization: 7 }; 27 | 28 | let vest_start = 10; 29 | let vest_sum = TokenAmount::from_atto(100); 30 | h.add_locked_funds(vest_start, &vest_sum, &vspec).unwrap(); 31 | assert_eq!(vest_sum, h.st.locked_funds); 32 | 33 | let mut total_vested = TokenAmount::zero(); 34 | for e in vest_start..=43 { 35 | let amount_vested = h.unlock_vested_funds(e).unwrap(); 36 | match e { 37 | 22 => { 38 | assert_eq!(TokenAmount::from_atto(40), amount_vested); 39 | } 40 | 29 => { 41 | assert_eq!(TokenAmount::from_atto(26), amount_vested); 42 | } 43 | 36 => { 44 | assert_eq!(TokenAmount::from_atto(26), amount_vested); 45 | } 46 | 43 => { 47 | assert_eq!(TokenAmount::from_atto(8), amount_vested); 48 | } 49 | _ => { 50 | assert_eq!(TokenAmount::zero(), amount_vested); 51 | } 52 | } 53 | total_vested += amount_vested; 54 | } 55 | assert_eq!(vest_sum, total_vested); 56 | assert!(h.st.locked_funds.is_zero()); 57 | assert!(h.vesting_funds_store_empty()) 58 | } 59 | -------------------------------------------------------------------------------- /actors/multisig/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_multisig" 3 | description = "Builtin multisig actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true} 18 | 19 | anyhow = { workspace = true } 20 | cid = { workspace = true } 21 | frc42_dispatch = { workspace = true } 22 | fvm_actor_utils = { workspace = true } 23 | fvm_ipld_blockstore = { workspace = true } 24 | fvm_ipld_encoding = { workspace = true } 25 | fvm_ipld_hamt = { workspace = true } 26 | fvm_shared = { workspace = true } 27 | indexmap = { workspace = true } 28 | integer-encoding = { workspace = true } 29 | num-derive = { workspace = true } 30 | num-traits = { workspace = true } 31 | serde = { workspace = true } 32 | 33 | [dev-dependencies] 34 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 35 | lazy_static = { workspace = true } 36 | 37 | [features] 38 | fil-actor = ["fil_actors_runtime/fil-actor"] 39 | -------------------------------------------------------------------------------- /actors/paych/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_paych" 3 | description = "Builtin paych actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true } 18 | frc42_dispatch = { workspace = true } 19 | fvm_shared = { workspace = true } 20 | num-traits = { workspace = true } 21 | num-derive = { workspace = true } 22 | serde = { workspace = true } 23 | cid = { workspace = true } 24 | anyhow = { workspace = true } 25 | fvm_ipld_blockstore = { workspace = true } 26 | fvm_ipld_encoding = { workspace = true } 27 | 28 | [dev-dependencies] 29 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 30 | fvm_ipld_amt = { workspace = true } 31 | derive_builder = { workspace = true } 32 | lazy_static = { workspace = true } 33 | 34 | [features] 35 | fil-actor = ["fil_actors_runtime/fil-actor"] 36 | -------------------------------------------------------------------------------- /actors/paych/src/ext.rs: -------------------------------------------------------------------------------- 1 | use fvm_ipld_encoding::strict_bytes; 2 | use fvm_ipld_encoding::tuple::*; 3 | 4 | pub mod account { 5 | use super::*; 6 | 7 | pub const AUTHENTICATE_MESSAGE_METHOD: u64 = 8 | frc42_dispatch::method_hash!("AuthenticateMessage"); 9 | 10 | #[derive(Serialize_tuple, Deserialize_tuple)] 11 | pub struct AuthenticateMessageParams { 12 | #[serde(with = "strict_bytes")] 13 | pub signature: Vec, 14 | #[serde(with = "strict_bytes")] 15 | pub message: Vec, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /actors/paych/src/state.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use cid::Cid; 5 | use fvm_ipld_encoding::tuple::*; 6 | use fvm_shared::address::Address; 7 | 8 | use fvm_shared::clock::ChainEpoch; 9 | use fvm_shared::econ::TokenAmount; 10 | 11 | /// A given payment channel actor is established by `from` 12 | /// to enable off-chain microtransactions to `to` address 13 | /// to be reconciled and tallied on chain. 14 | #[derive(Debug, Serialize_tuple, Deserialize_tuple, Clone)] 15 | pub struct State { 16 | /// Channel owner, who has funded the actor. 17 | pub from: Address, 18 | /// Recipient of payouts from channel. 19 | pub to: Address, 20 | /// Amount successfully redeemed through the payment channel, paid out on `Collect`. 21 | pub to_send: TokenAmount, 22 | /// Height at which the channel can be collected. 23 | pub settling_at: ChainEpoch, 24 | /// Height before which the channel `ToSend` cannot be collected. 25 | pub min_settle_height: ChainEpoch, 26 | /// Collections of lane states for the channel, maintained in ID order. 27 | pub lane_states: Cid, // AMT 28 | } 29 | 30 | impl State { 31 | pub fn new(from: Address, to: Address, empty_arr_cid: Cid) -> Self { 32 | Self { 33 | from, 34 | to, 35 | to_send: Default::default(), 36 | settling_at: 0, 37 | min_settle_height: 0, 38 | lane_states: empty_arr_cid, 39 | } 40 | } 41 | } 42 | 43 | /// The Lane state tracks the latest (highest) voucher nonce used to merge the lane 44 | /// as well as the amount it has already redeemed. 45 | #[derive(Default, Clone, PartialEq, Eq, Debug, Serialize_tuple, Deserialize_tuple)] 46 | pub struct LaneState { 47 | pub redeemed: TokenAmount, 48 | pub nonce: u64, 49 | } 50 | 51 | /// Specifies which `lane`s to be merged with what `nonce` on `channel_update` 52 | #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)] 53 | pub struct Merge { 54 | pub lane: u64, 55 | pub nonce: u64, 56 | } 57 | -------------------------------------------------------------------------------- /actors/paych/src/testing.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_runtime::MessageAccumulator; 2 | use fil_actors_runtime::fvm_ipld_amt; 3 | use fvm_ipld_amt::Amt; 4 | use fvm_ipld_blockstore::Blockstore; 5 | use fvm_shared::{address::Protocol, econ::TokenAmount}; 6 | use num_traits::Zero; 7 | 8 | use crate::{LaneState, State}; 9 | 10 | pub struct StateSummary { 11 | pub redeemed: TokenAmount, 12 | } 13 | 14 | /// Checks internal invariants of paych state 15 | pub fn check_state_invariants( 16 | state: &State, 17 | store: &BS, 18 | balance: &TokenAmount, 19 | ) -> (StateSummary, MessageAccumulator) { 20 | let acc = MessageAccumulator::default(); 21 | let mut redeemed = TokenAmount::zero(); 22 | 23 | acc.require( 24 | state.from.protocol() == Protocol::ID, 25 | format!("from address is not ID address {}", state.from), 26 | ); 27 | acc.require( 28 | state.to.protocol() == Protocol::ID, 29 | format!("to address is not ID address {}", state.to), 30 | ); 31 | acc.require( 32 | state.settling_at >= state.min_settle_height, 33 | format!( 34 | "channel is setting at epoch {} before min settle height {}", 35 | state.settling_at, state.min_settle_height 36 | ), 37 | ); 38 | 39 | match Amt::::load(&state.lane_states, store) { 40 | Ok(lanes) => { 41 | let ret = lanes.for_each(|i, lane| { 42 | acc.require( 43 | lane.redeemed.is_positive(), 44 | format!("lane {i} redeemed is not greater than zero {}", lane.redeemed), 45 | ); 46 | redeemed += &lane.redeemed; 47 | Ok(()) 48 | }); 49 | acc.require_no_error(ret, "error iterating lanes"); 50 | } 51 | Err(e) => acc.add(format!("error loading lanes: {e}")), 52 | } 53 | 54 | acc.require( 55 | balance >= &state.to_send, 56 | format!("channel has insufficient funds to send ({} < {})", balance, state.to_send), 57 | ); 58 | 59 | (StateSummary { redeemed }, acc) 60 | } 61 | -------------------------------------------------------------------------------- /actors/placeholder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_placeholder" 3 | description = "Builtin placeholder actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [features] 17 | fil-actor = [] 18 | -------------------------------------------------------------------------------- /actors/placeholder/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "fil-actor")] 2 | #[unsafe(no_mangle)] 3 | pub extern "C" fn invoke(_: u32) -> u32 { 4 | 0 5 | } 6 | -------------------------------------------------------------------------------- /actors/power/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_power" 3 | description = "Builtin power actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true } 18 | frc42_dispatch = { workspace = true } 19 | fvm_shared = { workspace = true } 20 | fvm_ipld_hamt = { workspace = true } 21 | num-traits = { workspace = true } 22 | num-derive = { workspace = true } 23 | log = { workspace = true } 24 | indexmap = { workspace = true } 25 | cid = { workspace = true } 26 | integer-encoding = { workspace = true } 27 | lazy_static = { workspace = true } 28 | serde = { workspace = true } 29 | anyhow = { workspace = true } 30 | fvm_ipld_blockstore = { workspace = true } 31 | fvm_ipld_encoding = { workspace = true } 32 | 33 | [dev-dependencies] 34 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 35 | fil_actor_reward = { workspace = true } 36 | hex-literal = { workspace = true } 37 | 38 | [features] 39 | fil-actor = ["fil_actors_runtime/fil-actor"] 40 | -------------------------------------------------------------------------------- /actors/power/src/ext.rs: -------------------------------------------------------------------------------- 1 | use cid::Cid; 2 | use fvm_ipld_encoding::tuple::*; 3 | use fvm_ipld_encoding::{BytesDe, strict_bytes}; 4 | 5 | use fvm_shared::METHOD_CONSTRUCTOR; 6 | use fvm_shared::address::Address; 7 | use fvm_shared::sector::RegisteredPoStProof; 8 | use num_derive::FromPrimitive; 9 | 10 | use fil_actors_runtime::reward::FilterEstimate; 11 | 12 | pub mod init { 13 | use super::*; 14 | use fvm_ipld_encoding::RawBytes; 15 | 16 | pub const EXEC_METHOD: u64 = 2; 17 | 18 | /// Init actor Exec Params 19 | #[derive(Serialize_tuple, Deserialize_tuple)] 20 | pub struct ExecParams { 21 | pub code_cid: Cid, 22 | pub constructor_params: RawBytes, 23 | } 24 | 25 | /// Init actor Exec Return value 26 | #[derive(Serialize_tuple, Deserialize_tuple)] 27 | pub struct ExecReturn { 28 | /// ID based address for created actor 29 | pub id_address: Address, 30 | /// Reorg safe address for actor 31 | pub robust_address: Address, 32 | } 33 | } 34 | 35 | pub mod miner { 36 | use super::*; 37 | 38 | pub const ON_DEFERRED_CRON_EVENT_METHOD: u64 = 12; 39 | 40 | #[derive(Serialize_tuple, Deserialize_tuple)] 41 | pub struct MinerConstructorParams { 42 | pub owner: Address, 43 | pub worker: Address, 44 | pub control_addresses: Vec
, 45 | pub window_post_proof_type: RegisteredPoStProof, 46 | #[serde(with = "strict_bytes")] 47 | pub peer_id: Vec, 48 | pub multi_addresses: Vec, 49 | } 50 | 51 | #[derive(Serialize_tuple, Deserialize_tuple)] 52 | pub struct DeferredCronEventParams { 53 | #[serde(with = "strict_bytes")] 54 | pub event_payload: Vec, 55 | pub reward_smoothed: FilterEstimate, 56 | pub quality_adj_power_smoothed: FilterEstimate, 57 | } 58 | } 59 | 60 | pub mod reward { 61 | use super::*; 62 | 63 | pub const UPDATE_NETWORK_KPI: u64 = 4; 64 | 65 | #[derive(FromPrimitive)] 66 | #[repr(u64)] 67 | pub enum Method { 68 | Constructor = METHOD_CONSTRUCTOR, 69 | AwardBlockReward = 2, 70 | ThisEpochReward = 3, 71 | UpdateNetworkKPI = 4, 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /actors/power/src/policy.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | /// Minimum power of an individual miner to meet the threshold for leader election. 5 | pub const CONSENSUS_MINER_MIN_MINERS: i64 = 4; 6 | 7 | /// Maximum number of prove commits a miner can submit in one epoch 8 | /// 9 | /// We bound this to 200 to limit the number of prove partitions we may need to update in a 10 | /// given epoch to 200. 11 | /// 12 | /// To support onboarding 1EiB/year, we need to allow at least 32 prove commits per epoch. 13 | pub const MAX_MINER_PROVE_COMMITS_PER_EPOCH: u64 = 200; 14 | -------------------------------------------------------------------------------- /actors/power/tests/types_test.rs: -------------------------------------------------------------------------------- 1 | // Tests to match with Go github.com/filecoin-project/go-state-types/builtin/*/power 2 | mod serialization { 3 | use hex_literal::hex; 4 | 5 | use fil_actor_power::CurrentTotalPowerReturn; 6 | use fvm_ipld_encoding::ipld_block::IpldBlock; 7 | 8 | use fil_actors_runtime::reward::FilterEstimate; 9 | use fvm_shared::bigint::BigInt; 10 | use fvm_shared::econ::TokenAmount; 11 | use fvm_shared::sector::StoragePower; 12 | 13 | #[test] 14 | fn current_total_power_return() { 15 | let test_cases = vec![ 16 | ( 17 | CurrentTotalPowerReturn { 18 | raw_byte_power: Default::default(), 19 | quality_adj_power: Default::default(), 20 | pledge_collateral: Default::default(), 21 | quality_adj_power_smoothed: Default::default(), 22 | ramp_start_epoch: Default::default(), 23 | ramp_duration_epochs: Default::default(), 24 | }, 25 | // [byte[],byte[],byte[],[byte[],byte[]],0,0] 26 | &hex!("864040408240400000")[..], 27 | ), 28 | ( 29 | CurrentTotalPowerReturn { 30 | raw_byte_power: StoragePower::from(1 << 20), 31 | quality_adj_power: StoragePower::from(1 << 21), 32 | pledge_collateral: TokenAmount::from_atto(1 << 22), 33 | quality_adj_power_smoothed: FilterEstimate::new( 34 | BigInt::from(1 << 23), 35 | BigInt::from(1 << 24), 36 | ), 37 | ramp_start_epoch: 25, 38 | ramp_duration_epochs: 26, 39 | }, 40 | // FilterEstimate BigInts have a precision shift of 128, so they end up larger than the others. 41 | // [byte[00100000],byte[00200000],byte[00400000],[byte[0080000000000000000000000000000000000000],byte[000100000000000000000000000000000000000000]],25,26] 42 | &hex!( 43 | "8644001000004400200000440040000082540080000000000000000000000000000000000000550001000000000000000000000000000000000000001819181a" 44 | ), 45 | ), 46 | ]; 47 | 48 | for (params, expected_hex) in test_cases { 49 | let encoded = IpldBlock::serialize_cbor(¶ms).unwrap().unwrap(); 50 | assert_eq!(encoded.data, expected_hex); 51 | let decoded: CurrentTotalPowerReturn = IpldBlock::deserialize(&encoded).unwrap(); 52 | assert_eq!(params, decoded); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /actors/reward/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_reward" 3 | description = "Builtin reward actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true } 18 | fvm_shared = { workspace = true } 19 | num-traits = { workspace = true } 20 | num-derive = { workspace = true } 21 | log = { workspace = true } 22 | lazy_static = { workspace = true } 23 | serde = { workspace = true } 24 | fvm_ipld_blockstore = { workspace = true } 25 | fvm_ipld_encoding = { workspace = true } 26 | 27 | [dev-dependencies] 28 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 29 | num = { workspace = true } 30 | 31 | [features] 32 | fil-actor = ["fil_actors_runtime/fil-actor"] 33 | -------------------------------------------------------------------------------- /actors/reward/src/expneg.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use fvm_shared::bigint::{BigInt, Integer}; 5 | use lazy_static::lazy_static; 6 | 7 | use fil_actors_runtime::builtin::reward::math::{PRECISION, poly_parse, poly_val}; 8 | 9 | lazy_static! { 10 | static ref EXP_NUM_COEF: Vec = poly_parse(&[ 11 | "-648770010757830093818553637600", 12 | "67469480939593786226847644286976", 13 | "-3197587544499098424029388939001856", 14 | "89244641121992890118377641805348864", 15 | "-1579656163641440567800982336819953664", 16 | "17685496037279256458459817590917169152", 17 | "-115682590513835356866803355398940131328", 18 | "340282366920938463463374607431768211456", 19 | ]) 20 | .unwrap(); 21 | static ref EXP_DENO_COEF: Vec = poly_parse(&[ 22 | "1225524182432722209606361", 23 | "114095592300906098243859450", 24 | "5665570424063336070530214243", 25 | "194450132448609991765137938448", 26 | "5068267641632683791026134915072", 27 | "104716890604972796896895427629056", 28 | "1748338658439454459487681798864896", 29 | "23704654329841312470660182937960448", 30 | "259380097567996910282699886670381056", 31 | "2250336698853390384720606936038375424", 32 | "14978272436876548034486263159246028800", 33 | "72144088983913131323343765784380833792", 34 | "224599776407103106596571252037123047424", 35 | "340282366920938463463374607431768211456", 36 | ]) 37 | .unwrap(); 38 | } 39 | 40 | /// expneg accepts x in Q.128 format and computes e^-x. 41 | /// It is most precise within [0, 1.725) range, where error is less than 3.4e-30. 42 | /// Over the [0, 5) range its error is less than 4.6e-15. 43 | /// Output is in Q.128 format. 44 | pub(crate) fn expneg(x: &BigInt) -> BigInt { 45 | let num = poly_val(&EXP_NUM_COEF, x); 46 | let deno = poly_val(&EXP_DENO_COEF, x); 47 | 48 | (num << PRECISION).div_floor(&deno) 49 | } 50 | -------------------------------------------------------------------------------- /actors/reward/src/ext.rs: -------------------------------------------------------------------------------- 1 | use fvm_ipld_encoding::tuple::*; 2 | use fvm_shared::econ::TokenAmount; 3 | 4 | pub mod miner { 5 | use super::*; 6 | 7 | pub const APPLY_REWARDS_METHOD: u64 = 14; 8 | 9 | #[derive(Debug, Serialize_tuple, Deserialize_tuple)] 10 | pub struct ApplyRewardParams { 11 | pub reward: TokenAmount, 12 | pub penalty: TokenAmount, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /actors/reward/src/testing.rs: -------------------------------------------------------------------------------- 1 | use crate::State; 2 | use fil_actors_runtime::MessageAccumulator; 3 | use fvm_shared::{clock::ChainEpoch, econ::TokenAmount}; 4 | use num_traits::Signed; 5 | 6 | #[derive(Default)] 7 | pub struct StateSummary {} 8 | 9 | pub fn check_state_invariants( 10 | state: &State, 11 | prior_epoch: ChainEpoch, 12 | balance: &TokenAmount, 13 | ) -> (StateSummary, MessageAccumulator) { 14 | let acc = MessageAccumulator::default(); 15 | 16 | let storage_mining_allocation_check = TokenAmount::from_whole(1_100_000_000); 17 | 18 | // Can't assert equality because anyone can send funds to reward actor (and already have on mainnet) 19 | acc.require( 20 | &state.total_storage_power_reward + balance >= storage_mining_allocation_check, 21 | format!( 22 | "reward given {} + reward left {} < storage mining allocation {}", 23 | state.total_storage_power_reward, balance, storage_mining_allocation_check 24 | ), 25 | ); 26 | 27 | acc.require( 28 | state.epoch == prior_epoch + 1, 29 | format!( 30 | "reward state epoch {} does not match prior_epoch+1 {}", 31 | state.epoch, 32 | prior_epoch + 1 33 | ), 34 | ); 35 | acc.require( 36 | state.effective_network_time <= state.epoch, 37 | format!( 38 | "effective network time {} greater than state epoch {}", 39 | state.effective_network_time, state.epoch 40 | ), 41 | ); 42 | 43 | acc.require( 44 | state.cumsum_realized <= state.cumsum_baseline, 45 | format!( 46 | "cumsum realized {} > cumsum baseline {}", 47 | state.cumsum_realized, state.cumsum_baseline 48 | ), 49 | ); 50 | acc.require( 51 | !state.cumsum_realized.is_negative(), 52 | format!("cumsum realized negative ({})", state.cumsum_realized), 53 | ); 54 | 55 | (StateSummary::default(), acc) 56 | } 57 | -------------------------------------------------------------------------------- /actors/reward/src/types.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use fvm_ipld_encoding::tuple::*; 5 | use fvm_shared::address::Address; 6 | use fvm_shared::bigint::bigint_ser::BigIntDe; 7 | use fvm_shared::econ::TokenAmount; 8 | 9 | #[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)] 10 | #[serde(transparent)] 11 | pub struct ConstructorParams { 12 | pub power: Option, 13 | } 14 | 15 | #[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)] 16 | pub struct AwardBlockRewardParams { 17 | pub miner: Address, 18 | pub penalty: TokenAmount, 19 | pub gas_reward: TokenAmount, 20 | pub win_count: i64, 21 | } 22 | 23 | pub use fil_actors_runtime::builtin::reward::ThisEpochRewardReturn; 24 | 25 | #[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)] 26 | #[serde(transparent)] 27 | pub struct UpdateNetworkKPIParams { 28 | pub curr_realized_power: Option, 29 | } 30 | -------------------------------------------------------------------------------- /actors/system/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_system" 3 | description = "Builtin system actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true } 18 | fvm_shared = { workspace = true } 19 | fvm_ipld_encoding = { workspace = true } 20 | multihash-codetable = { workspace = true } 21 | fvm_ipld_blockstore = { workspace = true } 22 | num-traits = { workspace = true } 23 | anyhow = { workspace = true } 24 | num-derive = { workspace = true } 25 | serde = { workspace = true } 26 | cid = { workspace = true } 27 | 28 | [dev-dependencies] 29 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 30 | 31 | [features] 32 | fil-actor = ["fil_actors_runtime/fil-actor"] 33 | -------------------------------------------------------------------------------- /actors/verifreg/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actor_verifreg" 3 | description = "Builtin verifreg actor for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actors_runtime = { workspace = true} 18 | 19 | anyhow = { workspace = true } 20 | cid = { workspace = true } 21 | frc42_dispatch = { workspace = true } 22 | frc46_token = { workspace = true } 23 | fvm_actor_utils = { workspace = true } 24 | fvm_ipld_blockstore = { workspace = true } 25 | fvm_ipld_encoding = { workspace = true } 26 | fvm_ipld_hamt = { workspace = true } 27 | fvm_shared = { workspace = true } 28 | lazy_static = { workspace = true } 29 | log = { workspace = true } 30 | num-derive = { workspace = true } 31 | num-traits = { workspace = true } 32 | serde = { workspace = true } 33 | 34 | [dev-dependencies] 35 | hex-literal = { workspace = true } 36 | fil_actors_runtime = { workspace = true, features = ["test_utils", "sector-default"] } 37 | 38 | [features] 39 | fil-actor = ["fil_actors_runtime/fil-actor"] 40 | 41 | -------------------------------------------------------------------------------- /actors/verifreg/src/ext.rs: -------------------------------------------------------------------------------- 1 | use fvm_ipld_encoding::strict_bytes; 2 | use fvm_ipld_encoding::tuple::*; 3 | use fvm_ipld_encoding::tuple::{Deserialize_tuple, Serialize_tuple}; 4 | use fvm_shared::address::Address; 5 | 6 | pub mod account { 7 | use super::*; 8 | 9 | pub const AUTHENTICATE_MESSAGE_METHOD: u64 = 10 | frc42_dispatch::method_hash!("AuthenticateMessage"); 11 | 12 | #[derive(Serialize_tuple, Deserialize_tuple)] 13 | pub struct AuthenticateMessageParams { 14 | #[serde(with = "strict_bytes")] 15 | pub signature: Vec, 16 | #[serde(with = "strict_bytes")] 17 | pub message: Vec, 18 | } 19 | } 20 | 21 | pub mod datacap { 22 | use super::*; 23 | use fvm_shared::econ::TokenAmount; 24 | 25 | #[repr(u64)] 26 | pub enum Method { 27 | Mint = frc42_dispatch::method_hash!("Mint"), 28 | Destroy = frc42_dispatch::method_hash!("Destroy"), 29 | Balance = frc42_dispatch::method_hash!("Balance"), 30 | Transfer = frc42_dispatch::method_hash!("Transfer"), 31 | Burn = frc42_dispatch::method_hash!("Burn"), 32 | } 33 | 34 | #[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)] 35 | pub struct MintParams { 36 | pub to: Address, 37 | pub amount: TokenAmount, 38 | pub operators: Vec
, 39 | } 40 | 41 | #[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)] 42 | pub struct DestroyParams { 43 | pub owner: Address, 44 | pub amount: TokenAmount, 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | [advisories] 2 | ignore = [ 3 | { id = "RUSTSEC-2024-0436", reason = "paste@1.0.15 excluded pending removal from alloy-core and syn-solidity; see https://github.com/alloy-rs/core/issues/897" }, 4 | { id = "RUSTSEC-2025-0014", reason = "humantime@2.1.0 is excluded pending an update of pretty_env_logger to use env_logger@0.11 which removes it" }, 5 | ] 6 | 7 | [licenses] 8 | allow = [ 9 | "Apache-2.0", 10 | "Apache-2.0 WITH LLVM-exception", 11 | "BSD-2-Clause", 12 | "BSD-3-Clause", 13 | "CC0-1.0", 14 | "MIT", 15 | "Unlicense", 16 | "Unicode-3.0" 17 | ] 18 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | This directory contains a dummy example to force cargo to include the "lock" file in the published 2 | crate. That way, we can do a wasm build with the locked dependencies. 3 | 4 | Unfortunately, simply "including" it doesn't work. We need to either add an example or a binary target. 5 | -------------------------------------------------------------------------------- /examples/dummy.rs: -------------------------------------------------------------------------------- 1 | fn main() {} 2 | -------------------------------------------------------------------------------- /integration_tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_actors_integration_tests" 3 | description = "Portable integration tests for FVM targets" 4 | version = "1.0.0" 5 | license = "MIT OR Apache-2.0" 6 | authors = ["Protocol Labs", "Filecoin Core Devs"] 7 | edition.workspace = true 8 | keywords = ["filecoin", "web3", "wasm"] 9 | publish = false 10 | 11 | [lib] 12 | 13 | [dependencies] 14 | fil_builtin_actors_state = { workspace = true } 15 | fil_actors_runtime = { workspace = true, features = [ "test_utils" ] } 16 | fil_actor_init = { workspace = true } 17 | fil_actor_cron = { workspace = true } 18 | fil_actor_system = { workspace = true } 19 | fil_actor_account = { workspace = true } 20 | fil_actor_multisig = { workspace = true } 21 | fil_actor_paych = { workspace = true } 22 | fil_actor_reward = { workspace = true } 23 | fil_actor_power = { workspace = true } 24 | fil_actor_market = { workspace = true } 25 | fil_actor_verifreg = { workspace = true } 26 | fil_actor_miner = { workspace = true } 27 | fil_actor_datacap = { workspace = true } 28 | fil_actor_evm = { workspace = true } 29 | fil_actor_eam = { workspace = true } 30 | fil_actor_ethaccount = { workspace = true } 31 | fil_actors_evm_shared = { workspace = true } 32 | vm_api = { workspace = true, features = ["testing"] } 33 | 34 | anyhow = { workspace = true } 35 | bimap = { workspace = true } 36 | blake2b_simd = { workspace = true } 37 | cid = { workspace = true } 38 | alloy-core = { workspace = true } 39 | frc42_dispatch = { workspace = true } 40 | frc46_token = { workspace = true } 41 | fvm_actor_utils = { workspace = true } 42 | fvm_ipld_bitfield = { workspace = true } 43 | fvm_ipld_blockstore = { workspace = true } 44 | fvm_ipld_encoding = { workspace = true } 45 | fvm_ipld_hamt = { workspace = true } 46 | fvm_shared = { workspace = true } 47 | hex = { workspace = true } 48 | hex-literal = { workspace = true } 49 | indexmap = { workspace = true } 50 | integer-encoding = { workspace = true } 51 | lazy_static = { workspace = true } 52 | log = { workspace = true } 53 | num-derive = { workspace = true } 54 | num-traits = { workspace = true } 55 | rand = { workspace = true } 56 | rand_chacha = { workspace = true } 57 | regex = { workspace = true } 58 | serde = { workspace = true } 59 | thiserror = { workspace = true } 60 | k256 = { workspace = true, features = ["ecdsa"] } 61 | export_macro = { path = "./macro" } 62 | ctor = "0.4.1" 63 | multihash-codetable = { workspace = true } 64 | 65 | [dev-dependencies] 66 | test-case = { workspace = true } 67 | hex-literal = { workspace = true } 68 | -------------------------------------------------------------------------------- /integration_tests/macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "export_macro" 3 | description = "Macro to decorate integration tests" 4 | version = "1.0.0" 5 | license = "MIT OR Apache-2.0" 6 | edition.workspace = true 7 | publish = false 8 | 9 | [lib] 10 | proc-macro = true 11 | 12 | [dependencies] 13 | syn = "2.0.100" 14 | quote = "1.0.40" 15 | proc-macro2 = "1.0.94" 16 | -------------------------------------------------------------------------------- /integration_tests/macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use quote::{format_ident, quote}; 3 | 4 | /// The vm_test attribute is used to decorate tests that run on an implementation of the FVM (i.e. 5 | /// taking vm_api::VM as an argument). Decorated tests are added to the global TEST_REGISTRY which 6 | /// is exported for use in other environments. 7 | /// TEST_REGISTRY acts as a single entry point for external crates/tooling to discover the suite of 8 | /// builtin-actors' integration tests. 9 | /// Test speed is an optional argument to the macro which must be a u8. Speed defaults to 0 indicating 10 | /// a fast test, with value increasing for slower tests. 11 | #[proc_macro_attribute] 12 | pub fn vm_test(attr: TokenStream, item: TokenStream) -> TokenStream { 13 | // Try to parse the u8 argument 14 | let literal_arg: Result = syn::parse(attr.clone()); 15 | 16 | // Determine the test speed based on the provided argument 17 | let test_category = if attr.is_empty() { 18 | 0 // Default if not provided 19 | } else { 20 | match literal_arg { 21 | Ok(syn::Lit::Int(lit_int)) => { 22 | // Attempt to parse the integer 23 | match lit_int.base10_parse::() { 24 | Ok(val) => val, 25 | Err(_) => panic!("Test speed value is too large. Please use a u8."), 26 | } 27 | } 28 | _ => panic!("Invalid argument for test speed. Please provide a u8 value."), 29 | } 30 | }; 31 | 32 | let input_fn = syn::parse_macro_input!(item as syn::ItemFn); 33 | let fn_name = &input_fn.sig.ident; 34 | 35 | // Generate a unique identifier for the registration function (unique within the module) 36 | let register_fn_name = format_ident!("register_{}", fn_name); 37 | 38 | let registry_code = quote! { 39 | #input_fn 40 | #[ctor::ctor] 41 | fn #register_fn_name() { 42 | // Registry key needs to be globally unique so we include module name 43 | let registry_key = concat!(module_path!(), "::", stringify!(#fn_name)); 44 | crate::TEST_REGISTRY.lock().unwrap().insert(registry_key.to_string(), (#test_category, #fn_name)); 45 | } 46 | }; 47 | 48 | registry_code.into() 49 | } 50 | -------------------------------------------------------------------------------- /integration_tests/src/tests/authenticate_message_test.rs: -------------------------------------------------------------------------------- 1 | use export_macro::vm_test; 2 | use fil_actor_account::Method::AuthenticateMessageExported; 3 | use fil_actor_account::types::AuthenticateMessageParams; 4 | use fvm_ipld_encoding::RawBytes; 5 | use fvm_shared::bigint::Zero; 6 | use fvm_shared::econ::TokenAmount; 7 | use fvm_shared::error::ExitCode; 8 | 9 | use crate::util::{create_accounts, generate_deal_proposal}; 10 | use vm_api::VM; 11 | use vm_api::util::{apply_code, apply_ok}; 12 | 13 | /// Using a deal proposal as a serialized message, we confirm that: 14 | /// - calls to Account::authenticate_message with valid signatures succeed 15 | /// - calls to Account::authenticate_message with invalid signatures fail 16 | #[vm_test] 17 | pub fn account_authenticate_message_test(v: &dyn VM) { 18 | let addr = create_accounts(v, 1, &TokenAmount::from_whole(10_000))[0]; 19 | 20 | let proposal = 21 | generate_deal_proposal(&addr, &addr, &TokenAmount::zero(), &TokenAmount::zero(), 0, 0); 22 | let proposal_ser = 23 | RawBytes::serialize(proposal).expect("failed to marshal deal proposal").to_vec(); 24 | 25 | // With a good sig, message succeeds 26 | let authenticate_message_params = AuthenticateMessageParams { 27 | signature: proposal_ser.clone(), 28 | message: proposal_ser.clone(), 29 | }; 30 | apply_ok( 31 | v, 32 | &addr, 33 | &addr, 34 | &TokenAmount::zero(), 35 | AuthenticateMessageExported as u64, 36 | Some(authenticate_message_params), 37 | ); 38 | 39 | // Bad, bad sig! message fails 40 | let authenticate_message_params = 41 | AuthenticateMessageParams { signature: vec![], message: proposal_ser }; 42 | apply_code( 43 | v, 44 | &addr, 45 | &addr, 46 | &TokenAmount::zero(), 47 | AuthenticateMessageExported as u64, 48 | Some(authenticate_message_params), 49 | ExitCode::USR_ILLEGAL_ARGUMENT, 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /integration_tests/src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | mod authenticate_message_test; 2 | pub use authenticate_message_test::*; 3 | mod batch_onboarding; 4 | pub use batch_onboarding::*; 5 | mod batch_onboarding_deals_test; 6 | pub use batch_onboarding_deals_test::*; 7 | mod change_beneficiary_test; 8 | pub use change_beneficiary_test::*; 9 | mod change_owner_test; 10 | pub use change_owner_test::*; 11 | mod commit_post_test; 12 | pub use commit_post_test::*; 13 | mod datacap_tests; 14 | pub use datacap_tests::*; 15 | mod evm_test; 16 | pub use evm_test::*; 17 | mod extend_sectors_test; 18 | pub use extend_sectors_test::*; 19 | mod market_miner_withdrawal_test; 20 | pub use market_miner_withdrawal_test::*; 21 | mod multisig_test; 22 | pub use multisig_test::*; 23 | mod init_test; 24 | pub use init_test::*; 25 | mod power_scenario_tests; 26 | pub use power_scenario_tests::*; 27 | mod publish_deals_test; 28 | pub use publish_deals_test::*; 29 | mod replica_update_test; 30 | pub use replica_update_test::*; 31 | mod terminate_test; 32 | pub use terminate_test::*; 33 | mod verified_claim_test; 34 | pub use verified_claim_test::*; 35 | mod verifreg_remove_datacap_test; 36 | pub use verifreg_remove_datacap_test::*; 37 | mod withdraw_balance_test; 38 | pub use withdraw_balance_test::*; 39 | mod prove_commit3_test; 40 | pub use prove_commit3_test::*; 41 | mod prove_commit_niporep_test; 42 | pub use prove_commit_niporep_test::*; 43 | mod replica_update3_test; 44 | pub use replica_update3_test::*; 45 | -------------------------------------------------------------------------------- /output/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/filecoin-project/builtin-actors/8fdbdec5e3f46b60ba0132d90533783a44c5961f/output/.keep -------------------------------------------------------------------------------- /runtime/build.rs: -------------------------------------------------------------------------------- 1 | static NETWORKS: &[(&str, &[&str])] = &[ 2 | ("mainnet", &["sector-32g", "sector-64g"]), 3 | ( 4 | "caterpillarnet", 5 | &[ 6 | "sector-512m", 7 | "sector-32g", 8 | "sector-64g", 9 | "small-deals", 10 | "short-precommit", 11 | "min-power-2k", 12 | ], 13 | ), 14 | ("butterflynet", &["sector-512m", "sector-32g", "sector-64g", "min-power-2g"]), 15 | ("calibrationnet", &["sector-32g", "sector-64g", "min-power-32g"]), 16 | ("devnet", &["sector-2k", "sector-8m", "small-deals", "short-precommit", "min-power-2k"]), 17 | ( 18 | "testing", 19 | &[ 20 | "sector-2k", 21 | "sector-8m", 22 | "sector-512m", 23 | "sector-32g", 24 | "sector-64g", 25 | "small-deals", 26 | "short-precommit", 27 | "min-power-2k", 28 | "no-provider-deal-collateral", 29 | ], 30 | ), 31 | ( 32 | "testing-fake-proofs", 33 | &[ 34 | "sector-2k", 35 | "sector-8m", 36 | "sector-512m", 37 | "sector-32g", 38 | "sector-64g", 39 | "small-deals", 40 | "short-precommit", 41 | "min-power-2k", 42 | "no-provider-deal-collateral", 43 | "fake-proofs", 44 | ], 45 | ), 46 | ]; 47 | const NETWORK_ENV: &str = "BUILD_FIL_NETWORK"; 48 | 49 | fn main() { 50 | let network = std::env::var(NETWORK_ENV).ok(); 51 | println!("cargo:rerun-if-env-changed={}", NETWORK_ENV); 52 | 53 | let network = network.as_deref().unwrap_or("mainnet"); 54 | let features = NETWORKS.iter().find(|(k, _)| k == &network).expect("unknown network").1; 55 | for feature in features { 56 | println!("cargo:rustc-cfg=feature=\"{}\"", feature); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /runtime/src/builtin/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | pub use self::network::*; 5 | pub use self::shared::*; 6 | pub use self::singletons::*; 7 | 8 | pub mod network; 9 | pub mod reward; 10 | pub mod shared; 11 | pub mod singletons; 12 | -------------------------------------------------------------------------------- /runtime/src/builtin/network.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | /// Assumed epoch duration. If this changes, a large state-migration will need to be run to update 5 | /// expirations, etc. 6 | pub const EPOCH_DURATION_SECONDS: i64 = 30; 7 | 8 | pub const SECONDS_IN_HOUR: i64 = 3600; 9 | pub const SECONDS_IN_DAY: i64 = 86400; 10 | pub const SECONDS_IN_YEAR: i64 = 31556925; 11 | pub const EPOCHS_IN_HOUR: i64 = SECONDS_IN_HOUR / EPOCH_DURATION_SECONDS; 12 | pub const EPOCHS_IN_DAY: i64 = SECONDS_IN_DAY / EPOCH_DURATION_SECONDS; 13 | pub const EPOCHS_IN_YEAR: i64 = SECONDS_IN_YEAR / EPOCH_DURATION_SECONDS; 14 | 15 | /// This is a protocol constant from Filecoin and depends on expected consensus. Here it is used to 16 | /// determine expected rewards, fault penalties, etc. This will need to be changed if expected 17 | /// consensus ever changes (and, likely, so will pledge, etc.). 18 | pub const EXPECTED_LEADERS_PER_EPOCH: u64 = 5; 19 | -------------------------------------------------------------------------------- /runtime/src/builtin/reward/math.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2023 Protocol Labs 2 | // Copyright 2019-2022 ChainSafe Systems 3 | // SPDX-License-Identifier: Apache-2.0, MIT 4 | 5 | use fvm_shared::bigint::{BigInt, ParseBigIntError}; 6 | 7 | pub const PRECISION: u64 = 128; 8 | 9 | /// polyval evaluates a polynomial given by coefficients `p` in Q.128 format 10 | /// at point `x` in Q.128 format. Output is in Q.128. 11 | /// Coefficients should be ordered from the highest order coefficient to the lowest. 12 | pub fn poly_val(poly: &[BigInt], x: &BigInt) -> BigInt { 13 | let mut res = BigInt::default(); 14 | 15 | for coeff in poly { 16 | res = ((res * x) >> PRECISION) + coeff; 17 | } 18 | res 19 | } 20 | 21 | pub fn poly_parse(coefs: &[&str]) -> Result, ParseBigIntError> { 22 | coefs.iter().map(|c| c.parse()).collect() 23 | } 24 | -------------------------------------------------------------------------------- /runtime/src/builtin/reward/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2023 Protocol Labs 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | use fvm_ipld_encoding::tuple::*; 4 | use fvm_shared::bigint::bigint_ser; 5 | use fvm_shared::sector::StoragePower; 6 | 7 | pub mod math; 8 | pub mod smooth; 9 | 10 | pub use smooth::FilterEstimate; 11 | 12 | #[derive(Clone, Debug, PartialEq, Eq, Serialize_tuple, Deserialize_tuple)] 13 | pub struct ThisEpochRewardReturn { 14 | // * Removed this_epoch_reward in v2 15 | pub this_epoch_reward_smoothed: FilterEstimate, 16 | #[serde(with = "bigint_ser")] 17 | pub this_epoch_baseline_power: StoragePower, 18 | } 19 | -------------------------------------------------------------------------------- /runtime/src/builtin/reward/smooth/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2023 Protocol Labs 2 | // Copyright 2019-2022 ChainSafe Systems 3 | // SPDX-License-Identifier: Apache-2.0, MIT 4 | 5 | mod alpha_beta_filter; 6 | mod smooth_func; 7 | 8 | pub use alpha_beta_filter::*; 9 | pub use smooth_func::*; 10 | -------------------------------------------------------------------------------- /runtime/src/builtin/singletons.rs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0, MIT 2 | 3 | use fvm_shared::ActorID; 4 | use fvm_shared::address::Address; 5 | 6 | /// Singleton Actor IDs 7 | pub const SYSTEM_ACTOR_ID: ActorID = 0; 8 | pub const INIT_ACTOR_ID: ActorID = 1; 9 | pub const REWARD_ACTOR_ID: ActorID = 2; 10 | pub const CRON_ACTOR_ID: ActorID = 3; 11 | pub const STORAGE_POWER_ACTOR_ID: ActorID = 4; 12 | pub const STORAGE_MARKET_ACTOR_ID: ActorID = 5; 13 | pub const VERIFIED_REGISTRY_ACTOR_ID: ActorID = 6; 14 | pub const DATACAP_TOKEN_ACTOR_ID: ActorID = 7; 15 | pub const EAM_ACTOR_ID: ActorID = 10; 16 | pub const BURNT_FUNDS_ACTOR_ID: ActorID = 99; 17 | 18 | /// Singleton Actor Addresses 19 | pub const SYSTEM_ACTOR_ADDR: Address = Address::new_id(SYSTEM_ACTOR_ID); 20 | pub const INIT_ACTOR_ADDR: Address = Address::new_id(INIT_ACTOR_ID); 21 | pub const REWARD_ACTOR_ADDR: Address = Address::new_id(REWARD_ACTOR_ID); 22 | pub const CRON_ACTOR_ADDR: Address = Address::new_id(CRON_ACTOR_ID); 23 | pub const STORAGE_POWER_ACTOR_ADDR: Address = Address::new_id(STORAGE_POWER_ACTOR_ID); 24 | pub const STORAGE_MARKET_ACTOR_ADDR: Address = Address::new_id(STORAGE_MARKET_ACTOR_ID); 25 | pub const VERIFIED_REGISTRY_ACTOR_ADDR: Address = Address::new_id(VERIFIED_REGISTRY_ACTOR_ID); 26 | pub const DATACAP_TOKEN_ACTOR_ADDR: Address = Address::new_id(DATACAP_TOKEN_ACTOR_ID); 27 | pub const EAM_ACTOR_ADDR: Address = Address::new_id(EAM_ACTOR_ID); 28 | pub const BURNT_FUNDS_ACTOR_ADDR: Address = Address::new_id(BURNT_FUNDS_ACTOR_ID); 29 | 30 | /// Defines first available ID address after builtin actors 31 | pub const FIRST_NON_SINGLETON_ADDR: ActorID = 100; 32 | -------------------------------------------------------------------------------- /runtime/src/runtime/actor_blockstore.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryFrom; 2 | 3 | use anyhow::Result; 4 | use cid::Cid; 5 | use fvm_ipld_blockstore::Block; 6 | use fvm_sdk as fvm; 7 | use multihash_codetable::Code; 8 | 9 | use crate::actor_error; 10 | 11 | /// A blockstore suitable for use within actors. 12 | /// 13 | /// Cloning simply clones a reference and does not copy the underlying blocks. 14 | #[derive(Debug, Clone)] 15 | pub struct ActorBlockstore; 16 | 17 | /// Implements a blockstore delegating to IPLD syscalls. 18 | impl fvm_ipld_blockstore::Blockstore for ActorBlockstore { 19 | fn get(&self, cid: &Cid) -> Result>> { 20 | // If this fails, the _CID_ is invalid. I.e., we have a bug. 21 | fvm::ipld::get(cid).map(Some).map_err(|c| { 22 | actor_error!(illegal_state; "get failed with {:?} on CID '{}'", c, cid).into() 23 | }) 24 | } 25 | 26 | fn put_keyed(&self, k: &Cid, block: &[u8]) -> Result<()> { 27 | let code = Code::try_from(k.hash().code()) 28 | .map_err(|e| actor_error!(serialization, e.to_string()))?; 29 | let k2 = self.put(code, &Block::new(k.codec(), block))?; 30 | if k != &k2 { 31 | Err(actor_error!(serialization; "put block with cid {} but has cid {}", k, k2).into()) 32 | } else { 33 | Ok(()) 34 | } 35 | } 36 | 37 | fn put(&self, code: Code, block: &Block) -> Result 38 | where 39 | D: AsRef<[u8]>, 40 | { 41 | // TODO: Don't hard-code the size. Unfortunately, there's no good way to get it from the 42 | // codec at the moment. 43 | const SIZE: u32 = 32; 44 | let k = fvm::ipld::put(code.into(), SIZE, block.codec, block.data.as_ref()) 45 | .map_err(|c| actor_error!(illegal_state; "put failed with {:?}", c))?; 46 | Ok(k) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /runtime/src/runtime/actor_code.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use fvm_ipld_blockstore::Blockstore; 5 | use fvm_ipld_encoding::ipld_block::IpldBlock; 6 | use fvm_shared::MethodNum; 7 | 8 | use crate::{ActorError, Runtime}; 9 | 10 | /// Interface for invoking methods on an Actor 11 | pub trait ActorCode { 12 | type Methods; 13 | /// A name for the actor type, used in debugging. 14 | fn name() -> &'static str; 15 | /// Invokes method with runtime on the actor's code. Method number will match one 16 | /// defined by the Actor, and parameters will be serialized and used in execution 17 | fn invoke_method( 18 | rt: &RT, 19 | method: MethodNum, 20 | params: Option, 21 | ) -> Result, ActorError> 22 | where 23 | // TODO: remove the clone requirement on the blockstore when we fix "replica update" to not 24 | // hold onto state between transactions. 25 | // https://github.com/filecoin-project/builtin-actors/issues/133 26 | RT: Runtime, 27 | RT::Blockstore: Blockstore + Clone; 28 | } 29 | -------------------------------------------------------------------------------- /runtime/src/runtime/builtins.rs: -------------------------------------------------------------------------------- 1 | pub use vm_api::builtin::Type; 2 | -------------------------------------------------------------------------------- /runtime/src/runtime/empty.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | use cid::Cid; 4 | use cid::multihash::Multihash; 5 | use fvm_ipld_encoding::DAG_CBOR; 6 | use fvm_shared::crypto::hash::SupportedHashes; 7 | 8 | const fn const_unwrap(r: Result) -> T { 9 | let v = match r { 10 | Ok(r) => r, 11 | Err(_) => panic!(), 12 | }; 13 | mem::forget(r); 14 | v 15 | } 16 | 17 | // 45b0cfc220ceec5b7c1c62c4d4193d38e4eba48e8815729ce75f9c0ab0e4c1c0 18 | const EMPTY_ARR_HASH_DIGEST: &[u8] = &[ 19 | 0x45, 0xb0, 0xcf, 0xc2, 0x20, 0xce, 0xec, 0x5b, 0x7c, 0x1c, 0x62, 0xc4, 0xd4, 0x19, 0x3d, 0x38, 20 | 0xe4, 0xeb, 0xa4, 0x8e, 0x88, 0x15, 0x72, 0x9c, 0xe7, 0x5f, 0x9c, 0x0a, 0xb0, 0xe4, 0xc1, 0xc0, 21 | ]; 22 | 23 | // bafy2bzacebc3bt6cedhoyw34drrmjvazhu4oj25er2ebk4u445pzycvq4ta4a 24 | pub const EMPTY_ARR_CID: Cid = Cid::new_v1( 25 | DAG_CBOR, 26 | const_unwrap(Multihash::wrap(SupportedHashes::Blake2b256 as u64, EMPTY_ARR_HASH_DIGEST)), 27 | ); 28 | 29 | #[test] 30 | fn test_empty_arr_cid() { 31 | use fvm_ipld_encoding::to_vec; 32 | use multihash_codetable::{Code, MultihashDigest}; 33 | 34 | let empty = to_vec::<[(); 0]>(&[]).unwrap(); 35 | let expected = Cid::new_v1(DAG_CBOR, Code::Blake2b256.digest(&empty)); 36 | assert_eq!(EMPTY_ARR_CID, expected); 37 | } 38 | -------------------------------------------------------------------------------- /runtime/src/runtime/hash_algorithm.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | // use fvm_ipld_hamt::{Hash, HashAlgorithm, HashedKey}; 5 | use fvm_ipld_hamt::{Hash, HashAlgorithm}; 6 | use fvm_sdk as fvm; 7 | use fvm_shared::crypto::hash::SupportedHashes; 8 | use std::hash::Hasher; 9 | 10 | pub type HashedKey = [u8; 32]; 11 | 12 | #[derive(Default)] 13 | pub struct RuntimeHasherWrapper(pub Vec); 14 | 15 | impl Hasher for RuntimeHasherWrapper { 16 | fn finish(&self) -> u64 { 17 | // u64 hash not used in hamt 18 | 0 19 | } 20 | 21 | fn write(&mut self, bytes: &[u8]) { 22 | self.0.extend_from_slice(bytes); 23 | } 24 | } 25 | 26 | #[derive(Default, Debug)] 27 | pub struct FvmHashSha256; 28 | 29 | impl HashAlgorithm for FvmHashSha256 { 30 | fn hash(key: &X) -> HashedKey 31 | where 32 | X: Hash + ?Sized, 33 | { 34 | let mut rval_digest: HashedKey = Default::default(); 35 | let mut hasher = RuntimeHasherWrapper::default(); 36 | key.hash(&mut hasher); 37 | 38 | fvm::crypto::hash_into(SupportedHashes::Sha2_256, &hasher.0, &mut rval_digest); 39 | 40 | rval_digest 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /runtime/src/util/cbor.rs: -------------------------------------------------------------------------------- 1 | use fvm_ipld_encoding::{RawBytes, to_vec}; 2 | use serde::{de, ser}; 3 | 4 | use crate::ActorError; 5 | 6 | /// Serializes a structure as a CBOR vector of bytes, returning a serialization error on failure. 7 | /// `desc` is a noun phrase for the object being serialized, included in any error message. 8 | pub fn serialize_vec(value: &T, desc: &str) -> Result, ActorError> 9 | where 10 | T: ser::Serialize + ?Sized, 11 | { 12 | to_vec(value) 13 | .map_err(|e| ActorError::serialization(format!("failed to serialize {}: {}", desc, e))) 14 | } 15 | 16 | /// Serializes a structure as CBOR bytes, returning a serialization error on failure. 17 | /// `desc` is a noun phrase for the object being serialized, included in any error message. 18 | pub fn serialize(value: &T, desc: &str) -> Result 19 | where 20 | T: ser::Serialize + ?Sized, 21 | { 22 | Ok(RawBytes::new(serialize_vec(value, desc)?)) 23 | } 24 | 25 | /// Deserialises CBOR-encoded bytes as a structure, returning a serialization error on failure. 26 | /// `desc` is a noun phrase for the object being deserialized, included in any error message. 27 | pub fn deserialize(v: &RawBytes, desc: &str) -> Result { 28 | v.deserialize() 29 | .map_err(|e| ActorError::serialization(format!("failed to deserialize {}: {}", desc, e))) 30 | } 31 | 32 | /// Deserialises CBOR-encoded bytes as a method parameters object. 33 | pub fn deserialize_params(params: &RawBytes) -> Result { 34 | deserialize(params, "method parameters") 35 | } 36 | -------------------------------------------------------------------------------- /runtime/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | pub use self::batch_return::*; 5 | pub use self::downcast::*; 6 | pub use self::events::*; 7 | pub use self::map::*; 8 | pub use self::mapmap::MapMap; 9 | pub use self::message_accumulator::MessageAccumulator; 10 | pub use self::multimap::*; 11 | pub use self::set::Set; 12 | pub use self::set_multimap::SetMultimap; 13 | pub use self::set_multimap::SetMultimapConfig; 14 | 15 | mod batch_return; 16 | pub mod cbor; 17 | mod downcast; 18 | mod events; 19 | mod map; 20 | mod mapmap; 21 | mod message_accumulator; 22 | mod multimap; 23 | mod set; 24 | mod set_multimap; 25 | -------------------------------------------------------------------------------- /runtime/src/util/set.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use cid::Cid; 5 | use fvm_ipld_blockstore::Blockstore; 6 | 7 | use crate::{ActorError, Config, Map2, MapKey}; 8 | 9 | /// Set is a HAMT with empty values. 10 | pub struct Set(Map2) 11 | where 12 | BS: Blockstore, 13 | K: MapKey; 14 | 15 | impl Set 16 | where 17 | BS: Blockstore, 18 | K: MapKey, 19 | { 20 | /// Initializes a new empty Set with the default bitwidth. 21 | pub fn empty(bs: BS, config: Config, name: &'static str) -> Self { 22 | Self(Map2::empty(bs, config, name)) 23 | } 24 | 25 | /// Initializes a Set from a root Cid. 26 | pub fn load( 27 | bs: BS, 28 | root: &Cid, 29 | config: Config, 30 | name: &'static str, 31 | ) -> Result { 32 | Ok(Self(Map2::load(bs, root, config, name)?)) 33 | } 34 | 35 | /// Retrieve root from the Set. 36 | #[inline] 37 | pub fn flush(&mut self) -> Result { 38 | self.0.flush() 39 | } 40 | 41 | /// Adds key to the set. 42 | #[inline] 43 | pub fn put(&mut self, key: &K) -> Result, ActorError> { 44 | self.0.set(key, ()) 45 | } 46 | 47 | /// Checks if key exists in the set. 48 | #[inline] 49 | pub fn has(&self, key: &K) -> Result { 50 | self.0.contains_key(key) 51 | } 52 | 53 | /// Deletes key from set. 54 | #[inline] 55 | pub fn delete(&mut self, key: &K) -> Result, ActorError> { 56 | self.0.delete(key) 57 | } 58 | 59 | /// Iterates through all keys in the set. 60 | pub fn for_each(&self, mut f: F) -> Result<(), ActorError> 61 | where 62 | F: FnMut(K) -> Result<(), ActorError>, 63 | { 64 | self.0.for_each(|s, _| f(s)) 65 | } 66 | 67 | /// Collects all keys from the set into a vector. 68 | pub fn collect_keys(&self) -> Result, ActorError> { 69 | let mut ret_keys = Vec::new(); 70 | self.for_each(|k| { 71 | ret_keys.push(k); 72 | Ok(()) 73 | })?; 74 | Ok(ret_keys) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /runtime/tests/multimap_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 5 | use fil_actors_runtime::{Multimap, parse_uint_key, u64_key}; 6 | use fvm_ipld_amt::Amt; 7 | use fvm_shared::HAMT_BIT_WIDTH; 8 | use fvm_shared::address::Address; 9 | 10 | #[test] 11 | fn basic_add() { 12 | let store = MemoryBlockstore::new(); 13 | let mut mm = Multimap::new(&store, HAMT_BIT_WIDTH, 3); 14 | 15 | let addr = Address::new_id(100); 16 | assert_eq!(mm.get::(&addr.to_bytes()).unwrap(), None); 17 | 18 | mm.add(addr.to_bytes().into(), 8).unwrap(); 19 | let arr: Amt = mm.get(&addr.to_bytes()).unwrap().unwrap(); 20 | assert_eq!(arr.get(0).unwrap(), Some(&8)); 21 | 22 | mm.add(addr.to_bytes().into(), 2).unwrap(); 23 | mm.add(addr.to_bytes().into(), 78).unwrap(); 24 | } 25 | 26 | #[test] 27 | fn for_each() { 28 | let store = MemoryBlockstore::new(); 29 | let mut mm = Multimap::new(&store, HAMT_BIT_WIDTH, 3); 30 | 31 | let addr = Address::new_id(100); 32 | assert_eq!(mm.get::(&addr.to_bytes()).unwrap(), None); 33 | 34 | mm.add(addr.to_bytes().into(), 8).unwrap(); 35 | mm.add(addr.to_bytes().into(), 2).unwrap(); 36 | mm.add(addr.to_bytes().into(), 3).unwrap(); 37 | mm.add("Some other string".into(), 7).unwrap(); 38 | 39 | let mut vals: Vec<(u64, u64)> = Vec::new(); 40 | mm.for_each(&addr.to_bytes(), |i, v| { 41 | vals.push((i, *v)); 42 | Ok(()) 43 | }) 44 | .unwrap(); 45 | 46 | assert_eq!(&vals, &[(0, 8), (1, 2), (2, 3)]) 47 | } 48 | 49 | #[test] 50 | fn remove_all() { 51 | let store = MemoryBlockstore::new(); 52 | let mut mm = Multimap::new(&store, HAMT_BIT_WIDTH, 3); 53 | 54 | let addr1 = Address::new_id(100); 55 | let addr2 = Address::new_id(101); 56 | 57 | mm.add(addr1.to_bytes().into(), 8).unwrap(); 58 | mm.add(addr1.to_bytes().into(), 88).unwrap(); 59 | mm.add(addr2.to_bytes().into(), 1).unwrap(); 60 | 61 | let arr: Amt = mm.get(&addr1.to_bytes()).unwrap().unwrap(); 62 | assert_eq!(arr.get(1).unwrap(), Some(&88)); 63 | 64 | mm.remove_all(&addr1.to_bytes()).unwrap(); 65 | assert_eq!(mm.get::(&addr1.to_bytes()).unwrap(), None); 66 | 67 | assert!(mm.get::(&addr2.to_bytes()).unwrap().is_some()); 68 | mm.remove_all(&addr2.to_bytes()).unwrap(); 69 | assert_eq!(mm.get::(&addr2.to_bytes()).unwrap(), None); 70 | } 71 | 72 | #[test] 73 | fn varint_key() { 74 | let k = u64_key(1); 75 | let out = parse_uint_key(&k).unwrap(); 76 | assert_eq!(1, out); 77 | } 78 | -------------------------------------------------------------------------------- /runtime/tests/set_multimap_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use fvm_shared::clock::ChainEpoch; 5 | 6 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 7 | use fil_actors_runtime::{DEFAULT_HAMT_CONFIG, SetMultimap, SetMultimapConfig}; 8 | 9 | pub const CONFIG: SetMultimapConfig = 10 | SetMultimapConfig { outer: DEFAULT_HAMT_CONFIG, inner: DEFAULT_HAMT_CONFIG }; 11 | 12 | #[test] 13 | fn put_remove() { 14 | let store = MemoryBlockstore::new(); 15 | let mut smm = SetMultimap::<_, ChainEpoch, u64>::empty(&store, CONFIG, "t"); 16 | 17 | let epoch: ChainEpoch = 100; 18 | assert!(smm.get(&epoch).unwrap().is_none()); 19 | 20 | smm.put(&epoch, 8).unwrap(); 21 | smm.put(&epoch, 2).unwrap(); 22 | smm.remove(&epoch, 2).unwrap(); 23 | 24 | let set = smm.get(&epoch).unwrap().unwrap(); 25 | assert!(set.has(&8).unwrap()); 26 | assert!(!set.has(&2).unwrap()); 27 | 28 | smm.remove_all(&epoch).unwrap(); 29 | assert!(smm.get(&epoch).unwrap().is_none()); 30 | } 31 | 32 | #[test] 33 | fn for_each() { 34 | let store = MemoryBlockstore::new(); 35 | let mut smm = SetMultimap::<_, ChainEpoch, u64>::empty(&store, CONFIG, "t"); 36 | 37 | let epoch: ChainEpoch = 100; 38 | assert!(smm.get(&epoch).unwrap().is_none()); 39 | 40 | smm.put(&epoch, 8).unwrap(); 41 | smm.put(&epoch, 3).unwrap(); 42 | smm.put(&epoch, 2).unwrap(); 43 | smm.put(&epoch, 8).unwrap(); 44 | 45 | let mut vals: Vec = Vec::new(); 46 | smm.for_each_in(&epoch, |i| { 47 | vals.push(i); 48 | Ok(()) 49 | }) 50 | .unwrap(); 51 | 52 | assert_eq!(vals.len(), 3); 53 | } 54 | -------------------------------------------------------------------------------- /runtime/tests/set_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2022 ChainSafe Systems 2 | // SPDX-License-Identifier: Apache-2.0, MIT 3 | 4 | use fil_actors_runtime::{DEFAULT_HAMT_CONFIG, Set}; 5 | 6 | #[test] 7 | fn put() { 8 | let store = fil_actors_runtime::test_blockstores::MemoryBlockstore::new(); 9 | let mut set = Set::empty(&store, DEFAULT_HAMT_CONFIG, "t"); 10 | 11 | let key: Vec = "test".into(); 12 | assert!(!set.has(&key).unwrap()); 13 | 14 | set.put(&key).unwrap(); 15 | assert!(set.has(&key).unwrap()); 16 | } 17 | 18 | #[test] 19 | fn collect_keys() { 20 | let store = fil_actors_runtime::test_blockstores::MemoryBlockstore::new(); 21 | let mut set = Set::<_, u64>::empty(&store, DEFAULT_HAMT_CONFIG, "t"); 22 | 23 | set.put(&0u64).unwrap(); 24 | 25 | assert_eq!(set.collect_keys().unwrap(), [0u64]); 26 | 27 | set.put(&1u64).unwrap(); 28 | set.put(&2u64).unwrap(); 29 | set.put(&3u64).unwrap(); 30 | 31 | assert_eq!(set.collect_keys().unwrap().len(), 4); 32 | } 33 | 34 | #[test] 35 | fn delete() { 36 | let store = fil_actors_runtime::test_blockstores::MemoryBlockstore::new(); 37 | let mut set = Set::empty(&store, DEFAULT_HAMT_CONFIG, "t"); 38 | 39 | let key = 0u64; 40 | 41 | assert!(!set.has(&key).unwrap()); 42 | set.put(&key).unwrap(); 43 | assert!(set.has(&key).unwrap()); 44 | set.delete(&key).unwrap(); 45 | assert!(!set.has(&key).unwrap()); 46 | 47 | // Test delete when doesn't exist doesn't error 48 | set.delete(&key).unwrap(); 49 | } 50 | -------------------------------------------------------------------------------- /runtime/tests/types_test.rs: -------------------------------------------------------------------------------- 1 | // Tests to match with Go github.com/filecoin-project/go-state-types/*/BatchReturn 2 | mod serialization { 3 | use hex_literal::hex; 4 | 5 | use fil_actors_runtime::{BatchReturn, BatchReturnGen}; 6 | use fvm_ipld_encoding::ipld_block::IpldBlock; 7 | use fvm_shared::error::ExitCode; 8 | 9 | #[test] 10 | fn batch_return() { 11 | let mut test_cases = vec![]; 12 | 13 | let mut batch = BatchReturnGen::new(0); 14 | test_cases.push(( 15 | batch.generate(), 16 | // [0,[]] 17 | &hex!("820080")[..], 18 | )); 19 | 20 | batch = BatchReturnGen::new(1); 21 | batch.add_success(); 22 | test_cases.push(( 23 | batch.generate(), 24 | // [1,[]] 25 | &hex!("820180"), 26 | )); 27 | 28 | batch = BatchReturnGen::new(1); 29 | batch.add_fail(ExitCode::USR_ILLEGAL_ARGUMENT); 30 | test_cases.push(( 31 | batch.generate(), 32 | // [0,[[0,16]]] 33 | &hex!("820081820010"), 34 | )); 35 | 36 | batch = BatchReturnGen::new(5); 37 | batch.add_success(); 38 | batch.add_fail(ExitCode::SYS_OUT_OF_GAS); 39 | batch.add_fail(ExitCode::USR_ILLEGAL_STATE); 40 | batch.add_success(); 41 | batch.add_fail(ExitCode::USR_ILLEGAL_ARGUMENT); 42 | 43 | test_cases.push(( 44 | batch.generate(), 45 | // [2,[[1,7],[2,20],[4,16]]] 46 | &hex!("820283820107820214820410"), 47 | )); 48 | 49 | for (params, expected_hex) in test_cases { 50 | let encoded = IpldBlock::serialize_cbor(¶ms).unwrap().unwrap(); 51 | assert_eq!(encoded.data, expected_hex); 52 | let decoded: BatchReturn = IpldBlock::deserialize(&encoded).unwrap(); 53 | assert_eq!(params, decoded); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.86.0" 3 | components = ["clippy", "llvm-tools-preview", "rustfmt"] 4 | targets = ["wasm32-unknown-unknown"] 5 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | use_small_heuristics = "Max" 2 | -------------------------------------------------------------------------------- /scripts/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ -n "$1" ]]; then 6 | SUFFIX="-$1" 7 | else 8 | SUFFIX="" 9 | fi 10 | 11 | make "bundle${SUFFIX}" 12 | install -o "$(stat -c '%u' /output)" -g "$(stat -c '%g' /output)" \ 13 | -m 0644 \ 14 | -t "/output" "output/builtin-actors${SUFFIX}.car" 15 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /// The bundled CAR embedded as a byte slice for easy consumption by Rust programs. 2 | /// 3 | /// The root CID of the CAR points to an actor index data structure. It is a 4 | /// CBOR-encoded IPLD Map, enumerating actor name and their 5 | /// respective CIDs. 6 | /// 7 | /// The actor names are values from this enumeration: 8 | /// 9 | /// - "account" 10 | /// - "cron" 11 | /// - "init" 12 | /// - "market" 13 | /// - "miner" 14 | /// - "multisig" 15 | /// - "paych" 16 | /// - "power" 17 | /// - "reward" 18 | /// - "system" 19 | /// - "verifreg" 20 | /// - "evm" 21 | /// - "eam" 22 | /// - "ethaccount" 23 | /// - "placeholder" 24 | /// 25 | /// The Filecoin client must import the contents of CAR into the blockstore, but 26 | /// may opt to exclude the index data structure. 27 | pub const BUNDLE_CAR: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/bundle/bundle.car")); 28 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use std::io::Write; 3 | 4 | use fil_builtin_actors_bundle::BUNDLE_CAR; 5 | 6 | #[derive(Parser)] 7 | #[clap(name = env!("CARGO_PKG_NAME"))] 8 | #[clap(version = env!("CARGO_PKG_VERSION"))] 9 | #[clap(about = "Writes a CAR file containing Wasm bytecode for Filecoin actors.", long_about = None)] 10 | struct Cli { 11 | /// The output car path. Defaults to STDOUT. 12 | #[clap(short, long, required = false)] 13 | output: Option, 14 | } 15 | 16 | fn main() -> Result<(), std::io::Error> { 17 | let cli = Cli::parse(); 18 | match cli.output { 19 | Some(path) => std::fs::write(path, BUNDLE_CAR), 20 | None => std::io::stdout().write_all(BUNDLE_CAR), 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /state/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fil_builtin_actors_state" 3 | description = "Builtin Actor state utils for Filecoin" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | repository.workspace = true 8 | authors = ["ChainSafe Systems ", "Protocol Labs", "Filecoin Core Devs"] 9 | keywords = ["filecoin", "web3", "wasm"] 10 | 11 | [lib] 12 | ## lib is necessary for integration tests 13 | ## cdylib is necessary for Wasm build 14 | crate-type = ["cdylib", "lib"] 15 | 16 | [dependencies] 17 | fil_actor_account = { workspace = true} 18 | fil_actor_verifreg = { workspace = true} 19 | fil_actor_datacap = { workspace = true} 20 | fil_actor_cron = { workspace = true} 21 | fil_actor_market = { workspace = true} 22 | fil_actor_multisig = { workspace = true} 23 | fil_actor_paych = { workspace = true} 24 | fil_actor_power = { workspace = true} 25 | fil_actor_miner = { workspace = true} 26 | fil_actor_reward = { workspace = true} 27 | fil_actor_system = { workspace = true} 28 | fil_actor_init = { workspace = true} 29 | fil_actors_runtime = { workspace = true} 30 | frc46_token = { workspace = true } 31 | fvm_shared = { workspace = true } 32 | fvm_ipld_encoding = { workspace = true } 33 | fvm_ipld_blockstore = { workspace = true } 34 | vm_api = { workspace = true } 35 | 36 | num-traits = { workspace = true } 37 | anyhow = { workspace = true } 38 | bimap = { workspace = true } 39 | num-derive = { workspace = true } 40 | serde = { workspace = true } 41 | cid = { workspace = true } 42 | 43 | [dev-dependencies] 44 | 45 | [features] 46 | fil-actor = ["fil_actors_runtime/fil-actor"] 47 | -------------------------------------------------------------------------------- /state/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod check; 2 | -------------------------------------------------------------------------------- /test_vm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test_vm" 3 | description = "Reference vm for integration testing builtin actors" 4 | version.workspace = true 5 | license.workspace = true 6 | edition.workspace = true 7 | authors = ["Protocol Labs", "Filecoin Core Devs"] 8 | keywords = ["filecoin", "web3", "wasm"] 9 | publish = false 10 | 11 | [lib] 12 | 13 | [dependencies] 14 | fil_builtin_actors_state = { workspace = true } 15 | fil_actors_runtime = { workspace = true, features = [ "test_utils" ] } 16 | fil_actor_init = { workspace = true } 17 | fil_actor_cron = { workspace = true } 18 | fil_actor_system = { workspace = true } 19 | fil_actor_account = { workspace = true } 20 | fil_actor_multisig = { workspace = true } 21 | fil_actor_paych = { workspace = true } 22 | fil_actor_reward = { workspace = true } 23 | fil_actor_power = { workspace = true } 24 | fil_actor_market = { workspace = true } 25 | fil_actor_verifreg = { workspace = true } 26 | fil_actor_miner = { workspace = true } 27 | fil_actor_datacap = { workspace = true } 28 | fil_actor_evm = { workspace = true } 29 | fil_actor_eam = { workspace = true } 30 | fil_actor_ethaccount = { workspace = true } 31 | fil_actors_evm_shared = { workspace = true } 32 | 33 | anyhow = { workspace = true } 34 | blake2b_simd = { workspace = true } 35 | cid = { workspace = true } 36 | fvm_ipld_blockstore = { workspace = true } 37 | fvm_ipld_encoding = { workspace = true } 38 | fvm_ipld_hamt = { workspace = true } 39 | fvm_shared = { workspace = true } 40 | integer-encoding = { workspace = true } 41 | num-traits = { workspace = true } 42 | serde = { workspace = true } 43 | vm_api = { workspace = true } 44 | multihash-codetable = { workspace = true } 45 | 46 | [dev-dependencies] 47 | test-case = { workspace = true } 48 | fil_actors_integration_tests = { workspace = true } 49 | -------------------------------------------------------------------------------- /test_vm/src/constants.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_runtime::FIRST_NON_SINGLETON_ADDR; 2 | use fvm_shared::{ActorID, address::Address}; 3 | 4 | // TODO: Deduplicate these constants which currently exist both here and in the integration_tests crate. 5 | // https://github.com/filecoin-project/builtin-actors/issues/1348 6 | 7 | // accounts for verifreg root signer and msig 8 | pub const VERIFREG_ROOT_KEY: &[u8] = &[200; fvm_shared::address::BLS_PUB_LEN]; 9 | pub const TEST_VERIFREG_ROOT_SIGNER_ADDR: Address = Address::new_id(FIRST_NON_SINGLETON_ADDR); 10 | pub const TEST_VERIFREG_ROOT_ADDR: Address = Address::new_id(FIRST_NON_SINGLETON_ADDR + 1); 11 | 12 | // account actor seeding funds created by new_with_singletons 13 | pub const FAUCET_ROOT_KEY: &[u8] = &[153; fvm_shared::address::BLS_PUB_LEN]; 14 | pub const TEST_FAUCET_ADDR: Address = Address::new_id(FIRST_NON_SINGLETON_ADDR + 2); 15 | pub const FIRST_TEST_USER_ADDR: ActorID = FIRST_NON_SINGLETON_ADDR + 3; 16 | 17 | // static values for predictable testing 18 | pub const TEST_VM_RAND_ARRAY: [u8; 32] = [ 19 | 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 20 | 26, 27, 28, 29, 30, 31, 32, 21 | ]; 22 | pub const TEST_VM_INVALID_POST: &str = "i_am_invalid_post"; 23 | -------------------------------------------------------------------------------- /test_vm/tests/README.md: -------------------------------------------------------------------------------- 1 | Put all tests in the `suite` directory and add them to the module. This way, they'll get compiled as one target which is _much_ faster. 2 | -------------------------------------------------------------------------------- /test_vm/tests/all_tests.rs: -------------------------------------------------------------------------------- 1 | mod suite; 2 | -------------------------------------------------------------------------------- /test_vm/tests/suite/authenticate_message_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::account_authenticate_message_test; 2 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 3 | use test_vm::TestVM; 4 | 5 | #[test] 6 | fn account_authenticate_message() { 7 | let store = MemoryBlockstore::new(); 8 | let v = TestVM::new_with_singletons(store); 9 | account_authenticate_message_test(&v); 10 | } 11 | -------------------------------------------------------------------------------- /test_vm/tests/suite/batch_onboarding.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::batch_onboarding_test; 2 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 3 | use test_vm::TestVM; 4 | 5 | // Test for batch pre-commit and aggregate prove-commit onboarding sectors (no deals). 6 | #[test] 7 | fn batch_onboarding() { 8 | let store = MemoryBlockstore::new(); 9 | let v = TestVM::new_with_singletons(store); 10 | 11 | batch_onboarding_test(&v); 12 | } 13 | -------------------------------------------------------------------------------- /test_vm/tests/suite/batch_onboarding_deals_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | batch_onboarding_deals_test, pre_commit_requires_commd_test, 3 | }; 4 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 5 | use test_vm::TestVM; 6 | 7 | #[test] 8 | fn batch_onboarding_deals() { 9 | let store = MemoryBlockstore::new(); 10 | let v = TestVM::new_with_singletons(store); 11 | batch_onboarding_deals_test(&v); 12 | } 13 | 14 | #[test] 15 | fn pre_commit_requires_commd() { 16 | let store = MemoryBlockstore::new(); 17 | let v = TestVM::new_with_singletons(store); 18 | pre_commit_requires_commd_test(&v); 19 | } 20 | -------------------------------------------------------------------------------- /test_vm/tests/suite/change_beneficiary_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | change_beneficiary_back_owner_success_test, change_beneficiary_fail_test, 3 | change_beneficiary_success_test, 4 | }; 5 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 6 | use test_vm::TestVM; 7 | 8 | #[test] 9 | fn change_beneficiary_success() { 10 | let store = MemoryBlockstore::new(); 11 | let v = TestVM::new_with_singletons(store); 12 | change_beneficiary_success_test(&v); 13 | } 14 | 15 | #[test] 16 | fn change_beneficiary_back_owner_success() { 17 | let store = MemoryBlockstore::new(); 18 | let v = TestVM::new_with_singletons(store); 19 | change_beneficiary_back_owner_success_test(&v); 20 | } 21 | 22 | #[test] 23 | fn change_beneficiary_fail() { 24 | let store = MemoryBlockstore::new(); 25 | let v = TestVM::new_with_singletons(store); 26 | change_beneficiary_fail_test(&v); 27 | } 28 | -------------------------------------------------------------------------------- /test_vm/tests/suite/change_owner_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | change_owner_fail_test, change_owner_success_test, keep_beneficiary_when_owner_changed_test, 3 | }; 4 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 5 | use test_vm::TestVM; 6 | 7 | #[test] 8 | fn change_owner_success() { 9 | let store = MemoryBlockstore::new(); 10 | let v = TestVM::new_with_singletons(store); 11 | change_owner_success_test(&v); 12 | } 13 | 14 | #[test] 15 | fn keep_beneficiary_when_owner_changed() { 16 | let store = MemoryBlockstore::new(); 17 | let v = TestVM::new_with_singletons(store); 18 | keep_beneficiary_when_owner_changed_test(&v); 19 | } 20 | 21 | #[test] 22 | fn change_owner_fail() { 23 | let store = MemoryBlockstore::new(); 24 | let v = TestVM::new_with_singletons(store); 25 | change_owner_fail_test(&v); 26 | } 27 | -------------------------------------------------------------------------------- /test_vm/tests/suite/commit_post_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | aggregate_bad_sector_number_test, aggregate_bad_sender_test, 3 | aggregate_one_precommit_expires_test, aggregate_size_limits_test, 4 | missed_first_post_deadline_test, overdue_precommit_test, skip_sector_test, 5 | submit_post_succeeds_test, 6 | }; 7 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 8 | use test_vm::TestVM; 9 | #[test] 10 | fn submit_post_succeeds() { 11 | let store = MemoryBlockstore::new(); 12 | let v = TestVM::new_with_singletons(store); 13 | submit_post_succeeds_test(&v); 14 | } 15 | 16 | #[test] 17 | fn skip_sector() { 18 | let store = MemoryBlockstore::new(); 19 | let v = TestVM::new_with_singletons(store); 20 | skip_sector_test(&v); 21 | } 22 | 23 | #[test] 24 | fn missed_first_post_deadline() { 25 | let store = MemoryBlockstore::new(); 26 | let v = TestVM::new_with_singletons(store); 27 | missed_first_post_deadline_test(&v); 28 | } 29 | 30 | #[test] 31 | fn overdue_precommit() { 32 | let store = MemoryBlockstore::new(); 33 | let v = TestVM::new_with_singletons(store); 34 | overdue_precommit_test(&v); 35 | } 36 | 37 | #[test] 38 | fn aggregate_bad_sector_number() { 39 | let store = MemoryBlockstore::new(); 40 | let v = TestVM::new_with_singletons(store); 41 | aggregate_bad_sector_number_test(&v); 42 | } 43 | 44 | #[test] 45 | fn aggregate_size_limits() { 46 | let store = MemoryBlockstore::new(); 47 | let v = TestVM::new_with_singletons(store); 48 | aggregate_size_limits_test(&v); 49 | } 50 | 51 | #[test] 52 | fn aggregate_bad_sender() { 53 | let store = MemoryBlockstore::new(); 54 | let v = TestVM::new_with_singletons(store); 55 | aggregate_bad_sender_test(&v); 56 | } 57 | 58 | #[test] 59 | fn aggregate_one_precommit_expires() { 60 | let store = MemoryBlockstore::new(); 61 | let v = TestVM::new_with_singletons(store); 62 | aggregate_one_precommit_expires_test(&v); 63 | } 64 | -------------------------------------------------------------------------------- /test_vm/tests/suite/datacap_tests.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{call_name_symbol_test, datacap_transfer_test}; 2 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 3 | use test_vm::TestVM; 4 | 5 | /* Mint a token for client and transfer it to a receiver, exercising error cases */ 6 | #[test] 7 | fn datacap_transfer() { 8 | let store = MemoryBlockstore::new(); 9 | let v = TestVM::new_with_singletons(store); 10 | datacap_transfer_test(&v); 11 | } 12 | 13 | /* Call name & symbol */ 14 | #[test] 15 | fn call_name_symbol() { 16 | let store = MemoryBlockstore::new(); 17 | let v = TestVM::new_with_singletons(store); 18 | call_name_symbol_test(&v); 19 | } 20 | -------------------------------------------------------------------------------- /test_vm/tests/suite/evm_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | evm_call_test, evm_constructor_delegatecall_regression_test, evm_create_test, 3 | evm_delegatecall_test, evm_empty_initcode_test, evm_eth_create_external_test, 4 | evm_init_revert_data_test, evm_staticcall_delegatecall_test, evm_staticcall_test, 5 | evm_transient_nested_test, evm_transient_reentry_test, 6 | }; 7 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 8 | use test_vm::TestVM; 9 | 10 | #[test] 11 | fn evm_call() { 12 | let store = MemoryBlockstore::new(); 13 | let v = TestVM::new_with_singletons(store); 14 | evm_call_test(&v); 15 | } 16 | 17 | #[test] 18 | fn evm_create() { 19 | let store = MemoryBlockstore::new(); 20 | let v = TestVM::new_with_singletons(store); 21 | evm_create_test(&v); 22 | } 23 | 24 | #[test] 25 | fn evm_eth_create_external() { 26 | let store = MemoryBlockstore::new(); 27 | let v = TestVM::new_with_singletons(store); 28 | evm_eth_create_external_test(&v); 29 | } 30 | 31 | #[test] 32 | fn evm_empty_initcode() { 33 | let store = MemoryBlockstore::new(); 34 | let v = TestVM::new_with_singletons(store); 35 | evm_empty_initcode_test(&v); 36 | } 37 | #[test] 38 | fn evm_staticcall() { 39 | let store = MemoryBlockstore::new(); 40 | let v = TestVM::new_with_singletons(store); 41 | evm_staticcall_test(&v); 42 | } 43 | 44 | #[test] 45 | fn evm_delegatecall() { 46 | let store = MemoryBlockstore::new(); 47 | let v = TestVM::new_with_singletons(store); 48 | evm_delegatecall_test(&v); 49 | } 50 | 51 | #[test] 52 | fn evm_staticcall_delegatecall() { 53 | let store = MemoryBlockstore::new(); 54 | let v = TestVM::new_with_singletons(store); 55 | evm_staticcall_delegatecall_test(&v); 56 | } 57 | 58 | #[test] 59 | fn evm_constructor_delegatecall_regression() { 60 | let store = MemoryBlockstore::new(); 61 | let v = TestVM::new_with_singletons(store); 62 | evm_constructor_delegatecall_regression_test(&v); 63 | } 64 | 65 | #[test] 66 | fn evm_init_revert_data() { 67 | let store = MemoryBlockstore::new(); 68 | let v = TestVM::new_with_singletons(store); 69 | evm_init_revert_data_test(&v); 70 | } 71 | 72 | #[test] 73 | fn evm_transient_nested() { 74 | let store = MemoryBlockstore::new(); 75 | let v = TestVM::new_with_singletons(store); 76 | evm_transient_nested_test(&v); 77 | } 78 | 79 | #[test] 80 | fn evm_transient_reentry() { 81 | let store = MemoryBlockstore::new(); 82 | let v = TestVM::new_with_singletons(store); 83 | evm_transient_reentry_test(&v); 84 | } 85 | -------------------------------------------------------------------------------- /test_vm/tests/suite/extend_sectors_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | commit_sector_with_max_duration_deal_test, extend_legacy_sector_with_deals_test, 3 | extend_sector_up_to_max_relative_extension_test, extend_updated_sector_with_claims_test, 4 | }; 5 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 6 | use test_vm::TestVM; 7 | 8 | #[test] 9 | fn extend_legacy_sector_with_deals() { 10 | let store = MemoryBlockstore::new(); 11 | let v = TestVM::new_with_singletons(store); 12 | extend_legacy_sector_with_deals_test(&v, false); 13 | } 14 | 15 | #[test] 16 | fn extend2_legacy_sector_with_deals() { 17 | let store = MemoryBlockstore::new(); 18 | let v = TestVM::new_with_singletons(store); 19 | extend_legacy_sector_with_deals_test(&v, true); 20 | } 21 | 22 | #[test] 23 | fn extend_updated_sector_with_claim() { 24 | let store = MemoryBlockstore::new(); 25 | let v = TestVM::new_with_singletons(store); 26 | extend_updated_sector_with_claims_test(&v); 27 | } 28 | 29 | #[test] 30 | fn extend_sector_up_to_max_relative_extension() { 31 | let store = MemoryBlockstore::new(); 32 | let v = TestVM::new_with_singletons(store); 33 | extend_sector_up_to_max_relative_extension_test(&v); 34 | } 35 | 36 | #[test] 37 | fn commit_sector_with_max_duration_deal() { 38 | let store = MemoryBlockstore::new(); 39 | let v = TestVM::new_with_singletons(store); 40 | commit_sector_with_max_duration_deal_test(&v); 41 | } 42 | -------------------------------------------------------------------------------- /test_vm/tests/suite/init_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::placeholder_deploy_test; 2 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 3 | use test_vm::TestVM; 4 | 5 | #[test] 6 | fn placeholder_deploy() { 7 | let store = MemoryBlockstore::new(); 8 | let v = TestVM::new_with_singletons(store); 9 | 10 | placeholder_deploy_test(&v); 11 | } 12 | -------------------------------------------------------------------------------- /test_vm/tests/suite/market_miner_withdrawal_test.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod market_tests { 3 | use fil_actors_integration_tests::tests::market_tests::*; 4 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 5 | use test_vm::TestVM; 6 | 7 | #[test] 8 | fn withdraw_all_funds() { 9 | let store = MemoryBlockstore::new(); 10 | let v = TestVM::new_with_singletons(store); 11 | withdraw_all_funds_test(&v); 12 | } 13 | 14 | #[test] 15 | fn withdraw_as_much_as_possible() { 16 | let store = MemoryBlockstore::new(); 17 | let v = TestVM::new_with_singletons(store); 18 | 19 | withdraw_as_much_as_possible_test(&v); 20 | } 21 | 22 | #[test] 23 | fn withdraw_0() { 24 | let store = MemoryBlockstore::new(); 25 | let v = TestVM::new_with_singletons(store); 26 | withdraw_0_test(&v); 27 | } 28 | } 29 | 30 | #[cfg(test)] 31 | mod miner_tests { 32 | use fil_actors_integration_tests::tests::miner_tests::*; 33 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 34 | use test_vm::TestVM; 35 | 36 | #[test] 37 | fn withdraw_all_funds() { 38 | let store = MemoryBlockstore::new(); 39 | let v = TestVM::new_with_singletons(store); 40 | 41 | withdraw_all_funds_test(&v); 42 | } 43 | 44 | #[test] 45 | fn withdraw_as_much_as_possible() { 46 | let store = MemoryBlockstore::new(); 47 | let v = TestVM::new_with_singletons(store); 48 | withdraw_as_much_as_possible_test(&v); 49 | } 50 | 51 | #[test] 52 | fn withdraw_0() { 53 | let store = MemoryBlockstore::new(); 54 | let v = TestVM::new_with_singletons(store); 55 | withdraw_0_test(&v); 56 | } 57 | 58 | #[test] 59 | fn withdraw_from_non_owner_address_fails() { 60 | let store = MemoryBlockstore::new(); 61 | let v = TestVM::new_with_singletons(store); 62 | withdraw_from_non_owner_address_fails_test(&v) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test_vm/tests/suite/mod.rs: -------------------------------------------------------------------------------- 1 | mod authenticate_message_test; 2 | mod batch_onboarding; 3 | mod batch_onboarding_deals_test; 4 | mod change_beneficiary_test; 5 | mod change_owner_test; 6 | mod commit_post_test; 7 | mod datacap_tests; 8 | mod evm_test; 9 | mod extend_sectors_test; 10 | mod init_test; 11 | mod market_miner_withdrawal_test; 12 | mod multisig_test; 13 | mod power_scenario_tests; 14 | mod prove_commit3_test; 15 | mod prove_commit_niporep_test; 16 | mod publish_deals_test; 17 | mod replica_update3_test; 18 | mod replica_update_test; 19 | mod terminate_test; 20 | mod test_vm_test; 21 | mod verified_claim_test; 22 | mod verifreg_remove_datacap_test; 23 | mod withdraw_balance_test; 24 | -------------------------------------------------------------------------------- /test_vm/tests/suite/move_partitions_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::move_partitions_test; 2 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 3 | use test_vm::TestVM; 4 | 5 | #[test] 6 | fn move_partitions() { 7 | let store = MemoryBlockstore::new(); 8 | let v = TestVM::new_with_singletons(store); 9 | move_partitions_test(&v); 10 | } 11 | -------------------------------------------------------------------------------- /test_vm/tests/suite/multisig_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | proposal_hash_test, swap_self_1_of_2_test, swap_self_2_of_3_test, test_delete_self_inner_test, 3 | }; 4 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 5 | use test_vm::TestVM; 6 | 7 | #[test] 8 | fn proposal_hash() { 9 | let store = MemoryBlockstore::new(); 10 | let v = TestVM::new_with_singletons(store); 11 | proposal_hash_test(&v); 12 | } 13 | 14 | #[test] 15 | fn test_delete_self() { 16 | let test = |threshold: usize, signers: u64, remove_idx: usize| { 17 | let store = MemoryBlockstore::new(); 18 | let v = TestVM::new_with_singletons(store); 19 | test_delete_self_inner_test(&v, signers, threshold, remove_idx); 20 | }; 21 | test(2, 3, 0); // 2 of 3 removed is proposer 22 | test(2, 3, 1); // 2 of 3 removed is approver 23 | test(2, 2, 0); // 2 of 2 removed is proposer 24 | test(1, 2, 0); // 1 of 2 25 | } 26 | 27 | #[test] 28 | fn swap_self_1_of_2() { 29 | let store = MemoryBlockstore::new(); 30 | let v = TestVM::new_with_singletons(store); 31 | swap_self_1_of_2_test(&v); 32 | } 33 | 34 | #[test] 35 | fn swap_self_2_of_3() { 36 | let store = MemoryBlockstore::new(); 37 | let v = TestVM::new_with_singletons(store); 38 | swap_self_2_of_3_test(&v); 39 | } 40 | -------------------------------------------------------------------------------- /test_vm/tests/suite/power_scenario_tests.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{cron_tick_test, power_create_miner_test}; 2 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 3 | use test_vm::TestVM; 4 | 5 | #[test] 6 | fn power_create_miner() { 7 | let store = MemoryBlockstore::new(); 8 | let v = TestVM::new_with_singletons(store); 9 | 10 | power_create_miner_test(&v); 11 | } 12 | 13 | #[test] 14 | fn cron_tick() { 15 | let store = MemoryBlockstore::new(); 16 | let v = TestVM::new_with_singletons(store); 17 | 18 | cron_tick_test(&v); 19 | } 20 | -------------------------------------------------------------------------------- /test_vm/tests/suite/prove_commit3_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::prove_commit_sectors2_test; 2 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 3 | use test_vm::TestVM; 4 | 5 | #[test] 6 | fn prove_commit_sectors2() { 7 | let store = MemoryBlockstore::new(); 8 | let v = TestVM::new_with_singletons(store); 9 | prove_commit_sectors2_test(&v); 10 | } 11 | -------------------------------------------------------------------------------- /test_vm/tests/suite/prove_commit_niporep_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | prove_commit_ni_next_deadline_post_required_test, 3 | prove_commit_ni_partial_success_not_required_test, prove_commit_ni_whole_success_test, 4 | }; 5 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 6 | use test_vm::TestVM; 7 | 8 | #[test] 9 | fn prove_commit_ni_whole_success() { 10 | let store = MemoryBlockstore::new(); 11 | let v = TestVM::new_with_singletons(store); 12 | prove_commit_ni_whole_success_test(&v); 13 | } 14 | 15 | #[test] 16 | fn prove_commit_ni_partial_success_not_required() { 17 | let store = MemoryBlockstore::new(); 18 | let v = TestVM::new_with_singletons(store); 19 | prove_commit_ni_partial_success_not_required_test(&v); 20 | } 21 | 22 | #[test] 23 | fn prove_commit_ni_next_deadline_post_required() { 24 | let store = MemoryBlockstore::new(); 25 | let v = TestVM::new_with_singletons(store); 26 | prove_commit_ni_next_deadline_post_required_test(&v); 27 | } 28 | -------------------------------------------------------------------------------- /test_vm/tests/suite/replica_update3_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::prove_replica_update2_test; 2 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 3 | use test_vm::TestVM; 4 | 5 | #[test] 6 | fn prove_replica_update2() { 7 | let store = MemoryBlockstore::new(); 8 | let v = TestVM::new_with_singletons(store); 9 | prove_replica_update2_test(&v); 10 | } 11 | -------------------------------------------------------------------------------- /test_vm/tests/suite/terminate_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::terminate_sectors_test; 2 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 3 | use test_vm::TestVM; 4 | 5 | #[test] 6 | fn terminate_sectors() { 7 | let store = MemoryBlockstore::new(); 8 | let v = TestVM::new_with_singletons(store); 9 | terminate_sectors_test(&v); 10 | } 11 | -------------------------------------------------------------------------------- /test_vm/tests/suite/verified_claim_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | deal_passes_claim_fails_test, expired_allocations_test, verified_claim_scenario_test, 3 | }; 4 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 5 | use test_vm::TestVM; 6 | 7 | #[test] 8 | fn verified_claim_scenario() { 9 | let store = MemoryBlockstore::new(); 10 | let v = TestVM::new_with_singletons(store); 11 | verified_claim_scenario_test(&v); 12 | } 13 | 14 | #[test] 15 | fn expired_allocations() { 16 | let store = MemoryBlockstore::new(); 17 | let v = TestVM::new_with_singletons(store); 18 | expired_allocations_test(&v); 19 | } 20 | 21 | #[test] 22 | fn deal_passes_claim_fails() { 23 | let store = MemoryBlockstore::new(); 24 | let v = TestVM::new_with_singletons(store); 25 | deal_passes_claim_fails_test(&v); 26 | } 27 | -------------------------------------------------------------------------------- /test_vm/tests/suite/verifreg_remove_datacap_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | remove_datacap_fails_on_verifreg_test, remove_datacap_simple_successful_path_test, 3 | }; 4 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 5 | use test_vm::TestVM; 6 | 7 | #[test] 8 | fn remove_datacap_simple_successful_path() { 9 | let store = MemoryBlockstore::new(); 10 | let v = TestVM::new_with_singletons(store); 11 | remove_datacap_simple_successful_path_test(&v); 12 | } 13 | 14 | #[test] 15 | fn remove_datacap_fails_on_verifreg() { 16 | let store = MemoryBlockstore::new(); 17 | let v = TestVM::new_with_singletons(store); 18 | remove_datacap_fails_on_verifreg_test(&v); 19 | } 20 | -------------------------------------------------------------------------------- /test_vm/tests/suite/withdraw_balance_test.rs: -------------------------------------------------------------------------------- 1 | use fil_actors_integration_tests::tests::{ 2 | withdraw_balance_fail_test, withdraw_balance_success_test, 3 | }; 4 | use fil_actors_runtime::test_blockstores::MemoryBlockstore; 5 | use test_vm::TestVM; 6 | #[test] 7 | fn withdraw_balance_success() { 8 | let store = MemoryBlockstore::new(); 9 | let v = TestVM::new_with_singletons(store); 10 | withdraw_balance_success_test(&v); 11 | } 12 | 13 | #[test] 14 | fn withdraw_balance_fail() { 15 | let store = MemoryBlockstore::new(); 16 | let v = TestVM::new_with_singletons(store); 17 | withdraw_balance_fail_test(&v); 18 | } 19 | -------------------------------------------------------------------------------- /vm_api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vm_api" 3 | description = "Abstract virtual machine interface used for testing FVM native wasm actors" 4 | version = "1.0.0" 5 | license = "MIT OR Apache-2.0" 6 | authors = ["Protocol Labs", "Filecoin Core Devs"] 7 | edition.workspace = true 8 | keywords = ["filecoin", "web3", "wasm"] 9 | publish = false 10 | 11 | [lib] 12 | 13 | [dependencies] 14 | anyhow = { workspace = true } 15 | cid = { workspace = true } 16 | fvm_ipld_blockstore = { workspace = true } 17 | fvm_ipld_encoding = { workspace = true } 18 | fvm_ipld_hamt = { workspace = true } 19 | fvm_shared = { workspace = true } 20 | num-derive = { workspace = true } 21 | num-traits = { workspace = true } 22 | rand = { workspace = true } 23 | rand_chacha = { workspace = true } 24 | serde = { workspace = true } 25 | 26 | multihash-codetable = { workspace = true } 27 | multihash-derive = { workspace = true, optional = true } 28 | 29 | [features] 30 | testing = ["multihash-derive"] 31 | -------------------------------------------------------------------------------- /vm_api/src/builtin.rs: -------------------------------------------------------------------------------- 1 | use num_derive::FromPrimitive; 2 | 3 | /// Identifies the builtin actor types for usage with the 4 | /// actor::resolve_builtin_actor_type syscall. 5 | /// Note that there is a mirror of this enum in the FVM SDK src/actors/builtins.rs. 6 | /// These must be kept in sync for the syscall to work correctly, without either side 7 | /// importing the other. 8 | #[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord, FromPrimitive, Debug)] 9 | #[repr(i32)] 10 | pub enum Type { 11 | System = 1, 12 | Init = 2, 13 | Cron = 3, 14 | Account = 4, 15 | Power = 5, 16 | Miner = 6, 17 | Market = 7, 18 | PaymentChannel = 8, 19 | Multisig = 9, 20 | Reward = 10, 21 | VerifiedRegistry = 11, 22 | DataCap = 12, 23 | Placeholder = 13, 24 | EVM = 14, 25 | EAM = 15, 26 | EthAccount = 16, 27 | } 28 | 29 | impl Type { 30 | pub fn name(&self) -> &'static str { 31 | match *self { 32 | Type::System => "system", 33 | Type::Init => "init", 34 | Type::Cron => "cron", 35 | Type::Account => "account", 36 | Type::Power => "storagepower", 37 | Type::Miner => "storageminer", 38 | Type::Market => "storagemarket", 39 | Type::PaymentChannel => "paymentchannel", 40 | Type::Multisig => "multisig", 41 | Type::Reward => "reward", 42 | Type::VerifiedRegistry => "verifiedregistry", 43 | Type::DataCap => "datacap", 44 | Type::Placeholder => "placeholder", 45 | Type::EVM => "evm", 46 | Type::EAM => "eam", 47 | Type::EthAccount => "ethaccount", 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /vm_api/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | #[derive(Debug)] 4 | pub struct VMError { 5 | msg: String, 6 | } 7 | 8 | impl fmt::Display for VMError { 9 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 10 | write!(f, "{}", self.msg) 11 | } 12 | } 13 | 14 | impl Error for VMError { 15 | fn description(&self) -> &str { 16 | &self.msg 17 | } 18 | } 19 | 20 | impl From for VMError { 21 | fn from(h_err: fvm_ipld_hamt::Error) -> Self { 22 | vm_err(h_err.to_string().as_str()) 23 | } 24 | } 25 | 26 | pub fn vm_err(msg: &str) -> VMError { 27 | VMError { msg: msg.to_string() } 28 | } 29 | -------------------------------------------------------------------------------- /vm_api/src/util/blockstore.rs: -------------------------------------------------------------------------------- 1 | use cid::Cid; 2 | use fvm_ipld_blockstore::Blockstore; 3 | 4 | /// A DynBlockstore is used to make the blockstore trait object consumable by functions that 5 | /// accept a generic BS: Blockstore parameter rather than a dyn Blockstore 6 | pub struct DynBlockstore<'bs>(&'bs dyn Blockstore); 7 | 8 | impl Blockstore for DynBlockstore<'_> { 9 | fn get(&self, k: &Cid) -> anyhow::Result>> { 10 | self.0.get(k) 11 | } 12 | 13 | fn put_keyed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { 14 | self.0.put_keyed(k, block) 15 | } 16 | } 17 | 18 | impl<'bs> DynBlockstore<'bs> { 19 | pub fn wrap(blockstore: &'bs dyn Blockstore) -> Self { 20 | Self(blockstore) 21 | } 22 | } 23 | --------------------------------------------------------------------------------