feat: vm: switch to the new exec trace format (#10372)

This is now "FVM" native. Changes include:

1. Don't treat "trace" messages like off-chain messages. E.g., don't
include CIDs, versions, etc.
2. Include IPLD codecs where applicable.
3. Remove fields that aren't filled by the FVM (timing, some errors,
code locations, etc.).
This commit is contained in:
Steven Allen 2023-03-01 16:02:18 -08:00 committed by Aayush
parent 7dcef330e7
commit f6add2f723
18 changed files with 964 additions and 1112 deletions

View File

@ -1,5 +1,159 @@
# Lotus changelog
# UNRELEASED
## Execution Trace Format Changes
Execution traces (returned from `lotus state exec-trace`, `lotus state replay`, etc.), has changed to account for changes introduced by the FVM. Specifically:
- The `Msg` field no longer matches the Filecoin message format as many of the message fields didn't make sense in on-chain sub-calls. Instead, it now has the fields `To`, `From`, `Value`, `Method`, `Params`, and `ParamsCodec` where `ParamsCodec` is a new field indicating the IPLD codec of the parameters.
- Importantly, the `Msg.CID` field has been removed. This field is still present in top-level invocation results, just not inside the execution trace itself.
- The `MsgRct` field no longer includes a `GasUsed` field and now has a `ReturnCodec` field to indicating the IPLD codec of the return value.
- The `Error` and `Duration` fields have been removed as these are not set by the FVM. The top-level message "invocation result" retains the `Error` and `Duration` fields, they've only been removed from the trace itself.
- Gas Charges no longer include "virtual" gas fields (those starting with `v...`) or source location information (`loc`) as neither field is set by the FVM.
A note on "codecs": FVM parameters and return values are IPLD blocks where the "codec" specifies the data encoding. The codec will generally be one of:
- `0x51`, `0x71` - CBOR or DagCBOR. You should generally treat these as equivalent.
- `0x55` - Raw bytes.
- `0x00` - Nothing. If the codec is `0x00`, the parameter and/or return value should be empty and should be treated as "void" (not specified).
<details>
<summary>
Old <code>ExecutionTrace</code>:
</summary>
```json
{
"Msg": {
"Version": 0,
"To": "f01234",
"From": "f04321",
"Nonce": 1,
"Value": "0",
"GasLimit": 0,
"GasFeeCap": "1234",
"GasPremium": "1234",
"Method": 42,
"Params": "<base64-data-or-null>",
"CID": {
"/": "bafyxyz....."
},
},
"MsgRct": {
"ExitCode": 0,
"Return": "<base64-data-or-null>",
"GasUsed": 12345,
},
"Error": "",
"Duration": 568191845,
"GasCharges": [
{
"Name": "OnMethodInvocation",
"loc": null,
"tg": 23856,
"cg": 23856,
"sg": 0,
"vtg": 0,
"vcg": 0,
"vsg": 0,
"tt": 0
},
{
"Name": "wasm_exec",
"loc": null,
"tg": 1764,
"cg": 1764,
"sg": 0,
"vtg": 0,
"vcg": 0,
"vsg": 0,
"tt": 0
},
{
"Name": "OnSyscall",
"loc": null,
"tg": 14000,
"cg": 14000,
"sg": 0,
"vtg": 0,
"vcg": 0,
"vsg": 0,
"tt": 0
},
],
"Subcalls": [
{
"Msg": { },
"MsgRct": { },
"Error": "",
"Duration": 1235,
"GasCharges": [],
"Subcalls": [],
},
]
}
```
</details>
<details>
<summary>
New <code>ExecutionTrace</code>:
</summary>
```json
{
"Msg": {
"To": "f01234",
"From": "f04321",
"Value": "0",
"Method": 42,
"Params": "<base64-data-or-null>",
"ParamsCodec": 81
},
"MsgRct": {
"ExitCode": 0,
"Return": "<base64-data-or-null>",
"ReturnCodec": 81
},
"GasCharges": [
{
"Name": "OnMethodInvocation",
"loc": null,
"tg": 23856,
"cg": 23856,
"tt": 0
},
{
"Name": "wasm_exec",
"loc": null,
"tg": 1764,
"cg": 1764,
"sg": 0,
"tt": 0
},
{
"Name": "OnSyscall",
"loc": null,
"tg": 14000,
"cg": 14000,
"sg": 0,
"tt": 0
},
],
"Subcalls": [
{
"Msg": { },
"MsgRct": { },
"GasCharges": [],
"Subcalls": [],
},
]
}
```
</details>
# v1.20.4 / 2023-03-17
This is a patch release intended to alleviate performance issues reported by some users since the nv18 upgrade.

View File

@ -152,8 +152,8 @@ func init() {
addExample(map[string]int{"name": 42})
addExample(map[string]time.Time{"name": time.Unix(1615243938, 0).UTC()})
addExample(&types.ExecutionTrace{
Msg: ExampleValue("init", reflect.TypeOf(&types.Message{}), nil).(*types.Message),
MsgRct: ExampleValue("init", reflect.TypeOf(&types.MessageReceipt{}), nil).(*types.MessageReceipt),
Msg: ExampleValue("init", reflect.TypeOf(types.MessageTrace{}), nil).(types.MessageTrace),
MsgRct: ExampleValue("init", reflect.TypeOf(types.ReturnTrace{}), nil).(types.ReturnTrace),
})
addExample(map[string]types.Actor{
"t01236": ExampleValue("init", reflect.TypeOf(types.Actor{}), nil).(types.Actor),

Binary file not shown.

Binary file not shown.

View File

@ -525,12 +525,11 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *stmgr.StateManager, _ st
MessageReceipt: *stmgr.MakeFakeRct(),
ActorErr: nil,
ExecutionTrace: types.ExecutionTrace{
Msg: fakeMsg,
MsgRct: stmgr.MakeFakeRct(),
Error: "",
Duration: 0,
GasCharges: nil,
Subcalls: subcalls,
Msg: types.MessageTrace{
To: fakeMsg.To,
From: fakeMsg.From,
},
Subcalls: subcalls,
},
Duration: 0,
GasCosts: nil,
@ -703,12 +702,11 @@ func splitGenesisMultisig0(ctx context.Context, em stmgr.ExecMonitor, addr addre
MessageReceipt: *stmgr.MakeFakeRct(),
ActorErr: nil,
ExecutionTrace: types.ExecutionTrace{
Msg: fakeMsg,
MsgRct: stmgr.MakeFakeRct(),
Error: "",
Duration: 0,
GasCharges: nil,
Subcalls: subcalls,
Msg: types.MessageTrace{
From: fakeMsg.From,
To: fakeMsg.To,
},
Subcalls: subcalls,
},
Duration: 0,
GasCosts: nil,

View File

@ -347,12 +347,11 @@ func DoTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmo
// record the transfer in execution traces
cb(types.ExecutionTrace{
Msg: MakeFakeMsg(from, to, amt, 0),
MsgRct: MakeFakeRct(),
Error: "",
Duration: 0,
GasCharges: nil,
Subcalls: nil,
Msg: types.MessageTrace{
From: from,
To: to,
Value: amt,
},
})
}

View File

@ -7,6 +7,7 @@ import (
"io"
"math"
"sort"
time "time"
cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
@ -15,6 +16,7 @@ import (
address "github.com/filecoin-project/go-address"
abi "github.com/filecoin-project/go-state-types/abi"
crypto "github.com/filecoin-project/go-state-types/crypto"
exitcode "github.com/filecoin-project/go-state-types/exitcode"
proof "github.com/filecoin-project/go-state-types/proof"
)
@ -2078,3 +2080,659 @@ func (t *EventEntry) UnmarshalCBOR(r io.Reader) (err error) {
}
return nil
}
var lengthBufGasTrace = []byte{133}
func (t *GasTrace) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
cw := cbg.NewCborWriter(w)
if _, err := cw.Write(lengthBufGasTrace); err != nil {
return err
}
// t.Name (string) (string)
if len(t.Name) > cbg.MaxLength {
return xerrors.Errorf("Value in field t.Name was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Name))); err != nil {
return err
}
if _, err := io.WriteString(w, string(t.Name)); err != nil {
return err
}
// t.TotalGas (int64) (int64)
if t.TotalGas >= 0 {
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.TotalGas)); err != nil {
return err
}
} else {
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.TotalGas-1)); err != nil {
return err
}
}
// t.ComputeGas (int64) (int64)
if t.ComputeGas >= 0 {
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ComputeGas)); err != nil {
return err
}
} else {
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.ComputeGas-1)); err != nil {
return err
}
}
// t.StorageGas (int64) (int64)
if t.StorageGas >= 0 {
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.StorageGas)); err != nil {
return err
}
} else {
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.StorageGas-1)); err != nil {
return err
}
}
// t.TimeTaken (time.Duration) (int64)
if t.TimeTaken >= 0 {
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.TimeTaken)); err != nil {
return err
}
} else {
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.TimeTaken-1)); err != nil {
return err
}
}
return nil
}
func (t *GasTrace) UnmarshalCBOR(r io.Reader) (err error) {
*t = GasTrace{}
cr := cbg.NewCborReader(r)
maj, extra, err := cr.ReadHeader()
if err != nil {
return err
}
defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
}()
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 5 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Name (string) (string)
{
sval, err := cbg.ReadString(cr)
if err != nil {
return err
}
t.Name = string(sval)
}
// t.TotalGas (int64) (int64)
{
maj, extra, err := cr.ReadHeader()
var extraI int64
if err != nil {
return err
}
switch maj {
case cbg.MajUnsignedInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 positive overflow")
}
case cbg.MajNegativeInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 negative oveflow")
}
extraI = -1 - extraI
default:
return fmt.Errorf("wrong type for int64 field: %d", maj)
}
t.TotalGas = int64(extraI)
}
// t.ComputeGas (int64) (int64)
{
maj, extra, err := cr.ReadHeader()
var extraI int64
if err != nil {
return err
}
switch maj {
case cbg.MajUnsignedInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 positive overflow")
}
case cbg.MajNegativeInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 negative oveflow")
}
extraI = -1 - extraI
default:
return fmt.Errorf("wrong type for int64 field: %d", maj)
}
t.ComputeGas = int64(extraI)
}
// t.StorageGas (int64) (int64)
{
maj, extra, err := cr.ReadHeader()
var extraI int64
if err != nil {
return err
}
switch maj {
case cbg.MajUnsignedInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 positive overflow")
}
case cbg.MajNegativeInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 negative oveflow")
}
extraI = -1 - extraI
default:
return fmt.Errorf("wrong type for int64 field: %d", maj)
}
t.StorageGas = int64(extraI)
}
// t.TimeTaken (time.Duration) (int64)
{
maj, extra, err := cr.ReadHeader()
var extraI int64
if err != nil {
return err
}
switch maj {
case cbg.MajUnsignedInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 positive overflow")
}
case cbg.MajNegativeInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 negative oveflow")
}
extraI = -1 - extraI
default:
return fmt.Errorf("wrong type for int64 field: %d", maj)
}
t.TimeTaken = time.Duration(extraI)
}
return nil
}
var lengthBufMessageTrace = []byte{134}
func (t *MessageTrace) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
cw := cbg.NewCborWriter(w)
if _, err := cw.Write(lengthBufMessageTrace); err != nil {
return err
}
// t.From (address.Address) (struct)
if err := t.From.MarshalCBOR(cw); err != nil {
return err
}
// t.To (address.Address) (struct)
if err := t.To.MarshalCBOR(cw); err != nil {
return err
}
// t.Value (big.Int) (struct)
if err := t.Value.MarshalCBOR(cw); err != nil {
return err
}
// t.Method (abi.MethodNum) (uint64)
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Method)); err != nil {
return err
}
// t.Params ([]uint8) (slice)
if len(t.Params) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.Params was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Params))); err != nil {
return err
}
if _, err := cw.Write(t.Params[:]); err != nil {
return err
}
// t.ParamsCodec (uint64) (uint64)
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ParamsCodec)); err != nil {
return err
}
return nil
}
func (t *MessageTrace) UnmarshalCBOR(r io.Reader) (err error) {
*t = MessageTrace{}
cr := cbg.NewCborReader(r)
maj, extra, err := cr.ReadHeader()
if err != nil {
return err
}
defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
}()
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 6 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.From (address.Address) (struct)
{
if err := t.From.UnmarshalCBOR(cr); err != nil {
return xerrors.Errorf("unmarshaling t.From: %w", err)
}
}
// t.To (address.Address) (struct)
{
if err := t.To.UnmarshalCBOR(cr); err != nil {
return xerrors.Errorf("unmarshaling t.To: %w", err)
}
}
// t.Value (big.Int) (struct)
{
if err := t.Value.UnmarshalCBOR(cr); err != nil {
return xerrors.Errorf("unmarshaling t.Value: %w", err)
}
}
// t.Method (abi.MethodNum) (uint64)
{
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Method = abi.MethodNum(extra)
}
// t.Params ([]uint8) (slice)
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.Params: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array")
}
if extra > 0 {
t.Params = make([]uint8, extra)
}
if _, err := io.ReadFull(cr, t.Params[:]); err != nil {
return err
}
// t.ParamsCodec (uint64) (uint64)
{
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.ParamsCodec = uint64(extra)
}
return nil
}
var lengthBufReturnTrace = []byte{131}
func (t *ReturnTrace) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
cw := cbg.NewCborWriter(w)
if _, err := cw.Write(lengthBufReturnTrace); err != nil {
return err
}
// t.ExitCode (exitcode.ExitCode) (int64)
if t.ExitCode >= 0 {
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ExitCode)); err != nil {
return err
}
} else {
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.ExitCode-1)); err != nil {
return err
}
}
// t.Return ([]uint8) (slice)
if len(t.Return) > cbg.ByteArrayMaxLen {
return xerrors.Errorf("Byte array in field t.Return was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Return))); err != nil {
return err
}
if _, err := cw.Write(t.Return[:]); err != nil {
return err
}
// t.ReturnCodec (uint64) (uint64)
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ReturnCodec)); err != nil {
return err
}
return nil
}
func (t *ReturnTrace) UnmarshalCBOR(r io.Reader) (err error) {
*t = ReturnTrace{}
cr := cbg.NewCborReader(r)
maj, extra, err := cr.ReadHeader()
if err != nil {
return err
}
defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
}()
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 3 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.ExitCode (exitcode.ExitCode) (int64)
{
maj, extra, err := cr.ReadHeader()
var extraI int64
if err != nil {
return err
}
switch maj {
case cbg.MajUnsignedInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 positive overflow")
}
case cbg.MajNegativeInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 negative oveflow")
}
extraI = -1 - extraI
default:
return fmt.Errorf("wrong type for int64 field: %d", maj)
}
t.ExitCode = exitcode.ExitCode(extraI)
}
// t.Return ([]uint8) (slice)
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if extra > cbg.ByteArrayMaxLen {
return fmt.Errorf("t.Return: byte array too large (%d)", extra)
}
if maj != cbg.MajByteString {
return fmt.Errorf("expected byte array")
}
if extra > 0 {
t.Return = make([]uint8, extra)
}
if _, err := io.ReadFull(cr, t.Return[:]); err != nil {
return err
}
// t.ReturnCodec (uint64) (uint64)
{
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.ReturnCodec = uint64(extra)
}
return nil
}
var lengthBufExecutionTrace = []byte{132}
func (t *ExecutionTrace) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
cw := cbg.NewCborWriter(w)
if _, err := cw.Write(lengthBufExecutionTrace); err != nil {
return err
}
// t.Msg (types.MessageTrace) (struct)
if err := t.Msg.MarshalCBOR(cw); err != nil {
return err
}
// t.MsgRct (types.ReturnTrace) (struct)
if err := t.MsgRct.MarshalCBOR(cw); err != nil {
return err
}
// t.GasCharges ([]*types.GasTrace) (slice)
if len(t.GasCharges) > 1000000000 {
return xerrors.Errorf("Slice value in field t.GasCharges was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.GasCharges))); err != nil {
return err
}
for _, v := range t.GasCharges {
if err := v.MarshalCBOR(cw); err != nil {
return err
}
}
// t.Subcalls ([]types.ExecutionTrace) (slice)
if len(t.Subcalls) > 1000000000 {
return xerrors.Errorf("Slice value in field t.Subcalls was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Subcalls))); err != nil {
return err
}
for _, v := range t.Subcalls {
if err := v.MarshalCBOR(cw); err != nil {
return err
}
}
return nil
}
func (t *ExecutionTrace) UnmarshalCBOR(r io.Reader) (err error) {
*t = ExecutionTrace{}
cr := cbg.NewCborReader(r)
maj, extra, err := cr.ReadHeader()
if err != nil {
return err
}
defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
}()
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 4 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Msg (types.MessageTrace) (struct)
{
if err := t.Msg.UnmarshalCBOR(cr); err != nil {
return xerrors.Errorf("unmarshaling t.Msg: %w", err)
}
}
// t.MsgRct (types.ReturnTrace) (struct)
{
if err := t.MsgRct.UnmarshalCBOR(cr); err != nil {
return xerrors.Errorf("unmarshaling t.MsgRct: %w", err)
}
}
// t.GasCharges ([]*types.GasTrace) (slice)
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if extra > 1000000000 {
return fmt.Errorf("t.GasCharges: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.GasCharges = make([]*GasTrace, extra)
}
for i := 0; i < int(extra); i++ {
var v GasTrace
if err := v.UnmarshalCBOR(cr); err != nil {
return err
}
t.GasCharges[i] = &v
}
// t.Subcalls ([]types.ExecutionTrace) (slice)
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if extra > 1000000000 {
return fmt.Errorf("t.Subcalls: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.Subcalls = make([]ExecutionTrace, extra)
}
for i := 0; i < int(extra); i++ {
var v ExecutionTrace
if err := v.UnmarshalCBOR(cr); err != nil {
return err
}
t.Subcalls[i] = v
}
return nil
}

View File

@ -2,44 +2,41 @@ package types
import (
"encoding/json"
"fmt"
"regexp"
"runtime"
"strings"
"time"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/exitcode"
)
type ExecutionTrace struct {
Msg *Message
MsgRct *MessageReceipt
Error string
Duration time.Duration
GasCharges []*GasTrace
Subcalls []ExecutionTrace
}
type GasTrace struct {
Name string
Location []Loc `json:"loc"`
TotalGas int64 `json:"tg"`
ComputeGas int64 `json:"cg"`
StorageGas int64 `json:"sg"`
TotalVirtualGas int64 `json:"vtg"`
VirtualComputeGas int64 `json:"vcg"`
VirtualStorageGas int64 `json:"vsg"`
TimeTaken time.Duration `json:"tt"`
Extra interface{} `json:"ex,omitempty"`
Callers []uintptr `json:"-"`
Name string
TotalGas int64 `json:"tg"`
ComputeGas int64 `json:"cg"`
StorageGas int64 `json:"sg"`
TimeTaken time.Duration `json:"tt"`
}
type Loc struct {
File string
Line int
Function string
type MessageTrace struct {
From address.Address
To address.Address
Value abi.TokenAmount
Method abi.MethodNum
Params []byte
ParamsCodec uint64
}
type ReturnTrace struct {
ExitCode exitcode.ExitCode
Return []byte
ReturnCodec uint64
}
type ExecutionTrace struct {
Msg MessageTrace
MsgRct ReturnTrace
GasCharges []*GasTrace `cborgen:"maxlen=1000000000"`
Subcalls []ExecutionTrace `cborgen:"maxlen=1000000000"`
}
func (et ExecutionTrace) SumGas() GasTrace {
@ -52,71 +49,13 @@ func SumGas(charges []*GasTrace) GasTrace {
out.TotalGas += gc.TotalGas
out.ComputeGas += gc.ComputeGas
out.StorageGas += gc.StorageGas
out.TotalVirtualGas += gc.TotalVirtualGas
out.VirtualComputeGas += gc.VirtualComputeGas
out.VirtualStorageGas += gc.VirtualStorageGas
}
return out
}
func (l Loc) Show() bool {
ignorePrefix := []string{
"reflect.",
"github.com/filecoin-project/lotus/chain/vm.(*Invoker).transform",
"github.com/filecoin-project/go-amt-ipld/",
}
for _, pre := range ignorePrefix {
if strings.HasPrefix(l.Function, pre) {
return false
}
}
return true
}
func (l Loc) String() string {
file := strings.Split(l.File, "/")
fn := strings.Split(l.Function, "/")
var fnpkg string
if len(fn) > 2 {
fnpkg = strings.Join(fn[len(fn)-2:], "/")
} else {
fnpkg = l.Function
}
return fmt.Sprintf("%s@%s:%d", fnpkg, file[len(file)-1], l.Line)
}
var importantRegex = regexp.MustCompile(`github.com/filecoin-project/specs-actors/(v\d+/)?actors/builtin`)
func (l Loc) Important() bool {
return importantRegex.MatchString(l.Function)
}
func (gt *GasTrace) MarshalJSON() ([]byte, error) {
type GasTraceCopy GasTrace
if len(gt.Location) == 0 {
if len(gt.Callers) != 0 {
frames := runtime.CallersFrames(gt.Callers)
for {
frame, more := frames.Next()
if frame.Function == "github.com/filecoin-project/lotus/chain/vm.(*VM).ApplyMessage" {
break
}
l := Loc{
File: frame.File,
Line: frame.Line,
Function: frame.Function,
}
gt.Location = append(gt.Location, l)
if !more {
break
}
}
}
}
cpy := (*GasTraceCopy)(gt)
return json.Marshal(cpy)
}

View File

@ -1,391 +0,0 @@
// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT.
package vm
import (
"fmt"
"io"
"math"
"sort"
cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors"
types "github.com/filecoin-project/lotus/chain/types"
)
var _ = xerrors.Errorf
var _ = cid.Undef
var _ = math.E
var _ = sort.Sort
var lengthBufFvmExecutionTrace = []byte{133}
func (t *FvmExecutionTrace) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
cw := cbg.NewCborWriter(w)
if _, err := cw.Write(lengthBufFvmExecutionTrace); err != nil {
return err
}
// t.Msg (types.Message) (struct)
if err := t.Msg.MarshalCBOR(cw); err != nil {
return err
}
// t.MsgRct (types.MessageReceipt) (struct)
if err := t.MsgRct.MarshalCBOR(cw); err != nil {
return err
}
// t.Error (string) (string)
if len(t.Error) > cbg.MaxLength {
return xerrors.Errorf("Value in field t.Error was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Error))); err != nil {
return err
}
if _, err := io.WriteString(w, string(t.Error)); err != nil {
return err
}
// t.GasCharges ([]vm.FvmGasCharge) (slice)
if len(t.GasCharges) > 1000000000 {
return xerrors.Errorf("Slice value in field t.GasCharges was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.GasCharges))); err != nil {
return err
}
for _, v := range t.GasCharges {
if err := v.MarshalCBOR(cw); err != nil {
return err
}
}
// t.Subcalls ([]vm.FvmExecutionTrace) (slice)
if len(t.Subcalls) > 1000000000 {
return xerrors.Errorf("Slice value in field t.Subcalls was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Subcalls))); err != nil {
return err
}
for _, v := range t.Subcalls {
if err := v.MarshalCBOR(cw); err != nil {
return err
}
}
return nil
}
func (t *FvmExecutionTrace) UnmarshalCBOR(r io.Reader) (err error) {
*t = FvmExecutionTrace{}
cr := cbg.NewCborReader(r)
maj, extra, err := cr.ReadHeader()
if err != nil {
return err
}
defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
}()
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 5 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Msg (types.Message) (struct)
{
b, err := cr.ReadByte()
if err != nil {
return err
}
if b != cbg.CborNull[0] {
if err := cr.UnreadByte(); err != nil {
return err
}
t.Msg = new(types.Message)
if err := t.Msg.UnmarshalCBOR(cr); err != nil {
return xerrors.Errorf("unmarshaling t.Msg pointer: %w", err)
}
}
}
// t.MsgRct (types.MessageReceipt) (struct)
{
b, err := cr.ReadByte()
if err != nil {
return err
}
if b != cbg.CborNull[0] {
if err := cr.UnreadByte(); err != nil {
return err
}
t.MsgRct = new(types.MessageReceipt)
if err := t.MsgRct.UnmarshalCBOR(cr); err != nil {
return xerrors.Errorf("unmarshaling t.MsgRct pointer: %w", err)
}
}
}
// t.Error (string) (string)
{
sval, err := cbg.ReadString(cr)
if err != nil {
return err
}
t.Error = string(sval)
}
// t.GasCharges ([]vm.FvmGasCharge) (slice)
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if extra > 1000000000 {
return fmt.Errorf("t.GasCharges: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.GasCharges = make([]FvmGasCharge, extra)
}
for i := 0; i < int(extra); i++ {
var v FvmGasCharge
if err := v.UnmarshalCBOR(cr); err != nil {
return err
}
t.GasCharges[i] = v
}
// t.Subcalls ([]vm.FvmExecutionTrace) (slice)
maj, extra, err = cr.ReadHeader()
if err != nil {
return err
}
if extra > 1000000000 {
return fmt.Errorf("t.Subcalls: array too large (%d)", extra)
}
if maj != cbg.MajArray {
return fmt.Errorf("expected cbor array")
}
if extra > 0 {
t.Subcalls = make([]FvmExecutionTrace, extra)
}
for i := 0; i < int(extra); i++ {
var v FvmExecutionTrace
if err := v.UnmarshalCBOR(cr); err != nil {
return err
}
t.Subcalls[i] = v
}
return nil
}
var lengthBufFvmGasCharge = []byte{132}
func (t *FvmGasCharge) MarshalCBOR(w io.Writer) error {
if t == nil {
_, err := w.Write(cbg.CborNull)
return err
}
cw := cbg.NewCborWriter(w)
if _, err := cw.Write(lengthBufFvmGasCharge); err != nil {
return err
}
// t.Name (string) (string)
if len(t.Name) > cbg.MaxLength {
return xerrors.Errorf("Value in field t.Name was too long")
}
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Name))); err != nil {
return err
}
if _, err := io.WriteString(w, string(t.Name)); err != nil {
return err
}
// t.TotalGas (int64) (int64)
if t.TotalGas >= 0 {
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.TotalGas)); err != nil {
return err
}
} else {
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.TotalGas-1)); err != nil {
return err
}
}
// t.ComputeGas (int64) (int64)
if t.ComputeGas >= 0 {
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ComputeGas)); err != nil {
return err
}
} else {
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.ComputeGas-1)); err != nil {
return err
}
}
// t.StorageGas (int64) (int64)
if t.StorageGas >= 0 {
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.StorageGas)); err != nil {
return err
}
} else {
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.StorageGas-1)); err != nil {
return err
}
}
return nil
}
func (t *FvmGasCharge) UnmarshalCBOR(r io.Reader) (err error) {
*t = FvmGasCharge{}
cr := cbg.NewCborReader(r)
maj, extra, err := cr.ReadHeader()
if err != nil {
return err
}
defer func() {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
}()
if maj != cbg.MajArray {
return fmt.Errorf("cbor input should be of type array")
}
if extra != 4 {
return fmt.Errorf("cbor input had wrong number of fields")
}
// t.Name (string) (string)
{
sval, err := cbg.ReadString(cr)
if err != nil {
return err
}
t.Name = string(sval)
}
// t.TotalGas (int64) (int64)
{
maj, extra, err := cr.ReadHeader()
var extraI int64
if err != nil {
return err
}
switch maj {
case cbg.MajUnsignedInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 positive overflow")
}
case cbg.MajNegativeInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 negative oveflow")
}
extraI = -1 - extraI
default:
return fmt.Errorf("wrong type for int64 field: %d", maj)
}
t.TotalGas = int64(extraI)
}
// t.ComputeGas (int64) (int64)
{
maj, extra, err := cr.ReadHeader()
var extraI int64
if err != nil {
return err
}
switch maj {
case cbg.MajUnsignedInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 positive overflow")
}
case cbg.MajNegativeInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 negative oveflow")
}
extraI = -1 - extraI
default:
return fmt.Errorf("wrong type for int64 field: %d", maj)
}
t.ComputeGas = int64(extraI)
}
// t.StorageGas (int64) (int64)
{
maj, extra, err := cr.ReadHeader()
var extraI int64
if err != nil {
return err
}
switch maj {
case cbg.MajUnsignedInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 positive overflow")
}
case cbg.MajNegativeInt:
extraI = int64(extra)
if extraI < 0 {
return fmt.Errorf("int64 negative oveflow")
}
extraI = -1 - extraI
default:
return fmt.Errorf("wrong type for int64 field: %d", maj)
}
t.StorageGas = int64(extraI)
}
return nil
}

View File

@ -51,57 +51,6 @@ type FvmExtern struct {
base cid.Cid
}
type FvmGasCharge struct {
Name string
TotalGas int64
ComputeGas int64
StorageGas int64
}
// This may eventually become identical to ExecutionTrace, but we can make incremental progress towards that
type FvmExecutionTrace struct {
Msg *types.Message
MsgRct *types.MessageReceipt
Error string
GasCharges []FvmGasCharge `cborgen:"maxlen=1000000000"`
Subcalls []FvmExecutionTrace `cborgen:"maxlen=1000000000"`
}
func (t *FvmExecutionTrace) ToExecutionTrace() types.ExecutionTrace {
if t == nil {
return types.ExecutionTrace{}
}
ret := types.ExecutionTrace{
Msg: t.Msg,
MsgRct: t.MsgRct,
Error: t.Error,
Subcalls: nil, // Should be nil when there are no subcalls for backwards compatibility
}
if len(t.GasCharges) > 0 {
ret.GasCharges = make([]*types.GasTrace, len(t.GasCharges))
for i, v := range t.GasCharges {
ret.GasCharges[i] = &types.GasTrace{
Name: v.Name,
TotalGas: v.TotalGas,
ComputeGas: v.ComputeGas,
StorageGas: v.StorageGas,
}
}
}
if len(t.Subcalls) > 0 {
ret.Subcalls = make([]types.ExecutionTrace, len(t.Subcalls))
for i, v := range t.Subcalls {
ret.Subcalls[i] = v.ToExecutionTrace()
}
}
return ret
}
func (x *FvmExtern) TipsetCid(ctx context.Context, epoch abi.ChainEpoch) (cid.Cid, error) {
tsk, err := x.tsGet(ctx, epoch)
if err != nil {
@ -487,19 +436,9 @@ func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet
var et types.ExecutionTrace
if len(ret.ExecTraceBytes) != 0 {
var fvmEt FvmExecutionTrace
if err = fvmEt.UnmarshalCBOR(bytes.NewReader(ret.ExecTraceBytes)); err != nil {
if err = et.UnmarshalCBOR(bytes.NewReader(ret.ExecTraceBytes)); err != nil {
return nil, xerrors.Errorf("failed to unmarshal exectrace: %w", err)
}
et = fvmEt.ToExecutionTrace()
}
// Set the top-level exectrace info from the message and receipt for backwards compatibility
et.Msg = vmMsg
et.MsgRct = &receipt
et.Duration = duration
if aerr != nil {
et.Error = aerr.Error()
}
applyRet := &ApplyRet{
@ -562,18 +501,9 @@ func (vm *FVM) ApplyImplicitMessage(ctx context.Context, cmsg *types.Message) (*
var et types.ExecutionTrace
if len(ret.ExecTraceBytes) != 0 {
var fvmEt FvmExecutionTrace
if err = fvmEt.UnmarshalCBOR(bytes.NewReader(ret.ExecTraceBytes)); err != nil {
if err = et.UnmarshalCBOR(bytes.NewReader(ret.ExecTraceBytes)); err != nil {
return nil, xerrors.Errorf("failed to unmarshal exectrace: %w", err)
}
et = fvmEt.ToExecutionTrace()
} else {
et.Msg = vmMsg
et.MsgRct = &receipt
et.Duration = duration
if aerr != nil {
et.Error = aerr.Error()
}
}
applyRet := &ApplyRet{

View File

@ -6,7 +6,6 @@ import (
"encoding/binary"
"fmt"
"os"
gruntime "runtime"
"time"
"github.com/ipfs/go-cid"
@ -571,35 +570,18 @@ func (rt *Runtime) chargeGasFunc(skip int) func(GasCharge) {
func (rt *Runtime) chargeGasInternal(gas GasCharge, skip int) aerrors.ActorError {
toUse := gas.Total()
if EnableDetailedTracing {
var callers [10]uintptr
cout := gruntime.Callers(2+skip, callers[:])
now := build.Clock.Now()
if rt.lastGasCharge != nil {
rt.lastGasCharge.TimeTaken = now.Sub(rt.lastGasChargeTime)
}
gasTrace := types.GasTrace{
Name: gas.Name,
Extra: gas.Extra,
Name: gas.Name,
TotalGas: toUse,
ComputeGas: gas.ComputeGas,
StorageGas: gas.StorageGas,
VirtualComputeGas: gas.VirtualCompute,
VirtualStorageGas: gas.VirtualStorage,
Callers: callers[:cout],
}
if gasTrace.VirtualStorageGas == 0 {
gasTrace.VirtualStorageGas = gasTrace.StorageGas
}
if gasTrace.VirtualComputeGas == 0 {
gasTrace.VirtualComputeGas = gasTrace.ComputeGas
}
gasTrace.TotalVirtualGas = gasTrace.VirtualComputeGas + gasTrace.VirtualStorageGas
rt.executionTrace.GasCharges = append(rt.executionTrace.GasCharges, &gasTrace)
rt.lastGasChargeTime = now

View File

@ -38,6 +38,7 @@ import (
)
const MaxCallDepth = 4096
const CborCodec = 0x51
var (
log = logging.Logger("vm")
@ -125,6 +126,10 @@ func (bs *gasChargingBlocks) Put(ctx context.Context, blk block.Block) error {
}
func (vm *LegacyVM) makeRuntime(ctx context.Context, msg *types.Message, parent *Runtime) *Runtime {
paramsCodec := uint64(0)
if len(msg.Params) > 0 {
paramsCodec = CborCodec
}
rt := &Runtime{
ctx: ctx,
vm: vm,
@ -140,7 +145,14 @@ func (vm *LegacyVM) makeRuntime(ctx context.Context, msg *types.Message, parent
pricelist: PricelistByEpoch(vm.blockHeight),
allowInternal: true,
callerValidated: false,
executionTrace: types.ExecutionTrace{Msg: msg},
executionTrace: types.ExecutionTrace{Msg: types.MessageTrace{
From: msg.From,
To: msg.To,
Value: msg.Value,
Method: msg.Method,
Params: msg.Params,
ParamsCodec: paramsCodec,
}},
}
if parent != nil {
@ -369,15 +381,14 @@ func (vm *LegacyVM) send(ctx context.Context, msg *types.Message, parent *Runtim
return nil, nil
}()
mr := types.MessageReceipt{
ExitCode: aerrors.RetCode(err),
Return: ret,
GasUsed: rt.gasUsed,
retCodec := uint64(0)
if len(ret) > 0 {
retCodec = CborCodec
}
rt.executionTrace.MsgRct = &mr
rt.executionTrace.Duration = time.Since(start)
if err != nil {
rt.executionTrace.Error = err.Error()
rt.executionTrace.MsgRct = types.ReturnTrace{
ExitCode: aerrors.RetCode(err),
Return: ret,
ReturnCodec: retCodec,
}
return ret, err, rt

View File

@ -22,7 +22,6 @@ import (
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
"github.com/multiformats/go-multiaddr"
"github.com/multiformats/go-multihash"
"github.com/urfave/cli/v2"
cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors"
@ -1228,7 +1227,7 @@ var compStateTemplate = `
<div>State CID: <b>{{.Comp.Root}}</b></div>
<div>Calls</div>
{{range .Comp.Trace}}
{{template "message" (Call .ExecutionTrace false .Msg.Cid.String)}}
{{template "message" (Call .ExecutionTrace false .MsgCid.String)}}
{{end}}
</body>
</html>
@ -1253,16 +1252,12 @@ var compStateMsg = `
</a>
</div>
<div><b>{{.Msg.From}}</b> -&gt; <b>{{.Msg.To}}</b> ({{ToFil .Msg.Value}} FIL), M{{.Msg.Method}}</div>
{{if not .Subcall}}<div><small>Msg CID: {{.Msg.Cid}}</small></div>{{end}}
<div><b>{{.Msg.From}}</b> -&gt; <b>{{.Msg.To}}</b> ({{ToFil .Msg.Value}}), M{{.Msg.Method}}</div>
{{if not .Subcall}}<div><small>Msg CID: {{.Hash}}</small></div>{{end}}
{{if gt (len .Msg.Params) 0}}
<div><pre class="params">{{JsonParams ($code) (.Msg.Method) (.Msg.Params) | html}}</pre></div>
{{end}}
{{if PrintTiming}}
<div><span class="slow-{{IsSlow .Duration}}-{{IsVerySlow .Duration}}">Took {{.Duration}}</span>, <span class="exit{{IntExit .MsgRct.ExitCode}}">Exit: <b>{{.MsgRct.ExitCode}}</b></span>{{if gt (len .MsgRct.Return) 0}}, Return{{end}}</div>
{{else}}
<div><span class="exit{{IntExit .MsgRct.ExitCode}}">Exit: <b>{{.MsgRct.ExitCode}}</b></span>{{if gt (len .MsgRct.Return) 0}}, Return{{end}}</div>
{{end}}
{{if gt (len .MsgRct.Return) 0}}
<div><pre class="ret">{{JsonReturn ($code) (.Msg.Method) (.MsgRct.Return) | html}}</pre></div>
{{end}}
@ -1274,62 +1269,26 @@ var compStateMsg = `
<details>
<summary>Gas Trace</summary>
<table>
<tr><th>Name</th><th>Total/Compute/Storage</th><th>Time Taken</th><th>Location</th></tr>
{{define "virt" -}}
{{- if . -}}
<span class="deemp">+({{.}})</span>
{{- end -}}
{{- end}}
<tr><th>Name</th><th>Total/Compute/Storage</th><th>Time Taken</th></tr>
{{define "gasC" -}}
<td>{{.TotalGas}}{{template "virt" .TotalVirtualGas }}/{{.ComputeGas}}{{template "virt" .VirtualComputeGas}}/{{.StorageGas}}{{template "virt" .VirtualStorageGas}}</td>
<td>{{.TotalGas}}/{{.ComputeGas}}/{{.StorageGas}}</td>
{{- end}}
{{range .GasCharges}}
<tr><td>{{.Name}}{{if .Extra}}:{{.Extra}}{{end}}</td>
{{template "gasC" .}}
<td>{{if PrintTiming}}{{.TimeTaken}}{{end}}</td>
<td>
{{ $fImp := FirstImportant .Location }}
{{ if $fImp }}
<details>
<summary>{{ $fImp }}</summary><hr />
{{ $elipOn := false }}
{{ range $index, $ele := .Location -}}
{{- if $index }}<br />{{end -}}
{{- if .Show -}}
{{ if $elipOn }}
{{ $elipOn = false }}
</span></label>
{{end}}
{{- if .Important }}<b>{{end -}}
{{- . -}}
{{if .Important }}</b>{{end}}
{{else}}
{{ if not $elipOn }}
{{ $elipOn = true }}
<label class="ellipsis-toggle"><input type="checkbox" /><span class="ellipsis">[]<br /></span>
<span class="ellipsis-content">
{{end}}
{{- "" -}}
{{- . -}}
{{end}}
{{end}}
{{ if $elipOn }}
{{ $elipOn = false }}
</span></label>
{{end}}
</details>
{{end}}
</td></tr>
{{end}}
{{with sumGas .GasCharges}}
<tr class="sum"><td><b>Sum</b></td>
{{template "gasC" .}}
<td>{{if PrintTiming}}{{.TimeTaken}}{{end}}</td>
<td></td></tr>
{{end}}
<tr>
<td>{{.Name}}</td>
{{template "gasC" .}}
<td>{{if PrintTiming}}{{.TimeTaken}}{{end}}</td>
</tr>
{{end}}
{{with sumGas .GasCharges}}
<tr class="sum">
<td><b>Sum</b></td>
{{template "gasC" .}}
<td>{{if PrintTiming}}{{.TimeTaken}}{{end}}</td>
</tr>
{{end}}
</table>
</details>
@ -1337,8 +1296,8 @@ var compStateMsg = `
{{if gt (len .Subcalls) 0}}
<div>Subcalls:</div>
{{$hash := .Hash}}
{{range .Subcalls}}
{{template "message" (Call . true (printf "%s-%s" $hash .Msg.Cid.String))}}
{{range $i, $call := .Subcalls}}
{{template "message" (Call $call true (printf "%s-%d" $hash $i))}}
{{end}}
{{end}}
</div>`
@ -1359,20 +1318,9 @@ func ComputeStateHTMLTempl(w io.Writer, ts *types.TipSet, o *api.ComputeStateOut
"IsVerySlow": isVerySlow,
"IntExit": func(i exitcode.ExitCode) int64 { return int64(i) },
"sumGas": types.SumGas,
"CodeStr": codeStr,
"CodeStr": builtin.ActorNameByCode,
"Call": call,
"PrintTiming": func() bool { return printTiming },
"FirstImportant": func(locs []types.Loc) *types.Loc {
if len(locs) != 0 {
for _, l := range locs {
if l.Important() {
return &l
}
}
return &locs[0]
}
return nil
},
}).Parse(compStateTemplate)
if err != nil {
return err
@ -1402,14 +1350,6 @@ func call(e types.ExecutionTrace, subcall bool, hash string) callMeta {
}
}
func codeStr(c cid.Cid) string {
cmh, err := multihash.Decode(c.Hash())
if err != nil {
panic(err)
}
return string(cmh.Digest)
}
func getMethod(code cid.Cid, method abi.MethodNum) string {
return filcns.NewActorRegistry().Methods[code][method].Name // todo: use remote
}

View File

@ -466,14 +466,11 @@ var importBenchCmd = &cli.Command{
Duration: time.Since(start),
}
if enc != nil {
stripCallers(tse.Trace)
if err := enc.Encode(tse); err != nil {
return xerrors.Errorf("failed to write out tipsetexec: %w", err)
}
}
if inverseChain[i-1].ParentState() != st {
stripCallers(tse.Trace)
lastTrace := tse.Trace
d, err := json.MarshalIndent(lastTrace, "", " ")
if err != nil {
@ -492,21 +489,6 @@ var importBenchCmd = &cli.Command{
},
}
func walkExecutionTrace(et *types.ExecutionTrace) {
for _, gc := range et.GasCharges {
gc.Callers = nil
}
for _, sub := range et.Subcalls {
walkExecutionTrace(&sub) //nolint:scopelint,gosec
}
}
func stripCallers(trace []*api.InvocResult) {
for _, t := range trace {
walkExecutionTrace(&t.ExecutionTrace)
}
}
type Invocation struct {
TipSet types.TipSetKey
Invoc *api.InvocResult
@ -514,28 +496,24 @@ type Invocation struct {
const GasPerNs = 10
func countGasCosts(et *types.ExecutionTrace) (int64, int64) {
var cgas, vgas int64
func countGasCosts(et *types.ExecutionTrace) int64 {
var cgas int64
for _, gc := range et.GasCharges {
cgas += gc.ComputeGas
vgas += gc.VirtualComputeGas
}
for _, sub := range et.Subcalls {
c, v := countGasCosts(&sub) //nolint
c := countGasCosts(&sub) //nolint
cgas += c
vgas += v
}
return cgas, vgas
return cgas
}
type stats struct {
timeTaken meanVar
gasRatio meanVar
extraCovar *covar
}
type covar struct {
@ -680,32 +658,8 @@ func (v1 *meanVar) Combine(v2 *meanVar) {
v1.m2 = m2
}
func getExtras(ex interface{}) (*string, *float64) {
if t, ok := ex.(string); ok {
return &t, nil
}
if size, ok := ex.(float64); ok {
return nil, &size
}
if exMap, ok := ex.(map[string]interface{}); ok {
t, tok := exMap["type"].(string)
size, sok := exMap["size"].(float64)
if tok && sok {
return &t, &size
}
if tok {
return &t, nil
}
if sok {
return nil, &size
}
return nil, nil
}
return nil, nil
}
func tallyGasCharges(charges map[string]*stats, et types.ExecutionTrace) {
for i, gc := range et.GasCharges {
for _, gc := range et.GasCharges {
name := gc.Name
if name == "OnIpldGetEnd" {
continue
@ -716,45 +670,18 @@ func tallyGasCharges(charges map[string]*stats, et types.ExecutionTrace) {
// discard initial very long OnVerifyPost
continue
}
eType, eSize := getExtras(gc.Extra)
if name == "OnIpldGet" {
next := &types.GasTrace{}
if i+1 < len(et.GasCharges) {
next = et.GasCharges[i+1]
}
if next.Name != "OnIpldGetEnd" {
log.Warn("OnIpldGet without OnIpldGetEnd")
} else {
_, size := getExtras(next.Extra)
eSize = size
}
}
if eType != nil {
name += "-" + *eType
}
compGas := gc.ComputeGas
if compGas == 0 {
compGas = gc.VirtualComputeGas
}
if compGas == 0 {
compGas = 1
}
s := charges[name]
if s == nil {
s = new(stats)
charges[name] = s
}
if eSize != nil {
if s.extraCovar == nil {
s.extraCovar = &covar{}
}
s.extraCovar.AddPoint(*eSize, tt)
}
s.timeTaken.AddPoint(tt)
if compGas == 0 {
compGas = 1
}
ratio := tt / float64(compGas) * GasPerNs
s.gasRatio.AddPoint(ratio)
}
@ -880,13 +807,6 @@ var importAnalyzeCmd = &cli.Command{
}
s.timeTaken.Combine(&v.timeTaken)
s.gasRatio.Combine(&v.gasRatio)
if v.extraCovar != nil {
if s.extraCovar == nil {
s.extraCovar = &covar{}
}
s.extraCovar.Combine(v.extraCovar)
}
}
totalTime += res.totalTime
}
@ -902,13 +822,6 @@ var importAnalyzeCmd = &cli.Command{
s := charges[k]
fmt.Printf("%s: incr by %.4f~%.4f; tt %.4f~%.4f\n", k, s.gasRatio.Mean(), s.gasRatio.Stddev(),
s.timeTaken.Mean(), s.timeTaken.Stddev())
if s.extraCovar != nil {
fmt.Printf("\t correll: %.2f, tt = %.2f * extra + %.2f\n", s.extraCovar.Correl(),
s.extraCovar.A(), s.extraCovar.B())
fmt.Printf("\t covar: %.2f, extra: %.2f~%.2f, tt2: %.2f~%.2f, count %.0f\n",
s.extraCovar.Covariance(), s.extraCovar.meanX, s.extraCovar.StddevX(),
s.extraCovar.meanY, s.extraCovar.StddevY(), s.extraCovar.n)
}
}
sort.Slice(invocs, func(i, j int) bool {

View File

@ -4866,95 +4866,49 @@ Response:
},
"ExecutionTrace": {
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": [
{
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": null
@ -5142,95 +5096,49 @@ Response:
},
"ExecutionTrace": {
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": [
{
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": null
@ -6576,95 +6484,49 @@ Response:
},
"ExecutionTrace": {
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": [
{
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": null

View File

@ -6136,95 +6136,49 @@ Response:
},
"ExecutionTrace": {
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": [
{
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": null
@ -6412,95 +6366,49 @@ Response:
},
"ExecutionTrace": {
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": [
{
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": null
@ -7929,95 +7837,49 @@ Response:
},
"ExecutionTrace": {
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": [
{
"Msg": {
"Version": 42,
"To": "f01234",
"From": "f01234",
"Nonce": 42,
"To": "f01234",
"Value": "0",
"GasLimit": 9,
"GasFeeCap": "0",
"GasPremium": "0",
"Method": 1,
"Params": "Ynl0ZSBhcnJheQ==",
"CID": {
"/": "bafy2bzacebbpdegvr3i4cosewthysg5xkxpqfn2wfcz6mv2hmoktwbdxkax4s"
}
"ParamsCodec": 42
},
"MsgRct": {
"ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
"ReturnCodec": 42
},
"Error": "string value",
"Duration": 60000000000,
"GasCharges": [
{
"Name": "string value",
"loc": [
{
"File": "string value",
"Line": 123,
"Function": "string value"
}
],
"tg": 9,
"cg": 9,
"sg": 9,
"vtg": 9,
"vcg": 9,
"vsg": 9,
"tt": 60000000000,
"ex": {}
"tt": 60000000000
}
],
"Subcalls": null

2
extern/filecoin-ffi vendored

@ -1 +1 @@
Subproject commit 5ab95e3d9c5a9ceb791b485c301212ff7760af8c
Subproject commit 28e3cd44d91681c074aba362d1e5c954db110ad9

View File

@ -11,7 +11,6 @@ import (
"github.com/filecoin-project/lotus/chain/exchange"
"github.com/filecoin-project/lotus/chain/market"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/cmd/lotus-shed/shedgen"
"github.com/filecoin-project/lotus/node/hello"
"github.com/filecoin-project/lotus/paychmgr"
@ -37,15 +36,11 @@ func main() {
types.StateInfo0{},
types.Event{},
types.EventEntry{},
)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = gen.WriteTupleEncodersToFile("./chain/vm/cbor_gen.go", "vm",
vm.FvmExecutionTrace{},
vm.FvmGasCharge{},
// Tracing
types.GasTrace{},
types.MessageTrace{},
types.ReturnTrace{},
types.ExecutionTrace{},
)
if err != nil {
fmt.Println(err)