From 2a1c880673d6a120f514ceaee0abdc7bd38a5a19 Mon Sep 17 00:00:00 2001 From: terence tsao Date: Mon, 12 Apr 2021 07:23:55 -0700 Subject: [PATCH] Altair: Split state getters and setters into its own file (#8746) * Categorize getters and setters into its own file * Go fmt --- beacon-chain/state/stateV0/BUILD.bazel | 25 +- beacon-chain/state/stateV0/field_root_eth1.go | 59 - .../state/stateV0/field_root_validator.go | 89 -- beacon-chain/state/stateV0/field_trie.go | 128 +- .../state/stateV0/field_trie_helpers.go | 141 +++ beacon-chain/state/stateV0/getters.go | 1037 ----------------- ..._attestation.go => getters_attestation.go} | 62 +- beacon-chain/state/stateV0/getters_block.go | 96 ++ .../state/stateV0/getters_checkpoint.go | 160 +++ beacon-chain/state/stateV0/getters_eth1.go | 145 +++ .../{field_root_vector.go => getters_misc.go} | 150 +++ beacon-chain/state/stateV0/getters_randao.go | 81 ++ beacon-chain/state/stateV0/getters_state.go | 172 +++ .../state/stateV0/getters_validator.go | 345 ++++++ beacon-chain/state/stateV0/setters.go | 754 ------------ .../state/stateV0/setters_attestation.go | 99 ++ ...rs_test.go => setters_attestation_test.go} | 0 beacon-chain/state/stateV0/setters_block.go | 68 ++ .../state/stateV0/setters_checkpoint.go | 58 + beacon-chain/state/stateV0/setters_eth1.go | 74 ++ beacon-chain/state/stateV0/setters_misc.go | 148 +++ beacon-chain/state/stateV0/setters_randao.go | 53 + beacon-chain/state/stateV0/setters_state.go | 59 + .../state/stateV0/setters_validator.go | 230 ++++ 24 files changed, 2168 insertions(+), 2065 deletions(-) delete mode 100644 beacon-chain/state/stateV0/field_root_eth1.go delete mode 100644 beacon-chain/state/stateV0/field_root_validator.go create mode 100644 beacon-chain/state/stateV0/field_trie_helpers.go delete mode 100644 beacon-chain/state/stateV0/getters.go rename beacon-chain/state/stateV0/{field_root_attestation.go => getters_attestation.go} (51%) create mode 100644 beacon-chain/state/stateV0/getters_block.go create mode 100644 beacon-chain/state/stateV0/getters_checkpoint.go create mode 100644 beacon-chain/state/stateV0/getters_eth1.go rename beacon-chain/state/stateV0/{field_root_vector.go => getters_misc.go} (58%) create mode 100644 beacon-chain/state/stateV0/getters_randao.go create mode 100644 beacon-chain/state/stateV0/getters_state.go create mode 100644 beacon-chain/state/stateV0/getters_validator.go delete mode 100644 beacon-chain/state/stateV0/setters.go create mode 100644 beacon-chain/state/stateV0/setters_attestation.go rename beacon-chain/state/stateV0/{setters_test.go => setters_attestation_test.go} (100%) create mode 100644 beacon-chain/state/stateV0/setters_block.go create mode 100644 beacon-chain/state/stateV0/setters_checkpoint.go create mode 100644 beacon-chain/state/stateV0/setters_eth1.go create mode 100644 beacon-chain/state/stateV0/setters_misc.go create mode 100644 beacon-chain/state/stateV0/setters_randao.go create mode 100644 beacon-chain/state/stateV0/setters_state.go create mode 100644 beacon-chain/state/stateV0/setters_validator.go diff --git a/beacon-chain/state/stateV0/BUILD.bazel b/beacon-chain/state/stateV0/BUILD.bazel index ad8341c048..33a7e1a4d5 100644 --- a/beacon-chain/state/stateV0/BUILD.bazel +++ b/beacon-chain/state/stateV0/BUILD.bazel @@ -6,14 +6,25 @@ go_library( srcs = [ "cloners.go", "doc.go", - "field_root_attestation.go", - "field_root_eth1.go", - "field_root_validator.go", - "field_root_vector.go", "field_roots.go", "field_trie.go", - "getters.go", - "setters.go", + "field_trie_helpers.go", + "getters_attestation.go", + "getters_block.go", + "getters_checkpoint.go", + "getters_eth1.go", + "getters_misc.go", + "getters_randao.go", + "getters_state.go", + "getters_validator.go", + "setters_attestation.go", + "setters_block.go", + "setters_checkpoint.go", + "setters_eth1.go", + "setters_misc.go", + "setters_randao.go", + "setters_state.go", + "setters_validator.go", "state_trie.go", "types.go", "validator_getters.go", @@ -61,7 +72,7 @@ go_test( "getters_test.go", "helpers_test.go", "references_test.go", - "setters_test.go", + "setters_attestation_test.go", "state_test.go", "state_trie_test.go", "types_test.go", diff --git a/beacon-chain/state/stateV0/field_root_eth1.go b/beacon-chain/state/stateV0/field_root_eth1.go deleted file mode 100644 index a761b9b13b..0000000000 --- a/beacon-chain/state/stateV0/field_root_eth1.go +++ /dev/null @@ -1,59 +0,0 @@ -package stateV0 - -import ( - "github.com/pkg/errors" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" - "github.com/prysmaticlabs/prysm/shared/featureconfig" - "github.com/prysmaticlabs/prysm/shared/htrutils" -) - -// eth1Root computes the HashTreeRoot Merkleization of -// a BeaconBlockHeader struct according to the eth2 -// Simple Serialize specification. -func eth1Root(hasher htrutils.HashFn, eth1Data *ethpb.Eth1Data) ([32]byte, error) { - if eth1Data == nil { - return [32]byte{}, errors.New("nil eth1 data") - } - - enc := stateutil.Eth1DataEncKey(eth1Data) - if featureconfig.Get().EnableSSZCache { - if found, ok := cachedHasher.rootsCache.Get(string(enc)); ok && found != nil { - return found.([32]byte), nil - } - } - - root, err := stateutil.Eth1DataRootWithHasher(hasher, eth1Data) - if err != nil { - return [32]byte{}, err - } - - if featureconfig.Get().EnableSSZCache { - cachedHasher.rootsCache.Set(string(enc), root, 32) - } - return root, nil -} - -// eth1DataVotesRoot computes the HashTreeRoot Merkleization of -// a list of Eth1Data structs according to the eth2 -// Simple Serialize specification. -func eth1DataVotesRoot(eth1DataVotes []*ethpb.Eth1Data) ([32]byte, error) { - hashKey, err := stateutil.Eth1DatasEncKey(eth1DataVotes) - if err != nil { - return [32]byte{}, err - } - - if featureconfig.Get().EnableSSZCache { - if found, ok := cachedHasher.rootsCache.Get(string(hashKey[:])); ok && found != nil { - return found.([32]byte), nil - } - } - root, err := stateutil.Eth1DatasRoot(eth1DataVotes) - if err != nil { - return [32]byte{}, err - } - if featureconfig.Get().EnableSSZCache { - cachedHasher.rootsCache.Set(string(hashKey[:]), root, 32) - } - return root, nil -} diff --git a/beacon-chain/state/stateV0/field_root_validator.go b/beacon-chain/state/stateV0/field_root_validator.go deleted file mode 100644 index aadf3ee18d..0000000000 --- a/beacon-chain/state/stateV0/field_root_validator.go +++ /dev/null @@ -1,89 +0,0 @@ -package stateV0 - -import ( - "bytes" - "encoding/binary" - - "github.com/pkg/errors" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" - "github.com/prysmaticlabs/prysm/shared/featureconfig" - "github.com/prysmaticlabs/prysm/shared/hashutil" - "github.com/prysmaticlabs/prysm/shared/htrutils" - "github.com/prysmaticlabs/prysm/shared/params" -) - -func (h *stateRootHasher) validatorRegistryRoot(validators []*ethpb.Validator) ([32]byte, error) { - hashKeyElements := make([]byte, len(validators)*32) - roots := make([][32]byte, len(validators)) - emptyKey := hashutil.FastSum256(hashKeyElements) - hasher := hashutil.CustomSHA256Hasher() - bytesProcessed := 0 - for i := 0; i < len(validators); i++ { - val, err := h.validatorRoot(hasher, validators[i]) - if err != nil { - return [32]byte{}, errors.Wrap(err, "could not compute validators merkleization") - } - copy(hashKeyElements[bytesProcessed:bytesProcessed+32], val[:]) - roots[i] = val - bytesProcessed += 32 - } - - hashKey := hashutil.FastSum256(hashKeyElements) - if hashKey != emptyKey && h.rootsCache != nil { - if found, ok := h.rootsCache.Get(string(hashKey[:])); found != nil && ok { - return found.([32]byte), nil - } - } - - validatorsRootsRoot, err := htrutils.BitwiseMerkleizeArrays(hasher, roots, uint64(len(roots)), params.BeaconConfig().ValidatorRegistryLimit) - if err != nil { - return [32]byte{}, errors.Wrap(err, "could not compute validator registry merkleization") - } - validatorsRootsBuf := new(bytes.Buffer) - if err := binary.Write(validatorsRootsBuf, binary.LittleEndian, uint64(len(validators))); err != nil { - return [32]byte{}, errors.Wrap(err, "could not marshal validator registry length") - } - // We need to mix in the length of the slice. - var validatorsRootsBufRoot [32]byte - copy(validatorsRootsBufRoot[:], validatorsRootsBuf.Bytes()) - res := htrutils.MixInLength(validatorsRootsRoot, validatorsRootsBufRoot[:]) - if hashKey != emptyKey && h.rootsCache != nil { - h.rootsCache.Set(string(hashKey[:]), res, 32) - } - return res, nil -} - -func (h *stateRootHasher) validatorRoot(hasher htrutils.HashFn, validator *ethpb.Validator) ([32]byte, error) { - if validator == nil { - return [32]byte{}, errors.New("nil validator") - } - - enc := stateutil.ValidatorEncKey(validator) - // Check if it exists in cache: - if h.rootsCache != nil { - if found, ok := h.rootsCache.Get(string(enc)); found != nil && ok { - return found.([32]byte), nil - } - } - - valRoot, err := stateutil.ValidatorRootWithHasher(hasher, validator) - if err != nil { - return [32]byte{}, err - } - - if h.rootsCache != nil { - h.rootsCache.Set(string(enc), valRoot, 32) - } - return valRoot, nil -} - -// ValidatorRegistryRoot computes the HashTreeRoot Merkleization of -// a list of validator structs according to the eth2 -// Simple Serialize specification. -func ValidatorRegistryRoot(vals []*ethpb.Validator) ([32]byte, error) { - if featureconfig.Get().EnableSSZCache { - return cachedHasher.validatorRegistryRoot(vals) - } - return nocachedHasher.validatorRegistryRoot(vals) -} diff --git a/beacon-chain/state/stateV0/field_trie.go b/beacon-chain/state/stateV0/field_trie.go index 53e89c409f..9ce88d7bb0 100644 --- a/beacon-chain/state/stateV0/field_trie.go +++ b/beacon-chain/state/stateV0/field_trie.go @@ -1,15 +1,11 @@ package stateV0 import ( - "fmt" "reflect" "sync" "github.com/pkg/errors" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" - pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - "github.com/prysmaticlabs/prysm/shared/hashutil" ) // FieldTrie is the representation of the representative @@ -19,6 +15,7 @@ type FieldTrie struct { reference *stateutil.Reference fieldLayers [][]*[32]byte field fieldIndex + length uint64 } // NewFieldTrie is the constructor for the field trie data structure. It creates the corresponding @@ -30,6 +27,7 @@ func NewFieldTrie(field fieldIndex, elements interface{}, length uint64) (*Field field: field, reference: stateutil.NewRef(1), RWMutex: new(sync.RWMutex), + length: length, }, nil } datType, ok := fieldMap[field] @@ -40,6 +38,9 @@ func NewFieldTrie(field fieldIndex, elements interface{}, length uint64) (*Field if err != nil { return nil, err } + if err := validateElements(field, elements, length); err != nil { + return nil, err + } switch datType { case basicArray: return &FieldTrie{ @@ -47,6 +48,7 @@ func NewFieldTrie(field fieldIndex, elements interface{}, length uint64) (*Field field: field, reference: stateutil.NewRef(1), RWMutex: new(sync.RWMutex), + length: length, }, nil case compositeArray: return &FieldTrie{ @@ -54,6 +56,7 @@ func NewFieldTrie(field fieldIndex, elements interface{}, length uint64) (*Field field: field, reference: stateutil.NewRef(1), RWMutex: new(sync.RWMutex), + length: length, }, nil default: return nil, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(datType).Name()) @@ -79,6 +82,9 @@ func (f *FieldTrie) RecomputeTrie(indices []uint64, elements interface{}) ([32]b if err != nil { return [32]byte{}, err } + if err := f.validateIndices(indices); err != nil { + return [32]byte{}, err + } switch datType { case basicArray: fieldRoot, f.fieldLayers, err = stateutil.RecomputeFromLayer(fieldRoots, indices, f.fieldLayers) @@ -106,6 +112,7 @@ func (f *FieldTrie) CopyTrie() *FieldTrie { field: f.field, reference: stateutil.NewRef(1), RWMutex: new(sync.RWMutex), + length: f.length, } } dstFieldTrie := make([][]*[32]byte, len(f.fieldLayers)) @@ -118,6 +125,7 @@ func (f *FieldTrie) CopyTrie() *FieldTrie { field: f.field, reference: stateutil.NewRef(1), RWMutex: new(sync.RWMutex), + length: f.length, } } @@ -137,115 +145,3 @@ func (f *FieldTrie) TrieRoot() ([32]byte, error) { return [32]byte{}, errors.Errorf("unrecognized data type in field map: %v", reflect.TypeOf(datType).Name()) } } - -// this converts the corresponding field and the provided elements to the appropriate roots. -func fieldConverters(field fieldIndex, indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) { - switch field { - case blockRoots, stateRoots, randaoMixes: - val, ok := elements.([][]byte) - if !ok { - return nil, errors.Errorf("Wanted type of %v but got %v", - reflect.TypeOf([][]byte{}).Name(), reflect.TypeOf(elements).Name()) - } - return stateutil.HandleByteArrays(val, indices, convertAll) - case eth1DataVotes: - val, ok := elements.([]*ethpb.Eth1Data) - if !ok { - return nil, errors.Errorf("Wanted type of %v but got %v", - reflect.TypeOf([]*ethpb.Eth1Data{}).Name(), reflect.TypeOf(elements).Name()) - } - return handleEth1DataSlice(val, indices, convertAll) - case validators: - val, ok := elements.([]*ethpb.Validator) - if !ok { - return nil, errors.Errorf("Wanted type of %v but got %v", - reflect.TypeOf([]*ethpb.Validator{}).Name(), reflect.TypeOf(elements).Name()) - } - return stateutil.HandleValidatorSlice(val, indices, convertAll) - case previousEpochAttestations, currentEpochAttestations: - val, ok := elements.([]*pb.PendingAttestation) - if !ok { - return nil, errors.Errorf("Wanted type of %v but got %v", - reflect.TypeOf([]*pb.PendingAttestation{}).Name(), reflect.TypeOf(elements).Name()) - } - return handlePendingAttestation(val, indices, convertAll) - default: - return [][32]byte{}, errors.Errorf("got unsupported type of %v", reflect.TypeOf(elements).Name()) - } -} - -func handleEth1DataSlice(val []*ethpb.Eth1Data, indices []uint64, convertAll bool) ([][32]byte, error) { - length := len(indices) - if convertAll { - length = len(val) - } - roots := make([][32]byte, 0, length) - hasher := hashutil.CustomSHA256Hasher() - rootCreator := func(input *ethpb.Eth1Data) error { - newRoot, err := eth1Root(hasher, input) - if err != nil { - return err - } - roots = append(roots, newRoot) - return nil - } - if convertAll { - for i := range val { - err := rootCreator(val[i]) - if err != nil { - return nil, err - } - } - return roots, nil - } - if len(val) > 0 { - for _, idx := range indices { - if idx > uint64(len(val))-1 { - return nil, fmt.Errorf("index %d greater than number of items in eth1 data slice %d", idx, len(val)) - } - err := rootCreator(val[idx]) - if err != nil { - return nil, err - } - } - } - return roots, nil -} - -func handlePendingAttestation(val []*pb.PendingAttestation, indices []uint64, convertAll bool) ([][32]byte, error) { - length := len(indices) - if convertAll { - length = len(val) - } - roots := make([][32]byte, 0, length) - hasher := hashutil.CustomSHA256Hasher() - rootCreator := func(input *pb.PendingAttestation) error { - newRoot, err := stateutil.PendingAttRootWithHasher(hasher, input) - if err != nil { - return err - } - roots = append(roots, newRoot) - return nil - } - if convertAll { - for i := range val { - err := rootCreator(val[i]) - if err != nil { - return nil, err - } - } - return roots, nil - } - if len(val) > 0 { - for _, idx := range indices { - if idx > uint64(len(val))-1 { - return nil, fmt.Errorf("index %d greater than number of pending attestations %d", idx, len(val)) - } - err := rootCreator(val[idx]) - if err != nil { - return nil, err - } - } - } - return roots, nil -} diff --git a/beacon-chain/state/stateV0/field_trie_helpers.go b/beacon-chain/state/stateV0/field_trie_helpers.go new file mode 100644 index 0000000000..0999c3af06 --- /dev/null +++ b/beacon-chain/state/stateV0/field_trie_helpers.go @@ -0,0 +1,141 @@ +package stateV0 + +import ( + "fmt" + "reflect" + + "github.com/pkg/errors" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" + pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/shared/hashutil" +) + +func (f *FieldTrie) validateIndices(idxs []uint64) error { + for _, idx := range idxs { + if idx >= f.length { + return errors.Errorf("invalid index for field %s: %d >= length %d", f.field.String(), idx, f.length) + } + } + return nil +} + +func validateElements(field fieldIndex, elements interface{}, length uint64) error { + val := reflect.ValueOf(elements) + if val.Len() > int(length) { + return errors.Errorf("elements length is larger than expected for field %s: %d > %d", field.String(), val.Len(), length) + } + return nil +} + +// this converts the corresponding field and the provided elements to the appropriate roots. +func fieldConverters(field fieldIndex, indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) { + switch field { + case blockRoots, stateRoots, randaoMixes: + val, ok := elements.([][]byte) + if !ok { + return nil, errors.Errorf("Wanted type of %v but got %v", + reflect.TypeOf([][]byte{}).Name(), reflect.TypeOf(elements).Name()) + } + return stateutil.HandleByteArrays(val, indices, convertAll) + case eth1DataVotes: + val, ok := elements.([]*ethpb.Eth1Data) + if !ok { + return nil, errors.Errorf("Wanted type of %v but got %v", + reflect.TypeOf([]*ethpb.Eth1Data{}).Name(), reflect.TypeOf(elements).Name()) + } + return handleEth1DataSlice(val, indices, convertAll) + case validators: + val, ok := elements.([]*ethpb.Validator) + if !ok { + return nil, errors.Errorf("Wanted type of %v but got %v", + reflect.TypeOf([]*ethpb.Validator{}).Name(), reflect.TypeOf(elements).Name()) + } + return stateutil.HandleValidatorSlice(val, indices, convertAll) + case previousEpochAttestations, currentEpochAttestations: + val, ok := elements.([]*pb.PendingAttestation) + if !ok { + return nil, errors.Errorf("Wanted type of %v but got %v", + reflect.TypeOf([]*pb.PendingAttestation{}).Name(), reflect.TypeOf(elements).Name()) + } + return handlePendingAttestation(val, indices, convertAll) + default: + return [][32]byte{}, errors.Errorf("got unsupported type of %v", reflect.TypeOf(elements).Name()) + } +} + +func handleEth1DataSlice(val []*ethpb.Eth1Data, indices []uint64, convertAll bool) ([][32]byte, error) { + length := len(indices) + if convertAll { + length = len(val) + } + roots := make([][32]byte, 0, length) + hasher := hashutil.CustomSHA256Hasher() + rootCreator := func(input *ethpb.Eth1Data) error { + newRoot, err := eth1Root(hasher, input) + if err != nil { + return err + } + roots = append(roots, newRoot) + return nil + } + if convertAll { + for i := range val { + err := rootCreator(val[i]) + if err != nil { + return nil, err + } + } + return roots, nil + } + if len(val) > 0 { + for _, idx := range indices { + if idx > uint64(len(val))-1 { + return nil, fmt.Errorf("index %d greater than number of items in eth1 data slice %d", idx, len(val)) + } + err := rootCreator(val[idx]) + if err != nil { + return nil, err + } + } + } + return roots, nil +} + +func handlePendingAttestation(val []*pb.PendingAttestation, indices []uint64, convertAll bool) ([][32]byte, error) { + length := len(indices) + if convertAll { + length = len(val) + } + roots := make([][32]byte, 0, length) + hasher := hashutil.CustomSHA256Hasher() + rootCreator := func(input *pb.PendingAttestation) error { + newRoot, err := stateutil.PendingAttRootWithHasher(hasher, input) + if err != nil { + return err + } + roots = append(roots, newRoot) + return nil + } + if convertAll { + for i := range val { + err := rootCreator(val[i]) + if err != nil { + return nil, err + } + } + return roots, nil + } + if len(val) > 0 { + for _, idx := range indices { + if idx > uint64(len(val))-1 { + return nil, fmt.Errorf("index %d greater than number of pending attestations %d", idx, len(val)) + } + err := rootCreator(val[idx]) + if err != nil { + return nil, err + } + } + } + return roots, nil +} diff --git a/beacon-chain/state/stateV0/getters.go b/beacon-chain/state/stateV0/getters.go deleted file mode 100644 index 8926ca9293..0000000000 --- a/beacon-chain/state/stateV0/getters.go +++ /dev/null @@ -1,1037 +0,0 @@ -package stateV0 - -import ( - "bytes" - "errors" - "fmt" - - types "github.com/prysmaticlabs/eth2-types" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/go-bitfield" - iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" - pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - "github.com/prysmaticlabs/prysm/shared/bytesutil" - "github.com/prysmaticlabs/prysm/shared/params" -) - -// InnerStateUnsafe returns the pointer value of the underlying -// beacon state proto object, bypassing immutability. Use with care. -func (b *BeaconState) InnerStateUnsafe() interface{} { - if b == nil { - return nil - } - return b.state -} - -// CloneInnerState the beacon state into a protobuf for usage. -func (b *BeaconState) CloneInnerState() interface{} { - if b == nil || b.state == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - return &pbp2p.BeaconState{ - GenesisTime: b.genesisTime(), - GenesisValidatorsRoot: b.genesisValidatorRoot(), - Slot: b.slot(), - Fork: b.fork(), - LatestBlockHeader: b.latestBlockHeader(), - BlockRoots: b.blockRoots(), - StateRoots: b.stateRoots(), - HistoricalRoots: b.historicalRoots(), - Eth1Data: b.eth1Data(), - Eth1DataVotes: b.eth1DataVotes(), - Eth1DepositIndex: b.eth1DepositIndex(), - Validators: b.validators(), - Balances: b.balances(), - RandaoMixes: b.randaoMixes(), - Slashings: b.slashings(), - PreviousEpochAttestations: b.previousEpochAttestations(), - CurrentEpochAttestations: b.currentEpochAttestations(), - JustificationBits: b.justificationBits(), - PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint(), - CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint(), - FinalizedCheckpoint: b.finalizedCheckpoint(), - } -} - -// hasInnerState detects if the internal reference to the state data structure -// is populated correctly. Returns false if nil. -func (b *BeaconState) hasInnerState() bool { - return b != nil && b.state != nil -} - -// GenesisTime of the beacon state as a uint64. -func (b *BeaconState) GenesisTime() uint64 { - if !b.hasInnerState() { - return 0 - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.genesisTime() -} - -// genesisTime of the beacon state as a uint64. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) genesisTime() uint64 { - if !b.hasInnerState() { - return 0 - } - - return b.state.GenesisTime -} - -// GenesisValidatorRoot of the beacon state. -func (b *BeaconState) GenesisValidatorRoot() []byte { - if !b.hasInnerState() { - return nil - } - if b.state.GenesisValidatorsRoot == nil { - return params.BeaconConfig().ZeroHash[:] - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.genesisValidatorRoot() -} - -// genesisValidatorRoot of the beacon state. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) genesisValidatorRoot() []byte { - if !b.hasInnerState() { - return nil - } - if b.state.GenesisValidatorsRoot == nil { - return params.BeaconConfig().ZeroHash[:] - } - - root := make([]byte, 32) - copy(root, b.state.GenesisValidatorsRoot) - return root -} - -// Slot of the current beacon chain state. -func (b *BeaconState) Slot() types.Slot { - if !b.hasInnerState() { - return 0 - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.slot() -} - -// slot of the current beacon chain state. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) slot() types.Slot { - if !b.hasInnerState() { - return 0 - } - - return b.state.Slot -} - -// Fork version of the beacon chain. -func (b *BeaconState) Fork() *pbp2p.Fork { - if !b.hasInnerState() { - return nil - } - if b.state.Fork == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.fork() -} - -// fork version of the beacon chain. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) fork() *pbp2p.Fork { - if !b.hasInnerState() { - return nil - } - if b.state.Fork == nil { - return nil - } - - prevVersion := make([]byte, len(b.state.Fork.PreviousVersion)) - copy(prevVersion, b.state.Fork.PreviousVersion) - currVersion := make([]byte, len(b.state.Fork.CurrentVersion)) - copy(currVersion, b.state.Fork.CurrentVersion) - return &pbp2p.Fork{ - PreviousVersion: prevVersion, - CurrentVersion: currVersion, - Epoch: b.state.Fork.Epoch, - } -} - -// LatestBlockHeader stored within the beacon state. -func (b *BeaconState) LatestBlockHeader() *ethpb.BeaconBlockHeader { - if !b.hasInnerState() { - return nil - } - if b.state.LatestBlockHeader == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.latestBlockHeader() -} - -// latestBlockHeader stored within the beacon state. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) latestBlockHeader() *ethpb.BeaconBlockHeader { - if !b.hasInnerState() { - return nil - } - if b.state.LatestBlockHeader == nil { - return nil - } - - hdr := ðpb.BeaconBlockHeader{ - Slot: b.state.LatestBlockHeader.Slot, - ProposerIndex: b.state.LatestBlockHeader.ProposerIndex, - } - - parentRoot := make([]byte, len(b.state.LatestBlockHeader.ParentRoot)) - bodyRoot := make([]byte, len(b.state.LatestBlockHeader.BodyRoot)) - stateRoot := make([]byte, len(b.state.LatestBlockHeader.StateRoot)) - - copy(parentRoot, b.state.LatestBlockHeader.ParentRoot) - copy(bodyRoot, b.state.LatestBlockHeader.BodyRoot) - copy(stateRoot, b.state.LatestBlockHeader.StateRoot) - hdr.ParentRoot = parentRoot - hdr.BodyRoot = bodyRoot - hdr.StateRoot = stateRoot - return hdr -} - -// BlockRoots kept track of in the beacon state. -func (b *BeaconState) BlockRoots() [][]byte { - if !b.hasInnerState() { - return nil - } - if b.state.BlockRoots == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.blockRoots() -} - -// blockRoots kept track of in the beacon state. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) blockRoots() [][]byte { - if !b.hasInnerState() { - return nil - } - return b.safeCopy2DByteSlice(b.state.BlockRoots) -} - -// BlockRootAtIndex retrieves a specific block root based on an -// input index value. -func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) { - if !b.hasInnerState() { - return nil, ErrNilInnerState - } - if b.state.BlockRoots == nil { - return nil, nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.blockRootAtIndex(idx) -} - -// blockRootAtIndex retrieves a specific block root based on an -// input index value. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) blockRootAtIndex(idx uint64) ([]byte, error) { - if !b.hasInnerState() { - return nil, ErrNilInnerState - } - return b.safeCopyBytesAtIndex(b.state.BlockRoots, idx) -} - -// StateRoots kept track of in the beacon state. -func (b *BeaconState) StateRoots() [][]byte { - if !b.hasInnerState() { - return nil - } - if b.state.StateRoots == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.stateRoots() -} - -// StateRoots kept track of in the beacon state. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) stateRoots() [][]byte { - if !b.hasInnerState() { - return nil - } - return b.safeCopy2DByteSlice(b.state.StateRoots) -} - -// StateRootAtIndex retrieves a specific state root based on an -// input index value. -func (b *BeaconState) StateRootAtIndex(idx uint64) ([]byte, error) { - if !b.hasInnerState() { - return nil, ErrNilInnerState - } - if b.state.StateRoots == nil { - return nil, nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.stateRootAtIndex(idx) -} - -// stateRootAtIndex retrieves a specific state root based on an -// input index value. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) stateRootAtIndex(idx uint64) ([]byte, error) { - if !b.hasInnerState() { - return nil, ErrNilInnerState - } - return b.safeCopyBytesAtIndex(b.state.StateRoots, idx) -} - -// HistoricalRoots based on epochs stored in the beacon state. -func (b *BeaconState) HistoricalRoots() [][]byte { - if !b.hasInnerState() { - return nil - } - if b.state.HistoricalRoots == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.historicalRoots() -} - -// historicalRoots based on epochs stored in the beacon state. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) historicalRoots() [][]byte { - if !b.hasInnerState() { - return nil - } - return b.safeCopy2DByteSlice(b.state.HistoricalRoots) -} - -// Eth1Data corresponding to the proof-of-work chain information stored in the beacon state. -func (b *BeaconState) Eth1Data() *ethpb.Eth1Data { - if !b.hasInnerState() { - return nil - } - if b.state.Eth1Data == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.eth1Data() -} - -// eth1Data corresponding to the proof-of-work chain information stored in the beacon state. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) eth1Data() *ethpb.Eth1Data { - if !b.hasInnerState() { - return nil - } - if b.state.Eth1Data == nil { - return nil - } - - return CopyETH1Data(b.state.Eth1Data) -} - -// Eth1DataVotes corresponds to votes from eth2 on the canonical proof-of-work chain -// data retrieved from eth1. -func (b *BeaconState) Eth1DataVotes() []*ethpb.Eth1Data { - if !b.hasInnerState() { - return nil - } - if b.state.Eth1DataVotes == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.eth1DataVotes() -} - -// eth1DataVotes corresponds to votes from eth2 on the canonical proof-of-work chain -// data retrieved from eth1. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) eth1DataVotes() []*ethpb.Eth1Data { - if !b.hasInnerState() { - return nil - } - if b.state.Eth1DataVotes == nil { - return nil - } - - res := make([]*ethpb.Eth1Data, len(b.state.Eth1DataVotes)) - for i := 0; i < len(res); i++ { - res[i] = CopyETH1Data(b.state.Eth1DataVotes[i]) - } - return res -} - -// Eth1DepositIndex corresponds to the index of the deposit made to the -// validator deposit contract at the time of this state's eth1 data. -func (b *BeaconState) Eth1DepositIndex() uint64 { - if !b.hasInnerState() { - return 0 - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.eth1DepositIndex() -} - -// eth1DepositIndex corresponds to the index of the deposit made to the -// validator deposit contract at the time of this state's eth1 data. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) eth1DepositIndex() uint64 { - if !b.hasInnerState() { - return 0 - } - - return b.state.Eth1DepositIndex -} - -// Validators participating in consensus on the beacon chain. -func (b *BeaconState) Validators() []*ethpb.Validator { - if !b.hasInnerState() { - return nil - } - if b.state.Validators == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.validators() -} - -// validators participating in consensus on the beacon chain. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) validators() []*ethpb.Validator { - if !b.hasInnerState() { - return nil - } - if b.state.Validators == nil { - return nil - } - - res := make([]*ethpb.Validator, len(b.state.Validators)) - for i := 0; i < len(res); i++ { - val := b.state.Validators[i] - if val == nil { - continue - } - res[i] = CopyValidator(val) - } - return res -} - -// references of validators participating in consensus on the beacon chain. -// This assumes that a lock is already held on BeaconState. This does not -// copy fully and instead just copies the reference. -func (b *BeaconState) validatorsReferences() []*ethpb.Validator { - if !b.hasInnerState() { - return nil - } - if b.state.Validators == nil { - return nil - } - - res := make([]*ethpb.Validator, len(b.state.Validators)) - for i := 0; i < len(res); i++ { - validator := b.state.Validators[i] - if validator == nil { - continue - } - // copy validator reference instead. - res[i] = validator - } - return res -} - -// ValidatorAtIndex is the validator at the provided index. -func (b *BeaconState) ValidatorAtIndex(idx types.ValidatorIndex) (*ethpb.Validator, error) { - if !b.hasInnerState() { - return nil, ErrNilInnerState - } - if b.state.Validators == nil { - return ðpb.Validator{}, nil - } - if uint64(len(b.state.Validators)) <= uint64(idx) { - return nil, fmt.Errorf("index %d out of range", idx) - } - - b.lock.RLock() - defer b.lock.RUnlock() - - val := b.state.Validators[idx] - return CopyValidator(val), nil -} - -// ValidatorAtIndexReadOnly is the validator at the provided index. This method -// doesn't clone the validator. -func (b *BeaconState) ValidatorAtIndexReadOnly(idx types.ValidatorIndex) (iface.ReadOnlyValidator, error) { - if !b.hasInnerState() { - return ReadOnlyValidator{}, ErrNilInnerState - } - if b.state.Validators == nil { - return ReadOnlyValidator{}, nil - } - if uint64(len(b.state.Validators)) <= uint64(idx) { - return ReadOnlyValidator{}, fmt.Errorf("index %d out of range", idx) - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return ReadOnlyValidator{b.state.Validators[idx]}, nil -} - -// ValidatorIndexByPubkey returns a given validator by its 48-byte public key. -func (b *BeaconState) ValidatorIndexByPubkey(key [48]byte) (types.ValidatorIndex, bool) { - if b == nil || b.valMapHandler == nil || b.valMapHandler.IsNil() { - return 0, false - } - b.lock.RLock() - defer b.lock.RUnlock() - idx, ok := b.valMapHandler.Get(key) - return idx, ok -} - -// PubkeyAtIndex returns the pubkey at the given -// validator index. -func (b *BeaconState) PubkeyAtIndex(idx types.ValidatorIndex) [48]byte { - if !b.hasInnerState() { - return [48]byte{} - } - if uint64(idx) >= uint64(len(b.state.Validators)) { - return [48]byte{} - } - b.lock.RLock() - defer b.lock.RUnlock() - - if b.state.Validators[idx] == nil { - return [48]byte{} - } - return bytesutil.ToBytes48(b.state.Validators[idx].PublicKey) -} - -// NumValidators returns the size of the validator registry. -func (b *BeaconState) NumValidators() int { - if !b.hasInnerState() { - return 0 - } - b.lock.RLock() - defer b.lock.RUnlock() - - return len(b.state.Validators) -} - -// ReadFromEveryValidator reads values from every validator and applies it to the provided function. -// Warning: This method is potentially unsafe, as it exposes the actual validator registry. -func (b *BeaconState) ReadFromEveryValidator(f func(idx int, val iface.ReadOnlyValidator) error) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - if b.state.Validators == nil { - return errors.New("nil validators in state") - } - b.lock.RLock() - validators := b.state.Validators - b.lock.RUnlock() - - for i, v := range validators { - err := f(i, ReadOnlyValidator{validator: v}) - if err != nil { - return err - } - } - return nil -} - -// Balances of validators participating in consensus on the beacon chain. -func (b *BeaconState) Balances() []uint64 { - if !b.hasInnerState() { - return nil - } - if b.state.Balances == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.balances() -} - -// balances of validators participating in consensus on the beacon chain. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) balances() []uint64 { - if !b.hasInnerState() { - return nil - } - if b.state.Balances == nil { - return nil - } - - res := make([]uint64, len(b.state.Balances)) - copy(res, b.state.Balances) - return res -} - -// BalanceAtIndex of validator with the provided index. -func (b *BeaconState) BalanceAtIndex(idx types.ValidatorIndex) (uint64, error) { - if !b.hasInnerState() { - return 0, ErrNilInnerState - } - if b.state.Balances == nil { - return 0, nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - if uint64(len(b.state.Balances)) <= uint64(idx) { - return 0, fmt.Errorf("index of %d does not exist", idx) - } - return b.state.Balances[idx], nil -} - -// BalancesLength returns the length of the balances slice. -func (b *BeaconState) BalancesLength() int { - if !b.hasInnerState() { - return 0 - } - if b.state.Balances == nil { - return 0 - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.balancesLength() -} - -// balancesLength returns the length of the balances slice. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) balancesLength() int { - if !b.hasInnerState() { - return 0 - } - if b.state.Balances == nil { - return 0 - } - - return len(b.state.Balances) -} - -// RandaoMixes of block proposers on the beacon chain. -func (b *BeaconState) RandaoMixes() [][]byte { - if !b.hasInnerState() { - return nil - } - if b.state.RandaoMixes == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.randaoMixes() -} - -// randaoMixes of block proposers on the beacon chain. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) randaoMixes() [][]byte { - if !b.hasInnerState() { - return nil - } - - return b.safeCopy2DByteSlice(b.state.RandaoMixes) -} - -// RandaoMixAtIndex retrieves a specific block root based on an -// input index value. -func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) { - if !b.hasInnerState() { - return nil, ErrNilInnerState - } - if b.state.RandaoMixes == nil { - return nil, nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.randaoMixAtIndex(idx) -} - -// randaoMixAtIndex retrieves a specific block root based on an -// input index value. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) randaoMixAtIndex(idx uint64) ([]byte, error) { - if !b.hasInnerState() { - return nil, ErrNilInnerState - } - - return b.safeCopyBytesAtIndex(b.state.RandaoMixes, idx) -} - -// RandaoMixesLength returns the length of the randao mixes slice. -func (b *BeaconState) RandaoMixesLength() int { - if !b.hasInnerState() { - return 0 - } - if b.state.RandaoMixes == nil { - return 0 - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.randaoMixesLength() -} - -// randaoMixesLength returns the length of the randao mixes slice. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) randaoMixesLength() int { - if !b.hasInnerState() { - return 0 - } - if b.state.RandaoMixes == nil { - return 0 - } - - return len(b.state.RandaoMixes) -} - -// Slashings of validators on the beacon chain. -func (b *BeaconState) Slashings() []uint64 { - if !b.hasInnerState() { - return nil - } - if b.state.Slashings == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.slashings() -} - -// slashings of validators on the beacon chain. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) slashings() []uint64 { - if !b.hasInnerState() { - return nil - } - if b.state.Slashings == nil { - return nil - } - - res := make([]uint64, len(b.state.Slashings)) - copy(res, b.state.Slashings) - return res -} - -// PreviousEpochAttestations corresponding to blocks on the beacon chain. -func (b *BeaconState) PreviousEpochAttestations() ([]*pbp2p.PendingAttestation, error) { - if !b.hasInnerState() { - return nil, nil - } - if b.state.PreviousEpochAttestations == nil { - return nil, nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.previousEpochAttestations(), nil -} - -// previousEpochAttestations corresponding to blocks on the beacon chain. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) previousEpochAttestations() []*pbp2p.PendingAttestation { - if !b.hasInnerState() { - return nil - } - - return b.safeCopyPendingAttestationSlice(b.state.PreviousEpochAttestations) -} - -// CurrentEpochAttestations corresponding to blocks on the beacon chain. -func (b *BeaconState) CurrentEpochAttestations() ([]*pbp2p.PendingAttestation, error) { - if !b.hasInnerState() { - return nil, nil - } - if b.state.CurrentEpochAttestations == nil { - return nil, nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.currentEpochAttestations(), nil -} - -// currentEpochAttestations corresponding to blocks on the beacon chain. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) currentEpochAttestations() []*pbp2p.PendingAttestation { - if !b.hasInnerState() { - return nil - } - - return b.safeCopyPendingAttestationSlice(b.state.CurrentEpochAttestations) -} - -// JustificationBits marking which epochs have been justified in the beacon chain. -func (b *BeaconState) JustificationBits() bitfield.Bitvector4 { - if !b.hasInnerState() { - return nil - } - if b.state.JustificationBits == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.justificationBits() -} - -// justificationBits marking which epochs have been justified in the beacon chain. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) justificationBits() bitfield.Bitvector4 { - if !b.hasInnerState() { - return nil - } - if b.state.JustificationBits == nil { - return nil - } - - res := make([]byte, len(b.state.JustificationBits.Bytes())) - copy(res, b.state.JustificationBits.Bytes()) - return res -} - -// PreviousJustifiedCheckpoint denoting an epoch and block root. -func (b *BeaconState) PreviousJustifiedCheckpoint() *ethpb.Checkpoint { - if !b.hasInnerState() { - return nil - } - if b.state.PreviousJustifiedCheckpoint == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.previousJustifiedCheckpoint() -} - -// previousJustifiedCheckpoint denoting an epoch and block root. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) previousJustifiedCheckpoint() *ethpb.Checkpoint { - if !b.hasInnerState() { - return nil - } - - return b.safeCopyCheckpoint(b.state.PreviousJustifiedCheckpoint) -} - -// CurrentJustifiedCheckpoint denoting an epoch and block root. -func (b *BeaconState) CurrentJustifiedCheckpoint() *ethpb.Checkpoint { - if !b.hasInnerState() { - return nil - } - if b.state.CurrentJustifiedCheckpoint == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.currentJustifiedCheckpoint() -} - -// currentJustifiedCheckpoint denoting an epoch and block root. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) currentJustifiedCheckpoint() *ethpb.Checkpoint { - if !b.hasInnerState() { - return nil - } - - return b.safeCopyCheckpoint(b.state.CurrentJustifiedCheckpoint) -} - -// MatchCurrentJustifiedCheckpoint returns true if input justified checkpoint matches -// the current justified checkpoint in state. -func (b *BeaconState) MatchCurrentJustifiedCheckpoint(c *ethpb.Checkpoint) bool { - if !b.hasInnerState() { - return false - } - if b.state.CurrentJustifiedCheckpoint == nil { - return false - } - - if c.Epoch != b.state.CurrentJustifiedCheckpoint.Epoch { - return false - } - return bytes.Equal(c.Root, b.state.CurrentJustifiedCheckpoint.Root) -} - -// MatchPreviousJustifiedCheckpoint returns true if the input justified checkpoint matches -// the previous justified checkpoint in state. -func (b *BeaconState) MatchPreviousJustifiedCheckpoint(c *ethpb.Checkpoint) bool { - if !b.hasInnerState() { - return false - } - if b.state.PreviousJustifiedCheckpoint == nil { - return false - } - - if c.Epoch != b.state.PreviousJustifiedCheckpoint.Epoch { - return false - } - return bytes.Equal(c.Root, b.state.PreviousJustifiedCheckpoint.Root) -} - -// FinalizedCheckpoint denoting an epoch and block root. -func (b *BeaconState) FinalizedCheckpoint() *ethpb.Checkpoint { - if !b.hasInnerState() { - return nil - } - if b.state.FinalizedCheckpoint == nil { - return nil - } - - b.lock.RLock() - defer b.lock.RUnlock() - - return b.finalizedCheckpoint() -} - -// finalizedCheckpoint denoting an epoch and block root. -// This assumes that a lock is already held on BeaconState. -func (b *BeaconState) finalizedCheckpoint() *ethpb.Checkpoint { - if !b.hasInnerState() { - return nil - } - - return b.safeCopyCheckpoint(b.state.FinalizedCheckpoint) -} - -// FinalizedCheckpointEpoch returns the epoch value of the finalized checkpoint. -func (b *BeaconState) FinalizedCheckpointEpoch() types.Epoch { - if !b.hasInnerState() { - return 0 - } - if b.state.FinalizedCheckpoint == nil { - return 0 - } - b.lock.RLock() - defer b.lock.RUnlock() - - return b.state.FinalizedCheckpoint.Epoch -} - -func (b *BeaconState) safeCopy2DByteSlice(input [][]byte) [][]byte { - if input == nil { - return nil - } - - dst := make([][]byte, len(input)) - for i, r := range input { - tmp := make([]byte, len(r)) - copy(tmp, r) - dst[i] = tmp - } - return dst -} - -func (b *BeaconState) safeCopyBytesAtIndex(input [][]byte, idx uint64) ([]byte, error) { - if input == nil { - return nil, nil - } - - if uint64(len(input)) <= idx { - return nil, fmt.Errorf("index %d out of range", idx) - } - root := make([]byte, 32) - copy(root, input[idx]) - return root, nil -} - -func (b *BeaconState) safeCopyPendingAttestationSlice(input []*pbp2p.PendingAttestation) []*pbp2p.PendingAttestation { - if input == nil { - return nil - } - - res := make([]*pbp2p.PendingAttestation, len(input)) - for i := 0; i < len(res); i++ { - res[i] = CopyPendingAttestation(input[i]) - } - return res -} - -func (b *BeaconState) safeCopyCheckpoint(input *ethpb.Checkpoint) *ethpb.Checkpoint { - if input == nil { - return nil - } - - return CopyCheckpoint(input) -} - -// MarshalSSZ marshals the underlying beacon state to bytes. -func (b *BeaconState) MarshalSSZ() ([]byte, error) { - if !b.hasInnerState() { - return nil, errors.New("nil beacon state") - } - return b.state.MarshalSSZ() -} - -// ProtobufBeaconState transforms an input into beacon state in the form of protobuf. -// Error is returned if the input is not type protobuf beacon state. -func ProtobufBeaconState(s interface{}) (*pbp2p.BeaconState, error) { - pbState, ok := s.(*pbp2p.BeaconState) - if !ok { - return nil, errors.New("input is not type pb.BeaconState") - } - return pbState, nil -} diff --git a/beacon-chain/state/stateV0/field_root_attestation.go b/beacon-chain/state/stateV0/getters_attestation.go similarity index 51% rename from beacon-chain/state/stateV0/field_root_attestation.go rename to beacon-chain/state/stateV0/getters_attestation.go index c1b8036b05..caeefa7a06 100644 --- a/beacon-chain/state/stateV0/field_root_attestation.go +++ b/beacon-chain/state/stateV0/getters_attestation.go @@ -3,16 +3,72 @@ package stateV0 import ( "bytes" "encoding/binary" + "fmt" "github.com/pkg/errors" "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" - pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/hashutil" "github.com/prysmaticlabs/prysm/shared/htrutils" "github.com/prysmaticlabs/prysm/shared/params" ) -func (h *stateRootHasher) epochAttestationsRoot(atts []*pb.PendingAttestation) ([32]byte, error) { +// PreviousEpochAttestations corresponding to blocks on the beacon chain. +func (b *BeaconState) PreviousEpochAttestations() ([]*pbp2p.PendingAttestation, error) { + if !b.hasInnerState() { + return nil, nil + } + if b.state.PreviousEpochAttestations == nil { + return nil, nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.previousEpochAttestations(), nil +} + +// previousEpochAttestations corresponding to blocks on the beacon chain. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) previousEpochAttestations() []*pbp2p.PendingAttestation { + if !b.hasInnerState() { + return nil + } + + return b.safeCopyPendingAttestationSlice(b.state.PreviousEpochAttestations) +} + +// CurrentEpochAttestations corresponding to blocks on the beacon chain. +func (b *BeaconState) CurrentEpochAttestations() ([]*pbp2p.PendingAttestation, error) { + if !b.hasInnerState() { + return nil, nil + } + if b.state.CurrentEpochAttestations == nil { + return nil, nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.currentEpochAttestations(), nil +} + +// currentEpochAttestations corresponding to blocks on the beacon chain. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) currentEpochAttestations() []*pbp2p.PendingAttestation { + if !b.hasInnerState() { + return nil + } + + return b.safeCopyPendingAttestationSlice(b.state.CurrentEpochAttestations) +} + +func (h *stateRootHasher) epochAttestationsRoot(atts []*pbp2p.PendingAttestation) ([32]byte, error) { + max := uint64(params.BeaconConfig().SlotsPerEpoch) * params.BeaconConfig().MaxAttestations + if uint64(len(atts)) > max { + return [32]byte{}, fmt.Errorf("epoch attestation exceeds max length %d", max) + } + hasher := hashutil.CustomSHA256Hasher() roots := make([][]byte, len(atts)) for i := 0; i < len(atts); i++ { @@ -43,7 +99,7 @@ func (h *stateRootHasher) epochAttestationsRoot(atts []*pb.PendingAttestation) ( return res, nil } -func (h *stateRootHasher) pendingAttestationRoot(hasher htrutils.HashFn, att *pb.PendingAttestation) ([32]byte, error) { +func (h *stateRootHasher) pendingAttestationRoot(hasher htrutils.HashFn, att *pbp2p.PendingAttestation) ([32]byte, error) { if att == nil { return [32]byte{}, errors.New("nil pending attestation") } diff --git a/beacon-chain/state/stateV0/getters_block.go b/beacon-chain/state/stateV0/getters_block.go new file mode 100644 index 0000000000..616d72644c --- /dev/null +++ b/beacon-chain/state/stateV0/getters_block.go @@ -0,0 +1,96 @@ +package stateV0 + +import ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + +// LatestBlockHeader stored within the beacon state. +func (b *BeaconState) LatestBlockHeader() *ethpb.BeaconBlockHeader { + if !b.hasInnerState() { + return nil + } + if b.state.LatestBlockHeader == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.latestBlockHeader() +} + +// latestBlockHeader stored within the beacon state. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) latestBlockHeader() *ethpb.BeaconBlockHeader { + if !b.hasInnerState() { + return nil + } + if b.state.LatestBlockHeader == nil { + return nil + } + + hdr := ðpb.BeaconBlockHeader{ + Slot: b.state.LatestBlockHeader.Slot, + ProposerIndex: b.state.LatestBlockHeader.ProposerIndex, + } + + parentRoot := make([]byte, len(b.state.LatestBlockHeader.ParentRoot)) + bodyRoot := make([]byte, len(b.state.LatestBlockHeader.BodyRoot)) + stateRoot := make([]byte, len(b.state.LatestBlockHeader.StateRoot)) + + copy(parentRoot, b.state.LatestBlockHeader.ParentRoot) + copy(bodyRoot, b.state.LatestBlockHeader.BodyRoot) + copy(stateRoot, b.state.LatestBlockHeader.StateRoot) + hdr.ParentRoot = parentRoot + hdr.BodyRoot = bodyRoot + hdr.StateRoot = stateRoot + return hdr +} + +// BlockRoots kept track of in the beacon state. +func (b *BeaconState) BlockRoots() [][]byte { + if !b.hasInnerState() { + return nil + } + if b.state.BlockRoots == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.blockRoots() +} + +// blockRoots kept track of in the beacon state. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) blockRoots() [][]byte { + if !b.hasInnerState() { + return nil + } + return b.safeCopy2DByteSlice(b.state.BlockRoots) +} + +// BlockRootAtIndex retrieves a specific block root based on an +// input index value. +func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) { + if !b.hasInnerState() { + return nil, ErrNilInnerState + } + if b.state.BlockRoots == nil { + return nil, nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.blockRootAtIndex(idx) +} + +// blockRootAtIndex retrieves a specific block root based on an +// input index value. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) blockRootAtIndex(idx uint64) ([]byte, error) { + if !b.hasInnerState() { + return nil, ErrNilInnerState + } + return b.safeCopyBytesAtIndex(b.state.BlockRoots, idx) +} diff --git a/beacon-chain/state/stateV0/getters_checkpoint.go b/beacon-chain/state/stateV0/getters_checkpoint.go new file mode 100644 index 0000000000..fe5a125846 --- /dev/null +++ b/beacon-chain/state/stateV0/getters_checkpoint.go @@ -0,0 +1,160 @@ +package stateV0 + +import ( + "bytes" + + types "github.com/prysmaticlabs/eth2-types" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/go-bitfield" +) + +// JustificationBits marking which epochs have been justified in the beacon chain. +func (b *BeaconState) JustificationBits() bitfield.Bitvector4 { + if !b.hasInnerState() { + return nil + } + if b.state.JustificationBits == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.justificationBits() +} + +// justificationBits marking which epochs have been justified in the beacon chain. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) justificationBits() bitfield.Bitvector4 { + if !b.hasInnerState() { + return nil + } + if b.state.JustificationBits == nil { + return nil + } + + res := make([]byte, len(b.state.JustificationBits.Bytes())) + copy(res, b.state.JustificationBits.Bytes()) + return res +} + +// PreviousJustifiedCheckpoint denoting an epoch and block root. +func (b *BeaconState) PreviousJustifiedCheckpoint() *ethpb.Checkpoint { + if !b.hasInnerState() { + return nil + } + if b.state.PreviousJustifiedCheckpoint == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.previousJustifiedCheckpoint() +} + +// previousJustifiedCheckpoint denoting an epoch and block root. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) previousJustifiedCheckpoint() *ethpb.Checkpoint { + if !b.hasInnerState() { + return nil + } + + return b.safeCopyCheckpoint(b.state.PreviousJustifiedCheckpoint) +} + +// CurrentJustifiedCheckpoint denoting an epoch and block root. +func (b *BeaconState) CurrentJustifiedCheckpoint() *ethpb.Checkpoint { + if !b.hasInnerState() { + return nil + } + if b.state.CurrentJustifiedCheckpoint == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.currentJustifiedCheckpoint() +} + +// currentJustifiedCheckpoint denoting an epoch and block root. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) currentJustifiedCheckpoint() *ethpb.Checkpoint { + if !b.hasInnerState() { + return nil + } + + return b.safeCopyCheckpoint(b.state.CurrentJustifiedCheckpoint) +} + +// MatchCurrentJustifiedCheckpoint returns true if input justified checkpoint matches +// the current justified checkpoint in state. +func (b *BeaconState) MatchCurrentJustifiedCheckpoint(c *ethpb.Checkpoint) bool { + if !b.hasInnerState() { + return false + } + if b.state.CurrentJustifiedCheckpoint == nil { + return false + } + + if c.Epoch != b.state.CurrentJustifiedCheckpoint.Epoch { + return false + } + return bytes.Equal(c.Root, b.state.CurrentJustifiedCheckpoint.Root) +} + +// MatchPreviousJustifiedCheckpoint returns true if the input justified checkpoint matches +// the previous justified checkpoint in state. +func (b *BeaconState) MatchPreviousJustifiedCheckpoint(c *ethpb.Checkpoint) bool { + if !b.hasInnerState() { + return false + } + if b.state.PreviousJustifiedCheckpoint == nil { + return false + } + + if c.Epoch != b.state.PreviousJustifiedCheckpoint.Epoch { + return false + } + return bytes.Equal(c.Root, b.state.PreviousJustifiedCheckpoint.Root) +} + +// FinalizedCheckpoint denoting an epoch and block root. +func (b *BeaconState) FinalizedCheckpoint() *ethpb.Checkpoint { + if !b.hasInnerState() { + return nil + } + if b.state.FinalizedCheckpoint == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.finalizedCheckpoint() +} + +// finalizedCheckpoint denoting an epoch and block root. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) finalizedCheckpoint() *ethpb.Checkpoint { + if !b.hasInnerState() { + return nil + } + + return b.safeCopyCheckpoint(b.state.FinalizedCheckpoint) +} + +// FinalizedCheckpointEpoch returns the epoch value of the finalized checkpoint. +func (b *BeaconState) FinalizedCheckpointEpoch() types.Epoch { + if !b.hasInnerState() { + return 0 + } + if b.state.FinalizedCheckpoint == nil { + return 0 + } + b.lock.RLock() + defer b.lock.RUnlock() + + return b.state.FinalizedCheckpoint.Epoch +} diff --git a/beacon-chain/state/stateV0/getters_eth1.go b/beacon-chain/state/stateV0/getters_eth1.go new file mode 100644 index 0000000000..e056de0b08 --- /dev/null +++ b/beacon-chain/state/stateV0/getters_eth1.go @@ -0,0 +1,145 @@ +package stateV0 + +import ( + "github.com/pkg/errors" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" + "github.com/prysmaticlabs/prysm/shared/featureconfig" + "github.com/prysmaticlabs/prysm/shared/htrutils" +) + +// Eth1Data corresponding to the proof-of-work chain information stored in the beacon state. +func (b *BeaconState) Eth1Data() *ethpb.Eth1Data { + if !b.hasInnerState() { + return nil + } + if b.state.Eth1Data == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.eth1Data() +} + +// eth1Data corresponding to the proof-of-work chain information stored in the beacon state. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) eth1Data() *ethpb.Eth1Data { + if !b.hasInnerState() { + return nil + } + if b.state.Eth1Data == nil { + return nil + } + + return CopyETH1Data(b.state.Eth1Data) +} + +// Eth1DataVotes corresponds to votes from eth2 on the canonical proof-of-work chain +// data retrieved from eth1. +func (b *BeaconState) Eth1DataVotes() []*ethpb.Eth1Data { + if !b.hasInnerState() { + return nil + } + if b.state.Eth1DataVotes == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.eth1DataVotes() +} + +// eth1DataVotes corresponds to votes from eth2 on the canonical proof-of-work chain +// data retrieved from eth1. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) eth1DataVotes() []*ethpb.Eth1Data { + if !b.hasInnerState() { + return nil + } + if b.state.Eth1DataVotes == nil { + return nil + } + + res := make([]*ethpb.Eth1Data, len(b.state.Eth1DataVotes)) + for i := 0; i < len(res); i++ { + res[i] = CopyETH1Data(b.state.Eth1DataVotes[i]) + } + return res +} + +// Eth1DepositIndex corresponds to the index of the deposit made to the +// validator deposit contract at the time of this state's eth1 data. +func (b *BeaconState) Eth1DepositIndex() uint64 { + if !b.hasInnerState() { + return 0 + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.eth1DepositIndex() +} + +// eth1DepositIndex corresponds to the index of the deposit made to the +// validator deposit contract at the time of this state's eth1 data. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) eth1DepositIndex() uint64 { + if !b.hasInnerState() { + return 0 + } + + return b.state.Eth1DepositIndex +} + +// eth1Root computes the HashTreeRoot Merkleization of +// a BeaconBlockHeader struct according to the eth2 +// Simple Serialize specification. +func eth1Root(hasher htrutils.HashFn, eth1Data *ethpb.Eth1Data) ([32]byte, error) { + if eth1Data == nil { + return [32]byte{}, errors.New("nil eth1 data") + } + + enc := stateutil.Eth1DataEncKey(eth1Data) + if featureconfig.Get().EnableSSZCache { + if found, ok := cachedHasher.rootsCache.Get(string(enc)); ok && found != nil { + return found.([32]byte), nil + } + } + + root, err := stateutil.Eth1DataRootWithHasher(hasher, eth1Data) + if err != nil { + return [32]byte{}, err + } + + if featureconfig.Get().EnableSSZCache { + cachedHasher.rootsCache.Set(string(enc), root, 32) + } + return root, nil +} + +// eth1DataVotesRoot computes the HashTreeRoot Merkleization of +// a list of Eth1Data structs according to the eth2 +// Simple Serialize specification. +func eth1DataVotesRoot(eth1DataVotes []*ethpb.Eth1Data) ([32]byte, error) { + hashKey, err := stateutil.Eth1DatasEncKey(eth1DataVotes) + if err != nil { + return [32]byte{}, err + } + + if featureconfig.Get().EnableSSZCache { + if found, ok := cachedHasher.rootsCache.Get(string(hashKey[:])); ok && found != nil { + return found.([32]byte), nil + } + } + root, err := stateutil.Eth1DatasRoot(eth1DataVotes) + if err != nil { + return [32]byte{}, err + } + if featureconfig.Get().EnableSSZCache { + cachedHasher.rootsCache.Set(string(hashKey[:]), root, 32) + } + return root, nil +} diff --git a/beacon-chain/state/stateV0/field_root_vector.go b/beacon-chain/state/stateV0/getters_misc.go similarity index 58% rename from beacon-chain/state/stateV0/field_root_vector.go rename to beacon-chain/state/stateV0/getters_misc.go index f5b6134ea7..58bc8d12da 100644 --- a/beacon-chain/state/stateV0/field_root_vector.go +++ b/beacon-chain/state/stateV0/getters_misc.go @@ -2,12 +2,162 @@ package stateV0 import ( "github.com/pkg/errors" + types "github.com/prysmaticlabs/eth2-types" "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" + pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/hashutil" "github.com/prysmaticlabs/prysm/shared/htrutils" + "github.com/prysmaticlabs/prysm/shared/params" ) +// GenesisTime of the beacon state as a uint64. +func (b *BeaconState) GenesisTime() uint64 { + if !b.hasInnerState() { + return 0 + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.genesisTime() +} + +// genesisTime of the beacon state as a uint64. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) genesisTime() uint64 { + if !b.hasInnerState() { + return 0 + } + + return b.state.GenesisTime +} + +// GenesisValidatorRoot of the beacon state. +func (b *BeaconState) GenesisValidatorRoot() []byte { + if !b.hasInnerState() { + return nil + } + if b.state.GenesisValidatorsRoot == nil { + return params.BeaconConfig().ZeroHash[:] + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.genesisValidatorRoot() +} + +// genesisValidatorRoot of the beacon state. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) genesisValidatorRoot() []byte { + if !b.hasInnerState() { + return nil + } + if b.state.GenesisValidatorsRoot == nil { + return params.BeaconConfig().ZeroHash[:] + } + + root := make([]byte, 32) + copy(root, b.state.GenesisValidatorsRoot) + return root +} + +// Slot of the current beacon chain state. +func (b *BeaconState) Slot() types.Slot { + if !b.hasInnerState() { + return 0 + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.slot() +} + +// slot of the current beacon chain state. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) slot() types.Slot { + if !b.hasInnerState() { + return 0 + } + + return b.state.Slot +} + +// Fork version of the beacon chain. +func (b *BeaconState) Fork() *pbp2p.Fork { + if !b.hasInnerState() { + return nil + } + if b.state.Fork == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.fork() +} + +// fork version of the beacon chain. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) fork() *pbp2p.Fork { + if !b.hasInnerState() { + return nil + } + if b.state.Fork == nil { + return nil + } + + prevVersion := make([]byte, len(b.state.Fork.PreviousVersion)) + copy(prevVersion, b.state.Fork.PreviousVersion) + currVersion := make([]byte, len(b.state.Fork.CurrentVersion)) + copy(currVersion, b.state.Fork.CurrentVersion) + return &pbp2p.Fork{ + PreviousVersion: prevVersion, + CurrentVersion: currVersion, + Epoch: b.state.Fork.Epoch, + } +} + +// HistoricalRoots based on epochs stored in the beacon state. +func (b *BeaconState) HistoricalRoots() [][]byte { + if !b.hasInnerState() { + return nil + } + if b.state.HistoricalRoots == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.historicalRoots() +} + +// historicalRoots based on epochs stored in the beacon state. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) historicalRoots() [][]byte { + if !b.hasInnerState() { + return nil + } + return b.safeCopy2DByteSlice(b.state.HistoricalRoots) +} + +// balancesLength returns the length of the balances slice. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) balancesLength() int { + if !b.hasInnerState() { + return 0 + } + if b.state.Balances == nil { + return 0 + } + + return len(b.state.Balances) +} + // RootsArrayHashTreeRoot computes the Merkle root of arrays of 32-byte hashes, such as [64][32]byte // according to the Simple Serialize specification of eth2. func RootsArrayHashTreeRoot(vals [][]byte, length uint64, fieldName string) ([32]byte, error) { diff --git a/beacon-chain/state/stateV0/getters_randao.go b/beacon-chain/state/stateV0/getters_randao.go new file mode 100644 index 0000000000..97824072a5 --- /dev/null +++ b/beacon-chain/state/stateV0/getters_randao.go @@ -0,0 +1,81 @@ +package stateV0 + +// RandaoMixes of block proposers on the beacon chain. +func (b *BeaconState) RandaoMixes() [][]byte { + if !b.hasInnerState() { + return nil + } + if b.state.RandaoMixes == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.randaoMixes() +} + +// randaoMixes of block proposers on the beacon chain. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) randaoMixes() [][]byte { + if !b.hasInnerState() { + return nil + } + + return b.safeCopy2DByteSlice(b.state.RandaoMixes) +} + +// RandaoMixAtIndex retrieves a specific block root based on an +// input index value. +func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) { + if !b.hasInnerState() { + return nil, ErrNilInnerState + } + if b.state.RandaoMixes == nil { + return nil, nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.randaoMixAtIndex(idx) +} + +// randaoMixAtIndex retrieves a specific block root based on an +// input index value. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) randaoMixAtIndex(idx uint64) ([]byte, error) { + if !b.hasInnerState() { + return nil, ErrNilInnerState + } + + return b.safeCopyBytesAtIndex(b.state.RandaoMixes, idx) +} + +// RandaoMixesLength returns the length of the randao mixes slice. +func (b *BeaconState) RandaoMixesLength() int { + if !b.hasInnerState() { + return 0 + } + if b.state.RandaoMixes == nil { + return 0 + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.randaoMixesLength() +} + +// randaoMixesLength returns the length of the randao mixes slice. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) randaoMixesLength() int { + if !b.hasInnerState() { + return 0 + } + if b.state.RandaoMixes == nil { + return 0 + } + + return len(b.state.RandaoMixes) +} diff --git a/beacon-chain/state/stateV0/getters_state.go b/beacon-chain/state/stateV0/getters_state.go new file mode 100644 index 0000000000..0e9d89f843 --- /dev/null +++ b/beacon-chain/state/stateV0/getters_state.go @@ -0,0 +1,172 @@ +package stateV0 + +import ( + "fmt" + + "github.com/pkg/errors" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" +) + +// InnerStateUnsafe returns the pointer value of the underlying +// beacon state proto object, bypassing immutability. Use with care. +func (b *BeaconState) InnerStateUnsafe() interface{} { + if b == nil { + return nil + } + return b.state +} + +// CloneInnerState the beacon state into a protobuf for usage. +func (b *BeaconState) CloneInnerState() interface{} { + if b == nil || b.state == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + return &pbp2p.BeaconState{ + GenesisTime: b.genesisTime(), + GenesisValidatorsRoot: b.genesisValidatorRoot(), + Slot: b.slot(), + Fork: b.fork(), + LatestBlockHeader: b.latestBlockHeader(), + BlockRoots: b.blockRoots(), + StateRoots: b.stateRoots(), + HistoricalRoots: b.historicalRoots(), + Eth1Data: b.eth1Data(), + Eth1DataVotes: b.eth1DataVotes(), + Eth1DepositIndex: b.eth1DepositIndex(), + Validators: b.validators(), + Balances: b.balances(), + RandaoMixes: b.randaoMixes(), + Slashings: b.slashings(), + PreviousEpochAttestations: b.previousEpochAttestations(), + CurrentEpochAttestations: b.currentEpochAttestations(), + JustificationBits: b.justificationBits(), + PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint(), + CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint(), + FinalizedCheckpoint: b.finalizedCheckpoint(), + } +} + +// hasInnerState detects if the internal reference to the state data structure +// is populated correctly. Returns false if nil. +func (b *BeaconState) hasInnerState() bool { + return b != nil && b.state != nil +} + +// StateRoots kept track of in the beacon state. +func (b *BeaconState) StateRoots() [][]byte { + if !b.hasInnerState() { + return nil + } + if b.state.StateRoots == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.stateRoots() +} + +// StateRoots kept track of in the beacon state. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) stateRoots() [][]byte { + if !b.hasInnerState() { + return nil + } + return b.safeCopy2DByteSlice(b.state.StateRoots) +} + +// StateRootAtIndex retrieves a specific state root based on an +// input index value. +func (b *BeaconState) StateRootAtIndex(idx uint64) ([]byte, error) { + if !b.hasInnerState() { + return nil, ErrNilInnerState + } + if b.state.StateRoots == nil { + return nil, nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.stateRootAtIndex(idx) +} + +// stateRootAtIndex retrieves a specific state root based on an +// input index value. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) stateRootAtIndex(idx uint64) ([]byte, error) { + if !b.hasInnerState() { + return nil, ErrNilInnerState + } + return b.safeCopyBytesAtIndex(b.state.StateRoots, idx) +} + +// MarshalSSZ marshals the underlying beacon state to bytes. +func (b *BeaconState) MarshalSSZ() ([]byte, error) { + if !b.hasInnerState() { + return nil, errors.New("nil beacon state") + } + return b.state.MarshalSSZ() +} + +// ProtobufBeaconState transforms an input into beacon state in the form of protobuf. +// Error is returned if the input is not type protobuf beacon state. +func ProtobufBeaconState(s interface{}) (*pbp2p.BeaconState, error) { + pbState, ok := s.(*pbp2p.BeaconState) + if !ok { + return nil, errors.New("input is not type pb.BeaconState") + } + return pbState, nil +} + +func (b *BeaconState) safeCopy2DByteSlice(input [][]byte) [][]byte { + if input == nil { + return nil + } + + dst := make([][]byte, len(input)) + for i, r := range input { + tmp := make([]byte, len(r)) + copy(tmp, r) + dst[i] = tmp + } + return dst +} + +func (b *BeaconState) safeCopyBytesAtIndex(input [][]byte, idx uint64) ([]byte, error) { + if input == nil { + return nil, nil + } + + if uint64(len(input)) <= idx { + return nil, fmt.Errorf("index %d out of range", idx) + } + root := make([]byte, 32) + copy(root, input[idx]) + return root, nil +} + +func (b *BeaconState) safeCopyPendingAttestationSlice(input []*pbp2p.PendingAttestation) []*pbp2p.PendingAttestation { + if input == nil { + return nil + } + + res := make([]*pbp2p.PendingAttestation, len(input)) + for i := 0; i < len(res); i++ { + res[i] = CopyPendingAttestation(input[i]) + } + return res +} + +func (b *BeaconState) safeCopyCheckpoint(input *ethpb.Checkpoint) *ethpb.Checkpoint { + if input == nil { + return nil + } + + return CopyCheckpoint(input) +} diff --git a/beacon-chain/state/stateV0/getters_validator.go b/beacon-chain/state/stateV0/getters_validator.go new file mode 100644 index 0000000000..2004c97d5a --- /dev/null +++ b/beacon-chain/state/stateV0/getters_validator.go @@ -0,0 +1,345 @@ +package stateV0 + +import ( + "bytes" + "encoding/binary" + "fmt" + + "github.com/pkg/errors" + types "github.com/prysmaticlabs/eth2-types" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" + "github.com/prysmaticlabs/prysm/shared/bytesutil" + "github.com/prysmaticlabs/prysm/shared/featureconfig" + "github.com/prysmaticlabs/prysm/shared/hashutil" + "github.com/prysmaticlabs/prysm/shared/htrutils" + "github.com/prysmaticlabs/prysm/shared/params" +) + +// Validators participating in consensus on the beacon chain. +func (b *BeaconState) Validators() []*ethpb.Validator { + if !b.hasInnerState() { + return nil + } + if b.state.Validators == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.validators() +} + +// validators participating in consensus on the beacon chain. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) validators() []*ethpb.Validator { + if !b.hasInnerState() { + return nil + } + if b.state.Validators == nil { + return nil + } + + res := make([]*ethpb.Validator, len(b.state.Validators)) + for i := 0; i < len(res); i++ { + val := b.state.Validators[i] + if val == nil { + continue + } + res[i] = CopyValidator(val) + } + return res +} + +// references of validators participating in consensus on the beacon chain. +// This assumes that a lock is already held on BeaconState. This does not +// copy fully and instead just copies the reference. +func (b *BeaconState) validatorsReferences() []*ethpb.Validator { + if !b.hasInnerState() { + return nil + } + if b.state.Validators == nil { + return nil + } + + res := make([]*ethpb.Validator, len(b.state.Validators)) + for i := 0; i < len(res); i++ { + validator := b.state.Validators[i] + if validator == nil { + continue + } + // copy validator reference instead. + res[i] = validator + } + return res +} + +// ValidatorAtIndex is the validator at the provided index. +func (b *BeaconState) ValidatorAtIndex(idx types.ValidatorIndex) (*ethpb.Validator, error) { + if !b.hasInnerState() { + return nil, ErrNilInnerState + } + if b.state.Validators == nil { + return ðpb.Validator{}, nil + } + if uint64(len(b.state.Validators)) <= uint64(idx) { + return nil, fmt.Errorf("index %d out of range", idx) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + val := b.state.Validators[idx] + return CopyValidator(val), nil +} + +// ValidatorAtIndexReadOnly is the validator at the provided index. This method +// doesn't clone the validator. +func (b *BeaconState) ValidatorAtIndexReadOnly(idx types.ValidatorIndex) (iface.ReadOnlyValidator, error) { + if !b.hasInnerState() { + return ReadOnlyValidator{}, ErrNilInnerState + } + if b.state.Validators == nil { + return ReadOnlyValidator{}, nil + } + if uint64(len(b.state.Validators)) <= uint64(idx) { + return ReadOnlyValidator{}, fmt.Errorf("index %d out of range", idx) + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return ReadOnlyValidator{b.state.Validators[idx]}, nil +} + +// ValidatorIndexByPubkey returns a given validator by its 48-byte public key. +func (b *BeaconState) ValidatorIndexByPubkey(key [48]byte) (types.ValidatorIndex, bool) { + if b == nil || b.valMapHandler == nil || b.valMapHandler.IsNil() { + return 0, false + } + b.lock.RLock() + defer b.lock.RUnlock() + idx, ok := b.valMapHandler.Get(key) + return idx, ok +} + +// PubkeyAtIndex returns the pubkey at the given +// validator index. +func (b *BeaconState) PubkeyAtIndex(idx types.ValidatorIndex) [48]byte { + if !b.hasInnerState() { + return [48]byte{} + } + if uint64(idx) >= uint64(len(b.state.Validators)) { + return [48]byte{} + } + b.lock.RLock() + defer b.lock.RUnlock() + + if b.state.Validators[idx] == nil { + return [48]byte{} + } + return bytesutil.ToBytes48(b.state.Validators[idx].PublicKey) +} + +// NumValidators returns the size of the validator registry. +func (b *BeaconState) NumValidators() int { + if !b.hasInnerState() { + return 0 + } + b.lock.RLock() + defer b.lock.RUnlock() + + return len(b.state.Validators) +} + +// ReadFromEveryValidator reads values from every validator and applies it to the provided function. +// Warning: This method is potentially unsafe, as it exposes the actual validator registry. +func (b *BeaconState) ReadFromEveryValidator(f func(idx int, val iface.ReadOnlyValidator) error) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + if b.state.Validators == nil { + return errors.New("nil validators in state") + } + b.lock.RLock() + validators := b.state.Validators + b.lock.RUnlock() + + for i, v := range validators { + err := f(i, ReadOnlyValidator{validator: v}) + if err != nil { + return err + } + } + return nil +} + +// Balances of validators participating in consensus on the beacon chain. +func (b *BeaconState) Balances() []uint64 { + if !b.hasInnerState() { + return nil + } + if b.state.Balances == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.balances() +} + +// balances of validators participating in consensus on the beacon chain. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) balances() []uint64 { + if !b.hasInnerState() { + return nil + } + if b.state.Balances == nil { + return nil + } + + res := make([]uint64, len(b.state.Balances)) + copy(res, b.state.Balances) + return res +} + +// BalanceAtIndex of validator with the provided index. +func (b *BeaconState) BalanceAtIndex(idx types.ValidatorIndex) (uint64, error) { + if !b.hasInnerState() { + return 0, ErrNilInnerState + } + if b.state.Balances == nil { + return 0, nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + if uint64(len(b.state.Balances)) <= uint64(idx) { + return 0, fmt.Errorf("index of %d does not exist", idx) + } + return b.state.Balances[idx], nil +} + +// BalancesLength returns the length of the balances slice. +func (b *BeaconState) BalancesLength() int { + if !b.hasInnerState() { + return 0 + } + if b.state.Balances == nil { + return 0 + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.balancesLength() +} + +// Slashings of validators on the beacon chain. +func (b *BeaconState) Slashings() []uint64 { + if !b.hasInnerState() { + return nil + } + if b.state.Slashings == nil { + return nil + } + + b.lock.RLock() + defer b.lock.RUnlock() + + return b.slashings() +} + +// slashings of validators on the beacon chain. +// This assumes that a lock is already held on BeaconState. +func (b *BeaconState) slashings() []uint64 { + if !b.hasInnerState() { + return nil + } + if b.state.Slashings == nil { + return nil + } + + res := make([]uint64, len(b.state.Slashings)) + copy(res, b.state.Slashings) + return res +} + +func (h *stateRootHasher) validatorRegistryRoot(validators []*ethpb.Validator) ([32]byte, error) { + hashKeyElements := make([]byte, len(validators)*32) + roots := make([][32]byte, len(validators)) + emptyKey := hashutil.FastSum256(hashKeyElements) + hasher := hashutil.CustomSHA256Hasher() + bytesProcessed := 0 + for i := 0; i < len(validators); i++ { + val, err := h.validatorRoot(hasher, validators[i]) + if err != nil { + return [32]byte{}, errors.Wrap(err, "could not compute validators merkleization") + } + copy(hashKeyElements[bytesProcessed:bytesProcessed+32], val[:]) + roots[i] = val + bytesProcessed += 32 + } + + hashKey := hashutil.FastSum256(hashKeyElements) + if hashKey != emptyKey && h.rootsCache != nil { + if found, ok := h.rootsCache.Get(string(hashKey[:])); found != nil && ok { + return found.([32]byte), nil + } + } + + validatorsRootsRoot, err := htrutils.BitwiseMerkleizeArrays(hasher, roots, uint64(len(roots)), params.BeaconConfig().ValidatorRegistryLimit) + if err != nil { + return [32]byte{}, errors.Wrap(err, "could not compute validator registry merkleization") + } + validatorsRootsBuf := new(bytes.Buffer) + if err := binary.Write(validatorsRootsBuf, binary.LittleEndian, uint64(len(validators))); err != nil { + return [32]byte{}, errors.Wrap(err, "could not marshal validator registry length") + } + // We need to mix in the length of the slice. + var validatorsRootsBufRoot [32]byte + copy(validatorsRootsBufRoot[:], validatorsRootsBuf.Bytes()) + res := htrutils.MixInLength(validatorsRootsRoot, validatorsRootsBufRoot[:]) + if hashKey != emptyKey && h.rootsCache != nil { + h.rootsCache.Set(string(hashKey[:]), res, 32) + } + return res, nil +} + +func (h *stateRootHasher) validatorRoot(hasher htrutils.HashFn, validator *ethpb.Validator) ([32]byte, error) { + if validator == nil { + return [32]byte{}, errors.New("nil validator") + } + + enc := stateutil.ValidatorEncKey(validator) + // Check if it exists in cache: + if h.rootsCache != nil { + if found, ok := h.rootsCache.Get(string(enc)); found != nil && ok { + return found.([32]byte), nil + } + } + + valRoot, err := stateutil.ValidatorRootWithHasher(hasher, validator) + if err != nil { + return [32]byte{}, err + } + + if h.rootsCache != nil { + h.rootsCache.Set(string(enc), valRoot, 32) + } + return valRoot, nil +} + +// ValidatorRegistryRoot computes the HashTreeRoot Merkleization of +// a list of validator structs according to the eth2 +// Simple Serialize specification. +func ValidatorRegistryRoot(vals []*ethpb.Validator) ([32]byte, error) { + if featureconfig.Get().EnableSSZCache { + return cachedHasher.validatorRegistryRoot(vals) + } + return nocachedHasher.validatorRegistryRoot(vals) +} diff --git a/beacon-chain/state/stateV0/setters.go b/beacon-chain/state/stateV0/setters.go deleted file mode 100644 index 5bbc4a3ac1..0000000000 --- a/beacon-chain/state/stateV0/setters.go +++ /dev/null @@ -1,754 +0,0 @@ -package stateV0 - -import ( - "fmt" - - "github.com/gogo/protobuf/proto" - "github.com/pkg/errors" - types "github.com/prysmaticlabs/eth2-types" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/go-bitfield" - "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" - pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - "github.com/prysmaticlabs/prysm/shared/bytesutil" - "github.com/prysmaticlabs/prysm/shared/hashutil" -) - -// 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 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 -// -// 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. - -// SetGenesisTime for the beacon state. -func (b *BeaconState) SetGenesisTime(val uint64) error { - b.lock.Lock() - defer b.lock.Unlock() - - b.state.GenesisTime = val - b.markFieldAsDirty(genesisTime) - return nil -} - -// SetGenesisValidatorRoot for the beacon state. -func (b *BeaconState) SetGenesisValidatorRoot(val []byte) error { - b.lock.Lock() - defer b.lock.Unlock() - - b.state.GenesisValidatorsRoot = val - b.markFieldAsDirty(genesisValidatorRoot) - return nil -} - -// SetSlot for the beacon state. -func (b *BeaconState) SetSlot(val types.Slot) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.state.Slot = val - b.markFieldAsDirty(slot) - return nil -} - -// SetFork version for the beacon chain. -func (b *BeaconState) SetFork(val *pbp2p.Fork) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - fk, ok := proto.Clone(val).(*pbp2p.Fork) - if !ok { - return errors.New("proto.Clone did not return a fork proto") - } - b.state.Fork = fk - b.markFieldAsDirty(fork) - return nil -} - -// SetLatestBlockHeader in the beacon state. -func (b *BeaconState) SetLatestBlockHeader(val *ethpb.BeaconBlockHeader) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.state.LatestBlockHeader = CopyBeaconBlockHeader(val) - b.markFieldAsDirty(latestBlockHeader) - return nil -} - -// SetBlockRoots for the beacon state. Updates the entire -// list to a new value by overwriting the previous one. -func (b *BeaconState) SetBlockRoots(val [][]byte) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.sharedFieldReferences[blockRoots].MinusRef() - b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1) - - b.state.BlockRoots = val - b.markFieldAsDirty(blockRoots) - b.rebuildTrie[blockRoots] = true - return nil -} - -// UpdateBlockRootAtIndex for the beacon state. Updates the block root -// at a specific index to a new value. -func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - if uint64(len(b.state.BlockRoots)) <= idx { - return fmt.Errorf("invalid index provided %d", idx) - } - b.lock.Lock() - defer b.lock.Unlock() - - r := b.state.BlockRoots - if ref := b.sharedFieldReferences[blockRoots]; ref.Refs() > 1 { - // Copy elements in underlying array by reference. - r = make([][]byte, len(b.state.BlockRoots)) - copy(r, b.state.BlockRoots) - ref.MinusRef() - b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1) - } - - r[idx] = blockRoot[:] - b.state.BlockRoots = r - - b.markFieldAsDirty(blockRoots) - b.addDirtyIndices(blockRoots, []uint64{idx}) - return nil -} - -// SetStateRoots for the beacon state. Updates the state roots -// to a new value by overwriting the previous value. -func (b *BeaconState) SetStateRoots(val [][]byte) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.sharedFieldReferences[stateRoots].MinusRef() - b.sharedFieldReferences[stateRoots] = stateutil.NewRef(1) - - b.state.StateRoots = val - b.markFieldAsDirty(stateRoots) - b.rebuildTrie[stateRoots] = true - return nil -} - -// UpdateStateRootAtIndex for the beacon state. Updates the state root -// at a specific index to a new value. -func (b *BeaconState) UpdateStateRootAtIndex(idx uint64, stateRoot [32]byte) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - - b.lock.RLock() - if uint64(len(b.state.StateRoots)) <= idx { - b.lock.RUnlock() - return errors.Errorf("invalid index provided %d", idx) - } - b.lock.RUnlock() - - b.lock.Lock() - defer b.lock.Unlock() - - // Check if we hold the only reference to the shared state roots slice. - r := b.state.StateRoots - if ref := b.sharedFieldReferences[stateRoots]; ref.Refs() > 1 { - // Copy elements in underlying array by reference. - r = make([][]byte, len(b.state.StateRoots)) - copy(r, b.state.StateRoots) - ref.MinusRef() - b.sharedFieldReferences[stateRoots] = stateutil.NewRef(1) - } - - r[idx] = stateRoot[:] - b.state.StateRoots = r - - b.markFieldAsDirty(stateRoots) - b.addDirtyIndices(stateRoots, []uint64{idx}) - 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 { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.sharedFieldReferences[historicalRoots].MinusRef() - b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1) - - b.state.HistoricalRoots = val - b.markFieldAsDirty(historicalRoots) - return nil -} - -// SetEth1Data for the beacon state. -func (b *BeaconState) SetEth1Data(val *ethpb.Eth1Data) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.state.Eth1Data = val - b.markFieldAsDirty(eth1Data) - return nil -} - -// SetEth1DataVotes for the beacon state. Updates the entire -// list to a new value by overwriting the previous one. -func (b *BeaconState) SetEth1DataVotes(val []*ethpb.Eth1Data) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.sharedFieldReferences[eth1DataVotes].MinusRef() - b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1) - - b.state.Eth1DataVotes = val - b.markFieldAsDirty(eth1DataVotes) - b.rebuildTrie[eth1DataVotes] = true - return nil -} - -// AppendEth1DataVotes for the beacon state. Appends the new value -// to the the end of list. -func (b *BeaconState) AppendEth1DataVotes(val *ethpb.Eth1Data) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - votes := b.state.Eth1DataVotes - if b.sharedFieldReferences[eth1DataVotes].Refs() > 1 { - // Copy elements in underlying array by reference. - votes = make([]*ethpb.Eth1Data, len(b.state.Eth1DataVotes)) - copy(votes, b.state.Eth1DataVotes) - b.sharedFieldReferences[eth1DataVotes].MinusRef() - b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1) - } - - b.state.Eth1DataVotes = append(votes, val) - b.markFieldAsDirty(eth1DataVotes) - b.addDirtyIndices(eth1DataVotes, []uint64{uint64(len(b.state.Eth1DataVotes) - 1)}) - return nil -} - -// SetEth1DepositIndex for the beacon state. -func (b *BeaconState) SetEth1DepositIndex(val uint64) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.state.Eth1DepositIndex = val - b.markFieldAsDirty(eth1DepositIndex) - return nil -} - -// SetValidators for the beacon state. Updates the entire -// to a new value by overwriting the previous one. -func (b *BeaconState) SetValidators(val []*ethpb.Validator) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.state.Validators = val - b.sharedFieldReferences[validators].MinusRef() - b.sharedFieldReferences[validators] = stateutil.NewRef(1) - b.markFieldAsDirty(validators) - b.rebuildTrie[validators] = true - b.valMapHandler = stateutil.NewValMapHandler(b.state.Validators) - return nil -} - -// ApplyToEveryValidator applies the provided callback function to each validator in the -// validator registry. -func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error)) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - v := b.state.Validators - if ref := b.sharedFieldReferences[validators]; ref.Refs() > 1 { - v = b.validatorsReferences() - ref.MinusRef() - b.sharedFieldReferences[validators] = stateutil.NewRef(1) - } - b.lock.Unlock() - var changedVals []uint64 - for i, val := range v { - changed, newVal, err := f(i, val) - if err != nil { - return err - } - if changed { - changedVals = append(changedVals, uint64(i)) - v[i] = newVal - } - } - - b.lock.Lock() - defer b.lock.Unlock() - - b.state.Validators = v - b.markFieldAsDirty(validators) - b.addDirtyIndices(validators, changedVals) - - return nil -} - -// UpdateValidatorAtIndex for the beacon state. Updates the validator -// at a specific index to a new value. -func (b *BeaconState) UpdateValidatorAtIndex(idx types.ValidatorIndex, val *ethpb.Validator) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - if uint64(len(b.state.Validators)) <= uint64(idx) { - return errors.Errorf("invalid index provided %d", idx) - } - b.lock.Lock() - defer b.lock.Unlock() - - v := b.state.Validators - if ref := b.sharedFieldReferences[validators]; ref.Refs() > 1 { - v = b.validatorsReferences() - ref.MinusRef() - b.sharedFieldReferences[validators] = stateutil.NewRef(1) - } - - v[idx] = val - b.state.Validators = v - b.markFieldAsDirty(validators) - b.addDirtyIndices(validators, []uint64{uint64(idx)}) - - return nil -} - -// SetBalances for the beacon state. Updates the entire -// list to a new value by overwriting the previous one. -func (b *BeaconState) SetBalances(val []uint64) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.sharedFieldReferences[balances].MinusRef() - b.sharedFieldReferences[balances] = stateutil.NewRef(1) - - b.state.Balances = val - b.markFieldAsDirty(balances) - return nil -} - -// UpdateBalancesAtIndex for the beacon state. This method updates the balance -// at a specific index to a new value. -func (b *BeaconState) UpdateBalancesAtIndex(idx types.ValidatorIndex, val uint64) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - if uint64(len(b.state.Balances)) <= uint64(idx) { - return errors.Errorf("invalid index provided %d", idx) - } - b.lock.Lock() - defer b.lock.Unlock() - - bals := b.state.Balances - if b.sharedFieldReferences[balances].Refs() > 1 { - bals = b.balances() - b.sharedFieldReferences[balances].MinusRef() - b.sharedFieldReferences[balances] = stateutil.NewRef(1) - } - - bals[idx] = val - b.state.Balances = bals - b.markFieldAsDirty(balances) - return nil -} - -// SetRandaoMixes for the beacon state. Updates the entire -// randao mixes to a new value by overwriting the previous one. -func (b *BeaconState) SetRandaoMixes(val [][]byte) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.sharedFieldReferences[randaoMixes].MinusRef() - b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1) - - b.state.RandaoMixes = val - b.markFieldAsDirty(randaoMixes) - b.rebuildTrie[randaoMixes] = true - return nil -} - -// UpdateRandaoMixesAtIndex for the beacon state. Updates the randao mixes -// at a specific index to a new value. -func (b *BeaconState) UpdateRandaoMixesAtIndex(idx uint64, val []byte) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - if uint64(len(b.state.RandaoMixes)) <= idx { - return errors.Errorf("invalid index provided %d", idx) - } - b.lock.Lock() - defer b.lock.Unlock() - - mixes := b.state.RandaoMixes - if refs := b.sharedFieldReferences[randaoMixes].Refs(); refs > 1 { - // Copy elements in underlying array by reference. - mixes = make([][]byte, len(b.state.RandaoMixes)) - copy(mixes, b.state.RandaoMixes) - b.sharedFieldReferences[randaoMixes].MinusRef() - b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1) - } - - mixes[idx] = val - b.state.RandaoMixes = mixes - b.markFieldAsDirty(randaoMixes) - b.addDirtyIndices(randaoMixes, []uint64{idx}) - - return nil -} - -// SetSlashings for the beacon state. Updates the entire -// list to a new value by overwriting the previous one. -func (b *BeaconState) SetSlashings(val []uint64) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.sharedFieldReferences[slashings].MinusRef() - b.sharedFieldReferences[slashings] = stateutil.NewRef(1) - - b.state.Slashings = val - b.markFieldAsDirty(slashings) - return nil -} - -// UpdateSlashingsAtIndex for the beacon state. Updates the slashings -// at a specific index to a new value. -func (b *BeaconState) UpdateSlashingsAtIndex(idx, val uint64) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - if uint64(len(b.state.Slashings)) <= idx { - return errors.Errorf("invalid index provided %d", idx) - } - b.lock.Lock() - defer b.lock.Unlock() - - s := b.state.Slashings - if b.sharedFieldReferences[slashings].Refs() > 1 { - s = b.slashings() - b.sharedFieldReferences[slashings].MinusRef() - b.sharedFieldReferences[slashings] = stateutil.NewRef(1) - } - - s[idx] = val - - b.state.Slashings = s - - b.markFieldAsDirty(slashings) - return nil -} - -func (b *BeaconState) setPreviousEpochAttestations(val []*pbp2p.PendingAttestation) { - b.sharedFieldReferences[previousEpochAttestations].MinusRef() - b.sharedFieldReferences[previousEpochAttestations] = stateutil.NewRef(1) - - b.state.PreviousEpochAttestations = val - b.markFieldAsDirty(previousEpochAttestations) - b.rebuildTrie[previousEpochAttestations] = true -} - -func (b *BeaconState) setCurrentEpochAttestations(val []*pbp2p.PendingAttestation) { - b.sharedFieldReferences[currentEpochAttestations].MinusRef() - b.sharedFieldReferences[currentEpochAttestations] = stateutil.NewRef(1) - - b.state.CurrentEpochAttestations = val - b.markFieldAsDirty(currentEpochAttestations) - b.rebuildTrie[currentEpochAttestations] = true -} - -// RotateAttestations sets the previous epoch attestations to the current epoch attestations and -// then clears the current epoch attestations. -func (b *BeaconState) RotateAttestations() error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.setPreviousEpochAttestations(b.currentEpochAttestations()) - b.setCurrentEpochAttestations([]*pbp2p.PendingAttestation{}) - 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 { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - roots := b.state.HistoricalRoots - if b.sharedFieldReferences[historicalRoots].Refs() > 1 { - roots = make([][]byte, len(b.state.HistoricalRoots)) - copy(roots, b.state.HistoricalRoots) - b.sharedFieldReferences[historicalRoots].MinusRef() - b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1) - } - - b.state.HistoricalRoots = append(roots, root[:]) - b.markFieldAsDirty(historicalRoots) - return nil -} - -// AppendCurrentEpochAttestations for the beacon state. Appends the new value -// to the the end of list. -func (b *BeaconState) AppendCurrentEpochAttestations(val *pbp2p.PendingAttestation) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - atts := b.state.CurrentEpochAttestations - if b.sharedFieldReferences[currentEpochAttestations].Refs() > 1 { - // Copy elements in underlying array by reference. - atts = make([]*pbp2p.PendingAttestation, len(b.state.CurrentEpochAttestations)) - copy(atts, b.state.CurrentEpochAttestations) - b.sharedFieldReferences[currentEpochAttestations].MinusRef() - b.sharedFieldReferences[currentEpochAttestations] = stateutil.NewRef(1) - } - - b.state.CurrentEpochAttestations = append(atts, val) - b.markFieldAsDirty(currentEpochAttestations) - b.dirtyIndices[currentEpochAttestations] = append(b.dirtyIndices[currentEpochAttestations], uint64(len(b.state.CurrentEpochAttestations)-1)) - return nil -} - -// AppendPreviousEpochAttestations for the beacon state. Appends the new value -// to the the end of list. -func (b *BeaconState) AppendPreviousEpochAttestations(val *pbp2p.PendingAttestation) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - atts := b.state.PreviousEpochAttestations - if b.sharedFieldReferences[previousEpochAttestations].Refs() > 1 { - atts = make([]*pbp2p.PendingAttestation, len(b.state.PreviousEpochAttestations)) - copy(atts, b.state.PreviousEpochAttestations) - b.sharedFieldReferences[previousEpochAttestations].MinusRef() - b.sharedFieldReferences[previousEpochAttestations] = stateutil.NewRef(1) - } - - b.state.PreviousEpochAttestations = append(atts, val) - b.markFieldAsDirty(previousEpochAttestations) - b.addDirtyIndices(previousEpochAttestations, []uint64{uint64(len(b.state.PreviousEpochAttestations) - 1)}) - - return nil -} - -// AppendValidator for the beacon state. Appends the new value -// to the the end of list. -func (b *BeaconState) AppendValidator(val *ethpb.Validator) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - vals := b.state.Validators - if b.sharedFieldReferences[validators].Refs() > 1 { - vals = b.validatorsReferences() - b.sharedFieldReferences[validators].MinusRef() - b.sharedFieldReferences[validators] = stateutil.NewRef(1) - } - - // append validator to slice - b.state.Validators = append(vals, val) - valIdx := types.ValidatorIndex(len(b.state.Validators) - 1) - - // Copy if this is a shared validator map - if ref := b.valMapHandler.MapRef(); ref.Refs() > 1 { - valMap := b.valMapHandler.Copy() - ref.MinusRef() - b.valMapHandler = valMap - } - b.valMapHandler.Set(bytesutil.ToBytes48(val.PublicKey), valIdx) - - b.markFieldAsDirty(validators) - b.addDirtyIndices(validators, []uint64{uint64(valIdx)}) - return nil -} - -// AppendBalance for the beacon state. Appends the new value -// to the the end of list. -func (b *BeaconState) AppendBalance(bal uint64) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - bals := b.state.Balances - if b.sharedFieldReferences[balances].Refs() > 1 { - bals = b.balances() - b.sharedFieldReferences[balances].MinusRef() - b.sharedFieldReferences[balances] = stateutil.NewRef(1) - } - - b.state.Balances = append(bals, bal) - b.markFieldAsDirty(balances) - return nil -} - -// SetJustificationBits for the beacon state. -func (b *BeaconState) SetJustificationBits(val bitfield.Bitvector4) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.state.JustificationBits = val - b.markFieldAsDirty(justificationBits) - return nil -} - -// SetPreviousJustifiedCheckpoint for the beacon state. -func (b *BeaconState) SetPreviousJustifiedCheckpoint(val *ethpb.Checkpoint) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.state.PreviousJustifiedCheckpoint = val - b.markFieldAsDirty(previousJustifiedCheckpoint) - return nil -} - -// SetCurrentJustifiedCheckpoint for the beacon state. -func (b *BeaconState) SetCurrentJustifiedCheckpoint(val *ethpb.Checkpoint) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.state.CurrentJustifiedCheckpoint = val - b.markFieldAsDirty(currentJustifiedCheckpoint) - return nil -} - -// SetFinalizedCheckpoint for the beacon state. -func (b *BeaconState) SetFinalizedCheckpoint(val *ethpb.Checkpoint) error { - if !b.hasInnerState() { - return ErrNilInnerState - } - b.lock.Lock() - defer b.lock.Unlock() - - b.state.FinalizedCheckpoint = val - b.markFieldAsDirty(finalizedCheckpoint) - return nil -} - -// Recomputes the branch up the index in the Merkle trie representation -// of the beacon state. This method performs map reads and the caller MUST -// hold the lock before calling this method. -func (b *BeaconState) recomputeRoot(idx int) { - hashFunc := hashutil.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 fieldIndex) { - _, ok := b.dirtyFields[field] - if !ok { - b.dirtyFields[field] = true - } - // do nothing if field already exists -} - -// addDirtyIndices adds the relevant dirty field indices, so that they -// can be recomputed. -func (b *BeaconState) addDirtyIndices(index fieldIndex, indices []uint64) { - b.dirtyIndices[index] = append(b.dirtyIndices[index], indices...) -} diff --git a/beacon-chain/state/stateV0/setters_attestation.go b/beacon-chain/state/stateV0/setters_attestation.go new file mode 100644 index 0000000000..2b09cecba8 --- /dev/null +++ b/beacon-chain/state/stateV0/setters_attestation.go @@ -0,0 +1,99 @@ +package stateV0 + +import ( + "fmt" + + "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" + pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/shared/params" +) + +// RotateAttestations sets the previous epoch attestations to the current epoch attestations and +// then clears the current epoch attestations. +func (b *BeaconState) RotateAttestations() error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.setPreviousEpochAttestations(b.currentEpochAttestations()) + b.setCurrentEpochAttestations([]*pbp2p.PendingAttestation{}) + return nil +} + +func (b *BeaconState) setPreviousEpochAttestations(val []*pbp2p.PendingAttestation) { + b.sharedFieldReferences[previousEpochAttestations].MinusRef() + b.sharedFieldReferences[previousEpochAttestations] = stateutil.NewRef(1) + + b.state.PreviousEpochAttestations = val + b.markFieldAsDirty(previousEpochAttestations) + b.rebuildTrie[previousEpochAttestations] = true +} + +func (b *BeaconState) setCurrentEpochAttestations(val []*pbp2p.PendingAttestation) { + b.sharedFieldReferences[currentEpochAttestations].MinusRef() + b.sharedFieldReferences[currentEpochAttestations] = stateutil.NewRef(1) + + b.state.CurrentEpochAttestations = val + b.markFieldAsDirty(currentEpochAttestations) + b.rebuildTrie[currentEpochAttestations] = true +} + +// AppendCurrentEpochAttestations for the beacon state. Appends the new value +// to the the end of list. +func (b *BeaconState) AppendCurrentEpochAttestations(val *pbp2p.PendingAttestation) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + atts := b.state.CurrentEpochAttestations + max := uint64(params.BeaconConfig().SlotsPerEpoch) * params.BeaconConfig().MaxAttestations + if uint64(len(atts)) >= max { + return fmt.Errorf("current pending attestation exceeds max length %d", max) + } + + if b.sharedFieldReferences[currentEpochAttestations].Refs() > 1 { + // Copy elements in underlying array by reference. + atts = make([]*pbp2p.PendingAttestation, len(b.state.CurrentEpochAttestations)) + copy(atts, b.state.CurrentEpochAttestations) + b.sharedFieldReferences[currentEpochAttestations].MinusRef() + b.sharedFieldReferences[currentEpochAttestations] = stateutil.NewRef(1) + } + + b.state.CurrentEpochAttestations = append(atts, val) + b.markFieldAsDirty(currentEpochAttestations) + b.dirtyIndices[currentEpochAttestations] = append(b.dirtyIndices[currentEpochAttestations], uint64(len(b.state.CurrentEpochAttestations)-1)) + return nil +} + +// AppendPreviousEpochAttestations for the beacon state. Appends the new value +// to the the end of list. +func (b *BeaconState) AppendPreviousEpochAttestations(val *pbp2p.PendingAttestation) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + atts := b.state.PreviousEpochAttestations + max := uint64(params.BeaconConfig().SlotsPerEpoch) * params.BeaconConfig().MaxAttestations + if uint64(len(atts)) >= max { + return fmt.Errorf("previous pending attestation exceeds max length %d", max) + } + + if b.sharedFieldReferences[previousEpochAttestations].Refs() > 1 { + atts = make([]*pbp2p.PendingAttestation, len(b.state.PreviousEpochAttestations)) + copy(atts, b.state.PreviousEpochAttestations) + b.sharedFieldReferences[previousEpochAttestations].MinusRef() + b.sharedFieldReferences[previousEpochAttestations] = stateutil.NewRef(1) + } + + b.state.PreviousEpochAttestations = append(atts, val) + b.markFieldAsDirty(previousEpochAttestations) + b.addDirtyIndices(previousEpochAttestations, []uint64{uint64(len(b.state.PreviousEpochAttestations) - 1)}) + + return nil +} diff --git a/beacon-chain/state/stateV0/setters_test.go b/beacon-chain/state/stateV0/setters_attestation_test.go similarity index 100% rename from beacon-chain/state/stateV0/setters_test.go rename to beacon-chain/state/stateV0/setters_attestation_test.go diff --git a/beacon-chain/state/stateV0/setters_block.go b/beacon-chain/state/stateV0/setters_block.go new file mode 100644 index 0000000000..73da62c608 --- /dev/null +++ b/beacon-chain/state/stateV0/setters_block.go @@ -0,0 +1,68 @@ +package stateV0 + +import ( + "fmt" + + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" +) + +// SetLatestBlockHeader in the beacon state. +func (b *BeaconState) SetLatestBlockHeader(val *ethpb.BeaconBlockHeader) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.state.LatestBlockHeader = CopyBeaconBlockHeader(val) + b.markFieldAsDirty(latestBlockHeader) + return nil +} + +// SetBlockRoots for the beacon state. Updates the entire +// list to a new value by overwriting the previous one. +func (b *BeaconState) SetBlockRoots(val [][]byte) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.sharedFieldReferences[blockRoots].MinusRef() + b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1) + + b.state.BlockRoots = val + b.markFieldAsDirty(blockRoots) + b.rebuildTrie[blockRoots] = true + return nil +} + +// UpdateBlockRootAtIndex for the beacon state. Updates the block root +// at a specific index to a new value. +func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + if uint64(len(b.state.BlockRoots)) <= idx { + return fmt.Errorf("invalid index provided %d", idx) + } + b.lock.Lock() + defer b.lock.Unlock() + + r := b.state.BlockRoots + if ref := b.sharedFieldReferences[blockRoots]; ref.Refs() > 1 { + // Copy elements in underlying array by reference. + r = make([][]byte, len(b.state.BlockRoots)) + copy(r, b.state.BlockRoots) + ref.MinusRef() + b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1) + } + + r[idx] = blockRoot[:] + b.state.BlockRoots = r + + b.markFieldAsDirty(blockRoots) + b.addDirtyIndices(blockRoots, []uint64{idx}) + return nil +} diff --git a/beacon-chain/state/stateV0/setters_checkpoint.go b/beacon-chain/state/stateV0/setters_checkpoint.go new file mode 100644 index 0000000000..e1e1d80f5e --- /dev/null +++ b/beacon-chain/state/stateV0/setters_checkpoint.go @@ -0,0 +1,58 @@ +package stateV0 + +import ( + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/go-bitfield" +) + +// SetJustificationBits for the beacon state. +func (b *BeaconState) SetJustificationBits(val bitfield.Bitvector4) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.state.JustificationBits = val + b.markFieldAsDirty(justificationBits) + return nil +} + +// SetPreviousJustifiedCheckpoint for the beacon state. +func (b *BeaconState) SetPreviousJustifiedCheckpoint(val *ethpb.Checkpoint) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.state.PreviousJustifiedCheckpoint = val + b.markFieldAsDirty(previousJustifiedCheckpoint) + return nil +} + +// SetCurrentJustifiedCheckpoint for the beacon state. +func (b *BeaconState) SetCurrentJustifiedCheckpoint(val *ethpb.Checkpoint) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.state.CurrentJustifiedCheckpoint = val + b.markFieldAsDirty(currentJustifiedCheckpoint) + return nil +} + +// SetFinalizedCheckpoint for the beacon state. +func (b *BeaconState) SetFinalizedCheckpoint(val *ethpb.Checkpoint) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.state.FinalizedCheckpoint = val + b.markFieldAsDirty(finalizedCheckpoint) + return nil +} diff --git a/beacon-chain/state/stateV0/setters_eth1.go b/beacon-chain/state/stateV0/setters_eth1.go new file mode 100644 index 0000000000..6d3fe4ea90 --- /dev/null +++ b/beacon-chain/state/stateV0/setters_eth1.go @@ -0,0 +1,74 @@ +package stateV0 + +import ( + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" +) + +// SetEth1Data for the beacon state. +func (b *BeaconState) SetEth1Data(val *ethpb.Eth1Data) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.state.Eth1Data = val + b.markFieldAsDirty(eth1Data) + return nil +} + +// SetEth1DataVotes for the beacon state. Updates the entire +// list to a new value by overwriting the previous one. +func (b *BeaconState) SetEth1DataVotes(val []*ethpb.Eth1Data) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.sharedFieldReferences[eth1DataVotes].MinusRef() + b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1) + + b.state.Eth1DataVotes = val + b.markFieldAsDirty(eth1DataVotes) + b.rebuildTrie[eth1DataVotes] = true + return nil +} + +// SetEth1DepositIndex for the beacon state. +func (b *BeaconState) SetEth1DepositIndex(val uint64) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.state.Eth1DepositIndex = val + b.markFieldAsDirty(eth1DepositIndex) + return nil +} + +// AppendEth1DataVotes for the beacon state. Appends the new value +// to the the end of list. +func (b *BeaconState) AppendEth1DataVotes(val *ethpb.Eth1Data) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + votes := b.state.Eth1DataVotes + if b.sharedFieldReferences[eth1DataVotes].Refs() > 1 { + // Copy elements in underlying array by reference. + votes = make([]*ethpb.Eth1Data, len(b.state.Eth1DataVotes)) + copy(votes, b.state.Eth1DataVotes) + b.sharedFieldReferences[eth1DataVotes].MinusRef() + b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1) + } + + b.state.Eth1DataVotes = append(votes, val) + b.markFieldAsDirty(eth1DataVotes) + b.addDirtyIndices(eth1DataVotes, []uint64{uint64(len(b.state.Eth1DataVotes) - 1)}) + return nil +} diff --git a/beacon-chain/state/stateV0/setters_misc.go b/beacon-chain/state/stateV0/setters_misc.go new file mode 100644 index 0000000000..496de74a87 --- /dev/null +++ b/beacon-chain/state/stateV0/setters_misc.go @@ -0,0 +1,148 @@ +package stateV0 + +import ( + "github.com/gogo/protobuf/proto" + "github.com/pkg/errors" + types "github.com/prysmaticlabs/eth2-types" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" + pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/shared/hashutil" +) + +// SetGenesisTime for the beacon state. +func (b *BeaconState) SetGenesisTime(val uint64) error { + b.lock.Lock() + defer b.lock.Unlock() + + b.state.GenesisTime = val + b.markFieldAsDirty(genesisTime) + return nil +} + +// SetGenesisValidatorRoot for the beacon state. +func (b *BeaconState) SetGenesisValidatorRoot(val []byte) error { + b.lock.Lock() + defer b.lock.Unlock() + + b.state.GenesisValidatorsRoot = val + b.markFieldAsDirty(genesisValidatorRoot) + return nil +} + +// SetSlot for the beacon state. +func (b *BeaconState) SetSlot(val types.Slot) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.state.Slot = val + b.markFieldAsDirty(slot) + return nil +} + +// SetFork version for the beacon chain. +func (b *BeaconState) SetFork(val *pbp2p.Fork) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + fk, ok := proto.Clone(val).(*pbp2p.Fork) + if !ok { + return errors.New("proto.Clone did not return a fork proto") + } + b.state.Fork = fk + b.markFieldAsDirty(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 { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.sharedFieldReferences[historicalRoots].MinusRef() + b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1) + + b.state.HistoricalRoots = val + b.markFieldAsDirty(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 { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + roots := b.state.HistoricalRoots + if b.sharedFieldReferences[historicalRoots].Refs() > 1 { + roots = make([][]byte, len(b.state.HistoricalRoots)) + copy(roots, b.state.HistoricalRoots) + b.sharedFieldReferences[historicalRoots].MinusRef() + b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1) + } + + b.state.HistoricalRoots = append(roots, root[:]) + b.markFieldAsDirty(historicalRoots) + return nil +} + +// Recomputes the branch up the index in the Merkle trie representation +// of the beacon state. This method performs map reads and the caller MUST +// hold the lock before calling this method. +func (b *BeaconState) recomputeRoot(idx int) { + hashFunc := hashutil.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 fieldIndex) { + _, ok := b.dirtyFields[field] + if !ok { + b.dirtyFields[field] = true + } + // do nothing if field already exists +} + +// addDirtyIndices adds the relevant dirty field indices, so that they +// can be recomputed. +func (b *BeaconState) addDirtyIndices(index fieldIndex, indices []uint64) { + b.dirtyIndices[index] = append(b.dirtyIndices[index], indices...) +} diff --git a/beacon-chain/state/stateV0/setters_randao.go b/beacon-chain/state/stateV0/setters_randao.go new file mode 100644 index 0000000000..6f4ceae7dc --- /dev/null +++ b/beacon-chain/state/stateV0/setters_randao.go @@ -0,0 +1,53 @@ +package stateV0 + +import ( + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" +) + +// SetRandaoMixes for the beacon state. Updates the entire +// randao mixes to a new value by overwriting the previous one. +func (b *BeaconState) SetRandaoMixes(val [][]byte) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.sharedFieldReferences[randaoMixes].MinusRef() + b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1) + + b.state.RandaoMixes = val + b.markFieldAsDirty(randaoMixes) + b.rebuildTrie[randaoMixes] = true + return nil +} + +// UpdateRandaoMixesAtIndex for the beacon state. Updates the randao mixes +// at a specific index to a new value. +func (b *BeaconState) UpdateRandaoMixesAtIndex(idx uint64, val []byte) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + if uint64(len(b.state.RandaoMixes)) <= idx { + return errors.Errorf("invalid index provided %d", idx) + } + b.lock.Lock() + defer b.lock.Unlock() + + mixes := b.state.RandaoMixes + if refs := b.sharedFieldReferences[randaoMixes].Refs(); refs > 1 { + // Copy elements in underlying array by reference. + mixes = make([][]byte, len(b.state.RandaoMixes)) + copy(mixes, b.state.RandaoMixes) + b.sharedFieldReferences[randaoMixes].MinusRef() + b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1) + } + + mixes[idx] = val + b.state.RandaoMixes = mixes + b.markFieldAsDirty(randaoMixes) + b.addDirtyIndices(randaoMixes, []uint64{idx}) + + return nil +} diff --git a/beacon-chain/state/stateV0/setters_state.go b/beacon-chain/state/stateV0/setters_state.go new file mode 100644 index 0000000000..a1ca0c4857 --- /dev/null +++ b/beacon-chain/state/stateV0/setters_state.go @@ -0,0 +1,59 @@ +package stateV0 + +import ( + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" +) + +// SetStateRoots for the beacon state. Updates the state roots +// to a new value by overwriting the previous value. +func (b *BeaconState) SetStateRoots(val [][]byte) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.sharedFieldReferences[stateRoots].MinusRef() + b.sharedFieldReferences[stateRoots] = stateutil.NewRef(1) + + b.state.StateRoots = val + b.markFieldAsDirty(stateRoots) + b.rebuildTrie[stateRoots] = true + return nil +} + +// UpdateStateRootAtIndex for the beacon state. Updates the state root +// at a specific index to a new value. +func (b *BeaconState) UpdateStateRootAtIndex(idx uint64, stateRoot [32]byte) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + + b.lock.RLock() + if uint64(len(b.state.StateRoots)) <= idx { + b.lock.RUnlock() + return errors.Errorf("invalid index provided %d", idx) + } + b.lock.RUnlock() + + b.lock.Lock() + defer b.lock.Unlock() + + // Check if we hold the only reference to the shared state roots slice. + r := b.state.StateRoots + if ref := b.sharedFieldReferences[stateRoots]; ref.Refs() > 1 { + // Copy elements in underlying array by reference. + r = make([][]byte, len(b.state.StateRoots)) + copy(r, b.state.StateRoots) + ref.MinusRef() + b.sharedFieldReferences[stateRoots] = stateutil.NewRef(1) + } + + r[idx] = stateRoot[:] + b.state.StateRoots = r + + b.markFieldAsDirty(stateRoots) + b.addDirtyIndices(stateRoots, []uint64{idx}) + return nil +} diff --git a/beacon-chain/state/stateV0/setters_validator.go b/beacon-chain/state/stateV0/setters_validator.go new file mode 100644 index 0000000000..f6da750167 --- /dev/null +++ b/beacon-chain/state/stateV0/setters_validator.go @@ -0,0 +1,230 @@ +package stateV0 + +import ( + "github.com/pkg/errors" + types "github.com/prysmaticlabs/eth2-types" + ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" + "github.com/prysmaticlabs/prysm/shared/bytesutil" +) + +// SetValidators for the beacon state. Updates the entire +// to a new value by overwriting the previous one. +func (b *BeaconState) SetValidators(val []*ethpb.Validator) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.state.Validators = val + b.sharedFieldReferences[validators].MinusRef() + b.sharedFieldReferences[validators] = stateutil.NewRef(1) + b.markFieldAsDirty(validators) + b.rebuildTrie[validators] = true + b.valMapHandler = stateutil.NewValMapHandler(b.state.Validators) + return nil +} + +// ApplyToEveryValidator applies the provided callback function to each validator in the +// validator registry. +func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error)) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + v := b.state.Validators + if ref := b.sharedFieldReferences[validators]; ref.Refs() > 1 { + v = b.validatorsReferences() + ref.MinusRef() + b.sharedFieldReferences[validators] = stateutil.NewRef(1) + } + b.lock.Unlock() + var changedVals []uint64 + for i, val := range v { + changed, newVal, err := f(i, val) + if err != nil { + return err + } + if changed { + changedVals = append(changedVals, uint64(i)) + v[i] = newVal + } + } + + b.lock.Lock() + defer b.lock.Unlock() + + b.state.Validators = v + b.markFieldAsDirty(validators) + b.addDirtyIndices(validators, changedVals) + + return nil +} + +// UpdateValidatorAtIndex for the beacon state. Updates the validator +// at a specific index to a new value. +func (b *BeaconState) UpdateValidatorAtIndex(idx types.ValidatorIndex, val *ethpb.Validator) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + if uint64(len(b.state.Validators)) <= uint64(idx) { + return errors.Errorf("invalid index provided %d", idx) + } + b.lock.Lock() + defer b.lock.Unlock() + + v := b.state.Validators + if ref := b.sharedFieldReferences[validators]; ref.Refs() > 1 { + v = b.validatorsReferences() + ref.MinusRef() + b.sharedFieldReferences[validators] = stateutil.NewRef(1) + } + + v[idx] = val + b.state.Validators = v + b.markFieldAsDirty(validators) + b.addDirtyIndices(validators, []uint64{uint64(idx)}) + + return nil +} + +// SetBalances for the beacon state. Updates the entire +// list to a new value by overwriting the previous one. +func (b *BeaconState) SetBalances(val []uint64) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.sharedFieldReferences[balances].MinusRef() + b.sharedFieldReferences[balances] = stateutil.NewRef(1) + + b.state.Balances = val + b.markFieldAsDirty(balances) + return nil +} + +// UpdateBalancesAtIndex for the beacon state. This method updates the balance +// at a specific index to a new value. +func (b *BeaconState) UpdateBalancesAtIndex(idx types.ValidatorIndex, val uint64) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + if uint64(len(b.state.Balances)) <= uint64(idx) { + return errors.Errorf("invalid index provided %d", idx) + } + b.lock.Lock() + defer b.lock.Unlock() + + bals := b.state.Balances + if b.sharedFieldReferences[balances].Refs() > 1 { + bals = b.balances() + b.sharedFieldReferences[balances].MinusRef() + b.sharedFieldReferences[balances] = stateutil.NewRef(1) + } + + bals[idx] = val + b.state.Balances = bals + b.markFieldAsDirty(balances) + return nil +} + +// SetSlashings for the beacon state. Updates the entire +// list to a new value by overwriting the previous one. +func (b *BeaconState) SetSlashings(val []uint64) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + b.sharedFieldReferences[slashings].MinusRef() + b.sharedFieldReferences[slashings] = stateutil.NewRef(1) + + b.state.Slashings = val + b.markFieldAsDirty(slashings) + return nil +} + +// UpdateSlashingsAtIndex for the beacon state. Updates the slashings +// at a specific index to a new value. +func (b *BeaconState) UpdateSlashingsAtIndex(idx, val uint64) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + if uint64(len(b.state.Slashings)) <= idx { + return errors.Errorf("invalid index provided %d", idx) + } + b.lock.Lock() + defer b.lock.Unlock() + + s := b.state.Slashings + if b.sharedFieldReferences[slashings].Refs() > 1 { + s = b.slashings() + b.sharedFieldReferences[slashings].MinusRef() + b.sharedFieldReferences[slashings] = stateutil.NewRef(1) + } + + s[idx] = val + + b.state.Slashings = s + + b.markFieldAsDirty(slashings) + return nil +} + +// AppendValidator for the beacon state. Appends the new value +// to the the end of list. +func (b *BeaconState) AppendValidator(val *ethpb.Validator) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + vals := b.state.Validators + if b.sharedFieldReferences[validators].Refs() > 1 { + vals = b.validatorsReferences() + b.sharedFieldReferences[validators].MinusRef() + b.sharedFieldReferences[validators] = stateutil.NewRef(1) + } + + // append validator to slice + b.state.Validators = append(vals, val) + valIdx := types.ValidatorIndex(len(b.state.Validators) - 1) + + // Copy if this is a shared validator map + if ref := b.valMapHandler.MapRef(); ref.Refs() > 1 { + valMap := b.valMapHandler.Copy() + ref.MinusRef() + b.valMapHandler = valMap + } + b.valMapHandler.Set(bytesutil.ToBytes48(val.PublicKey), valIdx) + + b.markFieldAsDirty(validators) + b.addDirtyIndices(validators, []uint64{uint64(valIdx)}) + return nil +} + +// AppendBalance for the beacon state. Appends the new value +// to the the end of list. +func (b *BeaconState) AppendBalance(bal uint64) error { + if !b.hasInnerState() { + return ErrNilInnerState + } + b.lock.Lock() + defer b.lock.Unlock() + + bals := b.state.Balances + if b.sharedFieldReferences[balances].Refs() > 1 { + bals = b.balances() + b.sharedFieldReferences[balances].MinusRef() + b.sharedFieldReferences[balances] = stateutil.NewRef(1) + } + + b.state.Balances = append(bals, bal) + b.markFieldAsDirty(balances) + return nil +}