diff --git a/api/api_full.go b/api/api_full.go index 67aebce5ef0..5a1996e3745 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -888,17 +888,15 @@ type FullNode interface { // Actor events - // GetActorEvents returns all FEVM Actor events that match the given filter. - // This is a request/response API. Please see the docs for `ActorEventFilter` for a detailed - // description of the filter options. + // GetActorEvents returns all FVM and built-in Actor events that match the given filter. + // This is a request/response API. GetActorEvents(ctx context.Context, filter *types.ActorEventFilter) ([]*types.ActorEvent, error) //perm:read - // SubscribeActorEvents returns a long-lived stream of all FEVM Actor events that match the given filter. - // Events that match the given filter are written to the stream in real-time as they are emitted from the FEVM. + // SubscribeActorEvents returns a long-lived stream of all FVM and built-in Actor events that match the given filter. + // Events that match the given filter are written to the stream in real-time as they are emitted from the FVM. // The response stream is closed when the client disconnects or if there is an error while writing an event to the stream. // This API also allows clients to read all historical events matching the given filter before // any real-time events are written to the response stream. - // Please see the docs for `SubActorEventFilter` for a detailed description of the filter options. // NOTE: THIS API IS ONLY SUPPORTED OVER WEBSOCKETS FOR NOW SubscribeActorEvents(ctx context.Context, filter *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) //perm:read } diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index ce4aa6118db..1d37ed6e719 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -430,8 +430,8 @@ func init() { }, }, }, - FromBlock: pstring("2301220"), - ToBlock: pstring("latest"), + FromEpoch: "earliest", + ToEpoch: "latest", }) addExample(&types.SubActorEventFilter{ @@ -445,8 +445,8 @@ func init() { }, }, }, - FromBlock: pstring("2301220"), - ToBlock: pstring("latest"), + FromEpoch: "earliest", + ToEpoch: "latest", }, Prefill: true, }) diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index e7495c0f9f6..0529bf8efd5 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index 25a477a4ba3..19437a9280b 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/chain/types/actor_event.go b/chain/types/actor_event.go index d148bdd3cc5..97f4ff71144 100644 --- a/chain/types/actor_event.go +++ b/chain/types/actor_event.go @@ -23,6 +23,8 @@ type SubActorEventFilter struct { // If true, all available matching historical events will be written to the response stream // before any new real-time events that match the given filter are written. + // If `Prefill` is true and `FromEpoch` is set to latest, the pre-fill operation will become a no-op. + // if `Prefill` is false and `FromEpoch` is set to earliest, historical events will still be sent to the client. Prefill bool `json:"prefill"` } @@ -37,14 +39,14 @@ type ActorEventFilter struct { // Interpreted as an epoch (in hex) or one of "latest" for last mined block, "earliest" for first, // Optional, default: "latest". - FromBlock string `json:"fromBlock,omitempty"` + FromEpoch string `json:"fromEpoch,omitempty"` // Interpreted as an epoch (in hex) or one of "latest" for last mined block, "earliest" for first, // Optional, default: "latest". - ToBlock string `json:"toBlock,omitempty"` + ToEpoch string `json:"toEpoch,omitempty"` // Restricts events returned to those emitted from messages contained in this tipset. - // If `TipSetKey` is present in the filter criteria, then neither `FromBlock` nor `ToBlock` are allowed. + // If `TipSetCid` is present in the filter criteria, then neither `FromEpoch` nor `ToEpoch` are allowed. TipSetCid *cid.Cid `json:"tipsetCid,omitempty"` } diff --git a/chain/types/actor_event_test.go b/chain/types/actor_event_test.go index 5aefa688575..689091c0744 100644 --- a/chain/types/actor_event_test.go +++ b/chain/types/actor_event_test.go @@ -99,16 +99,16 @@ func TestSubActorEventFilterJson(t *testing.T) { }, }, }, - FromBlock: &from, - ToBlock: &to, - TipSetKey: &c, + FromEpoch: from, + ToEpoch: to, + TipSetCid: &c, } bz, err := json.Marshal(f) require.NoError(t, err) require.NotEmpty(t, bz) - s := `{"address":["f410fagkp3qx2f76maqot74jaiw3tzbxe76k76zrkl3xifk67isrnbn2sll3yua","f410fagkp3qx2f76maqot74jaiw3tzbxe76k76zrkl3xifk67isrnbn2sll3yua"],"fields":{"key1":[{"codec":81,"value":"dmFsdWUx"}],"key2":[{"codec":82,"value":"dmFsdWUy"}]},"fromBlock":"earliest","toBlock":"latest","tipset_cid":{"/":"bafkqacqbst64f6rp7taeduy"}}` + s := `{"addresses":["f410fagkp3qx2f76maqot74jaiw3tzbxe76k76zrkl3xifk67isrnbn2sll3yua","f410fagkp3qx2f76maqot74jaiw3tzbxe76k76zrkl3xifk67isrnbn2sll3yua"],"fields":{"key1":[{"codec":81,"value":"dmFsdWUx"}],"key2":[{"codec":82,"value":"dmFsdWUy"}]},"fromEpoch":"earliest","toEpoch":"latest","tipsetCid":{"/":"bafkqacqbst64f6rp7taeduy"}}` var out ActorEventFilter err = json.Unmarshal([]byte(s), &out) require.NoError(t, err) diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index a83810a625f..c1a8f6a31fa 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -3392,9 +3392,8 @@ Response: ### GetActorEvents -GetActorEvents returns all FEVM Actor events that match the given filter. -This is a request/response API. Please see the docs for `ActorEventFilter` for a detailed -description of the filter options. +GetActorEvents returns all FVM and built-in Actor events that match the given filter. +This is a request/response API. Perms: read @@ -3403,7 +3402,7 @@ Inputs: ```json [ { - "address": [ + "addresses": [ "f01234" ], "fields": { @@ -3414,8 +3413,8 @@ Inputs: } ] }, - "fromBlock": "2301220", - "toBlock": "latest" + "fromEpoch": "earliest", + "toEpoch": "latest" } ] ``` @@ -8714,12 +8713,11 @@ Response: ### SubscribeActorEvents -SubscribeActorEvents returns a long-lived stream of all FEVM Actor events that match the given filter. -Events that match the given filter are written to the stream in real-time as they are emitted from the FEVM. +SubscribeActorEvents returns a long-lived stream of all FVM and built-in Actor events that match the given filter. +Events that match the given filter are written to the stream in real-time as they are emitted from the FVM. The response stream is closed when the client disconnects or if there is an error while writing an event to the stream. This API also allows clients to read all historical events matching the given filter before any real-time events are written to the response stream. -Please see the docs for `SubActorEventFilter` for a detailed description of the filter options. NOTE: THIS API IS ONLY SUPPORTED OVER WEBSOCKETS FOR NOW @@ -8730,7 +8728,7 @@ Inputs: [ { "filter": { - "address": [ + "addresses": [ "f01234" ], "fields": { @@ -8741,8 +8739,8 @@ Inputs: } ] }, - "fromBlock": "2301220", - "toBlock": "latest" + "fromEpoch": "earliest", + "toEpoch": "latest" }, "prefill": true } diff --git a/itests/direct_data_onboard_test.go b/itests/direct_data_onboard_test.go index 112efe7b8b8..f769bdfb4b6 100644 --- a/itests/direct_data_onboard_test.go +++ b/itests/direct_data_onboard_test.go @@ -328,14 +328,14 @@ func TestOnboardRawPieceVerified(t *testing.T) { require.NoError(t, err) require.Len(t, allocations, 0) eventsFromMessages := buildActorEventsFromMessages(ctx, t, miner.FullNode) + fmt.Println("eventsFromMessages", eventsFromMessages) writeEventsToFile(ctx, t, miner.FullNode, eventsFromMessages) /* --- Tests for the Actor events API --- */ - pstring := func(s string) *string { return &s } // Match events from Get API and receipts allEvtsFromGetAPI, err := miner.FullNode.GetActorEvents(ctx, &types.ActorEventFilter{ - FromBlock: pstring("earliest"), - ToBlock: pstring("latest"), + FromEpoch: "earliest", + ToEpoch: "latest", }) require.NoError(t, err) matchEvents(t, eventsFromMessages, getEventsArray(allEvtsFromGetAPI)) @@ -379,8 +379,8 @@ func TestOnboardRawPieceVerified(t *testing.T) { // Match pre-filled events from subscription channel and events obtained from receipts allEvtsCh, err := miner.FullNode.SubscribeActorEvents(ctx, &types.SubActorEventFilter{ Filter: types.ActorEventFilter{ - FromBlock: pstring("earliest"), - ToBlock: pstring("latest"), + FromEpoch: "earliest", + ToEpoch: "latest", }, Prefill: true, }) @@ -427,6 +427,8 @@ func matchEvents(t *testing.T, exp []types.ActorEvent, actual []types.ActorEvent sort.Slice(bz2, func(i, j int) bool { return bz2[i] <= bz2[j] }) + fmt.Println("bz1", string(bz1)) + fmt.Println("bz2", string(bz2)) require.True(t, bytes.Equal(bz1, bz2)) } diff --git a/node/impl/full/actor_event.go b/node/impl/full/actor_event.go index 1958e3569fa..ce555d6d235 100644 --- a/node/impl/full/actor_event.go +++ b/node/impl/full/actor_event.go @@ -3,6 +3,7 @@ package full import ( "context" "fmt" + "strings" "github.com/ipfs/go-cid" "go.uber.org/fx" @@ -49,7 +50,7 @@ func (a *ActorEvent) GetActorEvents(ctx context.Context, filter *types.ActorEven } // Create a temporary filter - f, err := a.EventFilterManager.Install(ctx, params.MinHeight, params.MaxHeight, params.TipSetKey, filter.Addresses, filter.Fields, false) + f, err := a.EventFilterManager.Install(ctx, params.MinHeight, params.MaxHeight, params.TipSetCid, filter.Addresses, filter.Fields, false) if err != nil { return nil, err } @@ -62,29 +63,41 @@ func (a *ActorEvent) GetActorEvents(ctx context.Context, filter *types.ActorEven type filterParams struct { MinHeight abi.ChainEpoch MaxHeight abi.ChainEpoch - TipSetKey cid.Cid + TipSetCid cid.Cid } func (a *ActorEvent) parseFilter(f *types.ActorEventFilter) (*filterParams, error) { - if f.TipSetKey != nil { - if f.FromBlock != nil || f.ToBlock != nil { - return nil, fmt.Errorf("cannot specify both TipSetKey and FromBlock/ToBlock") + if f.TipSetCid != nil { + if len(f.FromEpoch) != 0 || len(f.ToEpoch) != 0 { + return nil, fmt.Errorf("cannot specify both TipSetCid and FromEpoch/ToEpoch") } return &filterParams{ MinHeight: 0, MaxHeight: 0, - TipSetKey: *f.TipSetKey, + TipSetCid: *f.TipSetCid, }, nil } - min, max, err := parseBlockRange(a.Chain.GetHeaviestTipSet().Height(), f.FromBlock, f.ToBlock, a.MaxFilterHeightRange) + + from := f.FromEpoch + if len(from) != 0 && from != "latest" && from != "earliest" && !strings.HasPrefix(from, "0x") { + from = "0x" + from + } + + to := f.ToEpoch + if len(to) != 0 && to != "latest" && to != "earliest" && !strings.HasPrefix(to, "0x") { + to = "0x" + to + } + + min, max, err := parseBlockRange(a.Chain.GetHeaviestTipSet().Height(), &from, &to, a.MaxFilterHeightRange) if err != nil { return nil, err } + return &filterParams{ MinHeight: min, MaxHeight: max, - TipSetKey: cid.Undef, + TipSetCid: cid.Undef, }, nil } @@ -98,7 +111,7 @@ func (a *ActorEvent) SubscribeActorEvents(ctx context.Context, f *types.SubActor return nil, err } - fm, err := a.EventFilterManager.Install(ctx, params.MinHeight, params.MaxHeight, params.TipSetKey, f.Filter.Addresses, f.Filter.Fields, false) + fm, err := a.EventFilterManager.Install(ctx, params.MinHeight, params.MaxHeight, params.TipSetCid, f.Filter.Addresses, f.Filter.Fields, false) if err != nil { return nil, err } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index f517a92605d..b212b2bdf41 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -1264,7 +1264,7 @@ func (e *EthEvent) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID } func parseBlockRange(heaviest abi.ChainEpoch, fromBlock, toBlock *string, maxRange abi.ChainEpoch) (minHeight abi.ChainEpoch, maxHeight abi.ChainEpoch, err error) { - if fromBlock == nil || *fromBlock == "latest" { + if fromBlock == nil || *fromBlock == "latest" || len(*fromBlock) == 0 { minHeight = heaviest } else if *fromBlock == "earliest" { minHeight = 0 @@ -1279,7 +1279,7 @@ func parseBlockRange(heaviest abi.ChainEpoch, fromBlock, toBlock *string, maxRan minHeight = abi.ChainEpoch(epoch) } - if toBlock == nil || *toBlock == "latest" { + if toBlock == nil || *toBlock == "latest" || len(*toBlock) == 0 { // here latest means the latest at the time maxHeight = -1 } else if *toBlock == "earliest" {