Skip to main content

forest/rpc/methods/
misc.rs

1// Copyright 2019-2026 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        _: &http::Extensions,
37    ) -> Result<Self::Ok, ServerError> {
38        if let Some(filter) = filter {
39            let parsed_filter = ParsedFilter::from_actor_event_filter(
40                ctx.chain_store().heaviest_tipset().epoch(),
41                ctx.eth_event_handler.max_filter_height_range,
42                filter,
43            )?;
44            let events = ctx
45                .eth_event_handler
46                .get_events_for_parsed_filter(&ctx, &parsed_filter, SkipEvent::Never)
47                .await?;
48            Ok(events.into_iter().map(|ce| ce.into()).collect())
49        } else {
50            Ok(vec![])
51        }
52    }
53}
54
55#[derive(Clone, JsonSchema, Serialize, Deserialize)]
56#[serde(rename_all = "camelCase")]
57pub struct ActorEventFilter {
58    #[serde(default, skip_serializing_if = "Vec::is_empty")]
59    pub addresses: Vec<LotusJson<Address>>,
60    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
61    pub fields: BTreeMap<String, Vec<ActorEventBlock>>,
62    #[serde(default, skip_serializing_if = "Option::is_none")]
63    pub from_height: Option<ChainEpoch>,
64    #[serde(default, skip_serializing_if = "Option::is_none")]
65    pub to_height: Option<ChainEpoch>,
66    #[serde(default, skip_serializing_if = "Option::is_none")]
67    pub tipset_key: Option<LotusJson<TipsetKey>>,
68}
69
70#[derive(Clone, JsonSchema, Serialize, Deserialize)]
71pub struct ActorEventBlock {
72    pub codec: u64,
73    pub value: LotusJson<Vec<u8>>,
74}
75
76#[derive(Debug, PartialEq, Clone, JsonSchema, Serialize, Deserialize)]
77#[serde(rename_all = "camelCase")]
78pub struct ActorEvent {
79    pub entries: Vec<EventEntry>,
80    pub emitter: LotusJson<Address>,
81    pub reverted: bool,
82    pub height: ChainEpoch,
83    pub tipset_key: LotusJson<TipsetKey>,
84    pub msg_cid: LotusJson<Cid>,
85}
86
87lotus_json_with_self! {
88    ActorEvent,
89    ActorEventFilter
90}
91
92impl From<CollectedEvent> for ActorEvent {
93    fn from(event: CollectedEvent) -> Self {
94        ActorEvent {
95            entries: event.entries,
96            emitter: LotusJson(event.emitter_addr),
97            reverted: event.reverted,
98            height: event.height,
99            tipset_key: LotusJson(event.tipset_key),
100            msg_cid: LotusJson(event.msg_cid),
101        }
102    }
103}