Skip to content

Commit

Permalink
Merge pull request #9520 from filecoin-project/asr/invoker-method-name
Browse files Browse the repository at this point in the history
feat: Invoker: Use MethodMeta from go-state-types
  • Loading branch information
arajasek authored Oct 19, 2022
2 parents 6c08797 + 13b59c9 commit 8405017
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 53 deletions.
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

0 comments on commit 8405017

Please sign in to comment.