github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/validator/default.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package validator
    18  
    19  import (
    20  	"math"
    21  	"reflect"
    22  	"sync"
    23  
    24  	"github.com/electroneum/electroneum-sc/common"
    25  	"github.com/electroneum/electroneum-sc/consensus/istanbul"
    26  )
    27  
    28  type defaultValidator struct {
    29  	address common.Address
    30  }
    31  
    32  func (val *defaultValidator) Address() common.Address {
    33  	return val.address
    34  }
    35  
    36  func (val *defaultValidator) String() string {
    37  	return val.Address().String()
    38  }
    39  
    40  // ----------------------------------------------------------------------------
    41  
    42  type defaultSet struct {
    43  	validators istanbul.Validators
    44  	policy     *istanbul.ProposerPolicy
    45  
    46  	proposer    istanbul.Validator
    47  	validatorMu sync.RWMutex
    48  	selector    istanbul.ProposalSelector
    49  }
    50  
    51  func newDefaultSet(addrs []common.Address, policy *istanbul.ProposerPolicy) *defaultSet {
    52  	valSet := &defaultSet{}
    53  
    54  	valSet.policy = policy
    55  	// init validators
    56  	valSet.validators = make([]istanbul.Validator, len(addrs))
    57  	for i, addr := range addrs {
    58  		valSet.validators[i] = New(addr)
    59  	}
    60  
    61  	valSet.SortValidators()
    62  	// init proposer
    63  	if valSet.Size() > 0 {
    64  		valSet.proposer = valSet.GetByIndex(0)
    65  	}
    66  	valSet.selector = roundRobinProposer
    67  	if policy.Id == istanbul.Sticky {
    68  		valSet.selector = stickyProposer
    69  	}
    70  
    71  	policy.RegisterValidatorSet(valSet)
    72  
    73  	return valSet
    74  }
    75  
    76  func (valSet *defaultSet) Size() int {
    77  	valSet.validatorMu.RLock()
    78  	defer valSet.validatorMu.RUnlock()
    79  	return len(valSet.validators)
    80  }
    81  
    82  func (valSet *defaultSet) List() []istanbul.Validator {
    83  	valSet.validatorMu.RLock()
    84  	defer valSet.validatorMu.RUnlock()
    85  	return valSet.validators
    86  }
    87  
    88  func (valSet *defaultSet) GetByIndex(i uint64) istanbul.Validator {
    89  	valSet.validatorMu.RLock()
    90  	defer valSet.validatorMu.RUnlock()
    91  	if i < uint64(valSet.Size()) {
    92  		return valSet.validators[i]
    93  	}
    94  	return nil
    95  }
    96  
    97  func (valSet *defaultSet) GetByAddress(addr common.Address) (int, istanbul.Validator) {
    98  	for i, val := range valSet.List() {
    99  		if addr == val.Address() {
   100  			return i, val
   101  		}
   102  	}
   103  	return -1, nil
   104  }
   105  
   106  func (valSet *defaultSet) GetProposer() istanbul.Validator {
   107  	return valSet.proposer
   108  }
   109  
   110  func (valSet *defaultSet) IsProposer(address common.Address) bool {
   111  	_, val := valSet.GetByAddress(address)
   112  	return reflect.DeepEqual(valSet.GetProposer(), val)
   113  }
   114  
   115  func (valSet *defaultSet) CalcProposer(lastProposer common.Address, round uint64) {
   116  	valSet.validatorMu.RLock()
   117  	defer valSet.validatorMu.RUnlock()
   118  	valSet.proposer = valSet.selector(valSet, lastProposer, round)
   119  }
   120  
   121  // ValidatorSetSorter sorts the validators based on the configured By function
   122  func (valSet *defaultSet) SortValidators() {
   123  	valSet.Policy().By.Sort(valSet.validators)
   124  }
   125  
   126  func calcSeed(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) uint64 {
   127  	offset := 0
   128  	if idx, val := valSet.GetByAddress(proposer); val != nil {
   129  		offset = idx
   130  	}
   131  	return uint64(offset) + round
   132  }
   133  
   134  func emptyAddress(addr common.Address) bool {
   135  	return addr == common.Address{}
   136  }
   137  
   138  func roundRobinProposer(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) istanbul.Validator {
   139  	if valSet.Size() == 0 {
   140  		return nil
   141  	}
   142  	seed := uint64(0)
   143  	if emptyAddress(proposer) {
   144  		seed = round
   145  	} else {
   146  		seed = calcSeed(valSet, proposer, round) + 1
   147  	}
   148  	pick := seed % uint64(valSet.Size())
   149  	return valSet.GetByIndex(pick)
   150  }
   151  
   152  func stickyProposer(valSet istanbul.ValidatorSet, proposer common.Address, round uint64) istanbul.Validator {
   153  	if valSet.Size() == 0 {
   154  		return nil
   155  	}
   156  	seed := uint64(0)
   157  	if emptyAddress(proposer) {
   158  		seed = round
   159  	} else {
   160  		seed = calcSeed(valSet, proposer, round)
   161  	}
   162  	pick := seed % uint64(valSet.Size())
   163  	return valSet.GetByIndex(pick)
   164  }
   165  
   166  func (valSet *defaultSet) AddValidator(address common.Address) bool {
   167  	valSet.validatorMu.Lock()
   168  	defer valSet.validatorMu.Unlock()
   169  	for _, v := range valSet.validators {
   170  		if v.Address() == address {
   171  			return false
   172  		}
   173  	}
   174  	valSet.validators = append(valSet.validators, New(address))
   175  	// TODO: we may not need to re-sort it again
   176  	// sort validator
   177  	valSet.SortValidators()
   178  	return true
   179  }
   180  
   181  func (valSet *defaultSet) RemoveValidator(address common.Address) bool {
   182  	valSet.validatorMu.Lock()
   183  	defer valSet.validatorMu.Unlock()
   184  
   185  	for i, v := range valSet.validators {
   186  		if v.Address() == address {
   187  			valSet.validators = append(valSet.validators[:i], valSet.validators[i+1:]...)
   188  			return true
   189  		}
   190  	}
   191  	return false
   192  }
   193  
   194  func (valSet *defaultSet) Copy() istanbul.ValidatorSet {
   195  	valSet.validatorMu.RLock()
   196  	defer valSet.validatorMu.RUnlock()
   197  
   198  	addresses := make([]common.Address, 0, len(valSet.validators))
   199  	for _, v := range valSet.validators {
   200  		addresses = append(addresses, v.Address())
   201  	}
   202  	return NewSet(addresses, valSet.policy)
   203  }
   204  
   205  func (valSet *defaultSet) F() int { return int(math.Ceil(float64(valSet.Size())/3)) - 1 }
   206  
   207  func (valSet *defaultSet) Policy() istanbul.ProposerPolicy { return *valSet.policy }