mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-12 04:30:04 +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>
223 lines
6.7 KiB
Go
223 lines
6.7 KiB
Go
package fieldtrie
|
|
|
|
import (
|
|
"reflect"
|
|
"sync"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
|
|
pmath "github.com/prysmaticlabs/prysm/math"
|
|
)
|
|
|
|
// FieldTrie is the representation of the representative
|
|
// trie of the particular field.
|
|
type FieldTrie struct {
|
|
*sync.RWMutex
|
|
reference *stateutil.Reference
|
|
fieldLayers [][]*[32]byte
|
|
field types.BeaconStateField
|
|
dataType types.DataType
|
|
length uint64
|
|
numOfElems int
|
|
}
|
|
|
|
// NewFieldTrie is the constructor for the field trie data structure. It creates the corresponding
|
|
// trie according to the given parameters. Depending on whether the field is a basic/composite array
|
|
// which is either fixed/variable length, it will appropriately determine the trie.
|
|
func NewFieldTrie(field types.BeaconStateField, dataType types.DataType, elements interface{}, length uint64) (*FieldTrie, error) {
|
|
if elements == nil {
|
|
return &FieldTrie{
|
|
field: field,
|
|
dataType: dataType,
|
|
reference: stateutil.NewRef(1),
|
|
RWMutex: new(sync.RWMutex),
|
|
length: length,
|
|
numOfElems: 0,
|
|
}, nil
|
|
}
|
|
|
|
var fieldRoots [][32]byte
|
|
var err error
|
|
if field.Native() {
|
|
fieldRoots, err = fieldConvertersNative(field, []uint64{}, elements, true)
|
|
} else {
|
|
fieldRoots, err = fieldConverters(field, []uint64{}, elements, true)
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := validateElements(field, dataType, elements, length); err != nil {
|
|
return nil, err
|
|
}
|
|
switch dataType {
|
|
case types.BasicArray:
|
|
fl, err := stateutil.ReturnTrieLayer(fieldRoots, length)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &FieldTrie{
|
|
fieldLayers: fl,
|
|
field: field,
|
|
dataType: dataType,
|
|
reference: stateutil.NewRef(1),
|
|
RWMutex: new(sync.RWMutex),
|
|
length: length,
|
|
numOfElems: reflect.Indirect(reflect.ValueOf(elements)).Len(),
|
|
}, nil
|
|
case types.CompositeArray, types.CompressedArray:
|
|
return &FieldTrie{
|
|
fieldLayers: stateutil.ReturnTrieLayerVariable(fieldRoots, length),
|
|
field: field,
|
|
dataType: dataType,
|
|
reference: stateutil.NewRef(1),
|
|
RWMutex: new(sync.RWMutex),
|
|
length: length,
|
|
numOfElems: reflect.Indirect(reflect.ValueOf(elements)).Len(),
|
|
}, nil
|
|
default:
|
|
return nil, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(dataType).Name())
|
|
}
|
|
|
|
}
|
|
|
|
// RecomputeTrie rebuilds the affected branches in the trie according to the provided
|
|
// changed indices and elements. This recomputes the trie according to the particular
|
|
// field the trie is based on.
|
|
func (f *FieldTrie) RecomputeTrie(indices []uint64, elements interface{}) ([32]byte, error) {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
var fieldRoot [32]byte
|
|
if len(indices) == 0 {
|
|
return f.TrieRoot()
|
|
}
|
|
|
|
var fieldRoots [][32]byte
|
|
var err error
|
|
if f.field.Native() {
|
|
fieldRoots, err = fieldConvertersNative(f.field, indices, elements, false)
|
|
} else {
|
|
fieldRoots, err = fieldConverters(f.field, indices, elements, false)
|
|
}
|
|
if err != nil {
|
|
return [32]byte{}, err
|
|
}
|
|
|
|
if err := f.validateIndices(indices); err != nil {
|
|
return [32]byte{}, err
|
|
}
|
|
switch f.dataType {
|
|
case types.BasicArray:
|
|
fieldRoot, f.fieldLayers, err = stateutil.RecomputeFromLayer(fieldRoots, indices, f.fieldLayers)
|
|
if err != nil {
|
|
return [32]byte{}, err
|
|
}
|
|
f.numOfElems = reflect.Indirect(reflect.ValueOf(elements)).Len()
|
|
return fieldRoot, nil
|
|
case types.CompositeArray:
|
|
fieldRoot, f.fieldLayers, err = stateutil.RecomputeFromLayerVariable(fieldRoots, indices, f.fieldLayers)
|
|
if err != nil {
|
|
return [32]byte{}, err
|
|
}
|
|
f.numOfElems = reflect.Indirect(reflect.ValueOf(elements)).Len()
|
|
return stateutil.AddInMixin(fieldRoot, uint64(len(f.fieldLayers[0])))
|
|
case types.CompressedArray:
|
|
numOfElems, err := f.field.ElemsInChunk()
|
|
if err != nil {
|
|
return [32]byte{}, err
|
|
}
|
|
iNumOfElems, err := pmath.Int(numOfElems)
|
|
if err != nil {
|
|
return [32]byte{}, err
|
|
}
|
|
// We remove the duplicates here in order to prevent
|
|
// duplicated insertions into the trie.
|
|
newIndices := []uint64{}
|
|
indexExists := make(map[uint64]bool)
|
|
newRoots := make([][32]byte, 0, len(fieldRoots)/iNumOfElems)
|
|
for i, idx := range indices {
|
|
startIdx := idx / numOfElems
|
|
if indexExists[startIdx] {
|
|
continue
|
|
}
|
|
newIndices = append(newIndices, startIdx)
|
|
indexExists[startIdx] = true
|
|
newRoots = append(newRoots, fieldRoots[i])
|
|
}
|
|
fieldRoot, f.fieldLayers, err = stateutil.RecomputeFromLayerVariable(newRoots, newIndices, f.fieldLayers)
|
|
if err != nil {
|
|
return [32]byte{}, err
|
|
}
|
|
f.numOfElems = reflect.Indirect(reflect.ValueOf(elements)).Len()
|
|
return stateutil.AddInMixin(fieldRoot, uint64(f.numOfElems))
|
|
default:
|
|
return [32]byte{}, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(f.dataType).Name())
|
|
}
|
|
}
|
|
|
|
// CopyTrie copies the references to the elements the trie
|
|
// is built on.
|
|
func (f *FieldTrie) CopyTrie() *FieldTrie {
|
|
if f.fieldLayers == nil {
|
|
return &FieldTrie{
|
|
field: f.field,
|
|
dataType: f.dataType,
|
|
reference: stateutil.NewRef(1),
|
|
RWMutex: new(sync.RWMutex),
|
|
length: f.length,
|
|
numOfElems: f.numOfElems,
|
|
}
|
|
}
|
|
dstFieldTrie := make([][]*[32]byte, len(f.fieldLayers))
|
|
for i, layer := range f.fieldLayers {
|
|
dstFieldTrie[i] = make([]*[32]byte, len(layer))
|
|
copy(dstFieldTrie[i], layer)
|
|
}
|
|
return &FieldTrie{
|
|
fieldLayers: dstFieldTrie,
|
|
field: f.field,
|
|
dataType: f.dataType,
|
|
reference: stateutil.NewRef(1),
|
|
RWMutex: new(sync.RWMutex),
|
|
length: f.length,
|
|
numOfElems: f.numOfElems,
|
|
}
|
|
}
|
|
|
|
// TrieRoot returns the corresponding root of the trie.
|
|
func (f *FieldTrie) TrieRoot() ([32]byte, error) {
|
|
switch f.dataType {
|
|
case types.BasicArray:
|
|
return *f.fieldLayers[len(f.fieldLayers)-1][0], nil
|
|
case types.CompositeArray:
|
|
trieRoot := *f.fieldLayers[len(f.fieldLayers)-1][0]
|
|
return stateutil.AddInMixin(trieRoot, uint64(len(f.fieldLayers[0])))
|
|
case types.CompressedArray:
|
|
trieRoot := *f.fieldLayers[len(f.fieldLayers)-1][0]
|
|
return stateutil.AddInMixin(trieRoot, uint64(f.numOfElems))
|
|
default:
|
|
return [32]byte{}, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(f.dataType).Name())
|
|
}
|
|
}
|
|
|
|
// FieldReference returns the underlying field reference
|
|
// object for the trie.
|
|
func (f *FieldTrie) FieldReference() *stateutil.Reference {
|
|
return f.reference
|
|
}
|
|
|
|
// Empty checks whether the underlying field trie is
|
|
// empty or not.
|
|
func (f *FieldTrie) Empty() bool {
|
|
return f == nil || len(f.fieldLayers) == 0
|
|
}
|
|
|
|
// InsertFieldLayer manually inserts a field layer. This method
|
|
// bypasses the normal method of field computation, it is only
|
|
// meant to be used in tests.
|
|
func (f *FieldTrie) InsertFieldLayer(layer [][]*[32]byte) {
|
|
f.fieldLayers = layer
|
|
}
|