Skip to content

Commit

Permalink
Add chain metadata actor
Browse files Browse the repository at this point in the history
  • Loading branch information
fridrik01 committed Jan 15, 2024
1 parent 227e4a4 commit ebfd26b
Show file tree
Hide file tree
Showing 9 changed files with 712 additions and 102 deletions.
536 changes: 440 additions & 96 deletions Cargo.lock

Large diffs are not rendered by default.

33 changes: 28 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ members = [
"fendermint/testing",
"fendermint/testing/*-test",
"fendermint/vm/*",
"fendermint/actors",
"fendermint/actors/chainmetadata",
]

[workspace.package]
Expand Down Expand Up @@ -65,10 +67,14 @@ gcra = "0.4"
hex = "0.4"
im = "15.1.0"
integer-encoding = { version = "3.0.3", default-features = false }
jsonrpc-v2 = { version = "0.11", default-features = false, features = ["bytes-v10"] }
jsonrpc-v2 = { version = "0.11", default-features = false, features = [
"bytes-v10",
] }
k256 = "0.11" # Same as tendermint-rs
lazy_static = "1.4"
libipld = { version = "0.16", default-features = false, features = ["dag-cbor"] }
libipld = { version = "0.16", default-features = false, features = [
"dag-cbor",
] }
libp2p = { version = "0.53", default-features = false, features = [
"gossipsub",
"kad",
Expand Down Expand Up @@ -151,7 +157,7 @@ openssl = { version = "0.10", features = ["vendored"] }
# to version which are different than the ones in the builtin-actors project, and since
# they are 0.x cargo cannot upgrade them automatically, which leads to version conflicts.
fvm = { version = "4.0.0", default-features = false } # no opencl feature or it fails on CI
fvm_shared = { version = "4.0.0", features = ["crypto"] }
fvm_shared = { version = "4.0.0" }
fvm_sdk = { version = "4.0.0" }

fvm_ipld_blockstore = "0.2.0"
Expand All @@ -178,7 +184,10 @@ fil_actors_runtime = { git = "https://github.com/filecoin-project/builtin-actors
# Using 0.8 because of ref-fvm.
# 0.9 would be better because of its updated quickcheck dependency.
# 0.10 breaks some API.
cid = { version = "0.10.1", default-features = false, features = ["serde-codec", "std"] }
cid = { version = "0.10.1", default-features = false, features = [
"serde-codec",
"std",
] }

# Depending on the release cycle, this dependency might want an earlier version of the FVM.
# We can work around it by hardcoding the method hashes; currently there is only one.
Expand All @@ -188,11 +197,25 @@ cid = { version = "0.10.1", default-features = false, features = ["serde-codec",
tower-abci = { version = "0.7" }
tendermint = { version = "0.31", features = ["secp256k1"] }
tendermint-config = "0.33.0"
tendermint-rpc = { version = "0.31", features = ["secp256k1", "http-client", "websocket-client"] }
tendermint-rpc = { version = "0.31", features = [
"secp256k1",
"http-client",
"websocket-client",
] }
tendermint-proto = { version = "0.31" }

[patch.crates-io]
# Use stable-only features.
gcra = { git = "https://github.com/consensus-shipyard/gcra-rs.git", branch = "main" }
# Contains some API changes that the upstream has not merged.
merkle-tree-rs = { git = "https://github.com/consensus-shipyard/merkle-tree-rs.git", branch = "dev" }

[profile.wasm]
inherits = "release"
panic = "abort"
overflow-checks = false
lto = true
opt-level = "z"
strip = true
codegen-units = 1
incremental = false
12 changes: 12 additions & 0 deletions fendermint/actors/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "fendermint_actors"
version = "0.1.0"

[build-dependencies]
fil_actors_runtime = { workspace = true, features = ["test_utils"] }
fil_actor_bundler = "6.1.0"
num-traits = { workspace = true}

[features]
default=[]
testing=[]
110 changes: 110 additions & 0 deletions fendermint/actors/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright 2022-2024 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
extern crate fil_actor_bundler;
extern crate fil_actors_runtime;
extern crate num_traits;

use fil_actor_bundler::Bundler;
use std::error::Error;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::process::{Command, Stdio};
use std::thread;

const ACTORS: &[&str] = &["chainmetadata"];

const FILES_TO_WATCH: &[&str] = &["Cargo.toml", "src", "actors"];

fn main() -> Result<(), Box<dyn Error>> {
// Cargo executable location.
let cargo = std::env::var_os("CARGO").expect("no CARGO env var");

let out_dir = std::env::var_os("OUT_DIR")
.as_ref()
.map(Path::new)
.map(|p| p.join("bundle"))
.expect("no OUT_DIR env var");
println!("cargo:warning=out_dir: {:?}", &out_dir);

let manifest_path =
Path::new(&std::env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR unset"))
.join("Cargo.toml");

for file in FILES_TO_WATCH.to_vec() {
println!("cargo:rerun-if-changed={}", file);
}

// Cargo build command for all test_actors at once.
let mut cmd = Command::new(cargo);
cmd.arg("build")
.args(
ACTORS
.iter()
.map(|pkg| "-p=fendermint_actor_".to_owned() + pkg),
)
.arg("--target=wasm32-unknown-unknown")
.arg("--profile=wasm")
.arg("--manifest-path=".to_owned() + manifest_path.to_str().unwrap())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
// We are supposed to only generate artifacts under OUT_DIR,
// so set OUT_DIR as the target directory for this build.
.env("CARGO_TARGET_DIR", &out_dir)
// As we are being called inside a build-script, this env variable is set. However, we set
// our own `RUSTFLAGS` and thus, we need to remove this. Otherwise cargo favors this
// env variable.
.env_remove("CARGO_ENCODED_RUSTFLAGS");

// Print out the command line we're about to run.
println!("cargo:warning=cmd={:?}", &cmd);

// Launch the command.
let mut child = cmd.spawn().expect("failed to launch cargo build");

// Pipe the output as cargo warnings. Unfortunately this is the only way to
// get cargo build to print the output.
let stdout = child.stdout.take().expect("no stdout");
let stderr = child.stderr.take().expect("no stderr");
let j1 = thread::spawn(move || {
for line in BufReader::new(stderr).lines() {
println!("cargo:warning={:?}", line.unwrap());
}
});
let j2 = thread::spawn(move || {
for line in BufReader::new(stdout).lines() {
println!("cargo:warning={:?}", line.unwrap());
}
});

j1.join().unwrap();
j2.join().unwrap();

let result = child.wait().expect("failed to wait for build to finish");
if !result.success() {
return Err("actor build failed".into());
}

let dst = Path::new(&out_dir).join("bundle.car");
let mut bundler = Bundler::new(&dst);
for (&pkg, id) in ACTORS.iter().zip(1u32..) {
let bytecode_path = Path::new(&out_dir)
.join("wasm32-unknown-unknown/wasm")
.join(format!("fendermint_actor_{}.wasm", pkg));

// This actor version doesn't force synthetic CIDs; it uses genuine
// content-addressed CIDs.
let forced_cid = None;

let cid = bundler
.add_from_file(id, pkg.to_owned(), forced_cid, &bytecode_path)
.unwrap_or_else(|err| {
panic!("failed to add file {:?} to bundle for actor {}: {}", bytecode_path, id, err)
});
println!("cargo:warning=added {} ({}) to bundle with CID {}", pkg, id, cid);
}
bundler.finish().expect("failed to finish bundle");

println!("cargo:warning=bundle={}", dst.display());

Ok(())
}
26 changes: 26 additions & 0 deletions fendermint/actors/chainmetadata/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "fendermint_actor_chainmetadata"
description = "Actor for storing chain metadata"
license.workspace = true
edition.workspace = true
authors.workspace = true
version = "0.1.0"

[target.'cfg(target_arch = "wasm32")'.dependencies]
cid = { workspace = true, default-features = false }
frc42_dispatch = "5.0.0"
fvm_sdk = { workspace = true }
fvm_ipld_blockstore = { workspace = true }
fil_actors_runtime = { workspace = true }
fvm_shared = { workspace = true }
fvm_ipld_encoding = { workspace = true }
fvm_ipld_amt = { workspace = true }
getrandom = { version = "0.2.12", features = ["js"] }
serde = { workspace = true, features = ["derive"] }
serde_tuple = { workspace = true }
num-traits = { workspace = true }
num-derive = { workspace = true }


[lib]
crate-type = ["cdylib", "lib"]
89 changes: 89 additions & 0 deletions fendermint/actors/chainmetadata/src/actor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT

use cid::Cid;
use fil_actors_runtime::actor_dispatch;
use fil_actors_runtime::actor_error;
use fil_actors_runtime::runtime::{ActorCode, Runtime};
use fil_actors_runtime::ActorError;
use fvm_ipld_encoding::tuple::{Deserialize_tuple, Serialize_tuple};
use fvm_shared::METHOD_CONSTRUCTOR;
use num_derive::FromPrimitive;
use std::collections::VecDeque;

#[derive(Serialize_tuple, Deserialize_tuple)]
struct State {
blockhashes: VecDeque<Cid>,
params: ConstructorParams,
}

#[derive(Default, Debug, Serialize_tuple, Deserialize_tuple)]
struct ConstructorParams {
lookback_len: u64,
}

#[derive(FromPrimitive)]
#[repr(u64)]
pub enum Method {
Constructor = METHOD_CONSTRUCTOR,
PushBlock = 2,
LookbackLen = 3,
BlockCID = 4,
}

pub struct Actor;

impl Actor {
fn constructor(rt: &impl Runtime, params: ConstructorParams) -> Result<(), ActorError> {
let state = State {
blockhashes: VecDeque::new(),
params,
};
rt.create(&state)?;
Ok(())
}

fn push_block(rt: &impl Runtime, block: Cid) -> Result<(), ActorError> {
rt.transaction(|st: &mut State, _rt| {
st.blockhashes.push_back(block);
if st.blockhashes.len() > st.params.lookback_len as usize {
st.blockhashes.pop_front();
}

Ok(())
})?;

Ok(())
}

fn lookback_len(rt: &impl Runtime) -> Result<u64, ActorError> {
let state: State = rt.state()?;
Ok(state.params.lookback_len)
}

fn block_cid(rt: &impl Runtime, rewind: u64) -> Result<Cid, ActorError> {
let state: State = rt.state()?;
let block = state
.blockhashes
.get(state.blockhashes.len() - rewind as usize - 1)
.ok_or_else(|| actor_error!(illegal_argument; "lookback too large"))?;


Ok(*block)
}
}

impl ActorCode for Actor {
type Methods = Method;

fn name() -> &'static str {
"ChainMetadata"
}

actor_dispatch! {
Constructor => constructor,
PushBlock => push_block,
LookbackLen => lookback_len,
BlockCID => block_cid,
}
}
4 changes: 4 additions & 0 deletions fendermint/actors/chainmetadata/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
#[cfg(target_arch = "wasm32")]
mod actor;
2 changes: 2 additions & 0 deletions fendermint/actors/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Copyright 2022-2024 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT
2 changes: 1 addition & 1 deletion ipc/wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ libsecp256k1 = { workspace = true }
log = { workspace = true }
rand = { workspace = true }
serde = { workspace = true }
serde_ipld_dagcbor = "0.2"
serde_ipld_dagcbor = "0.4.2"
serde_json = { workspace = true }
thiserror = { workspace = true }
xsalsa20poly1305 = "0.9"
Expand Down

0 comments on commit ebfd26b

Please sign in to comment.