code.vegaprotocol.io/vega@v0.79.0/core/vesting/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 vesting 17 18 import ( 19 "context" 20 "fmt" 21 "sort" 22 23 "code.vegaprotocol.io/vega/core/types" 24 vgcontext "code.vegaprotocol.io/vega/libs/context" 25 "code.vegaprotocol.io/vega/libs/num" 26 "code.vegaprotocol.io/vega/libs/proto" 27 "code.vegaprotocol.io/vega/logging" 28 snapshotpb "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" 29 ) 30 31 var VestingKey = (&types.PayloadVesting{}).Key() 32 33 type SnapshotEngine struct { 34 *Engine 35 } 36 37 func NewSnapshotEngine( 38 log *logging.Logger, 39 c Collateral, 40 asvm ActivityStreakVestingMultiplier, 41 broker Broker, 42 assets Assets, 43 parties Parties, 44 t Time, 45 stakeAccounting StakeAccounting, 46 ) *SnapshotEngine { 47 se := &SnapshotEngine{ 48 Engine: New(log, c, asvm, broker, assets, parties, t, stakeAccounting), 49 } 50 51 return se 52 } 53 54 func (e *SnapshotEngine) Namespace() types.SnapshotNamespace { 55 return types.VestingSnapshot 56 } 57 58 func (e *SnapshotEngine) Keys() []string { 59 return []string{VestingKey} 60 } 61 62 func (e *SnapshotEngine) Stopped() bool { 63 return false 64 } 65 66 func (e *SnapshotEngine) GetState(k string) ([]byte, []types.StateProvider, error) { 67 state, err := e.serialise(k) 68 return state, nil, err 69 } 70 71 func (e *SnapshotEngine) LoadState(ctx context.Context, p *types.Payload) ([]types.StateProvider, error) { 72 if e.Namespace() != p.Data.Namespace() { 73 return nil, types.ErrInvalidSnapshotNamespace 74 } 75 76 switch data := p.Data.(type) { 77 case *types.PayloadVesting: 78 e.loadStateFromSnapshot(ctx, data.Vesting) 79 return nil, nil 80 default: 81 return nil, types.ErrUnknownSnapshotType 82 } 83 } 84 85 func (e *SnapshotEngine) loadStateFromSnapshot(ctx context.Context, state *snapshotpb.Vesting) { 86 for _, entry := range state.PartiesReward { 87 for _, v := range entry.InVesting { 88 balance, underflow := num.UintFromString(v.Balance, 10) 89 if underflow { 90 e.log.Panic("uint256 in snapshot underflow", 91 logging.String("value", v.Balance)) 92 } 93 e.increaseVestingBalance(entry.Party, v.Asset, balance) 94 } 95 96 for _, locked := range entry.AssetLocked { 97 for _, epochBalance := range locked.EpochBalances { 98 balance, underflow := num.UintFromString(epochBalance.Balance, 10) 99 if underflow { 100 e.log.Panic("uint256 in snapshot underflow", 101 logging.String("value", epochBalance.Balance)) 102 } 103 e.increaseLockedForAsset(entry.Party, locked.Asset, balance, epochBalance.Epoch) 104 } 105 } 106 } 107 108 if vgcontext.InProgressUpgradeFrom(ctx, "v0.78.8") { 109 e.updateStakingOnUpgrade79(ctx) 110 } 111 } 112 113 // updateStakingOnUpgrade79 update staking balance for party which had 114 // rewards vesting before the upgrade. 115 func (e *SnapshotEngine) updateStakingOnUpgrade79(ctx context.Context) { 116 for i, v := range e.c.GetAllVestingAndVestedAccountForAsset(e.stakingAsset) { 117 e.updateStakingAccount(ctx, v.Owner, v.Balance.Clone(), uint64(i), e.broker.Stage) 118 } 119 } 120 121 func (e *SnapshotEngine) serialise(k string) ([]byte, error) { 122 switch k { 123 case VestingKey: 124 return e.serialiseAll() 125 default: 126 return nil, types.ErrSnapshotKeyDoesNotExist 127 } 128 } 129 130 func (e *SnapshotEngine) serialiseAll() ([]byte, error) { 131 out := snapshotpb.Vesting{} 132 133 for party, rewardState := range e.state { 134 partyReward := &snapshotpb.PartyReward{ 135 Party: party, 136 } 137 138 for asset, balance := range rewardState.Vesting { 139 partyReward.InVesting = append(partyReward.InVesting, &snapshotpb.InVesting{ 140 Asset: asset, 141 Balance: balance.String(), 142 }) 143 } 144 145 sort.Slice(partyReward.InVesting, func(i, j int) bool { 146 return partyReward.InVesting[i].Asset < partyReward.InVesting[j].Asset 147 }) 148 149 for asset, epochBalances := range rewardState.Locked { 150 assetLocked := &snapshotpb.AssetLocked{ 151 Asset: asset, 152 } 153 154 for epoch, balance := range epochBalances { 155 assetLocked.EpochBalances = append(assetLocked.EpochBalances, &snapshotpb.EpochBalance{ 156 Epoch: epoch, 157 Balance: balance.String(), 158 }) 159 } 160 161 sort.Slice(assetLocked.EpochBalances, func(i, j int) bool { 162 return assetLocked.EpochBalances[i].Epoch < assetLocked.EpochBalances[j].Epoch 163 }) 164 165 partyReward.AssetLocked = append(partyReward.AssetLocked, assetLocked) 166 } 167 168 sort.Slice(partyReward.AssetLocked, func(i, j int) bool { 169 return partyReward.AssetLocked[i].Asset < partyReward.AssetLocked[j].Asset 170 }) 171 172 out.PartiesReward = append(out.PartiesReward, partyReward) 173 } 174 175 sort.Slice(out.PartiesReward, func(i, j int) bool { return out.PartiesReward[i].Party < out.PartiesReward[j].Party }) 176 177 payload := &snapshotpb.Payload{ 178 Data: &snapshotpb.Payload_Vesting{ 179 Vesting: &out, 180 }, 181 } 182 183 serialized, err := proto.Marshal(payload) 184 if err != nil { 185 return nil, fmt.Errorf("could not serialize team switches payload: %w", err) 186 } 187 188 return serialized, nil 189 }