github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/acm/validator/ring.go (about) 1 package validator 2 3 import ( 4 "fmt" 5 "math/big" 6 7 "github.com/hyperledger/burrow/crypto" 8 ) 9 10 // Ring stores the validator power history in buckets as a ring buffer. The primary storage is a the difference between 11 // each rotation (commit - i.e. block) in 'delta' and the cumulative result of each delta in cum, where the result of 12 // the delta at i is stored in the cum at i+1. For example suppose we have 4 buckets then graphically: 13 // 14 // delta [d1| d2 | d3 | d4 ] 15 // cum [v0|v0+d1|v0+d1+d2 |v0+d1+d2+d3 ] 16 // 17 // After the fourth rotation we loop back to the 0th bucket (with [pwer 18 // 19 // delta [d5 | d6| d7 | d8 ] 20 // cum [v0+d1+d2+d3+d4|...| | ] 21 type Ring struct { 22 buckets []*Bucket 23 // Power tracks the sliding sum of all powers for each validator added by each delta bucket - power is added for the newest delta and subtracted from the oldest delta each rotation 24 power *Set 25 // Index of current head bucket 26 head int 27 // Number of buckets 28 size int 29 // Number of buckets that have so far had any increments made to them - equivalently the number of rotations made up to a maximum of the number of buckets available 30 populated int 31 } 32 33 var _ History = &Ring{} 34 35 // NewRing provides a sliding window over the last size buckets of validator power changes 36 func NewRing(initialSet Iterable, windowSize int) *Ring { 37 if windowSize < 1 { 38 windowSize = 1 39 } 40 vc := &Ring{ 41 buckets: make([]*Bucket, windowSize), 42 power: NewTrimSet(), 43 size: windowSize, 44 } 45 for i := 0; i < windowSize; i++ { 46 vc.buckets[i] = NewBucket() 47 } 48 if initialSet != nil { 49 vc.populated = 1 50 vc.buckets[0] = NewBucket(initialSet) 51 } 52 return vc 53 } 54 55 // Implement Reader 56 57 // Power gets the balance at index from the delta bucket then falling through to the cumulative 58 func (vc *Ring) Power(id crypto.Address) (*big.Int, error) { 59 return vc.GetPower(id), nil 60 } 61 62 func (vc *Ring) GetPower(id crypto.Address) *big.Int { 63 return vc.Head().Previous.GetPower(id) 64 } 65 66 func (vc *Ring) SetPower(id *crypto.PublicKey, power *big.Int) (*big.Int, error) { 67 return vc.Head().SetPower(id, power) 68 } 69 70 // CumulativePower gets the sum of all powers added in any bucket 71 func (vc *Ring) CumulativePower() *Set { 72 return vc.power 73 } 74 75 // Rotate the current head bucket to the next bucket and returns the change in total power between the previous bucket 76 // and the current head, and the total flow which is the sum of absolute values of all changes each validator's power 77 // after rotation the next head is a copy of the current head 78 func (vc *Ring) Rotate() (totalPowerChange *big.Int, totalFlow *big.Int, err error) { 79 // Subtract the tail bucket (if any) from the total 80 err = Subtract(vc.power, vc.Next().Delta) 81 if err != nil { 82 return 83 } 84 // Capture current head as previous before advancing buffer 85 prevHead := vc.Head() 86 // Add head delta to total power 87 err = Add(vc.power, prevHead.Delta) 88 if err != nil { 89 return 90 } 91 // Advance the ring buffer 92 vc.head = vc.index(1) 93 // Overwrite new head bucket (previous tail) with a fresh bucket with Previous_i+1 = Next_i = Previous_i + Delta_i 94 vc.buckets[vc.head] = NewBucket(prevHead.Next) 95 // Capture flow before we wipe it 96 totalFlow = prevHead.Flow.totalPower 97 // Subtract the previous bucket total power so we can add on the current buckets power after this 98 totalPowerChange = new(big.Int).Sub(vc.Head().Previous.TotalPower(), prevHead.Previous.TotalPower()) 99 // Record how many of our buckets we have cycled over 100 if vc.populated < vc.size { 101 vc.populated++ 102 } 103 return 104 } 105 106 func (vc *Ring) ReIndex(newHead int) { 107 buckets := make([]*Bucket, len(vc.buckets)) 108 for i := 0; i < len(buckets); i++ { 109 buckets[(i+newHead)%len(buckets)] = vc.buckets[vc.index(i)] 110 } 111 vc.head = newHead 112 vc.buckets = buckets 113 } 114 115 func (vc *Ring) CurrentSet() *Set { 116 return vc.Head().Previous 117 } 118 119 // Get the current accumulator bucket 120 func (vc *Ring) Head() *Bucket { 121 return vc.buckets[vc.head] 122 } 123 124 func (vc *Ring) ValidatorChanges(blocksAgo int) IterableReader { 125 return vc.PreviousDelta(blocksAgo) 126 } 127 128 func (vc *Ring) Validators(blocksAgo int) IterableReader { 129 return vc.PreviousSet(blocksAgo) 130 } 131 132 func (vc *Ring) PreviousSet(delay int) *Set { 133 // report the oldest cumulative set (i.e. genesis) if given a longer delay than populated 134 if delay >= vc.populated { 135 delay = vc.populated - 1 136 } 137 return vc.buckets[vc.index(-delay)].Previous 138 } 139 140 func (vc *Ring) PreviousDelta(delay int) *Set { 141 if delay >= vc.populated { 142 return NewSet() 143 } 144 return vc.buckets[vc.index(-delay)].Delta 145 } 146 147 func (vc *Ring) Next() *Bucket { 148 return vc.buckets[vc.index(1)] 149 } 150 151 func (vc *Ring) index(i int) int { 152 return (vc.size + vc.head + i) % vc.size 153 } 154 155 // Get the number of buckets in the ring (use Current().Count() to get the current number of validators) 156 func (vc *Ring) Size() int { 157 return vc.size 158 } 159 160 // Returns buckets in order head, previous, ... 161 func (vc *Ring) OrderedBuckets() []*Bucket { 162 buckets := make([]*Bucket, len(vc.buckets)) 163 for i := int(0); i < vc.size; i++ { 164 index := vc.index(-i) 165 buckets[i] = vc.buckets[index] 166 } 167 return buckets 168 } 169 170 func (vc *Ring) String() string { 171 buckets := vc.OrderedBuckets() 172 return fmt.Sprintf("ValidatorsRing{Total: %v; Buckets: %v}", vc.power, buckets) 173 } 174 175 func (vc *Ring) Equal(vcOther *Ring) error { 176 if vc.size != vcOther.size { 177 return fmt.Errorf("ring size %d != other ring size %d", vc.size, vcOther.size) 178 } 179 if vc.head != vcOther.head { 180 return fmt.Errorf("ring head index %d != other head index %d", vc.head, vcOther.head) 181 } 182 err := vc.power.Equal(vcOther.power) 183 if err != nil { 184 return fmt.Errorf("ring power != other ring power: %v", err) 185 } 186 for i := 0; i < len(vc.buckets); i++ { 187 err = vc.buckets[i].Equal(vcOther.buckets[i]) 188 if err != nil { 189 return fmt.Errorf("ring buckets do not match at index %d: %v", i, err) 190 } 191 } 192 return nil 193 }