Skip to content

Commit

Permalink
feat(rpc): implement Filecoin.F3GetOrRenewParticipationTicket and Fil…
Browse files Browse the repository at this point in the history
…ecoin.F3Participate (#4920)
  • Loading branch information
hanabi1224 authored Oct 23, 2024
1 parent 13ea026 commit 678c996
Show file tree
Hide file tree
Showing 8 changed files with 422 additions and 159 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,20 @@
- [#4910](https://github.com/ChainSafe/forest/issues/4910) Add support for the
`Filecoin.F3ListParticipants` RPC method.

- [#4920](https://github.com/ChainSafe/forest/issues/4920) Add support for the
`Filecoin.F3GetOrRenewParticipationTicket` RPC method.

- [#4917](https://github.com/ChainSafe/forest/issues/4917) Support `dnsaddr` in
the bootstrap list.

### Changed

- [#4920](https://github.com/ChainSafe/forest/issues/4920) Update
`Filecoin.F3Participate` RPC method to align with the spec change.

- [#4920](https://github.com/ChainSafe/forest/issues/4920) Update
`Filecoin.F3ListParticipants` RPC method to align with the spec change.

### Removed

### Fixed
Expand Down
8 changes: 8 additions & 0 deletions src/daemon/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ pub(super) async fn start(
let start_time = chrono::Utc::now();
let path: PathBuf = config.client.data_dir.join("libp2p");
let net_keypair = crate::libp2p::keypair::get_or_create_keypair(&path)?;
let p2p_peer_id = net_keypair.public().to_peer_id();

let mut keystore = load_or_create_keystore(&config).await?;

Expand Down Expand Up @@ -414,7 +415,14 @@ pub(super) async fn start(
.await
});

// Run F3 sidecar
services.spawn_blocking({
crate::rpc::f3::F3_LEASE_MANAGER
.set(crate::rpc::f3::F3LeaseManager::new(
chain_config.network.clone(),
p2p_peer_id,
))
.expect("F3 lease manager should not have been initialized before");
let chain_config = chain_config.clone();
let default_f3_root = config.client.data_dir.join(format!("f3/{}", config.chain));
let crate::f3::F3Options {
Expand Down
134 changes: 86 additions & 48 deletions src/rpc/methods/f3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
mod types;
mod util;

pub use self::types::F3LeaseManager;
use self::{types::*, util::*};
use super::wallet::WalletSign;
use crate::{
Expand All @@ -25,7 +26,7 @@ use crate::{
utils::misc::env::is_env_set_and_truthy,
};
use ahash::{HashMap, HashSet};
use anyhow::Context as _;
use anyhow::Context;
use fil_actor_interface::{
convert::{
from_policy_v13_to_v10, from_policy_v13_to_v11, from_policy_v13_to_v12,
Expand All @@ -37,11 +38,11 @@ use fvm_ipld_blockstore::Blockstore;
use jsonrpsee::core::{client::ClientT as _, params::ArrayParams};
use libp2p::PeerId;
use num::Signed as _;
use once_cell::sync::Lazy;
use once_cell::sync::OnceCell;
use parking_lot::RwLock;
use std::{borrow::Cow, fmt::Display, num::NonZeroU64, str::FromStr as _, sync::Arc};

static F3_LEASE_MANAGER: Lazy<F3LeaseManager> = Lazy::new(Default::default);
pub static F3_LEASE_MANAGER: OnceCell<F3LeaseManager> = OnceCell::new();

pub enum GetTipsetByEpoch {}
impl RpcMethod<1> for GetTipsetByEpoch {
Expand Down Expand Up @@ -437,16 +438,6 @@ impl RpcMethod<1> for ProtectPeer {

pub enum GetParticipatingMinerIDs {}

impl GetParticipatingMinerIDs {
fn run() -> Vec<u64> {
let mut ids = F3_LEASE_MANAGER.get_active_participants();
if let Some(permanent_miner_ids) = (*F3_PERMANENT_PARTICIPATING_MINER_IDS).clone() {
ids.extend(permanent_miner_ids);
}
ids.into_iter().collect()
}
}

impl RpcMethod<0> for GetParticipatingMinerIDs {
const NAME: &'static str = "F3.GetParticipatingMinerIDs";
const PARAM_NAMES: [&'static str; 0] = [];
Expand All @@ -457,7 +448,12 @@ impl RpcMethod<0> for GetParticipatingMinerIDs {
type Ok = Vec<u64>;

async fn handle(_: Ctx<impl Blockstore>, _: Self::Params) -> Result<Self::Ok, ServerError> {
Ok(Self::run())
let participants = F3ListParticipants::run().await?;
let mut ids: HashSet<u64> = participants.into_iter().map(|p| p.miner_id).collect();
if let Some(permanent_miner_ids) = (*F3_PERMANENT_PARTICIPATING_MINER_IDS).clone() {
ids.extend(permanent_miner_ids);
}
Ok(ids.into_iter().collect())
}
}

Expand Down Expand Up @@ -650,19 +646,26 @@ impl RpcMethod<0> for F3IsRunning {

/// See <https://github.com/filecoin-project/lotus/blob/master/documentation/en/api-v1-unstable-methods.md#F3GetProgress>
pub enum F3GetProgress {}

impl F3GetProgress {
async fn run() -> anyhow::Result<F3Instant> {
let client = get_rpc_http_client()?;
let response = client.request(Self::NAME, ArrayParams::new()).await?;
Ok(response)
}
}

impl RpcMethod<0> for F3GetProgress {
const NAME: &'static str = "Filecoin.F3GetProgress";
const PARAM_NAMES: [&'static str; 0] = [];
const API_PATHS: ApiPaths = ApiPaths::V1;
const PERMISSION: Permission = Permission::Read;

type Params = ();
type Ok = serde_json::Value;
type Ok = F3Instant;

async fn handle(_: Ctx<impl Blockstore>, (): Self::Params) -> Result<Self::Ok, ServerError> {
let client = get_rpc_http_client()?;
let response = client.request(Self::NAME, ArrayParams::new()).await?;
Ok(response)
Ok(Self::run().await?)
}
}

Expand All @@ -675,50 +678,85 @@ impl RpcMethod<0> for F3ListParticipants {
const PERMISSION: Permission = Permission::Read;

type Params = ();
type Ok = Vec<Address>;
type Ok = Vec<F3Participant>;

async fn handle(_: Ctx<impl Blockstore>, _: Self::Params) -> Result<Self::Ok, ServerError> {
let ids = GetParticipatingMinerIDs::run();
Ok(ids.into_iter().map(Address::new_id).collect())
Ok(Self::run().await?)
}
}

impl F3ListParticipants {
async fn run() -> anyhow::Result<Vec<F3Participant>> {
let current_instance = F3GetProgress::run().await?.id;
Ok(F3_LEASE_MANAGER
.get()
.context("F3 lease manager is not initialized")?
.get_active_participants(current_instance)
.values()
.map(F3Participant::from)
.collect())
}
}

/// retrieves or renews a participation ticket necessary for a miner to engage in
/// the F3 consensus process for the given number of instances.
pub enum F3GetOrRenewParticipationTicket {}
impl RpcMethod<3> for F3GetOrRenewParticipationTicket {
const NAME: &'static str = "Filecoin.F3GetOrRenewParticipationTicket";
const PARAM_NAMES: [&'static str; 3] = ["miner_address", "previous_lease_ticket", "instances"];
const API_PATHS: ApiPaths = ApiPaths::V1;
const PERMISSION: Permission = Permission::Sign;

type Params = (Address, Vec<u8>, u64);
type Ok = Vec<u8>;

async fn handle(
_: Ctx<impl Blockstore>,
(miner, previous_lease_ticket, instances): Self::Params,
) -> Result<Self::Ok, ServerError> {
let id = miner.id()?;
let previous_lease = if previous_lease_ticket.is_empty() {
None
} else {
Some(
fvm_ipld_encoding::from_slice::<F3ParticipationLease>(&previous_lease_ticket)
.context("the previous lease ticket is invalid")?,
)
};
let lease = F3_LEASE_MANAGER
.get()
.context("F3 lease manager is not initialized")?
.get_or_renew_participation_lease(id, previous_lease, instances)
.await?;
Ok(fvm_ipld_encoding::to_vec(&lease)?)
}
}

/// F3Participate should be called by a storage provider to participate in signing F3 consensus.
/// Calling this API gives the node a lease to sign in F3 on behalf of given SP.
/// The lease should be active only on one node. The lease will expire at the newLeaseExpiration.
/// To continue participating in F3 with the given node, call F3Participate again before the newLeaseExpiration time.
/// newLeaseExpiration cannot be further than 5 minutes in the future.
/// It is recommended to call F3Participate every 60 seconds with newLeaseExpiration set 2min into the future.
/// The oldLeaseExpiration has to be set to newLeaseExpiration of the last successful call.
/// For the first call to F3Participate, set the oldLeaseExpiration to zero value/time in the past.
/// F3Participate will return true if the lease was accepted. The minerID has to be the ID address of the miner.
/// enrolls a storage provider in the F3 consensus process using a
/// provided participation ticket. This ticket grants a temporary lease that enables
/// the provider to sign transactions as part of the F3 consensus.
pub enum F3Participate {}
impl RpcMethod<3> for F3Participate {
impl RpcMethod<1> for F3Participate {
const NAME: &'static str = "Filecoin.F3Participate";
const PARAM_NAMES: [&'static str; 3] = [
"miner_address",
"new_lease_expiration",
"old_lease_expiration",
];
const PARAM_NAMES: [&'static str; 1] = ["lease_ticket"];
const API_PATHS: ApiPaths = ApiPaths::V1;
const PERMISSION: Permission = Permission::Sign;

type Params = (
Address,
chrono::DateTime<chrono::Utc>,
chrono::DateTime<chrono::Utc>,
);
type Ok = bool;
type Params = (Vec<u8>,);
type Ok = F3ParticipationLease;

async fn handle(
_: Ctx<impl Blockstore>,
(miner, new_lease_expiration, old_lease_expiration): Self::Params,
(lease_ticket,): Self::Params,
) -> Result<Self::Ok, ServerError> {
Ok(F3_LEASE_MANAGER.upsert_defensive(
miner.id()?,
new_lease_expiration,
old_lease_expiration,
)?)
let lease: F3ParticipationLease =
fvm_ipld_encoding::from_slice(&lease_ticket).context("invalid lease ticket")?;
let current_instance = F3GetProgress::run().await?.id;
F3_LEASE_MANAGER
.get()
.context("F3 lease manager is not initialized")?
.participate(&lease, current_instance)?;
Ok(lease)
}
}

Expand Down
Loading

0 comments on commit 678c996

Please sign in to comment.