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  }