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:     &ethcallcommon.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  }