From 94add978b01f365fba1c838a61497ac035f8095b Mon Sep 17 00:00:00 2001 From: Geoff Stuart Date: Wed, 21 Sep 2022 10:56:58 -0400 Subject: [PATCH] chore: actors: Allow builtin-actors to return a map of methods (#9342) * Allow builtin-actors to return a map of methods * go mod * Fix tests * Fix tests, check carefully please --- chain/actors/builtin/registry.go | 28 ++++++++++++++++----- chain/actors/builtin/registry.go.template | 28 ++++++++++++++++----- chain/consensus/filcns/compute_state.go | 18 +++++++------- chain/stmgr/forks_test.go | 11 ++++++--- chain/vm/invoker.go | 30 ++++++++++------------- chain/vm/invoker_test.go | 26 ++++++++++---------- conformance/driver.go | 5 +++- go.mod | 2 +- go.sum | 4 +-- 9 files changed, 94 insertions(+), 58 deletions(-) diff --git a/chain/actors/builtin/registry.go b/chain/actors/builtin/registry.go index a51ef6245f3..fcd5079a639 100644 --- a/chain/actors/builtin/registry.go +++ b/chain/actors/builtin/registry.go @@ -32,19 +32,17 @@ import ( "github.com/filecoin-project/lotus/chain/actors" ) -var _ rtt.VMActor = (*RegistryEntry)(nil) - type RegistryEntry struct { state cbor.Er code cid.Cid - methods []interface{} + methods map[uint64]interface{} } func (r RegistryEntry) State() cbor.Er { return r.state } -func (r RegistryEntry) Exports() []interface{} { +func (r RegistryEntry) Exports() map[uint64]interface{} { return r.methods } @@ -52,11 +50,29 @@ func (r RegistryEntry) Code() cid.Cid { return r.code } -func MakeRegistry(av actorstypes.Version) []rtt.VMActor { +func MakeRegistryLegacy(actors []rtt.VMActor) []RegistryEntry { + registry := make([]RegistryEntry, 0) + + for _, actor := range actors { + methodMap := make(map[uint64]interface{}) + for methodNum, method := range actor.Exports() { + methodMap[uint64(methodNum)] = method + } + registry = append(registry, RegistryEntry{ + code: actor.Code(), + methods: methodMap, + state: actor.State(), + }) + } + + return registry +} + +func MakeRegistry(av actorstypes.Version) []RegistryEntry { if av < actorstypes.Version8 { panic("expected version v8 and up only, use specs-actors for v0-7") } - registry := make([]rtt.VMActor, 0) + registry := make([]RegistryEntry, 0) codeIDs, err := actors.GetActorCodeIDs(av) if err != nil { diff --git a/chain/actors/builtin/registry.go.template b/chain/actors/builtin/registry.go.template index ec6d5b63320..16cc9b8b89d 100644 --- a/chain/actors/builtin/registry.go.template +++ b/chain/actors/builtin/registry.go.template @@ -23,19 +23,17 @@ import ( "github.com/filecoin-project/lotus/chain/actors" ) -var _ rtt.VMActor = (*RegistryEntry)(nil) - type RegistryEntry struct { state cbor.Er code cid.Cid - methods []interface{} + methods map[uint64]interface{} } func (r RegistryEntry) State() cbor.Er { return r.state } -func (r RegistryEntry) Exports() []interface{} { +func (r RegistryEntry) Exports() map[uint64]interface{} { return r.methods } @@ -43,11 +41,29 @@ func (r RegistryEntry) Code() cid.Cid { return r.code } -func MakeRegistry(av actorstypes.Version) []rtt.VMActor { +func MakeRegistryLegacy(actors []rtt.VMActor) []RegistryEntry { + registry := make([]RegistryEntry, 0) + + for _, actor := range actors { + methodMap := make(map[uint64]interface{}) + for methodNum, method := range actor.Exports() { + methodMap[uint64(methodNum)] = method + } + registry = append(registry, RegistryEntry{ + code: actor.Code(), + methods: methodMap, + state: actor.State(), + }) + } + + return registry +} + +func MakeRegistry(av actorstypes.Version) []RegistryEntry { if av < actorstypes.Version8 { panic("expected version v8 and up only, use specs-actors for v0-7") } - registry := make([]rtt.VMActor, 0) + registry := make([]RegistryEntry, 0) codeIDs, err := actors.GetActorCodeIDs(av) if err != nil { diff --git a/chain/consensus/filcns/compute_state.go b/chain/consensus/filcns/compute_state.go index 9837e265f0f..6b5405543ea 100644 --- a/chain/consensus/filcns/compute_state.go +++ b/chain/consensus/filcns/compute_state.go @@ -39,15 +39,15 @@ import ( func NewActorRegistry() *vm.ActorRegistry { inv := vm.NewActorRegistry() - inv.Register(actorstypes.Version0, vm.ActorsVersionPredicate(actorstypes.Version0), exported0.BuiltinActors()...) - inv.Register(actorstypes.Version2, vm.ActorsVersionPredicate(actorstypes.Version2), exported2.BuiltinActors()...) - inv.Register(actorstypes.Version3, vm.ActorsVersionPredicate(actorstypes.Version3), exported3.BuiltinActors()...) - inv.Register(actorstypes.Version4, vm.ActorsVersionPredicate(actorstypes.Version4), exported4.BuiltinActors()...) - inv.Register(actorstypes.Version5, vm.ActorsVersionPredicate(actorstypes.Version5), exported5.BuiltinActors()...) - inv.Register(actorstypes.Version6, vm.ActorsVersionPredicate(actorstypes.Version6), exported6.BuiltinActors()...) - inv.Register(actorstypes.Version7, vm.ActorsVersionPredicate(actorstypes.Version7), exported7.BuiltinActors()...) - inv.Register(actorstypes.Version8, vm.ActorsVersionPredicate(actorstypes.Version8), builtin.MakeRegistry(actorstypes.Version8)...) - inv.Register(actorstypes.Version9, vm.ActorsVersionPredicate(actorstypes.Version9), builtin.MakeRegistry(actorstypes.Version9)...) + inv.Register(actorstypes.Version0, vm.ActorsVersionPredicate(actorstypes.Version0), builtin.MakeRegistryLegacy(exported0.BuiltinActors())) + inv.Register(actorstypes.Version2, vm.ActorsVersionPredicate(actorstypes.Version2), builtin.MakeRegistryLegacy(exported2.BuiltinActors())) + inv.Register(actorstypes.Version3, vm.ActorsVersionPredicate(actorstypes.Version3), builtin.MakeRegistryLegacy(exported3.BuiltinActors())) + inv.Register(actorstypes.Version4, vm.ActorsVersionPredicate(actorstypes.Version4), builtin.MakeRegistryLegacy(exported4.BuiltinActors())) + inv.Register(actorstypes.Version5, vm.ActorsVersionPredicate(actorstypes.Version5), builtin.MakeRegistryLegacy(exported5.BuiltinActors())) + inv.Register(actorstypes.Version6, vm.ActorsVersionPredicate(actorstypes.Version6), builtin.MakeRegistryLegacy(exported6.BuiltinActors())) + inv.Register(actorstypes.Version7, vm.ActorsVersionPredicate(actorstypes.Version7), builtin.MakeRegistryLegacy(exported7.BuiltinActors())) + inv.Register(actorstypes.Version8, vm.ActorsVersionPredicate(actorstypes.Version8), builtin.MakeRegistry(actorstypes.Version8)) + inv.Register(actorstypes.Version9, vm.ActorsVersionPredicate(actorstypes.Version9), builtin.MakeRegistry(actorstypes.Version9)) return inv } diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index d46d0befe0b..3c774a790e1 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -20,6 +20,7 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/network" + rtt "github.com/filecoin-project/go-state-types/rt" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin" init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" rt2 "github.com/filecoin-project/specs-actors/v2/actors/runtime" @@ -27,6 +28,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/aerrors" + "github.com/filecoin-project/lotus/chain/actors/builtin" _init "github.com/filecoin-project/lotus/chain/actors/builtin/init" "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/consensus/filcns" @@ -168,7 +170,8 @@ func TestForkHeightTriggers(t *testing.T) { } inv := filcns.NewActorRegistry() - inv.Register(actorstypes.Version0, nil, testActor{}) + registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}}) + inv.Register(actorstypes.Version0, nil, registry) sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) { nvm, err := vm.NewLegacyVM(ctx, vmopt) @@ -285,7 +288,8 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) { } inv := filcns.NewActorRegistry() - inv.Register(actorstypes.Version0, nil, testActor{}) + registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}}) + inv.Register(actorstypes.Version0, nil, registry) sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) { nvm, err := vm.NewLegacyVM(ctx, vmopt) @@ -506,7 +510,8 @@ func TestForkPreMigration(t *testing.T) { }() inv := filcns.NewActorRegistry() - inv.Register(actorstypes.Version0, nil, testActor{}) + registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}}) + inv.Register(actorstypes.Version0, nil, registry) sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) { nvm, err := vm.NewLegacyVM(ctx, vmopt) diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 8d9caad3eba..f8d817ff272 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -15,7 +15,6 @@ import ( actorstypes "github.com/filecoin-project/go-state-types/actors" "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-state-types/network" - rtt "github.com/filecoin-project/go-state-types/rt" vmr "github.com/filecoin-project/specs-actors/v7/actors/runtime" "github.com/filecoin-project/lotus/chain/actors" @@ -38,27 +37,27 @@ type ActorRegistry struct { } // An ActorPredicate returns an error if the given actor is not valid for the given runtime environment (e.g., chain height, version, etc.). -type ActorPredicate func(vmr.Runtime, rtt.VMActor) error +type ActorPredicate func(vmr.Runtime, cid.Cid) error func ActorsVersionPredicate(ver actorstypes.Version) ActorPredicate { - return func(rt vmr.Runtime, v rtt.VMActor) error { + return func(rt vmr.Runtime, codeCid cid.Cid) error { aver, err := actorstypes.VersionForNetwork(rt.NetworkVersion()) if err != nil { return xerrors.Errorf("unsupported network version: %w", err) } if aver != ver { - return xerrors.Errorf("actor %s is a version %d actor; chain only supports actor version %d at height %d and nver %d", v.Code(), ver, aver, rt.CurrEpoch(), rt.NetworkVersion()) + return xerrors.Errorf("actor %s is a version %d actor; chain only supports actor version %d at height %d and nver %d", codeCid, ver, aver, rt.CurrEpoch(), rt.NetworkVersion()) } return nil } } type invokeFunc func(rt vmr.Runtime, params []byte) ([]byte, aerrors.ActorError) -type nativeCode []invokeFunc +type nativeCode map[uint64]invokeFunc type actorInfo struct { methods nativeCode - vmActor rtt.VMActor + vmActor builtin.RegistryEntry // TODO: consider making this a network version range? predicate ActorPredicate } @@ -76,19 +75,19 @@ func (ar *ActorRegistry) Invoke(codeCid cid.Cid, rt vmr.Runtime, method abi.Meth log.Errorf("no code for actor %s (Addr: %s)", codeCid, rt.Receiver()) return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "no code for actor %s(%d)(%s)", codeCid, method, hex.EncodeToString(params)) } - if err := act.predicate(rt, act.vmActor); err != nil { + if err := act.predicate(rt, codeCid); err != nil { return nil, aerrors.Newf(exitcode.SysErrorIllegalActor, "unsupported actor: %s", err) } - if method >= abi.MethodNum(len(act.methods)) || act.methods[method] == nil { + if act.methods[uint64(method)] == nil { return nil, aerrors.Newf(exitcode.SysErrInvalidMethod, "no method %d on actor", method) } - return act.methods[method](rt, params) + return act.methods[uint64(method)](rt, params) } -func (ar *ActorRegistry) Register(av actorstypes.Version, pred ActorPredicate, vmactors ...rtt.VMActor) { +func (ar *ActorRegistry) Register(av actorstypes.Version, pred ActorPredicate, vmactors []builtin.RegistryEntry) { if pred == nil { - pred = func(vmr.Runtime, rtt.VMActor) error { return nil } + pred = func(vmr.Runtime, cid.Cid) error { return nil } } for _, a := range vmactors { // register in the `actors` map (for the invoker) @@ -140,7 +139,7 @@ func (ar *ActorRegistry) Register(av actorstypes.Version, pred ActorPredicate, v et := ev.Type() methods[abi.MethodNum(number)] = MethodMeta{ - Num: strconv.Itoa(number), + Num: strconv.Itoa(int(number)), Params: et.In(1), Ret: et.Out(0), } @@ -159,13 +158,10 @@ func (ar *ActorRegistry) Create(codeCid cid.Cid, rt vmr.Runtime) (*types.Actor, return nil, aerrors.Newf(exitcode.SysErrorIllegalArgument, "Can only create built-in actors.") } - if err := act.predicate(rt, act.vmActor); err != nil { + if err := act.predicate(rt, codeCid); err != nil { return nil, aerrors.Newf(exitcode.SysErrorIllegalArgument, "Cannot create actor: %w", err) } - if rtt.IsSingletonActor(act.vmActor) { - return nil, aerrors.Newf(exitcode.SysErrorIllegalArgument, "Can only have one instance of singleton actors.") - } return &types.Actor{ Code: codeCid, Head: EmptyObjectCid, @@ -175,7 +171,7 @@ func (ar *ActorRegistry) Create(codeCid cid.Cid, rt vmr.Runtime) (*types.Actor, } type invokee interface { - Exports() []interface{} + Exports() map[uint64]interface{} } func (*ActorRegistry) transform(instance invokee) (nativeCode, error) { diff --git a/chain/vm/invoker_test.go b/chain/vm/invoker_test.go index 5a4e1b40293..340f044d86e 100644 --- a/chain/vm/invoker_test.go +++ b/chain/vm/invoker_test.go @@ -49,19 +49,19 @@ func init() { cbor.RegisterCborType(basicParams{}) } -func (b basicContract) Exports() []interface{} { - return []interface{}{ - b.InvokeSomething0, - b.BadParam, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - nil, - b.InvokeSomething10, +func (b basicContract) Exports() map[uint64]interface{} { + return map[uint64]interface{}{ + 0: b.InvokeSomething0, + 1: b.BadParam, + 2: nil, + 3: nil, + 4: nil, + 5: nil, + 6: nil, + 7: nil, + 8: nil, + 9: nil, + 10: b.InvokeSomething10, } } diff --git a/conformance/driver.go b/conformance/driver.go index 2329fe336cf..ba9f49176d7 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -15,9 +15,11 @@ import ( "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/network" + rtt "github.com/filecoin-project/go-state-types/rt" "github.com/filecoin-project/test-vectors/schema" "github.com/filecoin-project/lotus/blockstore" + "github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/consensus/filcns" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/stmgr" @@ -250,7 +252,8 @@ func (d *Driver) ExecuteMessage(bs blockstore.Blockstore, params ExecuteMessageP // register the chaos actor if required by the vector. if chaosOn, ok := d.selector["chaos_actor"]; ok && chaosOn == "true" { av, _ := actorstypes.VersionForNetwork(params.NetworkVersion) - invoker.Register(av, nil, chaos.Actor{}) + registry := builtin.MakeRegistryLegacy([]rtt.VMActor{chaos.Actor{}}) + invoker.Register(av, nil, registry) } lvm.SetInvoker(invoker) diff --git a/go.mod b/go.mod index dd603bcadbe..9896600e408 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/filecoin-project/go-legs v0.4.4 github.com/filecoin-project/go-padreader v0.0.1 github.com/filecoin-project/go-paramfetch v0.0.4 - github.com/filecoin-project/go-state-types v0.1.12-beta + github.com/filecoin-project/go-state-types v0.1.12-beta.0.20220920181425-d683559e386b github.com/filecoin-project/go-statemachine v1.0.2 github.com/filecoin-project/go-statestore v0.2.0 github.com/filecoin-project/go-storedcounter v0.1.0 diff --git a/go.sum b/go.sum index ee452c5fe22..44ece0026f7 100644 --- a/go.sum +++ b/go.sum @@ -343,8 +343,8 @@ github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psS github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= github.com/filecoin-project/go-state-types v0.1.8/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= github.com/filecoin-project/go-state-types v0.1.10/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= -github.com/filecoin-project/go-state-types v0.1.12-beta h1:QZE00g75shqwhPn0/bZL38sFxVAqnXC7zjmYltRdhxI= -github.com/filecoin-project/go-state-types v0.1.12-beta/go.mod h1:n/kujdC9JphvYTrmaD1+vJpvDPy/DwzckoMzP0nBKWI= +github.com/filecoin-project/go-state-types v0.1.12-beta.0.20220920181425-d683559e386b h1:s4F3e3EBo56j+4xmrzmoAIvtgvDwLn4nsIf5bqcU0Qg= +github.com/filecoin-project/go-state-types v0.1.12-beta.0.20220920181425-d683559e386b/go.mod h1:n/kujdC9JphvYTrmaD1+vJpvDPy/DwzckoMzP0nBKWI= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc= github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54=