github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/transaction/oracle.go (about) 1 package transaction 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "math" 8 "strings" 9 10 "github.com/nspcc-dev/neo-go/pkg/io" 11 ) 12 13 //go:generate stringer -type=OracleResponseCode 14 15 // OracleResponseCode represents result code of oracle response. 16 type OracleResponseCode byte 17 18 // OracleResponse represents oracle response. 19 type OracleResponse struct { 20 ID uint64 `json:"id"` 21 Code OracleResponseCode `json:"code"` 22 Result []byte `json:"result"` 23 } 24 25 // MaxOracleResultSize is the maximum allowed oracle answer size. 26 const MaxOracleResultSize = math.MaxUint16 27 28 // Enumeration of possible oracle response types. 29 const ( 30 Success OracleResponseCode = 0x00 31 ProtocolNotSupported OracleResponseCode = 0x10 32 ConsensusUnreachable OracleResponseCode = 0x12 33 NotFound OracleResponseCode = 0x14 34 Timeout OracleResponseCode = 0x16 35 Forbidden OracleResponseCode = 0x18 36 ResponseTooLarge OracleResponseCode = 0x1a 37 InsufficientFunds OracleResponseCode = 0x1c 38 ContentTypeNotSupported OracleResponseCode = 0x1f 39 Error OracleResponseCode = 0xff 40 ) 41 42 // Various validation errors. 43 var ( 44 ErrInvalidResponseCode = errors.New("invalid oracle response code") 45 ErrInvalidResult = errors.New("oracle response != success, but result is not empty") 46 ) 47 48 // IsValid checks if c is valid response code. 49 func (c OracleResponseCode) IsValid() bool { 50 return c == Success || c == ProtocolNotSupported || c == ConsensusUnreachable || c == NotFound || 51 c == Timeout || c == Forbidden || c == ResponseTooLarge || 52 c == InsufficientFunds || c == ContentTypeNotSupported || c == Error 53 } 54 55 // MarshalJSON implements the json.Marshaler interface. 56 func (c OracleResponseCode) MarshalJSON() ([]byte, error) { 57 return []byte(`"` + c.String() + `"`), nil 58 } 59 60 // UnmarshalJSON implements the json.Unmarshaler interface. 61 func (c *OracleResponseCode) UnmarshalJSON(data []byte) error { 62 var js string 63 if err := json.Unmarshal(data, &js); err != nil { 64 return err 65 } 66 js = strings.ToLower(js) 67 switch js { 68 case "success": 69 *c = Success 70 case "protocolnotsupported": 71 *c = ProtocolNotSupported 72 case "consensusunreachable": 73 *c = ConsensusUnreachable 74 case "notfound": 75 *c = NotFound 76 case "timeout": 77 *c = Timeout 78 case "forbidden": 79 *c = Forbidden 80 case "responsetoolarge": 81 *c = ResponseTooLarge 82 case "insufficientfunds": 83 *c = InsufficientFunds 84 case "contenttypenotsupported": 85 *c = ContentTypeNotSupported 86 case "error": 87 *c = Error 88 default: 89 return errors.New("invalid oracle response code") 90 } 91 return nil 92 } 93 94 // DecodeBinary implements the io.Serializable interface. 95 func (r *OracleResponse) DecodeBinary(br *io.BinReader) { 96 r.ID = br.ReadU64LE() 97 r.Code = OracleResponseCode(br.ReadB()) 98 if !r.Code.IsValid() { 99 br.Err = ErrInvalidResponseCode 100 return 101 } 102 r.Result = br.ReadVarBytes(MaxOracleResultSize) 103 if r.Code != Success && len(r.Result) > 0 { 104 br.Err = ErrInvalidResult 105 } 106 } 107 108 // EncodeBinary implements the io.Serializable interface. 109 func (r *OracleResponse) EncodeBinary(w *io.BinWriter) { 110 w.WriteU64LE(r.ID) 111 w.WriteB(byte(r.Code)) 112 w.WriteVarBytes(r.Result) 113 } 114 115 func (r *OracleResponse) toJSONMap(m map[string]any) { 116 m["id"] = r.ID 117 m["code"] = r.Code 118 m["result"] = r.Result 119 } 120 121 // Copy implements the AttrValue interface. 122 func (r *OracleResponse) Copy() AttrValue { 123 return &OracleResponse{ 124 ID: r.ID, 125 Code: r.Code, 126 Result: bytes.Clone(r.Result), 127 } 128 }