github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/state/v1/setters_misc.go (about)

     1  package v1
     2  
     3  import (
     4  	"github.com/pkg/errors"
     5  	types "github.com/prysmaticlabs/eth2-types"
     6  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
     7  	pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
     8  	"github.com/prysmaticlabs/prysm/shared/hashutil"
     9  	"google.golang.org/protobuf/proto"
    10  )
    11  
    12  // For our setters, we have a field reference counter through
    13  // which we can track shared field references. This helps when
    14  // performing state copies, as we simply copy the reference to the
    15  // field. When we do need to do need to modify these fields, we
    16  // perform a full copy of the field. This is true of most of our
    17  // fields except for the following below.
    18  // 1) BlockRoots
    19  // 2) StateRoots
    20  // 3) Eth1DataVotes
    21  // 4) RandaoMixes
    22  // 5) HistoricalRoots
    23  // 6) CurrentEpochAttestations
    24  // 7) PreviousEpochAttestations
    25  // 8) Validators
    26  //
    27  // The fields referred to above are instead copied by reference, where
    28  // we simply copy the reference to the underlying object instead of the
    29  // whole object. This is possible due to how we have structured our state
    30  // as we copy the value on read, so as to ensure the underlying object is
    31  // not mutated while it is being accessed during a state read.
    32  
    33  const (
    34  	// This specifies the limit till which we process all dirty indices for a certain field.
    35  	// If we have more dirty indices than the theshold, then we rebuild the whole trie. This
    36  	// comes due to the fact that O(alogn) > O(n) beyong a certain value of a.
    37  	indicesLimit = 8000
    38  )
    39  
    40  // SetGenesisTime for the beacon state.
    41  func (b *BeaconState) SetGenesisTime(val uint64) error {
    42  	b.lock.Lock()
    43  	defer b.lock.Unlock()
    44  
    45  	b.state.GenesisTime = val
    46  	b.markFieldAsDirty(genesisTime)
    47  	return nil
    48  }
    49  
    50  // SetGenesisValidatorRoot for the beacon state.
    51  func (b *BeaconState) SetGenesisValidatorRoot(val []byte) error {
    52  	b.lock.Lock()
    53  	defer b.lock.Unlock()
    54  
    55  	b.state.GenesisValidatorsRoot = val
    56  	b.markFieldAsDirty(genesisValidatorRoot)
    57  	return nil
    58  }
    59  
    60  // SetSlot for the beacon state.
    61  func (b *BeaconState) SetSlot(val types.Slot) error {
    62  	if !b.hasInnerState() {
    63  		return ErrNilInnerState
    64  	}
    65  	b.lock.Lock()
    66  	defer b.lock.Unlock()
    67  
    68  	b.state.Slot = val
    69  	b.markFieldAsDirty(slot)
    70  	return nil
    71  }
    72  
    73  // SetFork version for the beacon chain.
    74  func (b *BeaconState) SetFork(val *pbp2p.Fork) error {
    75  	if !b.hasInnerState() {
    76  		return ErrNilInnerState
    77  	}
    78  	b.lock.Lock()
    79  	defer b.lock.Unlock()
    80  
    81  	fk, ok := proto.Clone(val).(*pbp2p.Fork)
    82  	if !ok {
    83  		return errors.New("proto.Clone did not return a fork proto")
    84  	}
    85  	b.state.Fork = fk
    86  	b.markFieldAsDirty(fork)
    87  	return nil
    88  }
    89  
    90  // SetHistoricalRoots for the beacon state. Updates the entire
    91  // list to a new value by overwriting the previous one.
    92  func (b *BeaconState) SetHistoricalRoots(val [][]byte) error {
    93  	if !b.hasInnerState() {
    94  		return ErrNilInnerState
    95  	}
    96  	b.lock.Lock()
    97  	defer b.lock.Unlock()
    98  
    99  	b.sharedFieldReferences[historicalRoots].MinusRef()
   100  	b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1)
   101  
   102  	b.state.HistoricalRoots = val
   103  	b.markFieldAsDirty(historicalRoots)
   104  	return nil
   105  }
   106  
   107  // AppendHistoricalRoots for the beacon state. Appends the new value
   108  // to the the end of list.
   109  func (b *BeaconState) AppendHistoricalRoots(root [32]byte) error {
   110  	if !b.hasInnerState() {
   111  		return ErrNilInnerState
   112  	}
   113  	b.lock.Lock()
   114  	defer b.lock.Unlock()
   115  
   116  	roots := b.state.HistoricalRoots
   117  	if b.sharedFieldReferences[historicalRoots].Refs() > 1 {
   118  		roots = make([][]byte, len(b.state.HistoricalRoots))
   119  		copy(roots, b.state.HistoricalRoots)
   120  		b.sharedFieldReferences[historicalRoots].MinusRef()
   121  		b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1)
   122  	}
   123  
   124  	b.state.HistoricalRoots = append(roots, root[:])
   125  	b.markFieldAsDirty(historicalRoots)
   126  	return nil
   127  }
   128  
   129  // Recomputes the branch up the index in the Merkle trie representation
   130  // of the beacon state. This method performs map reads and the caller MUST
   131  // hold the lock before calling this method.
   132  func (b *BeaconState) recomputeRoot(idx int) {
   133  	hashFunc := hashutil.CustomSHA256Hasher()
   134  	layers := b.merkleLayers
   135  	// The merkle tree structure looks as follows:
   136  	// [[r1, r2, r3, r4], [parent1, parent2], [root]]
   137  	// Using information about the index which changed, idx, we recompute
   138  	// only its branch up the tree.
   139  	currentIndex := idx
   140  	root := b.merkleLayers[0][idx]
   141  	for i := 0; i < len(layers)-1; i++ {
   142  		isLeft := currentIndex%2 == 0
   143  		neighborIdx := currentIndex ^ 1
   144  
   145  		neighbor := make([]byte, 32)
   146  		if layers[i] != nil && len(layers[i]) != 0 && neighborIdx < len(layers[i]) {
   147  			neighbor = layers[i][neighborIdx]
   148  		}
   149  		if isLeft {
   150  			parentHash := hashFunc(append(root, neighbor...))
   151  			root = parentHash[:]
   152  		} else {
   153  			parentHash := hashFunc(append(neighbor, root...))
   154  			root = parentHash[:]
   155  		}
   156  		parentIdx := currentIndex / 2
   157  		// Update the cached layers at the parent index.
   158  		layers[i+1][parentIdx] = root
   159  		currentIndex = parentIdx
   160  	}
   161  	b.merkleLayers = layers
   162  }
   163  
   164  func (b *BeaconState) markFieldAsDirty(field fieldIndex) {
   165  	_, ok := b.dirtyFields[field]
   166  	if !ok {
   167  		b.dirtyFields[field] = true
   168  	}
   169  	// do nothing if field already exists
   170  }
   171  
   172  // addDirtyIndices adds the relevant dirty field indices, so that they
   173  // can be recomputed.
   174  func (b *BeaconState) addDirtyIndices(index fieldIndex, indices []uint64) {
   175  	if b.rebuildTrie[index] {
   176  		return
   177  	}
   178  	b.dirtyIndices[index] = append(b.dirtyIndices[index], indices...)
   179  	if len(b.dirtyIndices[index]) > indicesLimit {
   180  		b.rebuildTrie[index] = true
   181  		b.dirtyIndices[index] = []uint64{}
   182  	}
   183  }