code.vegaprotocol.io/vega@v0.79.0/core/pow/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 pow
    17  
    18  import (
    19  	"context"
    20  	"sort"
    21  
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    24  
    25  	"github.com/golang/protobuf/proto"
    26  )
    27  
    28  func (e *Engine) Namespace() types.SnapshotNamespace {
    29  	return types.PoWSnapshot
    30  }
    31  
    32  func (e *Engine) Keys() []string {
    33  	return e.hashKeys
    34  }
    35  
    36  func (e *Engine) Stopped() bool {
    37  	return false
    38  }
    39  
    40  // get the serialised form and hash of the given key.
    41  func (e *Engine) serialise() ([]byte, error) {
    42  	nonceHeights := map[uint64][]*snapshot.NonceRef{}
    43  
    44  	for k, v := range e.heightToNonceRef {
    45  		refs := make([]*snapshot.NonceRef, 0, len(v))
    46  		for _, ref := range v {
    47  			refs = append(refs, &snapshot.NonceRef{Party: ref.party, Nonce: ref.nonce})
    48  		}
    49  		nonceHeights[k] = refs
    50  	}
    51  
    52  	payloadProofOfWork := &types.PayloadProofOfWork{
    53  		BlockHeight:      e.blockHeight[:ringSize],
    54  		BlockHash:        e.blockHash[:ringSize],
    55  		HeightToTx:       e.heightToTx,
    56  		HeightToTid:      e.heightToTid,
    57  		HeightToNonceRef: nonceHeights,
    58  		ActiveParams:     e.paramsToSnapshotParams(),
    59  		ActiveStates:     e.statesToSnapshotStates(),
    60  		LastPruningBlock: e.lastPruningBlock,
    61  	}
    62  	payload := types.Payload{
    63  		Data: payloadProofOfWork,
    64  	}
    65  
    66  	data, err := proto.Marshal(payload.IntoProto())
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	return data, nil
    72  }
    73  
    74  func (e *Engine) GetState(k string) ([]byte, []types.StateProvider, error) {
    75  	state, err := e.serialise()
    76  	return state, nil, err
    77  }
    78  
    79  func (e *Engine) paramsToSnapshotParams() []*snapshot.ProofOfWorkParams {
    80  	params := make([]*snapshot.ProofOfWorkParams, 0, len(e.activeParams))
    81  	for _, p := range e.activeParams {
    82  		until := int64(-1)
    83  		if p.untilBlock != nil {
    84  			until = int64(*p.untilBlock)
    85  		}
    86  		params = append(params, &snapshot.ProofOfWorkParams{
    87  			SpamPowNumberOfPastBlocks:   p.spamPoWNumberOfPastBlocks,
    88  			SpamPowDifficulty:           uint32(p.spamPoWDifficulty),
    89  			SpamPowHashFunction:         p.spamPoWHashFunction,
    90  			SpamPowNumberOfTxPerBlock:   p.spamPoWNumberOfTxPerBlock,
    91  			SpamPowIncreasingDifficulty: p.spamPoWIncreasingDifficulty,
    92  			FromBlock:                   p.fromBlock,
    93  			UntilBlock:                  until,
    94  		})
    95  	}
    96  	return params
    97  }
    98  
    99  func (e *Engine) blocksState(state map[uint64]map[string]*partyStateForBlock) []*snapshot.ProofOfWorkBlockState {
   100  	states := make([]*snapshot.ProofOfWorkBlockState, 0, len(state))
   101  	for k, v := range state {
   102  		partyStates := make([]*snapshot.ProofOfWorkPartyStateForBlock, 0, len(v))
   103  		for party, psfb := range v {
   104  			partyStates = append(partyStates, &snapshot.ProofOfWorkPartyStateForBlock{
   105  				Party:              party,
   106  				ObservedDifficulty: uint64(psfb.observedDifficulty),
   107  				SeenCount:          uint64(psfb.seenCount),
   108  			})
   109  		}
   110  		sort.Slice(partyStates, func(i, j int) bool { return partyStates[i].Party < partyStates[j].Party })
   111  
   112  		states = append(states, &snapshot.ProofOfWorkBlockState{
   113  			BlockHeight: k,
   114  			PartyState:  partyStates,
   115  		})
   116  	}
   117  	sort.Slice(states, func(i, j int) bool { return states[i].BlockHeight < states[j].BlockHeight })
   118  	return states
   119  }
   120  
   121  func (e *Engine) statesToSnapshotStates() []*snapshot.ProofOfWorkState {
   122  	states := make([]*snapshot.ProofOfWorkState, 0, len(e.activeStates))
   123  	for _, s := range e.activeStates {
   124  		states = append(states, &snapshot.ProofOfWorkState{
   125  			PowState: e.blocksState(s.blockToPartyState),
   126  		})
   127  	}
   128  	return states
   129  }
   130  
   131  func (e *Engine) snapshotParamsToParams(activeParams []*snapshot.ProofOfWorkParams) []*params {
   132  	pars := make([]*params, 0, len(activeParams))
   133  	for _, p := range activeParams {
   134  		param := &params{
   135  			spamPoWNumberOfPastBlocks:   p.SpamPowNumberOfPastBlocks,
   136  			spamPoWDifficulty:           uint(p.SpamPowDifficulty),
   137  			spamPoWHashFunction:         p.SpamPowHashFunction,
   138  			spamPoWNumberOfTxPerBlock:   p.SpamPowNumberOfTxPerBlock,
   139  			spamPoWIncreasingDifficulty: p.SpamPowIncreasingDifficulty,
   140  			fromBlock:                   p.FromBlock,
   141  			untilBlock:                  nil,
   142  		}
   143  		if p.UntilBlock >= 0 {
   144  			param.untilBlock = new(uint64)
   145  			*param.untilBlock = uint64(p.UntilBlock)
   146  		}
   147  		pars = append(pars, param)
   148  	}
   149  	return pars
   150  }
   151  
   152  func (e *Engine) snapshotStatesToStates(activeStates []*snapshot.ProofOfWorkState) []*state {
   153  	states := make([]*state, 0, len(activeStates))
   154  	for _, s := range activeStates {
   155  		currentState := &state{}
   156  		currentState.blockToPartyState = make(map[uint64]map[string]*partyStateForBlock, len(s.PowState))
   157  		for _, powbs := range s.PowState {
   158  			currentState.blockToPartyState[powbs.BlockHeight] = make(map[string]*partyStateForBlock, len(powbs.PartyState))
   159  			for _, partyState := range powbs.PartyState {
   160  				currentState.blockToPartyState[powbs.BlockHeight][partyState.Party] = &partyStateForBlock{
   161  					observedDifficulty: uint(partyState.ObservedDifficulty),
   162  					seenCount:          uint(partyState.SeenCount),
   163  				}
   164  			}
   165  		}
   166  		states = append(states, currentState)
   167  	}
   168  	return states
   169  }
   170  
   171  func (e *Engine) LoadState(ctx context.Context, p *types.Payload) ([]types.StateProvider, error) {
   172  	if e.Namespace() != p.Data.Namespace() {
   173  		return nil, types.ErrInvalidSnapshotNamespace
   174  	}
   175  	pl := p.Data.(*types.PayloadProofOfWork)
   176  	copy(e.blockHash[:], pl.BlockHash[:ringSize])
   177  	copy(e.blockHeight[:], pl.BlockHeight[:ringSize])
   178  	e.heightToTx = pl.HeightToTx
   179  	e.heightToTid = pl.HeightToTid
   180  
   181  	for k, v := range pl.HeightToNonceRef {
   182  		refs := make([]nonceRef, 0, len(v))
   183  		for _, ref := range v {
   184  			refs = append(refs, nonceRef{ref.Party, ref.Nonce})
   185  		}
   186  		e.heightToNonceRef[k] = refs
   187  	}
   188  
   189  	e.seenTx = map[string]struct{}{}
   190  	e.seenTid = map[string]struct{}{}
   191  	for _, block := range e.heightToTid {
   192  		for _, v := range block {
   193  			e.seenTid[v] = struct{}{}
   194  		}
   195  	}
   196  	for _, block := range e.heightToTx {
   197  		for _, v := range block {
   198  			e.seenTx[v] = struct{}{}
   199  		}
   200  	}
   201  	for _, block := range e.heightToNonceRef {
   202  		for _, v := range block {
   203  			e.seenNonceRef[v] = struct{}{}
   204  		}
   205  	}
   206  	e.activeParams = e.snapshotParamsToParams(pl.ActiveParams)
   207  	e.activeStates = e.snapshotStatesToStates(pl.ActiveStates)
   208  	e.lastPruningBlock = pl.LastPruningBlock
   209  	return nil, nil
   210  }