code.vegaprotocol.io/vega@v0.79.0/core/delegation/snapshot.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 delegation 17 18 import ( 19 "context" 20 "strconv" 21 "time" 22 23 "code.vegaprotocol.io/vega/core/types" 24 "code.vegaprotocol.io/vega/libs/proto" 25 "code.vegaprotocol.io/vega/logging" 26 ) 27 28 var hashKeys = []string{ 29 activeKey, 30 pendingKey, 31 autoKey, 32 lastReconKey, 33 } 34 35 type delegationSnapshotState struct { 36 serialisedActive []byte 37 serialisedPending []byte 38 serialisedAuto []byte 39 serialisedLastRecon []byte 40 } 41 42 func (e *Engine) Namespace() types.SnapshotNamespace { 43 return types.DelegationSnapshot 44 } 45 46 func (e *Engine) Keys() []string { 47 return hashKeys 48 } 49 50 func (e *Engine) Stopped() bool { 51 return false 52 } 53 54 func (e *Engine) serialiseLastReconTime() ([]byte, error) { 55 payload := types.Payload{ 56 Data: &types.PayloadDelegationLastReconTime{ 57 LastReconcilicationTime: e.lastReconciliation, 58 }, 59 } 60 return proto.Marshal(payload.IntoProto()) 61 } 62 63 func (e *Engine) serialiseActive() ([]byte, error) { 64 active := e.getActive() 65 delegations := make([]*types.Delegation, 0, len(active)) 66 for _, a := range active { 67 delegations = append(delegations, &types.Delegation{ 68 Party: a.Party, 69 NodeID: a.Node, 70 EpochSeq: strconv.FormatUint(a.EpochSeq, 10), 71 Amount: a.Amount.Clone(), 72 }) 73 } 74 75 payload := types.Payload{ 76 Data: &types.PayloadDelegationActive{ 77 DelegationActive: &types.DelegationActive{ 78 Delegations: delegations, 79 }, 80 }, 81 } 82 return proto.Marshal(payload.IntoProto()) 83 } 84 85 func (e *Engine) serialisePending() ([]byte, error) { 86 pending := e.getPendingNew() 87 pendingDelegations := make([]*types.Delegation, 0, len(pending)) 88 pendingUndelegations := make([]*types.Delegation, 0, len(pending)) 89 for _, a := range pending { 90 entry := &types.Delegation{ 91 Party: a.Party, 92 NodeID: a.Node, 93 EpochSeq: strconv.FormatUint(a.EpochSeq, 10), 94 Amount: a.Amount.Clone(), 95 } 96 if a.Undelegate { 97 pendingUndelegations = append(pendingUndelegations, entry) 98 } else { 99 pendingDelegations = append(pendingDelegations, entry) 100 } 101 } 102 payload := types.Payload{ 103 Data: &types.PayloadDelegationPending{ 104 DelegationPending: &types.DelegationPending{ 105 Delegations: pendingDelegations, 106 Undelegation: pendingUndelegations, 107 }, 108 }, 109 } 110 111 return proto.Marshal(payload.IntoProto()) 112 } 113 114 func (e *Engine) serialiseAuto() ([]byte, error) { 115 auto := e.getAuto() 116 payload := types.Payload{ 117 Data: &types.PayloadDelegationAuto{ 118 DelegationAuto: &types.DelegationAuto{Parties: auto}, 119 }, 120 } 121 return proto.Marshal(payload.IntoProto()) 122 } 123 124 func (e *Engine) serialiseK(serialFunc func() ([]byte, error), dataField *[]byte) ([]byte, error) { 125 data, err := serialFunc() 126 if err != nil { 127 return nil, err 128 } 129 *dataField = data 130 return data, nil 131 } 132 133 // get the serialised form and hash of the given key. 134 func (e *Engine) serialise(k string) ([]byte, error) { 135 switch k { 136 case activeKey: 137 return e.serialiseK(e.serialiseActive, &e.dss.serialisedActive) 138 case pendingKey: 139 return e.serialiseK(e.serialisePending, &e.dss.serialisedPending) 140 case autoKey: 141 return e.serialiseK(e.serialiseAuto, &e.dss.serialisedAuto) 142 case lastReconKey: 143 return e.serialiseK(e.serialiseLastReconTime, &e.dss.serialisedLastRecon) 144 default: 145 return nil, types.ErrSnapshotKeyDoesNotExist 146 } 147 } 148 149 func (e *Engine) GetState(k string) ([]byte, []types.StateProvider, error) { 150 state, err := e.serialise(k) 151 return state, nil, err 152 } 153 154 func (e *Engine) LoadState(ctx context.Context, p *types.Payload) ([]types.StateProvider, error) { 155 if e.Namespace() != p.Data.Namespace() { 156 return nil, types.ErrInvalidSnapshotNamespace 157 } 158 // see what we're reloading 159 switch pl := p.Data.(type) { 160 case *types.PayloadDelegationActive: 161 return nil, e.restoreActive(ctx, pl.DelegationActive, p) 162 case *types.PayloadDelegationPending: 163 return nil, e.restorePending(ctx, pl.DelegationPending, p) 164 case *types.PayloadDelegationAuto: 165 return nil, e.restoreAuto(pl.DelegationAuto, p) 166 case *types.PayloadDelegationLastReconTime: 167 return nil, e.restoreLastReconTime(pl.LastReconcilicationTime, p) 168 default: 169 return nil, types.ErrUnknownSnapshotType 170 } 171 } 172 173 func (e *Engine) restoreLastReconTime(t time.Time, p *types.Payload) error { 174 var err error 175 e.lastReconciliation = t 176 e.dss.serialisedLastRecon, err = proto.Marshal(p.IntoProto()) 177 178 return err 179 } 180 181 func (e *Engine) restoreActive(ctx context.Context, delegations *types.DelegationActive, p *types.Payload) error { 182 e.partyDelegationState = map[string]*partyDelegation{} 183 entries := make([]*types.DelegationEntry, 0, len(delegations.Delegations)) 184 for _, d := range delegations.Delegations { 185 epoch, _ := strconv.ParseUint(d.EpochSeq, 10, 64) 186 entries = append(entries, &types.DelegationEntry{ 187 Party: d.Party, 188 Node: d.NodeID, 189 Amount: d.Amount, 190 EpochSeq: epoch, 191 }) 192 } 193 e.setActive(ctx, entries) 194 var err error 195 e.dss.serialisedActive, err = proto.Marshal(p.IntoProto()) 196 return err 197 } 198 199 func (e *Engine) restorePending(ctx context.Context, delegations *types.DelegationPending, p *types.Payload) error { 200 e.nextPartyDelegationState = map[string]*partyDelegation{} 201 entries := make([]*types.DelegationEntry, 0, len(delegations.Delegations)) 202 for _, d := range delegations.Delegations { 203 epoch, _ := strconv.ParseUint(d.EpochSeq, 10, 64) 204 entries = append(entries, &types.DelegationEntry{ 205 Party: d.Party, 206 Node: d.NodeID, 207 Amount: d.Amount, 208 EpochSeq: epoch, 209 }) 210 } 211 e.setPendingNew(ctx, entries) 212 var err error 213 e.dss.serialisedPending, err = proto.Marshal(p.IntoProto()) 214 return err 215 } 216 217 func (e *Engine) restoreAuto(delegations *types.DelegationAuto, p *types.Payload) error { 218 e.autoDelegationMode = map[string]struct{}{} 219 e.setAuto(delegations.Parties) 220 var err error 221 e.dss.serialisedAuto, err = proto.Marshal(p.IntoProto()) 222 return err 223 } 224 225 func (e *Engine) onEpochRestore(ctx context.Context, epoch types.Epoch) { 226 e.log.Debug("epoch restoration notification received", logging.String("epoch", epoch.String())) 227 e.currentEpoch = epoch 228 }