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  }