Merge pull request #1975 from filecoin-project/feat/ex-trace

Refactor ExecutionResult to ExecutionTrace
This commit is contained in:
Łukasz Magiera 2020-06-11 16:24:17 +02:00 committed by GitHub
commit 1e41ca125d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 94 additions and 90 deletions

View File

@ -352,7 +352,7 @@ type RetrievalOrder struct {
type InvocResult struct { type InvocResult struct {
Msg *types.Message Msg *types.Message
MsgRct *types.MessageReceipt MsgRct *types.MessageReceipt
InternalExecutions []*types.ExecutionResult ExecutionTrace types.ExecutionTrace
Error string Error string
Duration time.Duration Duration time.Duration
} }

View File

@ -93,7 +93,7 @@ func init() {
addExample(build.APIVersion) addExample(build.APIVersion)
addExample(api.PCHInbound) addExample(api.PCHInbound)
addExample(time.Minute) addExample(time.Minute)
addExample(&types.ExecutionResult{ addExample(&types.ExecutionTrace{
Msg: exampleValue(reflect.TypeOf(&types.Message{})).(*types.Message), Msg: exampleValue(reflect.TypeOf(&types.Message{})).(*types.Message),
MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{})).(*types.MessageReceipt), MsgRct: exampleValue(reflect.TypeOf(&types.MessageReceipt{})).(*types.MessageReceipt),
}) })

View File

@ -64,7 +64,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
return &api.InvocResult{ return &api.InvocResult{
Msg: msg, Msg: msg,
MsgRct: &ret.MessageReceipt, MsgRct: &ret.MessageReceipt,
InternalExecutions: ret.InternalExecutions, ExecutionTrace: ret.ExecutionTrace,
Error: errs, Error: errs,
Duration: ret.Duration, Duration: ret.Duration,
}, nil }, nil

View File

@ -123,7 +123,7 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c
ir := &api.InvocResult{ ir := &api.InvocResult{
Msg: msg, Msg: msg,
MsgRct: &ret.MessageReceipt, MsgRct: &ret.MessageReceipt,
InternalExecutions: ret.InternalExecutions, ExecutionTrace: ret.ExecutionTrace,
Duration: ret.Duration, Duration: ret.Duration,
} }
if ret.ActorErr != nil { if ret.ActorErr != nil {

View File

@ -2,11 +2,11 @@ package types
import "time" import "time"
type ExecutionResult struct { type ExecutionTrace struct {
Msg *Message Msg *Message
MsgRct *MessageReceipt MsgRct *MessageReceipt
Error string Error string
Duration time.Duration Duration time.Duration
Subcalls []*ExecutionResult Subcalls []ExecutionTrace
} }

View File

@ -5,7 +5,6 @@ import (
"context" "context"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"time"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
@ -51,7 +50,7 @@ type Runtime struct {
origin address.Address origin address.Address
originNonce uint64 originNonce uint64
internalExecutions []*types.ExecutionResult executionTrace types.ExecutionTrace
numActorsCreated uint64 numActorsCreated uint64
allowInternal bool allowInternal bool
callerValidated bool callerValidated bool
@ -368,7 +367,6 @@ func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMars
} }
func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) { func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum, value types.BigInt, params []byte) ([]byte, aerrors.ActorError) {
start := time.Now()
ctx, span := trace.StartSpan(rt.ctx, "vmc.Send") ctx, span := trace.StartSpan(rt.ctx, "vmc.Send")
defer span.End() defer span.End()
if span.IsRecordingEvents() { if span.IsRecordingEvents() {
@ -401,27 +399,10 @@ func (rt *Runtime) internalSend(from, to address.Address, method abi.MethodNum,
} }
} }
mr := types.MessageReceipt{
ExitCode: aerrors.RetCode(errSend),
Return: ret,
GasUsed: 0,
}
er := types.ExecutionResult{
Msg: msg,
MsgRct: &mr,
Duration: time.Since(start),
}
if errSend != nil {
er.Error = errSend.Error()
}
if subrt != nil { if subrt != nil {
er.Subcalls = subrt.internalExecutions
rt.numActorsCreated = subrt.numActorsCreated rt.numActorsCreated = subrt.numActorsCreated
} }
rt.internalExecutions = append(rt.internalExecutions, &er) rt.executionTrace.Subcalls = append(rt.executionTrace.Subcalls, subrt.executionTrace) //&er)
return ret, errSend return ret, errSend
} }
@ -504,13 +485,13 @@ func (rt *Runtime) stateCommit(oldh, newh cid.Cid) aerrors.ActorError {
} }
func (rt *Runtime) ChargeGas(toUse int64) { func (rt *Runtime) ChargeGas(toUse int64) {
err := rt.chargeGasSafe(toUse) err := rt.chargeGasInternal(toUse)
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
func (rt *Runtime) chargeGasSafe(toUse int64) aerrors.ActorError { func (rt *Runtime) chargeGasInternal(toUse int64) aerrors.ActorError {
if rt.gasUsed+toUse > rt.gasAvailable { if rt.gasUsed+toUse > rt.gasAvailable {
rt.gasUsed = rt.gasAvailable rt.gasUsed = rt.gasAvailable
return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable) return aerrors.Newf(exitcode.SysErrOutOfGas, "not enough gas: used=%d, available=%d", rt.gasUsed, rt.gasAvailable)
@ -519,6 +500,10 @@ func (rt *Runtime) chargeGasSafe(toUse int64) aerrors.ActorError {
return nil return nil
} }
func (rt *Runtime) chargeGasSafe(toUse int64) aerrors.ActorError {
return rt.chargeGasInternal(toUse)
}
func (rt *Runtime) Pricelist() Pricelist { func (rt *Runtime) Pricelist() Pricelist {
return rt.pricelist return rt.pricelist
} }

View File

@ -102,6 +102,7 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres
pricelist: PricelistByEpoch(vm.blockHeight), pricelist: PricelistByEpoch(vm.blockHeight),
allowInternal: true, allowInternal: true,
callerValidated: false, callerValidated: false,
executionTrace: types.ExecutionTrace{Msg: msg},
} }
rt.cst = &cbor.BasicIpldStore{ rt.cst = &cbor.BasicIpldStore{
@ -165,12 +166,14 @@ type ApplyRet struct {
types.MessageReceipt types.MessageReceipt
ActorErr aerrors.ActorError ActorErr aerrors.ActorError
Penalty types.BigInt Penalty types.BigInt
InternalExecutions []*types.ExecutionResult ExecutionTrace types.ExecutionTrace
Duration time.Duration Duration time.Duration
} }
func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime, func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
gasCharge int64) ([]byte, aerrors.ActorError, *Runtime) { gasCharge int64) ([]byte, aerrors.ActorError, *Runtime) {
start := time.Now()
st := vm.cstate st := vm.cstate
gasUsed := gasCharge gasUsed := gasCharge
@ -191,8 +194,9 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
}() }()
} }
ret, err := func() ([]byte, aerrors.ActorError) {
if aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method)); aerr != nil { if aerr := rt.chargeGasSafe(rt.Pricelist().OnMethodInvocation(msg.Value, msg.Method)); aerr != nil {
return nil, aerrors.Wrap(aerr, "not enough gas for method invocation"), rt return nil, aerrors.Wrap(aerr, "not enough gas for method invocation")
} }
toActor, err := st.GetActor(msg.To) toActor, err := st.GetActor(msg.To)
@ -200,26 +204,40 @@ func (vm *VM) send(ctx context.Context, msg *types.Message, parent *Runtime,
if xerrors.Is(err, init_.ErrAddressNotFound) { if xerrors.Is(err, init_.ErrAddressNotFound) {
a, err := TryCreateAccountActor(rt, msg.To) a, err := TryCreateAccountActor(rt, msg.To)
if err != nil { if err != nil {
return nil, aerrors.Wrapf(err, "could not create account"), rt return nil, aerrors.Wrapf(err, "could not create account")
} }
toActor = a toActor = a
} else { } else {
return nil, aerrors.Escalate(err, "getting actor"), rt return nil, aerrors.Escalate(err, "getting actor")
} }
} }
if types.BigCmp(msg.Value, types.NewInt(0)) != 0 { if types.BigCmp(msg.Value, types.NewInt(0)) != 0 {
if err := vm.transfer(msg.From, msg.To, msg.Value); err != nil { if err := vm.transfer(msg.From, msg.To, msg.Value); err != nil {
return nil, aerrors.Wrap(err, "failed to transfer funds"), nil return nil, aerrors.Wrap(err, "failed to transfer funds")
} }
} }
if msg.Method != 0 { if msg.Method != 0 {
var ret []byte
ret, err := vm.Invoke(toActor, rt, msg.Method, msg.Params) ret, err := vm.Invoke(toActor, rt, msg.Method, msg.Params)
return ret, err, rt return ret, err
}
return nil, nil
}()
mr := types.MessageReceipt{
ExitCode: aerrors.RetCode(err),
Return: ret,
GasUsed: rt.gasUsed,
}
rt.executionTrace.MsgRct = &mr
rt.executionTrace.Duration = time.Since(start)
if err != nil {
rt.executionTrace.Error = err.Error()
} }
return nil, nil, rt return ret, err, rt
} }
func checkMessage(msg *types.Message) error { func checkMessage(msg *types.Message) error {
@ -251,7 +269,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap
GasUsed: 0, GasUsed: 0,
}, },
ActorErr: actorErr, ActorErr: actorErr,
InternalExecutions: rt.internalExecutions, ExecutionTrace: rt.executionTrace,
Penalty: types.NewInt(0), Penalty: types.NewInt(0),
Duration: time.Since(start), Duration: time.Since(start),
}, actorErr }, actorErr
@ -420,7 +438,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
GasUsed: gasUsed, GasUsed: gasUsed,
}, },
ActorErr: actorErr, ActorErr: actorErr,
InternalExecutions: rt.internalExecutions, ExecutionTrace: rt.executionTrace,
Penalty: types.NewInt(0), Penalty: types.NewInt(0),
Duration: time.Since(start), Duration: time.Since(start),
}, nil }, nil

View File

@ -931,14 +931,14 @@ var stateComputeStateCmd = &cli.Command{
if cctx.Bool("show-trace") { if cctx.Bool("show-trace") {
for _, ir := range stout.Trace { for _, ir := range stout.Trace {
fmt.Printf("%s\t%s\t%s\t%d\t%x\t%d\t%x\n", ir.Msg.From, ir.Msg.To, ir.Msg.Value, ir.Msg.Method, ir.Msg.Params, ir.MsgRct.ExitCode, ir.MsgRct.Return) fmt.Printf("%s\t%s\t%s\t%d\t%x\t%d\t%x\n", ir.Msg.From, ir.Msg.To, ir.Msg.Value, ir.Msg.Method, ir.Msg.Params, ir.MsgRct.ExitCode, ir.MsgRct.Return)
printInternalExecutions("\t", ir.InternalExecutions) printInternalExecutions("\t", ir.ExecutionTrace.Subcalls)
} }
} }
return nil return nil
}, },
} }
func printInternalExecutions(prefix string, trace []*types.ExecutionResult) { func printInternalExecutions(prefix string, trace []types.ExecutionTrace) {
for _, im := range trace { for _, im := range trace {
fmt.Printf("%s%s\t%s\t%s\t%d\t%x\t%d\t%x\n", prefix, im.Msg.From, im.Msg.To, im.Msg.Value, im.Msg.Method, im.Msg.Params, im.MsgRct.ExitCode, im.MsgRct.Return) fmt.Printf("%s%s\t%s\t%s\t%d\t%x\t%d\t%x\n", prefix, im.Msg.From, im.Msg.To, im.Msg.Value, im.Msg.Method, im.Msg.Params, im.MsgRct.ExitCode, im.MsgRct.Return)
printInternalExecutions(prefix+"\t", im.Subcalls) printInternalExecutions(prefix+"\t", im.Subcalls)
@ -1028,12 +1028,10 @@ func computeStateHtml(ts *types.TipSet, o *api.ComputeStateOutput, getCode func(
fmt.Printf(`<div class="error">Error: <pre>%s</pre></div>`, ir.Error) fmt.Printf(`<div class="error">Error: <pre>%s</pre></div>`, ir.Error)
} }
if len(ir.InternalExecutions) > 0 { fmt.Println("<div>Execution trace:</div>")
fmt.Println("<div>Internal executions:</div>") if err := printInternalExecutionsHtml(cid.String(), ir.ExecutionTrace.Subcalls, getCode); err != nil {
if err := printInternalExecutionsHtml(cid.String(), ir.InternalExecutions, getCode); err != nil {
return err return err
} }
}
fmt.Println("</div>") fmt.Println("</div>")
} }
@ -1042,7 +1040,7 @@ func computeStateHtml(ts *types.TipSet, o *api.ComputeStateOutput, getCode func(
return nil return nil
} }
func printInternalExecutionsHtml(hashName string, trace []*types.ExecutionResult, getCode func(addr address.Address) (cid.Cid, error)) error { func printInternalExecutionsHtml(hashName string, trace []types.ExecutionTrace, getCode func(addr address.Address) (cid.Cid, error)) error {
for i, im := range trace { for i, im := range trace {
hashName := fmt.Sprintf("%s-r%d", hashName, i) hashName := fmt.Sprintf("%s-r%d", hashName, i)

3
go.sum
View File

@ -42,9 +42,11 @@ github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE= github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
@ -1575,6 +1577,7 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -244,7 +244,7 @@ func (a *StateAPI) StateReplay(ctx context.Context, tsk types.TipSetKey, mc cid.
return &api.InvocResult{ return &api.InvocResult{
Msg: m, Msg: m,
MsgRct: &r.MessageReceipt, MsgRct: &r.MessageReceipt,
InternalExecutions: r.InternalExecutions, ExecutionTrace: r.ExecutionTrace,
Error: errstr, Error: errstr,
Duration: r.Duration, Duration: r.Duration,
}, nil }, nil