Skip to content

Commit

Permalink
Integrate chainmetadata actor in begin callback + use amt
Browse files Browse the repository at this point in the history
  • Loading branch information
fridrik01 committed Jan 22, 2024
1 parent 0e6b572 commit e72eb8c
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 42 deletions.
40 changes: 40 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ log = "0.4"
lru_time_cache = "0.11"
merkle-tree-rs = "0.1.0"
multiaddr = "0.18"
multihash = { version = "0.18.1", default-features = false, features = ["sha2"] }
multihash = { version = "0.18.1", default-features = false, features = [
"sha2",
] }
num-bigint = "0.4"
num-derive = "0.3"
num-traits = "0.2"
Expand Down Expand Up @@ -156,7 +158,7 @@ openssl = { version = "0.10", features = ["vendored"] }
# Using the 3.3 version of the FVM because the newer ones update the IPLD dependencies
# 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 = { version = "4.0.0", default-features = false } # no opencl feature or it fails on CI
fvm_shared = { version = "4.0.0" }
fvm_sdk = { version = "4.0.0" }

Expand Down Expand Up @@ -189,9 +191,7 @@ cid = { version = "0.10.1", default-features = false, features = [
"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.
# frc42_dispatch = "3.2"
frc42_dispatch = "5.0.0"

# Using the same tendermint-rs dependency as tower-abci. From both we are interested in v037 modules.
tower-abci = { version = "0.7" }
Expand Down
1 change: 1 addition & 0 deletions docs/fendermint/demos/milestone-1/fendermint-demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ rm -rf ~/.fendermint/data
mkdir -p ~/.fendermint/data
cp -r ./fendermint/app/config ~/.fendermint/config
cp ./builtin-actors/output/bundle.car ~/.fendermint/bundle.car
cp ./actors/output/actors_bundle.car ~/.fendermint/actors_bundle.car

#17
fendermint run
Expand Down
1 change: 1 addition & 0 deletions docs/fendermint/running.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ configuration will look for it at `~/.fendermint/bundle.car`, so we might as wel
```shell
make actor-bundle
cp ./builtin-actors/output/bundle.car ~/.fendermint/bundle.car
cp ./actors/output/actors_bundle.car ~/.fendermint/actors_bundle.car
```

Now, start the application.
Expand Down
4 changes: 4 additions & 0 deletions fendermint/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ $(BUILTIN_ACTORS_BUNDLE):
mkdir -p $(dir $@)
curl -L -o $@ https://github.com/filecoin-project/builtin-actors/releases/download/$(BUILTIN_ACTORS_TAG)/builtin-actors-mainnet.car

# Build a bundle CAR for the actors in this repo.
$(ACTORS_BUNDLE):
cargo build --release -p fendermint_actors

# Regenerate the ABI artifacts if we don't have them already, or they changed.
$(IPC_ACTORS_GEN): $(IPC_ACTORS_CODE)
cd $(IPC_ACTORS_DIR) && make compile-abi
Expand Down
1 change: 1 addition & 0 deletions fendermint/actors/chainmetadata/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ num-derive = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_tuple = { workspace = true }
num-traits = { workspace = true }
frc42_dispatch = { workspace = true }

[features]
fil-actor = []
89 changes: 75 additions & 14 deletions fendermint/actors/chainmetadata/src/actor.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
// Copyright 2021-2023 Protocol Labs
// SPDX-License-Identifier: Apache-2.0, MIT

use std::str::FromStr;

use cid::Cid;
use fil_actors_runtime::actor_dispatch;
use fil_actors_runtime::actor_error;
use fil_actors_runtime::builtin::singletons::SYSTEM_ACTOR_ADDR;
use fil_actors_runtime::runtime::{ActorCode, Runtime};
use fil_actors_runtime::ActorDowncast;
use fil_actors_runtime::ActorError;
use std::collections::VecDeque;
use fil_actors_runtime::Array;
use fvm_shared::error::ExitCode;

use crate::shared::BLOCKHASHES_AMT_BITWIDTH;
use crate::{ConstructorParams, Method, State};

#[cfg(feature = "fil-actor")]
Expand All @@ -17,21 +23,59 @@ pub struct Actor;

impl Actor {
fn constructor(rt: &impl Runtime, params: ConstructorParams) -> Result<(), ActorError> {
rt.validate_immediate_caller_is(std::iter::once(&SYSTEM_ACTOR_ADDR))?;

let empty_arr_cid =
Array::<(), _>::new_with_bit_width(rt.store(), BLOCKHASHES_AMT_BITWIDTH)
.flush()
.map_err(|e| {
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to create empty AMT")
})?;

let state = State {
blockhashes: VecDeque::new(),
params,
blockhashes: empty_arr_cid,
lookback_len: params.lookback_len,
};

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();
rt.validate_immediate_caller_is(std::iter::once(&SYSTEM_ACTOR_ADDR))?;

rt.transaction(|st: &mut State, rt| {
// load the blockhashes AMT
let mut blockhashes = Array::load(&st.blockhashes, rt.store()).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
"failed to load blockhashes states",
)
})?;

// push the block to the AMT
blockhashes
.set(rt.curr_epoch().try_into().unwrap(), block.to_string())
.unwrap();

// remove the oldest block if the AMT is full
if blockhashes.count() > st.lookback_len {
let mut first_idx = 0;
blockhashes
.for_each_while(|i, _: &String| {
first_idx = i;
Ok(false)
})
.unwrap();
blockhashes.delete(first_idx).unwrap();
}

// save the new blockhashes AMT cid root
st.blockhashes = blockhashes.flush().map_err(|e| {
e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to save blockhashes")
})?;

Ok(())
})?;

Expand All @@ -40,17 +84,34 @@ impl Actor {

fn lookback_len(rt: &impl Runtime) -> Result<u64, ActorError> {
let state: State = rt.state()?;
Ok(state.params.lookback_len)
Ok(state.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"))?;
let st: State = rt.state()?;

// load the blockhashes AMT
let blockhashes = Array::load(&st.blockhashes, rt.store()).map_err(|e| {
e.downcast_default(
ExitCode::USR_ILLEGAL_STATE,
"failed to load blockhashes states",
)
})?;

let blockhash: &String = blockhashes
.get(blockhashes.count() - rewind - 1)
.unwrap()
.unwrap();

Ok(*block)
Cid::from_str(blockhash.as_str()).map_err(|_| {
ActorError::unchecked(
ExitCode::USR_ILLEGAL_STATE,
format!(
"failed to parse cid, hash: {}, rewind: {}",
blockhash, rewind
),
)
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion fendermint/actors/chainmetadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
mod actor;
mod shared;

pub use shared::{ConstructorParams, Method, State};
pub use shared::*;
20 changes: 15 additions & 5 deletions fendermint/actors/chainmetadata/src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,24 @@ use cid::Cid;
use fvm_ipld_encoding::tuple::{Deserialize_tuple, Serialize_tuple};
use fvm_shared::METHOD_CONSTRUCTOR;
use num_derive::FromPrimitive;
use std::collections::VecDeque;

// The state is a stores `blockhashes` in an AMT containing the blockhashes of the
// last `lookback_len` epochs
#[derive(Serialize_tuple, Deserialize_tuple)]
pub struct State {
pub blockhashes: VecDeque<Cid>,
pub params: ConstructorParams,
// the AMT root cid of blockhashes
pub blockhashes: Cid,

// the maximum size of blockhashes before removing the oldest epoch
pub lookback_len: u64,
}

// the default lookback length is 256 epochs
pub const DEFAULT_LOOKBACK_LEN: u64 = 256;

// the default bitwidth of the blockhashes AMT
pub const BLOCKHASHES_AMT_BITWIDTH: u32 = 3;

#[derive(Default, Debug, Serialize_tuple, Deserialize_tuple)]
pub struct ConstructorParams {
pub lookback_len: u64,
Expand All @@ -23,6 +33,6 @@ pub struct ConstructorParams {
pub enum Method {
Constructor = METHOD_CONSTRUCTOR,
PushBlock = 2,
LookbackLen = 3,
BlockCID = 4,
LookbackLen = frc42_dispatch::method_hash!("LookbackLen"),
BlockCID = frc42_dispatch::method_hash!("BlockCID"),
}
2 changes: 1 addition & 1 deletion fendermint/actors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
// SPDX-License-Identifier: Apache-2.0, MIT
mod manifest;

pub use manifest::{Manifest, CHAINMETADATA_ACTOR_CODE_ID};
pub use manifest::{Manifest, CHAINMETADATA_ACTOR_CODE_ID, CHAINMETADATA_ACTOR_ID};
1 change: 1 addition & 0 deletions fendermint/actors/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct Manifest {
}

pub const CHAINMETADATA_ACTOR_CODE_ID: u32 = 1;
pub const CHAINMETADATA_ACTOR_ID: u64 = 48;

impl Manifest {
/// Load a manifest from the blockstore.
Expand Down
1 change: 1 addition & 0 deletions fendermint/docker/runner.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ ENV FM_ABCI__LISTEN__HOST=0.0.0.0
ENV FM_ETH__LISTEN__HOST=0.0.0.0

COPY fendermint/docker/.artifacts/bundle.car $FM_HOME_DIR/bundle.car
COPY fendermint/docker/.artifacts/actors_bundle.car $FM_HOME_DIR/actors_bundle.car
COPY fendermint/docker/.artifacts/contracts $FM_HOME_DIR/contracts
COPY --from=builder /app/fendermint/app/config $FM_HOME_DIR/config
COPY --from=builder /app/output/bin/fendermint /usr/local/bin/fendermint
1 change: 1 addition & 0 deletions fendermint/vm/interpreter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ fvm_shared = { workspace = true }
fvm_ipld_blockstore = { workspace = true }
fvm_ipld_encoding = { workspace = true }
fvm_ipld_car = { workspace = true }
fil_actors_runtime = { workspace = true }

futures-core = { workspace = true }
futures-util = { workspace = true }
Expand Down
21 changes: 21 additions & 0 deletions fendermint/vm/interpreter/src/fvm/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,27 @@ where
anyhow::bail!("failed to apply block cron message: {}", err);
}

// Push the current block hash to the chainmetadata actor
//
let block_cid = fendermint_vm_message::cid(&state.block_hash().unwrap()).unwrap();
let params = fvm_ipld_encoding::RawBytes::serialize(block_cid)?;
let msg = FvmMessage {
from: system::SYSTEM_ACTOR_ADDR,
to: fvm_shared::address::Address::new_id(fendermint_actors::CHAINMETADATA_ACTOR_ID),
sequence: height as u64,
gas_limit,
method_num: fendermint_actor_chainmetadata::Method::PushBlock as u64,
params,
value: Default::default(),
version: Default::default(),
gas_fee_cap: Default::default(),
gas_premium: Default::default(),
};
let (apply_ret, _) = state.execute_implicit(msg)?;
if let Some(err) = apply_ret.failure_info {
anyhow::bail!("failed to apply chainmetadata message: {}", err);
}

let ret = FvmApplyRet {
apply_ret,
from,
Expand Down
Loading

0 comments on commit e72eb8c

Please sign in to comment.