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::db::EthMappingsStore;
13use crate::rpc::eth::CollectedEvent;
14use crate::rpc::eth::filter::{ParsedFilter, SkipEvent};
15use crate::{
16    blocks::TipsetKey,
17    lotus_json::{LotusJson, lotus_json_with_self},
18    rpc::{ApiPaths, Ctx, Permission, RpcMethod, ServerError, types::EventEntry},
19    shim::{address::Address, clock::ChainEpoch},
20};
21
22pub enum GetActorEventsRaw {}
23impl RpcMethod<1> for GetActorEventsRaw {
24    const NAME: &'static str = "Filecoin.GetActorEventsRaw";
25    const PARAM_NAMES: [&'static str; 1] = ["eventFilter"];
26    const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
27    const PERMISSION: Permission = Permission::Read;
28    const DESCRIPTION: Option<&'static str> = Some(
29        "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.",
30    );
31
32    type Params = (Option<ActorEventFilter>,);
33    type Ok = Vec<ActorEvent>;
34    async fn handle(
35        ctx: Ctx<impl Blockstore + EthMappingsStore + Send + Sync + 'static>,
36        (filter,): Self::Params,
37        _: &http::Extensions,
38    ) -> Result<Self::Ok, ServerError> {
39        if let Some(filter) = filter {
40            let parsed_filter = ParsedFilter::from_actor_event_filter(
41                ctx.chain_store().heaviest_tipset().epoch(),
42                ctx.eth_event_handler.max_filter_height_range,
43                filter,
44            )?;
45            let events = ctx
46                .eth_event_handler
47                .get_events_for_parsed_filter(&ctx, &parsed_filter, SkipEvent::Never)
48                .await?;
49            Ok(events.into_iter().map(|ce| ce.into()).collect())
50        } else {
51            Ok(vec![])
52        }
53    }
54}
55
56#[derive(Clone, JsonSchema, Serialize, Deserialize)]
57#[serde(rename_all = "camelCase")]
58pub struct ActorEventFilter {
59    #[serde(default, skip_serializing_if = "Vec::is_empty")]
60    pub addresses: Vec<LotusJson<Address>>,
61    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
62    pub fields: BTreeMap<String, Vec<ActorEventBlock>>,
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub from_height: Option<ChainEpoch>,
65    #[serde(default, skip_serializing_if = "Option::is_none")]
66    pub to_height: Option<ChainEpoch>,
67    #[serde(default, skip_serializing_if = "Option::is_none")]
68    pub tipset_key: Option<LotusJson<TipsetKey>>,
69}
70
71#[derive(Clone, JsonSchema, Serialize, Deserialize)]
72pub struct ActorEventBlock {
73    pub codec: u64,
74    pub value: LotusJson<Vec<u8>>,
75}
76
77#[derive(Debug, PartialEq, Clone, JsonSchema, Serialize, Deserialize)]
78#[serde(rename_all = "camelCase")]
79pub struct ActorEvent {
80    pub entries: Vec<EventEntry>,
81    pub emitter: LotusJson<Address>,
82    pub reverted: bool,
83    pub height: ChainEpoch,
84    pub tipset_key: LotusJson<TipsetKey>,
85    pub msg_cid: LotusJson<Cid>,
86}
87
88lotus_json_with_self! {
89    ActorEvent,
90    ActorEventFilter
91}
92
93impl From<CollectedEvent> for ActorEvent {
94    fn from(event: CollectedEvent) -> Self {
95        ActorEvent {
96            entries: event.entries,
97            emitter: LotusJson(event.emitter_addr),
98            reverted: event.reverted,
99            height: event.height,
100            tipset_key: LotusJson(event.tipset_key),
101            msg_cid: LotusJson(event.msg_cid),
102        }
103    }
104}