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 }