github.com/datachainlab/burrow@v0.25.0/execution/state/validators.go (about)

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