diff --git a/pkg/core/dao/dao_test.go b/pkg/core/dao/dao_test.go index acc88c9ed..4ae08f4e1 100644 --- a/pkg/core/dao/dao_test.go +++ b/pkg/core/dao/dao_test.go @@ -197,7 +197,7 @@ func TestStoreAsTransaction(t *testing.T) { stackitem.NewBool(false), }), ArgumentsCount: 1, - IsValid: true, + Truncated: false, }}, }, } diff --git a/pkg/core/interop/context.go b/pkg/core/interop/context.go index 67f7718d7..08be26d20 100644 --- a/pkg/core/interop/context.go +++ b/pkg/core/interop/context.go @@ -71,6 +71,7 @@ type Context struct { loadToken func(ic *Context, id int32) error GetRandomCounter uint32 signers []transaction.Signer + SaveInvocations bool } // NewContext returns new interop context. @@ -81,20 +82,21 @@ func NewContext(trigger trigger.Type, bc Ledger, d *dao.Simple, baseExecFee, bas dao := d.GetPrivate() cfg := bc.GetConfig().ProtocolConfiguration return &Context{ - Chain: bc, - Network: uint32(cfg.Magic), - Hardforks: cfg.Hardforks, - Natives: natives, - Trigger: trigger, - Block: block, - Tx: tx, - DAO: dao, - Log: log, - Invocations: make(map[util.Uint160]int), - getContract: getContract, - baseExecFee: baseExecFee, - baseStorageFee: baseStorageFee, - loadToken: loadTokenFunc, + Chain: bc, + Network: uint32(cfg.Magic), + Hardforks: cfg.Hardforks, + Natives: natives, + Trigger: trigger, + Block: block, + Tx: tx, + DAO: dao, + Log: log, + Invocations: make(map[util.Uint160]int), + getContract: getContract, + baseExecFee: baseExecFee, + baseStorageFee: baseStorageFee, + loadToken: loadTokenFunc, + SaveInvocations: bc.GetConfig().SaveInvocations, } } diff --git a/pkg/core/interop/contract/call.go b/pkg/core/interop/contract/call.go index be1bbfdea..1cbabf5f3 100644 --- a/pkg/core/interop/contract/call.go +++ b/pkg/core/interop/contract/call.go @@ -70,23 +70,22 @@ func Call(ic *interop.Context) error { } hasReturn := md.ReturnType != smartcontract.VoidType - if ic.Chain.GetConfig().Ledger.SaveInvocations { - arr := stackitem.NewArray(args) - arrCount := len(args) - valid := true - argBytes := []byte{} - if argBytes, err = ic.DAO.GetItemCtx().Serialize(arr, false); err != nil { - arr = stackitem.NewArray([]stackitem.Item{}) - valid = false + if ic.SaveInvocations { + var ( + arrCount = len(args) + truncated = false + argBytes []byte + ) + if argBytes, err = ic.DAO.GetItemCtx().Serialize(stackitem.NewArray(args), false); err != nil { + truncated = true } ic.InvocationCalls = append(ic.InvocationCalls, state.ContractInvocation{ Hash: u, Method: method, - Arguments: arr, ArgumentsBytes: argBytes, ArgumentsCount: uint32(arrCount), - IsValid: valid, + Truncated: truncated, }) } return callInternal(ic, cs, method, fs, hasReturn, args, true) diff --git a/pkg/core/state/notification_event.go b/pkg/core/state/notification_event.go index 0d0394a4d..72c1a8dc8 100644 --- a/pkg/core/state/notification_event.go +++ b/pkg/core/state/notification_event.go @@ -20,13 +20,16 @@ type NotificationEvent struct { Item *stackitem.Array `json:"state"` } +// ContractInvocation contains method call information. +// The Arguments field will be nil if serialization of the arguments exceeds a predefined limit +// (for security reasons). In that case Truncated will be set to true. type ContractInvocation struct { - Hash util.Uint160 `json:"contract_hash"` + Hash util.Uint160 `json:"contracthash"` Method string `json:"method"` Arguments *stackitem.Array `json:"arguments"` - ArgumentsBytes []byte `json:"arguments_bytes"` - ArgumentsCount uint32 `json:"arguments_count"` - IsValid bool `json:"is_valid"` + ArgumentsBytes []byte + ArgumentsCount uint32 `json:"argumentscount"` + Truncated bool `json:"truncated"` } func (ci *ContractInvocation) DecodeBinary(r *io.BinReader) { @@ -39,7 +42,7 @@ func (ci *ContractInvocation) DecodeBinary(r *io.BinReader) { } ci.Arguments = si.(*stackitem.Array) ci.ArgumentsCount = r.ReadU32LE() - ci.IsValid = r.ReadBool() + ci.Truncated = r.ReadBool() } func (ci *ContractInvocation) EncodeBinaryWithContext(w *io.BinWriter, sc *stackitem.SerializationContext) { @@ -47,7 +50,7 @@ func (ci *ContractInvocation) EncodeBinaryWithContext(w *io.BinWriter, sc *stack w.WriteString(ci.Method) w.WriteVarBytes(ci.ArgumentsBytes) w.WriteU32LE(ci.ArgumentsCount) - w.WriteBool(ci.IsValid) + w.WriteBool(ci.Truncated) } // MarshalJSON implements the json.Marshaler interface. @@ -61,7 +64,7 @@ func (ci ContractInvocation) MarshalJSON() ([]byte, error) { Method: ci.Method, Arguments: item, ArgumentsCount: ci.ArgumentsCount, - IsValid: ci.IsValid, + Truncated: ci.Truncated, }) } @@ -82,7 +85,7 @@ func (ci *ContractInvocation) UnmarshalJSON(data []byte) error { ci.Method = aux.Method ci.Hash = aux.Hash ci.ArgumentsCount = aux.ArgumentsCount - ci.IsValid = aux.IsValid + ci.Truncated = aux.Truncated return nil } @@ -194,7 +197,9 @@ func (aer *AppExecResult) DecodeBinary(r *io.BinReader) { aer.Stack = arr r.ReadArray(&aer.Events) aer.FaultException = r.ReadString() - r.ReadArray(&aer.Invocations) + if r.Len() > 0 { + r.ReadArray(&aer.Invocations) + } } // notificationEventAux is an auxiliary struct for NotificationEvent JSON marshalling. @@ -288,11 +293,11 @@ type Execution struct { } type ContractInvocationAux struct { - Hash util.Uint160 `json:"contract_hash"` + Hash util.Uint160 `json:"contracthash"` Method string `json:"method"` Arguments json.RawMessage `json:"arguments"` - ArgumentsCount uint32 `json:"arguments_count"` - IsValid bool `json:"is_valid"` + ArgumentsCount uint32 `json:"argumentscount"` + Truncated bool `json:"truncated"` } // executionAux represents an auxiliary struct for Execution JSON marshalling.