From c90e87455269976534579ae492a5ab7b3d8b26a1 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Fri, 4 Sep 2020 16:56:50 +0100 Subject: [PATCH 1/7] test: wip actor abort --- gen/suites/vm_violations/actor_abort.go | 32 +++++++++++++++++++++++++ gen/suites/vm_violations/main.go | 25 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 gen/suites/vm_violations/actor_abort.go diff --git a/gen/suites/vm_violations/actor_abort.go b/gen/suites/vm_violations/actor_abort.go new file mode 100644 index 00000000..6621aa73 --- /dev/null +++ b/gen/suites/vm_violations/actor_abort.go @@ -0,0 +1,32 @@ +package main + +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/runtime/exitcode" + "github.com/filecoin-project/test-vectors/chaos" + + . "github.com/filecoin-project/test-vectors/gen/builders" +) + +func abort(args chaos.AbortArgs, expectedCode exitcode.ExitCode) func(*MessageVectorBuilder) { + return func(v *MessageVectorBuilder) { + v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200)) + + sender := v.Actors.Account(address.SECP256K1, abi.NewTokenAmount(1_000_000_000_000)) + v.CommitPreconditions() + + v.Messages.Raw( + sender.ID, + chaos.Address, + chaos.MethodAbort, + MustSerialize(&args), + Value(big.Zero()), + Nonce(0), + ) + v.CommitApplies() + + v.Assert.LastMessageResultSatisfies(ExitCode(expectedCode)) + } +} diff --git a/gen/suites/vm_violations/main.go b/gen/suites/vm_violations/main.go index 192a2e51..f25eb268 100644 --- a/gen/suites/vm_violations/main.go +++ b/gen/suites/vm_violations/main.go @@ -228,4 +228,29 @@ func main() { MessageFunc: mutateState(valPfx+"after-transaction", chaos.MutateAfterTransaction, exitcode.SysErrorIllegalActor), }, ) + + g.Group("actor_abort", + &VectorDef{ + Metadata: &Metadata{ + ID: "no-exit-code", + Version: "v1", + Desc: "no exit code provided, just panic and let the runtime return the error", + }, + Selector: map[string]string{"chaos_actor": "true"}, + Mode: ModeLenientAssertions, + Hints: []string{schema.HintIncorrect, schema.HintNegate}, + MessageFunc: abort(chaos.AbortArgs{NoCode: true, Message: "no exit code abort"}, exitcode.FirstActorSpecificExitCode), + }, + &VectorDef{ + Metadata: &Metadata{ + ID: "system-exit-code", + Version: "v1", + Desc: "actors should not return system exit codes", + }, + Selector: map[string]string{"chaos_actor": "true"}, + Mode: ModeLenientAssertions, + Hints: []string{schema.HintIncorrect, schema.HintNegate}, + MessageFunc: abort(chaos.AbortArgs{Code: exitcode.SysErrInsufficientFunds, Message: "system exit code abort"}, exitcode.SysErrorIllegalActor), + }, + ) } From 0bdf53e9b73e47eebcb4bb80d14e68df42c52202 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Tue, 8 Sep 2020 13:24:36 +0100 Subject: [PATCH 2/7] feat: wip actor abort with different error codes --- gen/builders/predicates.go | 8 ++++++++ gen/suites/vm_violations/actor_abort.go | 25 +++++++++++++++++++++++-- gen/suites/vm_violations/main.go | 21 +++++++++++++++------ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/gen/builders/predicates.go b/gen/builders/predicates.go index 506465a5..84987e37 100644 --- a/gen/builders/predicates.go +++ b/gen/builders/predicates.go @@ -48,6 +48,14 @@ func MessageReturns(expect cbg.CBORMarshaler) ApplyRetPredicate { } } +// PanickedRet represents a non-return value, a placeholder for when an actor panicked while applying a message. +var PanickedRet = vm.ApplyRet{} + +// Panicked returns an ApplyRetPredicate that passes if the message response is the PanickedRet. +func Panicked() ApplyRetPredicate { + return MessageReturns(&PanickedRet) +} + // BalanceUpdated returns a ActorPredicate that checks whether the balance // of the actor has been deducted the gas cost and the outgoing value transfers, // and has been increased by the offset (or decreased, if the argument is negative). diff --git a/gen/suites/vm_violations/actor_abort.go b/gen/suites/vm_violations/actor_abort.go index 6621aa73..ff35498d 100644 --- a/gen/suites/vm_violations/actor_abort.go +++ b/gen/suites/vm_violations/actor_abort.go @@ -10,7 +10,7 @@ import ( . "github.com/filecoin-project/test-vectors/gen/builders" ) -func abort(args chaos.AbortArgs, expectedCode exitcode.ExitCode) func(*MessageVectorBuilder) { +func actorAbort(abortCode exitcode.ExitCode, msg string, expectedCode exitcode.ExitCode) func(*MessageVectorBuilder) { return func(v *MessageVectorBuilder) { v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200)) @@ -21,7 +21,7 @@ func abort(args chaos.AbortArgs, expectedCode exitcode.ExitCode) func(*MessageVe sender.ID, chaos.Address, chaos.MethodAbort, - MustSerialize(&args), + MustSerialize(&chaos.AbortArgs{Code: abortCode, Message: msg}), Value(big.Zero()), Nonce(0), ) @@ -30,3 +30,24 @@ func abort(args chaos.AbortArgs, expectedCode exitcode.ExitCode) func(*MessageVe v.Assert.LastMessageResultSatisfies(ExitCode(expectedCode)) } } + +func actorPanic(msg string) func(*MessageVectorBuilder) { + return func(v *MessageVectorBuilder) { + v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200)) + + sender := v.Actors.Account(address.SECP256K1, abi.NewTokenAmount(1_000_000_000_000)) + v.CommitPreconditions() + + v.Messages.Raw( + sender.ID, + chaos.Address, + chaos.MethodAbort, + MustSerialize(&chaos.AbortArgs{NoCode: true, Message: msg}), + Value(big.Zero()), + Nonce(0), + ) + v.CommitApplies() + + v.Assert.LastMessageResultSatisfies(Panicked()) + } +} diff --git a/gen/suites/vm_violations/main.go b/gen/suites/vm_violations/main.go index f25eb268..1b570a0a 100644 --- a/gen/suites/vm_violations/main.go +++ b/gen/suites/vm_violations/main.go @@ -232,25 +232,34 @@ func main() { g.Group("actor_abort", &VectorDef{ Metadata: &Metadata{ - ID: "no-exit-code", + ID: "custom-exit-code", + Version: "v1", + Desc: "actors can abort with custom exit codes", + }, + Selector: map[string]string{"chaos_actor": "true"}, + MessageFunc: actorAbort(exitcode.FirstActorSpecificExitCode, "custom exit code abort", exitcode.FirstActorSpecificExitCode), + }, + &VectorDef{ + Metadata: &Metadata{ + ID: "system-exit-code", Version: "v1", - Desc: "no exit code provided, just panic and let the runtime return the error", + Desc: "actors should not abort with system exit codes", }, Selector: map[string]string{"chaos_actor": "true"}, Mode: ModeLenientAssertions, Hints: []string{schema.HintIncorrect, schema.HintNegate}, - MessageFunc: abort(chaos.AbortArgs{NoCode: true, Message: "no exit code abort"}, exitcode.FirstActorSpecificExitCode), + MessageFunc: actorAbort(exitcode.SysErrInsufficientFunds, "system exit code abort", exitcode.SysErrorIllegalActor), }, &VectorDef{ Metadata: &Metadata{ - ID: "system-exit-code", + ID: "no-exit-code", Version: "v1", - Desc: "actors should not return system exit codes", + Desc: "actor failure, a panic with no associated exit code", }, Selector: map[string]string{"chaos_actor": "true"}, Mode: ModeLenientAssertions, Hints: []string{schema.HintIncorrect, schema.HintNegate}, - MessageFunc: abort(chaos.AbortArgs{Code: exitcode.SysErrInsufficientFunds, Message: "system exit code abort"}, exitcode.SysErrorIllegalActor), + MessageFunc: actorPanic("no exit code abort"), }, ) } From 7ff4dbdf99c31ded0f8f0874d4d0e409b3ccdc5a Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Tue, 8 Sep 2020 14:17:24 +0100 Subject: [PATCH 3/7] feat: test all system codes --- gen/suites/vm_violations/actor_abort.go | 6 +-- gen/suites/vm_violations/main.go | 51 +++++++++++++++++++++---- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/gen/suites/vm_violations/actor_abort.go b/gen/suites/vm_violations/actor_abort.go index ff35498d..ce80b1e9 100644 --- a/gen/suites/vm_violations/actor_abort.go +++ b/gen/suites/vm_violations/actor_abort.go @@ -2,9 +2,9 @@ package main 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/runtime/exitcode" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/test-vectors/chaos" . "github.com/filecoin-project/test-vectors/gen/builders" diff --git a/gen/suites/vm_violations/main.go b/gen/suites/vm_violations/main.go index 1b570a0a..e4d7e39b 100644 --- a/gen/suites/vm_violations/main.go +++ b/gen/suites/vm_violations/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" @@ -229,8 +230,8 @@ func main() { }, ) - g.Group("actor_abort", - &VectorDef{ + actorAbortVectors := []*VectorDef{ + { Metadata: &Metadata{ ID: "custom-exit-code", Version: "v1", @@ -239,18 +240,18 @@ func main() { Selector: map[string]string{"chaos_actor": "true"}, MessageFunc: actorAbort(exitcode.FirstActorSpecificExitCode, "custom exit code abort", exitcode.FirstActorSpecificExitCode), }, - &VectorDef{ + { Metadata: &Metadata{ - ID: "system-exit-code", + ID: "negative-exit-code", Version: "v1", - Desc: "actors should not abort with system exit codes", + Desc: "actors should not abort with negative exit codes", }, Selector: map[string]string{"chaos_actor": "true"}, Mode: ModeLenientAssertions, Hints: []string{schema.HintIncorrect, schema.HintNegate}, - MessageFunc: actorAbort(exitcode.SysErrInsufficientFunds, "system exit code abort", exitcode.SysErrorIllegalActor), + MessageFunc: actorAbort(-1, "negative exit code abort", exitcode.SysErrorIllegalActor), }, - &VectorDef{ + { Metadata: &Metadata{ ID: "no-exit-code", Version: "v1", @@ -261,5 +262,39 @@ func main() { Hints: []string{schema.HintIncorrect, schema.HintNegate}, MessageFunc: actorPanic("no exit code abort"), }, - ) + } + + sysExitCodes := []exitcode.ExitCode{ + exitcode.SysErrSenderInvalid, + exitcode.SysErrSenderStateInvalid, + exitcode.SysErrInvalidMethod, + exitcode.SysErrReserved1, + exitcode.SysErrInvalidReceiver, + exitcode.SysErrInsufficientFunds, + exitcode.SysErrOutOfGas, + exitcode.SysErrForbidden, + exitcode.SysErrorIllegalActor, + exitcode.SysErrorIllegalArgument, + exitcode.SysErrReserved2, + exitcode.SysErrReserved3, + exitcode.SysErrReserved4, + exitcode.SysErrReserved5, + exitcode.SysErrReserved6, + } + + for _, xc := range sysExitCodes { + actorAbortVectors = append(actorAbortVectors, &VectorDef{ + Metadata: &Metadata{ + ID: fmt.Sprintf("system-exit-code-%d", xc), + Version: "v1", + Desc: fmt.Sprintf("actors should not abort with %s", xc), + }, + Selector: map[string]string{"chaos_actor": "true"}, + Mode: ModeLenientAssertions, + Hints: []string{schema.HintIncorrect, schema.HintNegate}, + MessageFunc: actorAbort(xc, fmt.Sprintf("%s abort", xc), exitcode.SysErrorIllegalActor), + }) + } + + g.Group("actor_abort", actorAbortVectors...) } From 9235f528af528d470349bf3e3fd15d4ef9f1cc8d Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Tue, 8 Sep 2020 15:16:34 +0100 Subject: [PATCH 4/7] feat: null receipts --- gen/builders/builder_message.go | 19 ++++++++++++------- gen/builders/messages.go | 4 ++++ gen/builders/predicates.go | 14 ++++++++------ gen/builders/state_tracker.go | 10 ++++++++-- gen/suites/vm_violations/actor_abort.go | 2 +- schema.json | 9 ++++++++- 6 files changed, 41 insertions(+), 17 deletions(-) diff --git a/gen/builders/builder_message.go b/gen/builders/builder_message.go index 7689b50d..2f064213 100644 --- a/gen/builders/builder_message.go +++ b/gen/builders/builder_message.go @@ -103,7 +103,7 @@ func (b *MessageVectorBuilder) CommitApplies() { for _, am := range b.Messages.All() { // apply all messages that are pending application. - if am.Result == nil { + if !am.Applied { b.StateTracker.ApplyMessage(am) } @@ -112,11 +112,17 @@ func (b *MessageVectorBuilder) CommitApplies() { Bytes: MustSerialize(am.Message), Epoch: &epoch, }) - b.vector.Post.Receipts = append(b.vector.Post.Receipts, &schema.Receipt{ - ExitCode: int64(am.Result.ExitCode), - ReturnValue: am.Result.Return, - GasUsed: am.Result.GasUsed, - }) + + // am.Result may still be nil if the message failed to be applied + if am.Result != nil { + b.vector.Post.Receipts = append(b.vector.Post.Receipts, &schema.Receipt{ + ExitCode: int64(am.Result.ExitCode), + ReturnValue: am.Result.Return, + GasUsed: am.Result.GasUsed, + }) + } else { + b.vector.Post.Receipts = append(b.vector.Post.Receipts, nil) + } } // update the internal state. @@ -124,7 +130,6 @@ func (b *MessageVectorBuilder) CommitApplies() { b.vector.Post.StateTree = &schema.StateTree{RootCID: b.PostRoot} b.Stage = StageChecks b.Assert.enterStage(StageChecks) - } // Finish signals to the builder that the checks stage is complete and that the diff --git a/gen/builders/messages.go b/gen/builders/messages.go index 4e6cb502..8c13d94d 100644 --- a/gen/builders/messages.go +++ b/gen/builders/messages.go @@ -38,6 +38,10 @@ type ApplicableMessage struct { Epoch abi.ChainEpoch Message *types.Message Result *vm.ApplyRet + // Applied is true if this message has already been applied. Note it's + // not safe to rely on non-nil Result as indication of application + // since applied messages may fail without a result. + Applied bool } func (m *Messages) Sugar() *sugarMsg { diff --git a/gen/builders/predicates.go b/gen/builders/predicates.go index 84987e37..ff56606c 100644 --- a/gen/builders/predicates.go +++ b/gen/builders/predicates.go @@ -48,12 +48,14 @@ func MessageReturns(expect cbg.CBORMarshaler) ApplyRetPredicate { } } -// PanickedRet represents a non-return value, a placeholder for when an actor panicked while applying a message. -var PanickedRet = vm.ApplyRet{} - -// Panicked returns an ApplyRetPredicate that passes if the message response is the PanickedRet. -func Panicked() ApplyRetPredicate { - return MessageReturns(&PanickedRet) +// Nil returns an ApplyRetPredicate that passes if the message receipt is nil. +func Nil() ApplyRetPredicate { + return func(ret *vm.ApplyRet) error { + if ret != nil { + return fmt.Errorf("message receipt was not nil: %+v", ret) + } + return nil + } } // BalanceUpdated returns a ActorPredicate that checks whether the balance diff --git a/gen/builders/state_tracker.go b/gen/builders/state_tracker.go index 971576e9..e0af6da3 100644 --- a/gen/builders/state_tracker.go +++ b/gen/builders/state_tracker.go @@ -86,10 +86,16 @@ func (st *StateTracker) Flush() cid.Cid { // root, refreshes the state tree, and updates the underlying vector with the // message and its receipt. func (st *StateTracker) ApplyMessage(am *ApplicableMessage) { + var postRoot cid.Cid var err error - am.Result, st.CurrRoot, err = st.Driver.ExecuteMessage(st.Stores.Blockstore, st.CurrRoot, am.Epoch, am.Message) - st.bc.Assert.NoError(err) + am.Applied = true + am.Result, postRoot, err = st.Driver.ExecuteMessage(st.Stores.Blockstore, st.CurrRoot, am.Epoch, am.Message) + if err != nil { + return + } + + st.CurrRoot = postRoot // replace the state tree. st.StateTree, err = state.LoadStateTree(st.Stores.CBORStore, st.CurrRoot) st.bc.Assert.NoError(err) diff --git a/gen/suites/vm_violations/actor_abort.go b/gen/suites/vm_violations/actor_abort.go index ce80b1e9..25cea74a 100644 --- a/gen/suites/vm_violations/actor_abort.go +++ b/gen/suites/vm_violations/actor_abort.go @@ -48,6 +48,6 @@ func actorPanic(msg string) func(*MessageVectorBuilder) { ) v.CommitApplies() - v.Assert.LastMessageResultSatisfies(Panicked()) + v.Assert.LastMessageResultSatisfies(Nil()) } } diff --git a/schema.json b/schema.json index 07ef5753..cdccac2b 100644 --- a/schema.json +++ b/schema.json @@ -148,7 +148,14 @@ "type": "array", "additionalItems": false, "items": { - "$ref": "#/definitions/receipt" + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/definitions/receipt" + } + ] } }, "receipts_roots": { From 522e15ffd0ac85442be33de32f30899310e2021d Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Wed, 9 Sep 2020 11:44:16 +0100 Subject: [PATCH 5/7] fix: dependencies --- go.mod | 4 ++-- go.sum | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 4bc6e52a..2b8a3572 100644 --- a/go.mod +++ b/go.mod @@ -8,9 +8,9 @@ require ( github.com/filecoin-project/go-bitfield v0.2.0 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df - github.com/filecoin-project/lotus v0.6.2-0.20200908205025-63cdbef2197c + github.com/filecoin-project/lotus v0.6.2-0.20200909104030-159be5b543fd github.com/filecoin-project/specs-actors v0.9.7 - github.com/filecoin-project/test-vectors/schema v0.0.0-00010101000000-000000000000 + github.com/filecoin-project/test-vectors/schema v0.0.1 github.com/ipfs/go-block-format v0.0.2 github.com/ipfs/go-blockservice v0.1.4-0.20200624145336-a978cec6e834 github.com/ipfs/go-cid v0.0.7 diff --git a/go.sum b/go.sum index 0c6a728b..623705e9 100644 --- a/go.sum +++ b/go.sum @@ -261,6 +261,8 @@ github.com/filecoin-project/lotus v0.4.3-0.20200819133134-a21234cd54d5/go.mod h1 github.com/filecoin-project/lotus v0.4.3-0.20200820203717-d1718369a182/go.mod h1:biFZPQ/YyQGfkHUmHMiaNf2hnD6zm1+OAXPQYQ61Zkg= github.com/filecoin-project/lotus v0.6.2-0.20200908205025-63cdbef2197c h1:S5wcQLt8tFbh5q/ajPCawRgFPQm3CJ9LAy9/dwlNxtk= github.com/filecoin-project/lotus v0.6.2-0.20200908205025-63cdbef2197c/go.mod h1:zK3h9oTAN5QSfcKq8JYmGPq7oIYGfwMQ9UKD5/yp5GU= +github.com/filecoin-project/lotus v0.6.2-0.20200909104030-159be5b543fd h1:6Reoqcam6sUmoeyUauwTHgnhYlzf7QAhXciIE1p//3s= +github.com/filecoin-project/lotus v0.6.2-0.20200909104030-159be5b543fd/go.mod h1:8SUeiDq172ZpVm4bLYfaulKLsYlYkl9ZI/IDxacP8M8= github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= From 80611441d07e2f3569c0a8bc1b713cdbbcf5c324 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Wed, 9 Sep 2020 13:07:25 +0100 Subject: [PATCH 6/7] fix: fallout from chaos move --- gen/suites/vm_violations/actor_abort.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/suites/vm_violations/actor_abort.go b/gen/suites/vm_violations/actor_abort.go index 25cea74a..573049c1 100644 --- a/gen/suites/vm_violations/actor_abort.go +++ b/gen/suites/vm_violations/actor_abort.go @@ -5,7 +5,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/test-vectors/chaos" + "github.com/filecoin-project/lotus/conformance/chaos" . "github.com/filecoin-project/test-vectors/gen/builders" ) From 4d5f398446595d54a692f40f43b919551ff6e9cc Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Wed, 9 Sep 2020 17:53:59 +0100 Subject: [PATCH 7/7] fix: not always have result --- gen/builders/builder_message.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gen/builders/builder_message.go b/gen/builders/builder_message.go index 2f064213..766155d9 100644 --- a/gen/builders/builder_message.go +++ b/gen/builders/builder_message.go @@ -151,8 +151,10 @@ func (b *MessageVectorBuilder) Finish(w io.Writer) { msgs := b.Messages.All() traces := make([]types.ExecutionTrace, 0, len(msgs)) - for _, msgs := range msgs { - traces = append(traces, msgs.Result.ExecutionTrace) + for _, msg := range msgs { + if msg.Result != nil { + traces = append(traces, msg.Result.ExecutionTrace) + } } b.vector.Diagnostics = EncodeTraces(traces)