From 4c6fa1b2c055e2148308aca41b8e5af0c8448fbb Mon Sep 17 00:00:00 2001 From: Jeromy Date: Fri, 3 Apr 2020 14:38:11 -0700 Subject: [PATCH 1/3] handle some runtime error edge cases --- chain/vm/invoker.go | 16 +++++++-------- chain/vm/runtime.go | 50 ++++++++++++++++++++++++--------------------- chain/vm/vm.go | 9 ++++++++ 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index a66eb5833..b01d4e3e6 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -137,15 +137,13 @@ func (*invoker) transform(instance Invokee) (nativeCode, error) { param := reflect.New(paramT) inBytes := in[1].Interface().([]byte) - if len(inBytes) > 0 { - if err := DecodeParams(inBytes, param.Interface()); err != nil { - aerr := aerrors.Absorb(err, 1, "failed to decode parameters") - return []reflect.Value{ - reflect.ValueOf([]byte{}), - // Below is a hack, fixed in Go 1.13 - // https://git.io/fjXU6 - reflect.ValueOf(&aerr).Elem(), - } + if err := DecodeParams(inBytes, param.Interface()); err != nil { + aerr := aerrors.Absorb(err, 1, "failed to decode parameters") + return []reflect.Value{ + reflect.ValueOf([]byte{}), + // Below is a hack, fixed in Go 1.13 + // https://git.io/fjXU6 + reflect.ValueOf(&aerr).Elem(), } } rt := in[0].Interface().(*Runtime) diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 8ce7b6492..5995b7312 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -9,6 +9,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi/big" + sainit "github.com/filecoin-project/specs-actors/actors/builtin/init" "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" vmr "github.com/filecoin-project/specs-actors/actors/runtime" @@ -19,6 +20,7 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" "go.opencensus.io/trace" + "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/actors/aerrors" "github.com/filecoin-project/lotus/chain/state" @@ -31,6 +33,7 @@ type Runtime struct { vm *VM state *state.StateTree msg *types.Message + vmsg vmr.Message height abi.ChainEpoch cst cbor.IpldStore pricelist Pricelist @@ -48,18 +51,29 @@ type Runtime struct { numActorsCreated uint64 } -func (rt *Runtime) ResolveAddress(address address.Address) (ret address.Address, ok bool) { - r, err := rt.state.LookupID(address) +func (rt *Runtime) ResolveAddress(addr address.Address) (ret address.Address, ok bool) { + r, err := rt.state.LookupID(addr) if err != nil { // TODO: check notfound - rt.Abortf(exitcode.ErrPlaceholder, "resolve address: %v", err) + if xerrors.Is(err, sainit.ErrAddressNotFound) { + return address.Undef, false + } + panic(aerrors.Fatalf("failed to resolve address %s: %s", addr, err)) } return r, true } +type notFoundErr interface { + IsNotFound() bool +} + func (rs *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool { if err := rs.cst.Get(context.TODO(), c, o); err != nil { - // TODO: err not found? - rs.Abortf(exitcode.ErrPlaceholder, "storage get: %v", err) + var nfe notFoundErr + if xerrors.As(err, &nfe) && nfe.IsNotFound() { + return false + } + + panic(aerrors.Fatalf("failed to get cbor object %s: %s", c, err)) } return true } @@ -67,7 +81,7 @@ func (rs *Runtime) Get(c cid.Cid, o vmr.CBORUnmarshaler) bool { func (rs *Runtime) Put(x vmr.CBORMarshaler) cid.Cid { c, err := rs.cst.Put(context.TODO(), x) if err != nil { - rs.Abortf(exitcode.ErrPlaceholder, "storage put: %v", err) // todo: spec code? + panic(aerrors.Fatalf("failed to put cbor object: %s", err)) } return c } @@ -107,20 +121,7 @@ func (rs *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act } func (rs *Runtime) Message() vmr.Message { - var ok bool - - rawm := *rs.msg - rawm.From, ok = rs.ResolveAddress(rawm.From) - if !ok { - rs.Abortf(exitcode.ErrPlaceholder, "resolve from address failed") - } - - rawm.To, ok = rs.ResolveAddress(rawm.To) - if !ok { - rs.Abortf(exitcode.ErrPlaceholder, "resolve to address failed") - } - - return &rawm + return rs.vmsg } func (rs *Runtime) ValidateImmediateCallerAcceptAny() { @@ -138,8 +139,11 @@ func (rs *Runtime) CurrentBalance() abi.TokenAmount { func (rs *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) { act, err := rs.state.GetActor(addr) if err != nil { - // todo: notfound - rs.Abortf(exitcode.ErrPlaceholder, "%v", err) + if xerrors.Is(err, types.ErrActorNotFound) { + return cid.Undef, false + } + + panic(aerrors.Fatalf("failed to get actor: %s", err)) } return act.Code, true @@ -148,7 +152,7 @@ func (rs *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool) func (rt *Runtime) GetRandomness(personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) abi.Randomness { res, err := rt.vm.rand.GetRandomness(rt.ctx, personalization, int64(randEpoch), entropy) if err != nil { - rt.Abortf(exitcode.SysErrInternal, "could not get randomness: %s", err) + panic(aerrors.Fatalf("could not get randomness: %s", err)) } return res } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 5e4034d1e..90a89ba28 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -131,6 +131,7 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres numActorsCreated: nac, pricelist: PricelistByEpoch(vm.blockHeight), } + rt.cst = &cbor.BasicIpldStore{ Blocks: &gasChargingBlocks{rt.ChargeGas, rt.pricelist, vm.cst.Blocks}, Atlas: vm.cst.Atlas, @@ -141,6 +142,14 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres pl: rt.pricelist, } + vmm := *msg + resF, ok := rt.ResolveAddress(msg.From) + if !ok { + rt.Abortf(exitcode.SysErrInvalidReceiver, "resolve msg.From address failed") + } + vmm.From = resF + rt.vmsg = &vmm + return rt } From 2d5becaaba9e39ec087a9fce87de146313bc67ee Mon Sep 17 00:00:00 2001 From: Jeromy Date: Fri, 3 Apr 2020 15:05:59 -0700 Subject: [PATCH 2/3] further removals --- chain/vm/runtime.go | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 5995b7312..3e96ced78 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -9,6 +9,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" sainit "github.com/filecoin-project/specs-actors/actors/builtin/init" "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" @@ -165,18 +166,18 @@ func (rt *Runtime) NewActorAddress() address.Address { var b bytes.Buffer oa, _ := ResolveToKeyAddr(rt.vm.cstate, rt.vm.cst, rt.origin) if err := oa.MarshalCBOR(&b); err != nil { // todo: spec says cbor; why not just bytes? - rt.Abortf(exitcode.ErrSerialization, "writing caller address into a buffer: %v", err) + panic(aerrors.Fatalf("writing caller address into a buffer: %v", err)) } if err := binary.Write(&b, binary.BigEndian, rt.originNonce); err != nil { - rt.Abortf(exitcode.ErrSerialization, "writing nonce address into a buffer: %v", err) + panic(aerrors.Fatalf("writing nonce address into a buffer: %v", err)) } if err := binary.Write(&b, binary.BigEndian, rt.numActorsCreated); err != nil { // TODO: expose on vm - rt.Abortf(exitcode.ErrSerialization, "writing callSeqNum address into a buffer: %v", err) + panic(aerrors.Fatalf("writing callSeqNum address into a buffer: %v", err)) } addr, err := address.NewActorAddress(b.Bytes()) if err != nil { - rt.Abortf(exitcode.ErrSerialization, "create actor address: %v", err) + panic(aerrors.Fatalf("create actor address: %v", err)) } rt.incrementNumActorsCreated() @@ -194,7 +195,7 @@ func (rt *Runtime) CreateActor(codeId cid.Cid, address address.Address) { Balance: big.Zero(), }) if err != nil { - rt.Abortf(exitcode.SysErrInternal, "creating actor entry: %v", err) + panic(aerrors.Fatalf("creating actor entry: %v", err)) } } @@ -202,13 +203,17 @@ func (rt *Runtime) DeleteActor() { rt.ChargeGas(rt.Pricelist().OnDeleteActor()) act, err := rt.state.GetActor(rt.Message().Receiver()) if err != nil { - rt.Abortf(exitcode.SysErrInternal, "failed to load actor in delete actor: %s", err) + if xerrors.Is(err, types.ErrActorNotFound) { + rt.Abortf(exitcode.SysErrorIllegalActor, "failed to load actor in delete actor: %s", err) + } + panic(aerrors.Fatalf("failed to get actor: %s", err)) } if !act.Balance.IsZero() { - rt.Abortf(exitcode.SysErrInternal, "cannot delete actor with non-zero balance") + rt.vm.transfer(rt.Message().Receiver(), builtin.BurntFundsActorAddr, act.Balance) } + if err := rt.state.DeleteActor(rt.Message().Receiver()); err != nil { - rt.Abortf(exitcode.SysErrInternal, "failed to delete actor: %s", err) + panic(aerrors.Fatalf("failed to delete actor: %s", err)) } } @@ -224,10 +229,7 @@ func (rs *Runtime) StartSpan(name string) vmr.TraceSpan { } func (rt *Runtime) ValidateImmediateCallerIs(as ...address.Address) { - imm, ok := rt.ResolveAddress(rt.Message().Caller()) - if !ok { - rt.Abortf(exitcode.ErrIllegalState, "couldn't resolve immediate caller") - } + imm := rt.Message().Caller() for _, a := range as { if imm == a { @@ -253,7 +255,7 @@ func (rs *Runtime) AbortStateMsg(msg string) { func (rt *Runtime) ValidateImmediateCallerType(ts ...cid.Cid) { callerCid, ok := rt.GetActorCodeCID(rt.Message().Caller()) if !ok { - rt.Abortf(exitcode.ErrIllegalArgument, "failed to lookup code cid for caller") + panic(aerrors.Fatalf("failed to lookup code cid for caller")) } for _, t := range ts { if t == callerCid { From ab5150184925b89135ec84717bbaa9f9ed009036 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Fri, 3 Apr 2020 15:50:52 -0700 Subject: [PATCH 3/3] remove todo --- chain/vm/runtime.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 3e96ced78..fcb8877e4 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -54,7 +54,7 @@ type Runtime struct { func (rt *Runtime) ResolveAddress(addr address.Address) (ret address.Address, ok bool) { r, err := rt.state.LookupID(addr) - if err != nil { // TODO: check notfound + if err != nil { if xerrors.Is(err, sainit.ErrAddressNotFound) { return address.Undef, false }