code.vegaprotocol.io/vega@v0.79.0/core/integration/stubs/state_var_stub.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 package stubs 17 18 import ( 19 "context" 20 "math/rand" 21 "sort" 22 "strconv" 23 "time" 24 25 "code.vegaprotocol.io/vega/core/types/statevar" 26 ) 27 28 var chars = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") 29 30 type StateVarStub struct { 31 seq int 32 currentTime time.Time 33 svs map[string]*sv 34 eventTypeToStateVar map[statevar.EventType][]*sv 35 rng *rand.Rand 36 readyForTimeTrigger map[string]struct{} 37 stateVarToNextCalc map[string]time.Time 38 updateFrequency time.Duration 39 } 40 41 func NewStateVar() *StateVarStub { 42 return &StateVarStub{ 43 seq: 0, 44 svs: map[string]*sv{}, 45 eventTypeToStateVar: map[statevar.EventType][]*sv{}, 46 rng: rand.New(rand.NewSource(0)), 47 readyForTimeTrigger: map[string]struct{}{}, 48 stateVarToNextCalc: map[string]time.Time{}, 49 } 50 } 51 52 type sv struct { 53 ID string 54 asset string 55 market string 56 converter statevar.Converter 57 startCalculation func(string, statevar.FinaliseCalculation) 58 trigger []statevar.EventType 59 result func(context.Context, statevar.StateVariableResult) error 60 eventID string 61 } 62 63 func (e *StateVarStub) OnFloatingPointUpdatesDurationUpdate(ctx context.Context, updateFrequency time.Duration) error { 64 e.updateFrequency = updateFrequency 65 return nil 66 } 67 68 func (e *StateVarStub) UnregisterStateVariable(asset, market string) { 69 } 70 71 func (e *StateVarStub) RegisterStateVariable(asset, market, name string, converter statevar.Converter, startCalculation func(string, statevar.FinaliseCalculation), trigger []statevar.EventType, result func(context.Context, statevar.StateVariableResult) error) error { 72 ID := asset + "_" + market + "_" + name + "_" + strconv.Itoa(e.seq) 73 e.seq++ 74 e.svs[ID] = &sv{ 75 ID: ID, 76 asset: asset, 77 market: market, 78 converter: converter, 79 startCalculation: startCalculation, 80 trigger: trigger, 81 result: result, 82 } 83 for _, t := range trigger { 84 if _, ok := e.eventTypeToStateVar[t]; !ok { 85 e.eventTypeToStateVar[t] = []*sv{} 86 } 87 e.eventTypeToStateVar[t] = append(e.eventTypeToStateVar[t], e.svs[ID]) 88 } 89 e.ReadyForTimeTrigger(asset, market) 90 return nil 91 } 92 93 func (e *StateVarStub) NewEvent(asset, market string, eventType statevar.EventType) { 94 eventID := e.generateID(asset, market) 95 for _, s := range e.eventTypeToStateVar[eventType] { 96 if s.market != market || s.asset != asset { 97 continue 98 } 99 s.eventID = eventID 100 s.startCalculation(eventID, s) 101 if _, ok := e.stateVarToNextCalc[s.ID]; ok { 102 e.stateVarToNextCalc[s.ID] = e.currentTime.Add(e.updateFrequency) 103 } 104 } 105 } 106 107 func (s *sv) CalculationFinished(eventID string, result statevar.StateVariableResult, err error) { 108 if err == nil { 109 s.result(context.Background(), result) 110 } 111 } 112 113 func (e *StateVarStub) ReadyForTimeTrigger(asset, mktID string) { 114 if _, ok := e.readyForTimeTrigger[asset+mktID]; !ok { 115 e.readyForTimeTrigger[mktID] = struct{}{} 116 for _, s := range e.eventTypeToStateVar[statevar.EventTypeTimeTrigger] { 117 if s.asset == asset && s.market == mktID { 118 e.stateVarToNextCalc[s.ID] = e.currentTime.Add(e.updateFrequency) 119 } 120 } 121 } 122 } 123 124 func (e *StateVarStub) OnTick(ctx context.Context, t time.Time) { 125 e.currentTime = t 126 stateVarIDs := []string{} 127 for ID, nextTime := range e.stateVarToNextCalc { 128 if nextTime.UnixNano() <= t.UnixNano() { 129 stateVarIDs = append(stateVarIDs, ID) 130 } 131 } 132 133 sort.Strings(stateVarIDs) 134 eventID := t.Format("20060102_150405.999999999") 135 for _, ID := range stateVarIDs { 136 s := e.svs[ID] 137 s.startCalculation(eventID, s) 138 e.stateVarToNextCalc[ID] = t.Add(e.updateFrequency) 139 } 140 } 141 142 // generate a random 32 chars identifier. 143 func (e *StateVarStub) generateID(asset, market string) string { 144 b := make([]rune, 32) 145 for i := range b { 146 b[i] = chars[e.rng.Intn(len(chars))] 147 } 148 return asset + "_" + market + "_" + string(b) 149 }