Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Invoker: Use MethodMeta from go-state-types #9520

Merged
merged 1 commit into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions chain/actors/builtin/registry.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package builtin

import (
"reflect"
"runtime"
"strings"

"github.com/ipfs/go-cid"

actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/builtin"
account8 "github.com/filecoin-project/go-state-types/builtin/v8/account"
cron8 "github.com/filecoin-project/go-state-types/builtin/v8/cron"
_init8 "github.com/filecoin-project/go-state-types/builtin/v8/init"
Expand Down Expand Up @@ -36,14 +41,14 @@ import (
type RegistryEntry struct {
state cbor.Er
code cid.Cid
methods map[uint64]interface{}
methods map[uint64]builtin.MethodMeta
}

func (r RegistryEntry) State() cbor.Er {
return r.state
}

func (r RegistryEntry) Exports() map[uint64]interface{} {
func (r RegistryEntry) Exports() map[uint64]builtin.MethodMeta {
return r.methods
}

Expand All @@ -55,9 +60,11 @@ func MakeRegistryLegacy(actors []rtt.VMActor) []RegistryEntry {
registry := make([]RegistryEntry, 0)

for _, actor := range actors {
methodMap := make(map[uint64]interface{})
methodMap := make(map[uint64]builtin.MethodMeta)
for methodNum, method := range actor.Exports() {
methodMap[uint64(methodNum)] = method
if method != nil {
methodMap[uint64(methodNum)] = makeMethodMeta(method)
}
}
registry = append(registry, RegistryEntry{
code: actor.Code(),
Expand All @@ -69,6 +76,20 @@ func MakeRegistryLegacy(actors []rtt.VMActor) []RegistryEntry {
return registry
}

func makeMethodMeta(method interface{}) builtin.MethodMeta {
ev := reflect.ValueOf(method)
// Extract the method names using reflection. These
// method names always match the field names in the
// `builtin.Method*` structs (tested in the specs-actors
// tests).
fnName := runtime.FuncForPC(ev.Pointer()).Name()
fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm")
return builtin.MethodMeta{
Name: fnName,
Method: method,
}
}

func MakeRegistry(av actorstypes.Version) []RegistryEntry {
if av < actorstypes.Version8 {
panic("expected version v8 and up only, use specs-actors for v0-7")
Expand Down
31 changes: 26 additions & 5 deletions chain/actors/builtin/registry.go.template
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package builtin
import (
actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/ipfs/go-cid"
"reflect"
"runtime"
"strings"

"github.com/filecoin-project/go-state-types/builtin"
{{range .versions}}
{{if (ge . 8)}}
account{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/account"
Expand All @@ -29,14 +34,14 @@ import (
type RegistryEntry struct {
state cbor.Er
code cid.Cid
methods map[uint64]interface{}
methods map[uint64]builtin.MethodMeta
}

func (r RegistryEntry) State() cbor.Er {
return r.state
}

func (r RegistryEntry) Exports() map[uint64]interface{} {
func (r RegistryEntry) Exports() map[uint64]builtin.MethodMeta {
return r.methods
}

Expand All @@ -48,10 +53,12 @@ func MakeRegistryLegacy(actors []rtt.VMActor) []RegistryEntry {
registry := make([]RegistryEntry, 0)

for _, actor := range actors {
methodMap := make(map[uint64]interface{})
methodMap := make(map[uint64]builtin.MethodMeta)
for methodNum, method := range actor.Exports() {
methodMap[uint64(methodNum)] = method
}
if method != nil {
methodMap[uint64(methodNum)] = makeMethodMeta(method)
}
}
registry = append(registry, RegistryEntry{
code: actor.Code(),
methods: methodMap,
Expand All @@ -62,6 +69,20 @@ func MakeRegistryLegacy(actors []rtt.VMActor) []RegistryEntry {
return registry
}

func makeMethodMeta(method interface{}) builtin.MethodMeta {
ev := reflect.ValueOf(method)
// Extract the method names using reflection. These
// method names always match the field names in the
// `builtin.Method*` structs (tested in the specs-actors
// tests).
fnName := runtime.FuncForPC(ev.Pointer()).Name()
fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm")
return builtin.MethodMeta{
Name: fnName,
Method: method,
}
}

func MakeRegistry(av actorstypes.Version) []RegistryEntry {
if av < actorstypes.Version8 {
panic("expected version v8 and up only, use specs-actors for v0-7")
Expand Down
1 change: 0 additions & 1 deletion chain/stmgr/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code)
}

fmt.Println("found ", m.Ret, " and ", m.Params, " for ", m.Num)
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
}

Expand Down
48 changes: 32 additions & 16 deletions chain/vm/invoker.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import (
"encoding/hex"
"fmt"
"reflect"
"strconv"

"github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"

"github.com/filecoin-project/go-state-types/abi"
actorstypes "github.com/filecoin-project/go-state-types/actors"
builtinst "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/go-state-types/network"
vmr "github.com/filecoin-project/specs-actors/v7/actors/runtime"
Expand All @@ -24,7 +24,7 @@ import (
)

type MethodMeta struct {
Num string
Name string

Params reflect.Type
Ret reflect.Type
Expand Down Expand Up @@ -90,10 +90,15 @@ func (ar *ActorRegistry) Register(av actorstypes.Version, pred ActorPredicate, v
pred = func(vmr.Runtime, cid.Cid) error { return nil }
}
for _, a := range vmactors {
// register in the `actors` map (for the invoker)
code, err := ar.transform(a)
if err != nil {
panic(xerrors.Errorf("%s: %w", string(a.Code().Hash()), err))

var code nativeCode
var err error
if av <= actorstypes.Version7 {
// register in the `actors` map (for the invoker)
code, err = ar.transform(a)
if err != nil {
panic(xerrors.Errorf("%s: %w", string(a.Code().Hash()), err))
}
}

ai := &actorInfo{
Expand Down Expand Up @@ -123,26 +128,35 @@ func (ar *ActorRegistry) Register(av actorstypes.Version, pred ActorPredicate, v

// Explicitly add send, it's special.
methods[builtin.MethodSend] = MethodMeta{
Num: "0",
Name: "Send",
Params: reflect.TypeOf(new(abi.EmptyValue)),
Ret: reflect.TypeOf(new(abi.EmptyValue)),
}

// Iterate over exported methods. Some of these _may_ be nil and
// must be skipped.
for number, export := range exports {
if export == nil {
if export.Method == nil {
continue
}

ev := reflect.ValueOf(export)
ev := reflect.ValueOf(export.Method)
et := ev.Type()

methods[abi.MethodNum(number)] = MethodMeta{
Num: strconv.Itoa(int(number)),
Params: et.In(1),
Ret: et.Out(0),
mm := MethodMeta{
Name: export.Name,
Ret: et.Out(0),
}

if av <= actorstypes.Version7 {
// methods exported from specs-actors have the runtime as the first param, so we want et.In(1)
mm.Params = et.In(1)
} else {
// methods exported from go-state-types do not, so we want et.In(0)
mm.Params = et.In(0)
}

methods[abi.MethodNum(number)] = mm
}
if realCode.Defined() {
ar.Methods[realCode] = methods
Expand Down Expand Up @@ -171,15 +185,16 @@ func (ar *ActorRegistry) Create(codeCid cid.Cid, rt vmr.Runtime) (*types.Actor,
}

type invokee interface {
Exports() map[uint64]interface{}
Exports() map[uint64]builtinst.MethodMeta
}

func (*ActorRegistry) transform(instance invokee) (nativeCode, error) {
itype := reflect.TypeOf(instance)
exports := instance.Exports()
runtimeType := reflect.TypeOf((*vmr.Runtime)(nil)).Elem()
for i, m := range exports {
for i, e := range exports {
i := i
m := e.Method
newErr := func(format string, args ...interface{}) error {
str := fmt.Sprintf(format, args...)
return fmt.Errorf("transform(%s) export(%d): %s", itype.Name(), i, str)
Expand Down Expand Up @@ -215,7 +230,8 @@ func (*ActorRegistry) transform(instance invokee) (nativeCode, error) {
}
}
code := make(nativeCode, len(exports))
for id, m := range exports {
for id, e := range exports {
m := e.Method
if m == nil {
continue
}
Expand Down
43 changes: 29 additions & 14 deletions chain/vm/invoker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,36 @@ import (
"io"
"testing"

cid "github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/stretchr/testify/assert"
cbg "github.com/whyrusleeping/cbor-gen"

"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
cbor2 "github.com/filecoin-project/go-state-types/cbor"
"github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/go-state-types/rt"
runtime2 "github.com/filecoin-project/specs-actors/v2/actors/runtime"

"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/aerrors"
"github.com/filecoin-project/lotus/chain/actors/builtin"
)

type basicContract struct{}

func (b basicContract) Code() cid.Cid {
return cid.Undef
}

func (b basicContract) State() cbor2.Er {
// works well enough as a dummy state
return new(basicParams)
}

type basicParams struct {
B byte
}
Expand Down Expand Up @@ -49,19 +63,19 @@ func init() {
cbor.RegisterCborType(basicParams{})
}

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,
func (b basicContract) Exports() []interface{} {
return []interface{}{
b.InvokeSomething0,
b.BadParam,
nil,
nil,
nil,
nil,
nil,
nil,
nil,
nil,
b.InvokeSomething10,
}
}

Expand Down Expand Up @@ -107,7 +121,8 @@ func (*basicRtMessage) ValueReceived() abi.TokenAmount {
func TestInvokerBasic(t *testing.T) {
//stm: @INVOKER_TRANSFORM_001
inv := ActorRegistry{}
code, err := inv.transform(basicContract{})
registry := builtin.MakeRegistryLegacy([]rt.VMActor{basicContract{}})
code, err := inv.transform(registry[0])
assert.NoError(t, err)

{
Expand Down
4 changes: 2 additions & 2 deletions cli/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,8 @@ var ChainInspectUsage = &cli.Command{

mm := filcns.NewActorRegistry().Methods[code][m.Message.Method] // TODO: use remote map

byMethod[mm.Num] += m.Message.GasLimit
byMethodC[mm.Num]++
byMethod[mm.Name] += m.Message.GasLimit
byMethodC[mm.Name]++
}

type keyGasPair struct {
Expand Down
3 changes: 1 addition & 2 deletions cli/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,7 @@ func TestInspectUsage(t *testing.T) {
// check for gas by sender
assert.Contains(t, out, "By Sender")
// check for gas by method
methodStr := fmt.Sprintf("By Method:\n%d", builtin.MethodSend)
assert.Contains(t, out, methodStr)
assert.Contains(t, out, "By Method:\nSend")
})
}

Expand Down
2 changes: 1 addition & 1 deletion cli/multisig.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ var msigInspectCmd = &cli.Command{
paramStr = string(b)
}

fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%s(%d)\t%s\n", txid, "pending", len(tx.Approved), target, types.FIL(tx.Value), method.Num, tx.Method, paramStr)
fmt.Fprintf(w, "%d\t%s\t%d\t%s\t%s\t%s(%d)\t%s\n", txid, "pending", len(tx.Approved), target, types.FIL(tx.Value), method.Name, tx.Method, paramStr)
}
}
if err := w.Flush(); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cli/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -1384,7 +1384,7 @@ func codeStr(c cid.Cid) string {
}

func getMethod(code cid.Cid, method abi.MethodNum) string {
return filcns.NewActorRegistry().Methods[code][method].Num // todo: use remote
return filcns.NewActorRegistry().Methods[code][method].Name // todo: use remote
}

func toFil(f types.BigInt) types.FIL {
Expand Down
2 changes: 1 addition & 1 deletion cmd/lotus-shed/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func printMessage(cctx *cli.Context, msg *types.Message) error {
return nil
}

fmt.Println("Method:", filcns.NewActorRegistry().Methods[toact.Code][msg.Method].Num) // todo use remote
fmt.Println("Method:", filcns.NewActorRegistry().Methods[toact.Code][msg.Method].Name) // todo use remote
p, err := lcli.JsonParams(toact.Code, msg.Method, msg.Params)
if err != nil {
return err
Expand Down
Loading