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 }