mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-15 06:28:20 +00:00
21bdbd548a
* v0 * getters/setters * init and copy * hasher * all the nice stuff * make bazel happy * remove tests for smaller PR * remove old states * move files * import fixes * custom MarshalSSZ * fixed deadlock * copy version when copying state * correct issues in state_trie * fix Copy() * better e2e comment * add code to minimal state * spectest test * Revert "Auxiliary commit to revert individual files from 84154423464e8372f7e0a03367403656ac5cd78e" This reverts commit 9602599d183081291dfa0ba4f1036430f63a7822. * native state assert * always error * always log * more native state usage * cleanup * remove empty line * Revert "spectests" This reverts commit 1c49bed5d1cf6224afaf21e18562bf72fae5d2b6. # Conflicts: # beacon-chain/powchain/service.go # beacon-chain/state/v1/state_trie.go # beacon-chain/state/v2/state_trie.go # beacon-chain/state/v3/state_trie.go # testing/spectest/shared/phase0/finality/BUILD.bazel # testing/spectest/shared/phase0/finality/runner.go * dedup field trie * fix test issues * cleanup * use correct field num in FinalizedRootProof * use existing version constant * halfway there * "working" version * some fixes * fix field nums in tests * rename v0types to nativetypes * Revert "Auxiliary commit to revert individual files from dc549b1cf8e724bd08cee1ecc760ff3771d5592d" This reverts commit 7254d3070d8693b283fc686a2e01a822ecbac1b3. * uncomment code * remove map size * Revert "Revert "spectests"" This reverts commit 39c271ae6b57d6a3737e2c202cd8407857475e56. * use reverse map * Revert "Revert "Revert "spectests""" This reverts commit 19ba8cf95cdca689357c8234a262e08cccbafef4. * finally found the bug (cherry picked from commit a5414c4be1bdb61a50b391ea5301895e772cc5e9) * simplify populateFieldIndexes * fix copy (cherry picked from commit 7da4fb8cf51557ef931bb781872ea52fc6731af5) * remove native state from e2e * remove index map * unsupported functions * Use ProtobufBeaconState() from native state * tests * typo * reduce complexity of `SaveStatesEfficient` * remove unused receiver name * update doc.go * fix test assertion * fix test assertion 2 * Phase0 justification bits * bring back state tests * rename fieldIndexRev * versioning of ToProto * remove version check from unexported function * hasher tests * don't return error from JustificationBits * extract fieldConvertersNative * helper error function * use fieldConvertersNative * Introduce RealPosition method on FieldIndex * use RealPosition in hasher * remove unused fields * remove TestAppendBeyondIndicesLimit (cherry picked from commit 3017e700282969c30006b64c95c21ffe6b166f8b) * simplify RealPosition * rename field interface * use helper in proofs.go * Update beacon-chain/core/altair/upgrade.go Co-authored-by: Nishant Das <nishdas93@gmail.com> Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
180 lines
5.6 KiB
Go
180 lines
5.6 KiB
Go
package state_native
|
|
|
|
import (
|
|
"github.com/pkg/errors"
|
|
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
|
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
|
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
|
"github.com/prysmaticlabs/prysm/crypto/hash"
|
|
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
|
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
// For our setters, we have a field reference counter through
|
|
// which we can track shared field references. This helps when
|
|
// performing state copies, as we simply copy the reference to the
|
|
// field. When we do need to modify these fields, we
|
|
// perform a full copy of the field. This is true of most of our
|
|
// fields except for the following below.
|
|
// 1) BlockRoots
|
|
// 2) StateRoots
|
|
// 3) Eth1DataVotes
|
|
// 4) RandaoMixes
|
|
// 5) HistoricalRoots
|
|
// 6) CurrentEpochAttestations
|
|
// 7) PreviousEpochAttestations
|
|
// 8) Validators
|
|
//
|
|
// The fields referred to above are instead copied by reference, where
|
|
// we simply copy the reference to the underlying object instead of the
|
|
// whole object. This is possible due to how we have structured our state
|
|
// as we copy the value on read, so as to ensure the underlying object is
|
|
// not mutated while it is being accessed during a state read.
|
|
|
|
const (
|
|
// This specifies the limit till which we process all dirty indices for a certain field.
|
|
// If we have more dirty indices than the threshold, then we rebuild the whole trie. This
|
|
// comes due to the fact that O(alogn) > O(n) beyond a certain value of a.
|
|
indicesLimit = 8000
|
|
)
|
|
|
|
// SetGenesisTime for the beacon state.
|
|
func (b *BeaconState) SetGenesisTime(val uint64) error {
|
|
b.lock.Lock()
|
|
defer b.lock.Unlock()
|
|
|
|
b.genesisTime = val
|
|
b.markFieldAsDirty(nativetypes.GenesisTime)
|
|
return nil
|
|
}
|
|
|
|
// SetGenesisValidatorsRoot for the beacon state.
|
|
func (b *BeaconState) SetGenesisValidatorsRoot(val []byte) error {
|
|
b.lock.Lock()
|
|
defer b.lock.Unlock()
|
|
|
|
if len(val) != fieldparams.RootLength {
|
|
return errors.New("incorrect validators root length")
|
|
}
|
|
b.genesisValidatorsRoot = bytesutil.ToBytes32(val)
|
|
b.markFieldAsDirty(nativetypes.GenesisValidatorsRoot)
|
|
return nil
|
|
}
|
|
|
|
// SetSlot for the beacon state.
|
|
func (b *BeaconState) SetSlot(val types.Slot) error {
|
|
b.lock.Lock()
|
|
defer b.lock.Unlock()
|
|
|
|
b.slot = val
|
|
b.markFieldAsDirty(nativetypes.Slot)
|
|
return nil
|
|
}
|
|
|
|
// SetFork version for the beacon chain.
|
|
func (b *BeaconState) SetFork(val *ethpb.Fork) error {
|
|
b.lock.Lock()
|
|
defer b.lock.Unlock()
|
|
|
|
fk, ok := proto.Clone(val).(*ethpb.Fork)
|
|
if !ok {
|
|
return errors.New("proto.Clone did not return a fork proto")
|
|
}
|
|
b.fork = fk
|
|
b.markFieldAsDirty(nativetypes.Fork)
|
|
return nil
|
|
}
|
|
|
|
// SetHistoricalRoots for the beacon state. Updates the entire
|
|
// list to a new value by overwriting the previous one.
|
|
func (b *BeaconState) SetHistoricalRoots(val [][]byte) error {
|
|
b.lock.Lock()
|
|
defer b.lock.Unlock()
|
|
|
|
b.sharedFieldReferences[nativetypes.HistoricalRoots].MinusRef()
|
|
b.sharedFieldReferences[nativetypes.HistoricalRoots] = stateutil.NewRef(1)
|
|
|
|
roots := make([][32]byte, len(val))
|
|
for i, r := range val {
|
|
copy(roots[i][:], r)
|
|
}
|
|
b.historicalRoots = roots
|
|
b.markFieldAsDirty(nativetypes.HistoricalRoots)
|
|
return nil
|
|
}
|
|
|
|
// AppendHistoricalRoots for the beacon state. Appends the new value
|
|
// to the the end of list.
|
|
func (b *BeaconState) AppendHistoricalRoots(root [32]byte) error {
|
|
b.lock.Lock()
|
|
defer b.lock.Unlock()
|
|
|
|
roots := b.historicalRoots
|
|
if b.sharedFieldReferences[nativetypes.HistoricalRoots].Refs() > 1 {
|
|
roots = make([][32]byte, len(b.historicalRoots))
|
|
copy(roots, b.historicalRoots)
|
|
b.sharedFieldReferences[nativetypes.HistoricalRoots].MinusRef()
|
|
b.sharedFieldReferences[nativetypes.HistoricalRoots] = stateutil.NewRef(1)
|
|
}
|
|
|
|
b.historicalRoots = append(roots, root)
|
|
b.markFieldAsDirty(nativetypes.HistoricalRoots)
|
|
return nil
|
|
}
|
|
|
|
// Recomputes the branch up the index in the Merkle trie representation
|
|
// of the beacon state. This method performs slice reads and the caller MUST
|
|
// hold the lock before calling this method.
|
|
func (b *BeaconState) recomputeRoot(idx int) {
|
|
hashFunc := hash.CustomSHA256Hasher()
|
|
layers := b.merkleLayers
|
|
// The merkle tree structure looks as follows:
|
|
// [[r1, r2, r3, r4], [parent1, parent2], [root]]
|
|
// Using information about the index which changed, idx, we recompute
|
|
// only its branch up the tree.
|
|
currentIndex := idx
|
|
root := b.merkleLayers[0][idx]
|
|
for i := 0; i < len(layers)-1; i++ {
|
|
isLeft := currentIndex%2 == 0
|
|
neighborIdx := currentIndex ^ 1
|
|
|
|
neighbor := make([]byte, 32)
|
|
if layers[i] != nil && len(layers[i]) != 0 && neighborIdx < len(layers[i]) {
|
|
neighbor = layers[i][neighborIdx]
|
|
}
|
|
if isLeft {
|
|
parentHash := hashFunc(append(root, neighbor...))
|
|
root = parentHash[:]
|
|
} else {
|
|
parentHash := hashFunc(append(neighbor, root...))
|
|
root = parentHash[:]
|
|
}
|
|
parentIdx := currentIndex / 2
|
|
// Update the cached layers at the parent index.
|
|
layers[i+1][parentIdx] = root
|
|
currentIndex = parentIdx
|
|
}
|
|
b.merkleLayers = layers
|
|
}
|
|
|
|
func (b *BeaconState) markFieldAsDirty(field nativetypes.FieldIndex) {
|
|
b.dirtyFields[field] = true
|
|
}
|
|
|
|
// addDirtyIndices adds the relevant dirty field indices, so that they
|
|
// can be recomputed.
|
|
func (b *BeaconState) addDirtyIndices(index nativetypes.FieldIndex, indices []uint64) {
|
|
if b.rebuildTrie[index] {
|
|
return
|
|
}
|
|
totalIndicesLen := len(b.dirtyIndices[index]) + len(indices)
|
|
if totalIndicesLen > indicesLimit {
|
|
b.rebuildTrie[index] = true
|
|
b.dirtyIndices[index] = []uint64{}
|
|
} else {
|
|
b.dirtyIndices[index] = append(b.dirtyIndices[index], indices...)
|
|
}
|
|
}
|