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
This commit is contained in:
Geoff Stuart 2022-09-21 10:56:58 -04:00 committed by GitHub
parent 99db94f476
commit 94add978b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 94 additions and 58 deletions

View File

@ -32,19 +32,17 @@ import (
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
) )
var _ rtt.VMActor = (*RegistryEntry)(nil)
type RegistryEntry struct { type RegistryEntry struct {
state cbor.Er state cbor.Er
code cid.Cid code cid.Cid
methods []interface{} methods map[uint64]interface{}
} }
func (r RegistryEntry) State() cbor.Er { func (r RegistryEntry) State() cbor.Er {
return r.state return r.state
} }
func (r RegistryEntry) Exports() []interface{} { func (r RegistryEntry) Exports() map[uint64]interface{} {
return r.methods return r.methods
} }
@ -52,11 +50,29 @@ func (r RegistryEntry) Code() cid.Cid {
return r.code 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 { if av < actorstypes.Version8 {
panic("expected version v8 and up only, use specs-actors for v0-7") 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) codeIDs, err := actors.GetActorCodeIDs(av)
if err != nil { if err != nil {

View File

@ -23,19 +23,17 @@ import (
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
) )
var _ rtt.VMActor = (*RegistryEntry)(nil)
type RegistryEntry struct { type RegistryEntry struct {
state cbor.Er state cbor.Er
code cid.Cid code cid.Cid
methods []interface{} methods map[uint64]interface{}
} }
func (r RegistryEntry) State() cbor.Er { func (r RegistryEntry) State() cbor.Er {
return r.state return r.state
} }
func (r RegistryEntry) Exports() []interface{} { func (r RegistryEntry) Exports() map[uint64]interface{} {
return r.methods return r.methods
} }
@ -43,11 +41,29 @@ func (r RegistryEntry) Code() cid.Cid {
return r.code 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 { if av < actorstypes.Version8 {
panic("expected version v8 and up only, use specs-actors for v0-7") 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) codeIDs, err := actors.GetActorCodeIDs(av)
if err != nil { if err != nil {

View File

@ -39,15 +39,15 @@ import (
func NewActorRegistry() *vm.ActorRegistry { func NewActorRegistry() *vm.ActorRegistry {
inv := vm.NewActorRegistry() inv := vm.NewActorRegistry()
inv.Register(actorstypes.Version0, vm.ActorsVersionPredicate(actorstypes.Version0), exported0.BuiltinActors()...) inv.Register(actorstypes.Version0, vm.ActorsVersionPredicate(actorstypes.Version0), builtin.MakeRegistryLegacy(exported0.BuiltinActors()))
inv.Register(actorstypes.Version2, vm.ActorsVersionPredicate(actorstypes.Version2), exported2.BuiltinActors()...) inv.Register(actorstypes.Version2, vm.ActorsVersionPredicate(actorstypes.Version2), builtin.MakeRegistryLegacy(exported2.BuiltinActors()))
inv.Register(actorstypes.Version3, vm.ActorsVersionPredicate(actorstypes.Version3), exported3.BuiltinActors()...) inv.Register(actorstypes.Version3, vm.ActorsVersionPredicate(actorstypes.Version3), builtin.MakeRegistryLegacy(exported3.BuiltinActors()))
inv.Register(actorstypes.Version4, vm.ActorsVersionPredicate(actorstypes.Version4), exported4.BuiltinActors()...) inv.Register(actorstypes.Version4, vm.ActorsVersionPredicate(actorstypes.Version4), builtin.MakeRegistryLegacy(exported4.BuiltinActors()))
inv.Register(actorstypes.Version5, vm.ActorsVersionPredicate(actorstypes.Version5), exported5.BuiltinActors()...) inv.Register(actorstypes.Version5, vm.ActorsVersionPredicate(actorstypes.Version5), builtin.MakeRegistryLegacy(exported5.BuiltinActors()))
inv.Register(actorstypes.Version6, vm.ActorsVersionPredicate(actorstypes.Version6), exported6.BuiltinActors()...) inv.Register(actorstypes.Version6, vm.ActorsVersionPredicate(actorstypes.Version6), builtin.MakeRegistryLegacy(exported6.BuiltinActors()))
inv.Register(actorstypes.Version7, vm.ActorsVersionPredicate(actorstypes.Version7), exported7.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.Version8, vm.ActorsVersionPredicate(actorstypes.Version8), builtin.MakeRegistry(actorstypes.Version8))
inv.Register(actorstypes.Version9, vm.ActorsVersionPredicate(actorstypes.Version9), builtin.MakeRegistry(actorstypes.Version9)...) inv.Register(actorstypes.Version9, vm.ActorsVersionPredicate(actorstypes.Version9), builtin.MakeRegistry(actorstypes.Version9))
return inv return inv
} }

View File

@ -20,6 +20,7 @@ import (
actorstypes "github.com/filecoin-project/go-state-types/actors" actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/cbor"
"github.com/filecoin-project/go-state-types/network" "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" builtin0 "github.com/filecoin-project/specs-actors/actors/builtin"
init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init" init2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/init"
rt2 "github.com/filecoin-project/specs-actors/v2/actors/runtime" 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/api"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/aerrors" "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" _init "github.com/filecoin-project/lotus/chain/actors/builtin/init"
"github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/chain/consensus/filcns" "github.com/filecoin-project/lotus/chain/consensus/filcns"
@ -168,7 +170,8 @@ func TestForkHeightTriggers(t *testing.T) {
} }
inv := filcns.NewActorRegistry() 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) { sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) {
nvm, err := vm.NewLegacyVM(ctx, vmopt) nvm, err := vm.NewLegacyVM(ctx, vmopt)
@ -285,7 +288,8 @@ func testForkRefuseCall(t *testing.T, nullsBefore, nullsAfter int) {
} }
inv := filcns.NewActorRegistry() 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) { sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) {
nvm, err := vm.NewLegacyVM(ctx, vmopt) nvm, err := vm.NewLegacyVM(ctx, vmopt)
@ -506,7 +510,8 @@ func TestForkPreMigration(t *testing.T) {
}() }()
inv := filcns.NewActorRegistry() 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) { sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) {
nvm, err := vm.NewLegacyVM(ctx, vmopt) nvm, err := vm.NewLegacyVM(ctx, vmopt)

View File

@ -15,7 +15,6 @@ import (
actorstypes "github.com/filecoin-project/go-state-types/actors" actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/go-state-types/network" "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" vmr "github.com/filecoin-project/specs-actors/v7/actors/runtime"
"github.com/filecoin-project/lotus/chain/actors" "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.). // 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 { 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()) aver, err := actorstypes.VersionForNetwork(rt.NetworkVersion())
if err != nil { if err != nil {
return xerrors.Errorf("unsupported network version: %w", err) return xerrors.Errorf("unsupported network version: %w", err)
} }
if aver != ver { 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 return nil
} }
} }
type invokeFunc func(rt vmr.Runtime, params []byte) ([]byte, aerrors.ActorError) type invokeFunc func(rt vmr.Runtime, params []byte) ([]byte, aerrors.ActorError)
type nativeCode []invokeFunc type nativeCode map[uint64]invokeFunc
type actorInfo struct { type actorInfo struct {
methods nativeCode methods nativeCode
vmActor rtt.VMActor vmActor builtin.RegistryEntry
// TODO: consider making this a network version range? // TODO: consider making this a network version range?
predicate ActorPredicate 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()) 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)) 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) 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 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 { 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 { for _, a := range vmactors {
// register in the `actors` map (for the invoker) // 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() et := ev.Type()
methods[abi.MethodNum(number)] = MethodMeta{ methods[abi.MethodNum(number)] = MethodMeta{
Num: strconv.Itoa(number), Num: strconv.Itoa(int(number)),
Params: et.In(1), Params: et.In(1),
Ret: et.Out(0), 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.") 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) 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{ return &types.Actor{
Code: codeCid, Code: codeCid,
Head: EmptyObjectCid, Head: EmptyObjectCid,
@ -175,7 +171,7 @@ func (ar *ActorRegistry) Create(codeCid cid.Cid, rt vmr.Runtime) (*types.Actor,
} }
type invokee interface { type invokee interface {
Exports() []interface{} Exports() map[uint64]interface{}
} }
func (*ActorRegistry) transform(instance invokee) (nativeCode, error) { func (*ActorRegistry) transform(instance invokee) (nativeCode, error) {

View File

@ -49,19 +49,19 @@ func init() {
cbor.RegisterCborType(basicParams{}) cbor.RegisterCborType(basicParams{})
} }
func (b basicContract) Exports() []interface{} { func (b basicContract) Exports() map[uint64]interface{} {
return []interface{}{ return map[uint64]interface{}{
b.InvokeSomething0, 0: b.InvokeSomething0,
b.BadParam, 1: b.BadParam,
nil, 2: nil,
nil, 3: nil,
nil, 4: nil,
nil, 5: nil,
nil, 6: nil,
nil, 7: nil,
nil, 8: nil,
nil, 9: nil,
b.InvokeSomething10, 10: b.InvokeSomething10,
} }
} }

View File

@ -15,9 +15,11 @@ import (
"github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/network" "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/test-vectors/schema"
"github.com/filecoin-project/lotus/blockstore" "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/consensus/filcns"
"github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/stmgr" "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. // register the chaos actor if required by the vector.
if chaosOn, ok := d.selector["chaos_actor"]; ok && chaosOn == "true" { if chaosOn, ok := d.selector["chaos_actor"]; ok && chaosOn == "true" {
av, _ := actorstypes.VersionForNetwork(params.NetworkVersion) 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) lvm.SetInvoker(invoker)

2
go.mod
View File

@ -42,7 +42,7 @@ require (
github.com/filecoin-project/go-legs v0.4.4 github.com/filecoin-project/go-legs v0.4.4
github.com/filecoin-project/go-padreader v0.0.1 github.com/filecoin-project/go-padreader v0.0.1
github.com/filecoin-project/go-paramfetch v0.0.4 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-statemachine v1.0.2
github.com/filecoin-project/go-statestore v0.2.0 github.com/filecoin-project/go-statestore v0.2.0
github.com/filecoin-project/go-storedcounter v0.1.0 github.com/filecoin-project/go-storedcounter v0.1.0

4
go.sum
View File

@ -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.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.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.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.0.20220920181425-d683559e386b h1:s4F3e3EBo56j+4xmrzmoAIvtgvDwLn4nsIf5bqcU0Qg=
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/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 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 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc=
github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54= github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54=