code.vegaprotocol.io/vega@v0.79.0/core/assets/checkpoint.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 assets
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	vgcrypto "code.vegaprotocol.io/vega/libs/crypto"
    24  	"code.vegaprotocol.io/vega/libs/proto"
    25  	"code.vegaprotocol.io/vega/logging"
    26  	checkpoint "code.vegaprotocol.io/vega/protos/vega/checkpoint/v1"
    27  )
    28  
    29  func (*Service) Name() types.CheckpointName {
    30  	return types.AssetsCheckpoint
    31  }
    32  
    33  func (s *Service) Checkpoint() ([]byte, error) {
    34  	t := &checkpoint.Assets{
    35  		Assets:               s.getEnabled(),
    36  		PendingListingAssets: s.getPendingListed(),
    37  	}
    38  	return proto.Marshal(t)
    39  }
    40  
    41  func (s *Service) Load(ctx context.Context, cp []byte) error {
    42  	data := &checkpoint.Assets{}
    43  	if err := proto.Unmarshal(cp, data); err != nil {
    44  		return err
    45  	}
    46  	s.amu.Lock()
    47  	s.pamu.Lock()
    48  	s.pendingAssets = map[string]*Asset{}
    49  	s.pamu.Unlock()
    50  	s.amu.Unlock()
    51  	for _, a := range data.Assets {
    52  		details, _ := types.AssetDetailsFromProto(a.AssetDetails)
    53  		// first check if the asset did get loaded from genesis
    54  		// if yes and the details + IDs are same, then all good
    55  		if existing, ok := s.assets[a.Id]; ok {
    56  			// we know this ID, are the details the same
    57  			// if not, then  there's an error, and we should not overwrite an existing
    58  			// asset, only new ones can be added
    59  			if !bytes.Equal(vgcrypto.Hash([]byte(details.String())), vgcrypto.Hash([]byte(existing.Type().Details.String()))) {
    60  				s.log.Panic("invalid asset loaded from genesis",
    61  					logging.String("id", a.Id),
    62  					logging.String("details-genesis", existing.String()),
    63  					logging.String("details-checkpoint", details.String()))
    64  			}
    65  			continue
    66  		}
    67  
    68  		// asset didn't match anything, we need to go through the process to add it.
    69  		s.restoreAsset(ctx, a.Id, details)
    70  		if err := s.Enable(ctx, a.Id); err != nil {
    71  			return err
    72  		}
    73  	}
    74  
    75  	// now do pending assets
    76  	for _, pa := range data.PendingListingAssets {
    77  		details, _ := types.AssetDetailsFromProto(pa.AssetDetails)
    78  
    79  		// restore it as valid
    80  		s.restoreAsset(ctx, pa.Id, details)
    81  
    82  		// set as pending and generate the signatures to list on the contract
    83  		s.SetPendingListing(ctx, pa.Id)
    84  		s.EnactPendingAsset(pa.Id)
    85  	}
    86  
    87  	return nil
    88  }
    89  
    90  func (s *Service) restoreAsset(ctx context.Context, id string, details *types.AssetDetails) error {
    91  	id, err := s.NewAsset(ctx, id, details)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	pa, _ := s.Get(id)
    96  	if s.isValidator {
    97  		if err := s.validateAsset(pa); err != nil {
    98  			return err
    99  		}
   100  	}
   101  	// always valid now
   102  	pa.SetValid()
   103  	return nil
   104  }
   105  
   106  func (s *Service) getEnabled() []*checkpoint.AssetEntry {
   107  	aa := s.GetEnabledAssets()
   108  	if len(aa) == 0 {
   109  		return nil
   110  	}
   111  	ret := make([]*checkpoint.AssetEntry, 0, len(aa))
   112  	for _, a := range aa {
   113  		ret = append(ret, &checkpoint.AssetEntry{
   114  			Id:           a.ID,
   115  			AssetDetails: a.Details.IntoProto(),
   116  		})
   117  	}
   118  
   119  	return ret
   120  }
   121  
   122  func (s *Service) getPendingListed() []*checkpoint.AssetEntry {
   123  	pd := s.getPendingAssets()
   124  	if len(pd) == 0 {
   125  		return nil
   126  	}
   127  	ret := make([]*checkpoint.AssetEntry, 0, len(pd))
   128  	for _, a := range pd {
   129  		if a.Status != types.AssetStatusPendingListing {
   130  			// we only want enacted but not listed assets
   131  			continue
   132  		}
   133  		ret = append(ret, &checkpoint.AssetEntry{
   134  			Id:           a.ID,
   135  			AssetDetails: a.Details.IntoProto(),
   136  		})
   137  	}
   138  	return ret
   139  }