code.vegaprotocol.io/vega@v0.79.0/core/datasource/common/data.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 //lint:file-ignore ST1003 Ignore underscores in names, this is straigh copied from the proto package to ease introducing the domain types 17 18 package common 19 20 import ( 21 "fmt" 22 "strconv" 23 "time" 24 25 "code.vegaprotocol.io/vega/libs/num" 26 "code.vegaprotocol.io/vega/logging" 27 28 "go.uber.org/zap" 29 ) 30 31 // Data holds normalized data coming from an oracle. 32 type Data struct { 33 // EthKey is currently just the spec id, which is suboptimal as multiple specs calling the same 34 // contracts at the same time will duplicate data. This is a temporary solution until we have 35 // a better method of making a key of (contract address, args, block height/time + previous height/time) 36 // 'previous' being required so that receivers can check if the their trigger would have fired. 37 EthKey string 38 Signers []*Signer 39 Data map[string]string 40 MetaData map[string]string 41 } 42 43 func (d Data) GetUint(name string) (*num.Uint, error) { 44 value, ok := d.Data[name] 45 if !ok { 46 return nil, errPropertyNotFound(name) 47 } 48 val, fail := num.UintFromString(value, 10) 49 if fail { 50 return nil, errInvalidString(name, value) 51 } 52 return val, nil 53 } 54 55 // GetInteger converts the value associated to propertyName into an integer. 56 func (d Data) GetInteger(propertyName string) (*num.Int, error) { 57 value, ok := d.Data[propertyName] 58 if !ok { 59 return num.IntZero(), errPropertyNotFound(propertyName) 60 } 61 return ToInteger(value) 62 } 63 64 // GetDecimal converts the value associated to propertyName into a decimal. 65 func (d Data) GetDecimal(propertyName string) (num.Decimal, error) { 66 value, ok := d.Data[propertyName] 67 if !ok { 68 return num.DecimalZero(), errPropertyNotFound(propertyName) 69 } 70 return ToDecimal(value) 71 } 72 73 // GetBoolean converts the value associated to propertyName into a boolean. 74 func (d Data) GetBoolean(propertyName string) (bool, error) { 75 value, ok := d.Data[propertyName] 76 if !ok { 77 return false, errPropertyNotFound(propertyName) 78 } 79 return ToBoolean(value) 80 } 81 82 // GetString returns the value associated to propertyName. 83 func (d Data) GetString(propertyName string) (string, error) { 84 value, ok := d.Data[propertyName] 85 if !ok { 86 return "", errPropertyNotFound(propertyName) 87 } 88 return value, nil 89 } 90 91 // GetTimestamp converts the value associated to propertyName into a timestamp. 92 func (d Data) GetTimestamp(propertyName string) (int64, error) { 93 value, ok := d.Data[propertyName] 94 if !ok { 95 return 0, errPropertyNotFound(propertyName) 96 } 97 return ToTimestamp(value) 98 } 99 100 // GetDataTimestampNano gets the eth block time (or vega time) associated with the oracle data. 101 func (d Data) GetDataTimestampNano() (int64, error) { 102 if ebt, ok := d.MetaData["eth-block-time"]; ok { 103 // add price point with "eth-block-time" as time 104 pt, err := strconv.ParseInt(ebt, 10, 64) 105 if err != nil { 106 return 0, err 107 } 108 return time.Unix(pt, 0).UnixNano(), nil 109 } 110 // open oracle timestamp 111 if oot, ok := d.MetaData["open-oracle-timestamp"]; ok { 112 pt, err := strconv.ParseInt(oot, 10, 64) 113 if err != nil { 114 return 0, err 115 } 116 return time.Unix(pt, 0).UnixNano(), nil 117 } 118 // fall back to vega time 119 if vt, ok := d.MetaData["vega-time"]; ok { 120 t, err := strconv.ParseInt(vt, 10, 64) 121 if err != nil { 122 return 0, err 123 } 124 return time.Unix(t, 0).UnixNano(), nil 125 } 126 return 0, fmt.Errorf("data has no timestamp data") 127 } 128 129 // FromInternalOracle returns true if the oracle data has been emitted by an 130 // internal oracle. 131 func (d Data) FromInternalOracle() bool { 132 return len(d.Signers) == 0 133 } 134 135 func (d Data) Debug() []zap.Field { 136 keys := "" 137 for _, key := range d.Signers { 138 keys += key.String() + " " 139 } 140 141 fields := []zap.Field{ 142 logging.String("Signers", keys), 143 } 144 for property, value := range d.Data { 145 fields = append(fields, logging.String(property, value)) 146 } 147 return fields 148 } 149 150 // errPropertyNotFound is returned when the property is not present in the Data. 151 func errPropertyNotFound(propertyName string) error { 152 return fmt.Errorf("property \"%s\" not found", propertyName) 153 } 154 155 func errInvalidString(name, val string) error { 156 return fmt.Errorf("could not parse value '%s' for property '%s'", val, name) 157 }