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  }