forest/rpc/methods/
misc.rs

1// Copyright 2019-2025 ChainSafe Systems
2// SPDX-License-Identifier: Apache-2.0, MIT
3
4use std::collections::BTreeMap;
5
6use cid::Cid;
7use enumflags2::BitFlags;
8use fvm_ipld_blockstore::Blockstore;
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11
12use crate::rpc::eth::CollectedEvent;
13use crate::rpc::eth::filter::{ParsedFilter, SkipEvent};
14use crate::{
15    blocks::TipsetKey,
16    lotus_json::{LotusJson, lotus_json_with_self},
17    rpc::{ApiPaths, Ctx, Permission, RpcMethod, ServerError, types::EventEntry},
18    shim::{address::Address, clock::ChainEpoch},
19};
20
21pub enum GetActorEventsRaw {}
22impl RpcMethod<1> for GetActorEventsRaw {
23    const NAME: &'static str = "Filecoin.GetActorEventsRaw";
24    const PARAM_NAMES: [&'static str; 1] = ["eventFilter"];
25    const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
26    const PERMISSION: Permission = Permission::Read;
27    const DESCRIPTION: Option<&'static str> = Some(
28        "Returns all user-programmed and built-in actor events that match the given filter. Results may be limited by MaxFilterResults, MaxFilterHeightRange, and the node's available historical data.",
29    );
30
31    type Params = (Option<ActorEventFilter>,);
32    type Ok = Vec<ActorEvent>;
33    async fn handle(
34        ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
35        (filter,): Self::Params,
36    ) -> Result<Self::Ok, ServerError> {
37        if let Some(filter) = filter {
38            let parsed_filter = ParsedFilter::from_actor_event_filter(
39                ctx.chain_store().heaviest_tipset().epoch(),
40                ctx.eth_event_handler.max_filter_height_range,
41                filter,
42            )?;
43            let events = ctx
44                .eth_event_handler
45                .get_events_for_parsed_filter(&ctx, &parsed_filter, SkipEvent::Never)
46                .await?;
47            Ok(events.into_iter().map(|ce| ce.into()).collect())
48        } else {
49            Ok(vec![])
50        }
51    }
52}
53
54#[derive(Clone, JsonSchema, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct ActorEventFilter {
57    #[serde(default, skip_serializing_if = "Vec::is_empty")]
58    pub addresses: Vec<LotusJson<Address>>,
59    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
60    pub fields: BTreeMap<String, Vec<ActorEventBlock>>,
61    #[serde(default, skip_serializing_if = "Option::is_none")]
62    pub from_height: Option<ChainEpoch>,
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub to_height: Option<ChainEpoch>,
65    #[serde(default, skip_serializing_if = "Option::is_none")]
66    pub tipset_key: Option<LotusJson<TipsetKey>>,
67}
68
69#[derive(Clone, JsonSchema, Serialize, Deserialize)]
70pub struct ActorEventBlock {
71    pub codec: u64,
72    pub value: LotusJson<Vec<u8>>,
73}
74
75#[derive(Debug, PartialEq, Clone, JsonSchema, Serialize, Deserialize)]
76#[serde(rename_all = "camelCase")]
77pub struct ActorEvent {
78    pub entries: Vec<EventEntry>,
79    pub emitter: LotusJson<Address>,
80    pub reverted: bool,
81    pub height: ChainEpoch,
82    pub tipset_key: LotusJson<TipsetKey>,
83    pub msg_cid: LotusJson<Cid>,
84}
85
86lotus_json_with_self! {
87    ActorEvent,
88    ActorEventFilter
89}
90
91impl From<CollectedEvent> for ActorEvent {
92    fn from(event: CollectedEvent) -> Self {
93        ActorEvent {
94            entries: event.entries,
95            emitter: LotusJson(event.emitter_addr),
96            reverted: event.reverted,
97            height: event.height,
98            tipset_key: LotusJson(event.tipset_key),
99            msg_cid: LotusJson(event.msg_cid),
100        }
101    }
102}