code.vegaprotocol.io/vega@v0.79.0/core/parties/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 parties 17 18 import ( 19 "context" 20 "fmt" 21 "strings" 22 23 "code.vegaprotocol.io/vega/core/types" 24 "code.vegaprotocol.io/vega/libs/proto" 25 vegapb "code.vegaprotocol.io/vega/protos/vega" 26 snapshotpb "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" 27 28 "golang.org/x/exp/slices" 29 ) 30 31 type SnapshottedEngine struct { 32 *Engine 33 34 pl types.Payload 35 36 stopped bool 37 38 hashKeys []string 39 partiesKey string 40 } 41 42 func (e *SnapshottedEngine) Namespace() types.SnapshotNamespace { 43 return types.PartiesSnapshot 44 } 45 46 func (e *SnapshottedEngine) Keys() []string { 47 return e.hashKeys 48 } 49 50 func (e *SnapshottedEngine) GetState(k string) ([]byte, []types.StateProvider, error) { 51 state, err := e.serialise(k) 52 return state, nil, err 53 } 54 55 func (e *SnapshottedEngine) LoadState(_ context.Context, p *types.Payload) ([]types.StateProvider, error) { 56 if e.Namespace() != p.Data.Namespace() { 57 return nil, types.ErrInvalidSnapshotNamespace 58 } 59 60 switch data := p.Data.(type) { 61 case *types.PayloadParties: 62 e.Engine.loadPartiesFromSnapshot(data) 63 return nil, nil 64 default: 65 return nil, types.ErrUnknownSnapshotType 66 } 67 } 68 69 func (e *SnapshottedEngine) Stopped() bool { 70 return e.stopped 71 } 72 73 func (e *SnapshottedEngine) StopSnapshots() { 74 e.stopped = true 75 } 76 77 func (e *SnapshottedEngine) serialise(k string) ([]byte, error) { 78 if e.stopped { 79 return nil, nil 80 } 81 82 switch k { 83 case e.partiesKey: 84 return e.serialiseParties() 85 default: 86 return nil, types.ErrSnapshotKeyDoesNotExist 87 } 88 } 89 90 func (e *SnapshottedEngine) serialiseParties() ([]byte, error) { 91 profiles := e.Engine.profiles 92 profilesSnapshot := make([]*snapshotpb.PartyProfile, 0, len(profiles)) 93 for _, profile := range profiles { 94 profileSnapshot := &snapshotpb.PartyProfile{ 95 PartyId: profile.PartyID.String(), 96 Alias: profile.Alias, 97 } 98 for k, v := range profile.Metadata { 99 profileSnapshot.Metadata = append(profileSnapshot.Metadata, &vegapb.Metadata{ 100 Key: k, 101 Value: v, 102 }) 103 } 104 105 // Ensure deterministic order among the metadata. 106 slices.SortStableFunc(profileSnapshot.Metadata, func(a, b *vegapb.Metadata) int { 107 return strings.Compare(a.Key, b.Key) 108 }) 109 110 for k := range profile.DerivedKeys { 111 profileSnapshot.DerivedKeys = append(profileSnapshot.DerivedKeys, k) 112 } 113 114 // Ensure deterministic order among the derived keys. 115 slices.Sort(profileSnapshot.DerivedKeys) 116 117 profilesSnapshot = append(profilesSnapshot, profileSnapshot) 118 } 119 120 // Ensure deterministic order among the parties. 121 slices.SortStableFunc(profilesSnapshot, func(a, b *snapshotpb.PartyProfile) int { 122 return strings.Compare(a.PartyId, b.PartyId) 123 }) 124 125 payload := &snapshotpb.Payload{ 126 Data: &snapshotpb.Payload_Parties{ 127 Parties: &snapshotpb.Parties{ 128 Profiles: profilesSnapshot, 129 }, 130 }, 131 } 132 133 serialisedProfiles, err := proto.Marshal(payload) 134 if err != nil { 135 return nil, fmt.Errorf("could not serialize parties payload: %w", err) 136 } 137 138 return serialisedProfiles, nil 139 } 140 141 func (e *SnapshottedEngine) buildHashKeys() { 142 e.partiesKey = (&types.PayloadParties{}).Key() 143 144 e.hashKeys = append([]string{}, e.partiesKey) 145 } 146 147 func NewSnapshottedEngine(broker Broker) *SnapshottedEngine { 148 se := &SnapshottedEngine{ 149 Engine: NewEngine(broker), 150 pl: types.Payload{}, 151 stopped: false, 152 } 153 154 se.buildHashKeys() 155 156 return se 157 }