code.vegaprotocol.io/vega@v0.79.0/core/datasource/definition/definition.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 definition 19 20 import ( 21 "errors" 22 "fmt" 23 "time" 24 25 "code.vegaprotocol.io/vega/core/datasource/common" 26 dserrors "code.vegaprotocol.io/vega/core/datasource/errors" 27 ethcallcommon "code.vegaprotocol.io/vega/core/datasource/external/ethcall/common" 28 "code.vegaprotocol.io/vega/core/datasource/external/signedoracle" 29 "code.vegaprotocol.io/vega/core/datasource/internal/timetrigger" 30 "code.vegaprotocol.io/vega/core/datasource/internal/vegatime" 31 vegapb "code.vegaprotocol.io/vega/protos/vega" 32 datapb "code.vegaprotocol.io/vega/protos/vega/data/v1" 33 ) 34 35 type ContentType int32 36 37 const ( 38 ContentTypeInvalid ContentType = iota 39 ContentTypeOracle 40 ContentTypeEthOracle 41 ContentTypeInternalTimeTermination 42 ContentTypeInternalTimeTriggerTermination 43 ) 44 45 type Definition struct { 46 common.DataSourceType 47 } 48 49 func NewWith(dst common.DataSourceType) *Definition { 50 if dst == nil { 51 return &Definition{} 52 } 53 return &Definition{ 54 DataSourceType: dst.DeepClone(), 55 } 56 } 57 58 // New creates a new EMPTY Definition object. 59 // TODO: eth oracle type too. 60 func New(tp ContentType) *Definition { 61 ds := &Definition{} 62 switch tp { 63 case ContentTypeOracle: 64 return NewWith( 65 signedoracle.SpecConfiguration{ 66 Signers: []*common.Signer{}, 67 Filters: []*common.SpecFilter{}, 68 }) 69 case ContentTypeEthOracle: 70 return NewWith( 71 ethcallcommon.Spec{ 72 AbiJson: []byte{}, 73 ArgsJson: []string{}, 74 Trigger: ðcallcommon.TimeTrigger{}, 75 Normalisers: map[string]string{}, 76 Filters: common.SpecFilters{}, 77 }) 78 case ContentTypeInternalTimeTermination: 79 return NewWith( 80 vegatime.SpecConfiguration{ 81 Conditions: []*common.SpecCondition{}, 82 }) 83 case ContentTypeInternalTimeTriggerTermination: 84 return NewWith( 85 timetrigger.SpecConfiguration{ 86 Triggers: common.InternalTimeTriggers{}, 87 Conditions: []*common.SpecCondition{}, 88 }) 89 } 90 return ds 91 } 92 93 // IntoProto returns the proto object from Definition 94 // that is - vegapb.DataSourceDefinition that may have external or internal SourceType. 95 // Returns the whole proto object. 96 func (s *Definition) IntoProto() *vegapb.DataSourceDefinition { 97 if s.DataSourceType == nil { 98 return &vegapb.DataSourceDefinition{} 99 } 100 proto, err := s.ToDefinitionProto() 101 if err != nil { 102 // TODO: bubble error 103 return &vegapb.DataSourceDefinition{} 104 } 105 106 return proto 107 } 108 109 // DeepClone returns a clone of the Definition object. 110 func (s Definition) DeepClone() common.DataSourceType { 111 if s.DataSourceType != nil { 112 return &Definition{ 113 DataSourceType: s.DataSourceType.DeepClone(), 114 } 115 } 116 return nil 117 } 118 119 func (s Definition) String() string { 120 if s.DataSourceType != nil { 121 return s.DataSourceType.String() 122 } 123 return "" 124 } 125 126 func (s *Definition) Content() interface{} { 127 return s.DataSourceType 128 } 129 130 // FromProto tries to build the Definiition object 131 // from the given proto object. 132 func FromProto(protoConfig *vegapb.DataSourceDefinition, tm *time.Time) (common.DataSourceType, error) { 133 if protoConfig != nil { 134 data := protoConfig.Content() 135 switch dtp := data.(type) { 136 case *vegapb.DataSourceSpecConfiguration: 137 return signedoracle.SpecConfigurationFromProto(dtp), nil 138 139 case *vegapb.EthCallSpec: 140 return ethcallcommon.SpecFromProto(dtp) 141 142 case *vegapb.DataSourceSpecConfigurationTime: 143 return vegatime.SpecConfigurationFromProto(dtp), nil 144 case *vegapb.DataSourceSpecConfigurationTimeTrigger: 145 return timetrigger.SpecConfigurationFromProto(dtp, tm) 146 } 147 } 148 149 return &Definition{}, nil 150 } 151 152 // GetSigners tries to get the signers from the Definition if they exist. 153 func (s *Definition) GetSigners() []*common.Signer { 154 signers := []*common.Signer{} 155 156 data := s.Content() 157 if data != nil { 158 switch tp := data.(type) { 159 case signedoracle.SpecConfiguration: 160 signers = tp.Signers 161 } 162 } 163 164 return signers 165 } 166 167 // GetFilters tries to get the filters from the Definition if they exist. 168 func (s *Definition) GetFilters() []*common.SpecFilter { 169 filters := []*common.SpecFilter{} 170 171 data := s.Content() 172 if data != nil { 173 switch tp := data.(type) { 174 case signedoracle.SpecConfiguration: 175 filters = tp.Filters 176 177 case ethcallcommon.Spec: 178 filters = tp.Filters 179 180 case vegatime.SpecConfiguration: 181 // TODO: Fix this to use the same method as in the vegatime package (example: as below) 182 // For the case the internal data source is time based 183 // (as of OT https://github.com/vegaprotocol/specs/blob/master/protocol/0048-DSRI-data_source_internal.md#13-vega-time-changed) 184 // We add the filter key values manually to match a time based data source 185 // Ensure only a single filter has been created, that holds the first condition 186 if len(tp.Conditions) > 0 { 187 filters = append( 188 filters, 189 &common.SpecFilter{ 190 Key: &common.SpecPropertyKey{ 191 Name: vegatime.VegaTimeKey, 192 Type: datapb.PropertyKey_TYPE_TIMESTAMP, 193 }, 194 Conditions: []*common.SpecCondition{ 195 tp.Conditions[0], 196 }, 197 }, 198 ) 199 } 200 201 case timetrigger.SpecConfiguration: 202 sc := s.GetInternalTimeTriggerSpecConfiguration() 203 filters = sc.GetFilters() 204 } 205 } 206 207 return filters 208 } 209 210 // GetSignedOracleSpecConfiguration returns the base object - vega oracle SpecConfiguration 211 // from the Definition. 212 func (s *Definition) GetSignedOracleSpecConfiguration() signedoracle.SpecConfiguration { 213 data := s.Content() 214 if data != nil { 215 switch tp := data.(type) { 216 case signedoracle.SpecConfiguration: 217 return tp 218 } 219 } 220 221 return signedoracle.SpecConfiguration{} 222 } 223 224 // GetEthCallSpec returns the base object - EthCallSpec 225 // from the Definition. 226 func (s *Definition) GetEthCallSpec() ethcallcommon.Spec { 227 data := s.Content() 228 if data != nil { 229 switch tp := data.(type) { 230 case ethcallcommon.Spec: 231 return tp 232 } 233 } 234 235 return ethcallcommon.Spec{} 236 } 237 238 func (s *Definition) IsEthCallSpec() bool { 239 data := s.Content() 240 if data != nil { 241 switch data.(type) { 242 case ethcallcommon.Spec: 243 return true 244 } 245 } 246 247 return false 248 } 249 250 func (s *Definition) EnsureValidChainID(ids []uint64) bool { 251 data := s.Content() 252 if data != nil { 253 switch d := data.(type) { 254 case ethcallcommon.Spec: 255 for _, id := range ids { 256 if id == d.SourceChainID { 257 return true 258 } 259 } 260 return false 261 } 262 } 263 264 return true 265 } 266 267 // Definition is also a `Timer`. 268 func (s *Definition) GetTimeTriggers() common.InternalTimeTriggers { 269 data := s.Content() 270 if data != nil { 271 switch tp := data.(type) { 272 case timetrigger.SpecConfiguration: 273 return tp.GetTimeTriggers() 274 } 275 } 276 277 return common.InternalTimeTriggers{} 278 } 279 280 func (s *Definition) IsTriggered(tm time.Time) bool { 281 data := s.Content() 282 if data != nil { 283 switch tp := data.(type) { 284 case timetrigger.SpecConfiguration: 285 return tp.IsTriggered(tm) 286 } 287 } 288 289 return false 290 } 291 292 // UpdateFilters updates the Definition Filters. 293 func (s *Definition) UpdateFilters(filters []*common.SpecFilter) error { 294 fTypeCheck := map[*common.SpecFilter]struct{}{} 295 fNameCheck := map[string]struct{}{} 296 for _, f := range filters { 297 if _, ok := fTypeCheck[f]; ok { 298 return dserrors.ErrDataSourceSpecHasMultipleSameKeyNamesInFilterList 299 } 300 if f.Key != nil { 301 if _, ok := fNameCheck[f.Key.Name]; ok { 302 return dserrors.ErrDataSourceSpecHasMultipleSameKeyNamesInFilterList 303 } 304 fNameCheck[f.Key.Name] = struct{}{} 305 } 306 fTypeCheck[f] = struct{}{} 307 } 308 309 // maybe todo - enforce that it's never nil 310 if s.DataSourceType == nil { 311 return nil 312 } 313 314 switch content := s.DataSourceType.DeepClone().(type) { 315 case signedoracle.SpecConfiguration: 316 content.Filters = filters 317 s.DataSourceType = content 318 319 case ethcallcommon.Spec: 320 content.Filters = filters 321 s.DataSourceType = content 322 323 case vegatime.SpecConfiguration: 324 // The data source definition is an internal time based source 325 // For this case we take only the first item from the list of filters 326 // https://github.com/vegaprotocol/specs/blob/master/protocol/0048-DSRI-data_source_internal.md#13-vega-time-changed 327 c := []*common.SpecCondition{} 328 if len(filters) > 0 { 329 if len(filters[0].Conditions) > 0 { 330 c = append(c, filters[0].Conditions[0]) 331 } 332 } 333 content.Conditions = c 334 s.DataSourceType = content 335 336 case timetrigger.SpecConfiguration: 337 c := []*common.SpecCondition{} 338 if len(filters) > 0 { 339 for _, f := range filters { 340 if len(f.Conditions) > 0 { 341 c = append(c, f.Conditions...) 342 } 343 } 344 } 345 content.Conditions = c 346 s.DataSourceType = content 347 348 default: 349 return fmt.Errorf("unable to set filters on data source type: %T", content) 350 } 351 return nil 352 } 353 354 func (s *Definition) SetFilterDecimals(d uint64) *Definition { 355 switch content := s.DataSourceType.DeepClone().(type) { 356 case signedoracle.SpecConfiguration: 357 for i := range content.Filters { 358 content.Filters[i].Key.NumberDecimalPlaces = &d 359 } 360 s.DataSourceType = content 361 case ethcallcommon.Spec: 362 for i := range content.Filters { 363 content.Filters[i].Key.NumberDecimalPlaces = &d 364 } 365 s.DataSourceType = content 366 367 default: 368 // we should really be returning an error here but this method is only used in the integration tests 369 panic(fmt.Sprintf("unable to set filter decimals on data source type: %T", content)) 370 } 371 return s 372 } 373 374 // SetOracleConfig sets a given oracle config in the receiver. 375 // If the receiver is not external oracle type data source - it is not changed. 376 // This method does not care about object previous contents. 377 func (s *Definition) SetOracleConfig(oc common.DataSourceType) *Definition { 378 if _, ok := s.DataSourceType.(signedoracle.SpecConfiguration); ok { 379 s.DataSourceType = oc.DeepClone() 380 } 381 382 if _, ok := s.DataSourceType.(ethcallcommon.Spec); ok { 383 s.DataSourceType = oc.DeepClone() 384 } 385 386 return s 387 } 388 389 // SetTimeTriggerConditionConfig sets a given conditions config in the receiver. 390 // If the receiver is not a time triggered data source - it does not set anything to it. 391 // This method does not care about object previous contents. 392 func (s *Definition) SetTimeTriggerConditionConfig(c []*common.SpecCondition) *Definition { 393 if _, ok := s.DataSourceType.(vegatime.SpecConfiguration); ok { 394 s.DataSourceType = vegatime.SpecConfiguration{ 395 Conditions: c, 396 } 397 } 398 399 if sc, ok := s.DataSourceType.(timetrigger.SpecConfiguration); ok { 400 s.DataSourceType = timetrigger.SpecConfiguration{ 401 Triggers: sc.Triggers, 402 Conditions: c, 403 } 404 } 405 return s 406 } 407 408 func (s *Definition) SetTimeTriggerTriggersConfig(tr common.InternalTimeTriggers) *Definition { 409 if sc, ok := s.DataSourceType.(timetrigger.SpecConfiguration); ok { 410 s.DataSourceType = timetrigger.SpecConfiguration{ 411 Triggers: tr, 412 Conditions: sc.Conditions, 413 } 414 } 415 return s 416 } 417 418 func (s *Definition) GetVegaTimeSpecConfiguration() vegatime.SpecConfiguration { 419 data := s.Content() 420 switch tp := data.(type) { 421 case vegatime.SpecConfiguration: 422 return tp 423 } 424 425 return vegatime.SpecConfiguration{} 426 } 427 428 func (s *Definition) GetInternalTimeTriggerSpecConfiguration() timetrigger.SpecConfiguration { 429 data := s.Content() 430 switch tp := data.(type) { 431 case timetrigger.SpecConfiguration: 432 return tp 433 } 434 return timetrigger.SpecConfiguration{} 435 } 436 437 func (s *Definition) IsExternal() (bool, error) { 438 switch s.DataSourceType.(type) { 439 case signedoracle.SpecConfiguration: 440 return true, nil 441 case ethcallcommon.Spec: 442 return true, nil 443 case vegatime.SpecConfiguration: 444 return false, nil 445 case timetrigger.SpecConfiguration: 446 return false, nil 447 } 448 return false, errors.New("unknown type of data source provided") 449 } 450 451 func (s *Definition) Type() (ContentType, bool) { 452 switch s.DataSourceType.(type) { 453 case signedoracle.SpecConfiguration: 454 return ContentTypeOracle, true 455 case ethcallcommon.Spec: 456 return ContentTypeEthOracle, true 457 case vegatime.SpecConfiguration: 458 return ContentTypeInternalTimeTermination, false 459 case timetrigger.SpecConfiguration: 460 return ContentTypeInternalTimeTriggerTermination, false 461 } 462 return ContentTypeInvalid, false 463 } 464 465 func (s *Definition) GetSpecConfiguration() common.DataSourceType { 466 switch s.DataSourceType.(type) { 467 case signedoracle.SpecConfiguration: 468 return s.GetSignedOracleSpecConfiguration() 469 case ethcallcommon.Spec: 470 return s.GetEthCallSpec() 471 case vegatime.SpecConfiguration: 472 return s.GetVegaTimeSpecConfiguration() 473 case timetrigger.SpecConfiguration: 474 return s.GetInternalTimeTriggerSpecConfiguration() 475 } 476 477 return nil 478 }