core: add FaultException to AppExecResult

This commit is contained in:
Anna Shaleva 2020-10-05 17:04:17 +03:00
parent 9a493dd2a0
commit 0f71088246
3 changed files with 69 additions and 33 deletions

View file

@ -584,6 +584,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
v.GasLimit = tx.SystemFee v.GasLimit = tx.SystemFee
err := v.Run() err := v.Run()
var faultException string
if !v.HasFailed() { if !v.HasFailed() {
_, err := systemInterop.DAO.Persist() _, err := systemInterop.DAO.Persist()
if err != nil { 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.String("tx", tx.Hash().StringLE()),
zap.Uint32("block", block.Index), zap.Uint32("block", block.Index),
zap.Error(err)) zap.Error(err))
faultException = err.Error()
} }
aer := &state.AppExecResult{ aer := &state.AppExecResult{
TxHash: tx.Hash(), TxHash: tx.Hash(),
Trigger: trigger.Application, Trigger: trigger.Application,
VMState: v.State(), VMState: v.State(),
GasConsumed: v.GasConsumed(), GasConsumed: v.GasConsumed(),
Stack: v.Estack().ToArray(), Stack: v.Estack().ToArray(),
Events: systemInterop.Notifications, Events: systemInterop.Notifications,
FaultException: faultException,
} }
appExecResults = append(appExecResults, aer) appExecResults = append(appExecResults, aer)
err = cache.PutAppExecResult(aer, writeBuf) err = cache.PutAppExecResult(aer, writeBuf)

View file

@ -23,12 +23,13 @@ type NotificationEvent struct {
// AppExecResult represent the result of the script execution, gathering together // AppExecResult represent the result of the script execution, gathering together
// all resulting notifications, state, stack and other metadata. // all resulting notifications, state, stack and other metadata.
type AppExecResult struct { type AppExecResult struct {
TxHash util.Uint256 TxHash util.Uint256
Trigger trigger.Type Trigger trigger.Type
VMState vm.State VMState vm.State
GasConsumed int64 GasConsumed int64
Stack []stackitem.Item Stack []stackitem.Item
Events []NotificationEvent Events []NotificationEvent
FaultException string
} }
// EncodeBinary implements the Serializable interface. // EncodeBinary implements the Serializable interface.
@ -62,6 +63,7 @@ func (aer *AppExecResult) EncodeBinary(w *io.BinWriter) {
w.WriteU64LE(uint64(aer.GasConsumed)) w.WriteU64LE(uint64(aer.GasConsumed))
stackitem.EncodeBinaryStackItem(stackitem.NewArray(aer.Stack), w) stackitem.EncodeBinaryStackItem(stackitem.NewArray(aer.Stack), w)
w.WriteArray(aer.Events) w.WriteArray(aer.Events)
w.WriteVarBytes([]byte(aer.FaultException))
} }
// DecodeBinary implements the Serializable interface. // DecodeBinary implements the Serializable interface.
@ -80,6 +82,7 @@ func (aer *AppExecResult) DecodeBinary(r *io.BinReader) {
aer.Stack = arr aer.Stack = arr
} }
r.ReadArray(&aer.Events) r.ReadArray(&aer.Events)
aer.FaultException = r.ReadString()
} }
// notificationEventAux is an auxiliary struct for NotificationEvent JSON marshalling. // 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 // appExecResultAux is an auxiliary struct for JSON marshalling
type appExecResultAux struct { type appExecResultAux struct {
TxHash *util.Uint256 `json:"txid"` TxHash *util.Uint256 `json:"txid"`
Trigger string `json:"trigger"` Trigger string `json:"trigger"`
VMState string `json:"vmstate"` VMState string `json:"vmstate"`
GasConsumed int64 `json:"gasconsumed,string"` GasConsumed int64 `json:"gasconsumed,string"`
Stack json.RawMessage `json:"stack"` Stack json.RawMessage `json:"stack"`
Events []NotificationEvent `json:"notifications"` Events []NotificationEvent `json:"notifications"`
FaultException string `json:"exception,omitempty"`
} }
// MarshalJSON implements implements json.Marshaler interface. // MarshalJSON implements implements json.Marshaler interface.
@ -158,12 +162,13 @@ func (aer *AppExecResult) MarshalJSON() ([]byte, error) {
hash = &aer.TxHash hash = &aer.TxHash
} }
return json.Marshal(&appExecResultAux{ return json.Marshal(&appExecResultAux{
TxHash: hash, TxHash: hash,
Trigger: aer.Trigger.String(), Trigger: aer.Trigger.String(),
VMState: aer.VMState.String(), VMState: aer.VMState.String(),
GasConsumed: aer.GasConsumed, GasConsumed: aer.GasConsumed,
Stack: st, Stack: st,
Events: aer.Events, Events: aer.Events,
FaultException: aer.FaultException,
}) })
} }
@ -202,6 +207,7 @@ func (aer *AppExecResult) UnmarshalJSON(data []byte) error {
aer.VMState = state aer.VMState = state
aer.Events = aux.Events aer.Events = aux.Events
aer.GasConsumed = aux.GasConsumed aer.GasConsumed = aux.GasConsumed
aer.FaultException = aux.FaultException
return nil return nil
} }

View file

@ -24,16 +24,31 @@ func TestEncodeDecodeNotificationEvent(t *testing.T) {
} }
func TestEncodeDecodeAppExecResult(t *testing.T) { func TestEncodeDecodeAppExecResult(t *testing.T) {
appExecResult := &AppExecResult{ t.Run("halt", func(t *testing.T) {
TxHash: random.Uint256(), appExecResult := &AppExecResult{
Trigger: 1, TxHash: random.Uint256(),
VMState: vm.HaltState, Trigger: 1,
GasConsumed: 10, VMState: vm.HaltState,
Stack: []stackitem.Item{}, GasConsumed: 10,
Events: []NotificationEvent{}, 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) { func TestMarshalUnmarshalJSONNotificationEvent(t *testing.T) {
@ -86,6 +101,18 @@ func TestMarshalUnmarshalJSONAppExecResult(t *testing.T) {
testserdes.MarshalUnmarshalJSON(t, appExecResult, new(AppExecResult)) 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) { t.Run("positive, block", func(t *testing.T) {
appExecResult := &AppExecResult{ appExecResult := &AppExecResult{
TxHash: random.Uint256(), TxHash: random.Uint256(),