github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/execution/state/validators.go (about)

     1  package state
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"github.com/hyperledger/burrow/encoding"
     7  	"github.com/hyperledger/burrow/genesis"
     8  
     9  	"github.com/hyperledger/burrow/acm/validator"
    10  	"github.com/hyperledger/burrow/storage"
    11  
    12  	"github.com/hyperledger/burrow/crypto"
    13  )
    14  
    15  // Initialises the validator Ring from the validator storage in forest
    16  func LoadValidatorRing(version int64, ringSize int,
    17  	getImmutable func(version int64) (*storage.ImmutableForest, error)) (*validator.Ring, error) {
    18  
    19  	// In this method we have to page through previous version of the tree in order to reconstruct the in-memory
    20  	// ring structure. The corner cases are a little subtle but printing the buckets helps
    21  
    22  	// The basic idea is to load each version of the tree ringSize back, work out the difference that must have occurred
    23  	// between each bucket in the ring, and apply each diff to the ring. Once the ring is full it is symmetrical (up to
    24  	// a reindexing). If we are loading a chain whose height is less than the ring size we need to get the initial state
    25  	// correct
    26  
    27  	startVersion := version - int64(ringSize)
    28  	if startVersion < 1 {
    29  		// The ring will not be fully populated
    30  		startVersion = 1
    31  	}
    32  	var err error
    33  	// Read state to pull immutable forests from
    34  	rs := &ReadState{}
    35  	// Start with an empty ring - we want the initial bucket to have no cumulative power
    36  	ring := validator.NewRing(nil, ringSize)
    37  	// Load the IAVL state
    38  	rs.Forest, err = getImmutable(startVersion)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	// Write the validator state at startVersion from IAVL tree into the ring's current bucket delta
    43  	err = validator.Write(ring, rs)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	// Rotate, now we have [ {bucket 0: cum: {}, delta: {start version changes} }, {bucket 1: cum: {start version changes}, delta {}, ... ]
    48  	// which is what we need (in particular we need this initial state if we are loading into a incompletely populated ring
    49  	_, _, err = ring.Rotate()
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	// Rebuild validator Ring
    55  	for v := startVersion + 1; v <= version; v++ {
    56  		// Update IAVL read state to version of interest
    57  		rs.Forest, err = getImmutable(v)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  		// Calculate the difference between the rings current cum and what is in state at this version
    62  		diff, err := validator.Diff(ring.CurrentSet(), rs)
    63  		if err != nil {
    64  			return nil, err
    65  		}
    66  		// Write that diff into the ring (just like it was when it was originally written to setPower)
    67  		err = validator.Write(ring, diff)
    68  		if err != nil {
    69  			return nil, err
    70  		}
    71  		// Rotate just like it was on the original commit
    72  		_, _, err = ring.Rotate()
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  	}
    77  	// Our ring should be the same up to symmetry in its index so we reindex to regain equality with the version we are loading
    78  	// This is the head index we would have had if we had started from version 1 like the chain did
    79  	ring.ReIndex(int(version % int64(ringSize)))
    80  	return ring, err
    81  }
    82  
    83  func (ws *writeState) MakeGenesisValidators(genesisDoc *genesis.GenesisDoc) error {
    84  	for _, gv := range genesisDoc.Validators {
    85  		_, err := ws.SetPower(gv.PublicKey, new(big.Int).SetUint64(gv.Amount))
    86  		if err != nil {
    87  			return err
    88  		}
    89  	}
    90  	return nil
    91  }
    92  
    93  func (s *ImmutableState) Power(id crypto.Address) (*big.Int, error) {
    94  	tree, err := s.Forest.Reader(keys.Validator.Prefix())
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	bs, err := tree.Get(keys.Validator.KeyNoPrefix(id))
    99  	if err != nil {
   100  		return nil, err
   101  	} else if len(bs) == 0 {
   102  		return new(big.Int), nil
   103  	}
   104  	v := new(validator.Validator)
   105  	err = encoding.Decode(bs, v)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	return v.BigPower(), nil
   110  }
   111  
   112  func (s *ImmutableState) IterateValidators(fn func(id crypto.Addressable, power *big.Int) error) error {
   113  	tree, err := s.Forest.Reader(keys.Validator.Prefix())
   114  	if err != nil {
   115  		return err
   116  	}
   117  	return tree.Iterate(nil, nil, true, func(_, value []byte) error {
   118  		v := new(validator.Validator)
   119  		err = encoding.Decode(value, v)
   120  		if err != nil {
   121  			return err
   122  		}
   123  		return fn(v, v.BigPower())
   124  	})
   125  }
   126  
   127  func (ws *writeState) SetPower(id *crypto.PublicKey, power *big.Int) (*big.Int, error) {
   128  	// SetPower in ring
   129  	flow, err := ws.ring.SetPower(id, power)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	// Set power in versioned state
   134  	return flow, ws.setPower(id, power)
   135  }
   136  
   137  func (ws *writeState) setPower(id *crypto.PublicKey, power *big.Int) error {
   138  	return ws.forest.Write(keys.Validator.Prefix(), func(tree *storage.RWTree) error {
   139  		key := keys.Validator.KeyNoPrefix(id.GetAddress())
   140  		if power.Sign() == 0 {
   141  			tree.Delete(key)
   142  			return nil
   143  		}
   144  		bs, err := encoding.Encode(validator.New(id, power))
   145  		if err != nil {
   146  			return err
   147  		}
   148  		tree.Set(key, bs)
   149  		return nil
   150  	})
   151  }