Skip to content

Commit e1c5fa2

Browse files
committed
Add 'fvm-utils/' from commit '368ad258a82204d0004b7321f1015373fb4d17b9'
git-subtree-dir: fvm-utils git-subtree-mainline: d3a0057 git-subtree-split: 368ad25
2 parents d3a0057 + 368ad25 commit e1c5fa2

46 files changed

Lines changed: 5205 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
## Changes
2+
3+
<!--
4+
5+
Please provide a brief but specific list of changes made, describe the changes
6+
in functionality rather than the changes in code.
7+
8+
-->
9+
10+
-
11+
-
12+
-
13+
14+
## Tests
15+
16+
<!--
17+
18+
Details on how to run tests relevant to the changes within this pull request.
19+
20+
-->
21+
22+
```
23+
24+
```
25+
26+
## Issues
27+
28+
<!--
29+
30+
Please link any issues that this pull request is related to and use the GitHub
31+
supported format for automatically closing issues (ie, closes #123, fixes #123)
32+
33+
-->
34+
35+
-
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- "main"
7+
pull_request:
8+
branches:
9+
- '**'
10+
11+
jobs:
12+
test:
13+
name: Test Suite
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v2
17+
- uses: actions-rs/toolchain@v1
18+
with:
19+
profile: minimal
20+
target: wasm32-unknown-unknown
21+
toolchain: nightly-2022-10-03
22+
override: true
23+
- run: cargo b --all --release
24+
- run: cargo t --all --release
25+
26+
fmt:
27+
name: Rustfmt
28+
runs-on: ubuntu-latest
29+
steps:
30+
- uses: actions/checkout@v2
31+
- uses: actions-rs/toolchain@v1
32+
with:
33+
profile: minimal
34+
target: wasm32-unknown-unknown
35+
toolchain: stable
36+
override: true
37+
- run: rustup component add rustfmt
38+
- uses: actions-rs/cargo@v1
39+
with:
40+
command: fmt
41+
args: --all -- --check
42+
43+
clippy:
44+
name: Clippy
45+
runs-on: ubuntu-latest
46+
steps:
47+
- uses: actions/checkout@v2
48+
- uses: actions-rs/toolchain@v1
49+
with:
50+
profile: minimal
51+
target: wasm32-unknown-unknown
52+
toolchain: stable
53+
override: true
54+
- run: rustup component add clippy
55+
- uses: actions-rs/cargo@v1
56+
with:
57+
command: clippy
58+
args: -- -D warnings

fvm-utils/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/target
2+
/Cargo.lock
3+
.idea

fvm-utils/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[package]
2+
name = "fvm-utils"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
[dependencies]
8+
fil_actors_runtime = { path = "./runtime", features = ["test_utils", "fil-actor"] }
9+
primitives = { path = "primitives" }
10+
11+
[workspace]
12+
members = [
13+
"runtime",
14+
"primitives",
15+
"example",
16+
]

fvm-utils/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# fvm-utils
2+
This repo contains a series of crates that serve as utils for fvm development and testing.
3+
Here are some simple breakdowns:
4+
- runtime: Contains the runtime wrapper for communicating with `fvm`. It provides some
5+
handy utility functions such as `transaction` and `verification`.
6+
- primitives: Contains typed version of `fvm` primitives such as `cid` and `hamt`.
7+
- example: Contains a sample user defined actor using `runtime` and `primitive` crate which
8+
one can deploy to `fvm` as wasm binary.
9+
10+
For more details, please refer to each crate's `README.md`.

fvm-utils/example/Cargo.toml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
[package]
2+
edition = "2021"
3+
name = "fil_actor_example"
4+
version = "0.1.0"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
[dependencies]
8+
fil_actors_runtime = {path = "../runtime", features = ["test_utils", "fil-actor"]}
9+
primitives = {path = "../primitives"}
10+
11+
frc42_dispatch = "3.2.0"
12+
fvm_ipld_blockstore = "0.1.1"
13+
fvm_ipld_encoding = "0.3.3"
14+
fvm_ipld_hamt = "0.5.1"
15+
fvm_shared = {version = "=3.2.0", default-features = false}
16+
17+
anyhow = "1.0.56"
18+
cid = {version = "0.8.3", default-features = false, features = ["serde-codec"]}
19+
log = "0.4.14"
20+
num-derive = "0.3.3"
21+
num-traits = "0.2.14"
22+
serde = {version = "1.0.136", features = ["derive"]}
23+
24+
[dev-dependencies]
25+
base64 = "0.13.0"
26+
blake2b_simd = "1.0.0"
27+
libsecp256k1 = {version = "0.7"}
28+
num-traits = "0.2"
29+
rand = "0.8"
30+
rand_chacha = "0.3"
31+
wabt = "0.10.0"
32+
wasmtime = "0.35.2"
33+
34+
[build-dependencies]
35+
wasm-builder = "3.0.1"
36+
wasmtime = "0.35.2"

fvm-utils/example/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# fil-actor-example
2+
Sample fvm actor based on `fvm-utils`. To create your own user defined actor, define
3+
`Actor` that implements `ActorCode` trait. At the same time, you can create the wasm
4+
entrypoint with the following short cut:
5+
```rust
6+
#[no_mangle]
7+
pub fn invoke(param: u32) -> u32 {
8+
runtime::fvm::trampoline::<Actor>(param)
9+
}
10+
```
11+
See `src/lib.rs` for more details.
12+
13+
## Build
14+
To compile:
15+
```shell
16+
cargo build
17+
```
18+
You should be able to see the `fil_actor_example.compact.wasm` compiled generated.
19+
20+
Set up a local fvm according to this [tutorial](https://lotus.filecoin.io/lotus/developers/local-network/).
21+
22+
## Test
23+
To trigger unit tests, perform the following:
24+
```shell
25+
cargo test
26+
```

fvm-utils/example/build.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
fn main() {
2+
use wasm_builder::WasmBuilder;
3+
WasmBuilder::new()
4+
.with_current_project()
5+
.import_memory()
6+
.append_to_rust_flags("-Ctarget-feature=+crt-static")
7+
.append_to_rust_flags("-Cpanic=abort")
8+
.append_to_rust_flags("-Coverflow-checks=true")
9+
.append_to_rust_flags("-Clto=true")
10+
.append_to_rust_flags("-Copt-level=z")
11+
.build()
12+
}

fvm-utils/example/src/lib.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
mod state;
2+
3+
use crate::state::{State, UserPersistParam};
4+
use fil_actors_runtime::runtime::{ActorCode, Runtime};
5+
use fil_actors_runtime::{
6+
actor_dispatch, actor_error, restrict_internal_api, runtime, ActorDowncast, ActorError,
7+
INIT_ACTOR_ADDR,
8+
};
9+
use fvm_shared::error::ExitCode;
10+
use fvm_shared::{MethodNum, METHOD_CONSTRUCTOR};
11+
use num_derive::FromPrimitive;
12+
use num_traits::FromPrimitive;
13+
14+
#[no_mangle]
15+
pub fn invoke(param: u32) -> u32 {
16+
runtime::fvm::trampoline::<Actor>(param)
17+
}
18+
19+
/// SCA actor methods available
20+
#[derive(FromPrimitive)]
21+
#[repr(u64)]
22+
pub enum Method {
23+
/// Constructor for Storage Power Actor
24+
Constructor = METHOD_CONSTRUCTOR,
25+
Persist = frc42_dispatch::method_hash!("Persist"),
26+
}
27+
28+
pub struct Actor;
29+
30+
impl Actor {
31+
/// Constructor for SCA actor
32+
fn constructor(rt: &mut impl Runtime) -> Result<(), ActorError> {
33+
rt.validate_immediate_caller_is(std::iter::once(&INIT_ACTOR_ADDR))?;
34+
let st = State::new(rt.store()).map_err(|e| {
35+
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "Failed to create actor state")
36+
})?;
37+
rt.create(&st)?;
38+
Ok(())
39+
}
40+
41+
/// Persists some bytes to storage
42+
fn persist(rt: &mut impl Runtime, param: UserPersistParam) -> Result<(), ActorError> {
43+
let caller = rt.message().caller();
44+
45+
rt.validate_immediate_caller_accept_any()?;
46+
47+
rt.transaction(|st: &mut State, rt| {
48+
st.upsert_user(&caller, param.name, rt.store())
49+
.map_err(|e| {
50+
e.downcast_default(
51+
ExitCode::USR_ILLEGAL_STATE,
52+
"Failed to create SCA actor state",
53+
)
54+
})?;
55+
Ok(())
56+
})?;
57+
58+
Ok(())
59+
}
60+
}
61+
62+
impl ActorCode for Actor {
63+
type Methods = Method;
64+
actor_dispatch! {
65+
Constructor => constructor,
66+
Persist => persist,
67+
}
68+
}
69+
70+
#[cfg(test)]
71+
mod test {
72+
use crate::{Actor, Method, State, UserPersistParam};
73+
use fil_actors_runtime::test_utils::{MockRuntime, INIT_ACTOR_CODE_ID};
74+
use fil_actors_runtime::INIT_ACTOR_ADDR;
75+
use fvm_ipld_encoding::ipld_block::IpldBlock;
76+
use fvm_shared::address::Address;
77+
use fvm_shared::MethodNum;
78+
79+
#[test]
80+
fn constructor_works() {
81+
let mut rt = new_runtime();
82+
83+
rt.set_caller(*INIT_ACTOR_CODE_ID, INIT_ACTOR_ADDR);
84+
rt.expect_validate_caller_addr(vec![INIT_ACTOR_ADDR]);
85+
86+
rt.call::<Actor>(Method::Constructor as MethodNum, None)
87+
.unwrap();
88+
89+
rt.verify()
90+
}
91+
92+
#[test]
93+
fn persists_works() {
94+
let mut rt = new_runtime();
95+
96+
rt.set_caller(*INIT_ACTOR_CODE_ID, INIT_ACTOR_ADDR);
97+
rt.expect_validate_caller_addr(vec![INIT_ACTOR_ADDR]);
98+
99+
rt.call::<Actor>(Method::Constructor as MethodNum, None)
100+
.unwrap();
101+
102+
rt.expect_validate_caller_any();
103+
rt.call::<Actor>(
104+
Method::Persist as MethodNum,
105+
IpldBlock::serialize_cbor(&UserPersistParam {
106+
name: String::from("sample"),
107+
})
108+
.unwrap(),
109+
)
110+
.unwrap();
111+
112+
rt.verify();
113+
let state: State = rt.get_state();
114+
assert_eq!(state.call_count, 1);
115+
}
116+
117+
fn new_runtime() -> MockRuntime {
118+
MockRuntime {
119+
receiver: Address::new_id(1),
120+
caller: INIT_ACTOR_ADDR,
121+
..Default::default()
122+
}
123+
}
124+
}

fvm-utils/example/src/state.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use cid::Cid;
2+
use fvm_ipld_blockstore::Blockstore;
3+
use fvm_ipld_hamt::BytesKey;
4+
use fvm_shared::address::Address;
5+
use primitives::{TCid, THamt};
6+
use serde::{Deserialize, Serialize};
7+
8+
/// Sample struct for user persistence
9+
#[derive(Serialize, Deserialize)]
10+
pub struct UserPersistParam {
11+
pub name: String,
12+
}
13+
14+
/// User data storage struct
15+
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)]
16+
pub struct User {
17+
pub name: String,
18+
pub owner: Address,
19+
}
20+
21+
/// The state storage struct, persisted in BlockStore
22+
#[derive(Serialize, Deserialize)]
23+
pub struct State {
24+
pub call_count: usize,
25+
pub typed_hamt: TCid<THamt<Cid, User>>,
26+
}
27+
28+
impl State {
29+
pub fn new<BS: Blockstore>(store: &BS) -> anyhow::Result<Self> {
30+
Ok(State {
31+
call_count: 0,
32+
typed_hamt: TCid::new_hamt(store)?,
33+
})
34+
}
35+
36+
pub fn upsert_user<BS: Blockstore>(
37+
&mut self,
38+
address: &Address,
39+
name: String,
40+
store: &BS,
41+
) -> anyhow::Result<()> {
42+
let key = BytesKey::from(address.to_bytes());
43+
let mut hamt = self.typed_hamt.load(store)?;
44+
hamt.set(
45+
key,
46+
User {
47+
owner: *address,
48+
name,
49+
},
50+
)?;
51+
52+
self.call_count += 1;
53+
self.typed_hamt.flush(hamt)?;
54+
55+
Ok(())
56+
}
57+
}

0 commit comments

Comments
 (0)