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