github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/bft/validator/default.go (about)

     1  package validator
     2  
     3  import (
     4  	"math"
     5  	"reflect"
     6  	"sort"
     7  	"sync"
     8  
     9  	"github.com/quickchainproject/quickchain/common"
    10  	"github.com/quickchainproject/quickchain/consensus/bft"
    11  )
    12  
    13  type defaultValidator struct {
    14  	address common.Address
    15  }
    16  
    17  func (val *defaultValidator) Address() common.Address {
    18  	return val.address
    19  }
    20  
    21  func (val *defaultValidator) String() string {
    22  	return val.Address().String()
    23  }
    24  
    25  // ----------------------------------------------------------------------------
    26  
    27  type defaultSet struct {
    28  	validators bft.Validators
    29  	policy     bft.ProposerPolicy
    30  
    31  	proposer    bft.Validator
    32  	validatorMu sync.RWMutex
    33  	selector    bft.ProposalSelector
    34  }
    35  
    36  func newDefaultSet(addrs []common.Address, policy bft.ProposerPolicy) *defaultSet {
    37  	valSet := &defaultSet{}
    38  
    39  	valSet.policy = policy
    40  	// init validators
    41  	valSet.validators = make([]bft.Validator, len(addrs))
    42  	for i, addr := range addrs {
    43  		valSet.validators[i] = New(addr)
    44  	}
    45  	// sort validator
    46  	sort.Sort(valSet.validators)
    47  	// init proposer
    48  	if valSet.Size() > 0 {
    49  		valSet.proposer = valSet.GetByIndex(0)
    50  	}
    51  	valSet.selector = roundRobinProposer
    52  	if policy == bft.Sticky {
    53  		valSet.selector = stickyProposer
    54  	}
    55  
    56  	return valSet
    57  }
    58  
    59  func (valSet *defaultSet) Size() int {
    60  	valSet.validatorMu.RLock()
    61  	defer valSet.validatorMu.RUnlock()
    62  	return len(valSet.validators)
    63  }
    64  
    65  func (valSet *defaultSet) List() []bft.Validator {
    66  	valSet.validatorMu.RLock()
    67  	defer valSet.validatorMu.RUnlock()
    68  	return valSet.validators
    69  }
    70  
    71  func (valSet *defaultSet) GetByIndex(i uint64) bft.Validator {
    72  	valSet.validatorMu.RLock()
    73  	defer valSet.validatorMu.RUnlock()
    74  	if i < uint64(valSet.Size()) {
    75  		return valSet.validators[i]
    76  	}
    77  	return nil
    78  }
    79  
    80  func (valSet *defaultSet) GetByAddress(addr common.Address) (int, bft.Validator) {
    81  	for i, val := range valSet.List() {
    82  		if addr == val.Address() {
    83  			return i, val
    84  		}
    85  	}
    86  	return -1, nil
    87  }
    88  
    89  func (valSet *defaultSet) GetProposer() bft.Validator {
    90  	return valSet.proposer
    91  }
    92  
    93  func (valSet *defaultSet) IsProposer(address common.Address) bool {
    94  	_, val := valSet.GetByAddress(address)
    95  	return reflect.DeepEqual(valSet.GetProposer(), val)
    96  }
    97  
    98  func (valSet *defaultSet) CalcProposer(lastProposer common.Address, round uint64) {
    99  	valSet.validatorMu.RLock()
   100  	defer valSet.validatorMu.RUnlock()
   101  	valSet.proposer = valSet.selector(valSet, lastProposer, round)
   102  }
   103  
   104  func calcSeed(valSet bft.ValidatorSet, proposer common.Address, round uint64) uint64 {
   105  	offset := 0
   106  	if idx, val := valSet.GetByAddress(proposer); val != nil {
   107  		offset = idx
   108  	}
   109  	return uint64(offset) + round
   110  }
   111  
   112  func emptyAddress(addr common.Address) bool {
   113  	return addr == common.Address{}
   114  }
   115  
   116  func roundRobinProposer(valSet bft.ValidatorSet, proposer common.Address, round uint64) bft.Validator {
   117  	if valSet.Size() == 0 {
   118  		return nil
   119  	}
   120  	seed := uint64(0)
   121  	if emptyAddress(proposer) {
   122  		seed = round
   123  	} else {
   124  		seed = calcSeed(valSet, proposer, round) + 1
   125  	}
   126  	pick := seed % uint64(valSet.Size())
   127  	return valSet.GetByIndex(pick)
   128  }
   129  
   130  func stickyProposer(valSet bft.ValidatorSet, proposer common.Address, round uint64) bft.Validator {
   131  	if valSet.Size() == 0 {
   132  		return nil
   133  	}
   134  	seed := uint64(0)
   135  	if emptyAddress(proposer) {
   136  		seed = round
   137  	} else {
   138  		seed = calcSeed(valSet, proposer, round)
   139  	}
   140  	pick := seed % uint64(valSet.Size())
   141  	return valSet.GetByIndex(pick)
   142  }
   143  
   144  func (valSet *defaultSet) AddValidator(address common.Address) bool {
   145  	valSet.validatorMu.Lock()
   146  	defer valSet.validatorMu.Unlock()
   147  	for _, v := range valSet.validators {
   148  		if v.Address() == address {
   149  			return false
   150  		}
   151  	}
   152  	valSet.validators = append(valSet.validators, New(address))
   153  	// TODO: we may not need to re-sort it again
   154  	// sort validator
   155  	sort.Sort(valSet.validators)
   156  	return true
   157  }
   158  
   159  func (valSet *defaultSet) RemoveValidator(address common.Address) bool {
   160  	valSet.validatorMu.Lock()
   161  	defer valSet.validatorMu.Unlock()
   162  
   163  	for i, v := range valSet.validators {
   164  		if v.Address() == address {
   165  			valSet.validators = append(valSet.validators[:i], valSet.validators[i+1:]...)
   166  			return true
   167  		}
   168  	}
   169  	return false
   170  }
   171  
   172  func (valSet *defaultSet) Copy() bft.ValidatorSet {
   173  	valSet.validatorMu.RLock()
   174  	defer valSet.validatorMu.RUnlock()
   175  
   176  	addresses := make([]common.Address, 0, len(valSet.validators))
   177  	for _, v := range valSet.validators {
   178  		addresses = append(addresses, v.Address())
   179  	}
   180  	return NewSet(addresses, valSet.policy)
   181  }
   182  
   183  func (valSet *defaultSet) F() int { return int(math.Ceil(float64(valSet.Size())/3)) - 1 }
   184  
   185  func (valSet *defaultSet) Policy() bft.ProposerPolicy { return valSet.policy }