code.vegaprotocol.io/vega@v0.79.0/core/validators/witness_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 validators
    17  
    18  import (
    19  	"context"
    20  	"errors"
    21  	"sort"
    22  	"sync"
    23  
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	"code.vegaprotocol.io/vega/libs/proto"
    26  	"code.vegaprotocol.io/vega/logging"
    27  )
    28  
    29  var (
    30  	key = (&types.PayloadWitness{}).Key()
    31  
    32  	hashKeys = []string{
    33  		key,
    34  	}
    35  
    36  	ErrSnapshotKeyDoesNotExist = errors.New("unknown key for witness snapshot")
    37  )
    38  
    39  type witnessSnapshotState struct {
    40  	serialised []byte
    41  	mu         sync.Mutex
    42  }
    43  
    44  func (w *Witness) Namespace() types.SnapshotNamespace {
    45  	return types.WitnessSnapshot
    46  }
    47  
    48  func (w *Witness) Keys() []string {
    49  	return hashKeys
    50  }
    51  
    52  func (w *Witness) serialiseWitness() ([]byte, error) {
    53  	w.log.Debug("serialising witness resources", logging.Int("n", len(w.resources)))
    54  	resources := make([]*types.Resource, 0, len(w.resources))
    55  	for id, r := range w.resources {
    56  		r.mu.Lock()
    57  		votes := make([]string, 0, len(r.votes))
    58  		for v := range r.votes {
    59  			votes = append(votes, v)
    60  		}
    61  		sort.Strings(votes)
    62  		resources = append(resources, &types.Resource{
    63  			ID:         id,
    64  			CheckUntil: r.checkUntil,
    65  			Votes:      votes,
    66  		})
    67  		r.mu.Unlock()
    68  	}
    69  
    70  	// sort the resources
    71  	sort.SliceStable(resources, func(i, j int) bool { return resources[i].ID < resources[j].ID })
    72  
    73  	payload := types.Payload{
    74  		Data: &types.PayloadWitness{
    75  			Witness: &types.Witness{
    76  				Resources: resources,
    77  			},
    78  		},
    79  	}
    80  	x := payload.IntoProto()
    81  	return proto.Marshal(x)
    82  }
    83  
    84  // get the serialised form of the given key.
    85  func (w *Witness) serialise(k string) ([]byte, error) {
    86  	if k != key {
    87  		return nil, ErrSnapshotKeyDoesNotExist
    88  	}
    89  
    90  	w.wss.mu.Lock()
    91  	defer w.wss.mu.Unlock()
    92  	data, err := w.serialiseWitness()
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	w.wss.serialised = data
    98  	return data, nil
    99  }
   100  
   101  func (w *Witness) Stopped() bool { return false }
   102  
   103  func (w *Witness) GetState(k string) ([]byte, []types.StateProvider, error) {
   104  	state, err := w.serialise(k)
   105  	return state, nil, err
   106  }
   107  
   108  func (w *Witness) LoadState(_ context.Context, p *types.Payload) ([]types.StateProvider, error) {
   109  	if w.Namespace() != p.Data.Namespace() {
   110  		return nil, types.ErrInvalidSnapshotNamespace
   111  	}
   112  	// see what we're reloading
   113  	switch pl := p.Data.(type) {
   114  	case *types.PayloadWitness:
   115  		return nil, w.restore(pl.Witness, p)
   116  	default:
   117  		return nil, types.ErrUnknownSnapshotType
   118  	}
   119  }
   120  
   121  func (w *Witness) restore(witness *types.Witness, p *types.Payload) error {
   122  	w.resources = map[string]*res{}
   123  	w.needResendRes = map[string]struct{}{}
   124  
   125  	w.log.Debug("restoring witness resources", logging.Int("n", len(witness.Resources)))
   126  	for _, r := range witness.Resources {
   127  		w.resources[r.ID] = &res{
   128  			checkUntil: r.CheckUntil,
   129  			votes:      map[string]struct{}{},
   130  		}
   131  		selfVoted := false
   132  		for _, v := range r.Votes {
   133  			w.resources[r.ID].votes[v] = struct{}{}
   134  			if v == w.top.SelfVegaPubKey() {
   135  				selfVoted = true
   136  			}
   137  		}
   138  
   139  		// if not a validator or we've seen a self vote set the state to vote sent
   140  		// otherwise we stay in validated state
   141  		state := notValidated
   142  		if !w.top.IsValidator() || selfVoted {
   143  			state = voteSent
   144  		}
   145  
   146  		w.resources[r.ID].state.Store(state)
   147  	}
   148  
   149  	w.wss.mu.Lock()
   150  	var err error
   151  	w.wss.serialised, err = proto.Marshal(p.IntoProto())
   152  	w.wss.mu.Unlock()
   153  	return err
   154  }
   155  
   156  func (w *Witness) RestoreResource(r Resource, cb func(interface{}, bool)) error {
   157  	w.log.Info("finalising restored resource", logging.String("id", r.GetID()))
   158  	if _, ok := w.resources[r.GetID()]; !ok {
   159  		return ErrInvalidResourceIDForNodeVote
   160  	}
   161  
   162  	res := w.resources[r.GetID()]
   163  	res.cb = cb
   164  	res.res = r
   165  	ctx, cfunc := context.WithDeadline(context.Background(), res.checkUntil)
   166  	res.cfunc = cfunc
   167  	if w.top.IsValidator() && res.state.Load() != voteSent {
   168  		// no initial delay
   169  		go w.start(ctx, res, nil)
   170  	}
   171  	return nil
   172  }