code.vegaprotocol.io/vega@v0.79.0/core/validators/topology.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  	"encoding/hex"
    21  	"errors"
    22  	"fmt"
    23  	"math"
    24  	"math/rand"
    25  	"sort"
    26  	"sync"
    27  	"time"
    28  
    29  	"code.vegaprotocol.io/vega/core/events"
    30  	"code.vegaprotocol.io/vega/core/types"
    31  	"code.vegaprotocol.io/vega/libs/crypto"
    32  	vgcrypto "code.vegaprotocol.io/vega/libs/crypto"
    33  	"code.vegaprotocol.io/vega/libs/num"
    34  	"code.vegaprotocol.io/vega/logging"
    35  	proto "code.vegaprotocol.io/vega/protos/vega"
    36  	commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1"
    37  	v1 "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    38  
    39  	abcitypes "github.com/cometbft/cometbft/abci/types"
    40  	"github.com/ethereum/go-ethereum/common"
    41  	"golang.org/x/exp/maps"
    42  )
    43  
    44  var (
    45  	ErrVegaNodeAlreadyRegisterForChain = errors.New("a vega node is already registered with the blockchain node")
    46  	ErrIssueSignaturesUnexpectedKind   = errors.New("unexpected node-signature kind")
    47  )
    48  
    49  // Broker needs no mocks.
    50  type Broker interface {
    51  	Send(event events.Event)
    52  	SendBatch(events []events.Event)
    53  }
    54  
    55  type Wallet interface {
    56  	PubKey() crypto.PublicKey
    57  	ID() crypto.PublicKey
    58  	Signer
    59  }
    60  
    61  type MultiSigTopology interface {
    62  	IsSigner(address string) bool
    63  	ExcessSigners(addresses []string) bool
    64  	GetSigners() []string
    65  	GetThreshold() uint32
    66  	ChainID() string
    67  }
    68  
    69  type ValidatorPerformance interface {
    70  	ValidatorPerformanceScore(address string, votingPower, totalPower int64, performanceScalingFactor num.Decimal) num.Decimal
    71  	BeginBlock(ctx context.Context, proposer string)
    72  	Serialize() *v1.ValidatorPerformance
    73  	Deserialize(*v1.ValidatorPerformance)
    74  	Reset()
    75  }
    76  
    77  // Notary ...
    78  type Notary interface {
    79  	StartAggregate(resID string, kind types.NodeSignatureKind, signature []byte)
    80  	IsSigned(ctx context.Context, id string, kind types.NodeSignatureKind) ([]types.NodeSignature, bool)
    81  	OfferSignatures(kind types.NodeSignatureKind, f func(resources string) []byte)
    82  }
    83  
    84  type ValidatorData struct {
    85  	ID               string `json:"id"`
    86  	VegaPubKey       string `json:"vega_pub_key"`
    87  	VegaPubKeyIndex  uint32 `json:"vega_pub_key_index"`
    88  	EthereumAddress  string `json:"ethereum_address"`
    89  	TmPubKey         string `json:"tm_pub_key"`
    90  	InfoURL          string `json:"info_url"`
    91  	Country          string `json:"country"`
    92  	Name             string `json:"name"`
    93  	AvatarURL        string `json:"avatar_url"`
    94  	FromEpoch        uint64 `json:"from_epoch"`
    95  	SubmitterAddress string `json:"submitter_address"`
    96  }
    97  
    98  func (v ValidatorData) IsValid() bool {
    99  	if len(v.ID) <= 0 || len(v.VegaPubKey) <= 0 ||
   100  		len(v.EthereumAddress) <= 0 || len(v.TmPubKey) <= 0 {
   101  		return false
   102  	}
   103  	return true
   104  }
   105  
   106  // HashVegaPubKey returns hash VegaPubKey encoded as hex string.
   107  func (v ValidatorData) HashVegaPubKey() (string, error) {
   108  	decoded, err := hex.DecodeString(v.VegaPubKey)
   109  	if err != nil {
   110  		return "", fmt.Errorf("couldn't decode public key: %w", err)
   111  	}
   112  
   113  	return hex.EncodeToString(vgcrypto.Hash(decoded)), nil
   114  }
   115  
   116  // ValidatorMapping maps a tendermint pubkey with a vega pubkey.
   117  type ValidatorMapping map[string]ValidatorData
   118  
   119  type validators map[string]*valState
   120  
   121  type Topology struct {
   122  	log                  *logging.Logger
   123  	cfg                  Config
   124  	wallets              NodeWallets
   125  	broker               Broker
   126  	timeService          TimeService
   127  	validatorPerformance ValidatorPerformance
   128  	primaryMultisig      MultiSigTopology
   129  	secondaryMultisig    MultiSigTopology
   130  
   131  	// vega pubkey to validator data
   132  	validators validators
   133  
   134  	chainValidators []string
   135  
   136  	// this is the runtime information
   137  	// has the validator been added to the validator set
   138  	isValidator bool
   139  
   140  	// this is about the node setup,
   141  	// is the node configured to be a validator
   142  	isValidatorSetup bool
   143  
   144  	// Vega key rotations
   145  	pendingPubKeyRotations pendingKeyRotationMapping
   146  	pubKeyChangeListeners  []func(ctx context.Context, oldPubKey, newPubKey string)
   147  
   148  	// Ethereum key rotations
   149  	// pending are those lined up to happen in a future block, unresolved are ones
   150  	// that have happened but we are waiting to see the old key has been removed from the contract
   151  	pendingEthKeyRotations    pendingEthereumKeyRotationMapping
   152  	unresolvedEthKeyRotations map[string]PendingEthereumKeyRotation
   153  
   154  	mu sync.RWMutex
   155  
   156  	tss *topologySnapshotState
   157  
   158  	rng                *rand.Rand // random generator seeded by block
   159  	currentBlockHeight uint64
   160  
   161  	// net params
   162  	numberOfTendermintValidators         int
   163  	numberOfErsatzValidators             int
   164  	validatorIncumbentBonusFactor        num.Decimal
   165  	ersatzValidatorsFactor               num.Decimal
   166  	minimumStake                         *num.Uint
   167  	minimumEthereumEventsForNewValidator uint64
   168  	numberEthMultisigSigners             int
   169  
   170  	// transient data for updating tendermint on validator voting power changes.
   171  	validatorPowerUpdates []abcitypes.ValidatorUpdate
   172  	epochSeq              uint64
   173  	newEpochStarted       bool
   174  
   175  	cmd              Commander
   176  	checkpointLoaded bool
   177  	notary           Notary
   178  	signatures       Signatures
   179  
   180  	// validator heartbeat parameters
   181  	blocksToKeepMalperforming int64
   182  	timeBetweenHeartbeats     time.Duration
   183  	timeToSendHeartbeat       time.Duration
   184  
   185  	performanceScalingFactor num.Decimal
   186  }
   187  
   188  func (t *Topology) OnEpochEvent(ctx context.Context, epoch types.Epoch) {
   189  	t.epochSeq = epoch.Seq
   190  	if epoch.Action == proto.EpochAction_EPOCH_ACTION_START {
   191  		t.newEpochStarted = true
   192  		// this is needed because when we load a checkpoint on genesis t.rng is not initialised as it's done before calling beginBlock
   193  		// so we need to initialise the rng to something.
   194  		if t.rng == nil {
   195  			t.rng = rand.New(rand.NewSource(epoch.StartTime.Unix()))
   196  		}
   197  	}
   198  	// this is a workaround to the topology loaded from checkpoint before the epoch.
   199  	if t.checkpointLoaded {
   200  		evts := make([]events.Event, 0, len(t.validators))
   201  		seq := num.NewUint(t.epochSeq).String()
   202  		t.checkpointLoaded = false
   203  		nodeIDs := make([]string, 0, len(t.validators))
   204  		for k := range t.validators {
   205  			nodeIDs = append(nodeIDs, k)
   206  		}
   207  		sort.Strings(nodeIDs)
   208  		for _, nid := range nodeIDs {
   209  			node := t.validators[nid]
   210  			if node.rankingScore == nil {
   211  				continue
   212  			}
   213  			evts = append(evts, events.NewValidatorRanking(ctx, seq, node.data.ID, node.rankingScore.StakeScore, node.rankingScore.PerformanceScore, node.rankingScore.RankingScore, protoStatusToString(node.rankingScore.PreviousStatus), protoStatusToString(node.rankingScore.Status), int(node.rankingScore.VotingPower)))
   214  		}
   215  		// send ranking events for all loaded validators so data node knows the current ranking
   216  		t.broker.SendBatch(evts)
   217  	}
   218  }
   219  
   220  func NewTopology(
   221  	log *logging.Logger,
   222  	cfg Config,
   223  	wallets NodeWallets,
   224  	broker Broker,
   225  	isValidatorSetup bool,
   226  	cmd Commander,
   227  	primaryMultisig MultiSigTopology,
   228  	secondaryMultisig MultiSigTopology,
   229  	timeService TimeService,
   230  ) *Topology {
   231  	log = log.Named(namedLogger)
   232  	log.SetLevel(cfg.Level.Get())
   233  
   234  	t := &Topology{
   235  		log:                           log,
   236  		cfg:                           cfg,
   237  		wallets:                       wallets,
   238  		broker:                        broker,
   239  		timeService:                   timeService,
   240  		validators:                    map[string]*valState{},
   241  		chainValidators:               []string{},
   242  		tss:                           &topologySnapshotState{},
   243  		pendingPubKeyRotations:        pendingKeyRotationMapping{},
   244  		pendingEthKeyRotations:        pendingEthereumKeyRotationMapping{},
   245  		unresolvedEthKeyRotations:     map[string]PendingEthereumKeyRotation{},
   246  		isValidatorSetup:              isValidatorSetup,
   247  		validatorPerformance:          NewValidatorPerformance(log),
   248  		validatorIncumbentBonusFactor: num.DecimalZero(),
   249  		ersatzValidatorsFactor:        num.DecimalZero(),
   250  		primaryMultisig:               primaryMultisig,
   251  		secondaryMultisig:             secondaryMultisig,
   252  		cmd:                           cmd,
   253  		signatures:                    &noopSignatures{log},
   254  	}
   255  
   256  	return t
   257  }
   258  
   259  // OnEpochLengthUpdate updates the duration of an epoch - which is used to calculate the number of blocks to keep a malperforming validators.
   260  // The number of blocks is calculated as 10 epochs x duration of epoch in seconds, assuming block time is 1s.
   261  func (t *Topology) OnEpochLengthUpdate(ctx context.Context, l time.Duration) error {
   262  	t.blocksToKeepMalperforming = int64(10 * l.Seconds())
   263  	// set time between hearbeats to 1% of the epoch duration in seconds as blocks
   264  	// e.g. if epoch is 1 day = 86400 seconds (blocks) then time between hb becomes 864
   265  	// if epoch is 300 seconds then blocks becomes 50 (lower bound applied).
   266  	blocks := int64(math.Max(l.Seconds()*0.01, 50.0))
   267  	t.timeBetweenHeartbeats = time.Duration(blocks * int64(time.Second))
   268  	t.timeToSendHeartbeat = time.Duration(blocks * int64(time.Second) / 2)
   269  	return nil
   270  }
   271  
   272  // SetNotary this is not good, the topology depends on the notary
   273  // which in return also depends on the topology... Luckily they
   274  // do not require recursive calls as for each calls are one offs...
   275  // anyway we may want to extract the code requiring the notary somewhere
   276  // else or have different pattern somehow...
   277  func (t *Topology) SetNotary(notary Notary) {
   278  	t.signatures = NewSignatures(t.log, t.primaryMultisig, t.secondaryMultisig, notary, t.wallets, t.broker, t.isValidatorSetup)
   279  	t.notary = notary
   280  }
   281  
   282  // SetSignatures this is not good, same issue as for SetNotary method.
   283  // This is only used as a helper for testing..
   284  func (t *Topology) SetSignatures(signatures Signatures) {
   285  	t.signatures = signatures
   286  }
   287  
   288  // SetIsValidator will set the flag for `self` so that it is considered a real validator
   289  // for example, when a node has announced itself and is accepted as a PENDING validator.
   290  func (t *Topology) SetIsValidator() {
   291  	t.isValidator = true
   292  }
   293  
   294  // ReloadConf updates the internal configuration.
   295  func (t *Topology) ReloadConf(cfg Config) {
   296  	t.log.Info("reloading configuration")
   297  	if t.log.GetLevel() != cfg.Level.Get() {
   298  		t.log.Info("updating log level",
   299  			logging.String("old", t.log.GetLevel().String()),
   300  			logging.String("new", cfg.Level.String()),
   301  		)
   302  		t.log.SetLevel(cfg.Level.Get())
   303  	}
   304  
   305  	t.cfg = cfg
   306  }
   307  
   308  func (t *Topology) IsValidator() bool {
   309  	return t.isValidatorSetup && t.isValidator
   310  }
   311  
   312  // Len return the number of validators with status Tendermint, the only validators that matter.
   313  func (t *Topology) Len() int {
   314  	t.mu.RLock()
   315  	defer t.mu.RUnlock()
   316  
   317  	count := 0
   318  	for _, v := range t.validators {
   319  		if v.status == ValidatorStatusTendermint {
   320  			count++
   321  		}
   322  	}
   323  	return count
   324  }
   325  
   326  // Get returns validator data based on validator master public key.
   327  func (t *Topology) Get(key string) *ValidatorData {
   328  	t.mu.RLock()
   329  	defer t.mu.RUnlock()
   330  
   331  	if data, ok := t.validators[key]; ok {
   332  		return &data.data
   333  	}
   334  
   335  	return nil
   336  }
   337  
   338  // AllVegaPubKeys returns all the validators vega public keys.
   339  func (t *Topology) AllVegaPubKeys() []string {
   340  	t.mu.RLock()
   341  	defer t.mu.RUnlock()
   342  	keys := make([]string, 0, len(t.validators))
   343  	for _, data := range t.validators {
   344  		keys = append(keys, data.data.VegaPubKey)
   345  	}
   346  	return keys
   347  }
   348  
   349  // AllNodeIDs returns all the validators node IDs keys.
   350  func (t *Topology) AllNodeIDs() []string {
   351  	t.mu.RLock()
   352  	defer t.mu.RUnlock()
   353  	keys := make([]string, 0, len(t.validators))
   354  	for k := range t.validators {
   355  		keys = append(keys, k)
   356  	}
   357  	return keys
   358  }
   359  
   360  func (t *Topology) SelfVegaPubKey() string {
   361  	if !t.isValidatorSetup {
   362  		return ""
   363  	}
   364  	return t.wallets.GetVega().PubKey().Hex()
   365  }
   366  
   367  func (t *Topology) SelfNodeID() string {
   368  	if !t.isValidatorSetup {
   369  		return ""
   370  	}
   371  	return t.wallets.GetVega().ID().Hex()
   372  }
   373  
   374  // IsValidatorNodeID takes a nodeID and returns true if the node is a validator node.
   375  func (t *Topology) IsValidatorNodeID(nodeID string) bool {
   376  	t.mu.RLock()
   377  	defer t.mu.RUnlock()
   378  	_, ok := t.validators[nodeID]
   379  	return ok
   380  }
   381  
   382  // IsValidatorVegaPubKey returns true if the given key is a Vega validator public key.
   383  func (t *Topology) IsValidatorVegaPubKey(pubkey string) (ok bool) {
   384  	defer func() {
   385  		if t.log.GetLevel() <= logging.DebugLevel {
   386  			s := "requested non-existing validator"
   387  			if ok {
   388  				s = "requested existing validator"
   389  			}
   390  			t.log.Debug(s,
   391  				logging.Strings("validators", t.AllVegaPubKeys()),
   392  				logging.String("pubkey", pubkey),
   393  			)
   394  		}
   395  	}()
   396  
   397  	t.mu.RLock()
   398  	defer t.mu.RUnlock()
   399  
   400  	for _, data := range t.validators {
   401  		if data.data.VegaPubKey == pubkey {
   402  			return true
   403  		}
   404  	}
   405  
   406  	return false
   407  }
   408  
   409  func (t *Topology) IsSelfTendermintValidator() bool {
   410  	return t.IsTendermintValidator(t.SelfVegaPubKey())
   411  }
   412  
   413  func (t *Topology) GetTotalVotingPower() int64 {
   414  	t.mu.RLock()
   415  	defer t.mu.RUnlock()
   416  	total := int64(0)
   417  	for _, data := range t.validators {
   418  		total += data.validatorPower
   419  	}
   420  	return total
   421  }
   422  
   423  func (t *Topology) GetVotingPower(pubkey string) int64 {
   424  	t.mu.RLock()
   425  	defer t.mu.RUnlock()
   426  	for _, data := range t.validators {
   427  		if data.data.VegaPubKey == pubkey && data.status == ValidatorStatusTendermint {
   428  			return data.validatorPower
   429  		}
   430  	}
   431  
   432  	return int64(0)
   433  }
   434  
   435  // IsValidatorVegaPubKey returns true if the given key is a Vega validator public key and the validators is of status Tendermint.
   436  func (t *Topology) IsTendermintValidator(pubkey string) (ok bool) {
   437  	t.mu.RLock()
   438  	defer t.mu.RUnlock()
   439  
   440  	for _, data := range t.validators {
   441  		if data.data.VegaPubKey == pubkey && data.status == ValidatorStatusTendermint {
   442  			return true
   443  		}
   444  	}
   445  
   446  	return false
   447  }
   448  
   449  func (t *Topology) NumberOfTendermintValidators() uint {
   450  	t.mu.RLock()
   451  	defer t.mu.RUnlock()
   452  
   453  	count := uint(0)
   454  	for _, data := range t.validators {
   455  		if data.status == ValidatorStatusTendermint {
   456  			count++
   457  		}
   458  	}
   459  	return count
   460  }
   461  
   462  func (t *Topology) BeginBlock(ctx context.Context, blockHeight uint64, proposer string) {
   463  	// we're not adding or removing nodes only potentially changing their state so should be safe
   464  	t.mu.RLock()
   465  	defer t.mu.RUnlock()
   466  
   467  	// resetting the seed every block, to both get some more unpredictability and still deterministic
   468  	// and play nicely with snapshot
   469  	currentTime := t.timeService.GetTimeNow()
   470  	t.rng = rand.New(rand.NewSource(currentTime.Unix()))
   471  
   472  	t.checkHeartbeat(ctx)
   473  	t.validatorPerformance.BeginBlock(ctx, proposer)
   474  	t.currentBlockHeight = blockHeight
   475  
   476  	t.signatures.SetNonce(currentTime)
   477  	t.signatures.ClearStaleSignatures()
   478  	t.signatures.OfferSignatures()
   479  	t.keyRotationBeginBlockLocked(ctx)
   480  	t.ethereumKeyRotationBeginBlockLocked(ctx)
   481  }
   482  
   483  // OnPerformanceScalingChanged updates the network parameter for performance scaling factor.
   484  func (t *Topology) OnPerformanceScalingChanged(ctx context.Context, scalingFactor num.Decimal) error {
   485  	t.performanceScalingFactor = scalingFactor
   486  	return nil
   487  }
   488  
   489  func (t *Topology) AddNewNode(ctx context.Context, nr *commandspb.AnnounceNode, status ValidatorStatus) error {
   490  	// write lock!
   491  	t.mu.Lock()
   492  	defer t.mu.Unlock()
   493  
   494  	if _, ok := t.validators[nr.Id]; ok {
   495  		return ErrVegaNodeAlreadyRegisterForChain
   496  	}
   497  
   498  	data := ValidatorData{
   499  		ID:               nr.Id,
   500  		VegaPubKey:       nr.VegaPubKey,
   501  		VegaPubKeyIndex:  nr.VegaPubKeyIndex,
   502  		EthereumAddress:  nr.EthereumAddress,
   503  		TmPubKey:         nr.ChainPubKey,
   504  		InfoURL:          nr.InfoUrl,
   505  		Country:          nr.Country,
   506  		Name:             nr.Name,
   507  		AvatarURL:        nr.AvatarUrl,
   508  		FromEpoch:        nr.FromEpoch,
   509  		SubmitterAddress: nr.SubmitterAddress,
   510  	}
   511  
   512  	// then add it to the topology
   513  	t.validators[nr.Id] = &valState{
   514  		data:                            data,
   515  		status:                          status,
   516  		blockAdded:                      int64(t.currentBlockHeight),
   517  		statusChangeBlock:               int64(t.currentBlockHeight),
   518  		lastBlockWithPositiveRanking:    -1,
   519  		numberOfEthereumEventsForwarded: 0,
   520  		heartbeatTracker:                &validatorHeartbeatTracker{},
   521  	}
   522  
   523  	if status == ValidatorStatusTendermint {
   524  		t.validators[nr.Id].validatorPower = 10
   525  	}
   526  
   527  	rankingScoreStatus := statusToProtoStatus(ValidatorStatusToName[status])
   528  	t.validators[nr.Id].rankingScore = &proto.RankingScore{
   529  		StakeScore:       "0",
   530  		PerformanceScore: "0",
   531  		RankingScore:     "0",
   532  		Status:           rankingScoreStatus,
   533  		PreviousStatus:   statusToProtoStatus("pending"),
   534  		VotingPower:      uint32(t.validators[nr.Id].validatorPower),
   535  	}
   536  
   537  	// Send event to notify core about new validator
   538  	t.sendValidatorUpdateEvent(ctx, data, true)
   539  	// Send an event to notify the new validator ranking
   540  	epochSeq := num.NewUint(t.epochSeq).String()
   541  	t.broker.Send(events.NewValidatorRanking(ctx, epochSeq, nr.Id, "0", "0", "0", "pending", ValidatorStatusToName[status], int(t.validators[nr.Id].validatorPower)))
   542  	t.log.Info("new node registration successful",
   543  		logging.String("id", nr.Id),
   544  		logging.String("vega-key", nr.VegaPubKey),
   545  		logging.String("eth-addr", nr.EthereumAddress),
   546  		logging.String("tm-key", nr.ChainPubKey))
   547  	return nil
   548  }
   549  
   550  func (t *Topology) sendValidatorUpdateEvent(ctx context.Context, data ValidatorData, added bool) {
   551  	t.broker.Send(events.NewValidatorUpdateEvent(
   552  		ctx,
   553  		data.ID,
   554  		data.VegaPubKey,
   555  		data.VegaPubKeyIndex,
   556  		data.EthereumAddress,
   557  		data.TmPubKey,
   558  		data.InfoURL,
   559  		data.Country,
   560  		data.Name,
   561  		data.AvatarURL,
   562  		data.FromEpoch,
   563  		added,
   564  		t.epochSeq,
   565  	))
   566  }
   567  
   568  func (t *Topology) LoadValidatorsOnGenesis(ctx context.Context, rawstate []byte) (err error) {
   569  	t.log.Debug("Entering validators.Topology.LoadValidatorsOnGenesis")
   570  	defer func() {
   571  		t.log.Debug("Leaving validators.Topology.LoadValidatorsOnGenesis without error")
   572  		if err != nil {
   573  			t.log.Debug("Failure in validators.Topology.LoadValidatorsOnGenesis", logging.Error(err))
   574  		}
   575  	}()
   576  
   577  	state, err := LoadGenesisState(rawstate)
   578  	if err != nil {
   579  		return err
   580  	}
   581  
   582  	// tm is base64 encoded, vega is hex
   583  	keys := maps.Keys(state)
   584  	sort.Strings(keys)
   585  	for _, tm := range keys {
   586  		data := state[tm]
   587  		if !data.IsValid() {
   588  			return fmt.Errorf("missing required field from validator data: %#v", data)
   589  		}
   590  
   591  		// this node is started and expect to be a validator
   592  		// but so far we haven't seen ourselves as validators for
   593  		// this network.
   594  		if t.isValidatorSetup && !t.isValidator {
   595  			t.checkValidatorDataWithSelfWallets(data)
   596  		}
   597  
   598  		nr := &commandspb.AnnounceNode{
   599  			Id:              data.ID,
   600  			VegaPubKey:      data.VegaPubKey,
   601  			VegaPubKeyIndex: data.VegaPubKeyIndex,
   602  			EthereumAddress: data.EthereumAddress,
   603  			ChainPubKey:     tm,
   604  			InfoUrl:         data.InfoURL,
   605  			Country:         data.Country,
   606  			Name:            data.Name,
   607  			AvatarUrl:       data.AvatarURL,
   608  		}
   609  		if err := t.AddNewNode(ctx, nr, ValidatorStatusTendermint); err != nil {
   610  			return err
   611  		}
   612  	}
   613  
   614  	return nil
   615  }
   616  
   617  // checkValidatorDataWithSelfWallets in the genesis file, validators data
   618  // are a mapping of a tendermint pubkey to validator info.
   619  // in here we are going to check if:
   620  // - the tm pubkey is the same as the one stored in the nodewallet
   621  //   - if no we return straight away and consider ourself as non validator
   622  //   - if yes then we do the following checks
   623  //
   624  // - check that all pubkeys / addresses matches what's in the node wallet
   625  //   - if they all match, we are a validator!
   626  //   - if they don't, we panic, that's a missconfiguration from the checkValidatorDataWithSelfWallets, ever the genesis or the node is misconfigured
   627  func (t *Topology) checkValidatorDataWithSelfWallets(data ValidatorData) {
   628  	if data.TmPubKey != t.wallets.GetTendermintPubkey() {
   629  		return
   630  	}
   631  
   632  	// if any of these are wrong, the nodewallet didn't import
   633  	// the keys set in the genesis block
   634  	hasError := t.wallets.GetVega().ID().Hex() != data.ID ||
   635  		t.wallets.GetVega().PubKey().Hex() != data.VegaPubKey ||
   636  		common.HexToAddress(t.wallets.GetEthereumAddress()) != common.HexToAddress(data.EthereumAddress)
   637  
   638  	if hasError {
   639  		t.log.Panic("invalid node wallet configurations, the genesis validator mapping differ to the wallets imported by the nodewallet",
   640  			logging.String("genesis-tendermint-pubkey", data.TmPubKey),
   641  			logging.String("nodewallet-tendermint-pubkey", t.wallets.GetTendermintPubkey()),
   642  			logging.String("genesis-vega-pubkey", data.VegaPubKey),
   643  			logging.String("nodewallet-vega-pubkey", t.wallets.GetVega().PubKey().Hex()),
   644  			logging.String("genesis-vega-id", data.ID),
   645  			logging.String("nodewallet-vega-id", t.wallets.GetVega().ID().Hex()),
   646  			logging.String("genesis-ethereum-address", data.EthereumAddress),
   647  			logging.String("nodewallet-ethereum-address", t.wallets.GetEthereumAddress()),
   648  		)
   649  	}
   650  
   651  	t.isValidator = true
   652  }
   653  
   654  func (t *Topology) IssueSignatures(ctx context.Context, submitter, nodeID, chainID string, kind types.NodeSignatureKind) error {
   655  	t.log.Debug("received IssueSignatures txn", logging.String("submitter", submitter), logging.String("nodeID", nodeID))
   656  	currentTime := t.timeService.GetTimeNow()
   657  	switch kind {
   658  	case types.NodeSignatureKindERC20MultiSigSignerAdded:
   659  		return t.signatures.EmitValidatorAddedSignatures(ctx, submitter, nodeID, chainID, currentTime)
   660  	case types.NodeSignatureKindERC20MultiSigSignerRemoved:
   661  		return t.signatures.EmitValidatorRemovedSignatures(ctx, submitter, nodeID, chainID, currentTime)
   662  	default:
   663  		return ErrIssueSignaturesUnexpectedKind
   664  	}
   665  }