Built-in actor events first draft
This commit is contained in:
parent
9aef2ec8b5
commit
f007a012af
@ -906,6 +906,20 @@ type FullNode interface {
|
|||||||
|
|
||||||
RaftState(ctx context.Context) (*RaftStateData, error) //perm:read
|
RaftState(ctx context.Context) (*RaftStateData, error) //perm:read
|
||||||
RaftLeader(ctx context.Context) (peer.ID, error) //perm:read
|
RaftLeader(ctx context.Context) (peer.ID, error) //perm:read
|
||||||
|
|
||||||
|
// Actor events
|
||||||
|
|
||||||
|
// 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 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.
|
||||||
|
// NOTE: THIS API IS ONLY SUPPORTED OVER WEBSOCKETS FOR NOW
|
||||||
|
SubscribeActorEvents(ctx context.Context, filter *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) //perm:read
|
||||||
}
|
}
|
||||||
|
|
||||||
// reverse interface to the client, called after EthSubscribe
|
// reverse interface to the client, called after EthSubscribe
|
||||||
|
@ -129,4 +129,7 @@ type Gateway interface {
|
|||||||
Web3ClientVersion(ctx context.Context) (string, error)
|
Web3ClientVersion(ctx context.Context) (string, error)
|
||||||
EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error)
|
EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error)
|
||||||
EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error)
|
EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error)
|
||||||
|
|
||||||
|
GetActorEvents(ctx context.Context, filter *types.ActorEventFilter) ([]*types.ActorEvent, error)
|
||||||
|
SubscribeActorEvents(ctx context.Context, filter *types.SubActorEventFilter) (<-chan *types.ActorEvent, error)
|
||||||
}
|
}
|
||||||
|
@ -414,6 +414,42 @@ func init() {
|
|||||||
VerifiedAllocationKey: nil,
|
VerifiedAllocationKey: nil,
|
||||||
Notify: nil,
|
Notify: nil,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
addExample(&types.ActorEventBlock{
|
||||||
|
Codec: 0x51,
|
||||||
|
Value: []byte("data"),
|
||||||
|
})
|
||||||
|
|
||||||
|
addExample(&types.ActorEventFilter{
|
||||||
|
Addresses: []address.Address{addr},
|
||||||
|
Fields: map[string][]types.ActorEventBlock{
|
||||||
|
"abc": {
|
||||||
|
{
|
||||||
|
Codec: 0x51,
|
||||||
|
Value: []byte("data"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MinEpoch: 2301220,
|
||||||
|
MaxEpoch: 2301220,
|
||||||
|
})
|
||||||
|
|
||||||
|
addExample(&types.SubActorEventFilter{
|
||||||
|
Filter: types.ActorEventFilter{
|
||||||
|
Addresses: []address.Address{addr},
|
||||||
|
Fields: map[string][]types.ActorEventBlock{
|
||||||
|
"abc": {
|
||||||
|
{
|
||||||
|
Codec: 0x51,
|
||||||
|
Value: []byte("data"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MinEpoch: 2301220,
|
||||||
|
MaxEpoch: 2301220,
|
||||||
|
},
|
||||||
|
Prefill: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []reflect.Type) {
|
func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []reflect.Type) {
|
||||||
|
@ -1626,6 +1626,21 @@ func (mr *MockFullNodeMockRecorder) GasEstimateMessageGas(arg0, arg1, arg2, arg3
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GasEstimateMessageGas", reflect.TypeOf((*MockFullNode)(nil).GasEstimateMessageGas), arg0, arg1, arg2, arg3)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GasEstimateMessageGas", reflect.TypeOf((*MockFullNode)(nil).GasEstimateMessageGas), arg0, arg1, arg2, arg3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetActorEvents mocks base method.
|
||||||
|
func (m *MockFullNode) GetActorEvents(arg0 context.Context, arg1 *types.ActorEventFilter) ([]*types.ActorEvent, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetActorEvents", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].([]*types.ActorEvent)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetActorEvents indicates an expected call of GetActorEvents.
|
||||||
|
func (mr *MockFullNodeMockRecorder) GetActorEvents(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActorEvents", reflect.TypeOf((*MockFullNode)(nil).GetActorEvents), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// ID mocks base method.
|
// ID mocks base method.
|
||||||
func (m *MockFullNode) ID(arg0 context.Context) (peer.ID, error) {
|
func (m *MockFullNode) ID(arg0 context.Context) (peer.ID, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@ -3968,6 +3983,21 @@ func (mr *MockFullNodeMockRecorder) StateWaitMsg(arg0, arg1, arg2, arg3, arg4 in
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateWaitMsg", reflect.TypeOf((*MockFullNode)(nil).StateWaitMsg), arg0, arg1, arg2, arg3, arg4)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateWaitMsg", reflect.TypeOf((*MockFullNode)(nil).StateWaitMsg), arg0, arg1, arg2, arg3, arg4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubscribeActorEvents mocks base method.
|
||||||
|
func (m *MockFullNode) SubscribeActorEvents(arg0 context.Context, arg1 *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "SubscribeActorEvents", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(<-chan *types.ActorEvent)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscribeActorEvents indicates an expected call of SubscribeActorEvents.
|
||||||
|
func (mr *MockFullNodeMockRecorder) SubscribeActorEvents(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubscribeActorEvents", reflect.TypeOf((*MockFullNode)(nil).SubscribeActorEvents), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// SyncCheckBad mocks base method.
|
// SyncCheckBad mocks base method.
|
||||||
func (m *MockFullNode) SyncCheckBad(arg0 context.Context, arg1 cid.Cid) (string, error) {
|
func (m *MockFullNode) SyncCheckBad(arg0 context.Context, arg1 cid.Cid) (string, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -335,6 +335,8 @@ type FullNodeMethods struct {
|
|||||||
|
|
||||||
GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `perm:"read"`
|
GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) `perm:"read"`
|
||||||
|
|
||||||
|
GetActorEvents func(p0 context.Context, p1 *types.ActorEventFilter) ([]*types.ActorEvent, error) `perm:"read"`
|
||||||
|
|
||||||
MarketAddBalance func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"`
|
MarketAddBalance func(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) `perm:"sign"`
|
||||||
|
|
||||||
MarketGetReserved func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"sign"`
|
MarketGetReserved func(p0 context.Context, p1 address.Address) (types.BigInt, error) `perm:"sign"`
|
||||||
@ -589,6 +591,8 @@ type FullNodeMethods struct {
|
|||||||
|
|
||||||
StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `perm:"read"`
|
StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) `perm:"read"`
|
||||||
|
|
||||||
|
SubscribeActorEvents func(p0 context.Context, p1 *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) `perm:"read"`
|
||||||
|
|
||||||
SyncCheckBad func(p0 context.Context, p1 cid.Cid) (string, error) `perm:"read"`
|
SyncCheckBad func(p0 context.Context, p1 cid.Cid) (string, error) `perm:"read"`
|
||||||
|
|
||||||
SyncCheckpoint func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"`
|
SyncCheckpoint func(p0 context.Context, p1 types.TipSetKey) error `perm:"admin"`
|
||||||
@ -755,6 +759,8 @@ type GatewayMethods struct {
|
|||||||
|
|
||||||
GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) ``
|
GasEstimateMessageGas func(p0 context.Context, p1 *types.Message, p2 *MessageSendSpec, p3 types.TipSetKey) (*types.Message, error) ``
|
||||||
|
|
||||||
|
GetActorEvents func(p0 context.Context, p1 *types.ActorEventFilter) ([]*types.ActorEvent, error) ``
|
||||||
|
|
||||||
MinerGetBaseInfo func(p0 context.Context, p1 address.Address, p2 abi.ChainEpoch, p3 types.TipSetKey) (*MiningBaseInfo, error) ``
|
MinerGetBaseInfo func(p0 context.Context, p1 address.Address, p2 abi.ChainEpoch, p3 types.TipSetKey) (*MiningBaseInfo, error) ``
|
||||||
|
|
||||||
MpoolGetNonce func(p0 context.Context, p1 address.Address) (uint64, error) ``
|
MpoolGetNonce func(p0 context.Context, p1 address.Address) (uint64, error) ``
|
||||||
@ -829,6 +835,8 @@ type GatewayMethods struct {
|
|||||||
|
|
||||||
StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) ``
|
StateWaitMsg func(p0 context.Context, p1 cid.Cid, p2 uint64, p3 abi.ChainEpoch, p4 bool) (*MsgLookup, error) ``
|
||||||
|
|
||||||
|
SubscribeActorEvents func(p0 context.Context, p1 *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) ``
|
||||||
|
|
||||||
Version func(p0 context.Context) (APIVersion, error) ``
|
Version func(p0 context.Context) (APIVersion, error) ``
|
||||||
|
|
||||||
WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) ``
|
WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) ``
|
||||||
@ -2584,6 +2592,17 @@ func (s *FullNodeStub) GasEstimateMessageGas(p0 context.Context, p1 *types.Messa
|
|||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) GetActorEvents(p0 context.Context, p1 *types.ActorEventFilter) ([]*types.ActorEvent, error) {
|
||||||
|
if s.Internal.GetActorEvents == nil {
|
||||||
|
return *new([]*types.ActorEvent), ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.GetActorEvents(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) GetActorEvents(p0 context.Context, p1 *types.ActorEventFilter) ([]*types.ActorEvent, error) {
|
||||||
|
return *new([]*types.ActorEvent), ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) MarketAddBalance(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) {
|
func (s *FullNodeStruct) MarketAddBalance(p0 context.Context, p1 address.Address, p2 address.Address, p3 types.BigInt) (cid.Cid, error) {
|
||||||
if s.Internal.MarketAddBalance == nil {
|
if s.Internal.MarketAddBalance == nil {
|
||||||
return *new(cid.Cid), ErrNotSupported
|
return *new(cid.Cid), ErrNotSupported
|
||||||
@ -3981,6 +4000,17 @@ func (s *FullNodeStub) StateWaitMsg(p0 context.Context, p1 cid.Cid, p2 uint64, p
|
|||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) SubscribeActorEvents(p0 context.Context, p1 *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) {
|
||||||
|
if s.Internal.SubscribeActorEvents == nil {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.SubscribeActorEvents(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) SubscribeActorEvents(p0 context.Context, p1 *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) SyncCheckBad(p0 context.Context, p1 cid.Cid) (string, error) {
|
func (s *FullNodeStruct) SyncCheckBad(p0 context.Context, p1 cid.Cid) (string, error) {
|
||||||
if s.Internal.SyncCheckBad == nil {
|
if s.Internal.SyncCheckBad == nil {
|
||||||
return "", ErrNotSupported
|
return "", ErrNotSupported
|
||||||
@ -4828,6 +4858,17 @@ func (s *GatewayStub) GasEstimateMessageGas(p0 context.Context, p1 *types.Messag
|
|||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *GatewayStruct) GetActorEvents(p0 context.Context, p1 *types.ActorEventFilter) ([]*types.ActorEvent, error) {
|
||||||
|
if s.Internal.GetActorEvents == nil {
|
||||||
|
return *new([]*types.ActorEvent), ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.GetActorEvents(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GatewayStub) GetActorEvents(p0 context.Context, p1 *types.ActorEventFilter) ([]*types.ActorEvent, error) {
|
||||||
|
return *new([]*types.ActorEvent), ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
func (s *GatewayStruct) MinerGetBaseInfo(p0 context.Context, p1 address.Address, p2 abi.ChainEpoch, p3 types.TipSetKey) (*MiningBaseInfo, error) {
|
func (s *GatewayStruct) MinerGetBaseInfo(p0 context.Context, p1 address.Address, p2 abi.ChainEpoch, p3 types.TipSetKey) (*MiningBaseInfo, error) {
|
||||||
if s.Internal.MinerGetBaseInfo == nil {
|
if s.Internal.MinerGetBaseInfo == nil {
|
||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
@ -5235,6 +5276,17 @@ func (s *GatewayStub) StateWaitMsg(p0 context.Context, p1 cid.Cid, p2 uint64, p3
|
|||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *GatewayStruct) SubscribeActorEvents(p0 context.Context, p1 *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) {
|
||||||
|
if s.Internal.SubscribeActorEvents == nil {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.SubscribeActorEvents(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *GatewayStub) SubscribeActorEvents(p0 context.Context, p1 *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
func (s *GatewayStruct) Version(p0 context.Context) (APIVersion, error) {
|
func (s *GatewayStruct) Version(p0 context.Context) (APIVersion, error) {
|
||||||
if s.Internal.Version == nil {
|
if s.Internal.Version == nil {
|
||||||
return *new(APIVersion), ErrNotSupported
|
return *new(APIVersion), ErrNotSupported
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -28,13 +28,14 @@ func isIndexedValue(b uint8) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EventFilter struct {
|
type EventFilter struct {
|
||||||
id types.FilterID
|
id types.FilterID
|
||||||
minHeight abi.ChainEpoch // minimum epoch to apply filter or -1 if no minimum
|
minHeight abi.ChainEpoch // minimum epoch to apply filter or -1 if no minimum
|
||||||
maxHeight abi.ChainEpoch // maximum epoch to apply filter or -1 if no maximum
|
maxHeight abi.ChainEpoch // maximum epoch to apply filter or -1 if no maximum
|
||||||
tipsetCid cid.Cid
|
tipsetCid cid.Cid
|
||||||
addresses []address.Address // list of f4 actor addresses that are extpected to emit the event
|
addresses []address.Address // list of f4 actor addresses that are extpected to emit the event
|
||||||
keys map[string][][]byte // map of key names to a list of alternate values that may match
|
|
||||||
maxResults int // maximum number of results to collect, 0 is unlimited
|
keysWithCodec map[string][]types.ActorEventBlock // map of key names to a list of alternate values that may match
|
||||||
|
maxResults int // maximum number of results to collect, 0 is unlimited
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
collected []*CollectedEvent
|
collected []*CollectedEvent
|
||||||
@ -194,7 +195,7 @@ func (f *EventFilter) matchAddress(o address.Address) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *EventFilter) matchKeys(ees []types.EventEntry) bool {
|
func (f *EventFilter) matchKeys(ees []types.EventEntry) bool {
|
||||||
if len(f.keys) == 0 {
|
if len(f.keysWithCodec) == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// TODO: optimize this naive algorithm
|
// TODO: optimize this naive algorithm
|
||||||
@ -216,19 +217,19 @@ func (f *EventFilter) matchKeys(ees []types.EventEntry) bool {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
wantlist, ok := f.keys[keyname]
|
wantlist, ok := f.keysWithCodec[keyname]
|
||||||
if !ok || len(wantlist) == 0 {
|
if !ok || len(wantlist) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, w := range wantlist {
|
for _, w := range wantlist {
|
||||||
if bytes.Equal(w, ee.Value) {
|
if bytes.Equal(w.Value, ee.Value) && w.Codec == ee.Codec {
|
||||||
matched[keyname] = true
|
matched[keyname] = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(matched) == len(f.keys) {
|
if len(matched) == len(f.keysWithCodec) {
|
||||||
// all keys have been matched
|
// all keys have been matched
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -362,7 +363,8 @@ func (m *EventFilterManager) Revert(ctx context.Context, from, to *types.TipSet)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *EventFilterManager) Install(ctx context.Context, minHeight, maxHeight abi.ChainEpoch, tipsetCid cid.Cid, addresses []address.Address, keys map[string][][]byte) (*EventFilter, error) {
|
func (m *EventFilterManager) Install(ctx context.Context, minHeight, maxHeight abi.ChainEpoch, tipsetCid cid.Cid, addresses []address.Address,
|
||||||
|
keysWithCodec map[string][]types.ActorEventBlock, excludeReverted bool) (*EventFilter, error) {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
currentHeight := m.currentHeight
|
currentHeight := m.currentHeight
|
||||||
m.mu.Unlock()
|
m.mu.Unlock()
|
||||||
@ -377,18 +379,18 @@ func (m *EventFilterManager) Install(ctx context.Context, minHeight, maxHeight a
|
|||||||
}
|
}
|
||||||
|
|
||||||
f := &EventFilter{
|
f := &EventFilter{
|
||||||
id: id,
|
id: id,
|
||||||
minHeight: minHeight,
|
minHeight: minHeight,
|
||||||
maxHeight: maxHeight,
|
maxHeight: maxHeight,
|
||||||
tipsetCid: tipsetCid,
|
tipsetCid: tipsetCid,
|
||||||
addresses: addresses,
|
addresses: addresses,
|
||||||
keys: keys,
|
keysWithCodec: keysWithCodec,
|
||||||
maxResults: m.MaxFilterResults,
|
maxResults: m.MaxFilterResults,
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.EventIndex != nil && minHeight != -1 && minHeight < currentHeight {
|
if m.EventIndex != nil && minHeight != -1 && minHeight < currentHeight {
|
||||||
// Filter needs historic events
|
// Filter needs historic events
|
||||||
if err := m.EventIndex.PrefillFilter(ctx, f, true); err != nil {
|
if err := m.EventIndex.PrefillFilter(ctx, f, excludeReverted); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,19 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func keysToKeysWithCodec(keys map[string][][]byte) map[string][]types.ActorEventBlock {
|
||||||
|
keysWithCodec := make(map[string][]types.ActorEventBlock)
|
||||||
|
for k, v := range keys {
|
||||||
|
for _, vv := range v {
|
||||||
|
keysWithCodec[k] = append(keysWithCodec[k], types.ActorEventBlock{
|
||||||
|
Codec: cid.Raw,
|
||||||
|
Value: vv,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keysWithCodec
|
||||||
|
}
|
||||||
|
|
||||||
func TestEventFilterCollectEvents(t *testing.T) {
|
func TestEventFilterCollectEvents(t *testing.T) {
|
||||||
rng := pseudo.New(pseudo.NewSource(299792458))
|
rng := pseudo.New(pseudo.NewSource(299792458))
|
||||||
a1 := randomF4Addr(t, rng)
|
a1 := randomF4Addr(t, rng)
|
||||||
@ -139,11 +152,11 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: oneCollectedEvent,
|
want: oneCollectedEvent,
|
||||||
@ -153,13 +166,13 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("cancel"),
|
[]byte("cancel"),
|
||||||
[]byte("propose"),
|
[]byte("propose"),
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: oneCollectedEvent,
|
want: oneCollectedEvent,
|
||||||
@ -169,12 +182,12 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("cancel"),
|
[]byte("cancel"),
|
||||||
[]byte("propose"),
|
[]byte("propose"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -184,11 +197,11 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"method": {
|
"method": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -198,14 +211,14 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"signer": {
|
"signer": {
|
||||||
[]byte("addr1"),
|
[]byte("addr1"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: oneCollectedEvent,
|
want: oneCollectedEvent,
|
||||||
@ -215,14 +228,14 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"approver": {
|
"approver": {
|
||||||
[]byte("addr1"),
|
[]byte("addr1"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -232,14 +245,14 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"signer": {
|
"signer": {
|
||||||
[]byte("addr2"),
|
[]byte("addr2"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -249,11 +262,11 @@ func TestEventFilterCollectEvents(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"amount": {
|
"amount": {
|
||||||
[]byte("2988181"),
|
[]byte("2988181"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
|
@ -514,9 +514,9 @@ func (ei *EventIndex) PrefillFilter(ctx context.Context, f *EventFilter, exclude
|
|||||||
clauses = append(clauses, "("+strings.Join(subclauses, " OR ")+")")
|
clauses = append(clauses, "("+strings.Join(subclauses, " OR ")+")")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(f.keys) > 0 {
|
if len(f.keysWithCodec) > 0 {
|
||||||
join := 0
|
join := 0
|
||||||
for key, vals := range f.keys {
|
for key, vals := range f.keysWithCodec {
|
||||||
if len(vals) > 0 {
|
if len(vals) > 0 {
|
||||||
join++
|
join++
|
||||||
joinAlias := fmt.Sprintf("ee%d", join)
|
joinAlias := fmt.Sprintf("ee%d", join)
|
||||||
@ -525,8 +525,8 @@ func (ei *EventIndex) PrefillFilter(ctx context.Context, f *EventFilter, exclude
|
|||||||
values = append(values, key)
|
values = append(values, key)
|
||||||
subclauses := []string{}
|
subclauses := []string{}
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
subclauses = append(subclauses, fmt.Sprintf("%s.value=?", joinAlias))
|
subclauses = append(subclauses, fmt.Sprintf("(%s.value=? AND %[1]s.codec=?)", joinAlias))
|
||||||
values = append(values, val)
|
values = append(values, val.Value, val.Codec)
|
||||||
}
|
}
|
||||||
clauses = append(clauses, "("+strings.Join(subclauses, " OR ")+")")
|
clauses = append(clauses, "("+strings.Join(subclauses, " OR ")+")")
|
||||||
}
|
}
|
||||||
|
@ -148,11 +148,11 @@ func TestEventIndexPrefillFilter(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: oneCollectedEvent,
|
want: oneCollectedEvent,
|
||||||
@ -162,13 +162,13 @@ func TestEventIndexPrefillFilter(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("cancel"),
|
[]byte("cancel"),
|
||||||
[]byte("propose"),
|
[]byte("propose"),
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: oneCollectedEvent,
|
want: oneCollectedEvent,
|
||||||
@ -178,12 +178,12 @@ func TestEventIndexPrefillFilter(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("cancel"),
|
[]byte("cancel"),
|
||||||
[]byte("propose"),
|
[]byte("propose"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -193,11 +193,11 @@ func TestEventIndexPrefillFilter(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"method": {
|
"method": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -207,14 +207,14 @@ func TestEventIndexPrefillFilter(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"signer": {
|
"signer": {
|
||||||
[]byte("addr1"),
|
[]byte("addr1"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: oneCollectedEvent,
|
want: oneCollectedEvent,
|
||||||
@ -224,14 +224,14 @@ func TestEventIndexPrefillFilter(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"approver": {
|
"approver": {
|
||||||
[]byte("addr1"),
|
[]byte("addr1"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -241,14 +241,14 @@ func TestEventIndexPrefillFilter(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"signer": {
|
"signer": {
|
||||||
[]byte("addr2"),
|
[]byte("addr2"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -258,11 +258,11 @@ func TestEventIndexPrefillFilter(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"amount": {
|
"amount": {
|
||||||
[]byte("2988181"),
|
[]byte("2988181"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -495,11 +495,11 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: twoCollectedEvent,
|
want: twoCollectedEvent,
|
||||||
@ -509,13 +509,13 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("cancel"),
|
[]byte("cancel"),
|
||||||
[]byte("propose"),
|
[]byte("propose"),
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: twoCollectedEvent,
|
want: twoCollectedEvent,
|
||||||
@ -525,12 +525,12 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("cancel"),
|
[]byte("cancel"),
|
||||||
[]byte("propose"),
|
[]byte("propose"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -540,11 +540,11 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"method": {
|
"method": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -554,14 +554,14 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"signer": {
|
"signer": {
|
||||||
[]byte("addr1"),
|
[]byte("addr1"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: oneCollectedEvent,
|
want: oneCollectedEvent,
|
||||||
@ -571,14 +571,14 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"signer": {
|
"signer": {
|
||||||
[]byte("addr2"),
|
[]byte("addr2"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: revertedEvents14000,
|
te: revertedEvents14000,
|
||||||
want: oneCollectedRevertedEvent,
|
want: oneCollectedRevertedEvent,
|
||||||
@ -588,14 +588,14 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"approver": {
|
"approver": {
|
||||||
[]byte("addr1"),
|
[]byte("addr1"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -605,14 +605,14 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"signer": {
|
"signer": {
|
||||||
[]byte("addr3"),
|
[]byte("addr3"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -622,11 +622,11 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"amount": {
|
"amount": {
|
||||||
[]byte("2988181"),
|
[]byte("2988181"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -636,11 +636,11 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"amount": {
|
"amount": {
|
||||||
[]byte("2988182"),
|
[]byte("2988182"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -735,11 +735,11 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: oneCollectedEvent,
|
want: oneCollectedEvent,
|
||||||
@ -749,13 +749,13 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("cancel"),
|
[]byte("cancel"),
|
||||||
[]byte("propose"),
|
[]byte("propose"),
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: oneCollectedEvent,
|
want: oneCollectedEvent,
|
||||||
@ -765,12 +765,12 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("cancel"),
|
[]byte("cancel"),
|
||||||
[]byte("propose"),
|
[]byte("propose"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -780,11 +780,11 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"method": {
|
"method": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -794,14 +794,14 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"signer": {
|
"signer": {
|
||||||
[]byte("addr1"),
|
[]byte("addr1"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: oneCollectedEvent,
|
want: oneCollectedEvent,
|
||||||
@ -811,14 +811,14 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"approver": {
|
"approver": {
|
||||||
[]byte("addr1"),
|
[]byte("addr1"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -828,14 +828,14 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"signer": {
|
"signer": {
|
||||||
[]byte("addr2"),
|
[]byte("addr2"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -845,14 +845,14 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"type": {
|
"type": {
|
||||||
[]byte("approval"),
|
[]byte("approval"),
|
||||||
},
|
},
|
||||||
"signer": {
|
"signer": {
|
||||||
[]byte("addr3"),
|
[]byte("addr3"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
@ -862,11 +862,11 @@ func TestEventIndexPrefillFilterExcludeReverted(t *testing.T) {
|
|||||||
filter: &EventFilter{
|
filter: &EventFilter{
|
||||||
minHeight: -1,
|
minHeight: -1,
|
||||||
maxHeight: -1,
|
maxHeight: -1,
|
||||||
keys: map[string][][]byte{
|
keysWithCodec: keysToKeysWithCodec(map[string][][]byte{
|
||||||
"amount": {
|
"amount": {
|
||||||
[]byte("2988181"),
|
[]byte("2988181"),
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
te: events14000,
|
te: events14000,
|
||||||
want: noCollectedEvents,
|
want: noCollectedEvents,
|
||||||
|
47
chain/types/actor_event.go
Normal file
47
chain/types/actor_event.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ActorEventBlock struct {
|
||||||
|
// what value codec does client want to match on ?
|
||||||
|
Codec uint64 `json:"codec"`
|
||||||
|
// data associated with the "event key"
|
||||||
|
Value []byte `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SubActorEventFilter struct {
|
||||||
|
Filter ActorEventFilter `json:"filter"`
|
||||||
|
Prefill bool `json:"prefill"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ActorEventFilter struct {
|
||||||
|
// Matches events from one of these actors, or any actor if empty.
|
||||||
|
// TODO: Should we also allow Eth addresses here?
|
||||||
|
// For now, this MUST be a Filecoin address.
|
||||||
|
Addresses []address.Address `json:"address"`
|
||||||
|
|
||||||
|
// Matches events with the specified key/values, or all events if empty.
|
||||||
|
// If the `Blocks` slice is empty, matches on the key only.
|
||||||
|
Fields map[string][]ActorEventBlock `json:"fields"`
|
||||||
|
|
||||||
|
// Epoch based filtering ?
|
||||||
|
// Start epoch for the filter; -1 means no minimum
|
||||||
|
MinEpoch abi.ChainEpoch `json:"minEpoch,omitempty"`
|
||||||
|
|
||||||
|
// End epoch for the filter; -1 means no maximum
|
||||||
|
MaxEpoch abi.ChainEpoch `json:"maxEpoch,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ActorEvent struct {
|
||||||
|
Entries []EventEntry
|
||||||
|
EmitterAddr address.Address // f4 address of emitter
|
||||||
|
Reverted bool
|
||||||
|
Height abi.ChainEpoch
|
||||||
|
TipSetKey cid.Cid // tipset that contained the message
|
||||||
|
MsgCid cid.Cid // cid of message that produced event
|
||||||
|
}
|
@ -115,6 +115,8 @@
|
|||||||
* [GasEstimateGasLimit](#GasEstimateGasLimit)
|
* [GasEstimateGasLimit](#GasEstimateGasLimit)
|
||||||
* [GasEstimateGasPremium](#GasEstimateGasPremium)
|
* [GasEstimateGasPremium](#GasEstimateGasPremium)
|
||||||
* [GasEstimateMessageGas](#GasEstimateMessageGas)
|
* [GasEstimateMessageGas](#GasEstimateMessageGas)
|
||||||
|
* [Get](#Get)
|
||||||
|
* [GetActorEvents](#GetActorEvents)
|
||||||
* [I](#I)
|
* [I](#I)
|
||||||
* [ID](#ID)
|
* [ID](#ID)
|
||||||
* [Log](#Log)
|
* [Log](#Log)
|
||||||
@ -282,6 +284,8 @@
|
|||||||
* [StateVerifiedRegistryRootKey](#StateVerifiedRegistryRootKey)
|
* [StateVerifiedRegistryRootKey](#StateVerifiedRegistryRootKey)
|
||||||
* [StateVerifierStatus](#StateVerifierStatus)
|
* [StateVerifierStatus](#StateVerifierStatus)
|
||||||
* [StateWaitMsg](#StateWaitMsg)
|
* [StateWaitMsg](#StateWaitMsg)
|
||||||
|
* [Subscribe](#Subscribe)
|
||||||
|
* [SubscribeActorEvents](#SubscribeActorEvents)
|
||||||
* [Sync](#Sync)
|
* [Sync](#Sync)
|
||||||
* [SyncCheckBad](#SyncCheckBad)
|
* [SyncCheckBad](#SyncCheckBad)
|
||||||
* [SyncCheckpoint](#SyncCheckpoint)
|
* [SyncCheckpoint](#SyncCheckpoint)
|
||||||
@ -3382,6 +3386,62 @@ Response:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Get
|
||||||
|
|
||||||
|
|
||||||
|
### GetActorEvents
|
||||||
|
GetActorEvents returns all FVM and built-in Actor events that match the given filter.
|
||||||
|
This is a request/response API.
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"address": [
|
||||||
|
"f01234"
|
||||||
|
],
|
||||||
|
"fields": {
|
||||||
|
"abc": [
|
||||||
|
{
|
||||||
|
"codec": 81,
|
||||||
|
"value": "ZGF0YQ=="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minEpoch": 2301220,
|
||||||
|
"maxEpoch": 2301220
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Entries": [
|
||||||
|
{
|
||||||
|
"Flags": 7,
|
||||||
|
"Key": "string value",
|
||||||
|
"Codec": 42,
|
||||||
|
"Value": "Ynl0ZSBhcnJheQ=="
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"EmitterAddr": "f01234",
|
||||||
|
"Reverted": true,
|
||||||
|
"Height": 10101,
|
||||||
|
"TipSetKey": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
},
|
||||||
|
"MsgCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
## I
|
## I
|
||||||
|
|
||||||
|
|
||||||
@ -8758,6 +8818,67 @@ Response:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Subscribe
|
||||||
|
|
||||||
|
|
||||||
|
### SubscribeActorEvents
|
||||||
|
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.
|
||||||
|
NOTE: THIS API IS ONLY SUPPORTED OVER WEBSOCKETS FOR NOW
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"filter": {
|
||||||
|
"address": [
|
||||||
|
"f01234"
|
||||||
|
],
|
||||||
|
"fields": {
|
||||||
|
"abc": [
|
||||||
|
{
|
||||||
|
"codec": 81,
|
||||||
|
"value": "ZGF0YQ=="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"minEpoch": 2301220,
|
||||||
|
"maxEpoch": 2301220
|
||||||
|
},
|
||||||
|
"prefill": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Entries": [
|
||||||
|
{
|
||||||
|
"Flags": 7,
|
||||||
|
"Key": "string value",
|
||||||
|
"Codec": 42,
|
||||||
|
"Value": "Ynl0ZSBhcnJheQ=="
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"EmitterAddr": "f01234",
|
||||||
|
"Reverted": true,
|
||||||
|
"Height": 10101,
|
||||||
|
"TipSetKey": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
},
|
||||||
|
"MsgCid": {
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Sync
|
## Sync
|
||||||
The Sync method group contains methods for interacting with and
|
The Sync method group contains methods for interacting with and
|
||||||
observing the lotus sync service.
|
observing the lotus sync service.
|
||||||
|
@ -330,6 +330,10 @@
|
|||||||
# env var: LOTUS_FEVM_ENABLEETHRPC
|
# env var: LOTUS_FEVM_ENABLEETHRPC
|
||||||
#EnableEthRPC = false
|
#EnableEthRPC = false
|
||||||
|
|
||||||
|
# type: bool
|
||||||
|
# env var: LOTUS_FEVM_ENABLEACTOREVENTSAPI
|
||||||
|
#EnableActorEventsAPI = false
|
||||||
|
|
||||||
# EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
|
# EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
|
||||||
# Set to 0 to keep all mappings
|
# Set to 0 to keep all mappings
|
||||||
#
|
#
|
||||||
|
@ -146,6 +146,9 @@ type TargetAPI interface {
|
|||||||
Web3ClientVersion(ctx context.Context) (string, error)
|
Web3ClientVersion(ctx context.Context) (string, error)
|
||||||
EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error)
|
EthTraceBlock(ctx context.Context, blkNum string) ([]*ethtypes.EthTraceBlock, error)
|
||||||
EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error)
|
EthTraceReplayBlockTransactions(ctx context.Context, blkNum string, traceTypes []string) ([]*ethtypes.EthTraceReplayBlockTransaction, error)
|
||||||
|
|
||||||
|
GetActorEvents(ctx context.Context, filter *types.ActorEventFilter) ([]*types.ActorEvent, error)
|
||||||
|
SubscribeActorEvents(ctx context.Context, filter *types.SubActorEventFilter) (<-chan *types.ActorEvent, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ TargetAPI = *new(api.FullNode) // gateway depends on latest
|
var _ TargetAPI = *new(api.FullNode) // gateway depends on latest
|
||||||
|
@ -437,6 +437,20 @@ func (gw *Node) StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64
|
|||||||
return gw.target.StateWaitMsg(ctx, msg, confidence, limit, allowReplaced)
|
return gw.target.StateWaitMsg(ctx, msg, confidence, limit, allowReplaced)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gw *Node) GetActorEvents(ctx context.Context, filter *types.ActorEventFilter) ([]*types.ActorEvent, error) {
|
||||||
|
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return gw.target.GetActorEvents(ctx, filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gw *Node) SubscribeActorEvents(ctx context.Context, filter *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) {
|
||||||
|
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return gw.target.SubscribeActorEvents(ctx, filter)
|
||||||
|
}
|
||||||
|
|
||||||
func (gw *Node) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) {
|
func (gw *Node) StateReadState(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*api.ActorState, error) {
|
||||||
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
|
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
94
itests/actor_events_filter_test.go
Normal file
94
itests/actor_events_filter_test.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package itests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/itests/kit"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetActorEvents(t *testing.T) {
|
||||||
|
t.Skip("skipping for now")
|
||||||
|
//require := require.New(t)
|
||||||
|
kit.QuietAllLogsExcept("events", "messagepool")
|
||||||
|
|
||||||
|
blockTime := 100 * time.Millisecond
|
||||||
|
|
||||||
|
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
||||||
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Set up the test fixture with a standard list of invocations
|
||||||
|
contract1, contract2, invocations := prepareEventMatrixInvocations(ctx, t, client)
|
||||||
|
fmt.Printf("contract1:%s; contract2:%s\n", contract1, contract2)
|
||||||
|
|
||||||
|
cf1, err := contract1.ToFilecoinAddress()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cf2, err := contract2.ToFilecoinAddress()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("contract1 f4 is:%s; contract2 f4 is:%s\n", cf1.String(), cf2.String())
|
||||||
|
|
||||||
|
testCases := getCombinationFilterTestCases(contract1, contract2, "0x0")
|
||||||
|
|
||||||
|
messages := invokeAndWaitUntilAllOnChain(t, client, invocations)
|
||||||
|
|
||||||
|
// f410fiy2dwcbbvc5c6xwwrhlwgi2dby4rzgamxllpgva
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
tc := tc // appease the lint despot
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
|
||||||
|
res, err := client.EthGetLogs(ctx, tc.spec)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
/*ch, _ := client.SubscribeActorEvents(ctx, &types.SubActorEventFilter{
|
||||||
|
Prefill: true,
|
||||||
|
ActorEventFilter: types.ActorEventFilter{
|
||||||
|
MinEpoch: 0,
|
||||||
|
MaxEpoch: 1000,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
for i := range ch {
|
||||||
|
fmt.Println("Hello Chan", i.Entries[0].Key, i.Entries[0].Codec, i.EmitterAddr.String())
|
||||||
|
}*/
|
||||||
|
|
||||||
|
res2, _ := client.GetActorEvents(ctx, &types.ActorEventFilter{
|
||||||
|
MinEpoch: 0,
|
||||||
|
MaxEpoch: -1,
|
||||||
|
Addresses: []address.Address{cf2},
|
||||||
|
//EthAddresses: []ethtypes.EthAddress{
|
||||||
|
// contract1,
|
||||||
|
//},
|
||||||
|
})
|
||||||
|
for _, res := range res2 {
|
||||||
|
res := res
|
||||||
|
fmt.Println("Emitter Address is", res.EmitterAddr.String())
|
||||||
|
for _, entry := range res.Entries {
|
||||||
|
fmt.Println("Hello", entry.Key, entry.Codec, string(entry.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
fmt.Println("Hello", res2[0].Entries[0].Key, res2[0].Entries[0].Codec, res2[0].EmitterAddr.String())
|
||||||
|
|
||||||
|
elogs, err := parseEthLogsFromFilterResult(res)
|
||||||
|
require.NoError(t, err)
|
||||||
|
AssertEthLogs(t, elogs, tc.expected, messages)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -63,6 +63,7 @@ var DefaultNodeOpts = nodeOpts{
|
|||||||
// test defaults
|
// test defaults
|
||||||
|
|
||||||
cfg.Fevm.EnableEthRPC = true
|
cfg.Fevm.EnableEthRPC = true
|
||||||
|
cfg.Fevm.EnableActorEventsAPI = true
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/consensus"
|
"github.com/filecoin-project/lotus/chain/consensus"
|
||||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||||
"github.com/filecoin-project/lotus/chain/events"
|
"github.com/filecoin-project/lotus/chain/events"
|
||||||
|
"github.com/filecoin-project/lotus/chain/events/filter"
|
||||||
"github.com/filecoin-project/lotus/chain/exchange"
|
"github.com/filecoin-project/lotus/chain/exchange"
|
||||||
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
"github.com/filecoin-project/lotus/chain/gen/slashfilter"
|
||||||
"github.com/filecoin-project/lotus/chain/index"
|
"github.com/filecoin-project/lotus/chain/index"
|
||||||
@ -155,6 +156,7 @@ var ChainNode = Options(
|
|||||||
Override(new(stmgr.StateManagerAPI), rpcstmgr.NewRPCStateManager),
|
Override(new(stmgr.StateManagerAPI), rpcstmgr.NewRPCStateManager),
|
||||||
Override(new(full.EthModuleAPI), From(new(api.Gateway))),
|
Override(new(full.EthModuleAPI), From(new(api.Gateway))),
|
||||||
Override(new(full.EthEventAPI), From(new(api.Gateway))),
|
Override(new(full.EthEventAPI), From(new(api.Gateway))),
|
||||||
|
Override(new(full.ActorEventAPI), From(new(api.Gateway))),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Full node API / service startup
|
// Full node API / service startup
|
||||||
@ -265,6 +267,8 @@ func ConfigFullNode(c interface{}) Option {
|
|||||||
// Actor event filtering support
|
// Actor event filtering support
|
||||||
Override(new(events.EventAPI), From(new(modules.EventAPI))),
|
Override(new(events.EventAPI), From(new(modules.EventAPI))),
|
||||||
|
|
||||||
|
Override(new(*filter.EventFilterManager), modules.EventFilterManager(cfg.Fevm)),
|
||||||
|
|
||||||
// in lite-mode Eth api is provided by gateway
|
// in lite-mode Eth api is provided by gateway
|
||||||
ApplyIf(isFullNode,
|
ApplyIf(isFullNode,
|
||||||
If(cfg.Fevm.EnableEthRPC,
|
If(cfg.Fevm.EnableEthRPC,
|
||||||
@ -277,6 +281,15 @@ func ConfigFullNode(c interface{}) Option {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
ApplyIf(isFullNode,
|
||||||
|
If(cfg.Fevm.EnableActorEventsAPI,
|
||||||
|
Override(new(full.ActorEventAPI), modules.ActorEventAPI(cfg.Fevm)),
|
||||||
|
),
|
||||||
|
If(!cfg.Fevm.EnableActorEventsAPI,
|
||||||
|
Override(new(full.ActorEventAPI), &full.ActorEventDummy{}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
// enable message index for full node when configured by the user, otherwise use dummy.
|
// enable message index for full node when configured by the user, otherwise use dummy.
|
||||||
If(cfg.Index.EnableMsgIndex, Override(new(index.MsgIndex), modules.MsgIndex)),
|
If(cfg.Index.EnableMsgIndex, Override(new(index.MsgIndex), modules.MsgIndex)),
|
||||||
If(!cfg.Index.EnableMsgIndex, Override(new(index.MsgIndex), modules.DummyMsgIndex)),
|
If(!cfg.Index.EnableMsgIndex, Override(new(index.MsgIndex), modules.DummyMsgIndex)),
|
||||||
|
@ -109,6 +109,7 @@ func DefaultFullNode() *FullNode {
|
|||||||
Cluster: *DefaultUserRaftConfig(),
|
Cluster: *DefaultUserRaftConfig(),
|
||||||
Fevm: FevmConfig{
|
Fevm: FevmConfig{
|
||||||
EnableEthRPC: false,
|
EnableEthRPC: false,
|
||||||
|
EnableActorEventsAPI: false,
|
||||||
EthTxHashMappingLifetimeDays: 0,
|
EthTxHashMappingLifetimeDays: 0,
|
||||||
Events: Events{
|
Events: Events{
|
||||||
DisableRealTimeFilterAPI: false,
|
DisableRealTimeFilterAPI: false,
|
||||||
|
@ -455,6 +455,12 @@ rewards. This address should have adequate funds to cover gas fees.`,
|
|||||||
Comment: `EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
|
Comment: `EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
|
||||||
This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.`,
|
This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "EnableActorEventsAPI",
|
||||||
|
Type: "bool",
|
||||||
|
|
||||||
|
Comment: ``,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "EthTxHashMappingLifetimeDays",
|
Name: "EthTxHashMappingLifetimeDays",
|
||||||
Type: "int",
|
Type: "int",
|
||||||
|
@ -786,6 +786,8 @@ type FevmConfig struct {
|
|||||||
// This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.
|
// This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.
|
||||||
EnableEthRPC bool
|
EnableEthRPC bool
|
||||||
|
|
||||||
|
EnableActorEventsAPI bool
|
||||||
|
|
||||||
// EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
|
// EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
|
||||||
// Set to 0 to keep all mappings
|
// Set to 0 to keep all mappings
|
||||||
EthTxHashMappingLifetimeDays int
|
EthTxHashMappingLifetimeDays int
|
||||||
|
@ -36,6 +36,7 @@ type FullNodeAPI struct {
|
|||||||
full.SyncAPI
|
full.SyncAPI
|
||||||
full.RaftAPI
|
full.RaftAPI
|
||||||
full.EthAPI
|
full.EthAPI
|
||||||
|
full.ActorEventsAPI
|
||||||
|
|
||||||
DS dtypes.MetadataDS
|
DS dtypes.MetadataDS
|
||||||
NetworkName dtypes.NetworkName
|
NetworkName dtypes.NetworkName
|
||||||
|
171
node/impl/full/actor_event.go
Normal file
171
node/impl/full/actor_event.go
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package full
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
"go.uber.org/fx"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/events/filter"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ActorEventAPI interface {
|
||||||
|
GetActorEvents(ctx context.Context, filter *types.ActorEventFilter) ([]*types.ActorEvent, error)
|
||||||
|
SubscribeActorEvents(ctx context.Context, filter *types.SubActorEventFilter) (<-chan *types.ActorEvent, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ ActorEventAPI = *new(api.FullNode)
|
||||||
|
_ ActorEventAPI = *new(api.Gateway)
|
||||||
|
)
|
||||||
|
|
||||||
|
type ActorEvent struct {
|
||||||
|
EventFilterManager *filter.EventFilterManager
|
||||||
|
MaxFilterHeightRange abi.ChainEpoch
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ ActorEventAPI = (*ActorEvent)(nil)
|
||||||
|
|
||||||
|
type ActorEventsAPI struct {
|
||||||
|
fx.In
|
||||||
|
ActorEventAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ActorEvent) GetActorEvents(ctx context.Context, filter *types.ActorEventFilter) ([]*types.ActorEvent, error) {
|
||||||
|
if a.EventFilterManager == nil {
|
||||||
|
return nil, api.ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a temporary filter
|
||||||
|
f, err := a.EventFilterManager.Install(ctx, filter.MinEpoch, filter.MaxEpoch, cid.Undef, filter.Addresses, filter.Fields, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
evs, err := getCollected(ctx, f)
|
||||||
|
_ = a.EventFilterManager.Remove(ctx, f.ID())
|
||||||
|
return evs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ActorEvent) SubscribeActorEvents(ctx context.Context, f *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) {
|
||||||
|
if a.EventFilterManager == nil {
|
||||||
|
return nil, api.ErrNotSupported
|
||||||
|
}
|
||||||
|
fm, err := a.EventFilterManager.Install(ctx, f.Filter.MinEpoch, f.Filter.MaxEpoch, cid.Undef, f.Filter.Addresses, f.Filter.Fields, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make(chan *types.ActorEvent, 25)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
// Tell the caller we're done
|
||||||
|
close(out)
|
||||||
|
|
||||||
|
// Unsubscribe.
|
||||||
|
fm.ClearSubChannel()
|
||||||
|
_ = a.EventFilterManager.Remove(ctx, fm.ID())
|
||||||
|
}()
|
||||||
|
|
||||||
|
if f.Prefill {
|
||||||
|
evs, err := getCollected(ctx, fm)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get collected events: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ev := range evs {
|
||||||
|
ev := ev
|
||||||
|
select {
|
||||||
|
case out <- ev:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
log.Errorf("closing event subscription due to slow reader")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
in := make(chan interface{}, 256)
|
||||||
|
fm.SetSubChannel(in)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case val, ok := <-in:
|
||||||
|
if !ok {
|
||||||
|
// Shutting down.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ce, ok := val.(*filter.CollectedEvent)
|
||||||
|
if !ok {
|
||||||
|
log.Errorf("got unexpected value from event filter: %T", val)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c, err := ce.TipSetKey.Cid()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get tipset cid: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ev := &types.ActorEvent{
|
||||||
|
Entries: ce.Entries,
|
||||||
|
EmitterAddr: ce.EmitterAddr,
|
||||||
|
Reverted: ce.Reverted,
|
||||||
|
Height: ce.Height,
|
||||||
|
TipSetKey: c,
|
||||||
|
MsgCid: ce.MsgCid,
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case out <- ev:
|
||||||
|
default:
|
||||||
|
log.Errorf("closing event subscription due to slow reader")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(out) > 5 {
|
||||||
|
log.Warnf("event subscription is slow, has %d buffered entries", len(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCollected(ctx context.Context, f *filter.EventFilter) ([]*types.ActorEvent, error) {
|
||||||
|
ces := f.TakeCollectedEvents(ctx)
|
||||||
|
|
||||||
|
var out []*types.ActorEvent
|
||||||
|
|
||||||
|
for _, e := range ces {
|
||||||
|
e := e
|
||||||
|
c, err := e.TipSetKey.Cid()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get tipset cid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ev := &types.ActorEvent{
|
||||||
|
Entries: e.Entries,
|
||||||
|
EmitterAddr: e.EmitterAddr,
|
||||||
|
Reverted: e.Reverted,
|
||||||
|
Height: e.Height,
|
||||||
|
TipSetKey: c,
|
||||||
|
MsgCid: e.MsgCid,
|
||||||
|
}
|
||||||
|
|
||||||
|
out = append(out, ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -188,3 +189,17 @@ func (e *EthModuleDummy) EthTraceReplayBlockTransactions(ctx context.Context, bl
|
|||||||
|
|
||||||
var _ EthModuleAPI = &EthModuleDummy{}
|
var _ EthModuleAPI = &EthModuleDummy{}
|
||||||
var _ EthEventAPI = &EthModuleDummy{}
|
var _ EthEventAPI = &EthModuleDummy{}
|
||||||
|
|
||||||
|
var ErrActorEventModuleDisabled = errors.New("module disabled, enable with Fevm.EnableActorEventsAPI")
|
||||||
|
|
||||||
|
type ActorEventDummy struct{}
|
||||||
|
|
||||||
|
func (a *ActorEventDummy) GetActorEvents(ctx context.Context, filter *types.ActorEventFilter) ([]*types.ActorEvent, error) {
|
||||||
|
return nil, ErrActorEventModuleDisabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *ActorEventDummy) SubscribeActorEvents(ctx context.Context, filter *types.SubActorEventFilter) (<-chan *types.ActorEvent, error) {
|
||||||
|
return nil, ErrActorEventModuleDisabled
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ ActorEventAPI = &ActorEventDummy{}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
"github.com/multiformats/go-multicodec"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
@ -1353,7 +1354,20 @@ func (e *EthEvent) installEthFilterSpec(ctx context.Context, filterSpec *ethtype
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.EventFilterManager.Install(ctx, minHeight, maxHeight, tipsetCid, addresses, keys)
|
return e.EventFilterManager.Install(ctx, minHeight, maxHeight, tipsetCid, addresses, keysToKeysWithCodec(keys), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func keysToKeysWithCodec(keys map[string][][]byte) map[string][]types.ActorEventBlock {
|
||||||
|
keysWithCodec := make(map[string][]types.ActorEventBlock)
|
||||||
|
for k, v := range keys {
|
||||||
|
for _, vv := range v {
|
||||||
|
keysWithCodec[k] = append(keysWithCodec[k], types.ActorEventBlock{
|
||||||
|
Codec: uint64(multicodec.Raw),
|
||||||
|
Value: vv,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keysWithCodec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EthEvent) EthNewFilter(ctx context.Context, filterSpec *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) {
|
func (e *EthEvent) EthNewFilter(ctx context.Context, filterSpec *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) {
|
||||||
@ -1527,7 +1541,7 @@ func (e *EthEvent) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := e.EventFilterManager.Install(ctx, -1, -1, cid.Undef, addresses, keys)
|
f, err := e.EventFilterManager.Install(ctx, -1, -1, cid.Undef, addresses, keysToKeysWithCodec(keys), true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// clean up any previous filters added and stop the sub
|
// clean up any previous filters added and stop the sub
|
||||||
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
||||||
|
@ -33,8 +33,8 @@ type EventAPI struct {
|
|||||||
|
|
||||||
var _ events.EventAPI = &EventAPI{}
|
var _ events.EventAPI = &EventAPI{}
|
||||||
|
|
||||||
func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI) (*full.EthEvent, error) {
|
func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *filter.EventFilterManager, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI) (*full.EthEvent, error) {
|
||||||
return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI) (*full.EthEvent, error) {
|
return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, fm *filter.EventFilterManager, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI) (*full.EthEvent, error) {
|
||||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||||
|
|
||||||
ee := &full.EthEvent{
|
ee := &full.EthEvent{
|
||||||
@ -64,6 +64,41 @@ func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ee.TipSetFilterManager = &filter.TipSetFilterManager{
|
||||||
|
MaxFilterResults: cfg.Events.MaxFilterResults,
|
||||||
|
}
|
||||||
|
ee.MemPoolFilterManager = &filter.MemPoolFilterManager{
|
||||||
|
MaxFilterResults: cfg.Events.MaxFilterResults,
|
||||||
|
}
|
||||||
|
ee.EventFilterManager = fm
|
||||||
|
|
||||||
|
lc.Append(fx.Hook{
|
||||||
|
OnStart: func(context.Context) error {
|
||||||
|
ev, err := events.NewEvents(ctx, &evapi)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// ignore returned tipsets
|
||||||
|
_ = ev.Observe(ee.TipSetFilterManager)
|
||||||
|
|
||||||
|
ch, err := mp.Updates(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go ee.MemPoolFilterManager.WaitForMpoolUpdates(ctx, ch)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return ee, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func EventFilterManager(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, full.ChainAPI) (*filter.EventFilterManager, error) {
|
||||||
|
return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, chainapi full.ChainAPI) (*filter.EventFilterManager, error) {
|
||||||
|
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||||
|
|
||||||
// Enable indexing of actor events
|
// Enable indexing of actor events
|
||||||
var eventIndex *filter.EventIndex
|
var eventIndex *filter.EventIndex
|
||||||
if !cfg.Events.DisableHistoricFilterAPI {
|
if !cfg.Events.DisableHistoricFilterAPI {
|
||||||
@ -91,7 +126,7 @@ func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
ee.EventFilterManager = &filter.EventFilterManager{
|
fm := &filter.EventFilterManager{
|
||||||
ChainStore: cs,
|
ChainStore: cs,
|
||||||
EventIndex: eventIndex, // will be nil unless EnableHistoricFilterAPI is true
|
EventIndex: eventIndex, // will be nil unless EnableHistoricFilterAPI is true
|
||||||
AddressResolver: func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool) {
|
AddressResolver: func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool) {
|
||||||
@ -111,6 +146,7 @@ func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo
|
|||||||
return address.Undef, false
|
return address.Undef, false
|
||||||
}
|
}
|
||||||
// we have an f4 address, make sure it's assigned by the EAM
|
// we have an f4 address, make sure it's assigned by the EAM
|
||||||
|
// What happens when we introduce events for built-in Actor events here ?
|
||||||
if namespace, _, err := varint.FromUvarint(actor.Address.Payload()); err != nil || namespace != builtintypes.EthereumAddressManagerActorID {
|
if namespace, _, err := varint.FromUvarint(actor.Address.Payload()); err != nil || namespace != builtintypes.EthereumAddressManagerActorID {
|
||||||
return address.Undef, false
|
return address.Undef, false
|
||||||
}
|
}
|
||||||
@ -119,12 +155,6 @@ func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo
|
|||||||
|
|
||||||
MaxFilterResults: cfg.Events.MaxFilterResults,
|
MaxFilterResults: cfg.Events.MaxFilterResults,
|
||||||
}
|
}
|
||||||
ee.TipSetFilterManager = &filter.TipSetFilterManager{
|
|
||||||
MaxFilterResults: cfg.Events.MaxFilterResults,
|
|
||||||
}
|
|
||||||
ee.MemPoolFilterManager = &filter.MemPoolFilterManager{
|
|
||||||
MaxFilterResults: cfg.Events.MaxFilterResults,
|
|
||||||
}
|
|
||||||
|
|
||||||
lc.Append(fx.Hook{
|
lc.Append(fx.Hook{
|
||||||
OnStart: func(context.Context) error {
|
OnStart: func(context.Context) error {
|
||||||
@ -132,20 +162,28 @@ func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// ignore returned tipsets
|
_ = ev.Observe(fm)
|
||||||
_ = ev.Observe(ee.EventFilterManager)
|
|
||||||
_ = ev.Observe(ee.TipSetFilterManager)
|
|
||||||
|
|
||||||
ch, err := mp.Updates(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
go ee.MemPoolFilterManager.WaitForMpoolUpdates(ctx, ch)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return fm, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ActorEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *filter.EventFilterManager, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI) (*full.ActorEvent, error) {
|
||||||
|
return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, fm *filter.EventFilterManager, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI) (*full.ActorEvent, error) {
|
||||||
|
ee := &full.ActorEvent{
|
||||||
|
MaxFilterHeightRange: abi.ChainEpoch(cfg.Events.MaxFilterHeightRange),
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cfg.EnableActorEventsAPI {
|
||||||
|
// all Actor events functionality is disabled
|
||||||
|
return ee, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ee.EventFilterManager = fm
|
||||||
|
|
||||||
return ee, nil
|
return ee, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user