From 0f7108824626cd3bc98bcf46aa78ecae85c1f800 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Mon, 5 Oct 2020 17:04:17 +0300 Subject: [PATCH] core: add FaultException to AppExecResult --- pkg/core/blockchain.go | 15 +++++--- pkg/core/state/notification_event.go | 42 ++++++++++++--------- pkg/core/state/notification_event_test.go | 45 ++++++++++++++++++----- 3 files changed, 69 insertions(+), 33 deletions(-) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index e66816531..59647ca76 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -584,6 +584,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error v.GasLimit = tx.SystemFee err := v.Run() + var faultException string if !v.HasFailed() { _, err := systemInterop.DAO.Persist() if err != nil { @@ -597,14 +598,16 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error zap.String("tx", tx.Hash().StringLE()), zap.Uint32("block", block.Index), zap.Error(err)) + faultException = err.Error() } aer := &state.AppExecResult{ - TxHash: tx.Hash(), - Trigger: trigger.Application, - VMState: v.State(), - GasConsumed: v.GasConsumed(), - Stack: v.Estack().ToArray(), - Events: systemInterop.Notifications, + TxHash: tx.Hash(), + Trigger: trigger.Application, + VMState: v.State(), + GasConsumed: v.GasConsumed(), + Stack: v.Estack().ToArray(), + Events: systemInterop.Notifications, + FaultException: faultException, } appExecResults = append(appExecResults, aer) err = cache.PutAppExecResult(aer, writeBuf) diff --git a/pkg/core/state/notification_event.go b/pkg/core/state/notification_event.go index 296ee7905..ab66fdaf4 100644 --- a/pkg/core/state/notification_event.go +++ b/pkg/core/state/notification_event.go @@ -23,12 +23,13 @@ type NotificationEvent struct { // AppExecResult represent the result of the script execution, gathering together // all resulting notifications, state, stack and other metadata. type AppExecResult struct { - TxHash util.Uint256 - Trigger trigger.Type - VMState vm.State - GasConsumed int64 - Stack []stackitem.Item - Events []NotificationEvent + TxHash util.Uint256 + Trigger trigger.Type + VMState vm.State + GasConsumed int64 + Stack []stackitem.Item + Events []NotificationEvent + FaultException string } // EncodeBinary implements the Serializable interface. @@ -62,6 +63,7 @@ func (aer *AppExecResult) EncodeBinary(w *io.BinWriter) { w.WriteU64LE(uint64(aer.GasConsumed)) stackitem.EncodeBinaryStackItem(stackitem.NewArray(aer.Stack), w) w.WriteArray(aer.Events) + w.WriteVarBytes([]byte(aer.FaultException)) } // DecodeBinary implements the Serializable interface. @@ -80,6 +82,7 @@ func (aer *AppExecResult) DecodeBinary(r *io.BinReader) { aer.Stack = arr } r.ReadArray(&aer.Events) + aer.FaultException = r.ReadString() } // notificationEventAux is an auxiliary struct for NotificationEvent JSON marshalling. @@ -123,12 +126,13 @@ func (ne *NotificationEvent) UnmarshalJSON(data []byte) error { // appExecResultAux is an auxiliary struct for JSON marshalling type appExecResultAux struct { - TxHash *util.Uint256 `json:"txid"` - Trigger string `json:"trigger"` - VMState string `json:"vmstate"` - GasConsumed int64 `json:"gasconsumed,string"` - Stack json.RawMessage `json:"stack"` - Events []NotificationEvent `json:"notifications"` + TxHash *util.Uint256 `json:"txid"` + Trigger string `json:"trigger"` + VMState string `json:"vmstate"` + GasConsumed int64 `json:"gasconsumed,string"` + Stack json.RawMessage `json:"stack"` + Events []NotificationEvent `json:"notifications"` + FaultException string `json:"exception,omitempty"` } // MarshalJSON implements implements json.Marshaler interface. @@ -158,12 +162,13 @@ func (aer *AppExecResult) MarshalJSON() ([]byte, error) { hash = &aer.TxHash } return json.Marshal(&appExecResultAux{ - TxHash: hash, - Trigger: aer.Trigger.String(), - VMState: aer.VMState.String(), - GasConsumed: aer.GasConsumed, - Stack: st, - Events: aer.Events, + TxHash: hash, + Trigger: aer.Trigger.String(), + VMState: aer.VMState.String(), + GasConsumed: aer.GasConsumed, + Stack: st, + Events: aer.Events, + FaultException: aer.FaultException, }) } @@ -202,6 +207,7 @@ func (aer *AppExecResult) UnmarshalJSON(data []byte) error { aer.VMState = state aer.Events = aux.Events aer.GasConsumed = aux.GasConsumed + aer.FaultException = aux.FaultException return nil } diff --git a/pkg/core/state/notification_event_test.go b/pkg/core/state/notification_event_test.go index c038ece08..562973b99 100644 --- a/pkg/core/state/notification_event_test.go +++ b/pkg/core/state/notification_event_test.go @@ -24,16 +24,31 @@ func TestEncodeDecodeNotificationEvent(t *testing.T) { } func TestEncodeDecodeAppExecResult(t *testing.T) { - appExecResult := &AppExecResult{ - TxHash: random.Uint256(), - Trigger: 1, - VMState: vm.HaltState, - GasConsumed: 10, - Stack: []stackitem.Item{}, - Events: []NotificationEvent{}, - } + t.Run("halt", func(t *testing.T) { + appExecResult := &AppExecResult{ + TxHash: random.Uint256(), + Trigger: 1, + VMState: vm.HaltState, + GasConsumed: 10, + Stack: []stackitem.Item{}, + Events: []NotificationEvent{}, + } - testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult)) + testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult)) + }) + t.Run("fault", func(t *testing.T) { + appExecResult := &AppExecResult{ + TxHash: random.Uint256(), + Trigger: 1, + VMState: vm.FaultState, + GasConsumed: 10, + Stack: []stackitem.Item{}, + Events: []NotificationEvent{}, + FaultException: "unhandled error", + } + + testserdes.EncodeDecodeBinary(t, appExecResult, new(AppExecResult)) + }) } func TestMarshalUnmarshalJSONNotificationEvent(t *testing.T) { @@ -86,6 +101,18 @@ func TestMarshalUnmarshalJSONAppExecResult(t *testing.T) { testserdes.MarshalUnmarshalJSON(t, appExecResult, new(AppExecResult)) }) + t.Run("positive, fault state", func(t *testing.T) { + appExecResult := &AppExecResult{ + TxHash: random.Uint256(), + Trigger: trigger.Application, + VMState: vm.FaultState, + GasConsumed: 10, + Stack: []stackitem.Item{}, + Events: []NotificationEvent{}, + FaultException: "unhandled exception", + } + testserdes.MarshalUnmarshalJSON(t, appExecResult, new(AppExecResult)) + }) t.Run("positive, block", func(t *testing.T) { appExecResult := &AppExecResult{ TxHash: random.Uint256(),