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 }