github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/acm/validator/set.go (about)

     1  package validator
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/hyperledger/burrow/crypto"
    10  )
    11  
    12  var big0 = big.NewInt(0)
    13  var big1 = big.NewInt(1)
    14  var big2 = big.NewInt(2)
    15  var big3 = big.NewInt(3)
    16  
    17  // A Validator multiset - can be used to capture the global state of validators or as an accumulator each block
    18  type Set struct {
    19  	powers     map[crypto.Address]*big.Int
    20  	publicKeys map[crypto.Address]crypto.Addressable
    21  	totalPower *big.Int
    22  	trim       bool
    23  }
    24  
    25  func newSet() *Set {
    26  	return &Set{
    27  		totalPower: new(big.Int),
    28  		powers:     make(map[crypto.Address]*big.Int),
    29  		publicKeys: make(map[crypto.Address]crypto.Addressable),
    30  	}
    31  }
    32  
    33  // Create a new Validators which can act as an accumulator for validator power changes
    34  func NewSet() *Set {
    35  	return newSet()
    36  }
    37  
    38  // Like Set but removes entries when power is set to 0 this make Count() == CountNonZero() and prevents a set from leaking
    39  // but does mean that a zero will not be iterated over when performing an update which is necessary in Ring
    40  func NewTrimSet() *Set {
    41  	s := newSet()
    42  	s.trim = true
    43  	return s
    44  }
    45  
    46  // Implements Writer, but will never error
    47  func (vs *Set) SetPower(id *crypto.PublicKey, power *big.Int) (*big.Int, error) {
    48  	return vs.ChangePower(id, power), nil
    49  }
    50  
    51  // Add the power of a validator and returns the flow into that validator
    52  func (vs *Set) ChangePower(id *crypto.PublicKey, power *big.Int) *big.Int {
    53  	address := id.GetAddress()
    54  	// Calculate flow into this validator (positive means in, negative means out)
    55  	flow := vs.Flow(id, power)
    56  	vs.totalPower.Add(vs.totalPower, flow)
    57  
    58  	if vs.trim && power.Sign() == 0 {
    59  		delete(vs.publicKeys, address)
    60  		delete(vs.powers, address)
    61  	} else {
    62  		vs.publicKeys[address] = crypto.NewAddressable(id)
    63  		vs.powers[address] = new(big.Int).Set(power)
    64  	}
    65  	return flow
    66  }
    67  
    68  func (vs *Set) TotalPower() *big.Int {
    69  	return new(big.Int).Set(vs.totalPower)
    70  }
    71  
    72  // Returns the maximum allowable flow whilst ensuring the majority of validators are non-byzantine after the transition
    73  // So need at most ceiling((Total Power)/3) - 1, in integer division we have ceiling(X*p/q) = (p(X+1)-1)/q
    74  // For p = 1 just X/q so we want (Total Power)/3 - 1
    75  func (vs *Set) MaxFlow() *big.Int {
    76  	max := vs.TotalPower()
    77  	return max.Sub(max.Div(max, big3), big1)
    78  }
    79  
    80  // Returns the flow that would be induced by a validator power change
    81  func (vs *Set) Flow(id *crypto.PublicKey, power *big.Int) *big.Int {
    82  	return new(big.Int).Sub(power, vs.GetPower(id.GetAddress()))
    83  }
    84  
    85  // Returns the power of id but only if it is set
    86  func (vs *Set) MaybePower(id crypto.Address) *big.Int {
    87  	if vs.powers[id] == nil {
    88  		return nil
    89  	}
    90  	return new(big.Int).Set(vs.powers[id])
    91  }
    92  
    93  // Version of Power to match interface
    94  func (vs *Set) Power(id crypto.Address) (*big.Int, error) {
    95  	return vs.GetPower(id), nil
    96  }
    97  
    98  // Error free version of Power
    99  func (vs *Set) GetPower(id crypto.Address) *big.Int {
   100  	if vs.powers[id] == nil {
   101  		return new(big.Int)
   102  	}
   103  	return new(big.Int).Set(vs.powers[id])
   104  }
   105  
   106  // Returns an error if the Sets are not equal describing which part of their structures differ
   107  func (vs *Set) Equal(vsOther *Set) error {
   108  	if vs.Size() != vsOther.Size() {
   109  		return fmt.Errorf("set size %d != other set size %d", vs.Size(), vsOther.Size())
   110  	}
   111  	// Stop iteration IFF we find a non-matching validator
   112  	return vs.IterateValidators(func(id crypto.Addressable, power *big.Int) error {
   113  		otherPower := vsOther.GetPower(id.GetAddress())
   114  		if otherPower.Cmp(power) != 0 {
   115  			return fmt.Errorf("set power %d != other set power %d", power, otherPower)
   116  		}
   117  		return nil
   118  	})
   119  }
   120  
   121  // Iterates over validators sorted by address
   122  func (vs *Set) IterateValidators(iter func(id crypto.Addressable, power *big.Int) error) error {
   123  	if vs == nil {
   124  		return nil
   125  	}
   126  	addresses := make(crypto.Addresses, 0, len(vs.powers))
   127  	for address := range vs.powers {
   128  		addresses = append(addresses, address)
   129  	}
   130  	sort.Sort(addresses)
   131  	for _, address := range addresses {
   132  		err := iter(vs.publicKeys[address], new(big.Int).Set(vs.powers[address]))
   133  		if err != nil {
   134  			return err
   135  		}
   136  	}
   137  	return nil
   138  }
   139  
   140  func (vs *Set) Flush(output Writer, backend Reader) error {
   141  	return vs.IterateValidators(func(id crypto.Addressable, power *big.Int) error {
   142  		_, err := output.SetPower(id.GetPublicKey(), power)
   143  		return err
   144  	})
   145  }
   146  
   147  func (vs *Set) CountNonZero() int {
   148  	var count int
   149  	vs.IterateValidators(func(id crypto.Addressable, power *big.Int) error {
   150  		if power.Sign() != 0 {
   151  			count++
   152  		}
   153  		return nil
   154  	})
   155  	return count
   156  }
   157  
   158  func (vs *Set) Size() int {
   159  	return len(vs.publicKeys)
   160  }
   161  
   162  func (vs *Set) Validators() []*Validator {
   163  	if vs == nil {
   164  		return nil
   165  	}
   166  	pvs := make([]*Validator, 0, vs.Size())
   167  	vs.IterateValidators(func(id crypto.Addressable, power *big.Int) error {
   168  		pvs = append(pvs, &Validator{PublicKey: id.GetPublicKey(), Power: power.Uint64()})
   169  		return nil
   170  	})
   171  	return pvs
   172  }
   173  
   174  func UnpersistSet(pvs []*Validator) *Set {
   175  	vs := NewSet()
   176  	for _, pv := range pvs {
   177  		vs.ChangePower(pv.PublicKey, new(big.Int).SetUint64(pv.Power))
   178  	}
   179  	return vs
   180  }
   181  
   182  func (vs *Set) String() string {
   183  	return fmt.Sprintf("Validators{TotalPower: %v; Count: %v; %v}", vs.TotalPower(), vs.Size(),
   184  		vs.Strings())
   185  }
   186  
   187  func (vs *Set) Strings() string {
   188  	strs := make([]string, 0, vs.Size())
   189  	vs.IterateValidators(func(id crypto.Addressable, power *big.Int) error {
   190  		strs = append(strs, fmt.Sprintf("%v->%v", id.GetAddress(), power))
   191  		return nil
   192  	})
   193  	return strings.Join(strs, ", ")
   194  }