Created
October 31, 2022 16:31
-
-
Save Stebalien/084ff93dde46527da14a8afa395c1cfb to your computer and use it in GitHub Desktop.
Diff between next & master, after merge
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/.github/actions/rust-cargo-run/action.yml b/.github/actions/rust-cargo-run/action.yml | |
index ee2aa8cf..643b872d 100644 | |
--- a/.github/actions/rust-cargo-run/action.yml | |
+++ b/.github/actions/rust-cargo-run/action.yml | |
@@ -20,7 +20,7 @@ inputs: | |
cache_name: | |
description: The name of the cache to save/restore | |
required: true | |
- default: v2-test | |
+ default: test | |
runs: | |
using: composite | |
@@ -41,7 +41,7 @@ runs: | |
CACHE_SKIP_SAVE: ${{ inputs.save_cache == '' || inputs.save_cache == 'false' }} | |
with: | |
version: v0.2.15 | |
- shared-key: ${{ inputs.cache_name }} # change this to invalidate sccache for this job | |
+ shared-key: v4-${{ inputs.cache_name }} # change this to invalidate sccache for this job | |
- name: Running ${{ inputs.command }} | |
uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1.0.3 | |
env: | |
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml | |
index e36cb97a..f2774509 100644 | |
--- a/.github/workflows/ci.yml | |
+++ b/.github/workflows/ci.yml | |
@@ -4,6 +4,7 @@ on: | |
push: | |
branches: | |
- master | |
+ - next | |
pull_request: | |
env: | |
@@ -43,7 +44,7 @@ jobs: | |
runs-on: ubuntu-latest | |
strategy: | |
matrix: | |
- network: [ 'mainnet', 'caterpillarnet', 'butterflynet', 'calibrationnet', 'devnet', 'testing', 'testing-fake-proofs' ] | |
+ network: [ 'mainnet', 'caterpillarnet', 'butterflynet', 'calibrationnet', 'devnet', 'testing', 'testing-fake-proofs', 'wallaby', 'devnet-wasm' ] | |
steps: | |
- name: Checking out | |
uses: actions/checkout@v2 | |
@@ -57,6 +58,10 @@ jobs: | |
BUILD_FIL_NETWORK: ${{ matrix.network }} | |
run: | | |
cargo run --locked -- -o output/builtin-actors.car | |
+ - name: Checking no wasm-bindgen references | |
+ run: | | |
+ sudo apt-get update && sudo apt-get -y install wabt parallel | |
+ find ./target -name '*.wasm' -print0 | parallel -0 --halt now,fail=1 sh -c 'wasm2wat --enable-bulk-memory {} | grep bindgen; test $? -ne 0' | |
coverage: | |
runs-on: ubuntu-latest | |
env: | |
@@ -70,7 +75,7 @@ jobs: | |
command: version | |
components: llvm-tools-preview | |
github_token: ${{ secrets.GITHUB_TOKEN }} | |
- cache_name: v3-cov | |
+ cache_name: cov | |
save_cache: true | |
- name: Put LLVM tools into the PATH | |
run: echo "${HOME}/.rustup/toolchains/$(cat rust-toolchain)-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin" >> $GITHUB_PATH | |
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml | |
index 36326fcc..9b007046 100644 | |
--- a/.github/workflows/release.yml | |
+++ b/.github/workflows/release.yml | |
@@ -16,7 +16,7 @@ jobs: | |
CACHE_SKIP_SAVE: ${{ matrix.push == '' || matrix.push == 'false' }} | |
strategy: | |
matrix: | |
- network: [ 'mainnet', 'caterpillarnet', 'butterflynet', 'calibrationnet', 'devnet', 'testing', 'testing-fake-proofs' ] | |
+ network: [ 'mainnet', 'caterpillarnet', 'butterflynet', 'calibrationnet', 'devnet', 'testing', 'testing-fake-proofs', 'wallaby', 'devnet-wasm' ] | |
steps: | |
- name: Checking out | |
uses: actions/checkout@v2 | |
diff --git a/.gitignore b/.gitignore | |
index 609dd565..5b6079d6 100644 | |
--- a/.gitignore | |
+++ b/.gitignore | |
@@ -3,4 +3,4 @@ target | |
*.wasm | |
.idea/ | |
**/.DS_Store | |
-output/builtin-actors.car | |
+output/*.car | |
diff --git a/Cargo.toml b/Cargo.toml | |
index 3824cc6b..b4ae4c41 100644 | |
--- a/Cargo.toml | |
+++ b/Cargo.toml | |
@@ -14,6 +14,8 @@ publish = false | |
[target.'cfg(target_arch = "wasm32")'.dependencies] | |
fil_actor_account = { version = "10.0.0-alpha.1", path = "./actors/account", features = ["fil-actor"] } | |
+fil_actor_embryo = { version = "10.0.0-alpha.1", path = "./actors/embryo", features = ["fil-actor"] } | |
+fil_actor_evm = { version = "10.0.0-alpha.1", path = "./actors/evm", features = ["fil-actor"] } | |
fil_actor_cron = { version = "10.0.0-alpha.1", path = "./actors/cron", features = ["fil-actor"] } | |
fil_actor_datacap = { version = "10.0.0-alpha.1", path = "./actors/datacap", features = ["fil-actor"] } | |
fil_actor_init = { version = "10.0.0-alpha.1", path = "./actors/init", features = ["fil-actor"] } | |
@@ -27,7 +29,7 @@ fil_actor_system = { version = "10.0.0-alpha.1", path = "./actors/system", featu | |
fil_actor_verifreg = { version = "10.0.0-alpha.1", path = "./actors/verifreg", features = ["fil-actor"] } | |
[build-dependencies] | |
-fil_actor_bundler = "4.0.0" | |
+fil_actor_bundler = "4.1.0" | |
cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] } | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "runtime" } | |
num-traits = "0.2.15" | |
@@ -44,6 +46,7 @@ calibrationnet = [] | |
devnet = [] | |
testing = [] | |
testing-fake-proofs = [] | |
+m2-native = [] | |
[workspace] | |
members = [ | |
@@ -53,7 +56,11 @@ members = [ | |
"test_vm", | |
] | |
-#[patch.crates-io] | |
+[patch.crates-io] | |
+frc42_dispatch = { git = "https://github.com/filecoin-project/filecoin-actor-utils", branch = "feat/fvm-m2" } | |
+frc46_token = { git = "https://github.com/filecoin-project/filecoin-actor-utils", branch = "feat/fvm-m2" } | |
+fvm_actor_utils = { git = "https://github.com/filecoin-project/filecoin-actor-utils", branch = "feat/fvm-m2" } | |
+ | |
#fvm_shared = { git = "https://github.com/filecoin-project/ref-fvm" } | |
#fvm_sdk = { git = "https://github.com/filecoin-project/ref-fvm" } | |
#fvm_ipld_hamt = { git = "https://github.com/filecoin-project/ref-fvm" } | |
diff --git a/Makefile b/Makefile | |
index db5a24de..ee3907a1 100644 | |
--- a/Makefile | |
+++ b/Makefile | |
@@ -62,6 +62,12 @@ bundle-calibrationnet: deps-build | |
bundle-devnet: deps-build | |
BUILD_FIL_NETWORK=devnet cargo run -- -o output/builtin-actors-devnet.car | |
+bundle-wallaby: deps-build | |
+ BUILD_FIL_NETWORK=wallaby cargo run -- -o output/builtin-actors-wallaby.car | |
+ | |
+bundle-devnet-wasm: deps-build | |
+ BUILD_FIL_NETWORK=devnet-wasm cargo run -- -o output/builtin-actors-devnet-wasm.car | |
+ | |
bundle-testing: deps-build | |
BUILD_FIL_NETWORK=testing cargo run -- -o output/builtin-actors-testing.car | |
BUILD_FIL_NETWORK=testing-fake-proofs cargo run -- -o output/builtin-actors-testing-fake-proofs.car | |
diff --git a/actors/account/Cargo.toml b/actors/account/Cargo.toml | |
index 6ae98064..8973fe58 100644 | |
--- a/actors/account/Cargo.toml | |
+++ b/actors/account/Cargo.toml | |
@@ -15,12 +15,12 @@ crate-type = ["cdylib", "lib"] | |
[dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime" } | |
frc42_dispatch = "1.0.0" | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
serde = { version = "1.0.136", features = ["derive"] } | |
num-traits = "0.2.14" | |
num-derive = "0.3.3" | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
+fvm_ipld_encoding = "0.3.0" | |
anyhow = "1.0.65" | |
[dev-dependencies] | |
diff --git a/actors/cron/Cargo.toml b/actors/cron/Cargo.toml | |
index d1eb7b6d..4efe9455 100644 | |
--- a/actors/cron/Cargo.toml | |
+++ b/actors/cron/Cargo.toml | |
@@ -15,13 +15,13 @@ crate-type = ["cdylib", "lib"] | |
[dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime" } | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
num-traits = "0.2.14" | |
num-derive = "0.3.3" | |
log = "0.4.14" | |
serde = { version = "1.0.136", features = ["derive"] } | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
+fvm_ipld_encoding = "0.3.0" | |
[dev-dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime", features = ["test_utils", "sector-default"] } | |
diff --git a/actors/datacap/Cargo.toml b/actors/datacap/Cargo.toml | |
index ea8f2202..cf1eb3ad 100644 | |
--- a/actors/datacap/Cargo.toml | |
+++ b/actors/datacap/Cargo.toml | |
@@ -21,9 +21,9 @@ frc42_dispatch = "1.0.0" | |
frc46_token = "1.1.0" | |
fvm_actor_utils = "0.1.0" | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
-fvm_ipld_hamt = "0.5.1" | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
+fvm_ipld_encoding = "0.3.0" | |
+fvm_ipld_hamt = "0.6.0" | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
lazy_static = "1.4.0" | |
num-derive = "0.3.3" | |
num-traits = "0.2.14" | |
@@ -34,4 +34,3 @@ log = "0.4.14" | |
fil_actors_runtime = { path = "../../runtime", features = ["test_utils", "sector-default"] } | |
[features] | |
fil-actor = ["fil_actors_runtime/fil-actor"] | |
- | |
diff --git a/actors/embryo/Cargo.toml b/actors/embryo/Cargo.toml | |
new file mode 100644 | |
index 00000000..374dc940 | |
--- /dev/null | |
+++ b/actors/embryo/Cargo.toml | |
@@ -0,0 +1,20 @@ | |
+[package] | |
+name = "fil_actor_embryo" | |
+description = "Builtin embryo actor for Filecoin" | |
+version = "10.0.0-alpha.1" | |
+license = "MIT OR Apache-2.0" | |
+authors = ["Protocol Labs", "Filecoin Core Devs"] | |
+edition = "2021" | |
+keywords = ["filecoin", "web3", "wasm"] | |
+ | |
+[lib] | |
+## lib is necessary for integration tests | |
+## cdylib is necessary for Wasm build | |
+crate-type = ["cdylib", "lib"] | |
+ | |
+[dependencies] | |
+fvm_sdk = { version = "3.0.0-alpha.8", optional = true } | |
+fvm_shared = { version = "3.0.0-alpha.8", optional = true } | |
+ | |
+[features] | |
+fil-actor = ["fvm_sdk", "fvm_shared"] | |
diff --git a/actors/embryo/src/lib.rs b/actors/embryo/src/lib.rs | |
new file mode 100644 | |
index 00000000..d33f2bfd | |
--- /dev/null | |
+++ b/actors/embryo/src/lib.rs | |
@@ -0,0 +1,8 @@ | |
+#[cfg(feature = "fil-actor")] | |
+#[no_mangle] | |
+pub extern "C" fn invoke(_: u32) -> u32 { | |
+ fvm_sdk::vm::abort( | |
+ fvm_shared::error::ExitCode::USR_UNHANDLED_MESSAGE.value(), | |
+ Some("embryo actors may only receive messages on method 0"), | |
+ ) | |
+} | |
diff --git a/actors/init/Cargo.toml b/actors/init/Cargo.toml | |
index 5a316801..6a84116e 100644 | |
--- a/actors/init/Cargo.toml | |
+++ b/actors/init/Cargo.toml | |
@@ -15,8 +15,8 @@ crate-type = ["cdylib", "lib"] | |
[dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime" } | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
-fvm_ipld_hamt = "0.5.1" | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
+fvm_ipld_hamt = "0.6.0" | |
serde = { version = "1.0.136", features = ["derive"] } | |
num-traits = "0.2.14" | |
num-derive = "0.3.3" | |
@@ -24,10 +24,11 @@ cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] | |
anyhow = "1.0.65" | |
log = "0.4.14" | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
+fvm_ipld_encoding = "0.3.0" | |
[dev-dependencies] | |
-fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime", features = ["test_utils", "sector-default"] } | |
+fil_actors_runtime = { path = "../../runtime", features = ["test_utils", "sector-default"] } | |
[features] | |
fil-actor = ["fil_actors_runtime/fil-actor"] | |
+m2-native = ["fil_actors_runtime/m2-native"] | |
diff --git a/actors/init/src/lib.rs b/actors/init/src/lib.rs | |
index 63dab273..b0cf0355 100644 | |
--- a/actors/init/src/lib.rs | |
+++ b/actors/init/src/lib.rs | |
@@ -1,10 +1,13 @@ | |
// Copyright 2019-2022 ChainSafe Systems | |
// SPDX-License-Identifier: Apache-2.0, MIT | |
+use std::iter; | |
+ | |
use cid::Cid; | |
-use fil_actors_runtime::runtime::builtins::Type; | |
use fil_actors_runtime::runtime::{ActorCode, Runtime}; | |
-use fil_actors_runtime::{actor_error, cbor, ActorContext, ActorError, SYSTEM_ACTOR_ADDR}; | |
+use fil_actors_runtime::{ | |
+ actor_error, cbor, ActorContext, ActorError, EAM_ACTOR_ADDR, SYSTEM_ACTOR_ADDR, | |
+}; | |
use fvm_ipld_blockstore::Blockstore; | |
use fvm_ipld_encoding::RawBytes; | |
use fvm_shared::address::Address; | |
@@ -28,6 +31,9 @@ fil_actors_runtime::wasm_trampoline!(Actor); | |
pub enum Method { | |
Constructor = METHOD_CONSTRUCTOR, | |
Exec = 2, | |
+ Exec4 = 3, | |
+ #[cfg(feature = "m2-native")] | |
+ InstallCode = 4, | |
} | |
/// Init actor | |
@@ -80,14 +86,14 @@ impl Actor { | |
log::trace!("robust address: {:?}", &robust_address); | |
// Allocate an ID for this actor. | |
- // Store mapping of pubkey or actor address to actor ID | |
+ // Store mapping of actor addresses to the actor ID. | |
let id_address: ActorID = rt.transaction(|s: &mut State, rt| { | |
s.map_address_to_new_id(rt.store(), &robust_address) | |
.context("failed to allocate ID address") | |
})?; | |
// Create an empty actor | |
- rt.create_actor(params.code_cid, id_address)?; | |
+ rt.create_actor(params.code_cid, id_address, None)?; | |
// Invoke constructor | |
rt.send( | |
@@ -100,6 +106,99 @@ impl Actor { | |
Ok(ExecReturn { id_address: Address::new_id(id_address), robust_address }) | |
} | |
+ | |
+ /// Exec init actor | |
+ pub fn exec4<BS, RT>(rt: &mut RT, params: Exec4Params) -> Result<Exec4Return, ActorError> | |
+ where | |
+ BS: Blockstore, | |
+ RT: Runtime<BS>, | |
+ { | |
+ if cfg!(feature = "m2-native") { | |
+ rt.validate_immediate_caller_accept_any()?; | |
+ } else { | |
+ rt.validate_immediate_caller_is(iter::once(&EAM_ACTOR_ADDR))?; | |
+ } | |
+ | |
+ // Compute the f4 address. | |
+ let caller_id = rt.message().caller().id().unwrap(); | |
+ let delegated_address = | |
+ Address::new_delegated(caller_id, ¶ms.subaddress).map_err(|e| { | |
+ ActorError::illegal_argument(format!("invalid delegated address: {}", e)) | |
+ })?; | |
+ | |
+ log::trace!("delegated address: {:?}", &delegated_address); | |
+ | |
+ // Compute a re-org-stable address. | |
+ // This address exists for use by messages coming from outside the system, in order to | |
+ // stably address the newly created actor even if a chain re-org causes it to end up with | |
+ // a different ID. | |
+ let robust_address = rt.new_actor_address()?; | |
+ | |
+ log::trace!("robust address: {:?}", &robust_address); | |
+ | |
+ // Allocate an ID for this actor. | |
+ // Store mapping of actor addresses to the actor ID. | |
+ let id_address: ActorID = rt.transaction(|s: &mut State, rt| { | |
+ s.map_address_to_f4(rt.store(), &robust_address, &delegated_address) | |
+ .context("constructor failed") | |
+ })?; | |
+ | |
+ // Create an empty actor | |
+ rt.create_actor(params.code_cid, id_address, Some(delegated_address))?; | |
+ | |
+ // Invoke constructor | |
+ rt.send( | |
+ &Address::new_id(id_address), | |
+ METHOD_CONSTRUCTOR, | |
+ params.constructor_params, | |
+ rt.message().value_received(), | |
+ ) | |
+ .context("constructor failed")?; | |
+ | |
+ Ok(Exec4Return { id_address: Address::new_id(id_address), robust_address }) | |
+ } | |
+ | |
+ #[cfg(feature = "m2-native")] | |
+ pub fn install<BS, RT>(rt: &mut RT, params: InstallParams) -> Result<InstallReturn, ActorError> | |
+ where | |
+ BS: Blockstore, | |
+ RT: Runtime<BS>, | |
+ { | |
+ use cid::multihash::Code; | |
+ use fil_actors_runtime::AsActorError; | |
+ use fvm_ipld_blockstore::Block; | |
+ use fvm_shared::error::ExitCode; | |
+ | |
+ rt.validate_immediate_caller_accept_any()?; | |
+ | |
+ let (code_cid, installed) = rt.transaction(|st: &mut State, rt| { | |
+ let code = params.code.bytes(); | |
+ let code_cid = rt.store().put(Code::Blake2b256, &Block::new(0x55, code)).context_code( | |
+ ExitCode::USR_SERIALIZATION, | |
+ "failed to put code into the bockstore", | |
+ )?; | |
+ | |
+ if st.is_installed_actor(rt.store(), &code_cid).context_code( | |
+ ExitCode::USR_ILLEGAL_STATE, | |
+ "failed to check state for installed actor", | |
+ )? { | |
+ return Ok((code_cid, false)); | |
+ } | |
+ | |
+ rt.install_actor(&code_cid).context_code( | |
+ ExitCode::USR_ILLEGAL_ARGUMENT, | |
+ "failed to check state for installed actor", | |
+ )?; | |
+ | |
+ st.add_installed_actor(rt.store(), code_cid).context_code( | |
+ ExitCode::USR_ILLEGAL_STATE, | |
+ "failed to add installed actor to state", | |
+ )?; | |
+ Ok((code_cid, true)) | |
+ })?; | |
+ | |
+ Ok(InstallReturn { code_cid, installed }) | |
+ } | |
} | |
impl ActorCode for Actor { | |
@@ -121,16 +220,28 @@ impl ActorCode for Actor { | |
let res = Self::exec(rt, cbor::deserialize_params(params)?)?; | |
Ok(RawBytes::serialize(res)?) | |
} | |
+ Some(Method::Exec4) => { | |
+ let res = Self::exec4(rt, cbor::deserialize_params(params)?)?; | |
+ Ok(RawBytes::serialize(res)?) | |
+ } | |
+ #[cfg(feature = "m2-native")] | |
+ Some(Method::InstallCode) => { | |
+ let res = Self::install(rt, cbor::deserialize_params(params)?)?; | |
+ Ok(RawBytes::serialize(res)?) | |
+ } | |
None => Err(actor_error!(unhandled_message; "Invalid method")), | |
} | |
} | |
} | |
+#[cfg(not(feature = "m2-native"))] | |
fn can_exec<BS, RT>(rt: &RT, caller: &Cid, exec: &Cid) -> bool | |
where | |
BS: Blockstore, | |
RT: Runtime<BS>, | |
{ | |
+ use fil_actors_runtime::runtime::builtins::Type; | |
+ | |
rt.resolve_builtin_actor_type(exec) | |
.map(|typ| match typ { | |
Type::Multisig | Type::PaymentChannel => true, | |
@@ -139,3 +250,15 @@ where | |
}) | |
.unwrap_or(false) | |
} | |
+ | |
+#[cfg(feature = "m2-native")] | |
+fn can_exec<BS, RT>(_rt: &RT, _caller: &Cid, _exec: &Cid) -> bool | |
+where | |
+ BS: Blockstore, | |
+ RT: Runtime<BS>, | |
+{ | |
+ // TODO figure out ACLs -- m2-native allows exec for everyone for now | |
+ // maybe we should leave this as is for production, but at least we should | |
+ // consider adding relevant ACLs. | |
+ true | |
+} | |
diff --git a/actors/init/src/state.rs b/actors/init/src/state.rs | |
index 3829ca91..c93f4f1b 100644 | |
--- a/actors/init/src/state.rs | |
+++ b/actors/init/src/state.rs | |
@@ -1,6 +1,8 @@ | |
// Copyright 2019-2022 ChainSafe Systems | |
// SPDX-License-Identifier: Apache-2.0, MIT | |
+#[cfg(feature = "m2-native")] | |
+use cid::multihash::Code; | |
use cid::Cid; | |
use fil_actors_runtime::{ | |
actor_error, make_empty_map, make_map_with_root_and_bitwidth, ActorError, AsActorError, | |
@@ -9,6 +11,8 @@ use fil_actors_runtime::{ | |
use fvm_ipld_blockstore::Blockstore; | |
use fvm_ipld_encoding::tuple::*; | |
use fvm_ipld_encoding::Cbor; | |
+#[cfg(feature = "m2-native")] | |
+use fvm_ipld_encoding::CborStore; | |
use fvm_shared::address::{Address, Protocol}; | |
use fvm_shared::error::ExitCode; | |
use fvm_shared::{ActorID, HAMT_BIT_WIDTH}; | |
@@ -19,6 +23,8 @@ pub struct State { | |
pub address_map: Cid, | |
pub next_id: ActorID, | |
pub network_name: String, | |
+ #[cfg(feature = "m2-native")] | |
+ pub installed_actors: Cid, | |
} | |
impl State { | |
@@ -26,13 +32,25 @@ impl State { | |
let empty_map = make_empty_map::<_, ()>(store, HAMT_BIT_WIDTH) | |
.flush() | |
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to create empty map")?; | |
- Ok(Self { address_map: empty_map, next_id: FIRST_NON_SINGLETON_ADDR, network_name }) | |
+ #[cfg(feature = "m2-native")] | |
+ let installed_actors = store.put_cbor(&Vec::<Cid>::new(), Code::Blake2b256).context_code( | |
+ ExitCode::USR_ILLEGAL_STATE, | |
+ "failed to create installed actors object", | |
+ )?; | |
+ Ok(Self { | |
+ address_map: empty_map, | |
+ next_id: FIRST_NON_SINGLETON_ADDR, | |
+ network_name, | |
+ #[cfg(feature = "m2-native")] | |
+ installed_actors, | |
+ }) | |
} | |
/// Allocates a new ID address and stores a mapping of the argument address to it. | |
/// Fails if the argument address is already present in the map to facilitate a tombstone | |
/// for when the predictable robust address generation is implemented. | |
- /// Returns the newly-allocated address. | |
+ /// | |
+ /// Returns the newly-allocated actor ID. | |
pub fn map_address_to_new_id<BS: Blockstore>( | |
&mut self, | |
store: &BS, | |
@@ -61,6 +79,56 @@ impl State { | |
Ok(id) | |
} | |
+ /// Allocates a new ID address and stores a mapping of the argument addresses to it. | |
+ /// Returns the newly-allocated actor ID. | |
+ pub fn map_address_to_f4<BS: Blockstore>( | |
+ &mut self, | |
+ store: &BS, | |
+ addr: &Address, | |
+ f4addr: &Address, | |
+ ) -> Result<ActorID, ActorError> | |
+ where | |
+ BS: Blockstore, | |
+ { | |
+ let mut map = make_map_with_root_and_bitwidth(&self.address_map, store, HAMT_BIT_WIDTH) | |
+ .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load address map")?; | |
+ | |
+ // Assign a new ID address, or use the one currently mapped to the f4 address. We don't | |
+ // bother checking if the target actor is an embryo here, the FVM will check that when we go to create the actor. | |
+ let f4addr_key = f4addr.to_bytes().into(); | |
+ let id: u64 = match map | |
+ .get(&f4addr_key) | |
+ .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to lookup f4 address in map")? | |
+ { | |
+ Some(id) => *id, | |
+ None => { | |
+ let id = self.next_id; | |
+ self.next_id += 1; | |
+ map.set(f4addr_key, id) | |
+ .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to set f4 address in map")?; | |
+ id | |
+ } | |
+ }; | |
+ | |
+ // Then go ahead and assign the f2 address. | |
+ let is_new = map | |
+ .set_if_absent(addr.to_bytes().into(), id) | |
+ .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to set map key")?; | |
+ if !is_new { | |
+ // this is impossible today as the robust address is a hash of unique inputs | |
+ // but in close future predictable address generation will make this possible | |
+ return Err(actor_error!( | |
+ forbidden, | |
+ "robust address {} is already allocated in the address map", | |
+ addr | |
+ )); | |
+ } | |
+ self.address_map = | |
+ map.flush().context_code(ExitCode::USR_ILLEGAL_STATE, "failed to store address map")?; | |
+ | |
+ Ok(id) | |
+ } | |
+ | |
/// ResolveAddress resolves an address to an ID-address, if possible. | |
/// If the provided address is an ID address, it is returned as-is. | |
/// This means that mapped ID-addresses (which should only appear as values, not keys) and | |
@@ -88,6 +156,44 @@ impl State { | |
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to get address entry")?; | |
Ok(found.copied().map(Address::new_id)) | |
} | |
+ | |
+ /// Check to see if an actor is already installed | |
+ #[cfg(feature = "m2-native")] | |
+ pub fn is_installed_actor<BS: Blockstore>( | |
+ &self, | |
+ store: &BS, | |
+ cid: &Cid, | |
+ ) -> Result<bool, ActorError> { | |
+ let installed: Vec<Cid> = match store | |
+ .get_cbor(&self.installed_actors) | |
+ .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load installed actor list")? | |
+ { | |
+ Some(v) => v, | |
+ None => Vec::new(), | |
+ }; | |
+ Ok(installed.contains(cid)) | |
+ } | |
+ | |
+ /// Adds a new code Cid to the list of installed actors. | |
+ #[cfg(feature = "m2-native")] | |
+ pub fn add_installed_actor<BS: Blockstore>( | |
+ &mut self, | |
+ store: &BS, | |
+ cid: Cid, | |
+ ) -> Result<(), ActorError> { | |
+ let mut installed: Vec<Cid> = match store | |
+ .get_cbor(&self.installed_actors) | |
+ .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load installed actor list")? | |
+ { | |
+ Some(v) => v, | |
+ None => Vec::new(), | |
+ }; | |
+ installed.push(cid); | |
+ self.installed_actors = store | |
+ .put_cbor(&installed, Code::Blake2b256) | |
+ .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to save installed actor list")?; | |
+ Ok(()) | |
+ } | |
} | |
impl Cbor for State {} | |
diff --git a/actors/init/src/testing.rs b/actors/init/src/testing.rs | |
index 88c09459..9fc069c6 100644 | |
--- a/actors/init/src/testing.rs | |
+++ b/actors/init/src/testing.rs | |
@@ -29,7 +29,8 @@ pub fn check_state_invariants<BS: Blockstore>( | |
let mut init_summary = StateSummary { ids_by_address: HashMap::new(), next_id: state.next_id }; | |
- let mut address_by_id = HashMap::<ActorID, Address>::new(); | |
+ let mut stable_address_by_id = HashMap::<ActorID, Address>::new(); | |
+ let mut delegated_address_by_id = HashMap::<ActorID, Address>::new(); | |
match Map::<_, ActorID>::load(&state.address_map, store) { | |
Ok(address_map) => { | |
let ret = address_map.for_each(|key, actor_id| { | |
@@ -44,11 +45,29 @@ pub fn check_state_invariants<BS: Blockstore>( | |
format!("unexpected singleton ID value {actor_id}"), | |
); | |
- if let Some(duplicate) = address_by_id.insert(*actor_id, key_address) { | |
- acc.add(format!( | |
- "duplicate mapping to ID {actor_id}: {key_address} {duplicate}" | |
- )); | |
+ match key_address.protocol() { | |
+ Protocol::ID => { | |
+ acc.add(format!("key {key_address} is an ID address")); | |
+ } | |
+ Protocol::Delegated => { | |
+ if let Some(duplicate) = | |
+ delegated_address_by_id.insert(*actor_id, key_address) | |
+ { | |
+ acc.add(format!( | |
+ "duplicate mapping to ID {actor_id}: {key_address} {duplicate}" | |
+ )); | |
+ } | |
+ } | |
+ _ => { | |
+ if let Some(duplicate) = stable_address_by_id.insert(*actor_id, key_address) | |
+ { | |
+ acc.add(format!( | |
+ "duplicate mapping to ID {actor_id}: {key_address} {duplicate}" | |
+ )); | |
+ } | |
+ } | |
} | |
+ | |
init_summary.ids_by_address.insert(key_address, *actor_id); | |
Ok(()) | |
diff --git a/actors/init/src/types.rs b/actors/init/src/types.rs | |
index 2464d9e4..fe2afcb0 100644 | |
--- a/actors/init/src/types.rs | |
+++ b/actors/init/src/types.rs | |
@@ -20,7 +20,7 @@ pub struct ExecParams { | |
} | |
/// Init actor Exec Return value | |
-#[derive(Serialize_tuple, Deserialize_tuple)] | |
+#[derive(Debug, Serialize_tuple, Deserialize_tuple)] | |
pub struct ExecReturn { | |
/// ID based address for created actor | |
pub id_address: Address, | |
@@ -28,5 +28,37 @@ pub struct ExecReturn { | |
pub robust_address: Address, | |
} | |
+/// Init actor Exec4 Params | |
+#[derive(Serialize_tuple, Deserialize_tuple)] | |
+pub struct Exec4Params { | |
+ pub code_cid: Cid, | |
+ pub constructor_params: RawBytes, | |
+ pub subaddress: RawBytes, | |
+} | |
+ | |
+/// Init actor Exec4 Return value | |
+pub type Exec4Return = ExecReturn; | |
+ | |
impl Cbor for ExecReturn {} | |
impl Cbor for ExecParams {} | |
+impl Cbor for Exec4Params {} | |
+ | |
+/// Init actor Install Params | |
+#[cfg(feature = "m2-native")] | |
+#[derive(Serialize_tuple, Deserialize_tuple)] | |
+pub struct InstallParams { | |
+ pub code: RawBytes, | |
+} | |
+ | |
+/// Init actor Install Return value | |
+#[cfg(feature = "m2-native")] | |
+#[derive(Serialize_tuple, Deserialize_tuple)] | |
+pub struct InstallReturn { | |
+ pub code_cid: Cid, | |
+ pub installed: bool, | |
+} | |
+ | |
+#[cfg(feature = "m2-native")] | |
+impl Cbor for InstallParams {} | |
+#[cfg(feature = "m2-native")] | |
+impl Cbor for InstallReturn {} | |
diff --git a/actors/init/tests/init_actor_test.rs b/actors/init/tests/init_actor_test.rs | |
index b6999220..03e55809 100644 | |
--- a/actors/init/tests/init_actor_test.rs | |
+++ b/actors/init/tests/init_actor_test.rs | |
@@ -4,10 +4,11 @@ | |
use cid::Cid; | |
use fil_actor_init::testing::check_state_invariants; | |
use fil_actor_init::{ | |
- Actor as InitActor, ConstructorParams, ExecParams, ExecReturn, Method, State, | |
+ Actor as InitActor, ConstructorParams, Exec4Params, Exec4Return, ExecParams, ExecReturn, | |
+ Method, State, | |
}; | |
use fil_actors_runtime::runtime::Runtime; | |
-use fil_actors_runtime::test_utils::*; | |
+use fil_actors_runtime::{test_utils::*, EAM_ACTOR_ADDR, EAM_ACTOR_ID}; | |
use fil_actors_runtime::{ | |
ActorError, Multimap, FIRST_NON_SINGLETON_ADDR, STORAGE_POWER_ACTOR_ADDR, SYSTEM_ACTOR_ADDR, | |
}; | |
@@ -66,7 +67,7 @@ fn repeated_robust_address() { | |
// Next id | |
let expected_id = 100; | |
let expected_id_addr = Address::new_id(expected_id); | |
- rt.expect_create_actor(*MULTISIG_ACTOR_CODE_ID, expected_id); | |
+ rt.expect_create_actor(*MULTISIG_ACTOR_CODE_ID, expected_id, None); | |
// Expect a send to the multisig actor constructor | |
rt.expect_send( | |
@@ -80,7 +81,6 @@ fn repeated_robust_address() { | |
// Return should have been successful. Check the returned addresses | |
let exec_ret = exec_and_verify(&mut rt, *MULTISIG_ACTOR_CODE_ID, &fake_params).unwrap(); | |
- let exec_ret: ExecReturn = RawBytes::deserialize(&exec_ret).unwrap(); | |
assert_eq!(unique_address, exec_ret.robust_address, "Robust address does not macth"); | |
assert_eq!(expected_id_addr, exec_ret.id_address, "Id address does not match"); | |
check_state(&rt); | |
@@ -125,12 +125,12 @@ fn create_2_payment_channels() { | |
let expected_id = 100 + n; | |
let expected_id_addr = Address::new_id(expected_id); | |
- rt.expect_create_actor(*PAYCH_ACTOR_CODE_ID, expected_id); | |
+ rt.expect_create_actor(*PAYCH_ACTOR_CODE_ID, expected_id, None); | |
let fake_params = ConstructorParams { network_name: String::from("fake_param") }; | |
// expect anne creating a payment channel to trigger a send to the payment channels constructor | |
- let balance = TokenAmount::from_atto(100u8); | |
+ let balance = TokenAmount::from_atto(100); | |
rt.expect_send( | |
expected_id_addr, | |
@@ -142,7 +142,6 @@ fn create_2_payment_channels() { | |
); | |
let exec_ret = exec_and_verify(&mut rt, *PAYCH_ACTOR_CODE_ID, &fake_params).unwrap(); | |
- let exec_ret: ExecReturn = RawBytes::deserialize(&exec_ret).unwrap(); | |
assert_eq!(unique_address, exec_ret.robust_address, "Robust Address does not match"); | |
assert_eq!(expected_id_addr, exec_ret.id_address, "Id address does not match"); | |
@@ -170,7 +169,7 @@ fn create_storage_miner() { | |
let expected_id = 100; | |
let expected_id_addr = Address::new_id(expected_id); | |
- rt.expect_create_actor(*MINER_ACTOR_CODE_ID, expected_id); | |
+ rt.expect_create_actor(*MINER_ACTOR_CODE_ID, expected_id, None); | |
let fake_params = ConstructorParams { network_name: String::from("fake_param") }; | |
@@ -184,8 +183,6 @@ fn create_storage_miner() { | |
); | |
let exec_ret = exec_and_verify(&mut rt, *MINER_ACTOR_CODE_ID, &fake_params).unwrap(); | |
- | |
- let exec_ret: ExecReturn = RawBytes::deserialize(&exec_ret).unwrap(); | |
assert_eq!(unique_address, exec_ret.robust_address); | |
assert_eq!(expected_id_addr, exec_ret.id_address); | |
@@ -221,7 +218,7 @@ fn create_multisig_actor() { | |
// Next id | |
let expected_id = 100; | |
let expected_id_addr = Address::new_id(expected_id); | |
- rt.expect_create_actor(*MULTISIG_ACTOR_CODE_ID, expected_id); | |
+ rt.expect_create_actor(*MULTISIG_ACTOR_CODE_ID, expected_id, None); | |
let fake_params = ConstructorParams { network_name: String::from("fake_param") }; | |
// Expect a send to the multisig actor constructor | |
@@ -236,7 +233,6 @@ fn create_multisig_actor() { | |
// Return should have been successful. Check the returned addresses | |
let exec_ret = exec_and_verify(&mut rt, *MULTISIG_ACTOR_CODE_ID, &fake_params).unwrap(); | |
- let exec_ret: ExecReturn = RawBytes::deserialize(&exec_ret).unwrap(); | |
assert_eq!(unique_address, exec_ret.robust_address, "Robust address does not macth"); | |
assert_eq!(expected_id_addr, exec_ret.id_address, "Id address does not match"); | |
check_state(&rt); | |
@@ -257,7 +253,7 @@ fn sending_constructor_failure() { | |
// Create the next id address | |
let expected_id = 100; | |
let expected_id_addr = Address::new_id(expected_id); | |
- rt.expect_create_actor(*MINER_ACTOR_CODE_ID, expected_id); | |
+ rt.expect_create_actor(*MINER_ACTOR_CODE_ID, expected_id, None); | |
let fake_params = ConstructorParams { network_name: String::from("fake_param") }; | |
rt.expect_send( | |
@@ -287,6 +283,52 @@ fn sending_constructor_failure() { | |
check_state(&rt); | |
} | |
+#[test] | |
+fn call_exec4() { | |
+ let mut rt = construct_runtime(); | |
+ construct_and_verify(&mut rt); | |
+ | |
+ // Assign addresses | |
+ let unique_address = Address::new_actor(b"test"); | |
+ rt.new_actor_addr = Some(unique_address); | |
+ | |
+ // Make the f4 addr | |
+ let subaddr = b"foobar"; | |
+ let f4_addr = Address::new_delegated(EAM_ACTOR_ID, subaddr).unwrap(); | |
+ | |
+ // Next id | |
+ let expected_id = 100; | |
+ let expected_id_addr = Address::new_id(expected_id); | |
+ rt.expect_create_actor(*MULTISIG_ACTOR_CODE_ID, expected_id, Some(f4_addr)); | |
+ | |
+ let fake_params = ConstructorParams { network_name: String::from("fake_param") }; | |
+ // Expect a send to the multisig actor constructor | |
+ rt.expect_send( | |
+ expected_id_addr, | |
+ METHOD_CONSTRUCTOR, | |
+ RawBytes::serialize(&fake_params).unwrap(), | |
+ TokenAmount::zero(), | |
+ RawBytes::default(), | |
+ ExitCode::OK, | |
+ ); | |
+ | |
+ // Return should have been successful. Check the returned addresses | |
+ let exec_ret = | |
+ exec4_and_verify(&mut rt, subaddr, *MULTISIG_ACTOR_CODE_ID, &fake_params).unwrap(); | |
+ | |
+ assert_eq!(unique_address, exec_ret.robust_address, "Robust address does not macth"); | |
+ assert_eq!(expected_id_addr, exec_ret.id_address, "Id address does not match"); | |
+ | |
+ // Check that we assigned the right f4 address. | |
+ let init_state: State = rt.get_state(); | |
+ let resolved_id = init_state | |
+ .resolve_address(rt.store(), &f4_addr) | |
+ .ok() | |
+ .flatten() | |
+ .expect("failed to lookup f4 address"); | |
+ assert_eq!(expected_id_addr, resolved_id, "f4 address not assigned to the right actor"); | |
+} | |
+ | |
fn construct_and_verify(rt: &mut MockRuntime) { | |
rt.expect_validate_caller_addr(vec![SYSTEM_ACTOR_ADDR]); | |
let params = ConstructorParams { network_name: "mock".to_string() }; | |
@@ -312,7 +354,7 @@ fn exec_and_verify<S: Serialize>( | |
rt: &mut MockRuntime, | |
code_id: Cid, | |
params: &S, | |
-) -> Result<RawBytes, ActorError> | |
+) -> Result<ExecReturn, ActorError> | |
where | |
S: Serialize, | |
{ | |
@@ -325,5 +367,34 @@ where | |
rt.verify(); | |
check_state(rt); | |
- ret | |
+ ret.and_then(|v| v.deserialize().map_err(|e| e.into())) | |
+} | |
+ | |
+fn exec4_and_verify<S: Serialize>( | |
+ rt: &mut MockRuntime, | |
+ subaddr: &[u8], | |
+ code_id: Cid, | |
+ params: &S, | |
+) -> Result<Exec4Return, ActorError> | |
+where | |
+ S: Serialize, | |
+{ | |
+ rt.set_caller(*ACCOUNT_ACTOR_CODE_ID, EAM_ACTOR_ADDR); | |
+ if cfg!(feature = "m2-native") { | |
+ rt.expect_validate_caller_any(); | |
+ } else { | |
+ rt.expect_validate_caller_addr(vec![EAM_ACTOR_ADDR]); | |
+ } | |
+ let exec_params = Exec4Params { | |
+ code_cid: code_id, | |
+ constructor_params: RawBytes::serialize(params).unwrap(), | |
+ subaddress: subaddr.to_owned().into(), | |
+ }; | |
+ | |
+ let ret = | |
+ rt.call::<InitActor>(Method::Exec4 as u64, &RawBytes::serialize(&exec_params).unwrap()); | |
+ | |
+ rt.verify(); | |
+ check_state(rt); | |
+ ret.and_then(|v| v.deserialize().map_err(|e| e.into())) | |
} | |
diff --git a/actors/market/Cargo.toml b/actors/market/Cargo.toml | |
index 055540fc..3e81b95c 100644 | |
--- a/actors/market/Cargo.toml | |
+++ b/actors/market/Cargo.toml | |
@@ -19,11 +19,11 @@ fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime"} | |
anyhow = "1.0.65" | |
cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] } | |
frc46_token = "1.1.0" | |
-fvm_ipld_bitfield = "0.5.2" | |
+fvm_ipld_bitfield = "0.5.4" | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
-fvm_ipld_hamt = "0.5.1" | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
+fvm_ipld_encoding = "0.3.0" | |
+fvm_ipld_hamt = "0.6.0" | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
integer-encoding = { version = "3.0.3", default-features = false } | |
libipld-core = { version = "0.13.1", features = ["serde-codec"] } | |
log = "0.4.14" | |
@@ -36,7 +36,7 @@ fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime", featu | |
fil_actor_power = { path = "../power" } | |
fil_actor_reward = { path = "../reward" } | |
fil_actor_verifreg = { path = "../verifreg" } | |
-fvm_ipld_amt = { version = "0.4.2", features = ["go-interop"] } | |
+fvm_ipld_amt = { version = "0.5.0", features = ["go-interop"] } | |
multihash = { version = "0.16.1", default-features = false } | |
regex = "1" | |
itertools = "0.10" | |
diff --git a/actors/miner/Cargo.toml b/actors/miner/Cargo.toml | |
index 0abd4b82..baac65d0 100644 | |
--- a/actors/miner/Cargo.toml | |
+++ b/actors/miner/Cargo.toml | |
@@ -15,10 +15,10 @@ crate-type = ["cdylib", "lib"] | |
[dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime" } | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
-fvm_ipld_bitfield = "0.5.2" | |
-fvm_ipld_amt = { version = "0.4.2", features = ["go-interop"] } | |
-fvm_ipld_hamt = "0.5.1" | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
+fvm_ipld_bitfield = "0.5.4" | |
+fvm_ipld_amt = { version = "0.5.0", features = ["go-interop"] } | |
+fvm_ipld_hamt = "0.6.0" | |
serde = { version = "1.0.136", features = ["derive"] } | |
cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] } | |
num-traits = "0.2.14" | |
@@ -29,7 +29,7 @@ byteorder = "1.4.3" | |
anyhow = "1.0.65" | |
itertools = "0.10.3" | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
+fvm_ipld_encoding = "0.3.0" | |
multihash = { version = "0.16.2", default-features = false } | |
[dev-dependencies] | |
diff --git a/actors/miner/src/state.rs b/actors/miner/src/state.rs | |
index 40179270..e59aead7 100644 | |
--- a/actors/miner/src/state.rs | |
+++ b/actors/miner/src/state.rs | |
@@ -16,7 +16,7 @@ use fvm_ipld_amt::Error as AmtError; | |
use fvm_ipld_bitfield::BitField; | |
use fvm_ipld_blockstore::Blockstore; | |
use fvm_ipld_encoding::tuple::*; | |
-use fvm_ipld_encoding::{serde_bytes, BytesDe, Cbor, CborStore}; | |
+use fvm_ipld_encoding::{strict_bytes, BytesDe, Cbor, CborStore}; | |
use fvm_ipld_hamt::Error as HamtError; | |
use fvm_shared::address::Address; | |
@@ -1208,7 +1208,7 @@ pub struct AdvanceDeadlineResult { | |
} | |
/// Static information about miner | |
-#[derive(Debug, PartialEq, Serialize_tuple, Deserialize_tuple)] | |
+#[derive(Debug, Eq, PartialEq, Serialize_tuple, Deserialize_tuple)] | |
pub struct MinerInfo { | |
/// Account that owns this miner | |
/// - Income and returned collateral are paid to this address | |
@@ -1228,7 +1228,7 @@ pub struct MinerInfo { | |
pub pending_worker_key: Option<WorkerKeyChange>, | |
/// Libp2p identity that should be used when connecting to this miner | |
- #[serde(with = "serde_bytes")] | |
+ #[serde(with = "strict_bytes")] | |
pub peer_id: Vec<u8>, | |
/// Vector of byte arrays representing Libp2p multi-addresses used for establishing a connection with this miner. | |
diff --git a/actors/miner/tests/miner_actor_test_construction.rs b/actors/miner/tests/miner_actor_test_construction.rs | |
index 41f4a7b1..e34eb3c7 100644 | |
--- a/actors/miner/tests/miner_actor_test_construction.rs | |
+++ b/actors/miner/tests/miner_actor_test_construction.rs | |
@@ -46,7 +46,7 @@ fn prepare_env() -> TestEnv { | |
env.rt.actor_code_cids.insert(env.worker, *ACCOUNT_ACTOR_CODE_ID); | |
env.rt.actor_code_cids.insert(env.control_addrs[0], *ACCOUNT_ACTOR_CODE_ID); | |
env.rt.actor_code_cids.insert(env.control_addrs[1], *ACCOUNT_ACTOR_CODE_ID); | |
- env.rt.hash_func = Box::new(blake2b_256); | |
+ env.rt.hash_func = Box::new(hash); | |
env.rt.caller = INIT_ACTOR_ADDR; | |
env.rt.caller_type = *INIT_ACTOR_CODE_ID; | |
env | |
diff --git a/actors/miner/tests/util.rs b/actors/miner/tests/util.rs | |
index e5929b95..48861b90 100644 | |
--- a/actors/miner/tests/util.rs | |
+++ b/actors/miner/tests/util.rs | |
@@ -63,6 +63,7 @@ use fvm_shared::clock::QuantSpec; | |
use fvm_shared::clock::{ChainEpoch, NO_QUANTIZATION}; | |
use fvm_shared::commcid::{FIL_COMMITMENT_SEALED, FIL_COMMITMENT_UNSEALED}; | |
use fvm_shared::consensus::ConsensusFault; | |
+use fvm_shared::crypto::hash::SupportedHashes; | |
use fvm_shared::deal::DealID; | |
use fvm_shared::econ::TokenAmount; | |
use fvm_shared::error::ExitCode; | |
@@ -2877,14 +2878,14 @@ where | |
} | |
// Returns a fake hashing function that always arranges the first 8 bytes of the digest to be the binary | |
-// encoding of a target uint64. | |
-fn fixed_hasher(offset: ChainEpoch) -> Box<dyn Fn(&[u8]) -> [u8; 32]> { | |
- let hash = move |_: &[u8]| -> [u8; 32] { | |
- let mut result = [0u8; 32]; | |
+// encoding of a target uint64 and ignores the hash function. | |
+fn fixed_hasher(offset: ChainEpoch) -> Box<dyn Fn(SupportedHashes, &[u8]) -> ([u8; 64], usize)> { | |
+ let hash = move |_: SupportedHashes, _: &[u8]| -> ([u8; 64], usize) { | |
+ let mut result = [0u8; 64]; | |
for (i, item) in result.iter_mut().enumerate().take(8) { | |
*item = ((offset >> (8 * (7 - i))) & 0xff) as u8; | |
} | |
- result | |
+ (result, 32) | |
}; | |
Box::new(hash) | |
} | |
diff --git a/actors/multisig/Cargo.toml b/actors/multisig/Cargo.toml | |
index 9e1c2c0a..90858e82 100644 | |
--- a/actors/multisig/Cargo.toml | |
+++ b/actors/multisig/Cargo.toml | |
@@ -20,9 +20,9 @@ anyhow = "1.0.65" | |
cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] } | |
frc42_dispatch = "1.0.0" | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
-fvm_ipld_hamt = "0.5.1" | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
+fvm_ipld_encoding = "0.3.0" | |
+fvm_ipld_hamt = "0.6.0" | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
indexmap = { version = "1.8.0", features = ["serde-1"] } | |
integer-encoding = { version = "3.0.3", default-features = false } | |
num-derive = "0.3.3" | |
diff --git a/actors/multisig/src/types.rs b/actors/multisig/src/types.rs | |
index 51ed7899..a961de9f 100644 | |
--- a/actors/multisig/src/types.rs | |
+++ b/actors/multisig/src/types.rs | |
@@ -4,7 +4,7 @@ | |
use std::fmt::Display; | |
use fvm_ipld_encoding::tuple::*; | |
-use fvm_ipld_encoding::{serde_bytes, Cbor, RawBytes}; | |
+use fvm_ipld_encoding::{strict_bytes, Cbor, RawBytes}; | |
use fvm_ipld_hamt::BytesKey; | |
use fvm_shared::address::Address; | |
@@ -105,7 +105,7 @@ pub struct TxnIDParams { | |
pub id: TxnID, | |
/// Optional hash of proposal to ensure an operation can only apply to a | |
/// specific proposal. | |
- #[serde(with = "serde_bytes")] | |
+ #[serde(with = "strict_bytes")] | |
pub proposal_hash: Vec<u8>, | |
} | |
diff --git a/actors/paych/Cargo.toml b/actors/paych/Cargo.toml | |
index 6cd02512..958f89e5 100644 | |
--- a/actors/paych/Cargo.toml | |
+++ b/actors/paych/Cargo.toml | |
@@ -15,18 +15,18 @@ crate-type = ["cdylib", "lib"] | |
[dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime" } | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
num-traits = "0.2.14" | |
num-derive = "0.3.3" | |
serde = { version = "1.0.136", features = ["derive"] } | |
cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] } | |
anyhow = "1.0.65" | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
+fvm_ipld_encoding = "0.3.0" | |
[dev-dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime", features = ["test_utils", "sector-default"] } | |
-fvm_ipld_amt = { version = "0.4.2", features = ["go-interop"] } | |
+fvm_ipld_amt = { version = "0.5.0", features = ["go-interop"] } | |
derive_builder = "0.10.2" | |
[features] | |
diff --git a/actors/paych/src/types.rs b/actors/paych/src/types.rs | |
index f09d9e47..918468ee 100644 | |
--- a/actors/paych/src/types.rs | |
+++ b/actors/paych/src/types.rs | |
@@ -3,7 +3,7 @@ | |
use fil_actors_runtime::network::EPOCHS_IN_HOUR; | |
use fvm_ipld_encoding::tuple::*; | |
-use fvm_ipld_encoding::{serde_bytes, to_vec, Error, RawBytes}; | |
+use fvm_ipld_encoding::{strict_bytes, to_vec, Error, RawBytes}; | |
use fvm_shared::address::Address; | |
use fvm_shared::clock::ChainEpoch; | |
use fvm_shared::crypto::signature::Signature; | |
@@ -40,7 +40,7 @@ pub struct SignedVoucher { | |
/// set to 0 means no timeout | |
pub time_lock_max: ChainEpoch, | |
/// (optional) Used by `to` to validate | |
- #[serde(with = "serde_bytes")] | |
+ #[serde(with = "strict_bytes")] | |
pub secret_pre_image: Vec<u8>, | |
/// (optional) Specified by `from` to add a verification method to the voucher | |
pub extra: Option<ModVerifyParams>, | |
@@ -68,7 +68,7 @@ impl SignedVoucher { | |
pub channel_addr: &'a Address, | |
pub time_lock_min: ChainEpoch, | |
pub time_lock_max: ChainEpoch, | |
- #[serde(with = "serde_bytes")] | |
+ #[serde(with = "strict_bytes")] | |
pub secret_pre_image: &'a [u8], | |
pub extra: &'a Option<ModVerifyParams>, | |
pub lane: u64, | |
@@ -108,14 +108,14 @@ pub struct ModVerifyParams { | |
#[derive(Serialize_tuple, Deserialize_tuple)] | |
pub struct PaymentVerifyParams { | |
pub extra: RawBytes, | |
- #[serde(with = "serde_bytes")] | |
+ #[serde(with = "strict_bytes")] | |
pub proof: Vec<u8>, | |
} | |
#[derive(Serialize_tuple, Deserialize_tuple)] | |
pub struct UpdateChannelStateParams { | |
pub sv: SignedVoucher, | |
- #[serde(with = "serde_bytes")] | |
+ #[serde(with = "strict_bytes")] | |
pub secret: Vec<u8>, | |
// * proof removed in v2 | |
} | |
diff --git a/actors/power/Cargo.toml b/actors/power/Cargo.toml | |
index 471bb44c..4307af3f 100644 | |
--- a/actors/power/Cargo.toml | |
+++ b/actors/power/Cargo.toml | |
@@ -15,8 +15,8 @@ crate-type = ["cdylib", "lib"] | |
[dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime" } | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
-fvm_ipld_hamt = "0.5.1" | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
+fvm_ipld_hamt = "0.6.0" | |
num-traits = "0.2.14" | |
num-derive = "0.3.3" | |
log = "0.4.14" | |
@@ -27,7 +27,7 @@ lazy_static = "1.4.0" | |
serde = { version = "1.0.136", features = ["derive"] } | |
anyhow = "1.0.65" | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
+fvm_ipld_encoding = "0.3.0" | |
[dev-dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime", features = ["test_utils", "sector-default"] } | |
diff --git a/actors/power/src/ext.rs b/actors/power/src/ext.rs | |
index 91ab19ec..f650ba27 100644 | |
--- a/actors/power/src/ext.rs | |
+++ b/actors/power/src/ext.rs | |
@@ -1,6 +1,6 @@ | |
use cid::Cid; | |
use fvm_ipld_encoding::tuple::*; | |
-use fvm_ipld_encoding::{serde_bytes, BytesDe, RawBytes}; | |
+use fvm_ipld_encoding::{strict_bytes, BytesDe, RawBytes}; | |
use fvm_shared::address::Address; | |
use fvm_shared::bigint::bigint_ser; | |
use fvm_shared::sector::{RegisteredPoStProof, SectorNumber, StoragePower}; | |
@@ -51,14 +51,14 @@ pub mod miner { | |
pub worker: Address, | |
pub control_addresses: Vec<Address>, | |
pub window_post_proof_type: RegisteredPoStProof, | |
- #[serde(with = "serde_bytes")] | |
+ #[serde(with = "strict_bytes")] | |
pub peer_id: Vec<u8>, | |
pub multi_addresses: Vec<BytesDe>, | |
} | |
#[derive(Serialize_tuple, Deserialize_tuple)] | |
pub struct DeferredCronEventParams { | |
- #[serde(with = "serde_bytes")] | |
+ #[serde(with = "strict_bytes")] | |
pub event_payload: Vec<u8>, | |
pub reward_smoothed: FilterEstimate, | |
pub quality_adj_power_smoothed: FilterEstimate, | |
diff --git a/actors/power/src/types.rs b/actors/power/src/types.rs | |
index 521be8f8..74537f7a 100644 | |
--- a/actors/power/src/types.rs | |
+++ b/actors/power/src/types.rs | |
@@ -2,7 +2,7 @@ | |
// SPDX-License-Identifier: Apache-2.0, MIT | |
use fvm_ipld_encoding::tuple::*; | |
-use fvm_ipld_encoding::{serde_bytes, BytesDe, Cbor, RawBytes}; | |
+use fvm_ipld_encoding::{strict_bytes, BytesDe, Cbor, RawBytes}; | |
use fvm_shared::address::Address; | |
use fvm_shared::bigint::bigint_ser; | |
use fvm_shared::clock::ChainEpoch; | |
@@ -28,7 +28,7 @@ pub struct CreateMinerParams { | |
pub owner: Address, | |
pub worker: Address, | |
pub window_post_proof_type: RegisteredPoStProof, | |
- #[serde(with = "serde_bytes")] | |
+ #[serde(with = "strict_bytes")] | |
pub peer: Vec<u8>, | |
pub multiaddrs: Vec<BytesDe>, | |
} | |
diff --git a/actors/reward/Cargo.toml b/actors/reward/Cargo.toml | |
index 74d720db..5dd3d32c 100644 | |
--- a/actors/reward/Cargo.toml | |
+++ b/actors/reward/Cargo.toml | |
@@ -15,14 +15,14 @@ crate-type = ["cdylib", "lib"] | |
[dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime" } | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
num-traits = "0.2.14" | |
num-derive = "0.3.3" | |
log = "0.4.14" | |
lazy_static = "1.4.0" | |
serde = { version = "1.0.136", features = ["derive"] } | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
+fvm_ipld_encoding = "0.3.0" | |
[dev-dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime", features = ["test_utils", "sector-default"] } | |
diff --git a/actors/system/Cargo.toml b/actors/system/Cargo.toml | |
index 0613ee2e..9584a264 100644 | |
--- a/actors/system/Cargo.toml | |
+++ b/actors/system/Cargo.toml | |
@@ -15,8 +15,8 @@ crate-type = ["cdylib", "lib"] | |
[dependencies] | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../../runtime" } | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
-fvm_ipld_encoding = "0.2.2" | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
+fvm_ipld_encoding = "0.3.0" | |
fvm_ipld_blockstore = "0.1.1" | |
num-traits = "0.2.14" | |
anyhow = "1.0.65" | |
diff --git a/actors/verifreg/Cargo.toml b/actors/verifreg/Cargo.toml | |
index 6acde782..93e44d13 100644 | |
--- a/actors/verifreg/Cargo.toml | |
+++ b/actors/verifreg/Cargo.toml | |
@@ -21,9 +21,9 @@ cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] | |
frc42_dispatch = "1.0.0" | |
frc46_token = "1.1.0" | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
-fvm_ipld_hamt = "0.5.1" | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
+fvm_ipld_encoding = "0.3.0" | |
+fvm_ipld_hamt = "0.6.0" | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
lazy_static = "1.4.0" | |
log = "0.4.14" | |
num-derive = "0.3.3" | |
diff --git a/build.rs b/build.rs | |
index 056a0beb..d3f46b66 100644 | |
--- a/build.rs | |
+++ b/build.rs | |
@@ -26,6 +26,19 @@ const ACTORS: &[(&Package, &ID)] = &[ | |
("reward", "reward"), | |
("verifreg", "verifiedregistry"), | |
("datacap", "datacap"), | |
+ ("embryo", "embryo"), | |
+ ("evm", "evm"), | |
+ ("eam", "eam"), | |
+]; | |
+ | |
+/// Default Cargo features to activate during the build. | |
+const DEFAULT_CARGO_FEATURES: &[&str] = &["fil-actor"]; | |
+ | |
+/// Extra Cargo-level features to enable per network. | |
+const EXTRA_CARGO_FEATURES: &[(&str, &[&str])] = &[ | |
+ ("devnet-wasm", &["m2-native"]), | |
+ /*("devnet-evm", &["m2-fevm"]),*/ | |
+ ("wallaby", &["m2-native"]), | |
]; | |
const NETWORK_ENV: &str = "BUILD_FIL_NETWORK"; | |
@@ -44,6 +57,10 @@ fn network_name() -> String { | |
Some("calibrationnet") | |
} else if cfg!(feature = "devnet") { | |
Some("devnet") | |
+ } else if cfg!(feature = "devnet-wasm") { | |
+ Some("devnet-wasm") | |
+ } else if cfg!(feature = "wallaby") { | |
+ Some("wallaby") | |
} else if cfg!(feature = "testing") { | |
Some("testing") | |
} else if cfg!(feature = "testing-fake-proofs") { | |
@@ -103,6 +120,16 @@ fn main() -> Result<(), Box<dyn Error>> { | |
println!("cargo:rerun-if-changed={}", file); | |
} | |
+ // Compute Cargo features to apply. | |
+ let features = { | |
+ let extra = EXTRA_CARGO_FEATURES | |
+ .iter() | |
+ .find(|(k, _)| k == &network_name) | |
+ .map(|f| f.1) | |
+ .unwrap_or_default(); | |
+ [DEFAULT_CARGO_FEATURES, extra].concat() | |
+ }; | |
+ | |
// Cargo build command for all actors at once. | |
let mut cmd = Command::new(&cargo); | |
cmd.arg("build") | |
@@ -110,7 +137,7 @@ fn main() -> Result<(), Box<dyn Error>> { | |
.arg("--target=wasm32-unknown-unknown") | |
.arg("--profile=wasm") | |
.arg("--locked") | |
- .arg("--features=fil-actor") | |
+ .arg("--features=".to_owned() + &features.join(",")) | |
.arg("--manifest-path=".to_owned() + manifest_path.to_str().unwrap()) | |
.env(NETWORK_ENV, network_name) | |
.stdout(Stdio::piped()) | |
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml | |
index 47df4007..94b5405f 100644 | |
--- a/runtime/Cargo.toml | |
+++ b/runtime/Cargo.toml | |
@@ -8,47 +8,54 @@ edition = "2021" | |
repository = "https://github.com/filecoin-project/builtin-actors" | |
[dependencies] | |
-fvm_ipld_hamt = "0.5.1" | |
-fvm_ipld_amt = { version = "0.4.2", features = ["go-interop"] } | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
+fvm_ipld_hamt = "0.6.0" | |
+fvm_ipld_amt = { version = "0.5.0", features = ["go-interop"] } | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
num-traits = "0.2.14" | |
num-derive = "0.3.3" | |
serde = { version = "1.0.136", features = ["derive"] } | |
lazy_static = { version = "1.4.0", optional = true } | |
unsigned-varint = "0.7.1" | |
-integer-encoding = { version = "3.0.3", default-features = false } | |
byteorder = "1.4.3" | |
cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] } | |
-base64 = "0.13.0" | |
log = "0.4.14" | |
-indexmap = { version = "1.8.0", features = ["serde-1"] } | |
thiserror = "1.0.30" | |
-# enforce wasm compat | |
-getrandom = { version = "0.2.5", features = ["js"] } | |
-hex = { version = "0.4.3", optional = true } | |
-anyhow = "1.0.65" | |
-fvm_sdk = { version = "2.0.0-alpha.3", optional = true } | |
-blake2b_simd = "1.0" | |
+anyhow = "1.0.56" | |
fvm_ipld_blockstore = "0.1.1" | |
-fvm_ipld_encoding = "0.2.2" | |
-fvm_ipld_bitfield = "0.5.2" | |
+fvm_ipld_encoding = "0.3.0" | |
multihash = { version = "0.16.1", default-features = false } | |
-rand = "0.8.5" | |
serde_repr = "0.1.8" | |
regex = "1" | |
itertools = "0.10" | |
paste = "1.0.9" | |
-[dependencies.sha2] | |
-version = "0.10" | |
+# A fake-proofs dependency but... we can't select on that feature here because we enable it from | |
+# build.rs. | |
+sha2 = "0.10" | |
+ | |
+# fil-actor | |
+fvm_sdk = { version = "3.0.0-alpha.8", optional = true } | |
+ | |
+# test_util | |
+rand = { version = "0.8.5", default-features = false, optional = true } | |
+hex = { version = "0.4.3", optional = true } | |
+blake2b_simd = { version = "1.0", optional = true } | |
+ | |
+[dependencies.libsecp256k1] | |
+version = "0.7.1" | |
+default-features = false | |
+features = ["static-context", "std"] | |
+optional = true | |
[dev-dependencies] | |
derive_builder = "0.10.2" | |
hex = "0.4.3" | |
+rand = { version = "0.8.5" } | |
[features] | |
default = [] | |
fil-actor = ["fvm_sdk"] | |
+m2-native = ["fvm_sdk/m2-native"] | |
# Enable 2k sectors | |
sector-2k = [] | |
@@ -79,4 +86,4 @@ no-provider-deal-collateral = [] | |
# fake proofs (for testing) | |
fake-proofs = [] | |
-test_utils = ["hex", "multihash/sha2", "lazy_static"] | |
+test_utils = ["hex", "multihash/sha2", "libsecp256k1", "blake2b_simd", "rand", "rand/std_rng", "lazy_static"] | |
diff --git a/runtime/build.rs b/runtime/build.rs | |
index 767b810b..e2193242 100644 | |
--- a/runtime/build.rs | |
+++ b/runtime/build.rs | |
@@ -1,7 +1,7 @@ | |
-static NETWORKS: &[(&str, &[&str])] = &[ | |
- ("mainnet", &["sector-32g", "sector-64g"]), | |
+static NETWORKS: &[(&[&str], &[&str])] = &[ | |
+ (&["mainnet"], &["sector-32g", "sector-64g"]), | |
( | |
- "caterpillarnet", | |
+ &["caterpillarnet"], | |
&[ | |
"sector-512m", | |
"sector-32g", | |
@@ -11,11 +11,18 @@ static NETWORKS: &[(&str, &[&str])] = &[ | |
"min-power-2k", | |
], | |
), | |
- ("butterflynet", &["sector-512m", "sector-32g", "sector-64g", "min-power-2g"]), | |
- ("calibrationnet", &["sector-32g", "sector-64g", "min-power-32g"]), | |
- ("devnet", &["sector-2k", "sector-8m", "small-deals", "short-precommit", "min-power-2k"]), | |
+ (&["butterflynet"], &["sector-512m", "sector-32g", "sector-64g", "min-power-2g"]), | |
( | |
- "testing", | |
+ &["wallaby"], | |
+ &["sector-512m", "sector-32g", "sector-64g", "min-power-16g", "short-precommit"], | |
+ ), | |
+ (&["calibrationnet"], &["sector-32g", "sector-64g", "min-power-32g"]), | |
+ ( | |
+ &["devnet", "devnet-wasm" /*devnet-fevm*/], | |
+ &["sector-2k", "sector-8m", "small-deals", "short-precommit", "min-power-2k"], | |
+ ), | |
+ ( | |
+ &["testing"], | |
&[ | |
"sector-2k", | |
"sector-8m", | |
@@ -29,7 +36,7 @@ static NETWORKS: &[(&str, &[&str])] = &[ | |
], | |
), | |
( | |
- "testing-fake-proofs", | |
+ &["testing-fake-proofs"], | |
&[ | |
"sector-2k", | |
"sector-8m", | |
@@ -46,12 +53,22 @@ static NETWORKS: &[(&str, &[&str])] = &[ | |
]; | |
const NETWORK_ENV: &str = "BUILD_FIL_NETWORK"; | |
+/// This build script enables _local_ compile features. These features do not | |
+/// affect the dependency graph (they are not processed by Cargo). They are only | |
+/// in effect for conditional compilation _in this crate_. | |
+/// | |
+/// The reason we can't set these features as Cargo features from the root build | |
+/// is that this crate is only ever used as a _transitive_ dependency from actor | |
+/// crates. | |
+/// | |
+/// So the only two options are: (a) actors crates set the features when | |
+/// importing us as a dependency (super repetitive), or (b) this. | |
fn main() { | |
let network = std::env::var(NETWORK_ENV).ok(); | |
println!("cargo:rerun-if-env-changed={}", NETWORK_ENV); | |
let network = network.as_deref().unwrap_or("mainnet"); | |
- let features = NETWORKS.iter().find(|(k, _)| k == &network).expect("unknown network").1; | |
+ let features = NETWORKS.iter().find(|(k, _)| k.contains(&network)).expect("unknown network").1; | |
for feature in features { | |
println!("cargo:rustc-cfg=feature=\"{}\"", feature); | |
} | |
diff --git a/runtime/src/builtin/singletons.rs b/runtime/src/builtin/singletons.rs | |
index 458996b8..f02566ad 100644 | |
--- a/runtime/src/builtin/singletons.rs | |
+++ b/runtime/src/builtin/singletons.rs | |
@@ -25,6 +25,7 @@ define_singletons! { | |
STORAGE_MARKET_ACTOR = 5, | |
VERIFIED_REGISTRY_ACTOR = 6, | |
DATACAP_TOKEN_ACTOR = 7, | |
+ EAM_ACTOR = 10, | |
CHAOS_ACTOR = 98, | |
BURNT_FUNDS_ACTOR = 99, | |
} | |
diff --git a/runtime/src/runtime/builtins.rs b/runtime/src/runtime/builtins.rs | |
index abc97cd0..6aab3bc7 100644 | |
--- a/runtime/src/runtime/builtins.rs | |
+++ b/runtime/src/runtime/builtins.rs | |
@@ -20,6 +20,9 @@ pub enum Type { | |
Reward = 10, | |
VerifiedRegistry = 11, | |
DataCap = 12, | |
+ Embryo = 13, | |
+ EVM = 14, | |
+ EAM = 15, | |
} | |
impl Type { | |
@@ -37,6 +40,9 @@ impl Type { | |
Type::Reward => "reward", | |
Type::VerifiedRegistry => "verifiedregistry", | |
Type::DataCap => "datacap", | |
+ Type::Embryo => "embryo", | |
+ Type::EVM => "evm", | |
+ Type::EAM => "eam", | |
} | |
} | |
} | |
diff --git a/runtime/src/runtime/chainid.rs b/runtime/src/runtime/chainid.rs | |
new file mode 100644 | |
index 00000000..2237366b | |
--- /dev/null | |
+++ b/runtime/src/runtime/chainid.rs | |
@@ -0,0 +1,37 @@ | |
+#[cfg(feature = "mainnet")] | |
+pub const CHAINID: u64 = 314; | |
+ | |
+// TODO buildernet | |
+// #[cfg(feature = "buildernet")] | |
+// pub const CHAINID: u64 = 3141; | |
+ | |
+#[cfg(feature = "wallaby")] | |
+pub const CHAINID: u64 = 31415; | |
+ | |
+#[cfg(feature = "calibrationnet")] | |
+pub const CHAINID: u64 = 314159; | |
+ | |
+#[cfg(any(feature = "caterpillarnet", feature = "butterflynet"))] | |
+pub const CHAINID: u64 = 3141592; | |
+ | |
+#[cfg(any( | |
+ feature = "devnet", | |
+ feature = "devnet-wasm", | |
+ feature = "testing", | |
+ feature = "testing-fake-proofs", | |
+))] | |
+pub const CHAINID: u64 = 31415926; | |
+ | |
+// default build is same as a devnet | |
+#[cfg(not(any( | |
+ feature = "mainnet", | |
+ feature = "wallaby", | |
+ feature = "calibrationnet", | |
+ feature = "caterpillarnet", | |
+ feature = "butterflynet", | |
+ feature = "devnet", | |
+ feature = "devnet-wasm", | |
+ feature = "testing", | |
+ feature = "testing-fake-proofs", | |
+)))] | |
+pub const CHAINID: u64 = 31415926; | |
diff --git a/runtime/src/runtime/fvm.rs b/runtime/src/runtime/fvm.rs | |
index 4ab78a40..d7b7dadf 100644 | |
--- a/runtime/src/runtime/fvm.rs | |
+++ b/runtime/src/runtime/fvm.rs | |
@@ -5,9 +5,12 @@ use fvm_ipld_blockstore::Blockstore; | |
use fvm_ipld_encoding::{Cbor, CborStore, RawBytes, DAG_CBOR}; | |
use fvm_sdk as fvm; | |
use fvm_sdk::NO_DATA_BLOCK_ID; | |
-use fvm_shared::address::Address; | |
+use fvm_shared::address::{Address, Payload}; | |
use fvm_shared::clock::ChainEpoch; | |
-use fvm_shared::crypto::signature::Signature; | |
+use fvm_shared::crypto::hash::SupportedHashes; | |
+use fvm_shared::crypto::signature::{ | |
+ Signature, SECP_PUB_LEN, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE, | |
+}; | |
use fvm_shared::econ::TokenAmount; | |
use fvm_shared::error::{ErrorNumber, ExitCode}; | |
use fvm_shared::piece::PieceInfo; | |
@@ -30,8 +33,6 @@ use crate::runtime::{ | |
}; | |
use crate::{actor_error, ActorError, Runtime}; | |
-use super::EMPTY_ARR_CID; | |
- | |
/// A runtime that bridges to the FVM environment through the FVM SDK. | |
pub struct FvmRuntime<B = ActorBlockstore> { | |
blockstore: B, | |
@@ -80,6 +81,10 @@ impl MessageInfo for FvmMessage { | |
Address::new_id(fvm::message::caller()) | |
} | |
+ fn origin(&self) -> Address { | |
+ Address::new_id(fvm::message::origin()) | |
+ } | |
+ | |
fn receiver(&self) -> Address { | |
Address::new_id(fvm::message::receiver()) | |
} | |
@@ -87,6 +92,14 @@ impl MessageInfo for FvmMessage { | |
fn value_received(&self) -> TokenAmount { | |
fvm::message::value_received() | |
} | |
+ | |
+ fn gas_limit(&self) -> u64 { | |
+ fvm::message::gas_limit() | |
+ } | |
+ | |
+ fn gas_premium(&self) -> TokenAmount { | |
+ fvm::message::gas_premium() | |
+ } | |
} | |
impl<B> Runtime<B> for FvmRuntime<B> | |
@@ -127,6 +140,26 @@ where | |
} | |
} | |
+ fn validate_immediate_caller_namespace<I>(&mut self, addresses: I) -> Result<(), ActorError> | |
+ where | |
+ I: IntoIterator<Item = u64>, | |
+ { | |
+ self.assert_not_validated()?; | |
+ let caller_addr = self.message().caller(); | |
+ let caller_f4 = self.lookup_address(caller_addr.id().unwrap()).map(|a| *a.payload()); | |
+ if addresses | |
+ .into_iter() | |
+ .any(|a| matches!(caller_f4, Some(Payload::Delegated(d)) if d.namespace() == a)) | |
+ { | |
+ self.caller_validated = true; | |
+ Ok(()) | |
+ } else { | |
+ Err(actor_error!(forbidden; | |
+ "caller's namespace {} is not one of supported", caller_addr | |
+ )) | |
+ } | |
+ } | |
+ | |
fn validate_immediate_caller_type<'a, I>(&mut self, types: I) -> Result<(), ActorError> | |
where | |
I: IntoIterator<Item = &'a Type>, | |
@@ -152,10 +185,18 @@ where | |
fvm::sself::current_balance() | |
} | |
+ fn actor_balance(&self, id: ActorID) -> Option<TokenAmount> { | |
+ fvm::actor::balance_of(id) | |
+ } | |
+ | |
fn resolve_address(&self, address: &Address) -> Option<ActorID> { | |
fvm::actor::resolve_address(address) | |
} | |
+ fn lookup_address(&self, id: ActorID) -> Option<Address> { | |
+ fvm::actor::lookup_address(id) | |
+ } | |
+ | |
fn get_actor_code_cid(&self, id: &ActorID) -> Option<Cid> { | |
fvm::actor::get_actor_code_cid(&Address::new_id(*id)) | |
} | |
@@ -223,25 +264,12 @@ where | |
}) | |
} | |
- fn create<C: Cbor>(&mut self, obj: &C) -> Result<(), ActorError> { | |
- let root = fvm::sself::root()?; | |
- if root != EMPTY_ARR_CID { | |
- return Err( | |
- actor_error!(illegal_state; "failed to create state; expected empty array CID, got: {}", root), | |
- ); | |
- } | |
- let new_root = ActorBlockstore.put_cbor(obj, Code::Blake2b256) | |
- .map_err(|e| actor_error!(illegal_argument; "failed to write actor state during creation: {}", e.to_string()))?; | |
- fvm::sself::set_root(&new_root)?; | |
- Ok(()) | |
+ fn get_state_root(&self) -> Result<Cid, ActorError> { | |
+ Ok(fvm::sself::root()?) | |
} | |
- fn state<C: Cbor>(&self) -> Result<C, ActorError> { | |
- let root = fvm::sself::root()?; | |
- Ok(ActorBlockstore | |
- .get_cbor(&root) | |
- .map_err(|_| actor_error!(illegal_argument; "failed to get actor for Readonly state"))? | |
- .expect("State does not exist for actor state root")) | |
+ fn set_state_root(&mut self, root: &Cid) -> Result<(), ActorError> { | |
+ Ok(fvm::sself::set_root(root)?) | |
} | |
fn transaction<C, RT, F>(&mut self, f: F) -> Result<RT, ActorError> | |
@@ -343,16 +371,22 @@ where | |
Ok(fvm::actor::new_actor_address()) | |
} | |
- fn create_actor(&mut self, code_id: Cid, actor_id: ActorID) -> Result<(), ActorError> { | |
+ fn create_actor( | |
+ &mut self, | |
+ code_id: Cid, | |
+ actor_id: ActorID, | |
+ predictable_address: Option<Address>, | |
+ ) -> Result<(), ActorError> { | |
if self.in_transaction { | |
return Err( | |
actor_error!(assertion_failed; "create_actor is not allowed during transaction"), | |
); | |
} | |
- fvm::actor::create_actor(actor_id, &code_id).map_err(|e| match e { | |
+ fvm::actor::create_actor(actor_id, &code_id, predictable_address).map_err(|e| match e { | |
ErrorNumber::IllegalArgument => { | |
ActorError::illegal_argument("failed to create actor".into()) | |
} | |
+ ErrorNumber::Forbidden => ActorError::forbidden("actor already exists".into()), | |
_ => actor_error!(assertion_failed; "create failed with unknown error: {}", e), | |
}) | |
} | |
@@ -377,6 +411,18 @@ where | |
fn base_fee(&self) -> TokenAmount { | |
fvm::network::base_fee() | |
} | |
+ | |
+ fn gas_available(&self) -> u64 { | |
+ fvm::gas::available() | |
+ } | |
+ | |
+ fn tipset_timestamp(&self) -> u64 { | |
+ fvm::network::tipset_timestamp() | |
+ } | |
+ | |
+ fn tipset_cid(&self, epoch: i64) -> Option<Cid> { | |
+ fvm::network::tipset_cid(epoch).ok() | |
+ } | |
} | |
impl<B> Primitives for FvmRuntime<B> | |
@@ -409,6 +455,30 @@ where | |
fvm::crypto::compute_unsealed_sector_cid(proof_type, pieces) | |
.map_err(|e| anyhow!("failed to compute unsealed sector CID; exit code: {}", e)) | |
} | |
+ | |
+ #[cfg(feature = "m2-native")] | |
+ fn install_actor(&self, code_id: &Cid) -> Result<(), Error> { | |
+ fvm::actor::install_actor(code_id).map_err(|_| Error::msg("failed to install actor")) | |
+ } | |
+ | |
+ fn hash(&self, hasher: SupportedHashes, data: &[u8]) -> Vec<u8> { | |
+ fvm::crypto::hash_owned(hasher, data) | |
+ } | |
+ | |
+ fn hash_64(&self, hasher: SupportedHashes, data: &[u8]) -> ([u8; 64], usize) { | |
+ let mut buf = [0u8; 64]; | |
+ let len = fvm::crypto::hash_into(hasher, data, &mut buf); | |
+ (buf, len) | |
+ } | |
+ | |
+ fn recover_secp_public_key( | |
+ &self, | |
+ hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE], | |
+ signature: &[u8; SECP_SIG_LEN], | |
+ ) -> Result<[u8; SECP_PUB_LEN], anyhow::Error> { | |
+ fvm::crypto::recover_secp_public_key(hash, signature) | |
+ .map_err(|e| anyhow!("failed to recover pubkey; exit code: {}", e)) | |
+ } | |
} | |
#[cfg(not(feature = "fake-proofs"))] | |
diff --git a/runtime/src/runtime/hash_algorithm.rs b/runtime/src/runtime/hash_algorithm.rs | |
index 320938e0..2c1d8895 100644 | |
--- a/runtime/src/runtime/hash_algorithm.rs | |
+++ b/runtime/src/runtime/hash_algorithm.rs | |
@@ -35,12 +35,7 @@ impl HashAlgorithm for FvmHashSha256 { | |
let mut hasher = RuntimeHasherWrapper::default(); | |
key.hash(&mut hasher); | |
- // TODO :: Enable this when moving to | |
- // fvm_sdk 3.0.0-alpha.2, | |
- // looks like fvm_sdk 2.0.0-alpha.3 doesn't support `hash_into()` api | |
- // fvm::crypto::hash_into(SupportedHashes::Sha2_256, &hasher.0, &mut rval_digest); | |
- | |
- rval_digest.copy_from_slice(&fvm::crypto::hash(SupportedHashes::Sha2_256, &hasher.0)); | |
+ fvm::crypto::hash_into(SupportedHashes::Sha2_256, &hasher.0, &mut rval_digest); | |
rval_digest | |
} | |
diff --git a/runtime/src/runtime/mod.rs b/runtime/src/runtime/mod.rs | |
index b69c0b93..76157ca4 100644 | |
--- a/runtime/src/runtime/mod.rs | |
+++ b/runtime/src/runtime/mod.rs | |
@@ -3,11 +3,14 @@ | |
use cid::Cid; | |
use fvm_ipld_blockstore::Blockstore; | |
-use fvm_ipld_encoding::{Cbor, RawBytes}; | |
+use fvm_ipld_encoding::{Cbor, CborStore, RawBytes}; | |
use fvm_shared::address::Address; | |
use fvm_shared::clock::ChainEpoch; | |
use fvm_shared::consensus::ConsensusFault; | |
-use fvm_shared::crypto::signature::Signature; | |
+use fvm_shared::crypto::hash::SupportedHashes; | |
+use fvm_shared::crypto::signature::{ | |
+ Signature, SECP_PUB_LEN, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE, | |
+}; | |
use fvm_shared::econ::TokenAmount; | |
use fvm_shared::piece::PieceInfo; | |
use fvm_shared::randomness::RANDOMNESS_LENGTH; | |
@@ -17,15 +20,17 @@ use fvm_shared::sector::{ | |
}; | |
use fvm_shared::version::NetworkVersion; | |
use fvm_shared::{ActorID, MethodNum}; | |
+use multihash::Code; | |
pub use self::actor_code::*; | |
pub use self::policy::*; | |
pub use self::randomness::DomainSeparationTag; | |
use crate::runtime::builtins::Type; | |
-use crate::ActorError; | |
+use crate::{actor_error, ActorError}; | |
mod actor_code; | |
pub mod builtins; | |
+pub mod chainid; | |
pub mod policy; | |
mod randomness; | |
@@ -57,6 +62,14 @@ pub trait Runtime<BS: Blockstore>: Primitives + Verifier + RuntimePolicy { | |
fn validate_immediate_caller_is<'a, I>(&mut self, addresses: I) -> Result<(), ActorError> | |
where | |
I: IntoIterator<Item = &'a Address>; | |
+ /// Validates the caller is a member of a namespace. | |
+ /// Addresses must be of Protocol ID. | |
+ fn validate_immediate_caller_namespace<I>( | |
+ &mut self, | |
+ namespace_manager_addresses: I, | |
+ ) -> Result<(), ActorError> | |
+ where | |
+ I: IntoIterator<Item = u64>; | |
fn validate_immediate_caller_type<'a, I>(&mut self, types: I) -> Result<(), ActorError> | |
where | |
I: IntoIterator<Item = &'a Type>; | |
@@ -64,11 +77,18 @@ pub trait Runtime<BS: Blockstore>: Primitives + Verifier + RuntimePolicy { | |
/// The balance of the receiver. | |
fn current_balance(&self) -> TokenAmount; | |
+ /// The balance of an actor. | |
+ fn actor_balance(&self, id: ActorID) -> Option<TokenAmount>; | |
+ | |
/// Resolves an address of any protocol to an ID address (via the Init actor's table). | |
/// This allows resolution of externally-provided SECP, BLS, or actor addresses to the canonical form. | |
/// If the argument is an ID address it is returned directly. | |
fn resolve_address(&self, address: &Address) -> Option<ActorID>; | |
+ /// Looks-up the "predictable" address of an actor by ID, if any. Returns None if either the | |
+ /// target actor doesn't exist, or if the target actord doesn't have a predictable address. | |
+ fn lookup_address(&self, id: ActorID) -> Option<Address>; | |
+ | |
/// Look up the code ID at an actor address. | |
fn get_actor_code_cid(&self, id: &ActorID) -> Option<Cid>; | |
@@ -95,10 +115,33 @@ pub trait Runtime<BS: Blockstore>: Primitives + Verifier + RuntimePolicy { | |
/// Initializes the state object. | |
/// This is only valid when the state has not yet been initialized. | |
/// NOTE: we should also limit this to being invoked during the constructor method | |
- fn create<C: Cbor>(&mut self, obj: &C) -> Result<(), ActorError>; | |
+ fn create<C: Cbor>(&mut self, obj: &C) -> Result<(), ActorError> { | |
+ let root = self.get_state_root()?; | |
+ if root != EMPTY_ARR_CID { | |
+ return Err( | |
+ actor_error!(illegal_state; "failed to create state; expected empty array CID, got: {}", root), | |
+ ); | |
+ } | |
+ let new_root = self.store().put_cbor(obj, Code::Blake2b256) | |
+ .map_err(|e| actor_error!(illegal_argument; "failed to write actor state during creation: {}", e.to_string()))?; | |
+ self.set_state_root(&new_root)?; | |
+ Ok(()) | |
+ } | |
/// Loads a readonly copy of the state of the receiver into the argument. | |
- fn state<C: Cbor>(&self) -> Result<C, ActorError>; | |
+ fn state<C: Cbor>(&self) -> Result<C, ActorError> { | |
+ Ok(self | |
+ .store() | |
+ .get_cbor(&self.get_state_root()?) | |
+ .map_err(|_| actor_error!(illegal_argument; "failed to get actor for Readonly state"))? | |
+ .expect("State does not exist for actor state root")) | |
+ } | |
+ | |
+ /// Gets the state-root. | |
+ fn get_state_root(&self) -> Result<Cid, ActorError>; | |
+ | |
+ /// Sets the state-root. | |
+ fn set_state_root(&mut self, root: &Cid) -> Result<(), ActorError>; | |
/// Loads a mutable copy of the state of the receiver, passes it to `f`, | |
/// and after `f` completes puts the state object back to the store and sets it as | |
@@ -135,9 +178,14 @@ pub trait Runtime<BS: Blockstore>: Primitives + Verifier + RuntimePolicy { | |
/// Always an ActorExec address. | |
fn new_actor_address(&mut self) -> Result<Address, ActorError>; | |
- /// Creates an actor with code `codeID` and address `address`, with empty state. | |
+ /// Creates an actor with code `codeID`, an empty state, id `actor_id`, and an optional predictable address. | |
/// May only be called by Init actor. | |
- fn create_actor(&mut self, code_id: Cid, address: ActorID) -> Result<(), ActorError>; | |
+ fn create_actor( | |
+ &mut self, | |
+ code_id: Cid, | |
+ actor_id: ActorID, | |
+ predictable_address: Option<Address>, | |
+ ) -> Result<(), ActorError>; | |
/// Deletes the executing actor from the state tree, transferring any balance to beneficiary. | |
/// Aborts if the beneficiary does not exist. | |
@@ -165,7 +213,17 @@ pub trait Runtime<BS: Blockstore>: Primitives + Verifier + RuntimePolicy { | |
/// `name` provides information about gas charging point | |
fn charge_gas(&mut self, name: &'static str, compute: i64); | |
+ /// The current network base fee | |
fn base_fee(&self) -> TokenAmount; | |
+ | |
+ /// The gas still available for computation | |
+ fn gas_available(&self) -> u64; | |
+ | |
+ /// The current tipset's timestamp, as UNIX seconds | |
+ fn tipset_timestamp(&self) -> u64; | |
+ | |
+ /// The hash of on of the last 256 blocks | |
+ fn tipset_cid(&self, epoch: i64) -> Option<Cid>; | |
} | |
/// Message information available to the actor about executing message. | |
@@ -173,12 +231,21 @@ pub trait MessageInfo { | |
/// The address of the immediate calling actor. Always an ID-address. | |
fn caller(&self) -> Address; | |
+ /// The address of the origin of the current invocation. Always an ID-address | |
+ fn origin(&self) -> Address; | |
+ | |
/// The address of the actor receiving the message. Always an ID-address. | |
fn receiver(&self) -> Address; | |
/// The value attached to the message being processed, implicitly | |
/// added to current_balance() before method invocation. | |
fn value_received(&self) -> TokenAmount; | |
+ | |
+ /// The message gas limit | |
+ fn gas_limit(&self) -> u64; | |
+ | |
+ /// The message gas premium | |
+ fn gas_premium(&self) -> TokenAmount; | |
} | |
/// Pure functions implemented as primitives by the runtime. | |
@@ -186,6 +253,12 @@ pub trait Primitives { | |
/// Hashes input data using blake2b with 256 bit output. | |
fn hash_blake2b(&self, data: &[u8]) -> [u8; 32]; | |
+ /// Hashes input data using a supported hash function. | |
+ fn hash(&self, hasher: SupportedHashes, data: &[u8]) -> Vec<u8>; | |
+ | |
+ /// Hashes input into a 64 byte buffer | |
+ fn hash_64(&self, hasher: SupportedHashes, data: &[u8]) -> ([u8; 64], usize); | |
+ | |
/// Computes an unsealed sector CID (CommD) from its constituent piece CIDs (CommPs) and sizes. | |
fn compute_unsealed_sector_cid( | |
&self, | |
@@ -200,6 +273,15 @@ pub trait Primitives { | |
signer: &Address, | |
plaintext: &[u8], | |
) -> Result<(), anyhow::Error>; | |
+ | |
+ fn recover_secp_public_key( | |
+ &self, | |
+ hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE], | |
+ signature: &[u8; SECP_SIG_LEN], | |
+ ) -> Result<[u8; SECP_PUB_LEN], anyhow::Error>; | |
+ | |
+ #[cfg(feature = "m2-native")] | |
+ fn install_actor(&self, code_cid: &Cid) -> Result<(), anyhow::Error>; | |
} | |
/// filcrypto verification primitives provided by the runtime | |
diff --git a/runtime/src/runtime/policy.rs b/runtime/src/runtime/policy.rs | |
index 5559433b..41c6561a 100644 | |
--- a/runtime/src/runtime/policy.rs | |
+++ b/runtime/src/runtime/policy.rs | |
@@ -287,7 +287,8 @@ pub mod policy_constants { | |
/// The period over which all a miner's active sectors will be challenged. | |
pub const WPOST_PROVING_PERIOD: ChainEpoch = EPOCHS_IN_DAY; | |
/// The duration of a deadline's challenge window, the period before a deadline when the challenge is available. | |
- pub const WPOST_CHALLENGE_WINDOW: ChainEpoch = 30 * 60 / EPOCH_DURATION_SECONDS; // Half an hour (=48 per day) | |
+ pub const WPOST_CHALLENGE_WINDOW: ChainEpoch = 30 * 60 / EPOCH_DURATION_SECONDS; | |
+ // Half an hour (=48 per day) | |
/// The number of non-overlapping PoSt deadlines in each proving period. | |
pub const WPOST_PERIOD_DEADLINES: u64 = 48; | |
/// The maximum distance back that a valid Window PoSt must commit to the current chain. | |
@@ -411,11 +412,14 @@ pub mod policy_constants { | |
pub const MINIMUM_CONSENSUS_POWER: i64 = 2 << 10; | |
#[cfg(feature = "min-power-2g")] | |
pub const MINIMUM_CONSENSUS_POWER: i64 = 2 << 30; | |
+ #[cfg(feature = "min-power-16g")] | |
+ pub const MINIMUM_CONSENSUS_POWER: i64 = 16 << 30; | |
#[cfg(feature = "min-power-32g")] | |
pub const MINIMUM_CONSENSUS_POWER: i64 = 32 << 30; | |
#[cfg(not(any( | |
feature = "min-power-2k", | |
feature = "min-power-2g", | |
+ feature = "min-power-16g", | |
feature = "min-power-32g" | |
)))] | |
pub const MINIMUM_CONSENSUS_POWER: i64 = 10 << 40; | |
diff --git a/runtime/src/test_utils.rs b/runtime/src/test_utils.rs | |
index d83912ce..dde00409 100644 | |
--- a/runtime/src/test_utils.rs | |
+++ b/runtime/src/test_utils.rs | |
@@ -9,15 +9,17 @@ use std::rc::Rc; | |
use anyhow::anyhow; | |
use cid::multihash::{Code, Multihash as OtherMultihash}; | |
use cid::Cid; | |
-use fvm_ipld_blockstore::MemoryBlockstore; | |
+use fvm_ipld_blockstore::{Blockstore, MemoryBlockstore}; | |
use fvm_ipld_encoding::de::DeserializeOwned; | |
use fvm_ipld_encoding::{Cbor, CborStore, RawBytes}; | |
-use fvm_shared::address::Payload; | |
-use fvm_shared::address::{Address, Protocol}; | |
+use fvm_shared::address::{Address, Payload, Protocol}; | |
use fvm_shared::clock::ChainEpoch; | |
use fvm_shared::commcid::{FIL_COMMITMENT_SEALED, FIL_COMMITMENT_UNSEALED}; | |
use fvm_shared::consensus::ConsensusFault; | |
-use fvm_shared::crypto::signature::Signature; | |
+use fvm_shared::crypto::hash::SupportedHashes; | |
+use fvm_shared::crypto::signature::{ | |
+ Signature, SECP_PUB_LEN, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE, | |
+}; | |
use fvm_shared::econ::TokenAmount; | |
use fvm_shared::error::ExitCode; | |
use fvm_shared::piece::PieceInfo; | |
@@ -37,9 +39,10 @@ use rand::prelude::*; | |
use crate::runtime::builtins::Type; | |
use crate::runtime::{ | |
ActorCode, DomainSeparationTag, MessageInfo, Policy, Primitives, Runtime, RuntimePolicy, | |
- Verifier, | |
+ Verifier, EMPTY_ARR_CID, | |
}; | |
use crate::{actor_error, ActorError}; | |
+use libsecp256k1::{recover, Message, RecoveryId, Signature as EcsdaSignature}; | |
lazy_static::lazy_static! { | |
pub static ref SYSTEM_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/system"); | |
@@ -54,6 +57,9 @@ lazy_static::lazy_static! { | |
pub static ref REWARD_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/reward"); | |
pub static ref VERIFREG_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/verifiedregistry"); | |
pub static ref DATACAP_TOKEN_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/datacap"); | |
+ pub static ref EMBRYO_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/embryo"); | |
+ pub static ref EVM_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/evm"); | |
+ pub static ref EAM_ACTOR_CODE_ID: Cid = make_builtin(b"fil/test/eam"); | |
pub static ref ACTOR_TYPES: BTreeMap<Cid, Type> = { | |
let mut map = BTreeMap::new(); | |
map.insert(*SYSTEM_ACTOR_CODE_ID, Type::System); | |
@@ -68,6 +74,9 @@ lazy_static::lazy_static! { | |
map.insert(*REWARD_ACTOR_CODE_ID, Type::Reward); | |
map.insert(*VERIFREG_ACTOR_CODE_ID, Type::VerifiedRegistry); | |
map.insert(*DATACAP_TOKEN_ACTOR_CODE_ID, Type::DataCap); | |
+ map.insert(*EMBRYO_ACTOR_CODE_ID, Type::Embryo); | |
+ map.insert(*EVM_ACTOR_CODE_ID, Type::EVM); | |
+ map.insert(*EAM_ACTOR_CODE_ID, Type::EAM); | |
map | |
}; | |
pub static ref ACTOR_CODES: BTreeMap<Type, Cid> = [ | |
@@ -83,6 +92,9 @@ lazy_static::lazy_static! { | |
(Type::Reward, *REWARD_ACTOR_CODE_ID), | |
(Type::VerifiedRegistry, *VERIFREG_ACTOR_CODE_ID), | |
(Type::DataCap, *DATACAP_TOKEN_ACTOR_CODE_ID), | |
+ (Type::Embryo, *EMBRYO_ACTOR_CODE_ID), | |
+ (Type::EVM, *EVM_ACTOR_CODE_ID), | |
+ (Type::EAM, *EAM_ACTOR_CODE_ID), | |
] | |
.into_iter() | |
.collect(); | |
@@ -92,6 +104,8 @@ lazy_static::lazy_static! { | |
map.insert(*PAYCH_ACTOR_CODE_ID, ()); | |
map.insert(*MULTISIG_ACTOR_CODE_ID, ()); | |
map.insert(*MINER_ACTOR_CODE_ID, ()); | |
+ map.insert(*EMBRYO_ACTOR_CODE_ID, ()); | |
+ map.insert(*EVM_ACTOR_CODE_ID, ()); | |
map | |
}; | |
} | |
@@ -103,19 +117,29 @@ pub fn make_builtin(bz: &[u8]) -> Cid { | |
Cid::new_v1(IPLD_RAW, OtherMultihash::wrap(0, bz).expect("name too long")) | |
} | |
-pub struct MockRuntime { | |
+pub struct MockRuntime<BS = MemoryBlockstore> { | |
pub epoch: ChainEpoch, | |
pub miner: Address, | |
pub base_fee: TokenAmount, | |
pub id_addresses: HashMap<Address, Address>, | |
+ pub delegated_addresses: HashMap<Address, Address>, | |
+ pub delegated_addresses_source: HashMap<Address, Address>, | |
pub actor_code_cids: HashMap<Address, Cid>, | |
pub new_actor_addr: Option<Address>, | |
pub receiver: Address, | |
pub caller: Address, | |
pub caller_type: Cid, | |
+ pub origin: Address, | |
pub value_received: TokenAmount, | |
#[allow(clippy::type_complexity)] | |
- pub hash_func: Box<dyn Fn(&[u8]) -> [u8; 32]>, | |
+ pub hash_func: Box<dyn Fn(SupportedHashes, &[u8]) -> ([u8; 64], usize)>, | |
+ #[allow(clippy::type_complexity)] | |
+ pub recover_pubkey_fn: Box< | |
+ dyn Fn( | |
+ &[u8; SECP_SIG_MESSAGE_HASH_SIZE], | |
+ &[u8; SECP_SIG_LEN], | |
+ ) -> Result<[u8; SECP_PUB_LEN], ()>, | |
+ >, | |
pub network_version: NetworkVersion, | |
// Actor State | |
@@ -124,7 +148,7 @@ pub struct MockRuntime { | |
// VM Impl | |
pub in_call: bool, | |
- pub store: Rc<MemoryBlockstore>, | |
+ pub store: Rc<BS>, | |
pub in_transaction: bool, | |
// Expectations | |
@@ -134,12 +158,20 @@ pub struct MockRuntime { | |
pub policy: Policy, | |
pub circulating_supply: TokenAmount, | |
+ | |
+ // iron | |
+ pub gas_limit: u64, | |
+ pub gas_premium: TokenAmount, | |
+ pub actor_balances: HashMap<ActorID, TokenAmount>, | |
+ pub tipset_timestamp: u64, | |
+ pub tipset_cids: Vec<Cid>, | |
} | |
#[derive(Default)] | |
pub struct Expectations { | |
pub expect_validate_caller_any: bool, | |
pub expect_validate_caller_addr: Option<Vec<Address>>, | |
+ pub expect_validate_caller_f4_namespace: Option<Vec<u64>>, | |
pub expect_validate_caller_type: Option<Vec<Type>>, | |
pub expect_sends: VecDeque<ExpectedMessage>, | |
pub expect_create_actor: Option<ExpectCreateActor>, | |
@@ -155,6 +187,7 @@ pub struct Expectations { | |
pub expect_aggregate_verify_seals: Option<ExpectAggregateVerifySeals>, | |
pub expect_replica_verify: Option<ExpectReplicaVerify>, | |
pub expect_gas_charge: VecDeque<i64>, | |
+ pub expect_gas_available: VecDeque<u64>, | |
} | |
impl Expectations { | |
@@ -169,6 +202,11 @@ impl Expectations { | |
"expected ValidateCallerAddr {:?}, not received", | |
self.expect_validate_caller_addr | |
); | |
+ assert!( | |
+ self.expect_validate_caller_f4_namespace.is_none(), | |
+ "expected ValidateNamespace {:?}, not received", | |
+ self.expect_validate_caller_f4_namespace | |
+ ); | |
assert!( | |
self.expect_validate_caller_type.is_none(), | |
"expected ValidateCallerType {:?}, not received", | |
@@ -244,40 +282,61 @@ impl Expectations { | |
"expect_gas_charge {:?}, not received", | |
self.expect_gas_charge | |
); | |
+ assert!( | |
+ self.expect_gas_available.is_empty(), | |
+ "expect_gas_charge {:?}, not received", | |
+ self.expect_gas_available | |
+ ); | |
} | |
} | |
impl Default for MockRuntime { | |
fn default() -> Self { | |
+ Self::new(Default::default()) | |
+ } | |
+} | |
+ | |
+impl<BS> MockRuntime<BS> { | |
+ pub fn new(store: BS) -> Self { | |
Self { | |
epoch: Default::default(), | |
miner: Address::new_id(0), | |
base_fee: Default::default(), | |
id_addresses: Default::default(), | |
+ delegated_addresses: Default::default(), | |
+ delegated_addresses_source: Default::default(), | |
actor_code_cids: Default::default(), | |
new_actor_addr: Default::default(), | |
receiver: Address::new_id(0), | |
caller: Address::new_id(0), | |
caller_type: Default::default(), | |
+ origin: Address::new_id(0), | |
value_received: Default::default(), | |
- hash_func: Box::new(blake2b_256), | |
+ hash_func: Box::new(hash), | |
+ recover_pubkey_fn: Box::new(recover_secp_public_key), | |
network_version: NetworkVersion::V0, | |
state: Default::default(), | |
balance: Default::default(), | |
in_call: Default::default(), | |
- store: Default::default(), | |
+ store: Rc::new(store), | |
in_transaction: Default::default(), | |
expectations: Default::default(), | |
policy: Default::default(), | |
circulating_supply: Default::default(), | |
+ gas_limit: 10_000_000_000u64, | |
+ gas_premium: Default::default(), | |
+ actor_balances: Default::default(), | |
+ tipset_timestamp: Default::default(), | |
+ tipset_cids: Default::default(), | |
} | |
} | |
} | |
-#[derive(Clone, Debug)] | |
+#[derive(PartialEq, Eq, Clone, Debug)] | |
pub struct ExpectCreateActor { | |
pub code_id: Cid, | |
pub actor_id: ActorID, | |
+ pub predictable_address: Option<Address>, | |
} | |
#[derive(Clone, Debug)] | |
@@ -391,7 +450,7 @@ pub fn expect_abort<T: fmt::Debug>(exit_code: ExitCode, res: Result<T, ActorErro | |
expect_abort_contains_message(exit_code, "", res); | |
} | |
-impl MockRuntime { | |
+impl<BS: Blockstore> MockRuntime<BS> { | |
///// Runtime access for tests ///// | |
pub fn get_state<T: Cbor>(&self) -> T { | |
@@ -424,6 +483,10 @@ impl MockRuntime { | |
self.actor_code_cids.insert(address, code_id); | |
} | |
+ pub fn set_origin(&mut self, address: Address) { | |
+ self.origin = address; | |
+ } | |
+ | |
pub fn set_address_actor_type(&mut self, address: Address, actor_type: Cid) { | |
self.actor_code_cids.insert(address, actor_type); | |
} | |
@@ -440,6 +503,17 @@ impl MockRuntime { | |
self.id_addresses.insert(source, target); | |
} | |
+ pub fn add_delegated_address(&mut self, source: Address, target: Address) { | |
+ assert_eq!( | |
+ target.protocol(), | |
+ Protocol::Delegated, | |
+ "target must use Delegated address protocol" | |
+ ); | |
+ assert_eq!(source.protocol(), Protocol::ID, "source must use ID address protocol"); | |
+ self.delegated_addresses.insert(source, target); | |
+ self.delegated_addresses_source.insert(target, source); | |
+ } | |
+ | |
pub fn call<A: ActorCode>( | |
&mut self, | |
method_num: MethodNum, | |
@@ -522,6 +596,12 @@ impl MockRuntime { | |
self.expectations.borrow_mut().expect_validate_caller_any = true; | |
} | |
+ #[allow(dead_code)] | |
+ pub fn expect_validate_caller_namespace(&self, namespaces: Vec<u64>) { | |
+ assert!(!namespaces.is_empty(), "f4 namespaces must be non-empty"); | |
+ self.expectations.borrow_mut().expect_validate_caller_f4_namespace = Some(namespaces); | |
+ } | |
+ | |
#[allow(dead_code)] | |
pub fn expect_delete_actor(&mut self, beneficiary: Address) { | |
self.expectations.borrow_mut().expect_delete_actor = Some(beneficiary); | |
@@ -548,8 +628,13 @@ impl MockRuntime { | |
} | |
#[allow(dead_code)] | |
- pub fn expect_create_actor(&mut self, code_id: Cid, actor_id: ActorID) { | |
- let a = ExpectCreateActor { code_id, actor_id }; | |
+ pub fn expect_create_actor( | |
+ &mut self, | |
+ code_id: Cid, | |
+ actor_id: ActorID, | |
+ predictable_address: Option<Address>, | |
+ ) { | |
+ let a = ExpectCreateActor { code_id, actor_id, predictable_address }; | |
self.expectations.borrow_mut().expect_create_actor = Some(a); | |
} | |
@@ -640,6 +725,11 @@ impl MockRuntime { | |
self.expectations.borrow_mut().expect_gas_charge.push_back(value); | |
} | |
+ #[allow(dead_code)] | |
+ pub fn expect_gas_available(&mut self, value: u64) { | |
+ self.expectations.borrow_mut().expect_gas_available.push_back(value); | |
+ } | |
+ | |
///// Private helpers ///// | |
fn require_in_call(&self) { | |
@@ -655,19 +745,28 @@ impl MockRuntime { | |
} | |
} | |
-impl MessageInfo for MockRuntime { | |
+impl<BS> MessageInfo for MockRuntime<BS> { | |
fn caller(&self) -> Address { | |
self.caller | |
} | |
+ fn origin(&self) -> Address { | |
+ self.origin | |
+ } | |
fn receiver(&self) -> Address { | |
self.receiver | |
} | |
fn value_received(&self) -> TokenAmount { | |
self.value_received.clone() | |
} | |
+ fn gas_limit(&self) -> u64 { | |
+ self.gas_limit | |
+ } | |
+ fn gas_premium(&self) -> TokenAmount { | |
+ self.gas_premium.clone() | |
+ } | |
} | |
-impl Runtime<Rc<MemoryBlockstore>> for MockRuntime { | |
+impl<BS: Blockstore> Runtime<Rc<BS>> for MockRuntime<BS> { | |
fn network_version(&self) -> NetworkVersion { | |
self.network_version | |
} | |
@@ -725,6 +824,51 @@ impl Runtime<Rc<MemoryBlockstore>> for MockRuntime { | |
self.message().caller(), &addrs | |
)) | |
} | |
+ | |
+ fn validate_immediate_caller_namespace<I>(&mut self, namespaces: I) -> Result<(), ActorError> | |
+ where | |
+ I: IntoIterator<Item = u64>, | |
+ { | |
+ self.require_in_call(); | |
+ | |
+ let namespaces: Vec<u64> = namespaces.into_iter().collect(); | |
+ | |
+ let mut expectations = self.expectations.borrow_mut(); | |
+ assert!( | |
+ expectations.expect_validate_caller_f4_namespace.is_some(), | |
+ "unexpected validate caller namespace" | |
+ ); | |
+ | |
+ let expected_namespaces = | |
+ expectations.expect_validate_caller_f4_namespace.as_ref().unwrap(); | |
+ | |
+ assert_eq!( | |
+ &namespaces, expected_namespaces, | |
+ "unexpected validate caller namespace {:?}, expected {:?}", | |
+ namespaces, &expectations.expect_validate_caller_f4_namespace | |
+ ); | |
+ | |
+ let caller_f4 = self.lookup_address(self.caller().id().unwrap()); | |
+ | |
+ assert!(caller_f4.is_some(), "unexpected caller doesn't have a delegated address"); | |
+ | |
+ for id in namespaces.iter() { | |
+ let bound_address = match caller_f4.unwrap().payload() { | |
+ Payload::Delegated(d) => d.namespace(), | |
+ _ => unreachable!("lookup_address should always return a delegated address"), | |
+ }; | |
+ if bound_address == *id { | |
+ expectations.expect_validate_caller_f4_namespace = None; | |
+ return Ok(()); | |
+ } | |
+ } | |
+ expectations.expect_validate_caller_addr = None; | |
+ Err(actor_error!(forbidden; | |
+ "caller address {:?} forbidden, allowed: {:?}", | |
+ self.message().caller(), &namespaces | |
+ )) | |
+ } | |
+ | |
fn validate_immediate_caller_type<'a, I>(&mut self, types: I) -> Result<(), ActorError> | |
where | |
I: IntoIterator<Item = &'a Type>, | |
@@ -762,11 +906,22 @@ impl Runtime<Rc<MemoryBlockstore>> for MockRuntime { | |
self.balance.borrow().clone() | |
} | |
+ fn actor_balance(&self, id: ActorID) -> Option<TokenAmount> { | |
+ self.require_in_call(); | |
+ self.actor_balances.get(&id).cloned() | |
+ } | |
+ | |
fn resolve_address(&self, address: &Address) -> Option<ActorID> { | |
self.require_in_call(); | |
if let &Payload::ID(id) = address.payload() { | |
return Some(id); | |
} | |
+ if Protocol::Delegated == address.protocol() { | |
+ return self | |
+ .delegated_addresses_source | |
+ .get(address) | |
+ .and_then(|a| self.resolve_address(a)); | |
+ } | |
match self.get_id_address(address) { | |
None => None, | |
@@ -779,6 +934,11 @@ impl Runtime<Rc<MemoryBlockstore>> for MockRuntime { | |
} | |
} | |
+ fn lookup_address(&self, id: ActorID) -> Option<Address> { | |
+ self.require_in_call(); | |
+ self.delegated_addresses.get(&Address::new_id(id)).copied() | |
+ } | |
+ | |
fn get_actor_code_cid(&self, id: &ActorID) -> Option<Cid> { | |
self.require_in_call(); | |
self.actor_code_cids.get(&Address::new_id(*id)).cloned() | |
@@ -862,6 +1022,15 @@ impl Runtime<Rc<MemoryBlockstore>> for MockRuntime { | |
Ok(self.store_get(self.state.as_ref().unwrap())) | |
} | |
+ fn get_state_root(&self) -> Result<Cid, ActorError> { | |
+ Ok(self.state.unwrap_or(EMPTY_ARR_CID)) | |
+ } | |
+ | |
+ fn set_state_root(&mut self, root: &Cid) -> Result<(), ActorError> { | |
+ self.state = Some(*root); | |
+ Ok(()) | |
+ } | |
+ | |
fn transaction<C, RT, F>(&mut self, f: F) -> Result<RT, ActorError> | |
where | |
C: Cbor, | |
@@ -880,7 +1049,7 @@ impl Runtime<Rc<MemoryBlockstore>> for MockRuntime { | |
ret | |
} | |
- fn store(&self) -> &Rc<MemoryBlockstore> { | |
+ fn store(&self) -> &Rc<BS> { | |
&self.store | |
} | |
@@ -949,7 +1118,12 @@ impl Runtime<Rc<MemoryBlockstore>> for MockRuntime { | |
Ok(ret) | |
} | |
- fn create_actor(&mut self, code_id: Cid, actor_id: ActorID) -> Result<(), ActorError> { | |
+ fn create_actor( | |
+ &mut self, | |
+ code_id: Cid, | |
+ actor_id: ActorID, | |
+ predictable_address: Option<Address>, | |
+ ) -> Result<(), ActorError> { | |
self.require_in_call(); | |
if self.in_transaction { | |
return Err(actor_error!(assertion_failed; "side-effect within transaction")); | |
@@ -961,7 +1135,11 @@ impl Runtime<Rc<MemoryBlockstore>> for MockRuntime { | |
.take() | |
.expect("unexpected call to create actor"); | |
- assert!(expect_create_actor.code_id == code_id && expect_create_actor.actor_id == actor_id, "unexpected actor being created, expected code: {:?} address: {:?}, actual code: {:?} address: {:?}", expect_create_actor.code_id, expect_create_actor.actor_id, code_id, actor_id); | |
+ assert_eq!( | |
+ expect_create_actor, | |
+ ExpectCreateActor { code_id, actor_id, predictable_address }, | |
+ "unexpected actor being created" | |
+ ); | |
Ok(()) | |
} | |
@@ -1008,9 +1186,26 @@ impl Runtime<Rc<MemoryBlockstore>> for MockRuntime { | |
fn base_fee(&self) -> TokenAmount { | |
self.base_fee.clone() | |
} | |
+ | |
+ fn gas_available(&self) -> u64 { | |
+ let mut exs = self.expectations.borrow_mut(); | |
+ assert!(!exs.expect_gas_available.is_empty(), "unexpected gas available call"); | |
+ exs.expect_gas_available.pop_front().unwrap() | |
+ } | |
+ | |
+ fn tipset_timestamp(&self) -> u64 { | |
+ self.tipset_timestamp | |
+ } | |
+ | |
+ fn tipset_cid(&self, epoch: i64) -> Option<Cid> { | |
+ if epoch > self.epoch || epoch < 0 { | |
+ return None; | |
+ } | |
+ self.tipset_cids.get((self.epoch - epoch) as usize).copied() | |
+ } | |
} | |
-impl Primitives for MockRuntime { | |
+impl<BS> Primitives for MockRuntime<BS> { | |
fn verify_signature( | |
&self, | |
signature: &Signature, | |
@@ -1053,8 +1248,17 @@ impl Primitives for MockRuntime { | |
} | |
fn hash_blake2b(&self, data: &[u8]) -> [u8; 32] { | |
- (*self.hash_func)(data) | |
+ let (digest, _) = (*self.hash_func)(SupportedHashes::Blake2b256, data); | |
+ let mut ret = [0u8; 32]; | |
+ ret.copy_from_slice(&digest[..32]); | |
+ ret | |
+ } | |
+ | |
+ fn hash(&self, hasher: SupportedHashes, data: &[u8]) -> Vec<u8> { | |
+ let (digest, len) = (*self.hash_func)(hasher, data); | |
+ Vec::from(&digest[..len]) | |
} | |
+ | |
fn compute_unsealed_sector_cid( | |
&self, | |
reg: RegisteredSealProof, | |
@@ -1083,9 +1287,26 @@ impl Primitives for MockRuntime { | |
} | |
Ok(exp.cid) | |
} | |
+ | |
+ #[cfg(feature = "m2-native")] | |
+ fn install_actor(&self, _code_cid: &Cid) -> anyhow::Result<(), anyhow::Error> { | |
+ Ok(()) | |
+ } | |
+ | |
+ fn recover_secp_public_key( | |
+ &self, | |
+ hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE], | |
+ signature: &[u8; SECP_SIG_LEN], | |
+ ) -> Result<[u8; SECP_PUB_LEN], anyhow::Error> { | |
+ (*self.recover_pubkey_fn)(hash, signature).map_err(|_| anyhow!("failed to recover pubkey.")) | |
+ } | |
+ | |
+ fn hash_64(&self, hasher: SupportedHashes, data: &[u8]) -> ([u8; 64], usize) { | |
+ (*self.hash_func)(hasher, data) | |
+ } | |
} | |
-impl Verifier for MockRuntime { | |
+impl<BS> Verifier for MockRuntime<BS> { | |
fn verify_seal(&self, seal: &SealVerifyInfo) -> anyhow::Result<()> { | |
let exp = self | |
.expectations | |
@@ -1213,7 +1434,7 @@ impl Verifier for MockRuntime { | |
} | |
} | |
-impl RuntimePolicy for MockRuntime { | |
+impl<BS> RuntimePolicy for MockRuntime<BS> { | |
fn policy(&self) -> &Policy { | |
&self.policy | |
} | |
@@ -1230,6 +1451,30 @@ pub fn blake2b_256(data: &[u8]) -> [u8; 32] { | |
.unwrap() | |
} | |
+pub fn hash(hasher: SupportedHashes, data: &[u8]) -> ([u8; 64], usize) { | |
+ let hasher = Code::try_from(hasher as u64).unwrap(); | |
+ let (_, digest, written) = hasher.digest(data).into_inner(); | |
+ (digest, written as usize) | |
+} | |
+ | |
+#[allow(clippy::result_unit_err)] | |
+pub fn recover_secp_public_key( | |
+ hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE], | |
+ signature: &[u8; SECP_SIG_LEN], | |
+) -> Result<[u8; SECP_PUB_LEN], ()> { | |
+ // generate types to recover key from | |
+ let rec_id = RecoveryId::parse(signature[64]).map_err(|_| ())?; | |
+ let message = Message::parse(hash); | |
+ | |
+ // Signature value without recovery byte | |
+ let mut s = [0u8; 64]; | |
+ s.copy_from_slice(signature[..64].as_ref()); | |
+ | |
+ // generate Signature | |
+ let sig = EcsdaSignature::parse_standard(&s).map_err(|_| ())?; | |
+ Ok(recover(&message, &sig, &rec_id).map_err(|_| ())?.serialize()) | |
+} | |
+ | |
// multihash library doesn't support poseidon hashing, so we fake it | |
#[derive(Clone, Copy, Debug, PartialEq, Eq, Multihash)] | |
#[mh(alloc_size = 64)] | |
diff --git a/runtime/src/util/chaos/mod.rs b/runtime/src/util/chaos/mod.rs | |
index de8f4a80..335e119e 100644 | |
--- a/runtime/src/util/chaos/mod.rs | |
+++ b/runtime/src/util/chaos/mod.rs | |
@@ -123,7 +123,7 @@ impl Actor { | |
let actor_address = arg.actor_id; | |
- rt.create_actor(actor_cid, actor_address) | |
+ rt.create_actor(actor_cid, actor_address, None) | |
} | |
/// Resolves address, and returns the resolved address (defaulting to 0 ID) and success boolean. | |
diff --git a/state/Cargo.toml b/state/Cargo.toml | |
index 15221012..1663fb15 100644 | |
--- a/state/Cargo.toml | |
+++ b/state/Cargo.toml | |
@@ -27,17 +27,15 @@ fil_actor_reward = { version = "10.0.0-alpha.1", path = "../actors/reward"} | |
fil_actor_system = { version = "10.0.0-alpha.1", path = "../actors/system"} | |
fil_actor_init = { version = "10.0.0-alpha.1", path = "../actors/init"} | |
fil_actors_runtime = { version = "10.0.0-alpha.1", path = "../runtime"} | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
-fvm_ipld_encoding = "0.2.2" | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
+fvm_ipld_encoding = "0.3.0" | |
fvm_ipld_blockstore = "0.1.1" | |
num-traits = "0.2.14" | |
-anyhow = "1.0.65" | |
bimap = { version = "0.6.2" } | |
+anyhow = "1.0.65" | |
num-derive = "0.3.3" | |
serde = { version = "1.0.136", features = ["derive"] } | |
cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] } | |
-[dev-dependencies] | |
- | |
[features] | |
fil-actor = ["fil_actors_runtime/fil-actor"] | |
diff --git a/state/src/check.rs b/state/src/check.rs | |
index 00131bf5..483f5705 100644 | |
--- a/state/src/check.rs | |
+++ b/state/src/check.rs | |
@@ -64,6 +64,10 @@ pub struct Actor { | |
pub call_seq_num: u64, | |
/// Token balance of the actor | |
pub balance: TokenAmount, | |
+ /// The actor's "predictable" address, if assigned. | |
+ /// | |
+ /// This field is set on actor creation and never modified. | |
+ pub address: Option<Address>, | |
} | |
/// A specialization of a map of ID-addresses to actor heads. | |
@@ -216,6 +220,9 @@ pub fn check_state_invariants<'a, BS: Blockstore + Debug>( | |
acc.with_prefix("datacap: ").add_all(&msgs); | |
datacap_summary = Some(summary); | |
} | |
+ Some(Type::Embryo) => {} | |
+ Some(Type::EVM) => {} | |
+ Some(Type::EAM) => {} | |
None => { | |
bail!("unexpected actor code CID {} for address {}", actor.code, key); | |
} | |
diff --git a/test_vm/Cargo.toml b/test_vm/Cargo.toml | |
index 3ad8eb4c..f25c20fb 100644 | |
--- a/test_vm/Cargo.toml | |
+++ b/test_vm/Cargo.toml | |
@@ -25,17 +25,19 @@ fil_actor_market = { version = "10.0.0-alpha.1", path = "../actors/market" } | |
fil_actor_verifreg = { version = "10.0.0-alpha.1", path = "../actors/verifreg" } | |
fil_actor_miner = { version = "10.0.0-alpha.1", path = "../actors/miner" } | |
fil_actor_datacap = { version = "10.0.0-alpha.1", path = "../actors/datacap" } | |
+fil_actor_evm = { version = "10.0.0-alpha.1", path = "../actors/evm" } | |
+fil_actor_eam = { version = "10.0.0-alpha.1", path = "../actors/eam" } | |
anyhow = "1.0.65" | |
bimap = { version = "0.6.2" } | |
blake2b_simd = "1.0" | |
cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] } | |
frc46_token = "1.1.0" | |
-fvm_ipld_bitfield = "0.5.2" | |
+fvm_ipld_bitfield = "0.5.4" | |
fvm_ipld_blockstore = { version = "0.1.1", default-features = false } | |
-fvm_ipld_encoding = { version = "0.2.2", default-features = false } | |
-fvm_ipld_hamt = "0.5.1" | |
-fvm_shared = { version = "2.0.0-alpha.2", default-features = false } | |
+fvm_ipld_encoding = { version = "0.3.0", default-features = false } | |
+fvm_ipld_hamt = "0.6.0" | |
+fvm_shared = { version = "3.0.0-alpha.8", default-features = false } | |
indexmap = { version = "1.8.0", features = ["serde-1"] } | |
integer-encoding = { version = "3.0.3", default-features = false } | |
lazy_static = "1.4.0" | |
@@ -50,5 +52,10 @@ thiserror = "1.0.30" | |
[dev-dependencies] | |
cid = { version = "0.8.3", default-features = false, features = ["serde-codec"] } | |
-multihash = { version = "0.16.1", default-features = false } | |
+ethers = { version = "0.17.0", features = ["abigen"] } | |
+hex = "0.4.3" | |
test-case = "2.2.1" | |
+multihash = { version = "0.16.1", default-features = false } | |
+ | |
+[features] | |
+m2-native = [] | |
diff --git a/test_vm/src/lib.rs b/test_vm/src/lib.rs | |
index ceda6a81..28c75bfb 100644 | |
--- a/test_vm/src/lib.rs | |
+++ b/test_vm/src/lib.rs | |
@@ -1,10 +1,13 @@ | |
use anyhow::anyhow; | |
use bimap::BiBTreeMap; | |
use cid::multihash::Code; | |
+use cid::multihash::MultihashDigest; | |
use cid::Cid; | |
use fil_actor_account::{Actor as AccountActor, State as AccountState}; | |
use fil_actor_cron::{Actor as CronActor, Entry as CronEntry, State as CronState}; | |
use fil_actor_datacap::{Actor as DataCapActor, State as DataCapState}; | |
+use fil_actor_eam::EamActor; | |
+use fil_actor_evm::EvmContractActor; | |
use fil_actor_init::{Actor as InitActor, ExecReturn, State as InitState}; | |
use fil_actor_market::{Actor as MarketActor, Method as MarketMethod, State as MarketState}; | |
use fil_actor_miner::{Actor as MinerActor, MinerInfo, State as MinerState}; | |
@@ -23,9 +26,9 @@ use fil_actors_runtime::runtime::{ | |
}; | |
use fil_actors_runtime::test_utils::*; | |
use fil_actors_runtime::{ | |
- ActorError, BURNT_FUNDS_ACTOR_ADDR, CRON_ACTOR_ADDR, FIRST_NON_SINGLETON_ADDR, INIT_ACTOR_ADDR, | |
- REWARD_ACTOR_ADDR, STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, SYSTEM_ACTOR_ADDR, | |
- VERIFIED_REGISTRY_ACTOR_ADDR, | |
+ ActorError, BURNT_FUNDS_ACTOR_ADDR, CRON_ACTOR_ADDR, EAM_ACTOR_ADDR, FIRST_NON_SINGLETON_ADDR, | |
+ INIT_ACTOR_ADDR, REWARD_ACTOR_ADDR, STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, | |
+ SYSTEM_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ADDR, | |
}; | |
use fil_actors_runtime::{MessageAccumulator, DATACAP_TOKEN_ACTOR_ADDR}; | |
use fil_builtin_actors_state::check::check_state_invariants; | |
@@ -34,12 +37,14 @@ use fvm_ipld_blockstore::MemoryBlockstore; | |
use fvm_ipld_encoding::tuple::*; | |
use fvm_ipld_encoding::{Cbor, CborStore, RawBytes}; | |
use fvm_ipld_hamt::{BytesKey, Hamt, Sha256}; | |
-use fvm_shared::address::Payload; | |
-use fvm_shared::address::{Address, Protocol}; | |
+use fvm_shared::address::{Address, Payload}; | |
use fvm_shared::bigint::Zero; | |
use fvm_shared::clock::ChainEpoch; | |
use fvm_shared::consensus::ConsensusFault; | |
-use fvm_shared::crypto::signature::Signature; | |
+use fvm_shared::crypto::hash::SupportedHashes; | |
+use fvm_shared::crypto::signature::{ | |
+ Signature, SECP_PUB_LEN, SECP_SIG_LEN, SECP_SIG_MESSAGE_HASH_SIZE, | |
+}; | |
use fvm_shared::econ::TokenAmount; | |
use fvm_shared::error::ExitCode; | |
use fvm_shared::piece::PieceInfo; | |
@@ -51,7 +56,7 @@ use fvm_shared::sector::{ | |
}; | |
use fvm_shared::smooth::FilterEstimate; | |
use fvm_shared::version::NetworkVersion; | |
-use fvm_shared::{ActorID, MethodNum, METHOD_CONSTRUCTOR, METHOD_SEND}; | |
+use fvm_shared::{ActorID, MethodNum, IPLD_RAW, METHOD_CONSTRUCTOR, METHOD_SEND}; | |
use regex::Regex; | |
use serde::ser; | |
use std::cell::{RefCell, RefMut}; | |
@@ -138,17 +143,23 @@ impl<'bs> VM<'bs> { | |
let sys_st = SystemState::new(store).unwrap(); | |
let sys_head = v.put_store(&sys_st); | |
let sys_value = faucet_total.clone(); // delegate faucet funds to system so we can construct faucet by sending to bls addr | |
- v.set_actor(SYSTEM_ACTOR_ADDR, actor(*SYSTEM_ACTOR_CODE_ID, sys_head, 0, sys_value)); | |
+ v.set_actor(SYSTEM_ACTOR_ADDR, actor(*SYSTEM_ACTOR_CODE_ID, sys_head, 0, sys_value, None)); | |
// init | |
let init_st = InitState::new(store, "integration-test".to_string()).unwrap(); | |
let init_head = v.put_store(&init_st); | |
- v.set_actor(INIT_ACTOR_ADDR, actor(*INIT_ACTOR_CODE_ID, init_head, 0, TokenAmount::zero())); | |
+ v.set_actor( | |
+ INIT_ACTOR_ADDR, | |
+ actor(*INIT_ACTOR_CODE_ID, init_head, 0, TokenAmount::zero(), None), | |
+ ); | |
// reward | |
let reward_head = v.put_store(&RewardState::new(StoragePower::zero())); | |
- v.set_actor(REWARD_ACTOR_ADDR, actor(*REWARD_ACTOR_CODE_ID, reward_head, 0, reward_total)); | |
+ v.set_actor( | |
+ REWARD_ACTOR_ADDR, | |
+ actor(*REWARD_ACTOR_CODE_ID, reward_head, 0, reward_total, None), | |
+ ); | |
// cron | |
let builtin_entries = vec![ | |
@@ -162,20 +173,23 @@ impl<'bs> VM<'bs> { | |
}, | |
]; | |
let cron_head = v.put_store(&CronState { entries: builtin_entries }); | |
- v.set_actor(CRON_ACTOR_ADDR, actor(*CRON_ACTOR_CODE_ID, cron_head, 0, TokenAmount::zero())); | |
+ v.set_actor( | |
+ CRON_ACTOR_ADDR, | |
+ actor(*CRON_ACTOR_CODE_ID, cron_head, 0, TokenAmount::zero(), None), | |
+ ); | |
// power | |
let power_head = v.put_store(&PowerState::new(&v.store).unwrap()); | |
v.set_actor( | |
STORAGE_POWER_ACTOR_ADDR, | |
- actor(*POWER_ACTOR_CODE_ID, power_head, 0, TokenAmount::zero()), | |
+ actor(*POWER_ACTOR_CODE_ID, power_head, 0, TokenAmount::zero(), None), | |
); | |
// market | |
let market_head = v.put_store(&MarketState::new(&v.store).unwrap()); | |
v.set_actor( | |
STORAGE_MARKET_ACTOR_ADDR, | |
- actor(*MARKET_ACTOR_CODE_ID, market_head, 0, TokenAmount::zero()), | |
+ actor(*MARKET_ACTOR_CODE_ID, market_head, 0, TokenAmount::zero(), None), | |
); | |
// verifreg | |
@@ -223,22 +237,28 @@ impl<'bs> VM<'bs> { | |
let verifreg_head = v.put_store(&VerifRegState::new(&v.store, root_msig_addr).unwrap()); | |
v.set_actor( | |
VERIFIED_REGISTRY_ACTOR_ADDR, | |
- actor(*VERIFREG_ACTOR_CODE_ID, verifreg_head, 0, TokenAmount::zero()), | |
+ actor(*VERIFREG_ACTOR_CODE_ID, verifreg_head, 0, TokenAmount::zero(), None), | |
); | |
- // datacap | |
- let datacap_head = | |
- v.put_store(&DataCapState::new(&v.store, VERIFIED_REGISTRY_ACTOR_ADDR).unwrap()); | |
+ // Ethereum Address Manager | |
v.set_actor( | |
- DATACAP_TOKEN_ACTOR_ADDR, | |
- actor(*DATACAP_TOKEN_ACTOR_CODE_ID, datacap_head, 0, TokenAmount::zero()), | |
+ EAM_ACTOR_ADDR, | |
+ actor(*EAM_ACTOR_CODE_ID, EMPTY_ARR_CID, 0, TokenAmount::zero(), None), | |
); | |
// burnt funds | |
let burnt_funds_head = v.put_store(&AccountState { address: BURNT_FUNDS_ACTOR_ADDR }); | |
v.set_actor( | |
BURNT_FUNDS_ACTOR_ADDR, | |
- actor(*ACCOUNT_ACTOR_CODE_ID, burnt_funds_head, 0, TokenAmount::zero()), | |
+ actor(*ACCOUNT_ACTOR_CODE_ID, burnt_funds_head, 0, TokenAmount::zero(), None), | |
+ ); | |
+ | |
+ // datacap | |
+ let datacap_head = | |
+ v.put_store(&DataCapState::new(&v.store, VERIFIED_REGISTRY_ACTOR_ADDR).unwrap()); | |
+ v.set_actor( | |
+ DATACAP_TOKEN_ACTOR_ADDR, | |
+ actor(*DATACAP_TOKEN_ACTOR_CODE_ID, datacap_head, 0, TokenAmount::zero(), None), | |
); | |
// create a faucet with 1 billion FIL for setting up test accounts | |
@@ -541,12 +561,21 @@ impl MessageInfo for InvocationCtx<'_, '_> { | |
fn caller(&self) -> Address { | |
self.msg.from | |
} | |
+ fn origin(&self) -> Address { | |
+ Address::new_id(self.resolve_address(&self.top.originator_stable_addr).unwrap()) | |
+ } | |
fn receiver(&self) -> Address { | |
self.to() | |
} | |
fn value_received(&self) -> TokenAmount { | |
self.msg.value.clone() | |
} | |
+ fn gas_limit(&self) -> u64 { | |
+ u32::MAX.into() | |
+ } | |
+ fn gas_premium(&self) -> TokenAmount { | |
+ TokenAmount::zero() | |
+ } | |
} | |
pub const TEST_VM_RAND_ARRAY: [u8; 32] = [ | |
@@ -573,16 +602,22 @@ impl<'invocation, 'bs> InvocationCtx<'invocation, 'bs> { | |
} | |
}; | |
// Address does not yet exist, create it | |
- let protocol = target.protocol(); | |
- match protocol { | |
- Protocol::Actor | Protocol::ID => { | |
+ let is_account = match target.payload() { | |
+ Payload::Secp256k1(_) | Payload::BLS(_) => true, | |
+ Payload::Delegated(da) | |
+ // Validate that there's an actor at the target ID (we don't care what is there, | |
+ // just that something is there). | |
+ if self.v.get_actor(Address::new_id(da.namespace())).is_some() => | |
+ { | |
+ false | |
+ } | |
+ _ => { | |
return Err(ActorError::unchecked( | |
ExitCode::SYS_INVALID_RECEIVER, | |
- format!("cannot create account for address {} type {}", target, protocol), | |
+ format!("cannot create account for address {} type {}", target, target.protocol()), | |
)); | |
} | |
- _ => (), | |
- } | |
+ }; | |
let mut st = self.v.get_state::<InitState>(INIT_ACTOR_ADDR).unwrap(); | |
let target_id = st.map_address_to_new_id(self.v.store, target).unwrap(); | |
let target_id_addr = Address::new_id(target_id); | |
@@ -607,13 +642,17 @@ impl<'invocation, 'bs> InvocationCtx<'invocation, 'bs> { | |
policy: self.policy, | |
subinvocations: RefCell::new(vec![]), | |
}; | |
- new_ctx.create_actor(*ACCOUNT_ACTOR_CODE_ID, target_id).unwrap(); | |
- let res = new_ctx.invoke(); | |
- let invoc = new_ctx.gather_trace(res); | |
- RefMut::map(self.subinvocations.borrow_mut(), |subinvocs| { | |
- subinvocs.push(invoc); | |
- subinvocs | |
- }); | |
+ if is_account { | |
+ new_ctx.create_actor(*ACCOUNT_ACTOR_CODE_ID, target_id, Some(*target)).unwrap(); | |
+ let res = new_ctx.invoke(); | |
+ let invoc = new_ctx.gather_trace(res); | |
+ RefMut::map(self.subinvocations.borrow_mut(), |subinvocs| { | |
+ subinvocs.push(invoc); | |
+ subinvocs | |
+ }); | |
+ } else { | |
+ new_ctx.create_actor(*EMBRYO_ACTOR_CODE_ID, target_id, Some(*target)).unwrap(); | |
+ } | |
} | |
Ok((self.v.get_actor(target_id_addr).unwrap(), target_id_addr)) | |
@@ -685,8 +724,12 @@ impl<'invocation, 'bs> InvocationCtx<'invocation, 'bs> { | |
Type::Power => PowerActor::invoke_method(self, self.msg.method, ¶ms), | |
Type::PaymentChannel => PaychActor::invoke_method(self, self.msg.method, ¶ms), | |
Type::VerifiedRegistry => VerifregActor::invoke_method(self, self.msg.method, ¶ms), | |
- // Type::EVM => panic!("no EVM"), | |
Type::DataCap => DataCapActor::invoke_method(self, self.msg.method, ¶ms), | |
+ Type::Embryo => { | |
+ Err(ActorError::unhandled_message("embryo actors only handle method 0".into())) | |
+ } | |
+ Type::EVM => EvmContractActor::invoke_method(self, self.msg.method, ¶ms), | |
+ Type::EAM => EamActor::invoke_method(self, self.msg.method, ¶ms), | |
}; | |
if res.is_ok() && !self.caller_validated { | |
res = Err(actor_error!(assertion_failed, "failed to validate caller")); | |
@@ -700,7 +743,12 @@ impl<'invocation, 'bs> InvocationCtx<'invocation, 'bs> { | |
} | |
impl<'invocation, 'bs> Runtime<&'bs MemoryBlockstore> for InvocationCtx<'invocation, 'bs> { | |
- fn create_actor(&mut self, code_id: Cid, actor_id: ActorID) -> Result<(), ActorError> { | |
+ fn create_actor( | |
+ &mut self, | |
+ code_id: Cid, | |
+ actor_id: ActorID, | |
+ predictable_address: Option<Address>, | |
+ ) -> Result<(), ActorError> { | |
match NON_SINGLETON_CODES.get(&code_id) { | |
Some(_) => (), | |
None => { | |
@@ -711,14 +759,21 @@ impl<'invocation, 'bs> Runtime<&'bs MemoryBlockstore> for InvocationCtx<'invocat | |
} | |
} | |
let addr = Address::new_id(actor_id); | |
- if self.v.get_actor(addr).is_some() { | |
- return Err(ActorError::unchecked( | |
- ExitCode::SYS_ASSERTION_FAILED, | |
- "attempt to create new actor at existing address".to_string(), | |
- )); | |
- } | |
- let a = actor(code_id, EMPTY_ARR_CID, 0, TokenAmount::zero()); | |
- self.v.set_actor(addr, a); | |
+ let actor = match self.v.get_actor(addr) { | |
+ Some(mut act) if act.code == *EMBRYO_ACTOR_CODE_ID => { | |
+ act.code = code_id; | |
+ act | |
+ } | |
+ None => actor(code_id, EMPTY_ARR_CID, 0, TokenAmount::zero(), predictable_address), | |
+ _ => { | |
+ // can happen if an actor is deployed to an f4 address. | |
+ return Err(ActorError::unchecked( | |
+ ExitCode::USR_FORBIDDEN, | |
+ "attempt to create new actor at existing address".to_string(), | |
+ )); | |
+ } | |
+ }; | |
+ self.v.set_actor(addr, actor); | |
Ok(()) | |
} | |
@@ -750,6 +805,43 @@ impl<'invocation, 'bs> Runtime<&'bs MemoryBlockstore> for InvocationCtx<'invocat | |
} | |
} | |
+ fn validate_immediate_caller_namespace<I>( | |
+ &mut self, | |
+ namespace_manager_addresses: I, | |
+ ) -> Result<(), ActorError> | |
+ where | |
+ I: IntoIterator<Item = u64>, | |
+ { | |
+ if self.caller_validated { | |
+ return Err(ActorError::unchecked( | |
+ ExitCode::SYS_ASSERTION_FAILED, | |
+ "caller double validated".to_string(), | |
+ )); | |
+ } | |
+ let managers: Vec<_> = namespace_manager_addresses.into_iter().collect(); | |
+ | |
+ if let Some(delegated) = self.lookup_address(self.message().caller().id().unwrap()) { | |
+ for id in managers { | |
+ if match delegated.payload() { | |
+ Payload::Delegated(d) => d.namespace() == id, | |
+ _ => false, | |
+ } { | |
+ return Ok(()); | |
+ } | |
+ } | |
+ } else { | |
+ return Err(ActorError::unchecked( | |
+ ExitCode::SYS_ASSERTION_FAILED, | |
+ "immediate caller actor expected to have namespace".to_string(), | |
+ )); | |
+ } | |
+ | |
+ Err(ActorError::unchecked( | |
+ ExitCode::SYS_ASSERTION_FAILED, | |
+ "immediate caller actor namespace forbidden".to_string(), | |
+ )) | |
+ } | |
+ | |
fn validate_immediate_caller_is<'a, I>(&mut self, addresses: I) -> Result<(), ActorError> | |
where | |
I: IntoIterator<Item = &'a Address>, | |
@@ -814,6 +906,10 @@ impl<'invocation, 'bs> Runtime<&'bs MemoryBlockstore> for InvocationCtx<'invocat | |
} | |
} | |
+ fn lookup_address(&self, id: ActorID) -> Option<Address> { | |
+ self.v.get_actor(Address::new_id(id)).and_then(|act| act.predictable_address) | |
+ } | |
+ | |
fn send( | |
&self, | |
to: &Address, | |
@@ -866,32 +962,25 @@ impl<'invocation, 'bs> Runtime<&'bs MemoryBlockstore> for InvocationCtx<'invocat | |
Ok(TEST_VM_RAND_ARRAY) | |
} | |
- fn create<C: Cbor>(&mut self, obj: &C) -> Result<(), ActorError> { | |
+ fn get_state_root(&self) -> Result<Cid, ActorError> { | |
+ Ok(self.v.get_actor(self.to()).unwrap().head) | |
+ } | |
+ | |
+ fn set_state_root(&mut self, root: &Cid) -> Result<(), ActorError> { | |
let maybe_act = self.v.get_actor(self.to()); | |
match maybe_act { | |
None => Err(ActorError::unchecked( | |
ExitCode::SYS_ASSERTION_FAILED, | |
- "failed to create state".to_string(), | |
+ "actor does not exist".to_string(), | |
)), | |
Some(mut act) => { | |
- if act.head != EMPTY_ARR_CID { | |
- Err(ActorError::unchecked( | |
- ExitCode::SYS_ASSERTION_FAILED, | |
- "failed to construct state: already initialized".to_string(), | |
- )) | |
- } else { | |
- act.head = self.v.store.put_cbor(obj, Code::Blake2b256).unwrap(); | |
- self.v.set_actor(self.to(), act); | |
- Ok(()) | |
- } | |
+ act.head = *root; | |
+ self.v.set_actor(self.to(), act); | |
+ Ok(()) | |
} | |
} | |
} | |
- fn state<C: Cbor>(&self) -> Result<C, ActorError> { | |
- Ok(self.v.get_state::<C>(self.to()).unwrap()) | |
- } | |
- | |
fn transaction<C, RT, F>(&mut self, f: F) -> Result<RT, ActorError> | |
where | |
C: Cbor, | |
@@ -938,6 +1027,22 @@ impl<'invocation, 'bs> Runtime<&'bs MemoryBlockstore> for InvocationCtx<'invocat | |
fn base_fee(&self) -> TokenAmount { | |
TokenAmount::zero() | |
} | |
+ | |
+ fn actor_balance(&self, id: ActorID) -> Option<TokenAmount> { | |
+ self.v.get_actor(Address::new_id(id)).map(|act| act.balance) | |
+ } | |
+ | |
+ fn gas_available(&self) -> u64 { | |
+ u32::MAX.into() | |
+ } | |
+ | |
+ fn tipset_timestamp(&self) -> u64 { | |
+ 0 | |
+ } | |
+ | |
+ fn tipset_cid(&self, _epoch: i64) -> Option<Cid> { | |
+ Some(Cid::new_v1(IPLD_RAW, Multihash::wrap(0, b"faketipset").unwrap())) | |
+ } | |
} | |
impl Primitives for VM<'_> { | |
@@ -975,6 +1080,25 @@ impl Primitives for VM<'_> { | |
) -> Result<Cid, anyhow::Error> { | |
Ok(make_piece_cid(b"unsealed from itest vm")) | |
} | |
+ | |
+ fn hash(&self, hasher: SupportedHashes, data: &[u8]) -> Vec<u8> { | |
+ let hasher = Code::try_from(hasher as u64).unwrap(); // supported hashes are all implemented in multihash | |
+ hasher.digest(data).to_bytes() | |
+ } | |
+ | |
+ fn hash_64(&self, hasher: SupportedHashes, data: &[u8]) -> ([u8; 64], usize) { | |
+ let hasher = Code::try_from(hasher as u64).unwrap(); | |
+ let (len, buf, ..) = hasher.digest(data).into_inner(); | |
+ (buf, len as usize) | |
+ } | |
+ | |
+ fn recover_secp_public_key( | |
+ &self, | |
+ hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE], | |
+ signature: &[u8; SECP_SIG_LEN], | |
+ ) -> Result<[u8; SECP_PUB_LEN], anyhow::Error> { | |
+ recover_secp_public_key(hash, signature).map_err(|_| anyhow!("failed to recover pubkey")) | |
+ } | |
} | |
impl Primitives for InvocationCtx<'_, '_> { | |
@@ -998,6 +1122,27 @@ impl Primitives for InvocationCtx<'_, '_> { | |
) -> Result<Cid, anyhow::Error> { | |
self.v.compute_unsealed_sector_cid(proof_type, pieces) | |
} | |
+ | |
+ #[cfg(feature = "m2-native")] | |
+ fn install_actor(&self, _: &Cid) -> Result<(), anyhow::Error> { | |
+ panic!("TODO implement me") | |
+ } | |
+ | |
+ fn hash(&self, hasher: SupportedHashes, data: &[u8]) -> Vec<u8> { | |
+ self.v.hash(hasher, data) | |
+ } | |
+ | |
+ fn hash_64(&self, hasher: SupportedHashes, data: &[u8]) -> ([u8; 64], usize) { | |
+ self.v.hash_64(hasher, data) | |
+ } | |
+ | |
+ fn recover_secp_public_key( | |
+ &self, | |
+ hash: &[u8; SECP_SIG_MESSAGE_HASH_SIZE], | |
+ signature: &[u8; SECP_SIG_LEN], | |
+ ) -> Result<[u8; SECP_PUB_LEN], anyhow::Error> { | |
+ self.v.recover_secp_public_key(hash, signature) | |
+ } | |
} | |
impl Verifier for InvocationCtx<'_, '_> { | |
@@ -1059,10 +1204,17 @@ pub struct Actor { | |
pub head: Cid, | |
pub call_seq_num: u64, | |
pub balance: TokenAmount, | |
+ pub predictable_address: Option<Address>, | |
} | |
-pub fn actor(code: Cid, head: Cid, seq: u64, bal: TokenAmount) -> Actor { | |
- Actor { code, head, call_seq_num: seq, balance: bal } | |
+pub fn actor( | |
+ code: Cid, | |
+ head: Cid, | |
+ call_seq_num: u64, | |
+ balance: TokenAmount, | |
+ predictable_address: Option<Address>, | |
+) -> Actor { | |
+ Actor { code, head, call_seq_num, balance, predictable_address } | |
} | |
#[derive(Clone)] | |
diff --git a/test_vm/tests/test_vm_test.rs b/test_vm/tests/test_vm_test.rs | |
index 1e17fe49..8311d1fa 100644 | |
--- a/test_vm/tests/test_vm_test.rs | |
+++ b/test_vm/tests/test_vm_test.rs | |
@@ -18,14 +18,25 @@ fn state_control() { | |
let addr2 = Address::new_id(2222); | |
// set actor | |
- let a1 = | |
- actor(*ACCOUNT_ACTOR_CODE_ID, make_builtin(b"a1-head"), 42, TokenAmount::from_atto(10u8)); | |
+ let a1 = actor( | |
+ *ACCOUNT_ACTOR_CODE_ID, | |
+ make_builtin(b"a1-head"), | |
+ 42, | |
+ TokenAmount::from_atto(10u8), | |
+ None, | |
+ ); | |
v.set_actor(addr1, a1.clone()); | |
let out = v.get_actor(addr1).unwrap(); | |
assert_eq!(out, a1); | |
let check = v.checkpoint(); | |
- let a2 = actor(*PAYCH_ACTOR_CODE_ID, make_builtin(b"a2-head"), 88, TokenAmount::from_atto(1u8)); | |
+ let a2 = actor( | |
+ *PAYCH_ACTOR_CODE_ID, | |
+ make_builtin(b"a2-head"), | |
+ 88, | |
+ TokenAmount::from_atto(1u8), | |
+ None, | |
+ ); | |
v.set_actor(addr2, a2.clone()); | |
assert_eq!(v.get_actor(addr2).unwrap(), a2); | |
// rollback removes a2 but not a1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment