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 }