9
9
10
10
"github.com/ipfs/go-cid"
11
11
cbg "github.com/whyrusleeping/cbor-gen"
12
+ "golang.org/x/sync/errgroup"
12
13
"golang.org/x/xerrors"
13
14
14
15
"github.com/filecoin-project/go-address"
@@ -28,7 +29,10 @@ func isIndexedValue(b uint8) bool {
28
29
return b & (types .EventFlagIndexedKey | types .EventFlagIndexedValue ) > 0
29
30
}
30
31
31
- type AddressResolver func (context.Context , abi.ActorID , * types.TipSet ) (address.Address , bool )
32
+ // AddressResolver is a function that resolves an actor ID to an address. If the
33
+ // actor ID cannot be resolved to an address, the function must return
34
+ // address.Undef.
35
+ type AddressResolver func (context.Context , abi.ActorID , * types.TipSet ) address.Address
32
36
33
37
type EventFilter interface {
34
38
Filter
@@ -77,9 +81,6 @@ func (f *eventFilter) CollectEvents(ctx context.Context, te *TipSetEvents, rever
77
81
return nil
78
82
}
79
83
80
- // cache of lookups between actor id and f4 address
81
- addressLookups := make (map [abi.ActorID ]address.Address )
82
-
83
84
ems , err := te .messages (ctx )
84
85
if err != nil {
85
86
return xerrors .Errorf ("load executed messages: %w" , err )
@@ -89,16 +90,10 @@ func (f *eventFilter) CollectEvents(ctx context.Context, te *TipSetEvents, rever
89
90
90
91
for msgIdx , em := range ems {
91
92
for _ , ev := range em .Events () {
92
- // lookup address corresponding to the actor id
93
- addr , found := addressLookups [ev .Emitter ]
94
- if ! found {
95
- var ok bool
96
- addr , ok = resolver (ctx , ev .Emitter , te .rctTs )
97
- if ! ok {
98
- // not an address we will be able to match against
99
- continue
100
- }
101
- addressLookups [ev .Emitter ] = addr
93
+ addr := resolver (ctx , ev .Emitter , te .rctTs )
94
+ if addr == address .Undef {
95
+ // not an address we will be able to match against
96
+ continue
102
97
}
103
98
104
99
if ! f .matchAddress (addr ) {
@@ -295,7 +290,7 @@ func (e *executedMessage) Events() []*types.Event {
295
290
296
291
type EventFilterManager struct {
297
292
ChainStore * cstore.ChainStore
298
- AddressResolver func ( ctx context. Context , emitter abi. ActorID , ts * types. TipSet ) (address. Address , bool )
293
+ AddressResolver AddressResolver
299
294
MaxFilterResults int
300
295
ChainIndexer index.Indexer
301
296
@@ -319,11 +314,17 @@ func (m *EventFilterManager) Apply(ctx context.Context, from, to *types.TipSet)
319
314
load : m .loadExecutedMessages ,
320
315
}
321
316
322
- // TODO: could run this loop in parallel with errgroup if there are many filters
317
+ tsAddressResolver := tipSetCachedAddressResolver (m .AddressResolver )
318
+
319
+ g , ctx := errgroup .WithContext (ctx )
323
320
for _ , f := range m .filters {
324
- if err := f .CollectEvents (ctx , tse , false , m .AddressResolver ); err != nil {
325
- return err
326
- }
321
+ g .Go (func () error {
322
+ return f .CollectEvents (ctx , tse , false , tsAddressResolver )
323
+ })
324
+ }
325
+
326
+ if err := g .Wait (); err != nil {
327
+ return err
327
328
}
328
329
329
330
return nil
@@ -344,11 +345,17 @@ func (m *EventFilterManager) Revert(ctx context.Context, from, to *types.TipSet)
344
345
load : m .loadExecutedMessages ,
345
346
}
346
347
347
- // TODO: could run this loop in parallel with errgroup if there are many filters
348
+ tsAddressResolver := tipSetCachedAddressResolver (m .AddressResolver )
349
+
350
+ g , ctx := errgroup .WithContext (ctx )
348
351
for _ , f := range m .filters {
349
- if err := f .CollectEvents (ctx , tse , true , m .AddressResolver ); err != nil {
350
- return err
351
- }
352
+ g .Go (func () error {
353
+ return f .CollectEvents (ctx , tse , true , tsAddressResolver )
354
+ })
355
+ }
356
+
357
+ if err := g .Wait (); err != nil {
358
+ return err
352
359
}
353
360
354
361
return nil
@@ -507,3 +514,25 @@ func (m *EventFilterManager) loadExecutedMessages(ctx context.Context, msgTs, rc
507
514
508
515
return ems , nil
509
516
}
517
+
518
+ // tipSetCachedAddressResolver returns a thread-safe function that resolves actor IDs to addresses
519
+ // with a cache that is shared across all calls to the returned function. This should only be used
520
+ // for a single TipSet, as the resolution may vary across TipSets and the cache does not account for
521
+ // this.
522
+ func tipSetCachedAddressResolver (resolver AddressResolver ) func (ctx context.Context , emitter abi.ActorID , ts * types.TipSet ) address.Address {
523
+ addressLookups := make (map [abi.ActorID ]address.Address )
524
+ var addressLookupsLk sync.Mutex
525
+
526
+ return func (ctx context.Context , emitter abi.ActorID , ts * types.TipSet ) address.Address {
527
+ addressLookupsLk .Lock ()
528
+ defer addressLookupsLk .Unlock ()
529
+
530
+ addr , ok := addressLookups [emitter ]
531
+ if ! ok {
532
+ addr = resolver (ctx , emitter , ts )
533
+ addressLookups [emitter ] = addr
534
+ }
535
+
536
+ return addr
537
+ }
538
+ }
0 commit comments