forked from TrueCloudLab/neoneo-go
956fd08adb
Add a method that makes a deep copy of all fields and resets size/hash caches. Close #3288 Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
128 lines
3.4 KiB
Go
128 lines
3.4 KiB
Go
package transaction
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"math"
|
|
"strings"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
|
)
|
|
|
|
//go:generate stringer -type=OracleResponseCode
|
|
|
|
// OracleResponseCode represents result code of oracle response.
|
|
type OracleResponseCode byte
|
|
|
|
// OracleResponse represents oracle response.
|
|
type OracleResponse struct {
|
|
ID uint64 `json:"id"`
|
|
Code OracleResponseCode `json:"code"`
|
|
Result []byte `json:"result"`
|
|
}
|
|
|
|
// MaxOracleResultSize is the maximum allowed oracle answer size.
|
|
const MaxOracleResultSize = math.MaxUint16
|
|
|
|
// Enumeration of possible oracle response types.
|
|
const (
|
|
Success OracleResponseCode = 0x00
|
|
ProtocolNotSupported OracleResponseCode = 0x10
|
|
ConsensusUnreachable OracleResponseCode = 0x12
|
|
NotFound OracleResponseCode = 0x14
|
|
Timeout OracleResponseCode = 0x16
|
|
Forbidden OracleResponseCode = 0x18
|
|
ResponseTooLarge OracleResponseCode = 0x1a
|
|
InsufficientFunds OracleResponseCode = 0x1c
|
|
ContentTypeNotSupported OracleResponseCode = 0x1f
|
|
Error OracleResponseCode = 0xff
|
|
)
|
|
|
|
// Various validation errors.
|
|
var (
|
|
ErrInvalidResponseCode = errors.New("invalid oracle response code")
|
|
ErrInvalidResult = errors.New("oracle response != success, but result is not empty")
|
|
)
|
|
|
|
// IsValid checks if c is valid response code.
|
|
func (c OracleResponseCode) IsValid() bool {
|
|
return c == Success || c == ProtocolNotSupported || c == ConsensusUnreachable || c == NotFound ||
|
|
c == Timeout || c == Forbidden || c == ResponseTooLarge ||
|
|
c == InsufficientFunds || c == ContentTypeNotSupported || c == Error
|
|
}
|
|
|
|
// MarshalJSON implements the json.Marshaler interface.
|
|
func (c OracleResponseCode) MarshalJSON() ([]byte, error) {
|
|
return []byte(`"` + c.String() + `"`), nil
|
|
}
|
|
|
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
|
func (c *OracleResponseCode) UnmarshalJSON(data []byte) error {
|
|
var js string
|
|
if err := json.Unmarshal(data, &js); err != nil {
|
|
return err
|
|
}
|
|
js = strings.ToLower(js)
|
|
switch js {
|
|
case "success":
|
|
*c = Success
|
|
case "protocolnotsupported":
|
|
*c = ProtocolNotSupported
|
|
case "consensusunreachable":
|
|
*c = ConsensusUnreachable
|
|
case "notfound":
|
|
*c = NotFound
|
|
case "timeout":
|
|
*c = Timeout
|
|
case "forbidden":
|
|
*c = Forbidden
|
|
case "responsetoolarge":
|
|
*c = ResponseTooLarge
|
|
case "insufficientfunds":
|
|
*c = InsufficientFunds
|
|
case "contenttypenotsupported":
|
|
*c = ContentTypeNotSupported
|
|
case "error":
|
|
*c = Error
|
|
default:
|
|
return errors.New("invalid oracle response code")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DecodeBinary implements the io.Serializable interface.
|
|
func (r *OracleResponse) DecodeBinary(br *io.BinReader) {
|
|
r.ID = br.ReadU64LE()
|
|
r.Code = OracleResponseCode(br.ReadB())
|
|
if !r.Code.IsValid() {
|
|
br.Err = ErrInvalidResponseCode
|
|
return
|
|
}
|
|
r.Result = br.ReadVarBytes(MaxOracleResultSize)
|
|
if r.Code != Success && len(r.Result) > 0 {
|
|
br.Err = ErrInvalidResult
|
|
}
|
|
}
|
|
|
|
// EncodeBinary implements the io.Serializable interface.
|
|
func (r *OracleResponse) EncodeBinary(w *io.BinWriter) {
|
|
w.WriteU64LE(r.ID)
|
|
w.WriteB(byte(r.Code))
|
|
w.WriteVarBytes(r.Result)
|
|
}
|
|
|
|
func (r *OracleResponse) toJSONMap(m map[string]any) {
|
|
m["id"] = r.ID
|
|
m["code"] = r.Code
|
|
m["result"] = r.Result
|
|
}
|
|
|
|
// Copy implements the AttrValue interface.
|
|
func (r *OracleResponse) Copy() AttrValue {
|
|
return &OracleResponse{
|
|
ID: r.ID,
|
|
Code: r.Code,
|
|
Result: bytes.Clone(r.Result),
|
|
}
|
|
}
|