Skip to content

Commit f77dccc

Browse files
authored
feat: add actor dump processor and task (#1245)
* add periodic actor dump processor * create periodic actor dump task: fevm_actor_dump * create the new table: fevm_actor_dumps
1 parent 3b55289 commit f77dccc

File tree

24 files changed

+430
-31
lines changed

24 files changed

+430
-31
lines changed

chain/datasource/datasource.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ func (t *DataSource) TipSetBlockMessages(ctx context.Context, ts *types.TipSet)
136136
return t.node.MessagesForTipSetBlocks(ctx, ts)
137137
}
138138

139+
func (t *DataSource) StateListActors(ctx context.Context, tsk types.TipSetKey) ([]address.Address, error) {
140+
return t.node.StateListActors(ctx, tsk)
141+
}
142+
139143
func (t *DataSource) ChainGetMessagesInTipset(ctx context.Context, tsk types.TipSetKey) ([]api.Message, error) {
140144
return t.node.ChainGetMessagesInTipset(ctx, tsk)
141145
}

chain/indexer/integrated/manager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func (i *Manager) TipSet(ctx context.Context, ts *types.TipSet, options ...index
9494
}
9595
defer cancel()
9696

97-
idxer, err := i.indexBuilder.WithTasks(opts.Tasks).Build()
97+
idxer, err := i.indexBuilder.WithTasks(opts.Tasks).WithInterval(opts.Interval).Build()
9898
if err != nil {
9999
return false, err
100100
}

chain/indexer/integrated/processor/state.go

Lines changed: 119 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import (
66
"sync"
77
"time"
88

9+
"github.com/filecoin-project/go-state-types/abi"
910
actorstypes "github.com/filecoin-project/go-state-types/actors"
11+
"github.com/filecoin-project/go-state-types/manifest"
1012
"github.com/filecoin-project/lotus/chain/types"
1113
"github.com/ipfs/go-cid"
1214
logging "github.com/ipfs/go-log/v2"
@@ -66,10 +68,15 @@ import (
6668
fevmtransactiontask "github.com/filecoin-project/lily/tasks/fevm/transaction"
6769
fevmactorstatstask "github.com/filecoin-project/lily/tasks/fevmactorstats"
6870

71+
// actor dump
72+
fevmactordumptask "github.com/filecoin-project/lily/tasks/periodic_actor_dump/fevm_actor"
73+
6974
"github.com/filecoin-project/lily/chain/indexer/tasktype"
7075
"github.com/filecoin-project/lily/metrics"
7176
"github.com/filecoin-project/lily/model"
7277
visormodel "github.com/filecoin-project/lily/model/visor"
78+
79+
builtin "github.com/filecoin-project/lotus/chain/actors/builtin"
7380
)
7481

7582
type TipSetProcessor interface {
@@ -79,6 +86,13 @@ type TipSetProcessor interface {
7986
ProcessTipSet(ctx context.Context, current *types.TipSet) (model.Persistable, *visormodel.ProcessingReport, error)
8087
}
8188

89+
type PeriodicActorDumpProcessor interface {
90+
// ProcessTipSet processes a tipset. If error is non-nil then the processor encountered a fatal error.
91+
// Any data returned must be accompanied by a processing report.
92+
// Implementations of this interface must abort processing when their context is canceled.
93+
ProcessPeriodicActorDump(ctx context.Context, current *types.TipSet, actors tasks.ActorStatesByType) (model.Persistable, *visormodel.ProcessingReport, error)
94+
}
95+
8296
type TipSetsProcessor interface {
8397
// ProcessTipSets processes sequential tipsts (a parent and a child, or an executed and a current). If error is non-nil then the processor encountered a fatal error.
8498
// Any data returned must be accompanied by a processing report.
@@ -111,20 +125,22 @@ func New(api tasks.DataSource, name string, taskNames []string) (*StateProcessor
111125
return nil, err
112126
}
113127
return &StateProcessor{
114-
builtinProcessors: processors.ReportProcessors,
115-
tipsetProcessors: processors.TipsetProcessors,
116-
tipsetsProcessors: processors.TipsetsProcessors,
117-
actorProcessors: processors.ActorProcessors,
118-
api: api,
119-
name: name,
128+
builtinProcessors: processors.ReportProcessors,
129+
tipsetProcessors: processors.TipsetProcessors,
130+
tipsetsProcessors: processors.TipsetsProcessors,
131+
actorProcessors: processors.ActorProcessors,
132+
periodicActorDumpProcessors: processors.PeriodicActorDumpProcessors,
133+
api: api,
134+
name: name,
120135
}, nil
121136
}
122137

123138
type StateProcessor struct {
124-
builtinProcessors map[string]ReportProcessor
125-
tipsetProcessors map[string]TipSetProcessor
126-
tipsetsProcessors map[string]TipSetsProcessor
127-
actorProcessors map[string]ActorProcessor
139+
builtinProcessors map[string]ReportProcessor
140+
tipsetProcessors map[string]TipSetProcessor
141+
tipsetsProcessors map[string]TipSetsProcessor
142+
actorProcessors map[string]ActorProcessor
143+
periodicActorDumpProcessors map[string]PeriodicActorDumpProcessor
128144

129145
// api used by tasks
130146
api tasks.DataSource
@@ -151,17 +167,18 @@ type Result struct {
151167
// emits results of the state extraction closing when processing is completed. It is the responsibility of the processors
152168
// to abort if its context is canceled.
153169
// A list of all tasks executing is returned.
154-
func (sp *StateProcessor) State(ctx context.Context, current, executed *types.TipSet) (chan *Result, []string) {
170+
func (sp *StateProcessor) State(ctx context.Context, current, executed *types.TipSet, interval int) (chan *Result, []string) {
155171
ctx, span := otel.Tracer("").Start(ctx, "StateProcessor.State")
156172

157-
num := len(sp.tipsetProcessors) + len(sp.actorProcessors) + len(sp.tipsetsProcessors) + len(sp.builtinProcessors)
173+
num := len(sp.tipsetProcessors) + len(sp.actorProcessors) + len(sp.tipsetsProcessors) + len(sp.builtinProcessors) + len(sp.periodicActorDumpProcessors)
158174
results := make(chan *Result, num)
159175
taskNames := make([]string, 0, num)
160176

161177
taskNames = append(taskNames, sp.startReport(ctx, current, results)...)
162178
taskNames = append(taskNames, sp.startTipSet(ctx, current, results)...)
163179
taskNames = append(taskNames, sp.startTipSets(ctx, current, executed, results)...)
164180
taskNames = append(taskNames, sp.startActor(ctx, current, executed, results)...)
181+
taskNames = append(taskNames, sp.startPeriodicActorDump(ctx, current, interval, results)...)
165182

166183
go func() {
167184
sp.pwg.Wait()
@@ -398,19 +415,95 @@ func (sp *StateProcessor) startActor(ctx context.Context, current, executed *typ
398415
return taskNames
399416
}
400417

418+
// startPeriodicActorDump starts all TipSetsProcessor's in parallel, their results are emitted on the `results` channel.
419+
// A list containing all executed task names is returned.
420+
func (sp *StateProcessor) startPeriodicActorDump(ctx context.Context, current *types.TipSet, interval int, results chan *Result) []string {
421+
start := time.Now()
422+
var taskNames []string
423+
424+
if interval > 0 && current.Height()%abi.ChainEpoch(interval) != 0 {
425+
logger := log.With("processor", "PeriodicActorDump")
426+
logger.Infow("Skip this epoch", current.Height())
427+
return taskNames
428+
}
429+
430+
actors := make(map[string][]*types.ActorV5)
431+
addrssArr, _ := sp.api.StateListActors(ctx, current.Key())
432+
433+
for _, address := range addrssArr {
434+
actor, err := sp.api.Actor(ctx, address, current.Key())
435+
if err != nil {
436+
continue
437+
}
438+
439+
// EVM Actor
440+
if builtin.IsEvmActor(actor.Code) {
441+
actors[manifest.EvmKey] = append(actors[manifest.EvmKey], actor)
442+
} else if builtin.IsEthAccountActor(actor.Code) {
443+
actors[manifest.EthAccountKey] = append(actors[manifest.EthAccountKey], actor)
444+
} else if builtin.IsPlaceholderActor(actor.Code) {
445+
actors[manifest.PlaceholderKey] = append(actors[manifest.PlaceholderKey], actor)
446+
}
447+
}
448+
449+
for taskName, proc := range sp.periodicActorDumpProcessors {
450+
name := taskName
451+
p := proc
452+
taskNames = append(taskNames, name)
453+
454+
sp.pwg.Add(1)
455+
go func() {
456+
ctx, _ = tag.New(ctx, tag.Upsert(metrics.TaskType, name))
457+
stats.Record(ctx, metrics.TipsetHeight.M(int64(current.Height())))
458+
stop := metrics.Timer(ctx, metrics.ProcessingDuration)
459+
defer stop()
460+
461+
pl := log.With("task", name, "height", current.Height(), "reporter", sp.name)
462+
pl.Infow("PeriodicActorDump processor started")
463+
defer func() {
464+
pl.Infow("processor ended", "duration", time.Since(start))
465+
sp.pwg.Done()
466+
}()
467+
468+
data, report, err := p.ProcessPeriodicActorDump(ctx, current, actors)
469+
if err != nil {
470+
stats.Record(ctx, metrics.ProcessingFailure.M(1))
471+
results <- &Result{
472+
Task: name,
473+
Error: err,
474+
StartedAt: start,
475+
CompletedAt: time.Now(),
476+
}
477+
pl.Errorw("processor error", "error", err)
478+
return
479+
}
480+
results <- &Result{
481+
Task: name,
482+
Report: visormodel.ProcessingReportList{report},
483+
Data: data,
484+
StartedAt: start,
485+
CompletedAt: time.Now(),
486+
}
487+
}()
488+
}
489+
return taskNames
490+
}
491+
401492
type IndexerProcessors struct {
402-
TipsetProcessors map[string]TipSetProcessor
403-
TipsetsProcessors map[string]TipSetsProcessor
404-
ActorProcessors map[string]ActorProcessor
405-
ReportProcessors map[string]ReportProcessor
493+
TipsetProcessors map[string]TipSetProcessor
494+
TipsetsProcessors map[string]TipSetsProcessor
495+
ActorProcessors map[string]ActorProcessor
496+
ReportProcessors map[string]ReportProcessor
497+
PeriodicActorDumpProcessors map[string]PeriodicActorDumpProcessor
406498
}
407499

408500
func MakeProcessors(api tasks.DataSource, indexerTasks []string) (*IndexerProcessors, error) {
409501
out := &IndexerProcessors{
410-
TipsetProcessors: make(map[string]TipSetProcessor),
411-
TipsetsProcessors: make(map[string]TipSetsProcessor),
412-
ActorProcessors: make(map[string]ActorProcessor),
413-
ReportProcessors: make(map[string]ReportProcessor),
502+
TipsetProcessors: make(map[string]TipSetProcessor),
503+
TipsetsProcessors: make(map[string]TipSetsProcessor),
504+
ActorProcessors: make(map[string]ActorProcessor),
505+
ReportProcessors: make(map[string]ReportProcessor),
506+
PeriodicActorDumpProcessors: make(map[string]PeriodicActorDumpProcessor),
414507
}
415508
for _, t := range indexerTasks {
416509
switch t {
@@ -687,6 +780,12 @@ func MakeProcessors(api tasks.DataSource, indexerTasks []string) (*IndexerProces
687780
case tasktype.FEVMTrace:
688781
out.TipsetsProcessors[t] = fevmtracetask.NewTask(api)
689782

783+
//
784+
// Dump
785+
//
786+
case tasktype.FEVMActorDump:
787+
out.PeriodicActorDumpProcessors[t] = fevmactordumptask.NewTask(api)
788+
690789
case BuiltinTaskName:
691790
out.ReportProcessors[t] = indexertask.NewTask(api)
692791
default:

chain/indexer/integrated/testing/builder.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ func (t *MockIndexBuilder) WithTasks(tasks []string) tipset.IndexerBuilder {
2424
return t
2525
}
2626

27+
func (t *MockIndexBuilder) WithInterval(interval int) tipset.IndexerBuilder {
28+
return t
29+
}
30+
2731
func (t *MockIndexBuilder) Build() (tipset.Indexer, error) {
2832
return t.MockIndexer, nil
2933
}

chain/indexer/integrated/tipset/builder.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
type IndexerBuilder interface {
1212
WithTasks(tasks []string) IndexerBuilder
13+
WithInterval(interval int) IndexerBuilder
1314
Build() (Indexer, error)
1415
Name() string
1516
}
@@ -45,6 +46,13 @@ func (b *Builder) WithTasks(tasks []string) IndexerBuilder {
4546
return b
4647
}
4748

49+
func (b *Builder) WithInterval(interval int) IndexerBuilder {
50+
b.add(func(ti *TipSetIndexer) {
51+
ti.Interval = interval
52+
})
53+
return b
54+
}
55+
4856
func (b *Builder) Build() (Indexer, error) {
4957
ti := &TipSetIndexer{
5058
name: b.name,

chain/indexer/integrated/tipset/tipset.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type TipSetIndexer struct {
3030
name string
3131
node taskapi.DataSource
3232
taskNames []string
33+
Interval int
3334

3435
processor *processor.StateProcessor
3536
}
@@ -91,7 +92,7 @@ func (ti *TipSetIndexer) TipSet(ctx context.Context, ts *types.TipSet) (chan *Re
9192
}
9293

9394
log.Infow("index", "reporter", ti.name, "current", current.Height(), "executed", executed.Height())
94-
stateResults, taskNames := ti.processor.State(ctx, current, executed)
95+
stateResults, taskNames := ti.processor.State(ctx, current, executed, ti.Interval)
9596

9697
// build list of executing tasks, used below to label incomplete tasks as skipped.
9798
executingTasks := make(map[string]bool, len(taskNames))

chain/indexer/interface.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ type OptionType int
2626
const (
2727
IndexTypeOpt OptionType = iota
2828
TasksOpt
29+
IntervalOpt
2930
)
3031

3132
type (
3233
indexTypeOption int
3334
tasksTypeOption []string
35+
intervalOption int
3436
)
3537

3638
// WithTasks returns and Option that specifies the tasks to be indexed.
@@ -80,10 +82,19 @@ func (o indexTypeOption) String() string { return fmt.Sprintf("IndexerType(%
8082
func (o indexTypeOption) Type() OptionType { return IndexTypeOpt }
8183
func (o indexTypeOption) Value() interface{} { return IndexerType(o) }
8284

85+
func WithInterval(interval int) Option {
86+
return intervalOption(interval)
87+
}
88+
89+
func (o intervalOption) String() string { return fmt.Sprintf("Interval: %d", o) }
90+
func (o intervalOption) Type() OptionType { return IntervalOpt }
91+
func (o intervalOption) Value() interface{} { return o }
92+
8393
// IndexerOptions are used by implementations of the Indexer interface for configuration.
8494
type IndexerOptions struct {
8595
IndexType IndexerType
8696
Tasks []string
97+
Interval int
8798
}
8899

89100
// ConstructOptions returns an IndexerOptions struct that may be used to configured implementations of the Indexer interface.
@@ -101,6 +112,8 @@ func ConstructOptions(opts ...Option) (IndexerOptions, error) {
101112
if len(res.Tasks) == 0 {
102113
return IndexerOptions{}, fmt.Errorf("tasks options cannot be empty")
103114
}
115+
case intervalOption:
116+
res.Interval = int(o)
104117
default:
105118
}
106119
}

chain/indexer/tasktype/table_tasks.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ const (
5151
FEVMTransaction = "fevm_transaction"
5252
FEVMContract = "fevm_contract"
5353
FEVMTrace = "fevm_trace"
54+
55+
// New task types
56+
FEVMActorDump = "fevm_actor_dump"
5457
)
5558

5659
var AllTableTasks = []string{
@@ -103,6 +106,7 @@ var AllTableTasks = []string{
103106
FEVMTransaction,
104107
FEVMContract,
105108
FEVMTrace,
109+
FEVMActorDump,
106110
}
107111

108112
var TableLookup = map[string]struct{}{
@@ -155,6 +159,7 @@ var TableLookup = map[string]struct{}{
155159
FEVMTransaction: {},
156160
FEVMContract: {},
157161
FEVMTrace: {},
162+
FEVMActorDump: {},
158163
}
159164

160165
var TableComment = map[string]string{
@@ -207,6 +212,7 @@ var TableComment = map[string]string{
207212
FEVMTransaction: ``,
208213
FEVMContract: ``,
209214
FEVMTrace: ``,
215+
FEVMActorDump: ``,
210216
}
211217

212218
var TableFieldComments = map[string]map[string]string{
@@ -316,4 +322,5 @@ var TableFieldComments = map[string]map[string]string{
316322
FEVMTransaction: {},
317323
FEVMContract: {},
318324
FEVMTrace: {},
325+
FEVMActorDump: {},
319326
}

chain/indexer/tasktype/tasks.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const (
1818
ImplicitMessageTask = "implicitmessage" // task that extract implicitly executed messages: cron tick and block reward.
1919
ChainConsensusTask = "consensus"
2020
FEVMTask = "fevm"
21+
ActorDump = "actordump"
2122
)
2223

2324
var TaskLookup = map[string][]string{
@@ -100,6 +101,9 @@ var TaskLookup = map[string][]string{
100101
FEVMContract,
101102
FEVMTrace,
102103
},
104+
ActorDump: {
105+
FEVMActorDump,
106+
},
103107
}
104108

105109
func MakeTaskNames(tasks []string) ([]string, error) {

chain/indexer/tasktype/tasks_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ func TestMakeAllTaskAliasNames(t *testing.T) {
101101
}
102102

103103
func TestMakeAllTaskNames(t *testing.T) {
104-
const TotalTableTasks = 49
104+
const TotalTableTasks = 50
105105
actual, err := tasktype.MakeTaskNames(tasktype.AllTableTasks)
106106
require.NoError(t, err)
107107
// if this test fails it means a new task name was added, update the above test

0 commit comments

Comments
 (0)