Compare commits

..

14 Commits

Author SHA1 Message Date
nisdas
4c8e420ab4 simulate 2022-05-10 22:26:58 +08:00
terencechain
bbdf19cfd0 Process atts and update head before proposing (#10653)
* Process atts and updeate head

* Fix ctx

* New test and old tests

* Update validator_test.go

* Update validator_test.go

* Update service.go

* Rename to UpdateHead

* Update receive_attestation.go

* Update receive_attestation.go

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-09 23:12:50 +00:00
Radosław Kapka
5d94030b4f Cleanup of stategen package (#10607)
* powchain and stategen

* revert powchain changes

* rename field to blockRootsOfSavedStates

* rename params to blockRoot

* review feedback

* fix loop

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-09 22:25:47 +00:00
terencechain
16273a2040 Add engine timeout values (#10645)
* Add timeout values

* Update engine_client.go

* Update engine_client.go

* Update beacon-chain/powchain/engine_client.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update beacon-chain/powchain/engine_client.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update beacon-chain/powchain/engine_client.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update engine_client.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
2022-05-09 20:02:20 +00:00
Preston Van Loon
97663548a1 fuzz: Add fuzz tests for sparse merkle trie (#10662)
* Add fuzz tests for sparse merkle trie and change HTR signature to return an error

* fix capitalization of error message
2022-05-09 16:51:48 +00:00
Radosław Kapka
7d9d8454b1 Improvements to powchain package (#10652)
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-09 13:57:34 +00:00
Radosław Kapka
21bdbd548a Deduplicate native state (a.k.a. One State to rule them all) (#10483)
* v0

* getters/setters

* init and copy

* hasher

* all the nice stuff

* make bazel happy

* remove tests for smaller PR

* remove old states

* move files

* import fixes

* custom MarshalSSZ

* fixed deadlock

* copy version when copying state

* correct issues in state_trie

* fix Copy()

* better e2e comment

* add code to minimal state

* spectest test

* Revert "Auxiliary commit to revert individual files from 84154423464e8372f7e0a03367403656ac5cd78e"

This reverts commit 9602599d183081291dfa0ba4f1036430f63a7822.

* native state assert

* always error

* always log

* more native state usage

* cleanup

* remove empty line

* Revert "spectests"

This reverts commit 1c49bed5d1cf6224afaf21e18562bf72fae5d2b6.

# Conflicts:
#	beacon-chain/powchain/service.go
#	beacon-chain/state/v1/state_trie.go
#	beacon-chain/state/v2/state_trie.go
#	beacon-chain/state/v3/state_trie.go
#	testing/spectest/shared/phase0/finality/BUILD.bazel
#	testing/spectest/shared/phase0/finality/runner.go

* dedup field trie

* fix test issues

* cleanup

* use correct field num in FinalizedRootProof

* use existing version constant

* halfway there

* "working" version

* some fixes

* fix field nums in tests

* rename v0types to nativetypes

* Revert "Auxiliary commit to revert individual files from dc549b1cf8e724bd08cee1ecc760ff3771d5592d"

This reverts commit 7254d3070d8693b283fc686a2e01a822ecbac1b3.

* uncomment code

* remove map size

* Revert "Revert "spectests""

This reverts commit 39c271ae6b.

* use reverse map

* Revert "Revert "Revert "spectests"""

This reverts commit 19ba8cf95c.

* finally found the bug

(cherry picked from commit a5414c4be1bdb61a50b391ea5301895e772cc5e9)

* simplify populateFieldIndexes

* fix copy

(cherry picked from commit 7da4fb8cf51557ef931bb781872ea52fc6731af5)

* remove native state from e2e

* remove index map

* unsupported functions

* Use ProtobufBeaconState() from native state

* tests

* typo

* reduce complexity of `SaveStatesEfficient`

* remove unused receiver name

* update doc.go

* fix test assertion

* fix test assertion 2

* Phase0 justification bits

* bring back state tests

* rename fieldIndexRev

* versioning of ToProto

* remove version check from unexported function

* hasher tests

* don't return error from JustificationBits

* extract fieldConvertersNative

* helper error function

* use fieldConvertersNative

* Introduce RealPosition method on FieldIndex

* use RealPosition in hasher

* remove unused fields

* remove TestAppendBeyondIndicesLimit

(cherry picked from commit 3017e700282969c30006b64c95c21ffe6b166f8b)

* simplify RealPosition

* rename field interface

* use helper in proofs.go

* Update beacon-chain/core/altair/upgrade.go

Co-authored-by: Nishant Das <nishdas93@gmail.com>
Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
2022-05-09 13:02:34 +00:00
Nishant Das
e2caaf972f Fix Multiclient E2E Runs (#10660) 2022-05-09 12:38:11 +02:00
Nishant Das
c5ddc266ae Perform Request Size Limiting When Caching Eth1 Headers (#10649)
* rate limit reqs

* fix issues

* make it better

* final check

* terence's review

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-05-09 03:19:23 +00:00
Nishant Das
74518f0e1b Log Out Missing Validators in Participation Drops (#10624)
* debug failures

* clean up

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
2022-05-09 01:44:47 +00:00
terencechain
122c3f44cc Insert over-the-wire slashing to forkchoice (#10615)
* remove equivocating votes from forkchoice

* shutup deepsource

* Add insertSlashingsToForkChoiceStore

* Fix equality checks, add tests

* Update process_block.go

* Fix equality check for doublylinked

* More checks

* Rm err return

* Consider slashings over the wire

* Update new_slot_test.go

* Fix spec tests

* Add ReceiveAttesterSlashing

* Update mock.go

* Revert spec test changes

Co-authored-by: Potuz <potuz@prysmaticlabs.com>
2022-05-07 15:56:34 +00:00
kasey
b1b13cfca7 simplify config names, use strings (#10656)
* simplify config names, use strings

* lint

Co-authored-by: kasey <kasey@users.noreply.github.com>
2022-05-06 21:42:27 +00:00
Preston Van Loon
495013e832 Update github actions to go 1.18 (#10655) 2022-05-06 17:50:52 +00:00
kasey
ae82c17dc3 run process_slots before caching committee data (#10639)
* demonstrate issue with committee caching in e2e

* lint

* run process_slots before caching committee data

* pass transitioned state to UpdateCommitteeCache

* don't run extra epochs w/ web3signer

Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
2022-05-06 14:33:09 +08:00
267 changed files with 5310 additions and 11250 deletions

View File

@@ -38,10 +38,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Go 1.17
- name: Set up Go 1.18
uses: actions/setup-go@v3
with:
go-version: 1.17
go-version: 1.18
- name: Run Gosec Security Scanner
run: | # https://github.com/securego/gosec/issues/469
export PATH=$PATH:$(go env GOPATH)/bin
@@ -55,16 +55,16 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Go 1.17
- name: Set up Go 1.18
uses: actions/setup-go@v3
with:
go-version: 1.17
go-version: 1.18
id: go
- name: Golangci-lint
uses: golangci/golangci-lint-action@v2
with:
args: --print-issued-lines --sort-results --no-config --timeout=10m --disable-all -E deadcode -E errcheck -E gosimple --skip-files=validator/web/site_data.go --skip-dirs=proto --go=1.17
args: --print-issued-lines --sort-results --no-config --timeout=10m --disable-all -E deadcode -E errcheck -E gosimple --skip-files=validator/web/site_data.go --skip-dirs=proto --go=1.18
version: v1.45.2
skip-go-installation: true
@@ -75,7 +75,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: 1.17
go-version: 1.18
id: go
- name: Check out code into the Go module directory

View File

@@ -31,6 +31,12 @@ type ChainInfoFetcher interface {
HeadDomainFetcher
}
// HeadUpdater defines a common interface for methods in blockchain service
// which allow to update the head info
type HeadUpdater interface {
UpdateHead(context.Context) error
}
// TimeFetcher retrieves the Ethereum consensus data that's related to time.
type TimeFetcher interface {
GenesisTime() time.Time

View File

@@ -127,7 +127,7 @@ func (s *Service) onBlock(ctx context.Context, signed interfaces.SignedBeaconBlo
if err := s.insertBlockAndAttestationsToForkChoiceStore(ctx, signed.Block(), blockRoot, postState); err != nil {
return errors.Wrapf(err, "could not insert block %d to fork choice store", signed.Block().Slot())
}
s.insertSlashingsToForkChoiceStore(ctx, signed.Block())
s.insertSlashingsToForkChoiceStore(ctx, signed.Block().Body().AttesterSlashings())
if isValidPayload {
if err := s.cfg.ForkChoiceStore.SetOptimisticToValid(ctx, blockRoot); err != nil {
return errors.Wrap(err, "could not set optimistic block to valid")
@@ -495,15 +495,15 @@ func (s *Service) handleEpochBoundary(ctx context.Context, postState state.Beaco
defer span.End()
if postState.Slot()+1 == s.nextEpochBoundarySlot {
// Update caches for the next epoch at epoch boundary slot - 1.
if err := helpers.UpdateCommitteeCache(postState, coreTime.NextEpoch(postState)); err != nil {
return err
}
copied := postState.Copy()
copied, err := transition.ProcessSlots(ctx, copied, copied.Slot()+1)
if err != nil {
return err
}
// Update caches for the next epoch at epoch boundary slot - 1.
if err := helpers.UpdateCommitteeCache(copied, coreTime.CurrentEpoch(copied)); err != nil {
return err
}
if err := helpers.UpdateProposerIndicesInCache(ctx, copied); err != nil {
return err
}
@@ -576,8 +576,7 @@ func (s *Service) insertBlockToForkChoiceStore(ctx context.Context, blk interfac
// Inserts attester slashing indices to fork choice store.
// To call this function, it's caller's responsibility to ensure the slashing object is valid.
func (s *Service) insertSlashingsToForkChoiceStore(ctx context.Context, blk interfaces.BeaconBlock) {
slashings := blk.Body().AttesterSlashings()
func (s *Service) insertSlashingsToForkChoiceStore(ctx context.Context, slashings []*ethpb.AttesterSlashing) {
for _, slashing := range slashings {
indices := blocks.SlashableAttesterIndices(slashing)
for _, index := range indices {

View File

@@ -1885,5 +1885,5 @@ func TestService_insertSlashingsToForkChoiceStore(t *testing.T) {
b.Block.Body.AttesterSlashings = slashings
wb, err := wrapper.WrappedSignedBeaconBlock(b)
require.NoError(t, err)
service.insertSlashingsToForkChoiceStore(ctx, wb.Block())
service.insertSlashingsToForkChoiceStore(ctx, wb.Block().Body().AttesterSlashings())
}

View File

@@ -117,7 +117,7 @@ func (s *Service) spawnProcessAttestationsRoutine(stateFeed *event.Feed) {
log.Warn("Genesis time received, now available to process attestations")
}
st := slots.NewSlotTicker(s.genesisTime, params.BeaconConfig().SecondsPerSlot/2)
st := slots.NewSlotTicker(s.genesisTime, params.BeaconConfig().SecondsPerSlot)
for {
select {
case <-s.ctx.Done():
@@ -128,39 +128,52 @@ func (s *Service) spawnProcessAttestationsRoutine(stateFeed *event.Feed) {
return
}
// Continue when there's no fork choice attestation, there's nothing to process and update head.
// This covers the condition when the node is still initial syncing to the head of the chain.
if s.cfg.AttPool.ForkchoiceAttestationCount() == 0 {
continue
if err := s.UpdateHead(s.ctx); err != nil {
log.WithError(err).Error("Could not process attestations and update head")
return
}
s.processAttestations(s.ctx)
justified := s.store.JustifiedCheckpt()
if justified == nil {
log.WithError(errNilJustifiedInStore).Error("Could not get justified checkpoint")
continue
}
balances, err := s.justifiedBalances.get(s.ctx, bytesutil.ToBytes32(justified.Root))
if err != nil {
log.WithError(err).Errorf("Unable to get justified balances for root %v", justified.Root)
continue
}
newHeadRoot, err := s.updateHead(s.ctx, balances)
if err != nil {
log.WithError(err).Warn("Resolving fork due to new attestation")
}
if s.headRoot() != newHeadRoot {
log.WithFields(logrus.Fields{
"oldHeadRoot": fmt.Sprintf("%#x", s.headRoot()),
"newHeadRoot": fmt.Sprintf("%#x", newHeadRoot),
}).Debug("Head changed due to attestations")
}
s.notifyEngineIfChangedHead(s.ctx, newHeadRoot)
}
}
}()
}
// UpdateHead updates the canonical head of the chain based on information from fork-choice attestations and votes.
// It requires no external inputs.
func (s *Service) UpdateHead(ctx context.Context) error {
// Continue when there's no fork choice attestation, there's nothing to process and update head.
// This covers the condition when the node is still initial syncing to the head of the chain.
if s.cfg.AttPool.ForkchoiceAttestationCount() == 0 {
return nil
}
// Only one process can process attestations and update head at a time.
s.processAttestationsLock.Lock()
defer s.processAttestationsLock.Unlock()
s.processAttestations(ctx)
justified := s.store.JustifiedCheckpt()
if justified == nil {
return errNilJustifiedInStore
}
balances, err := s.justifiedBalances.get(ctx, bytesutil.ToBytes32(justified.Root))
if err != nil {
return err
}
newHeadRoot, err := s.updateHead(ctx, balances)
if err != nil {
log.WithError(err).Warn("Resolving fork due to new attestation")
}
if s.headRoot() != newHeadRoot {
log.WithFields(logrus.Fields{
"oldHeadRoot": fmt.Sprintf("%#x", s.headRoot()),
"newHeadRoot": fmt.Sprintf("%#x", newHeadRoot),
}).Debug("Head changed due to attestations")
}
s.notifyEngineIfChangedHead(ctx, newHeadRoot)
return nil
}
// This calls notify Forkchoice Update in the event that the head has changed
func (s *Service) notifyEngineIfChangedHead(ctx context.Context, newHeadRoot [32]byte) {
if s.headRoot() == newHeadRoot {

View File

@@ -200,3 +200,37 @@ func TestNotifyEngineIfChangedHead(t *testing.T) {
require.Equal(t, types.ValidatorIndex(1), vId)
require.Equal(t, [8]byte{1}, payloadID)
}
func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) {
ctx := context.Background()
opts := testServiceOptsWithDB(t)
opts = append(opts, WithAttestationPool(attestations.NewPool()), WithStateNotifier(&mockBeaconNode{}))
service, err := NewService(ctx, opts...)
require.NoError(t, err)
service.genesisTime = prysmTime.Now().Add(-1 * time.Duration(params.BeaconConfig().SecondsPerSlot) * time.Second)
genesisState, pks := util.DeterministicGenesisState(t, 64)
require.NoError(t, genesisState.SetGenesisTime(uint64(prysmTime.Now().Unix())-params.BeaconConfig().SecondsPerSlot))
require.NoError(t, service.saveGenesisData(ctx, genesisState))
atts, err := util.GenerateAttestations(genesisState, pks, 1, 0, false)
require.NoError(t, err)
tRoot := bytesutil.ToBytes32(atts[0].Data.Target.Root)
copied := genesisState.Copy()
copied, err = transition.ProcessSlots(ctx, copied, 1)
require.NoError(t, err)
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, copied, tRoot))
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, &ethpb.StateSummary{Root: tRoot[:]}))
require.NoError(t, service.cfg.ForkChoiceStore.InsertOptimisticBlock(ctx, 0, tRoot, tRoot, params.BeaconConfig().ZeroHash, 1, 1))
require.NoError(t, service.cfg.AttPool.SaveForkchoiceAttestations(atts))
b := util.NewBeaconBlock()
wb, err := wrapper.WrappedSignedBeaconBlock(b)
require.NoError(t, err)
r, err := b.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wb))
service.head.root = r // Old head
require.Equal(t, 1, len(service.cfg.AttPool.ForkchoiceAttestations()))
require.NoError(t, err, service.UpdateHead(ctx))
require.Equal(t, tRoot, service.head.root) // Validate head is the new one
require.Equal(t, 0, len(service.cfg.AttPool.ForkchoiceAttestations())) // Validate att pool is empty
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/monitoring/tracing"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/time"
"github.com/prysmaticlabs/prysm/time/slots"
"go.opencensus.io/trace"
@@ -24,6 +25,11 @@ type BlockReceiver interface {
HasBlock(ctx context.Context, root [32]byte) bool
}
// SlashingReceiver interface defines the methods of chain service for receiving validated slashing over the wire.
type SlashingReceiver interface {
ReceiveAttesterSlashing(ctx context.Context, slashings *ethpb.AttesterSlashing)
}
// ReceiveBlock is a function that defines the the operations (minus pubsub)
// that are performed on blocks that is received from regular sync service. The operations consists of:
// 1. Validate block, apply state transition and update check points
@@ -133,6 +139,11 @@ func (s *Service) HasBlock(ctx context.Context, root [32]byte) bool {
return s.hasBlockInInitSyncOrDB(ctx, root)
}
// ReceiveAttesterSlashing receives an attester slashing and inserts it to forkchoice
func (s *Service) ReceiveAttesterSlashing(ctx context.Context, slashing *ethpb.AttesterSlashing) {
s.insertSlashingsToForkChoiceStore(ctx, []*ethpb.AttesterSlashing{slashing})
}
func (s *Service) handlePostBlockOperations(b interfaces.BeaconBlock) error {
// Delete the processed block attestations from attestation pool.
if err := s.deletePoolAtts(b.Body().Attestations()); err != nil {

View File

@@ -50,21 +50,22 @@ const headSyncMinEpochsAfterCheckpoint = 128
// Service represents a service that handles the internal
// logic of managing the full PoS beacon chain.
type Service struct {
cfg *config
ctx context.Context
cancel context.CancelFunc
genesisTime time.Time
head *head
headLock sync.RWMutex
originBlockRoot [32]byte // genesis root, or weak subjectivity checkpoint root, depending on how the node is initialized
nextEpochBoundarySlot types.Slot
boundaryRoots [][32]byte
checkpointStateCache *cache.CheckpointStateCache
initSyncBlocks map[[32]byte]interfaces.SignedBeaconBlock
initSyncBlocksLock sync.RWMutex
justifiedBalances *stateBalanceCache
wsVerifier *WeakSubjectivityVerifier
store *store.Store
cfg *config
ctx context.Context
cancel context.CancelFunc
genesisTime time.Time
head *head
headLock sync.RWMutex
originBlockRoot [32]byte // genesis root, or weak subjectivity checkpoint root, depending on how the node is initialized
nextEpochBoundarySlot types.Slot
boundaryRoots [][32]byte
checkpointStateCache *cache.CheckpointStateCache
initSyncBlocks map[[32]byte]interfaces.SignedBeaconBlock
initSyncBlocksLock sync.RWMutex
justifiedBalances *stateBalanceCache
wsVerifier *WeakSubjectivityVerifier
store *store.Store
processAttestationsLock sync.Mutex
}
// config options for the service.
@@ -143,6 +144,7 @@ func (s *Service) Stop() error {
defer s.cancel()
if s.cfg.StateGen != nil && s.head != nil && s.head.state != nil {
// Save the last finalized state so that starting up in the following run will be much faster.
if err := s.cfg.StateGen.ForceCheckpoint(s.ctx, s.head.state.FinalizedCheckpoint().Root); err != nil {
return err
}

View File

@@ -221,7 +221,8 @@ func TestChainService_InitializeBeaconChain(t *testing.T) {
require.NoError(t, err)
trie, _, err := util.DepositTrieFromDeposits(deposits)
require.NoError(t, err)
hashTreeRoot := trie.HashTreeRoot()
hashTreeRoot, err := trie.HashTreeRoot()
require.NoError(t, err)
genState, err := transition.EmptyGenesisState()
require.NoError(t, err)
err = genState.SetEth1Data(&ethpb.Eth1Data{

View File

@@ -450,3 +450,9 @@ func (s *ChainService) IsOptimistic(_ context.Context) (bool, error) {
func (s *ChainService) IsOptimisticForRoot(_ context.Context, _ [32]byte) (bool, error) {
return s.Optimistic, nil
}
// ProcessAttestationsAndUpdateHead mocks the same method in the chain service.
func (s *ChainService) UpdateHead(_ context.Context) error { return nil }
// ReceiveAttesterSlashing mocks the same method in the chain service.
func (s *ChainService) ReceiveAttesterSlashing(context.Context, *ethpb.AttesterSlashing) {}

View File

@@ -430,7 +430,11 @@ func TestFinalizedDeposits_DepositsCachedCorrectly(t *testing.T) {
}
trie, err := trie.GenerateTrieFromItems(deps, params.BeaconConfig().DepositContractTreeDepth)
require.NoError(t, err, "Could not generate deposit trie")
assert.Equal(t, trie.HashTreeRoot(), cachedDeposits.Deposits.HashTreeRoot())
rootA, err := trie.HashTreeRoot()
require.NoError(t, err)
rootB, err := cachedDeposits.Deposits.HashTreeRoot()
require.NoError(t, err)
assert.Equal(t, rootA, rootB)
}
func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
@@ -488,7 +492,11 @@ func TestFinalizedDeposits_UtilizesPreviouslyCachedDeposits(t *testing.T) {
}
trie, err := trie.GenerateTrieFromItems(deps, params.BeaconConfig().DepositContractTreeDepth)
require.NoError(t, err, "Could not generate deposit trie")
assert.Equal(t, trie.HashTreeRoot(), cachedDeposits.Deposits.HashTreeRoot())
rootA, err := trie.HashTreeRoot()
require.NoError(t, err)
rootB, err := cachedDeposits.Deposits.HashTreeRoot()
require.NoError(t, err)
assert.Equal(t, rootA, rootB)
}
func TestFinalizedDeposits_HandleZeroDeposits(t *testing.T) {

View File

@@ -16,6 +16,7 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/altair",
visibility = [
"//beacon-chain:__subpackages__",
"//testing/endtoend/evaluators:__subpackages__",
"//testing/spectest:__subpackages__",
"//testing/util:__pkg__",
"//validator/client:__pkg__",

View File

@@ -143,7 +143,8 @@ func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
},
}
balances := []uint64{0, 50}
root := depositTrie.HashTreeRoot()
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
beaconState, err := stateAltair.InitializeFromProto(&ethpb.BeaconStateAltair{
Validators: registry,
Balances: balances,
@@ -202,7 +203,8 @@ func TestProcessDeposit_SkipsInvalidDeposit(t *testing.T) {
dep[0].Data.Signature = make([]byte, 96)
trie, _, err := util.DepositTrieFromDeposits(dep)
require.NoError(t, err)
root := trie.HashTreeRoot()
root, err := trie.HashTreeRoot()
require.NoError(t, err)
eth1Data := &ethpb.Eth1Data{
DepositRoot: root[:],
DepositCount: 1,

View File

@@ -173,7 +173,8 @@ func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
},
}
balances := []uint64{0, 50}
root := depositTrie.HashTreeRoot()
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Validators: registry,
Balances: balances,
@@ -233,7 +234,8 @@ func TestProcessDeposit_SkipsInvalidDeposit(t *testing.T) {
dep[0].Data.Signature = make([]byte, 96)
trie, _, err := util.DepositTrieFromDeposits(dep)
require.NoError(t, err)
root := trie.HashTreeRoot()
root, err := trie.HashTreeRoot()
require.NoError(t, err)
eth1Data := &ethpb.Eth1Data{
DepositRoot: root[:],
DepositCount: 1,
@@ -289,7 +291,9 @@ func TestPreGenesisDeposits_SkipInvalidDeposit(t *testing.T) {
require.NoError(t, err)
dep[i].Proof = proof
}
root := trie.HashTreeRoot()
root, err := trie.HashTreeRoot()
require.NoError(t, err)
eth1Data := &ethpb.Eth1Data{
DepositRoot: root[:],
DepositCount: 1,
@@ -376,7 +380,9 @@ func TestProcessDeposit_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T)
},
}
balances := []uint64{0, 50}
root := depositTrie.HashTreeRoot()
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Validators: registry,
Balances: balances,

View File

@@ -106,7 +106,7 @@ func weighJustificationAndFinalization(state state.BeaconState,
if err := state.SetCurrentJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: prevEpoch, Root: blockRoot}); err != nil {
return nil, err
}
newBits := state.JustificationBits()
newBits = state.JustificationBits()
newBits.SetBitAt(1, true)
if err := state.SetJustificationBits(newBits); err != nil {
return nil, err
@@ -122,7 +122,7 @@ func weighJustificationAndFinalization(state state.BeaconState,
if err := state.SetCurrentJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: currentEpoch, Root: blockRoot}); err != nil {
return nil, err
}
newBits := state.JustificationBits()
newBits = state.JustificationBits()
newBits.SetBitAt(0, true)
if err := state.SetJustificationBits(newBits); err != nil {
return nil, err

View File

@@ -41,7 +41,10 @@ func UpdateGenesisEth1Data(state state.BeaconState, deposits []*ethpb.Deposit, e
}
}
depositRoot := t.HashTreeRoot()
depositRoot, err := t.HashTreeRoot()
if err != nil {
return nil, err
}
eth1Data.DepositRoot = depositRoot[:]
err = state.SetEth1Data(eth1Data)
if err != nil {

View File

@@ -40,6 +40,7 @@ go_library(
"//beacon-chain/db/iface:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/genesis:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/v1:go_default_library",
"//beacon-chain/state/v2:go_default_library",
"//beacon-chain/state/v3:go_default_library",

View File

@@ -83,7 +83,7 @@ func TestEnsureEmbeddedGenesis(t *testing.T) {
// Embedded Genesis works with Mainnet config
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
cfg.ConfigName = params.ConfigNames[params.Mainnet]
cfg.ConfigName = params.MainnetName
params.OverrideBeaconConfig(cfg)
ctx := context.Background()

View File

@@ -10,6 +10,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/genesis"
state_native "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
v3 "github.com/prysmaticlabs/prysm/beacon-chain/state/v3"
@@ -204,7 +205,13 @@ func (s *Store) SaveStatesEfficient(ctx context.Context, states []state.ReadOnly
// look at issue https://github.com/prysmaticlabs/prysm/issues/9262.
switch rawType := states[i].InnerStateUnsafe().(type) {
case *ethpb.BeaconState:
pbState, err := v1.ProtobufBeaconState(rawType)
var pbState *ethpb.BeaconState
var err error
if features.Get().EnableNativeState {
pbState, err = state_native.ProtobufBeaconStatePhase0(rawType)
} else {
pbState, err = v1.ProtobufBeaconState(rawType)
}
if err != nil {
return err
}
@@ -225,7 +232,13 @@ func (s *Store) SaveStatesEfficient(ctx context.Context, states []state.ReadOnly
return err
}
case *ethpb.BeaconStateAltair:
pbState, err := v2.ProtobufBeaconState(rawType)
var pbState *ethpb.BeaconStateAltair
var err error
if features.Get().EnableNativeState {
pbState, err = state_native.ProtobufBeaconStateAltair(rawType)
} else {
pbState, err = v2.ProtobufBeaconState(rawType)
}
if err != nil {
return err
}
@@ -247,7 +260,13 @@ func (s *Store) SaveStatesEfficient(ctx context.Context, states []state.ReadOnly
return err
}
case *ethpb.BeaconStateBellatrix:
pbState, err := v3.ProtobufBeaconState(rawType)
var pbState *ethpb.BeaconStateBellatrix
var err error
if features.Get().EnableNativeState {
pbState, err = state_native.ProtobufBeaconStateBellatrix(rawType)
} else {
pbState, err = v3.ProtobufBeaconState(rawType)
}
if err != nil {
return err
}
@@ -274,28 +293,7 @@ func (s *Store) SaveStatesEfficient(ctx context.Context, states []state.ReadOnly
}
// store the validator entries separately to save space.
valBkt := tx.Bucket(stateValidatorsBucket)
for hashStr, validatorEntry := range validatorsEntries {
key := []byte(hashStr)
// if the entry is not in the cache and not in the DB,
// then insert it in the DB and add to the cache.
if _, ok := s.validatorEntryCache.Get(key); !ok {
validatorEntryCacheMiss.Inc()
if valEntry := valBkt.Get(key); valEntry == nil {
valBytes, encodeErr := encode(ctx, validatorEntry)
if encodeErr != nil {
return encodeErr
}
if putErr := valBkt.Put(key, valBytes); putErr != nil {
return putErr
}
s.validatorEntryCache.Set(key, validatorEntry, int64(len(valBytes)))
}
} else {
validatorEntryCacheHit.Inc()
}
}
return nil
return s.storeValidatorEntriesSeparately(ctx, tx, validatorsEntries)
}); err != nil {
return err
}
@@ -303,6 +301,31 @@ func (s *Store) SaveStatesEfficient(ctx context.Context, states []state.ReadOnly
return nil
}
func (s *Store) storeValidatorEntriesSeparately(ctx context.Context, tx *bolt.Tx, validatorsEntries map[string]*ethpb.Validator) error {
valBkt := tx.Bucket(stateValidatorsBucket)
for hashStr, validatorEntry := range validatorsEntries {
key := []byte(hashStr)
// if the entry is not in the cache and not in the DB,
// then insert it in the DB and add to the cache.
if _, ok := s.validatorEntryCache.Get(key); !ok {
validatorEntryCacheMiss.Inc()
if valEntry := valBkt.Get(key); valEntry == nil {
valBytes, encodeErr := encode(ctx, validatorEntry)
if encodeErr != nil {
return encodeErr
}
if putErr := valBkt.Put(key, valBytes); putErr != nil {
return putErr
}
s.validatorEntryCache.Set(key, validatorEntry, int64(len(valBytes)))
}
} else {
validatorEntryCacheHit.Inc()
}
}
return nil
}
// HasState checks if a state by root exists in the db.
func (s *Store) HasState(ctx context.Context, blockRoot [32]byte) bool {
_, span := trace.StartSpan(ctx, "BeaconDB.HasState")

View File

@@ -15,13 +15,13 @@ func TestSaveOrigin(t *testing.T) {
// Embedded Genesis works with Mainnet config
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig()
cfg.ConfigName = params.ConfigNames[params.Mainnet]
cfg.ConfigName = params.MainnetName
params.OverrideBeaconConfig(cfg)
ctx := context.Background()
db := setupDB(t)
st, err := genesis.State(params.Mainnet.String())
st, err := genesis.State(params.MainnetName)
require.NoError(t, err)
sb, err := st.MarshalSSZ()

View File

@@ -779,6 +779,7 @@ func (b *BeaconNode) registerRPCService() error {
PeerManager: p2pService,
MetadataProvider: p2pService,
ChainInfoFetcher: chainService,
HeadUpdater: chainService,
HeadFetcher: chainService,
CanonicalFetcher: chainService,
ForkFetcher: chainService,

View File

@@ -34,7 +34,7 @@ go_library(
"//beacon-chain/db:go_default_library",
"//beacon-chain/powchain/types:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native/v1:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/state/v1:go_default_library",
"//config/features:go_default_library",

View File

@@ -22,7 +22,7 @@ const repeatedSearches = 2 * searchThreshold
// BlockExists returns true if the block exists, its height and any possible error encountered.
func (s *Service) BlockExists(ctx context.Context, hash common.Hash) (bool, *big.Int, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.web3service.BlockExists")
ctx, span := trace.StartSpan(ctx, "powchain.BlockExists")
defer span.End()
if exists, hdrInfo, err := s.headerCache.HeaderInfoByHash(hash); exists || err != nil {
@@ -45,24 +45,9 @@ func (s *Service) BlockExists(ctx context.Context, hash common.Hash) (bool, *big
return true, new(big.Int).Set(header.Number), nil
}
// BlockExistsWithCache returns true if the block exists in cache, its height and any possible error encountered.
func (s *Service) BlockExistsWithCache(ctx context.Context, hash common.Hash) (bool, *big.Int, error) {
_, span := trace.StartSpan(ctx, "beacon-chain.web3service.BlockExistsWithCache")
defer span.End()
if exists, hdrInfo, err := s.headerCache.HeaderInfoByHash(hash); exists || err != nil {
if err != nil {
return false, nil, err
}
span.AddAttributes(trace.BoolAttribute("blockCacheHit", true))
return true, hdrInfo.Number, nil
}
span.AddAttributes(trace.BoolAttribute("blockCacheHit", false))
return false, nil, nil
}
// BlockHashByHeight returns the block hash of the block at the given height.
func (s *Service) BlockHashByHeight(ctx context.Context, height *big.Int) (common.Hash, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.web3service.BlockHashByHeight")
ctx, span := trace.StartSpan(ctx, "powchain.BlockHashByHeight")
defer span.End()
if exists, hInfo, err := s.headerCache.HeaderInfoByHeight(height); exists || err != nil {
@@ -90,9 +75,9 @@ func (s *Service) BlockHashByHeight(ctx context.Context, height *big.Int) (commo
return header.Hash(), nil
}
// BlockTimeByHeight fetches an eth1.0 block timestamp by its height.
// BlockTimeByHeight fetches an eth1 block timestamp by its height.
func (s *Service) BlockTimeByHeight(ctx context.Context, height *big.Int) (uint64, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.web3service.BlockTimeByHeight")
ctx, span := trace.StartSpan(ctx, "powchain.BlockTimeByHeight")
defer span.End()
if s.eth1DataFetcher == nil {
err := errors.New("nil eth1DataFetcher")
@@ -111,7 +96,7 @@ func (s *Service) BlockTimeByHeight(ctx context.Context, height *big.Int) (uint6
// This is an optimized version with the worst case being O(2*repeatedSearches) number of calls
// while in best case search for the block is performed in O(1).
func (s *Service) BlockByTimestamp(ctx context.Context, time uint64) (*types.HeaderInfo, error) {
ctx, span := trace.StartSpan(ctx, "beacon-chain.web3service.BlockByTimestamp")
ctx, span := trace.StartSpan(ctx, "powchain.BlockByTimestamp")
defer span.End()
s.latestEth1DataLock.RLock()
@@ -122,15 +107,14 @@ func (s *Service) BlockByTimestamp(ctx context.Context, time uint64) (*types.Hea
if time > latestBlkTime {
return nil, errors.Errorf("provided time is later than the current eth1 head. %d > %d", time, latestBlkTime)
}
// Initialize a pointer to eth1 chain's history to start our search
// from.
// Initialize a pointer to eth1 chain's history to start our search from.
cursorNum := big.NewInt(0).SetUint64(latestBlkHeight)
cursorTime := latestBlkTime
numOfBlocks := uint64(0)
estimatedBlk := cursorNum.Uint64()
maxTimeBuffer := searchThreshold * params.BeaconConfig().SecondsPerETH1Block
// Terminate if we cant find an acceptable block after
// Terminate if we can't find an acceptable block after
// repeated searches.
for i := 0; i < repeatedSearches; i++ {
if ctx.Err() != nil {
@@ -157,12 +141,12 @@ func (s *Service) BlockByTimestamp(ctx context.Context, time uint64) (*types.Hea
// time - buffer <= head.time <= time + buffer
break
}
hinfo, err := s.retrieveHeaderInfo(ctx, estimatedBlk)
hInfo, err := s.retrieveHeaderInfo(ctx, estimatedBlk)
if err != nil {
return nil, err
}
cursorNum = hinfo.Number
cursorTime = hinfo.Time
cursorNum = hInfo.Number
cursorTime = hInfo.Time
}
// Exit early if we get the desired block.
@@ -170,15 +154,15 @@ func (s *Service) BlockByTimestamp(ctx context.Context, time uint64) (*types.Hea
return s.retrieveHeaderInfo(ctx, cursorNum.Uint64())
}
if cursorTime > time {
return s.findLessTargetEth1Block(ctx, big.NewInt(0).SetUint64(estimatedBlk), time)
return s.findMaxTargetEth1Block(ctx, big.NewInt(0).SetUint64(estimatedBlk), time)
}
return s.findMoreTargetEth1Block(ctx, big.NewInt(0).SetUint64(estimatedBlk), time)
return s.findMinTargetEth1Block(ctx, big.NewInt(0).SetUint64(estimatedBlk), time)
}
// Performs a search to find a target eth1 block which is earlier than or equal to the
// target time. This method is used when head.time > targetTime
func (s *Service) findLessTargetEth1Block(ctx context.Context, startBlk *big.Int, targetTime uint64) (*types.HeaderInfo, error) {
for bn := startBlk; ; bn = big.NewInt(0).Sub(bn, big.NewInt(1)) {
func (s *Service) findMaxTargetEth1Block(ctx context.Context, upperBoundBlk *big.Int, targetTime uint64) (*types.HeaderInfo, error) {
for bn := upperBoundBlk; ; bn = big.NewInt(0).Sub(bn, big.NewInt(1)) {
if ctx.Err() != nil {
return nil, ctx.Err()
}
@@ -194,8 +178,8 @@ func (s *Service) findLessTargetEth1Block(ctx context.Context, startBlk *big.Int
// Performs a search to find a target eth1 block which is just earlier than or equal to the
// target time. This method is used when head.time < targetTime
func (s *Service) findMoreTargetEth1Block(ctx context.Context, startBlk *big.Int, targetTime uint64) (*types.HeaderInfo, error) {
for bn := startBlk; ; bn = big.NewInt(0).Add(bn, big.NewInt(1)) {
func (s *Service) findMinTargetEth1Block(ctx context.Context, lowerBoundBlk *big.Int, targetTime uint64) (*types.HeaderInfo, error) {
for bn := lowerBoundBlk; ; bn = big.NewInt(0).Add(bn, big.NewInt(1)) {
if ctx.Err() != nil {
return nil, ctx.Err()
}
@@ -203,8 +187,7 @@ func (s *Service) findMoreTargetEth1Block(ctx context.Context, startBlk *big.Int
if err != nil {
return nil, err
}
// Return the last block before we hit the threshold
// time.
// Return the last block before we hit the threshold time.
if info.Time > targetTime {
return s.retrieveHeaderInfo(ctx, info.Number.Uint64()-1)
}

View File

@@ -61,7 +61,7 @@ func TestLatestMainchainInfo_OK(t *testing.T) {
require.NoError(t, err)
tickerChan := make(chan time.Time)
web3Service.headTicker = &time.Ticker{C: tickerChan}
web3Service.eth1HeadTicker = &time.Ticker{C: tickerChan}
tickerChan <- time.Now()
web3Service.cancel()
exitRoutine <- true
@@ -207,51 +207,6 @@ func TestBlockExists_UsesCachedBlockInfo(t *testing.T) {
require.Equal(t, 0, height.Cmp(header.Number))
}
func TestBlockExistsWithCache_UsesCachedHeaderInfo(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
server, endpoint, err := mockPOW.SetupRPCServer()
require.NoError(t, err)
t.Cleanup(func() {
server.Stop()
})
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
header := &gethTypes.Header{
Number: big.NewInt(0),
}
err = web3Service.headerCache.AddHeader(header)
require.NoError(t, err)
exists, height, err := web3Service.BlockExistsWithCache(context.Background(), header.Hash())
require.NoError(t, err, "Could not get block hash with given height")
require.Equal(t, true, exists)
require.Equal(t, 0, height.Cmp(header.Number))
}
func TestBlockExistsWithCache_HeaderNotCached(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
server, endpoint, err := mockPOW.SetupRPCServer()
require.NoError(t, err)
t.Cleanup(func() {
server.Stop()
})
web3Service, err := NewService(context.Background(),
WithHttpEndpoints([]string{endpoint}),
WithDatabase(beaconDB),
)
require.NoError(t, err, "unable to setup web3 ETH1.0 chain service")
exists, height, err := web3Service.BlockExistsWithCache(context.Background(), common.BytesToHash([]byte("hash")))
require.NoError(t, err, "Could not get block hash with given height")
require.Equal(t, false, exists)
require.Equal(t, (*big.Int)(nil), height)
}
func TestService_BlockNumberByTimestamp(t *testing.T) {
beaconDB := dbutil.SetupDB(t)
testAcc, err := mock.Setup()
@@ -313,11 +268,11 @@ func TestService_BlockNumberByTimestampLessTargetTime(t *testing.T) {
defer cancel()
// Provide an unattainable target time
_, err = web3Service.findLessTargetEth1Block(ctx, hd.Number, hd.Time/2)
_, err = web3Service.findMaxTargetEth1Block(ctx, hd.Number, hd.Time/2)
require.ErrorContains(t, context.DeadlineExceeded.Error(), err)
// Provide an attainable target time
blk, err := web3Service.findLessTargetEth1Block(context.Background(), hd.Number, hd.Time-5)
blk, err := web3Service.findMaxTargetEth1Block(context.Background(), hd.Number, hd.Time-5)
require.NoError(t, err)
require.NotEqual(t, hd.Number.Uint64(), blk.Number.Uint64(), "retrieved block is not less than the head")
}
@@ -351,11 +306,11 @@ func TestService_BlockNumberByTimestampMoreTargetTime(t *testing.T) {
defer cancel()
// Provide an unattainable target time with respect to head
_, err = web3Service.findMoreTargetEth1Block(ctx, big.NewInt(0).Div(hd.Number, big.NewInt(2)), hd.Time)
_, err = web3Service.findMinTargetEth1Block(ctx, big.NewInt(0).Div(hd.Number, big.NewInt(2)), hd.Time)
require.ErrorContains(t, context.DeadlineExceeded.Error(), err)
// Provide an attainable target time with respect to head
blk, err := web3Service.findMoreTargetEth1Block(context.Background(), big.NewInt(0).Sub(hd.Number, big.NewInt(5)), hd.Time)
blk, err := web3Service.findMinTargetEth1Block(context.Background(), big.NewInt(0).Sub(hd.Number, big.NewInt(5)), hd.Time)
require.NoError(t, err)
require.Equal(t, hd.Number.Uint64(), blk.Number.Uint64(), "retrieved block is not equal to the head")
}

View File

@@ -138,7 +138,8 @@ func TestProcessDeposit_InvalidPublicKey(t *testing.T) {
deposits[0].Proof, err = trie.MerkleProof(0)
require.NoError(t, err)
root := trie.HashTreeRoot()
root, err := trie.HashTreeRoot()
require.NoError(t, err)
eth1Data := &ethpb.Eth1Data{
DepositCount: 1,
@@ -178,7 +179,8 @@ func TestProcessDeposit_InvalidSignature(t *testing.T) {
trie, err := trie.GenerateTrieFromItems([][]byte{leaf[:]}, params.BeaconConfig().DepositContractTreeDepth)
require.NoError(t, err)
root := trie.HashTreeRoot()
root, err := trie.HashTreeRoot()
require.NoError(t, err)
eth1Data := &ethpb.Eth1Data{
DepositCount: 1,
@@ -213,7 +215,8 @@ func TestProcessDeposit_UnableToVerify(t *testing.T) {
trie, _, err := util.DepositTrieFromDeposits(deposits)
require.NoError(t, err)
root := trie.HashTreeRoot()
root, err := trie.HashTreeRoot()
require.NoError(t, err)
eth1Data := &ethpb.Eth1Data{
DepositCount: 1,
DepositRoot: root[:],
@@ -265,7 +268,8 @@ func TestProcessDeposit_IncompleteDeposit(t *testing.T) {
trie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
require.NoError(t, err)
root := trie.HashTreeRoot()
root, err := trie.HashTreeRoot()
require.NoError(t, err)
eth1Data := &ethpb.Eth1Data{
DepositCount: 1,
DepositRoot: root[:],
@@ -281,7 +285,8 @@ func TestProcessDeposit_IncompleteDeposit(t *testing.T) {
for i := 0; i < int(factor-1); i++ {
assert.NoError(t, trie.Insert(dataRoot[:], i))
trieRoot := trie.HashTreeRoot()
trieRoot, err := trie.HashTreeRoot()
require.NoError(t, err)
eth1Data.DepositRoot = trieRoot[:]
eth1Data.DepositCount = uint64(i + 1)

View File

@@ -33,6 +33,10 @@ const (
ExecutionBlockByHashMethod = "eth_getBlockByHash"
// ExecutionBlockByNumberMethod request string for JSON-RPC.
ExecutionBlockByNumberMethod = "eth_getBlockByNumber"
// Defines the seconds to wait before timing out engine endpoints with block execution semantics (newPayload, forkchoiceUpdated).
payloadAndForkchoiceUpdatedTimeout = 8 * time.Second
// Defines the seconds before timing out engine endpoints with non-block execution semantics.
defaultEngineTimeout = time.Second
)
// ForkchoiceUpdatedResponse is the response kind received by the
@@ -65,7 +69,9 @@ func (s *Service) NewPayload(ctx context.Context, payload *pb.ExecutionPayload)
defer func() {
newPayloadLatency.Observe(float64(time.Since(start).Milliseconds()))
}()
d := time.Now().Add(payloadAndForkchoiceUpdatedTimeout)
ctx, cancel := context.WithDeadline(ctx, d)
defer cancel()
result := &pb.PayloadStatus{}
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethod, payload)
if err != nil {
@@ -99,6 +105,9 @@ func (s *Service) ForkchoiceUpdated(
forkchoiceUpdatedLatency.Observe(float64(time.Since(start).Milliseconds()))
}()
d := time.Now().Add(payloadAndForkchoiceUpdatedTimeout)
ctx, cancel := context.WithDeadline(ctx, d)
defer cancel()
result := &ForkchoiceUpdatedResponse{}
err := s.rpcClient.CallContext(ctx, result, ForkchoiceUpdatedMethod, state, attrs)
if err != nil {
@@ -132,6 +141,9 @@ func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.Execut
getPayloadLatency.Observe(float64(time.Since(start).Milliseconds()))
}()
d := time.Now().Add(defaultEngineTimeout)
ctx, cancel := context.WithDeadline(ctx, d)
defer cancel()
result := &pb.ExecutionPayload{}
err := s.rpcClient.CallContext(ctx, result, GetPayloadMethod, pb.PayloadIDBytes(payloadId))
return result, handleRPCError(err)
@@ -147,10 +159,14 @@ func (s *Service) ExchangeTransitionConfiguration(
// We set terminal block number to 0 as the parameter is not set on the consensus layer.
zeroBigNum := big.NewInt(0)
cfg.TerminalBlockNumber = zeroBigNum.Bytes()
d := time.Now().Add(defaultEngineTimeout)
ctx, cancel := context.WithDeadline(ctx, d)
defer cancel()
result := &pb.TransitionConfiguration{}
if err := s.rpcClient.CallContext(ctx, result, ExchangeTransitionConfigurationMethod, cfg); err != nil {
return handleRPCError(err)
}
// We surface an error to the user if local configuration settings mismatch
// according to the response from the execution node.
cfgTerminalHash := params.BeaconConfig().TerminalBlockHash[:]

View File

@@ -19,8 +19,6 @@ var (
ErrUnknownPayload = errors.New("payload does not exist or is not available")
// ErrUnknownPayloadStatus when the payload status is unknown.
ErrUnknownPayloadStatus = errors.New("unknown payload status")
// ErrUnsupportedScheme for unsupported URL schemes.
ErrUnsupportedScheme = errors.New("unsupported url scheme, only http(s) and ipc are supported")
// ErrConfigMismatch when the execution node's terminal total difficulty or
// terminal block hash received via the API mismatches Prysm's configuration value.
ErrConfigMismatch = errors.New("execution client configuration mismatch")

View File

@@ -5,6 +5,7 @@ import (
"encoding/binary"
"fmt"
"math/big"
"strings"
"time"
"github.com/ethereum/go-ethereum"
@@ -16,7 +17,9 @@ import (
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
coreState "github.com/prysmaticlabs/prysm/beacon-chain/core/transition"
state_native "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
"github.com/prysmaticlabs/prysm/config/features"
"github.com/prysmaticlabs/prysm/config/params"
contracts "github.com/prysmaticlabs/prysm/contracts/deposit"
"github.com/prysmaticlabs/prysm/crypto/hash"
@@ -33,22 +36,28 @@ var (
const eth1DataSavingInterval = 1000
const maxTolerableDifference = 50
const defaultEth1HeaderReqLimit = uint64(1000)
const depositlogRequestLimit = 10000
const depositLogRequestLimit = 10000
const additiveFactorMultiplier = 0.10
const multiplicativeDecreaseDivisor = 2
var errTimedOut = errors.New("net/http: request canceled")
func tooMuchDataRequestedError(err error) bool {
// this error is only infura specific (other providers might have different error messages)
return err.Error() == "query returned more than 10000 results"
}
func clientTimedOutError(err error) bool {
return strings.Contains(err.Error(), errTimedOut.Error())
}
// Eth2GenesisPowchainInfo retrieves the genesis time and eth1 block number of the beacon chain
// from the deposit contract.
func (s *Service) Eth2GenesisPowchainInfo() (uint64, *big.Int) {
return s.chainStartData.GenesisTime, big.NewInt(int64(s.chainStartData.GenesisBlock))
}
// ProcessETH1Block processes the logs from the provided eth1Block.
// ProcessETH1Block processes logs from the provided eth1 block.
func (s *Service) ProcessETH1Block(ctx context.Context, blkNum *big.Int) error {
query := ethereum.FilterQuery{
Addresses: []common.Address{
@@ -71,7 +80,7 @@ func (s *Service) ProcessETH1Block(ctx context.Context, blkNum *big.Int) error {
}
}
if !s.chainStartData.Chainstarted {
if err := s.checkBlockNumberForChainStart(ctx, blkNum); err != nil {
if err := s.processChainStartFromBlockNum(ctx, blkNum); err != nil {
return err
}
}
@@ -79,7 +88,7 @@ func (s *Service) ProcessETH1Block(ctx context.Context, blkNum *big.Int) error {
}
// ProcessLog is the main method which handles the processing of all
// logs from the deposit contract on the ETH1.0 chain.
// logs from the deposit contract on the eth1 chain.
func (s *Service) ProcessLog(ctx context.Context, depositLog gethTypes.Log) error {
s.processingLock.RLock()
defer s.processingLock.RUnlock()
@@ -98,7 +107,7 @@ func (s *Service) ProcessLog(ctx context.Context, depositLog gethTypes.Log) erro
}
// ProcessDepositLog processes the log which had been received from
// the ETH1.0 chain by trying to ascertain which participant deposited
// the eth1 chain by trying to ascertain which participant deposited
// in the contract.
func (s *Service) ProcessDepositLog(ctx context.Context, depositLog gethTypes.Log) error {
pubkey, withdrawalCredentials, amount, signature, merkleTreeIndex, err := contracts.UnpackDepositLogData(depositLog.Data)
@@ -131,7 +140,7 @@ func (s *Service) ProcessDepositLog(ctx context.Context, depositLog gethTypes.Lo
depositHash, err := depositData.HashTreeRoot()
if err != nil {
return errors.Wrap(err, "Unable to determine hashed value of deposit")
return errors.Wrap(err, "unable to determine hashed value of deposit")
}
// Defensive check to validate incoming index.
@@ -149,20 +158,27 @@ func (s *Service) ProcessDepositLog(ctx context.Context, depositLog gethTypes.Lo
if !s.chainStartData.Chainstarted {
proof, err := s.depositTrie.MerkleProof(int(index))
if err != nil {
return errors.Wrap(err, "Unable to generate merkle proof for deposit")
return errors.Wrap(err, "unable to generate merkle proof for deposit")
}
deposit.Proof = proof
}
// We always store all historical deposits in the DB.
err = s.cfg.depositCache.InsertDeposit(ctx, deposit, depositLog.BlockNumber, index, s.depositTrie.HashTreeRoot())
root, err := s.depositTrie.HashTreeRoot()
if err != nil {
return errors.Wrap(err, "unable to determine root of deposit trie")
}
err = s.cfg.depositCache.InsertDeposit(ctx, deposit, depositLog.BlockNumber, index, root)
if err != nil {
return errors.Wrap(err, "unable to insert deposit into cache")
}
validData := true
if !s.chainStartData.Chainstarted {
s.chainStartData.ChainstartDeposits = append(s.chainStartData.ChainstartDeposits, deposit)
root := s.depositTrie.HashTreeRoot()
root, err := s.depositTrie.HashTreeRoot()
if err != nil {
return errors.Wrap(err, "unable to determine root of deposit trie")
}
eth1Data := &ethpb.Eth1Data{
DepositRoot: root[:],
DepositCount: uint64(len(s.chainStartData.ChainstartDeposits)),
@@ -172,7 +188,11 @@ func (s *Service) ProcessDepositLog(ctx context.Context, depositLog gethTypes.Lo
validData = false
}
} else {
s.cfg.depositCache.InsertPendingDeposit(ctx, deposit, depositLog.BlockNumber, index, s.depositTrie.HashTreeRoot())
root, err := s.depositTrie.HashTreeRoot()
if err != nil {
return errors.Wrap(err, "unable to determine root of deposit trie")
}
s.cfg.depositCache.InsertPendingDeposit(ctx, deposit, depositLog.BlockNumber, index, root)
}
if validData {
log.WithFields(logrus.Fields{
@@ -206,7 +226,7 @@ func (s *Service) ProcessDepositLog(ctx context.Context, depositLog gethTypes.Lo
}
// ProcessChainStart processes the log which had been received from
// the ETH1.0 chain by trying to determine when to start the beacon chain.
// the eth1 chain by trying to determine when to start the beacon chain.
func (s *Service) ProcessChainStart(genesisTime uint64, eth1BlockHash [32]byte, blockNumber *big.Int) {
s.chainStartData.Chainstarted = true
s.chainStartData.GenesisBlock = blockNumber.Uint64()
@@ -216,12 +236,16 @@ func (s *Service) ProcessChainStart(genesisTime uint64, eth1BlockHash [32]byte,
for i := range s.chainStartData.ChainstartDeposits {
proof, err := s.depositTrie.MerkleProof(i)
if err != nil {
log.Errorf("Unable to generate deposit proof %v", err)
log.Errorf("unable to generate deposit proof %v", err)
}
s.chainStartData.ChainstartDeposits[i].Proof = proof
}
root := s.depositTrie.HashTreeRoot()
root, err := s.depositTrie.HashTreeRoot()
if err != nil { // This should never happen.
log.WithError(err).Error("unable to determine root of deposit trie, aborting chain start")
return
}
s.chainStartData.Eth1Data = &ethpb.Eth1Data{
DepositCount: uint64(len(s.chainStartData.ChainstartDeposits)),
DepositRoot: root[:],
@@ -238,15 +262,15 @@ func (s *Service) ProcessChainStart(genesisTime uint64, eth1BlockHash [32]byte,
},
})
if err := s.savePowchainData(s.ctx); err != nil {
// continue on, if the save fails as this will get re-saved
// continue on if the save fails as this will get re-saved
// in the next interval.
log.Error(err)
}
}
// createGenesisTime adds in the genesis delay to the eth1 block time
// on which it was triggered.
func createGenesisTime(timeStamp uint64) uint64 {
// adds in the genesis delay to the eth1 block time
// on which it was triggered.
return timeStamp + params.BeaconConfig().GenesisDelay
}
@@ -283,7 +307,7 @@ func (s *Service) processPastLogs(ctx context.Context) error {
}
return nil
}
latestFollowHeight, err := s.followBlockHeight(ctx)
latestFollowHeight, err := s.followedBlockHeight(ctx)
if err != nil {
return err
}
@@ -309,7 +333,7 @@ func (s *Service) processPastLogs(ctx context.Context) error {
remainingLogs := logCount - uint64(s.lastReceivedMerkleIndex+1)
// only change the end block if the remaining logs are below the required log limit.
// reset our query and end block in this case.
withinLimit := remainingLogs < depositlogRequestLimit
withinLimit := remainingLogs < depositLogRequestLimit
aboveFollowHeight := end >= latestFollowHeight
if withinLimit && aboveFollowHeight {
query.ToBlock = big.NewInt(0).SetUint64(latestFollowHeight)
@@ -404,9 +428,9 @@ func (s *Service) processPastLogs(ctx context.Context) error {
// logs from the period last polled to now.
func (s *Service) requestBatchedHeadersAndLogs(ctx context.Context) error {
// We request for the nth block behind the current head, in order to have
// stabilized logs when we retrieve it from the 1.0 chain.
// stabilized logs when we retrieve it from the eth1 chain.
requestedBlock, err := s.followBlockHeight(ctx)
requestedBlock, err := s.followedBlockHeight(ctx)
if err != nil {
return err
}
@@ -448,18 +472,17 @@ func (s *Service) retrieveBlockHashAndTime(ctx context.Context, blkNum *big.Int)
return bHash, timeStamp, nil
}
// checkBlockNumberForChainStart checks the given block number for if chainstart has occurred.
func (s *Service) checkBlockNumberForChainStart(ctx context.Context, blkNum *big.Int) error {
func (s *Service) processChainStartFromBlockNum(ctx context.Context, blkNum *big.Int) error {
bHash, timeStamp, err := s.retrieveBlockHashAndTime(ctx, blkNum)
if err != nil {
return err
}
s.checkForChainstart(ctx, bHash, blkNum, timeStamp)
s.processChainStartIfReady(ctx, bHash, blkNum, timeStamp)
return nil
}
func (s *Service) checkHeaderForChainstart(ctx context.Context, header *gethTypes.Header) {
s.checkForChainstart(ctx, header.Hash(), header.Number, header.Time)
func (s *Service) processChainStartFromHeader(ctx context.Context, header *gethTypes.Header) {
s.processChainStartIfReady(ctx, header.Hash(), header.Number, header.Time)
}
func (s *Service) checkHeaderRange(ctx context.Context, start, end uint64, headersMap map[uint64]*gethTypes.Header,
@@ -475,7 +498,7 @@ func (s *Service) checkHeaderRange(ctx context.Context, start, end uint64, heade
i--
continue
}
s.checkHeaderForChainstart(ctx, h)
s.processChainStartFromHeader(ctx, h)
}
}
return nil
@@ -495,7 +518,7 @@ func (s *Service) currentCountAndTime(ctx context.Context, blockTime uint64) (ui
return valCount, createGenesisTime(blockTime)
}
func (s *Service) checkForChainstart(ctx context.Context, blockHash [32]byte, blockNumber *big.Int, blockTime uint64) {
func (s *Service) processChainStartIfReady(ctx context.Context, blockHash [32]byte, blockNumber *big.Int, blockTime uint64) {
valCount, genesisTime := s.currentCountAndTime(ctx, blockTime)
if valCount == 0 {
return
@@ -507,9 +530,15 @@ func (s *Service) checkForChainstart(ctx context.Context, blockHash [32]byte, bl
}
}
// save all powchain related metadata to disk.
// savePowchainData saves all powchain related metadata to disk.
func (s *Service) savePowchainData(ctx context.Context) error {
pbState, err := v1.ProtobufBeaconState(s.preGenesisState.InnerStateUnsafe())
var pbState *ethpb.BeaconState
var err error
if features.Get().EnableNativeState {
pbState, err = state_native.ProtobufBeaconStatePhase0(s.preGenesisState.InnerStateUnsafe())
} else {
pbState, err = v1.ProtobufBeaconState(s.preGenesisState.InnerStateUnsafe())
}
if err != nil {
return err
}

View File

@@ -589,7 +589,7 @@ func TestCheckForChainstart_NoValidator(t *testing.T) {
require.NoError(t, err, "Unable to set up simulated backend")
beaconDB := testDB.SetupDB(t)
s := newPowchainService(t, testAcc, beaconDB)
s.checkForChainstart(context.Background(), [32]byte{}, nil, 0)
s.processChainStartIfReady(context.Background(), [32]byte{}, nil, 0)
require.LogsDoNotContain(t, hook, "Could not determine active validator count from pre genesis state")
}

View File

@@ -13,7 +13,6 @@ import (
"sync"
"time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -30,7 +29,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/db"
"github.com/prysmaticlabs/prysm/beacon-chain/powchain/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
nativev1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
native "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
"github.com/prysmaticlabs/prysm/config/features"
@@ -98,7 +97,6 @@ type POWBlockFetcher interface {
BlockByTimestamp(ctx context.Context, time uint64) (*types.HeaderInfo, error)
BlockHashByHeight(ctx context.Context, height *big.Int) (common.Hash, error)
BlockExists(ctx context.Context, hash common.Hash) (bool, *big.Int, error)
BlockExistsWithCache(ctx context.Context, hash common.Hash) (bool, *big.Int, error)
}
// Chain defines a standard interface for the powchain service in Prysm.
@@ -114,7 +112,6 @@ type RPCDataFetcher interface {
Close()
HeaderByNumber(ctx context.Context, number *big.Int) (*gethTypes.Header, error)
HeaderByHash(ctx context.Context, hash common.Hash) (*gethTypes.Header, error)
SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error)
}
// RPCClient defines the rpc methods required to interact with the eth1 node.
@@ -139,10 +136,10 @@ type config struct {
}
// Service fetches important information about the canonical
// Ethereum ETH1.0 chain via a web3 endpoint using an ethclient. The Random
// Beacon Chain requires synchronization with the ETH1.0 chain's current
// blockhash, block number, and access to logs within the
// Validator Registration Contract on the ETH1.0 chain to kick off the beacon
// eth1 chain via a web3 endpoint using an ethclient.
// The beacon chain requires synchronization with the eth1 chain's current
// block hash, block number, and access to logs within the
// Validator Registration Contract on the eth1 chain to kick off the beacon
// chain's validator registration process.
type Service struct {
connectedETH1 bool
@@ -152,7 +149,7 @@ type Service struct {
cfg *config
ctx context.Context
cancel context.CancelFunc
headTicker *time.Ticker
eth1HeadTicker *time.Ticker
httpLogger bind.ContractFilterer
eth1DataFetcher RPCDataFetcher
rpcClient RPCClient
@@ -173,11 +170,11 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
depositTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
if err != nil {
cancel()
return nil, errors.Wrap(err, "could not setup deposit trie")
return nil, errors.Wrap(err, "could not set up deposit trie")
}
genState, err := transition.EmptyGenesisState()
if err != nil {
return nil, errors.Wrap(err, "could not setup genesis state")
return nil, errors.Wrap(err, "could not set up genesis state")
}
s := &Service{
@@ -201,7 +198,7 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
},
lastReceivedMerkleIndex: -1,
preGenesisState: genState,
headTicker: time.NewTicker(time.Duration(params.BeaconConfig().SecondsPerETH1Block) * time.Second),
eth1HeadTicker: time.NewTicker(time.Duration(params.BeaconConfig().SecondsPerETH1Block) * time.Second),
}
for _, opt := range opts {
@@ -225,7 +222,7 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
return s, nil
}
// Start a web3 service's main event loop.
// Start the powchain service's main event loop.
func (s *Service) Start() {
if err := s.setupExecutionClientConnections(s.ctx, s.cfg.currHttpEndpoint); err != nil {
log.WithError(err).Error("Could not connect to execution endpoint")
@@ -273,7 +270,7 @@ func (s *Service) Stop() error {
func (s *Service) ClearPreGenesisData() {
s.chainStartData.ChainstartDeposits = []*ethpb.Deposit{}
if features.Get().EnableNativeState {
s.preGenesisState = &nativev1.BeaconState{}
s.preGenesisState = &native.BeaconState{}
} else {
s.preGenesisState = &v1.BeaconState{}
}
@@ -372,7 +369,7 @@ func (s *Service) ETH1ConnectionErrors() []error {
// refers to the latest eth1 block which follows the condition: eth1_timestamp +
// SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= current_unix_time
func (s *Service) followBlockHeight(_ context.Context) (uint64, error) {
func (s *Service) followedBlockHeight(_ context.Context) (uint64, error) {
latestValidBlock := uint64(0)
if s.latestEth1Data.BlockHeight > params.BeaconConfig().Eth1FollowDistance {
latestValidBlock = s.latestEth1Data.BlockHeight - params.BeaconConfig().Eth1FollowDistance
@@ -386,8 +383,7 @@ func (s *Service) initDepositCaches(ctx context.Context, ctrs []*ethpb.DepositCo
}
s.cfg.depositCache.InsertDepositContainers(ctx, ctrs)
if !s.chainStartData.Chainstarted {
// do not add to pending cache
// if no genesis state exists.
// Do not add to pending cache if no genesis state exists.
validDepositsCount.Add(float64(s.preGenesisState.Eth1DepositIndex()))
return nil
}
@@ -395,7 +391,7 @@ func (s *Service) initDepositCaches(ctx context.Context, ctrs []*ethpb.DepositCo
if err != nil {
return err
}
// Default to all deposits post-genesis deposits in
// Default to all post-genesis deposits in
// the event we cannot find a finalized state.
currIndex := genesisState.Eth1DepositIndex()
chkPt, err := s.cfg.beaconDB.FinalizedCheckpoint(ctx)
@@ -411,17 +407,17 @@ func (s *Service) initDepositCaches(ctx context.Context, ctrs []*ethpb.DepositCo
// Set deposit index to the one in the current archived state.
currIndex = fState.Eth1DepositIndex()
// when a node pauses for some time and starts again, the deposits to finalize
// accumulates. we finalize them here before we are ready to receive a block.
// When a node pauses for some time and starts again, the deposits to finalize
// accumulates. We finalize them here before we are ready to receive a block.
// Otherwise, the first few blocks will be slower to compute as we will
// hold the lock and be busy finalizing the deposits.
// The deposit index in the state is always the index of the next deposit
// to be included(rather than the last one to be processed). This was most likely
// to be included (rather than the last one to be processed). This was most likely
// done as the state cannot represent signed integers.
actualIndex := int64(currIndex) - 1 // lint:ignore uintcast -- deposit index will not exceed int64 in your lifetime.
s.cfg.depositCache.InsertFinalizedDeposits(ctx, actualIndex)
// Deposit proofs are only used during state transition and can be safely removed to save space.
// Deposit proofs are only used during state transition and can be safely removed to save space.
if err = s.cfg.depositCache.PruneProofs(ctx, actualIndex); err != nil {
return errors.Wrap(err, "could not prune deposit proofs")
}
@@ -498,8 +494,7 @@ func (s *Service) batchRequestHeaders(startBlock, endBlock uint64) ([]*gethTypes
return headers, nil
}
// safelyHandleHeader will recover and log any panic that occurs from the
// block
// safelyHandleHeader will recover and log any panic that occurs from the block
func safelyHandlePanic() {
if r := recover(); r != nil {
log.WithFields(logrus.Fields{
@@ -522,7 +517,7 @@ func (s *Service) handleETH1FollowDistance() {
log.Warn("Execution client is not syncing")
}
if !s.chainStartData.Chainstarted {
if err := s.checkBlockNumberForChainStart(ctx, big.NewInt(int64(s.latestEth1Data.LastRequestedBlock))); err != nil {
if err := s.processChainStartFromBlockNum(ctx, big.NewInt(int64(s.latestEth1Data.LastRequestedBlock))); err != nil {
s.runError = err
log.Error(err)
return
@@ -530,9 +525,8 @@ func (s *Service) handleETH1FollowDistance() {
}
// If the last requested block has not changed,
// we do not request batched logs as this means there are no new
// logs for the powchain service to process. Also is a potential
// failure condition as would mean we have not respected the protocol
// threshold.
// logs for the powchain service to process. Also it is a potential
// failure condition as would mean we have not respected the protocol threshold.
if s.latestEth1Data.LastRequestedBlock == s.latestEth1Data.BlockHeight {
log.Error("Beacon node is not respecting the follow distance")
return
@@ -595,7 +589,7 @@ func (s *Service) initPOWService() {
if s.chainStartData.Chainstarted && s.chainStartData.GenesisBlock == 0 {
genHash := common.BytesToHash(s.chainStartData.Eth1Data.BlockHash)
genBlock := s.chainStartData.GenesisBlock
// In the event our provided chainstart data references a non-existent blockhash
// In the event our provided chainstart data references a non-existent block hash,
// we assume the genesis block to be 0.
if genHash != [32]byte{} {
genHeader, err := s.eth1DataFetcher.HeaderByHash(ctx, genHash)
@@ -618,7 +612,7 @@ func (s *Service) initPOWService() {
}
}
// run subscribes to all the services for the ETH1.0 chain.
// run subscribes to all the services for the eth1 chain.
func (s *Service) run(done <-chan struct{}) {
s.runError = nil
@@ -636,7 +630,7 @@ func (s *Service) run(done <-chan struct{}) {
s.updateConnectedETH1(false)
log.Debug("Context closed, exiting goroutine")
return
case <-s.headTicker.C:
case <-s.eth1HeadTicker.C:
head, err := s.eth1DataFetcher.HeaderByNumber(s.ctx, nil)
if err != nil {
s.pollConnectionStatus(s.ctx)
@@ -692,10 +686,10 @@ func (s *Service) logTillChainStart(ctx context.Context) {
}
// cacheHeadersForEth1DataVote makes sure that voting for eth1data after startup utilizes cached headers
// instead of making multiple RPC requests to the ETH1 endpoint.
// instead of making multiple RPC requests to the eth1 endpoint.
func (s *Service) cacheHeadersForEth1DataVote(ctx context.Context) error {
// Find the end block to request from.
end, err := s.followBlockHeight(ctx)
end, err := s.followedBlockHeight(ctx)
if err != nil {
return err
}
@@ -703,20 +697,48 @@ func (s *Service) cacheHeadersForEth1DataVote(ctx context.Context) error {
if err != nil {
return err
}
// We call batchRequestHeaders for its header caching side-effect, so we don't need the return value.
_, err = s.batchRequestHeaders(start, end)
if err != nil {
return err
return s.cacheBlockHeaders(start, end)
}
// Caches block headers from the desired range.
func (s *Service) cacheBlockHeaders(start, end uint64) error {
batchSize := s.cfg.eth1HeaderReqLimit
for i := start; i < end; i += batchSize {
startReq := i
endReq := i + batchSize
if endReq > end {
endReq = end
}
// We call batchRequestHeaders for its header caching side-effect, so we don't need the return value.
_, err := s.batchRequestHeaders(startReq, endReq)
if err != nil {
if clientTimedOutError(err) {
// Reduce batch size as eth1 node is
// unable to respond to the request in time.
batchSize /= 2
// Always have it greater than 0.
if batchSize == 0 {
batchSize += 1
}
// Reset request value
if i > batchSize {
i -= batchSize
}
continue
}
return err
}
}
return nil
}
// determines the earliest voting block from which to start caching all our previous headers from.
// Determines the earliest voting block from which to start caching all our previous headers from.
func (s *Service) determineEarliestVotingBlock(ctx context.Context, followBlock uint64) (uint64, error) {
genesisTime := s.chainStartData.GenesisTime
currSlot := slots.CurrentSlot(genesisTime)
// In the event genesis has not occurred yet, we just request go back follow_distance blocks.
// In the event genesis has not occurred yet, we just request to go back follow_distance blocks.
if genesisTime == 0 || currSlot == 0 {
earliestBlk := uint64(0)
if followBlock > params.BeaconConfig().Eth1FollowDistance {
@@ -763,7 +785,7 @@ func (s *Service) initializeEth1Data(ctx context.Context, eth1DataInDB *ethpb.ET
return nil
}
// validates that all deposit containers are valid and have their relevant indices
// Validates that all deposit containers are valid and have their relevant indices
// in order.
func validateDepositContainers(ctrs []*ethpb.DepositContainer) bool {
ctrLen := len(ctrs)
@@ -786,7 +808,7 @@ func validateDepositContainers(ctrs []*ethpb.DepositContainer) bool {
return true
}
// validates the current powchain data saved and makes sure that any
// Validates the current powchain data is saved and makes sure that any
// embedded genesis state is correctly accounted for.
func (s *Service) ensureValidPowchainData(ctx context.Context) error {
genState, err := s.cfg.beaconDB.GenesisState(ctx)
@@ -802,7 +824,13 @@ func (s *Service) ensureValidPowchainData(ctx context.Context) error {
return errors.Wrap(err, "unable to retrieve eth1 data")
}
if eth1Data == nil || !eth1Data.ChainstartData.Chainstarted || !validateDepositContainers(eth1Data.DepositContainers) {
pbState, err := v1.ProtobufBeaconState(s.preGenesisState.InnerStateUnsafe())
var pbState *ethpb.BeaconState
var err error
if features.Get().EnableNativeState {
pbState, err = native.ProtobufBeaconStatePhase0(s.preGenesisState.InnerStateUnsafe())
} else {
pbState, err = v1.ProtobufBeaconState(s.preGenesisState.InnerStateUnsafe())
}
if err != nil {
return err
}

View File

@@ -12,7 +12,9 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
gethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rpc"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/async/event"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
@@ -265,7 +267,7 @@ func TestFollowBlock_OK(t *testing.T) {
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
h, err := web3Service.followBlockHeight(context.Background())
h, err := web3Service.followedBlockHeight(context.Background())
require.NoError(t, err)
assert.Equal(t, baseHeight, h, "Unexpected block height")
numToForward := uint64(2)
@@ -278,7 +280,7 @@ func TestFollowBlock_OK(t *testing.T) {
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
h, err = web3Service.followBlockHeight(context.Background())
h, err = web3Service.followedBlockHeight(context.Background())
require.NoError(t, err)
assert.Equal(t, expectedHeight, h, "Unexpected block height")
}
@@ -843,3 +845,50 @@ func TestETH1Endpoints(t *testing.T) {
// Check endpoints are all present.
assert.DeepSSZEqual(t, endpoints, s1.ETH1Endpoints(), "Unexpected http endpoint slice")
}
func TestService_CacheBlockHeaders(t *testing.T) {
rClient := &slowRPCClient{limit: 1000}
s := &Service{
cfg: &config{eth1HeaderReqLimit: 1000},
rpcClient: rClient,
headerCache: newHeaderCache(),
}
assert.NoError(t, s.cacheBlockHeaders(1, 1000))
assert.Equal(t, 1, rClient.numOfCalls)
// Reset Num of Calls
rClient.numOfCalls = 0
assert.NoError(t, s.cacheBlockHeaders(1000, 3000))
// 1000 - 2000 would be 1001 headers which is higher than our request limit, it
// is then reduced to 500 and tried again.
assert.Equal(t, 5, rClient.numOfCalls)
}
type slowRPCClient struct {
limit int
numOfCalls int
}
func (s *slowRPCClient) Close() {
panic("implement me")
}
func (s *slowRPCClient) BatchCall(b []rpc.BatchElem) error {
s.numOfCalls++
if len(b) > s.limit {
return errTimedOut
}
for _, e := range b {
num, err := hexutil.DecodeBig(e.Args[0].(string))
if err != nil {
return err
}
h := &gethTypes.Header{Number: num}
*e.Result.(*gethTypes.Header) = *h
}
return nil
}
func (s *slowRPCClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {
panic("implement me")
}

View File

@@ -71,8 +71,3 @@ func (_ *FaultyMockPOWChain) ClearPreGenesisData() {
func (_ *FaultyMockPOWChain) IsConnectedToETH1() bool {
return true
}
// BlockExistsWithCache --
func (f *FaultyMockPOWChain) BlockExistsWithCache(ctx context.Context, hash common.Hash) (bool, *big.Int, error) {
return f.BlockExists(ctx, hash)
}

View File

@@ -179,11 +179,6 @@ func (m *POWChain) InsertBlock(height int, time uint64, hash []byte) *POWChain {
return m
}
// BlockExistsWithCache --
func (m *POWChain) BlockExistsWithCache(ctx context.Context, hash common.Hash) (bool, *big.Int, error) {
return m.BlockExists(ctx, hash)
}
func SetupRPCServer() (*rpc.Server, string, error) {
srv := rpc.NewServer()
if err := srv.RegisterName("eth", &testETHRPC{}); err != nil {

View File

@@ -37,4 +37,5 @@ type Server struct {
V1Alpha1ValidatorServer *v1alpha1validator.Server
SyncChecker sync.Checker
CanonicalHistory *stategen.CanonicalHistory
HeadUpdater blockchain.HeadUpdater
}

View File

@@ -14,6 +14,7 @@ import (
// providing RPC endpoints intended for validator clients.
type Server struct {
HeadFetcher blockchain.HeadFetcher
HeadUpdater blockchain.HeadUpdater
TimeFetcher blockchain.TimeFetcher
SyncChecker sync.Checker
AttestationsPool attestations.Pool

View File

@@ -670,6 +670,7 @@ func TestProduceBlock(t *testing.T) {
HeadFetcher: &mockChain.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mockChain.ChainService{},
HeadUpdater: &mockChain.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
@@ -774,6 +775,7 @@ func TestProduceBlockV2(t *testing.T) {
HeadFetcher: &mockChain.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mockChain.ChainService{},
HeadUpdater: &mockChain.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
@@ -879,6 +881,7 @@ func TestProduceBlockV2(t *testing.T) {
HeadFetcher: &mockChain.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mockChain.ChainService{},
HeadUpdater: &mockChain.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
@@ -1028,6 +1031,7 @@ func TestProduceBlockV2(t *testing.T) {
HeadFetcher: &mockChain.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mockChain.ChainService{},
HeadUpdater: &mockChain.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
@@ -1174,6 +1178,7 @@ func TestProduceBlindedBlock(t *testing.T) {
HeadFetcher: &mockChain.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mockChain.ChainService{},
HeadUpdater: &mockChain.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
@@ -1280,6 +1285,7 @@ func TestProduceBlindedBlock(t *testing.T) {
HeadFetcher: &mockChain.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mockChain.ChainService{},
HeadUpdater: &mockChain.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
@@ -1429,6 +1435,7 @@ func TestProduceBlindedBlock(t *testing.T) {
HeadFetcher: &mockChain.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mockChain.ChainService{},
HeadUpdater: &mockChain.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},

View File

@@ -46,4 +46,5 @@ type Server struct {
StateGen stategen.StateManager
SyncChecker sync.Checker
ReplayerBuilder stategen.ReplayerBuilder
HeadUpdater blockchain.HeadUpdater
}

View File

@@ -499,7 +499,7 @@ func (bs *Server) GetValidatorParticipation(
}
// Use the last slot of requested epoch to obtain current and previous epoch attestations.
// This ensures that we don't miss previous attestations when input requested epochs.
startSlot, err := slots.EpochEnd(requestedEpoch)
endSlot, err := slots.EpochEnd(requestedEpoch)
if err != nil {
return nil, err
}
@@ -507,14 +507,14 @@ func (bs *Server) GetValidatorParticipation(
// The above check ensures a future *epoch* isn't requested, but the end slot of the requested epoch could still
// be past the current slot. In that case, use the current slot as the best approximation of the requested epoch.
// Replayer will make sure the slot ultimately used is canonical.
if startSlot > currentSlot {
startSlot = currentSlot
if endSlot > currentSlot {
endSlot = currentSlot
}
// ReplayerBuilder ensures that a canonical chain is followed to the slot
beaconState, err := bs.ReplayerBuilder.ReplayerForSlot(startSlot).ReplayBlocks(ctx)
beaconState, err := bs.ReplayerBuilder.ReplayerForSlot(endSlot).ReplayBlocks(ctx)
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("error replaying blocks for state at slot %d: %v", startSlot, err))
return nil, status.Error(codes.Internal, fmt.Sprintf("error replaying blocks for state at slot %d: %v", endSlot, err))
}
var v []*precompute.Validator
var b *precompute.Balance

View File

@@ -197,10 +197,16 @@ func (vs *Server) rebuildDepositTrie(ctx context.Context, canonicalEth1Data *eth
// validate that the provided deposit trie matches up with the canonical eth1 data provided.
func validateDepositTrie(trie *trie.SparseMerkleTrie, canonicalEth1Data *ethpb.Eth1Data) (bool, error) {
if trie == nil || canonicalEth1Data == nil {
return false, errors.New("nil trie or eth1data provided")
}
if trie.NumOfItems() != int(canonicalEth1Data.DepositCount) {
return false, errors.Errorf("wanted the canonical count of %d but received %d", canonicalEth1Data.DepositCount, trie.NumOfItems())
}
rt := trie.HashTreeRoot()
rt, err := trie.HashTreeRoot()
if err != nil {
return false, err
}
if !bytes.Equal(rt[:], canonicalEth1Data.DepositRoot) {
return false, errors.Errorf("wanted the canonical deposit root of %#x but received %#x", canonicalEth1Data.DepositRoot, rt)
}

View File

@@ -82,6 +82,10 @@ func (vs *Server) buildPhase0BlockData(ctx context.Context, req *ethpb.BlockRequ
return nil, fmt.Errorf("syncing to latest head, not ready to respond")
}
if err := vs.HeadUpdater.UpdateHead(ctx); err != nil {
log.WithError(err).Error("Could not process attestations and update head")
}
// Retrieve the parent block as the current head of the canonical chain.
parentRoot, err := vs.HeadFetcher.HeadRoot(ctx)
if err != nil {

View File

@@ -72,6 +72,7 @@ func TestProposer_GetBlock_OK(t *testing.T) {
HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
HeadUpdater: &mock.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
@@ -158,6 +159,7 @@ func TestProposer_GetBlock_AddsUnaggregatedAtts(t *testing.T) {
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
HeadUpdater: &mock.ChainService{},
MockEth1Votes: true,
SlashingsPool: slashings.NewPool(),
AttPool: attestations.NewPool(),
@@ -503,10 +505,14 @@ func TestProposer_PendingDeposits_OutsideEth1FollowWindow(t *testing.T) {
require.NoError(t, err, "Unable to determine hashed value of deposit")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root))
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.HashTreeRoot())
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root)
}
blk := util.NewBeaconBlock()
@@ -638,10 +644,14 @@ func TestProposer_PendingDeposits_FollowsCorrectEth1Block(t *testing.T) {
require.NoError(t, err, "Unable to determine hashed value of deposit")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root))
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.HashTreeRoot())
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root)
}
bs := &Server{
@@ -737,10 +747,14 @@ func TestProposer_PendingDeposits_CantReturnBelowStateEth1DepositIndex(t *testin
require.NoError(t, err, "Unable to determine hashed value of deposit")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, root))
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.HashTreeRoot())
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, root)
}
bs := &Server{
@@ -833,10 +847,14 @@ func TestProposer_PendingDeposits_CantReturnMoreThanMax(t *testing.T) {
require.NoError(t, err, "Unable to determine hashed value of deposit")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, height.Uint64(), dp.Index, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, height.Uint64(), dp.Index, root))
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, height.Uint64(), dp.Index, depositTrie.HashTreeRoot())
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, height.Uint64(), dp.Index, root)
}
bs := &Server{
@@ -927,10 +945,14 @@ func TestProposer_PendingDeposits_CantReturnMoreThanDepositCount(t *testing.T) {
require.NoError(t, err, "Unable to determine hashed value of deposit")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, root))
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.HashTreeRoot())
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, root)
}
bs := &Server{
@@ -1036,10 +1058,14 @@ func TestProposer_DepositTrie_UtilizesCachedFinalizedDeposits(t *testing.T) {
require.NoError(t, err, "Unable to determine hashed value of deposit")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root))
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.HashTreeRoot())
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root)
}
bs := &Server{
@@ -1055,8 +1081,10 @@ func TestProposer_DepositTrie_UtilizesCachedFinalizedDeposits(t *testing.T) {
trie, err := bs.depositTrie(ctx, &ethpb.Eth1Data{}, big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)))
require.NoError(t, err)
actualRoot := trie.HashTreeRoot()
expectedRoot := depositTrie.HashTreeRoot()
actualRoot, err := trie.HashTreeRoot()
require.NoError(t, err)
expectedRoot, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.Equal(t, expectedRoot, actualRoot, "Incorrect deposit trie root")
}
@@ -1146,10 +1174,14 @@ func TestProposer_DepositTrie_RebuildTrie(t *testing.T) {
require.NoError(t, err, "Unable to determine hashed value of deposit")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root))
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.HashTreeRoot())
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root)
}
d := depositCache.AllDepositContainers(ctx)
origDeposit, ok := proto.Clone(d[0].Deposit).(*ethpb.Deposit)
@@ -1177,8 +1209,10 @@ func TestProposer_DepositTrie_RebuildTrie(t *testing.T) {
trie, err := bs.depositTrie(ctx, &ethpb.Eth1Data{}, big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)))
require.NoError(t, err)
expectedRoot := depositTrie.HashTreeRoot()
actualRoot := trie.HashTreeRoot()
expectedRoot, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
actualRoot, err := trie.HashTreeRoot()
require.NoError(t, err)
assert.Equal(t, expectedRoot, actualRoot, "Incorrect deposit trie root")
}
@@ -1230,7 +1264,8 @@ func TestProposer_ValidateDepositTrie(t *testing.T) {
assert.NoError(t, trie.Insert([]byte{'a'}, 0))
assert.NoError(t, trie.Insert([]byte{'b'}, 1))
assert.NoError(t, trie.Insert([]byte{'c'}, 2))
rt := trie.HashTreeRoot()
rt, err := trie.HashTreeRoot()
require.NoError(t, err)
return &ethpb.Eth1Data{DepositRoot: rt[:], DepositCount: 3, BlockHash: []byte{}}
},
trieCreator: func() *trie.SparseMerkleTrie {
@@ -1274,7 +1309,9 @@ func TestProposer_Eth1Data_MajorityVote(t *testing.T) {
require.NoError(t, err)
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, root))
t.Run("choose highest count", func(t *testing.T) {
t.Skip()
@@ -1976,10 +2013,14 @@ func TestProposer_Deposits_ReturnsEmptyList_IfLatestEth1DataEqGenesisEth1Block(t
require.NoError(t, err, "Unable to determine hashed value of deposit")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, root))
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.HashTreeRoot())
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, root)
}
bs := &Server{
@@ -2066,6 +2107,7 @@ func TestProposer_GetBeaconBlock_PreForkEpoch(t *testing.T) {
HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
HeadUpdater: &mock.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
@@ -2178,6 +2220,7 @@ func TestProposer_GetBeaconBlock_PostForkEpoch(t *testing.T) {
HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
HeadUpdater: &mock.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
@@ -2331,6 +2374,7 @@ func TestProposer_GetBeaconBlock_BellatrixEpoch(t *testing.T) {
TimeFetcher: &mock.ChainService{Genesis: time.Now()},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
HeadUpdater: &mock.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: c,

View File

@@ -43,6 +43,7 @@ type Server struct {
AttestationCache *cache.AttestationCache
ProposerSlotIndexCache *cache.ProposerPayloadIDsCache
HeadFetcher blockchain.HeadFetcher
HeadUpdater blockchain.HeadUpdater
ForkFetcher blockchain.ForkFetcher
FinalizationFetcher blockchain.FinalizationFetcher
TimeFetcher blockchain.TimeFetcher

View File

@@ -137,7 +137,9 @@ func TestWaitForActivation_ValidatorOriginallyExists(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 10 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 10 /*blockNum*/, 0, root))
trie, err := v1.InitializeFromProtoUnsafe(beaconState)
require.NoError(t, err)
vs := &Server{

View File

@@ -41,7 +41,9 @@ func TestValidatorStatus_DepositedEth1(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, root))
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
@@ -84,7 +86,9 @@ func TestValidatorStatus_Deposited(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, root))
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
@@ -134,7 +138,9 @@ func TestValidatorStatus_PartiallyDeposited(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, root))
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
@@ -202,7 +208,9 @@ func TestValidatorStatus_Pending(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, root))
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
p := &mockPOW.POWChain{
@@ -247,7 +255,9 @@ func TestValidatorStatus_Active(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, root))
// Active because activation epoch <= current epoch < exit epoch.
activeEpoch := helpers.ActivationExitEpoch(0)
@@ -334,7 +344,9 @@ func TestValidatorStatus_Exiting(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, root))
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
@@ -391,7 +403,9 @@ func TestValidatorStatus_Slashing(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, root))
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
@@ -449,7 +463,9 @@ func TestValidatorStatus_Exited(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, root))
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{
@@ -532,11 +548,15 @@ func TestActivationStatus_OK(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dep, 10 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dep, 10 /*blockNum*/, 0, root))
dep = deposits[2]
assert.NoError(t, depositTrie.Insert(dep.Data.Signature, 15))
assert.NoError(t, depositCache.InsertDeposit(context.Background(), dep, 0, 1, depositTrie.HashTreeRoot()))
root, err = depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(context.Background(), dep, 0, 1, root))
vs := &Server{
Ctx: context.Background(),
@@ -677,7 +697,9 @@ func TestValidatorStatus_CorrectActivationQueue(t *testing.T) {
deposit := &ethpb.Deposit{
Data: depData,
}
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, int64(i), depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, int64(i), root))
}
@@ -758,10 +780,14 @@ func TestMultipleValidatorStatus_Pubkeys(t *testing.T) {
require.NoError(t, err)
dep := deposits[0]
assert.NoError(t, depositCache.InsertDeposit(ctx, dep, 10 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dep, 10 /*blockNum*/, 0, root))
dep = deposits[2]
assert.NoError(t, depositTrie.Insert(dep.Data.Signature, 15))
assert.NoError(t, depositCache.InsertDeposit(context.Background(), dep, 0, 1, depositTrie.HashTreeRoot()))
root, err = depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(context.Background(), dep, 0, 1, root))
vs := &Server{
Ctx: context.Background(),
@@ -918,7 +944,9 @@ func TestValidatorStatus_Invalid(t *testing.T) {
depositCache, err := depositcache.New()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.HashTreeRoot()))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, root))
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
p := &mockPOW.POWChain{
TimesByHeight: map[int]uint64{

View File

@@ -78,6 +78,7 @@ type Config struct {
BeaconMonitoringPort int
BeaconDB db.HeadAccessDatabase
ChainInfoFetcher blockchain.ChainInfoFetcher
HeadUpdater blockchain.HeadUpdater
HeadFetcher blockchain.HeadFetcher
CanonicalFetcher blockchain.CanonicalFetcher
ForkFetcher blockchain.ForkFetcher
@@ -189,6 +190,7 @@ func (s *Service) Start() {
AttPool: s.cfg.AttestationsPool,
ExitPool: s.cfg.ExitPool,
HeadFetcher: s.cfg.HeadFetcher,
HeadUpdater: s.cfg.HeadUpdater,
ForkFetcher: s.cfg.ForkFetcher,
FinalizationFetcher: s.cfg.FinalizationFetcher,
TimeFetcher: s.cfg.GenesisTimeFetcher,
@@ -215,6 +217,7 @@ func (s *Service) Start() {
}
validatorServerV1 := &validator.Server{
HeadFetcher: s.cfg.HeadFetcher,
HeadUpdater: s.cfg.HeadUpdater,
TimeFetcher: s.cfg.GenesisTimeFetcher,
SyncChecker: s.cfg.SyncService,
AttestationsPool: s.cfg.AttestationsPool,
@@ -261,6 +264,7 @@ func (s *Service) Start() {
BeaconDB: s.cfg.BeaconDB,
AttestationsPool: s.cfg.AttestationsPool,
SlashingsPool: s.cfg.SlashingsPool,
HeadUpdater: s.cfg.HeadUpdater,
HeadFetcher: s.cfg.HeadFetcher,
FinalizationFetcher: s.cfg.FinalizationFetcher,
CanonicalFetcher: s.cfg.CanonicalFetcher,

View File

@@ -10,6 +10,7 @@ go_library(
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//beacon-chain/state/state-native/custom-types:go_default_library",
"//beacon-chain/state/state-native/types:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//beacon-chain/state/types:go_default_library",
"//crypto/hash:go_default_library",

View File

@@ -16,7 +16,7 @@ type FieldTrie struct {
*sync.RWMutex
reference *stateutil.Reference
fieldLayers [][]*[32]byte
field types.FieldIndex
field types.BeaconStateField
dataType types.DataType
length uint64
numOfElems int
@@ -25,7 +25,7 @@ type FieldTrie struct {
// NewFieldTrie is the constructor for the field trie data structure. It creates the corresponding
// trie according to the given parameters. Depending on whether the field is a basic/composite array
// which is either fixed/variable length, it will appropriately determine the trie.
func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements interface{}, length uint64) (*FieldTrie, error) {
func NewFieldTrie(field types.BeaconStateField, dataType types.DataType, elements interface{}, length uint64) (*FieldTrie, error) {
if elements == nil {
return &FieldTrie{
field: field,
@@ -36,10 +36,19 @@ func NewFieldTrie(field types.FieldIndex, dataType types.DataType, elements inte
numOfElems: 0,
}, nil
}
fieldRoots, err := fieldConverters(field, []uint64{}, elements, true)
var fieldRoots [][32]byte
var err error
if field.Native() {
fieldRoots, err = fieldConvertersNative(field, []uint64{}, elements, true)
} else {
fieldRoots, err = fieldConverters(field, []uint64{}, elements, true)
}
if err != nil {
return nil, err
}
if err := validateElements(field, dataType, elements, length); err != nil {
return nil, err
}
@@ -84,10 +93,18 @@ func (f *FieldTrie) RecomputeTrie(indices []uint64, elements interface{}) ([32]b
if len(indices) == 0 {
return f.TrieRoot()
}
fieldRoots, err := fieldConverters(f.field, indices, elements, false)
var fieldRoots [][32]byte
var err error
if f.field.Native() {
fieldRoots, err = fieldConvertersNative(f.field, indices, elements, false)
} else {
fieldRoots, err = fieldConverters(f.field, indices, elements, false)
}
if err != nil {
return [32]byte{}, err
}
if err := f.validateIndices(indices); err != nil {
return [32]byte{}, err
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/pkg/errors"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
"github.com/prysmaticlabs/prysm/crypto/hash"
@@ -18,7 +19,7 @@ import (
)
// ProofFromMerkleLayers creates a proof starting at the leaf index of the state Merkle layers.
func ProofFromMerkleLayers(layers [][][]byte, startingLeafIndex types.FieldIndex) [][]byte {
func ProofFromMerkleLayers(layers [][][]byte, startingLeafIndex int) [][]byte {
// The merkle tree structure looks as follows:
// [[r1, r2, r3, r4], [parent1, parent2], [root]]
proof := make([][]byte, 0)
@@ -49,7 +50,7 @@ func (f *FieldTrie) validateIndices(idxs []uint64) error {
return nil
}
func validateElements(field types.FieldIndex, dataType types.DataType, elements interface{}, length uint64) error {
func validateElements(field types.BeaconStateField, dataType types.DataType, elements interface{}, length uint64) error {
if dataType == types.CompressedArray {
comLength, err := field.ElemsInChunk()
if err != nil {
@@ -65,68 +66,118 @@ func validateElements(field types.FieldIndex, dataType types.DataType, elements
}
// fieldConverters converts the corresponding field and the provided elements to the appropriate roots.
func fieldConverters(field types.FieldIndex, indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
func fieldConverters(field types.BeaconStateField, indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
switch field {
case types.BlockRoots:
switch val := elements.(type) {
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.BlockRoots:
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for block roots")
}
return convertBlockRoots(indices, elements, convertAll)
case types.StateRoots:
switch val := elements.(type) {
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.StateRoots:
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for state roots")
}
return convertStateRoots(indices, elements, convertAll)
case types.RandaoMixes:
switch val := elements.(type) {
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.RandaoMixes:
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for randao mixes")
}
return convertRandaoMixes(indices, elements, convertAll)
case types.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)
return convertEth1DataVotes(indices, elements, convertAll)
case types.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 handleValidatorSlice(val, indices, convertAll)
return convertValidators(indices, elements, convertAll)
case types.PreviousEpochAttestations, types.CurrentEpochAttestations:
val, ok := elements.([]*ethpb.PendingAttestation)
if !ok {
return nil, errors.Errorf("Wanted type of %v but got %v",
reflect.TypeOf([]*ethpb.PendingAttestation{}).Name(), reflect.TypeOf(elements).Name())
}
return handlePendingAttestationSlice(val, indices, convertAll)
return convertAttestations(indices, elements, convertAll)
case types.Balances:
val, ok := elements.([]uint64)
if !ok {
return nil, errors.Errorf("Wanted type of %v but got %v",
reflect.TypeOf([]uint64{}).Name(), reflect.TypeOf(elements).Name())
}
return handleBalanceSlice(val, indices, convertAll)
return convertBalances(indices, elements, convertAll)
default:
return [][32]byte{}, errors.Errorf("got unsupported type of %v", reflect.TypeOf(elements).Name())
}
}
// fieldConvertersNative converts the corresponding field and the provided elements to the appropriate roots.
func fieldConvertersNative(field types.BeaconStateField, indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
switch field {
case nativetypes.BlockRoots:
return convertBlockRoots(indices, elements, convertAll)
case nativetypes.StateRoots:
return convertStateRoots(indices, elements, convertAll)
case nativetypes.RandaoMixes:
return convertRandaoMixes(indices, elements, convertAll)
case nativetypes.Eth1DataVotes:
return convertEth1DataVotes(indices, elements, convertAll)
case nativetypes.Validators:
return convertValidators(indices, elements, convertAll)
case nativetypes.PreviousEpochAttestations, nativetypes.CurrentEpochAttestations:
return convertAttestations(indices, elements, convertAll)
case nativetypes.Balances:
return convertBalances(indices, elements, convertAll)
default:
return [][32]byte{}, errors.Errorf("got unsupported type of %v", reflect.TypeOf(elements).Name())
}
}
func convertBlockRoots(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
switch val := elements.(type) {
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.BlockRoots:
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for block roots")
}
}
func convertStateRoots(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
switch val := elements.(type) {
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.StateRoots:
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for state roots")
}
}
func convertRandaoMixes(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
switch val := elements.(type) {
case [][]byte:
return handleByteArrays(val, indices, convertAll)
case *customtypes.RandaoMixes:
return handle32ByteArrays(val[:], indices, convertAll)
default:
return nil, errors.Errorf("Incorrect type used for randao mixes")
}
}
func convertEth1DataVotes(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
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)
}
func convertValidators(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
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 handleValidatorSlice(val, indices, convertAll)
}
func convertAttestations(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
val, ok := elements.([]*ethpb.PendingAttestation)
if !ok {
return nil, errors.Errorf("Wanted type of %v but got %v",
reflect.TypeOf([]*ethpb.PendingAttestation{}).Name(), reflect.TypeOf(elements).Name())
}
return handlePendingAttestationSlice(val, indices, convertAll)
}
func convertBalances(indices []uint64, elements interface{}, convertAll bool) ([][32]byte, error) {
val, ok := elements.([]uint64)
if !ok {
return nil, errors.Errorf("Wanted type of %v but got %v",
reflect.TypeOf([]uint64{}).Name(), reflect.TypeOf(elements).Name())
}
return handleBalanceSlice(val, indices, convertAll)
}
// handleByteArrays computes and returns byte arrays in a slice of root format.
func handleByteArrays(val [][]byte, indices []uint64, convertAll bool) ([][32]byte, error) {
length := len(indices)

View File

@@ -18,7 +18,7 @@ func TestFieldTrie_NewTrie(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 40)
// 5 represents the enum value of state roots
trie, err := fieldtrie.NewFieldTrie(5, stateTypes.BasicArray, newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(5), stateTypes.BasicArray, newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
root, err := stateutil.RootsArrayHashTreeRoot(newState.StateRoots(), uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
@@ -30,7 +30,7 @@ func TestFieldTrie_NewTrie(t *testing.T) {
func TestFieldTrie_RecomputeTrie(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
// 10 represents the enum value of validators
trie, err := fieldtrie.NewFieldTrie(11, stateTypes.CompositeArray, newState.Validators(), params.BeaconConfig().ValidatorRegistryLimit)
trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(11), stateTypes.CompositeArray, newState.Validators(), params.BeaconConfig().ValidatorRegistryLimit)
require.NoError(t, err)
changedIdx := []uint64{2, 29}
@@ -58,7 +58,7 @@ func TestFieldTrie_RecomputeTrie(t *testing.T) {
func TestFieldTrie_CopyTrieImmutable(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
// 12 represents the enum value of randao mixes.
trie, err := fieldtrie.NewFieldTrie(13, stateTypes.BasicArray, newState.RandaoMixes(), uint64(params.BeaconConfig().EpochsPerHistoricalVector))
trie, err := fieldtrie.NewFieldTrie(stateTypes.FieldIndex(13), stateTypes.BasicArray, newState.RandaoMixes(), uint64(params.BeaconConfig().EpochsPerHistoricalVector))
require.NoError(t, err)
newTrie := trie.CopyTrie()

View File

@@ -18,7 +18,7 @@ var (
// State returns a copy of the genesis state from a hardcoded value.
func State(name string) (state.BeaconState, error) {
switch name {
case params.ConfigNames[params.Mainnet]:
case params.MainnetName:
return load(mainnetRawSSZCompressed)
default:
// No state found.

View File

@@ -9,15 +9,15 @@ import (
func TestGenesisState(t *testing.T) {
tests := []struct {
name params.ConfigName
name string
}{
{
name: params.Mainnet,
name: params.MainnetName,
},
}
for _, tt := range tests {
t.Run(params.ConfigNames[tt.name], func(t *testing.T) {
st, err := genesis.State(params.ConfigNames[tt.name])
t.Run(tt.name, func(t *testing.T) {
st, err := genesis.State(tt.name)
if err != nil {
t.Fatal(err)
}

View File

@@ -1,20 +1,21 @@
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
load("//proto:ssz_proto_library.bzl", "ssz_proto_files")
load("//tools:ssz.bzl", "SSZ_DEPS", "ssz_gen_marshal")
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"field_roots.go",
"getters_attestation.go",
"getters_block.go",
"getters_checkpoint.go",
"getters_eth1.go",
"getters_misc.go",
"getters_participation.go",
"getters_payload_header.go",
"getters_randao.go",
"getters_state.go",
"getters_sync_committee.go",
"getters_validator.go",
"hasher.go",
"proofs.go",
"readonly_validator.go",
"setters_attestation.go",
@@ -22,19 +23,20 @@ go_library(
"setters_checkpoint.go",
"setters_eth1.go",
"setters_misc.go",
"setters_participation.go",
"setters_payload_header.go",
"setters_randao.go",
"setters_state.go",
"setters_sync_committee.go",
"setters_validator.go",
"ssz.go",
"state_trie.go",
"types.go",
"unsupported_getters.go",
"unsupported_setters.go",
":ssz_generated_files", # keep
] + select({
"//config:mainnet": ["beacon_state_mainnet.go"],
"//config:minimal": ["beacon_state_minimal.go"],
}),
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1",
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native",
visibility = [
"//beacon-chain:__subpackages__",
"//contracts/deposit:__subpackages__",
@@ -54,6 +56,7 @@ go_library(
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/fieldtrie:go_default_library",
"//beacon-chain/state/state-native/custom-types:go_default_library",
"//beacon-chain/state/state-native/types:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//beacon-chain/state/types:go_default_library",
"//config/fieldparams:go_default_library",
@@ -65,7 +68,6 @@ go_library(
"//encoding/ssz:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ferranbt_fastssz//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
@@ -73,14 +75,15 @@ go_library(
],
)
# gazelle:exclude types_bench_test.go
go_test(
name = "go_default_test",
srcs = [
"getters_attestation_test.go",
"getters_block_test.go",
"getters_checkpoint_test.go",
"getters_test.go",
"getters_validator_test.go",
"hasher_test.go",
"proofs_test.go",
"readonly_validator_test.go",
"references_test.go",
@@ -95,9 +98,12 @@ go_test(
embed = [":go_default_library"],
deps = [
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native/types:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//beacon-chain/state/testing:go_default_library",
"//beacon-chain/state/types:go_default_library",
"//beacon-chain/state/v1:go_default_library",
"//beacon-chain/state/v2:go_default_library",
"//beacon-chain/state/v3:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
@@ -113,20 +119,3 @@ go_test(
"@org_golang_google_protobuf//proto:go_default_library",
],
)
ssz_gen_marshal(
name = "ssz_generated_files",
srcs = select({
"//config:mainnet": ["beacon_state_mainnet.go"],
"//config:minimal": ["beacon_state_minimal.go"],
}),
includes = [
"//beacon-chain/state/state-native/custom-types:go_default_library",
"//config/fieldparams:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
],
objs = [
"BeaconState[no-htr]",
],
)

View File

@@ -1,7 +1,7 @@
//go:build !minimal
// +build !minimal
package v3
package state_native
import (
"sync"
@@ -9,15 +9,16 @@ import (
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
eth2types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// BeaconState defines a struct containing utilities for the eth2 chain state, defining
// BeaconState defines a struct containing utilities for the Ethereum Beacon Chain state, defining
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
type BeaconState struct {
version int
genesisTime uint64 `ssz-gen:"true"`
genesisValidatorsRoot customtypes.Byte32 `ssz-gen:"true" ssz-size:"32"`
slot eth2types.Slot `ssz-gen:"true"`
@@ -33,6 +34,8 @@ type BeaconState struct {
balances []uint64 `ssz-gen:"true" ssz-max:"1099511627776"`
randaoMixes *customtypes.RandaoMixes `ssz-gen:"true" ssz-size:"65536,32"`
slashings []uint64 `ssz-gen:"true" ssz-size:"8192"`
previousEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"4096"`
currentEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"4096"`
previousEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
currentEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
justificationBits bitfield.Bitvector4 `ssz-gen:"true" ssz-size:"1"`
@@ -45,11 +48,11 @@ type BeaconState struct {
latestExecutionPayloadHeader *ethpb.ExecutionPayloadHeader `ssz-gen:"true"`
lock sync.RWMutex
dirtyFields map[types.FieldIndex]bool
dirtyIndices map[types.FieldIndex][]uint64
stateFieldLeaves map[types.FieldIndex]*fieldtrie.FieldTrie
rebuildTrie map[types.FieldIndex]bool
dirtyFields map[nativetypes.FieldIndex]bool
dirtyIndices map[nativetypes.FieldIndex][]uint64
stateFieldLeaves map[nativetypes.FieldIndex]*fieldtrie.FieldTrie
rebuildTrie map[nativetypes.FieldIndex]bool
valMapHandler *stateutil.ValidatorMapHandler
merkleLayers [][][]byte
sharedFieldReferences map[types.FieldIndex]*stateutil.Reference
sharedFieldReferences map[nativetypes.FieldIndex]*stateutil.Reference
}

View File

@@ -1,7 +1,7 @@
//go:build !minimal
// +build !minimal
package v1
package state_native
import (
"reflect"
@@ -9,6 +9,7 @@ import (
"testing"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
)
@@ -79,4 +80,9 @@ func TestMainnetSszValuesAgainstFieldParams(t *testing.T) {
require.Equal(t, true, ok, "Required field not found")
v = f.Tag.Get("ssz-size")
assert.Equal(t, "1", v)
f, ok = bsType.FieldByName("inactivityScores")
require.Equal(t, true, ok, "Required field not found")
v = f.Tag.Get("ssz-max")
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
}

View File

@@ -1,7 +1,7 @@
//go:build minimal
// +build minimal
package v3
package state_native
import (
"sync"
@@ -9,15 +9,16 @@ import (
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
eth2types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
// BeaconState defines a struct containing utilities for the eth2 chain state, defining
// BeaconState defines a struct containing utilities for the Ethereum Beacon Chain state, defining
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
type BeaconState struct {
version int
genesisTime uint64 `ssz-gen:"true"`
genesisValidatorsRoot customtypes.Byte32 `ssz-gen:"true" ssz-size:"32"`
slot eth2types.Slot `ssz-gen:"true"`
@@ -33,6 +34,8 @@ type BeaconState struct {
balances []uint64 `ssz-gen:"true" ssz-max:"1099511627776"`
randaoMixes *customtypes.RandaoMixes `ssz-gen:"true" ssz-size:"64,32"`
slashings []uint64 `ssz-gen:"true" ssz-size:"64"`
previousEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"1024"`
currentEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"1024"`
previousEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
currentEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
justificationBits bitfield.Bitvector4 `ssz-gen:"true" ssz-size:"1"`
@@ -45,11 +48,11 @@ type BeaconState struct {
latestExecutionPayloadHeader *ethpb.ExecutionPayloadHeader `ssz-gen:"true"`
lock sync.RWMutex
dirtyFields map[types.FieldIndex]bool
dirtyIndices map[types.FieldIndex][]uint64
stateFieldLeaves map[types.FieldIndex]*fieldtrie.FieldTrie
rebuildTrie map[types.FieldIndex]bool
dirtyFields map[nativetypes.FieldIndex]bool
dirtyIndices map[nativetypes.FieldIndex][]uint64
stateFieldLeaves map[nativetypes.FieldIndex]*fieldtrie.FieldTrie
rebuildTrie map[nativetypes.FieldIndex]bool
valMapHandler *stateutil.ValidatorMapHandler
merkleLayers [][][]byte
sharedFieldReferences map[types.FieldIndex]*stateutil.Reference
sharedFieldReferences map[nativetypes.FieldIndex]*stateutil.Reference
}

View File

@@ -1,7 +1,7 @@
//go:build minimal
// +build minimal
package v1
package state_native
import (
"reflect"
@@ -79,4 +79,9 @@ func TestMinimalSszValuesAgainstFieldParams(t *testing.T) {
require.Equal(t, true, ok, "Required field not found")
v = f.Tag.Get("ssz-size")
assert.Equal(t, "1", v)
f, ok = bsType.FieldByName("inactivityScores")
require.Equal(t, true, ok, "Required field not found")
v = f.Tag.Get("ssz-max")
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
}

View File

@@ -1,22 +1,15 @@
// Package v1 defines how the beacon chain state for Ethereum
// Package state_native defines how the beacon chain state for Ethereum
// functions in the running beacon node, using an advanced,
// immutable implementation of the state data structure.
//
// BeaconState getters may be accessed from inside or outside the package. To
// avoid duplicating locks, we have internal and external versions of the
// getter The external function carries out the short-circuit conditions,
// obtains a read lock, then calls the internal function. The internal function
// carries out the short-circuit conditions and returns the required data
// without further locking, allowing it to be used by other package-level
// functions that already hold a lock. Hence the functions look something
// like this:
// getter. The external function obtains a read lock, then calls the internal function.
// The internal function returns the required data without further locking,
// allowing it to be used by other package-level functions that already hold a lock.
// Hence the functions look something like this:
//
// func (b *BeaconState) Foo() uint64 {
// // Short-circuit conditions.
// if !b.hasInnerState() {
// return 0
// }
//
// // Read lock.
// b.lock.RLock()
// defer b.lock.RUnlock()
@@ -26,15 +19,12 @@
// }
//
// func (b *BeaconState) foo() uint64 {
// // Short-circuit conditions.
// if !b.hasInnerState() {
// return 0
// }
// (...) // Some processing logic.
//
// return b.state.foo
// return b.foo
// }
//
// Although it is technically possible to remove the short-circuit conditions
// from the external function, that would require every read to obtain a lock
// even if the data was not present, leading to potential slowdowns.
package v1
package state_native

View File

@@ -1,11 +1,16 @@
package v1
package state_native
import (
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// PreviousEpochAttestations corresponding to blocks on the beacon chain.
func (b *BeaconState) PreviousEpochAttestations() ([]*ethpb.PendingAttestation, error) {
if b.version != version.Phase0 {
return nil, errNotSupported("PreviousEpochAttestations", b.version)
}
if b.previousEpochAttestations == nil {
return nil, nil
}
@@ -24,6 +29,10 @@ func (b *BeaconState) previousEpochAttestationsVal() []*ethpb.PendingAttestation
// CurrentEpochAttestations corresponding to blocks on the beacon chain.
func (b *BeaconState) CurrentEpochAttestations() ([]*ethpb.PendingAttestation, error) {
if b.version != version.Phase0 {
return nil, errNotSupported("CurrentEpochAttestations", b.version)
}
if b.currentEpochAttestations == nil {
return nil, nil
}

View File

@@ -1,4 +1,4 @@
package v1
package state_native
import (
"testing"
@@ -8,14 +8,14 @@ import (
)
func TestBeaconState_PreviousEpochAttestations(t *testing.T) {
s, err := InitializeFromProto(&ethpb.BeaconState{})
s, err := InitializeFromProtoPhase0(&ethpb.BeaconState{})
require.NoError(t, err)
atts, err := s.PreviousEpochAttestations()
require.NoError(t, err)
require.DeepEqual(t, []*ethpb.PendingAttestation(nil), atts)
want := []*ethpb.PendingAttestation{{ProposerIndex: 100}}
s, err = InitializeFromProto(&ethpb.BeaconState{PreviousEpochAttestations: want})
s, err = InitializeFromProtoPhase0(&ethpb.BeaconState{PreviousEpochAttestations: want})
require.NoError(t, err)
got, err := s.PreviousEpochAttestations()
require.NoError(t, err)
@@ -27,14 +27,14 @@ func TestBeaconState_PreviousEpochAttestations(t *testing.T) {
}
func TestBeaconState_CurrentEpochAttestations(t *testing.T) {
s, err := InitializeFromProto(&ethpb.BeaconState{})
s, err := InitializeFromProtoPhase0(&ethpb.BeaconState{})
require.NoError(t, err)
atts, err := s.CurrentEpochAttestations()
require.NoError(t, err)
require.DeepEqual(t, []*ethpb.PendingAttestation(nil), atts)
want := []*ethpb.PendingAttestation{{ProposerIndex: 101}}
s, err = InitializeFromProto(&ethpb.BeaconState{CurrentEpochAttestations: want})
s, err = InitializeFromProtoPhase0(&ethpb.BeaconState{CurrentEpochAttestations: want})
require.NoError(t, err)
got, err := s.CurrentEpochAttestations()
require.NoError(t, err)

View File

@@ -1,4 +1,4 @@
package v1
package state_native
import (
"fmt"

View File

@@ -0,0 +1,117 @@
package state_native
import (
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
func TestBeaconState_LatestBlockHeader_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateLatestBlockHeader(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoPhase0(&ethpb.BeaconState{})
},
func(BH *ethpb.BeaconBlockHeader) (state.BeaconState, error) {
return InitializeFromProtoPhase0(&ethpb.BeaconState{LatestBlockHeader: BH})
},
)
}
func TestBeaconState_LatestBlockHeader_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateLatestBlockHeader(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoAltair(&ethpb.BeaconStateAltair{})
},
func(BH *ethpb.BeaconBlockHeader) (state.BeaconState, error) {
return InitializeFromProtoAltair(&ethpb.BeaconStateAltair{LatestBlockHeader: BH})
},
)
}
func TestBeaconState_LatestBlockHeader_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateLatestBlockHeader(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoBellatrix(&ethpb.BeaconStateBellatrix{})
},
func(BH *ethpb.BeaconBlockHeader) (state.BeaconState, error) {
return InitializeFromProtoBellatrix(&ethpb.BeaconStateBellatrix{LatestBlockHeader: BH})
},
)
}
func TestBeaconState_BlockRoots_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateBlockRootsNative(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoPhase0(&ethpb.BeaconState{})
},
func(BR [][]byte) (state.BeaconState, error) {
return InitializeFromProtoPhase0(&ethpb.BeaconState{BlockRoots: BR})
},
)
}
func TestBeaconState_BlockRoots_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateBlockRootsNative(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoAltair(&ethpb.BeaconStateAltair{})
},
func(BR [][]byte) (state.BeaconState, error) {
return InitializeFromProtoAltair(&ethpb.BeaconStateAltair{BlockRoots: BR})
},
)
}
func TestBeaconState_BlockRoots_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateBlockRootsNative(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoBellatrix(&ethpb.BeaconStateBellatrix{})
},
func(BR [][]byte) (state.BeaconState, error) {
return InitializeFromProtoBellatrix(&ethpb.BeaconStateBellatrix{BlockRoots: BR})
},
)
}
func TestBeaconState_BlockRootAtIndex_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateBlockRootAtIndexNative(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoPhase0(&ethpb.BeaconState{})
},
func(BR [][]byte) (state.BeaconState, error) {
return InitializeFromProtoPhase0(&ethpb.BeaconState{BlockRoots: BR})
},
)
}
func TestBeaconState_BlockRootAtIndex_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateBlockRootAtIndexNative(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoAltair(&ethpb.BeaconStateAltair{})
},
func(BR [][]byte) (state.BeaconState, error) {
return InitializeFromProtoAltair(&ethpb.BeaconStateAltair{BlockRoots: BR})
},
)
}
func TestBeaconState_BlockRootAtIndex_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateBlockRootAtIndexNative(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoBellatrix(&ethpb.BeaconStateBellatrix{})
},
func(BR [][]byte) (state.BeaconState, error) {
return InitializeFromProtoBellatrix(&ethpb.BeaconStateBellatrix{BlockRoots: BR})
},
)
}

View File

@@ -1,4 +1,4 @@
package v3
package state_native
import (
"bytes"

View File

@@ -0,0 +1,202 @@
package state_native
import (
"testing"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
func TestBeaconState_PreviousJustifiedCheckpointNil_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStatePreviousJustifiedCheckpointNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{})
})
}
func TestBeaconState_PreviousJustifiedCheckpointNil_Altair(t *testing.T) {
testtmpl.VerifyBeaconStatePreviousJustifiedCheckpointNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{})
})
}
func TestBeaconState_PreviousJustifiedCheckpointNil_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStatePreviousJustifiedCheckpointNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{})
})
}
func TestBeaconState_PreviousJustifiedCheckpoint_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStatePreviousJustifiedCheckpoint(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{PreviousJustifiedCheckpoint: cp})
})
}
func TestBeaconState_PreviousJustifiedCheckpoint_Altair(t *testing.T) {
testtmpl.VerifyBeaconStatePreviousJustifiedCheckpoint(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{PreviousJustifiedCheckpoint: cp})
})
}
func TestBeaconState_PreviousJustifiedCheckpoint_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStatePreviousJustifiedCheckpoint(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{PreviousJustifiedCheckpoint: cp})
})
}
func TestBeaconState_CurrentJustifiedCheckpointNil_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateCurrentJustifiedCheckpointNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{})
})
}
func TestBeaconState_CurrentJustifiedCheckpointNil_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateCurrentJustifiedCheckpointNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{})
})
}
func TestBeaconState_CurrentJustifiedCheckpointNil_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateCurrentJustifiedCheckpointNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{})
})
}
func TestBeaconState_CurrentJustifiedCheckpoint_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateCurrentJustifiedCheckpoint(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{CurrentJustifiedCheckpoint: cp})
})
}
func TestBeaconState_CurrentJustifiedCheckpoint_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateCurrentJustifiedCheckpoint(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{CurrentJustifiedCheckpoint: cp})
})
}
func TestBeaconState_CurrentJustifiedCheckpoint_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateCurrentJustifiedCheckpoint(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{CurrentJustifiedCheckpoint: cp})
})
}
func TestBeaconState_FinalizedCheckpointNil_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateFinalizedCheckpointNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{})
})
}
func TestBeaconState_FinalizedCheckpointNil_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateFinalizedCheckpointNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{})
})
}
func TestBeaconState_FinalizedCheckpointNil_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateFinalizedCheckpointNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{})
})
}
func TestBeaconState_FinalizedCheckpoint_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateFinalizedCheckpoint(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{FinalizedCheckpoint: cp})
})
}
func TestBeaconState_FinalizedCheckpoint_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateFinalizedCheckpoint(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{FinalizedCheckpoint: cp})
})
}
func TestBeaconState_FinalizedCheckpoint_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateFinalizedCheckpoint(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{FinalizedCheckpoint: cp})
})
}
func TestBeaconState_JustificationBitsNil_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateJustificationBitsNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{})
})
}
func TestBeaconState_JustificationBitsNil_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateJustificationBitsNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{})
})
}
func TestBeaconState_JustificationBitsNil_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateJustificationBitsNil(
t,
func() (state.BeaconState, error) {
return InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{})
})
}
func TestBeaconState_JustificationBits_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateJustificationBits(
t,
func(bits bitfield.Bitvector4) (state.BeaconState, error) {
return InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{JustificationBits: bits})
})
}
func TestBeaconState_JustificationBits_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateJustificationBits(
t,
func(bits bitfield.Bitvector4) (state.BeaconState, error) {
return InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{JustificationBits: bits})
})
}
func TestBeaconState_JustificationBits_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateJustificationBits(
t,
func(bits bitfield.Bitvector4) (state.BeaconState, error) {
return InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{JustificationBits: bits})
})
}

View File

@@ -1,4 +1,4 @@
package v3
package state_native
import (
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"

View File

@@ -1,9 +1,8 @@
package v2
package state_native
import (
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// GenesisTime of the beacon state as a uint64.
@@ -25,8 +24,8 @@ func (b *BeaconState) GenesisValidatorsRoot() []byte {
// Version of the beacon state. This method
// is strictly meant to be used without a lock
// internally.
func (_ *BeaconState) Version() int {
return version.Altair
func (b *BeaconState) Version() int {
return b.version
}
// Slot of the current beacon chain state.

View File

@@ -1,7 +1,15 @@
package v3
package state_native
import (
"github.com/prysmaticlabs/prysm/runtime/version"
)
// CurrentEpochParticipation corresponding to participation bits on the beacon chain.
func (b *BeaconState) CurrentEpochParticipation() ([]byte, error) {
if b.version == version.Phase0 {
return nil, errNotSupported("CurrentEpochParticipation", b.version)
}
if b.currentEpochParticipation == nil {
return nil, nil
}
@@ -14,6 +22,10 @@ func (b *BeaconState) CurrentEpochParticipation() ([]byte, error) {
// PreviousEpochParticipation corresponding to participation bits on the beacon chain.
func (b *BeaconState) PreviousEpochParticipation() ([]byte, error) {
if b.version == version.Phase0 {
return nil, errNotSupported("PreviousEpochParticipation", b.version)
}
if b.previousEpochParticipation == nil {
return nil, nil
}

View File

@@ -1,11 +1,16 @@
package v3
package state_native
import (
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// LatestExecutionPayloadHeader of the beacon state.
func (b *BeaconState) LatestExecutionPayloadHeader() (*ethpb.ExecutionPayloadHeader, error) {
if b.version == version.Phase0 || b.version == version.Altair {
return nil, errNotSupported("LatestExecutionPayloadHeader", b.version)
}
if b.latestExecutionPayloadHeader == nil {
return nil, nil
}

View File

@@ -1,4 +1,4 @@
package v3
package state_native
import (
"fmt"

View File

@@ -0,0 +1,279 @@
package state_native
import (
"fmt"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// ToProtoUnsafe returns the pointer value of the underlying
// beacon state proto object, bypassing immutability. Use with care.
func (b *BeaconState) ToProtoUnsafe() interface{} {
if b == nil {
return nil
}
gvrCopy := b.genesisValidatorsRoot
switch b.version {
case version.Phase0:
return &ethpb.BeaconState{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
Slot: b.slot,
Fork: b.fork,
LatestBlockHeader: b.latestBlockHeader,
BlockRoots: b.blockRoots.Slice(),
StateRoots: b.stateRoots.Slice(),
HistoricalRoots: b.historicalRoots.Slice(),
Eth1Data: b.eth1Data,
Eth1DataVotes: b.eth1DataVotes,
Eth1DepositIndex: b.eth1DepositIndex,
Validators: b.validators,
Balances: b.balances,
RandaoMixes: b.randaoMixes.Slice(),
Slashings: b.slashings,
PreviousEpochAttestations: b.previousEpochAttestations,
CurrentEpochAttestations: b.currentEpochAttestations,
JustificationBits: b.justificationBits,
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
}
case version.Altair:
return &ethpb.BeaconStateAltair{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
Slot: b.slot,
Fork: b.fork,
LatestBlockHeader: b.latestBlockHeader,
BlockRoots: b.blockRoots.Slice(),
StateRoots: b.stateRoots.Slice(),
HistoricalRoots: b.historicalRoots.Slice(),
Eth1Data: b.eth1Data,
Eth1DataVotes: b.eth1DataVotes,
Eth1DepositIndex: b.eth1DepositIndex,
Validators: b.validators,
Balances: b.balances,
RandaoMixes: b.randaoMixes.Slice(),
Slashings: b.slashings,
PreviousEpochParticipation: b.previousEpochParticipation,
CurrentEpochParticipation: b.currentEpochParticipation,
JustificationBits: b.justificationBits,
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: b.inactivityScores,
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
}
case version.Bellatrix:
return &ethpb.BeaconStateBellatrix{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
Slot: b.slot,
Fork: b.fork,
LatestBlockHeader: b.latestBlockHeader,
BlockRoots: b.blockRoots.Slice(),
StateRoots: b.stateRoots.Slice(),
HistoricalRoots: b.historicalRoots.Slice(),
Eth1Data: b.eth1Data,
Eth1DataVotes: b.eth1DataVotes,
Eth1DepositIndex: b.eth1DepositIndex,
Validators: b.validators,
Balances: b.balances,
RandaoMixes: b.randaoMixes.Slice(),
Slashings: b.slashings,
PreviousEpochParticipation: b.previousEpochParticipation,
CurrentEpochParticipation: b.currentEpochParticipation,
JustificationBits: b.justificationBits,
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: b.inactivityScores,
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeader,
}
default:
return nil
}
}
// ToProto the beacon state into a protobuf for usage.
func (b *BeaconState) ToProto() interface{} {
if b == nil {
return nil
}
b.lock.RLock()
defer b.lock.RUnlock()
gvrCopy := b.genesisValidatorsRoot
switch b.version {
case version.Phase0:
return &ethpb.BeaconState{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
Slot: b.slot,
Fork: b.forkVal(),
LatestBlockHeader: b.latestBlockHeaderVal(),
BlockRoots: b.blockRoots.Slice(),
StateRoots: b.stateRoots.Slice(),
HistoricalRoots: b.historicalRoots.Slice(),
Eth1Data: b.eth1DataVal(),
Eth1DataVotes: b.eth1DataVotesVal(),
Eth1DepositIndex: b.eth1DepositIndex,
Validators: b.validatorsVal(),
Balances: b.balancesVal(),
RandaoMixes: b.randaoMixes.Slice(),
Slashings: b.slashingsVal(),
PreviousEpochAttestations: b.previousEpochAttestationsVal(),
CurrentEpochAttestations: b.currentEpochAttestationsVal(),
JustificationBits: b.justificationBitsVal(),
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
FinalizedCheckpoint: b.finalizedCheckpointVal(),
}
case version.Altair:
return &ethpb.BeaconStateAltair{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
Slot: b.slot,
Fork: b.forkVal(),
LatestBlockHeader: b.latestBlockHeaderVal(),
BlockRoots: b.blockRoots.Slice(),
StateRoots: b.stateRoots.Slice(),
HistoricalRoots: b.historicalRoots.Slice(),
Eth1Data: b.eth1DataVal(),
Eth1DataVotes: b.eth1DataVotesVal(),
Eth1DepositIndex: b.eth1DepositIndex,
Validators: b.validatorsVal(),
Balances: b.balancesVal(),
RandaoMixes: b.randaoMixes.Slice(),
Slashings: b.slashingsVal(),
PreviousEpochParticipation: b.previousEpochParticipationVal(),
CurrentEpochParticipation: b.currentEpochParticipationVal(),
JustificationBits: b.justificationBitsVal(),
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
FinalizedCheckpoint: b.finalizedCheckpointVal(),
InactivityScores: b.inactivityScoresVal(),
CurrentSyncCommittee: b.currentSyncCommitteeVal(),
NextSyncCommittee: b.nextSyncCommitteeVal(),
}
case version.Bellatrix:
return &ethpb.BeaconStateBellatrix{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
Slot: b.slot,
Fork: b.forkVal(),
LatestBlockHeader: b.latestBlockHeaderVal(),
BlockRoots: b.blockRoots.Slice(),
StateRoots: b.stateRoots.Slice(),
HistoricalRoots: b.historicalRoots.Slice(),
Eth1Data: b.eth1DataVal(),
Eth1DataVotes: b.eth1DataVotesVal(),
Eth1DepositIndex: b.eth1DepositIndex,
Validators: b.validatorsVal(),
Balances: b.balancesVal(),
RandaoMixes: b.randaoMixes.Slice(),
Slashings: b.slashingsVal(),
PreviousEpochParticipation: b.previousEpochParticipationVal(),
CurrentEpochParticipation: b.currentEpochParticipationVal(),
JustificationBits: b.justificationBitsVal(),
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
FinalizedCheckpoint: b.finalizedCheckpointVal(),
InactivityScores: b.inactivityScoresVal(),
CurrentSyncCommittee: b.currentSyncCommitteeVal(),
NextSyncCommittee: b.nextSyncCommitteeVal(),
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderVal(),
}
default:
return nil
}
}
// StateRoots kept track of in the beacon state.
func (b *BeaconState) StateRoots() [][]byte {
if b.stateRoots == nil {
return nil
}
b.lock.RLock()
defer b.lock.RUnlock()
return b.stateRoots.Slice()
}
// StateRootAtIndex retrieves a specific state root based on an
// input index value.
func (b *BeaconState) StateRootAtIndex(idx uint64) ([]byte, error) {
if b.stateRoots == nil {
return nil, nil
}
b.lock.RLock()
defer b.lock.RUnlock()
r, err := b.stateRootAtIndex(idx)
if err != nil {
return nil, err
}
return r[:], nil
}
// 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) ([32]byte, error) {
if uint64(len(b.stateRoots)) <= idx {
return [32]byte{}, fmt.Errorf("index %d out of range", idx)
}
return b.stateRoots[idx], nil
}
// ProtobufBeaconStatePhase0 transforms an input into beacon state in the form of protobuf.
// Error is returned if the input is not type protobuf beacon state.
func ProtobufBeaconStatePhase0(s interface{}) (*ethpb.BeaconState, error) {
pbState, ok := s.(*ethpb.BeaconState)
if !ok {
return nil, errors.New("input is not type ethpb.BeaconState")
}
return pbState, nil
}
// ProtobufBeaconStateAltair transforms an input into beacon state Altair in the form of protobuf.
// Error is returned if the input is not type protobuf beacon state.
func ProtobufBeaconStateAltair(s interface{}) (*ethpb.BeaconStateAltair, error) {
pbState, ok := s.(*ethpb.BeaconStateAltair)
if !ok {
return nil, errors.New("input is not type pb.BeaconStateAltair")
}
return pbState, nil
}
// ProtobufBeaconStateBellatrix transforms an input into beacon state Bellatrix in the form of protobuf.
// Error is returned if the input is not type protobuf beacon state.
func ProtobufBeaconStateBellatrix(s interface{}) (*ethpb.BeaconStateBellatrix, error) {
pbState, ok := s.(*ethpb.BeaconStateBellatrix)
if !ok {
return nil, errors.New("input is not type pb.BeaconStateBellatrix")
}
return pbState, nil
}
// InnerStateUnsafe returns the pointer value of the underlying
// beacon state proto object, bypassing immutability. Use with care.
func (b *BeaconState) InnerStateUnsafe() interface{} {
return b.ToProtoUnsafe()
}
// CloneInnerState the beacon state into a protobuf for usage.
func (b *BeaconState) CloneInnerState() interface{} {
return b.ToProto()
}

View File

@@ -1,27 +1,20 @@
package v2
package state_native
import (
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// currentSyncCommitteeVal of the current sync committee in beacon chain state.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) currentSyncCommitteeVal() *ethpb.SyncCommittee {
return CopySyncCommittee(b.currentSyncCommittee)
}
// nextSyncCommitteeVal of the next sync committee in beacon chain state.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) nextSyncCommitteeVal() *ethpb.SyncCommittee {
return CopySyncCommittee(b.nextSyncCommittee)
}
// CurrentSyncCommittee of the current sync committee in beacon chain state.
func (b *BeaconState) CurrentSyncCommittee() (*ethpb.SyncCommittee, error) {
b.lock.RLock()
defer b.lock.RUnlock()
if b.version == version.Phase0 {
return nil, errNotSupported("CurrentSyncCommittee", b.version)
}
if b.currentSyncCommittee == nil {
return nil, nil
}
@@ -29,11 +22,21 @@ func (b *BeaconState) CurrentSyncCommittee() (*ethpb.SyncCommittee, error) {
return b.currentSyncCommitteeVal(), nil
}
// currentSyncCommitteeVal of the current sync committee in beacon chain state.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) currentSyncCommitteeVal() *ethpb.SyncCommittee {
return copySyncCommittee(b.currentSyncCommittee)
}
// NextSyncCommittee of the next sync committee in beacon chain state.
func (b *BeaconState) NextSyncCommittee() (*ethpb.SyncCommittee, error) {
b.lock.RLock()
defer b.lock.RUnlock()
if b.version == version.Phase0 {
return nil, errNotSupported("NextSyncCommittee", b.version)
}
if b.nextSyncCommittee == nil {
return nil, nil
}
@@ -41,8 +44,14 @@ func (b *BeaconState) NextSyncCommittee() (*ethpb.SyncCommittee, error) {
return b.nextSyncCommitteeVal(), nil
}
// CopySyncCommittee copies the provided sync committee object.
func CopySyncCommittee(data *ethpb.SyncCommittee) *ethpb.SyncCommittee {
// nextSyncCommitteeVal of the next sync committee in beacon chain state.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) nextSyncCommitteeVal() *ethpb.SyncCommittee {
return copySyncCommittee(b.nextSyncCommittee)
}
// copySyncCommittee copies the provided sync committee object.
func copySyncCommittee(data *ethpb.SyncCommittee) *ethpb.SyncCommittee {
if data == nil {
return nil
}

View File

@@ -0,0 +1,99 @@
package state_native
import (
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
func TestBeaconState_SlotDataRace_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateSlotDataRace(t, func() (state.BeaconState, error) {
return InitializeFromProtoPhase0(&ethpb.BeaconState{Slot: 1})
})
}
func TestBeaconState_SlotDataRace_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateSlotDataRace(t, func() (state.BeaconState, error) {
return InitializeFromProtoAltair(&ethpb.BeaconStateAltair{Slot: 1})
})
}
func TestBeaconState_SlotDataRace_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateSlotDataRace(t, func() (state.BeaconState, error) {
return InitializeFromProtoBellatrix(&ethpb.BeaconStateBellatrix{Slot: 1})
})
}
func TestBeaconState_MatchCurrentJustifiedCheckpt_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateMatchCurrentJustifiedCheckptNative(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoPhase0(&ethpb.BeaconState{CurrentJustifiedCheckpoint: cp})
},
)
}
func TestBeaconState_MatchCurrentJustifiedCheckpt_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateMatchCurrentJustifiedCheckptNative(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoAltair(&ethpb.BeaconStateAltair{CurrentJustifiedCheckpoint: cp})
},
)
}
func TestBeaconState_MatchCurrentJustifiedCheckpt_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateMatchCurrentJustifiedCheckptNative(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoBellatrix(&ethpb.BeaconStateBellatrix{CurrentJustifiedCheckpoint: cp})
},
)
}
func TestBeaconState_MatchPreviousJustifiedCheckpt_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateMatchPreviousJustifiedCheckptNative(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoPhase0(&ethpb.BeaconState{PreviousJustifiedCheckpoint: cp})
},
)
}
func TestBeaconState_MatchPreviousJustifiedCheckpt_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateMatchPreviousJustifiedCheckptNative(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoAltair(&ethpb.BeaconStateAltair{PreviousJustifiedCheckpoint: cp})
},
)
}
func TestBeaconState_MatchPreviousJustifiedCheckpt_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateMatchPreviousJustifiedCheckptNative(
t,
func(cp *ethpb.Checkpoint) (state.BeaconState, error) {
return InitializeFromProtoBellatrix(&ethpb.BeaconStateBellatrix{PreviousJustifiedCheckpoint: cp})
},
)
}
func TestBeaconState_ValidatorByPubkey_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateValidatorByPubkey(t, func() (state.BeaconState, error) {
return InitializeFromProtoPhase0(&ethpb.BeaconState{})
})
}
func TestBeaconState_ValidatorByPubkey_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateValidatorByPubkey(t, func() (state.BeaconState, error) {
return InitializeFromProtoAltair(&ethpb.BeaconStateAltair{})
})
}
func TestBeaconState_ValidatorByPubkey_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateValidatorByPubkey(t, func() (state.BeaconState, error) {
return InitializeFromProtoBellatrix(&ethpb.BeaconStateBellatrix{})
})
}

View File

@@ -1,15 +1,15 @@
package v3
package state_native
import (
"fmt"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// ValidatorIndexOutOfRangeError represents an error scenario where a validator does not exist
@@ -111,7 +111,7 @@ func (b *BeaconState) ValidatorAtIndexReadOnly(idx types.ValidatorIndex) (state.
b.lock.RLock()
defer b.lock.RUnlock()
return v1.NewValidator(b.validators[idx])
return NewValidator(b.validators[idx])
}
// ValidatorIndexByPubkey returns a given validator by its 48-byte public key.
@@ -164,7 +164,7 @@ func (b *BeaconState) ReadFromEveryValidator(f func(idx int, val state.ReadOnlyV
b.lock.RUnlock()
for i, v := range validators {
v, err := v1.NewValidator(v)
v, err := NewValidator(v)
if err != nil {
return err
}
@@ -250,6 +250,22 @@ func (b *BeaconState) slashingsVal() []uint64 {
return res
}
// InactivityScores of validators participating in consensus on the beacon chain.
func (b *BeaconState) InactivityScores() ([]uint64, error) {
if b.version == version.Phase0 {
return nil, errNotSupported("InactivityScores", b.version)
}
if b.inactivityScores == nil {
return nil, nil
}
b.lock.RLock()
defer b.lock.RUnlock()
return b.inactivityScoresVal(), nil
}
// inactivityScoresVal of validators participating in consensus on the beacon chain.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) inactivityScoresVal() []uint64 {
@@ -261,15 +277,3 @@ func (b *BeaconState) inactivityScoresVal() []uint64 {
copy(res, b.inactivityScores)
return res
}
// InactivityScores of validators participating in consensus on the beacon chain.
func (b *BeaconState) InactivityScores() ([]uint64, error) {
if b.inactivityScores == nil {
return nil, nil
}
b.lock.RLock()
defer b.lock.RUnlock()
return b.inactivityScoresVal(), nil
}

View File

@@ -0,0 +1,34 @@
package state_native_test
import (
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
statenative "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native"
testtmpl "github.com/prysmaticlabs/prysm/beacon-chain/state/testing"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice_Phase0(t *testing.T) {
testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) {
return statenative.InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{
Validators: nil,
})
})
}
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice_Altair(t *testing.T) {
testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) {
return statenative.InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{
Validators: nil,
})
})
}
func TestBeaconState_ValidatorAtIndexReadOnly_HandlesNilSlice_Bellatrix(t *testing.T) {
testtmpl.VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t, func() (state.BeaconState, error) {
return statenative.InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{
Validators: nil,
})
})
}

View File

@@ -0,0 +1,240 @@
package state_native
import (
"context"
"encoding/binary"
"github.com/pkg/errors"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/encoding/ssz"
"github.com/prysmaticlabs/prysm/runtime/version"
"go.opencensus.io/trace"
)
// ComputeFieldRootsWithHasher hashes the provided state and returns its respective field roots.
func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]byte, error) {
_, span := trace.StartSpan(ctx, "ComputeFieldRootsWithHasher")
defer span.End()
if state == nil {
return nil, errors.New("nil state")
}
hasher := hash.CustomSHA256Hasher()
var fieldRoots [][]byte
switch state.version {
case version.Phase0:
fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateFieldCount)
case version.Altair:
fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateAltairFieldCount)
case version.Bellatrix:
fieldRoots = make([][]byte, params.BeaconConfig().BeaconStateBellatrixFieldCount)
}
// Genesis time root.
genesisRoot := ssz.Uint64Root(state.genesisTime)
fieldRoots[nativetypes.GenesisTime.RealPosition()] = genesisRoot[:]
// Genesis validators root.
r := [32]byte{}
copy(r[:], state.genesisValidatorsRoot[:])
fieldRoots[nativetypes.GenesisValidatorsRoot.RealPosition()] = r[:]
// Slot root.
slotRoot := ssz.Uint64Root(uint64(state.slot))
fieldRoots[nativetypes.Slot.RealPosition()] = slotRoot[:]
// Fork data structure root.
forkHashTreeRoot, err := ssz.ForkRoot(state.fork)
if err != nil {
return nil, errors.Wrap(err, "could not compute fork merkleization")
}
fieldRoots[nativetypes.Fork.RealPosition()] = forkHashTreeRoot[:]
// BeaconBlockHeader data structure root.
headerHashTreeRoot, err := stateutil.BlockHeaderRoot(state.latestBlockHeader)
if err != nil {
return nil, errors.Wrap(err, "could not compute block header merkleization")
}
fieldRoots[nativetypes.LatestBlockHeader.RealPosition()] = headerHashTreeRoot[:]
// BlockRoots array root.
bRoots := make([][]byte, len(state.blockRoots))
for i := range bRoots {
bRoots[i] = state.blockRoots[i][:]
}
blockRootsRoot, err := stateutil.ArraysRoot(bRoots, fieldparams.BlockRootsLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute block roots merkleization")
}
fieldRoots[nativetypes.BlockRoots.RealPosition()] = blockRootsRoot[:]
// StateRoots array root.
sRoots := make([][]byte, len(state.stateRoots))
for i := range sRoots {
sRoots[i] = state.stateRoots[i][:]
}
stateRootsRoot, err := stateutil.ArraysRoot(sRoots, fieldparams.StateRootsLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute state roots merkleization")
}
fieldRoots[nativetypes.StateRoots.RealPosition()] = stateRootsRoot[:]
// HistoricalRoots slice root.
hRoots := make([][]byte, len(state.historicalRoots))
for i := range hRoots {
hRoots[i] = state.historicalRoots[i][:]
}
historicalRootsRt, err := ssz.ByteArrayRootWithLimit(hRoots, fieldparams.HistoricalRootsLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute historical roots merkleization")
}
fieldRoots[nativetypes.HistoricalRoots.RealPosition()] = historicalRootsRt[:]
// Eth1Data data structure root.
eth1HashTreeRoot, err := stateutil.Eth1Root(hasher, state.eth1Data)
if err != nil {
return nil, errors.Wrap(err, "could not compute eth1data merkleization")
}
fieldRoots[nativetypes.Eth1Data.RealPosition()] = eth1HashTreeRoot[:]
// Eth1DataVotes slice root.
eth1VotesRoot, err := stateutil.Eth1DataVotesRoot(state.eth1DataVotes)
if err != nil {
return nil, errors.Wrap(err, "could not compute eth1data votes merkleization")
}
fieldRoots[nativetypes.Eth1DataVotes.RealPosition()] = eth1VotesRoot[:]
// Eth1DepositIndex root.
eth1DepositIndexBuf := make([]byte, 8)
binary.LittleEndian.PutUint64(eth1DepositIndexBuf, state.eth1DepositIndex)
eth1DepositBuf := bytesutil.ToBytes32(eth1DepositIndexBuf)
fieldRoots[nativetypes.Eth1DepositIndex.RealPosition()] = eth1DepositBuf[:]
// Validators slice root.
validatorsRoot, err := stateutil.ValidatorRegistryRoot(state.validators)
if err != nil {
return nil, errors.Wrap(err, "could not compute validator registry merkleization")
}
fieldRoots[nativetypes.Validators.RealPosition()] = validatorsRoot[:]
// Balances slice root.
balancesRoot, err := stateutil.Uint64ListRootWithRegistryLimit(state.balances)
if err != nil {
return nil, errors.Wrap(err, "could not compute validator balances merkleization")
}
fieldRoots[nativetypes.Balances.RealPosition()] = balancesRoot[:]
// RandaoMixes array root.
mixes := make([][]byte, len(state.randaoMixes))
for i := range mixes {
mixes[i] = state.randaoMixes[i][:]
}
randaoRootsRoot, err := stateutil.ArraysRoot(mixes, fieldparams.RandaoMixesLength)
if err != nil {
return nil, errors.Wrap(err, "could not compute randao roots merkleization")
}
fieldRoots[nativetypes.RandaoMixes.RealPosition()] = randaoRootsRoot[:]
// Slashings array root.
slashingsRootsRoot, err := ssz.SlashingsRoot(state.slashings)
if err != nil {
return nil, errors.Wrap(err, "could not compute slashings merkleization")
}
fieldRoots[nativetypes.Slashings.RealPosition()] = slashingsRootsRoot[:]
if state.version == version.Phase0 {
// PreviousEpochAttestations slice root.
prevAttsRoot, err := stateutil.EpochAttestationsRoot(state.previousEpochAttestations)
if err != nil {
return nil, errors.Wrap(err, "could not compute previous epoch attestations merkleization")
}
fieldRoots[nativetypes.PreviousEpochAttestations.RealPosition()] = prevAttsRoot[:]
// CurrentEpochAttestations slice root.
currAttsRoot, err := stateutil.EpochAttestationsRoot(state.currentEpochAttestations)
if err != nil {
return nil, errors.Wrap(err, "could not compute current epoch attestations merkleization")
}
fieldRoots[nativetypes.CurrentEpochAttestations.RealPosition()] = currAttsRoot[:]
}
if state.version == version.Altair || state.version == version.Bellatrix {
// PreviousEpochParticipation slice root.
prevParticipationRoot, err := stateutil.ParticipationBitsRoot(state.previousEpochParticipation)
if err != nil {
return nil, errors.Wrap(err, "could not compute previous epoch participation merkleization")
}
fieldRoots[nativetypes.PreviousEpochParticipationBits.RealPosition()] = prevParticipationRoot[:]
// CurrentEpochParticipation slice root.
currParticipationRoot, err := stateutil.ParticipationBitsRoot(state.currentEpochParticipation)
if err != nil {
return nil, errors.Wrap(err, "could not compute current epoch participation merkleization")
}
fieldRoots[nativetypes.CurrentEpochParticipationBits.RealPosition()] = currParticipationRoot[:]
}
// JustificationBits root.
justifiedBitsRoot := bytesutil.ToBytes32(state.justificationBits)
fieldRoots[nativetypes.JustificationBits.RealPosition()] = justifiedBitsRoot[:]
// PreviousJustifiedCheckpoint data structure root.
prevCheckRoot, err := ssz.CheckpointRoot(hasher, state.previousJustifiedCheckpoint)
if err != nil {
return nil, errors.Wrap(err, "could not compute previous justified checkpoint merkleization")
}
fieldRoots[nativetypes.PreviousJustifiedCheckpoint.RealPosition()] = prevCheckRoot[:]
// CurrentJustifiedCheckpoint data structure root.
currJustRoot, err := ssz.CheckpointRoot(hasher, state.currentJustifiedCheckpoint)
if err != nil {
return nil, errors.Wrap(err, "could not compute current justified checkpoint merkleization")
}
fieldRoots[nativetypes.CurrentJustifiedCheckpoint.RealPosition()] = currJustRoot[:]
// FinalizedCheckpoint data structure root.
finalRoot, err := ssz.CheckpointRoot(hasher, state.finalizedCheckpoint)
if err != nil {
return nil, errors.Wrap(err, "could not compute finalized checkpoint merkleization")
}
fieldRoots[nativetypes.FinalizedCheckpoint.RealPosition()] = finalRoot[:]
if state.version == version.Altair || state.version == version.Bellatrix {
// Inactivity scores root.
inactivityScoresRoot, err := stateutil.Uint64ListRootWithRegistryLimit(state.inactivityScores)
if err != nil {
return nil, errors.Wrap(err, "could not compute inactivityScoreRoot")
}
fieldRoots[nativetypes.InactivityScores.RealPosition()] = inactivityScoresRoot[:]
// Current sync committee root.
currentSyncCommitteeRoot, err := stateutil.SyncCommitteeRoot(state.currentSyncCommittee)
if err != nil {
return nil, errors.Wrap(err, "could not compute sync committee merkleization")
}
fieldRoots[nativetypes.CurrentSyncCommittee.RealPosition()] = currentSyncCommitteeRoot[:]
// Next sync committee root.
nextSyncCommitteeRoot, err := stateutil.SyncCommitteeRoot(state.nextSyncCommittee)
if err != nil {
return nil, errors.Wrap(err, "could not compute sync committee merkleization")
}
fieldRoots[nativetypes.NextSyncCommittee.RealPosition()] = nextSyncCommitteeRoot[:]
}
if state.version == version.Bellatrix {
// Execution payload root.
executionPayloadRoot, err := state.latestExecutionPayloadHeader.HashTreeRoot()
if err != nil {
return nil, err
}
fieldRoots[nativetypes.LatestExecutionPayloadHeader.RealPosition()] = executionPayloadRoot[:]
}
return fieldRoots, nil
}

View File

@@ -0,0 +1,355 @@
package state_native_test
import (
"context"
"testing"
"github.com/prysmaticlabs/go-bitfield"
state_native "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2"
v3 "github.com/prysmaticlabs/prysm/beacon-chain/state/v3"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
"github.com/prysmaticlabs/prysm/testing/util"
)
func TestComputeFieldRootsWithHasher_Phase0(t *testing.T) {
beaconState, err := util.NewBeaconState(util.FillRootsNaturalOpt)
require.NoError(t, err)
require.NoError(t, beaconState.SetGenesisTime(123))
require.NoError(t, beaconState.SetGenesisValidatorsRoot(genesisValidatorsRoot()))
require.NoError(t, beaconState.SetSlot(123))
require.NoError(t, beaconState.SetFork(fork()))
require.NoError(t, beaconState.SetLatestBlockHeader(latestBlockHeader()))
historicalRoots, err := util.PrepareRoots(int(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
require.NoError(t, beaconState.SetHistoricalRoots(historicalRoots))
require.NoError(t, beaconState.SetEth1Data(eth1Data()))
require.NoError(t, beaconState.SetEth1DataVotes([]*ethpb.Eth1Data{eth1Data()}))
require.NoError(t, beaconState.SetEth1DepositIndex(123))
require.NoError(t, beaconState.SetValidators([]*ethpb.Validator{validator()}))
require.NoError(t, beaconState.SetBalances([]uint64{1, 2, 3}))
randaoMixes, err := util.PrepareRoots(int(params.BeaconConfig().EpochsPerHistoricalVector))
require.NoError(t, err)
require.NoError(t, beaconState.SetRandaoMixes(randaoMixes))
require.NoError(t, beaconState.SetSlashings([]uint64{1, 2, 3}))
require.NoError(t, beaconState.AppendPreviousEpochAttestations(pendingAttestation("previous")))
require.NoError(t, beaconState.AppendCurrentEpochAttestations(pendingAttestation("current")))
require.NoError(t, beaconState.SetJustificationBits(justificationBits()))
require.NoError(t, beaconState.SetPreviousJustifiedCheckpoint(checkpoint("previous")))
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(checkpoint("current")))
require.NoError(t, beaconState.SetFinalizedCheckpoint(checkpoint("finalized")))
v1State, ok := beaconState.(*v1.BeaconState)
require.Equal(t, true, ok)
protoState, ok := v1State.InnerStateUnsafe().(*ethpb.BeaconState)
require.Equal(t, true, ok)
initState, err := state_native.InitializeFromProtoPhase0(protoState)
require.NoError(t, err)
s, ok := initState.(*state_native.BeaconState)
require.Equal(t, true, ok)
root, err := state_native.ComputeFieldRootsWithHasher(context.Background(), s)
require.NoError(t, err)
expected := [][]byte{
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x67, 0x76, 0x72, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x58, 0xba, 0xf, 0x9b, 0x4f, 0x63, 0x1c, 0xa6, 0x19, 0xb1, 0xa2, 0x1f, 0xd1, 0x29, 0xc7, 0x67, 0x9c, 0x32, 0x4, 0x1f, 0xcf, 0x4e, 0x64, 0x9b, 0x8f, 0x21, 0xb4, 0xe6, 0xa5, 0xc9, 0xc, 0x38},
{0x8b, 0x5, 0x59, 0x78, 0xed, 0xbe, 0x2c, 0xde, 0xa6, 0xf, 0x52, 0xdc, 0x16, 0x83, 0xa0, 0x5d, 0x8, 0xc3, 0x37, 0x91, 0x3a, 0xf6, 0xfa, 0x6, 0x62, 0xc9, 0x6, 0xb1, 0x41, 0x48, 0xaf, 0xec},
{0xcc, 0xa1, 0x69, 0xa8, 0x8b, 0x1e, 0x49, 0x5, 0x1f, 0xe4, 0xd8, 0xff, 0x82, 0xa2, 0x2e, 0xf0, 0x54, 0xd1, 0x13, 0xc9, 0x8e, 0xb9, 0x82, 0xa6, 0x9e, 0x42, 0x2, 0xec, 0x97, 0x6f, 0x33, 0x88},
{0xcc, 0xa1, 0x69, 0xa8, 0x8b, 0x1e, 0x49, 0x5, 0x1f, 0xe4, 0xd8, 0xff, 0x82, 0xa2, 0x2e, 0xf0, 0x54, 0xd1, 0x13, 0xc9, 0x8e, 0xb9, 0x82, 0xa6, 0x9e, 0x42, 0x2, 0xec, 0x97, 0x6f, 0x33, 0x88},
{0xf, 0xad, 0xd3, 0x92, 0x4b, 0xda, 0xfa, 0xc6, 0x61, 0x50, 0xb7, 0xdf, 0x5f, 0x2c, 0xd0, 0x94, 0xc3, 0xaf, 0x41, 0x9d, 0xa, 0xea, 0x50, 0x96, 0x82, 0x62, 0x1c, 0x72, 0x26, 0x20, 0x6b, 0xac},
{0xc9, 0x4e, 0x2c, 0xb0, 0x20, 0xe3, 0xe7, 0x8c, 0x5c, 0xbd, 0xeb, 0x9b, 0xa5, 0x7b, 0x53, 0x50, 0xca, 0xfe, 0xe9, 0x48, 0x9e, 0x8d, 0xf8, 0x4a, 0xe6, 0x8d, 0x9c, 0x97, 0x81, 0x74, 0xb, 0x5e},
{0x71, 0x52, 0xd2, 0x9b, 0x87, 0x3c, 0x8a, 0xd9, 0x51, 0x55, 0xc0, 0x42, 0xb, 0xc4, 0x12, 0xa4, 0x79, 0xf5, 0x7d, 0x37, 0x16, 0xf4, 0x90, 0x72, 0x5d, 0xe0, 0x34, 0xb4, 0x2, 0x8c, 0x39, 0xe4},
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0xf, 0xf7, 0x4f, 0xe1, 0xa9, 0x72, 0x9c, 0x95, 0xf0, 0xe1, 0xde, 0xa4, 0x32, 0xc, 0x67, 0x52, 0x23, 0x13, 0x9e, 0xe2, 0x40, 0x8d, 0xf6, 0x18, 0x57, 0xf0, 0x1a, 0x4a, 0xad, 0x46, 0xce, 0x42},
{0xf9, 0x11, 0x2c, 0xc2, 0x71, 0x70, 0xde, 0x47, 0x26, 0xeb, 0x26, 0xd4, 0xa4, 0xe8, 0x68, 0xb, 0x16, 0xa2, 0x6e, 0x52, 0x54, 0xe, 0x5c, 0x83, 0x17, 0x3, 0xea, 0xdd, 0xd5, 0xa7, 0xb2, 0x3f},
{0x64, 0xbd, 0x40, 0xa7, 0x10, 0x44, 0x84, 0xed, 0xf3, 0x5f, 0xc3, 0x5d, 0x7b, 0xbe, 0xe8, 0x75, 0xbf, 0x66, 0xcb, 0xce, 0x77, 0xfa, 0x0, 0x3, 0xdd, 0xfb, 0x80, 0xd2, 0x77, 0x1b, 0xc2, 0x8},
{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x54, 0xd3, 0xce, 0x8a, 0x3f, 0xfd, 0x21, 0x3a, 0xb4, 0xa6, 0xd, 0xb, 0x9f, 0xf2, 0x88, 0xf0, 0xb1, 0x44, 0x9d, 0xb1, 0x2, 0x95, 0x67, 0xdf, 0x6f, 0x28, 0xa9, 0x68, 0xcd, 0xaa, 0x8c, 0x54},
{0xeb, 0x8, 0xb4, 0x1b, 0x76, 0xa2, 0x23, 0xbb, 0x4a, 0xd3, 0x78, 0xca, 0x2e, 0xe8, 0x2c, 0xa1, 0xbf, 0x45, 0xf2, 0x58, 0xdf, 0x39, 0xdf, 0x43, 0x40, 0xb, 0x96, 0xcf, 0xfd, 0x9a, 0x87, 0x85},
{0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x76, 0x88, 0xa0, 0x68, 0x45, 0x25, 0x8f, 0xd5, 0xf9, 0xb2, 0xb0, 0x42, 0x68, 0x6b, 0x51, 0xcc, 0x29, 0x94, 0x63, 0x85, 0xec, 0xf5, 0x47, 0xf0, 0x9c, 0x46, 0x86, 0xa9, 0x99, 0x7d, 0x29, 0x6c},
{0x41, 0x44, 0x52, 0xff, 0x8c, 0xa6, 0xb3, 0x2e, 0xcc, 0x5e, 0x63, 0x8f, 0x8e, 0x7d, 0xe7, 0x52, 0x42, 0x94, 0x55, 0x2f, 0x89, 0xdd, 0x1e, 0x3c, 0xb0, 0xf4, 0x51, 0x51, 0x36, 0x81, 0x72, 0x1},
{0xa9, 0xbb, 0x6a, 0x1f, 0x5d, 0x86, 0x7d, 0xa7, 0x5a, 0x7d, 0x9d, 0x8d, 0xc0, 0x15, 0xb7, 0x0, 0xee, 0xa9, 0x68, 0x51, 0x88, 0x57, 0x5a, 0xd9, 0x4e, 0x1d, 0x8e, 0x44, 0xbf, 0xdc, 0x73, 0xff},
}
assert.DeepEqual(t, expected, root)
}
func TestComputeFieldRootsWithHasher_Altair(t *testing.T) {
beaconState, err := util.NewBeaconStateAltair(util.FillRootsNaturalOptAltair)
require.NoError(t, err)
require.NoError(t, beaconState.SetGenesisTime(123))
require.NoError(t, beaconState.SetGenesisValidatorsRoot(genesisValidatorsRoot()))
require.NoError(t, beaconState.SetSlot(123))
require.NoError(t, beaconState.SetFork(fork()))
require.NoError(t, beaconState.SetLatestBlockHeader(latestBlockHeader()))
historicalRoots, err := util.PrepareRoots(int(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
require.NoError(t, beaconState.SetHistoricalRoots(historicalRoots))
require.NoError(t, beaconState.SetEth1Data(eth1Data()))
require.NoError(t, beaconState.SetEth1DataVotes([]*ethpb.Eth1Data{eth1Data()}))
require.NoError(t, beaconState.SetEth1DepositIndex(123))
require.NoError(t, beaconState.SetValidators([]*ethpb.Validator{validator()}))
require.NoError(t, beaconState.SetBalances([]uint64{1, 2, 3}))
randaoMixes, err := util.PrepareRoots(int(params.BeaconConfig().EpochsPerHistoricalVector))
require.NoError(t, err)
require.NoError(t, beaconState.SetRandaoMixes(randaoMixes))
require.NoError(t, beaconState.SetSlashings([]uint64{1, 2, 3}))
require.NoError(t, beaconState.SetPreviousParticipationBits([]byte{1, 2, 3}))
require.NoError(t, beaconState.SetCurrentParticipationBits([]byte{1, 2, 3}))
require.NoError(t, beaconState.SetJustificationBits(justificationBits()))
require.NoError(t, beaconState.SetPreviousJustifiedCheckpoint(checkpoint("previous")))
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(checkpoint("current")))
require.NoError(t, beaconState.SetFinalizedCheckpoint(checkpoint("finalized")))
require.NoError(t, beaconState.SetInactivityScores([]uint64{1, 2, 3}))
require.NoError(t, beaconState.SetCurrentSyncCommittee(syncCommittee("current")))
require.NoError(t, beaconState.SetNextSyncCommittee(syncCommittee("next")))
v1State, ok := beaconState.(*v2.BeaconState)
require.Equal(t, true, ok)
protoState, ok := v1State.InnerStateUnsafe().(*ethpb.BeaconStateAltair)
require.Equal(t, true, ok)
initState, err := state_native.InitializeFromProtoAltair(protoState)
require.NoError(t, err)
s, ok := initState.(*state_native.BeaconState)
require.Equal(t, true, ok)
root, err := state_native.ComputeFieldRootsWithHasher(context.Background(), s)
require.NoError(t, err)
expected := [][]byte{
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x67, 0x76, 0x72, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x58, 0xba, 0xf, 0x9b, 0x4f, 0x63, 0x1c, 0xa6, 0x19, 0xb1, 0xa2, 0x1f, 0xd1, 0x29, 0xc7, 0x67, 0x9c, 0x32, 0x4, 0x1f, 0xcf, 0x4e, 0x64, 0x9b, 0x8f, 0x21, 0xb4, 0xe6, 0xa5, 0xc9, 0xc, 0x38},
{0x8b, 0x5, 0x59, 0x78, 0xed, 0xbe, 0x2c, 0xde, 0xa6, 0xf, 0x52, 0xdc, 0x16, 0x83, 0xa0, 0x5d, 0x8, 0xc3, 0x37, 0x91, 0x3a, 0xf6, 0xfa, 0x6, 0x62, 0xc9, 0x6, 0xb1, 0x41, 0x48, 0xaf, 0xec},
{0xcc, 0xa1, 0x69, 0xa8, 0x8b, 0x1e, 0x49, 0x5, 0x1f, 0xe4, 0xd8, 0xff, 0x82, 0xa2, 0x2e, 0xf0, 0x54, 0xd1, 0x13, 0xc9, 0x8e, 0xb9, 0x82, 0xa6, 0x9e, 0x42, 0x2, 0xec, 0x97, 0x6f, 0x33, 0x88},
{0xcc, 0xa1, 0x69, 0xa8, 0x8b, 0x1e, 0x49, 0x5, 0x1f, 0xe4, 0xd8, 0xff, 0x82, 0xa2, 0x2e, 0xf0, 0x54, 0xd1, 0x13, 0xc9, 0x8e, 0xb9, 0x82, 0xa6, 0x9e, 0x42, 0x2, 0xec, 0x97, 0x6f, 0x33, 0x88},
{0xf, 0xad, 0xd3, 0x92, 0x4b, 0xda, 0xfa, 0xc6, 0x61, 0x50, 0xb7, 0xdf, 0x5f, 0x2c, 0xd0, 0x94, 0xc3, 0xaf, 0x41, 0x9d, 0xa, 0xea, 0x50, 0x96, 0x82, 0x62, 0x1c, 0x72, 0x26, 0x20, 0x6b, 0xac},
{0xc9, 0x4e, 0x2c, 0xb0, 0x20, 0xe3, 0xe7, 0x8c, 0x5c, 0xbd, 0xeb, 0x9b, 0xa5, 0x7b, 0x53, 0x50, 0xca, 0xfe, 0xe9, 0x48, 0x9e, 0x8d, 0xf8, 0x4a, 0xe6, 0x8d, 0x9c, 0x97, 0x81, 0x74, 0xb, 0x5e},
{0x71, 0x52, 0xd2, 0x9b, 0x87, 0x3c, 0x8a, 0xd9, 0x51, 0x55, 0xc0, 0x42, 0xb, 0xc4, 0x12, 0xa4, 0x79, 0xf5, 0x7d, 0x37, 0x16, 0xf4, 0x90, 0x72, 0x5d, 0xe0, 0x34, 0xb4, 0x2, 0x8c, 0x39, 0xe4},
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0xf, 0xf7, 0x4f, 0xe1, 0xa9, 0x72, 0x9c, 0x95, 0xf0, 0xe1, 0xde, 0xa4, 0x32, 0xc, 0x67, 0x52, 0x23, 0x13, 0x9e, 0xe2, 0x40, 0x8d, 0xf6, 0x18, 0x57, 0xf0, 0x1a, 0x4a, 0xad, 0x46, 0xce, 0x42},
{0xf9, 0x11, 0x2c, 0xc2, 0x71, 0x70, 0xde, 0x47, 0x26, 0xeb, 0x26, 0xd4, 0xa4, 0xe8, 0x68, 0xb, 0x16, 0xa2, 0x6e, 0x52, 0x54, 0xe, 0x5c, 0x83, 0x17, 0x3, 0xea, 0xdd, 0xd5, 0xa7, 0xb2, 0x3f},
{0x64, 0xbd, 0x40, 0xa7, 0x10, 0x44, 0x84, 0xed, 0xf3, 0x5f, 0xc3, 0x5d, 0x7b, 0xbe, 0xe8, 0x75, 0xbf, 0x66, 0xcb, 0xce, 0x77, 0xfa, 0x0, 0x3, 0xdd, 0xfb, 0x80, 0xd2, 0x77, 0x1b, 0xc2, 0x8},
{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x75, 0xb2, 0xae, 0x1d, 0xd8, 0xca, 0xe6, 0x4d, 0xa8, 0xc5, 0xc9, 0x19, 0x8, 0x96, 0xaf, 0x9b, 0xe6, 0xf6, 0x99, 0xb9, 0x58, 0x56, 0x5b, 0x25, 0xea, 0x9c, 0x86, 0x5e, 0x96, 0x6a, 0x48, 0xb},
{0x75, 0xb2, 0xae, 0x1d, 0xd8, 0xca, 0xe6, 0x4d, 0xa8, 0xc5, 0xc9, 0x19, 0x8, 0x96, 0xaf, 0x9b, 0xe6, 0xf6, 0x99, 0xb9, 0x58, 0x56, 0x5b, 0x25, 0xea, 0x9c, 0x86, 0x5e, 0x96, 0x6a, 0x48, 0xb},
{0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x76, 0x88, 0xa0, 0x68, 0x45, 0x25, 0x8f, 0xd5, 0xf9, 0xb2, 0xb0, 0x42, 0x68, 0x6b, 0x51, 0xcc, 0x29, 0x94, 0x63, 0x85, 0xec, 0xf5, 0x47, 0xf0, 0x9c, 0x46, 0x86, 0xa9, 0x99, 0x7d, 0x29, 0x6c},
{0x41, 0x44, 0x52, 0xff, 0x8c, 0xa6, 0xb3, 0x2e, 0xcc, 0x5e, 0x63, 0x8f, 0x8e, 0x7d, 0xe7, 0x52, 0x42, 0x94, 0x55, 0x2f, 0x89, 0xdd, 0x1e, 0x3c, 0xb0, 0xf4, 0x51, 0x51, 0x36, 0x81, 0x72, 0x1},
{0xa9, 0xbb, 0x6a, 0x1f, 0x5d, 0x86, 0x7d, 0xa7, 0x5a, 0x7d, 0x9d, 0x8d, 0xc0, 0x15, 0xb7, 0x0, 0xee, 0xa9, 0x68, 0x51, 0x88, 0x57, 0x5a, 0xd9, 0x4e, 0x1d, 0x8e, 0x44, 0xbf, 0xdc, 0x73, 0xff},
{0xf9, 0x11, 0x2c, 0xc2, 0x71, 0x70, 0xde, 0x47, 0x26, 0xeb, 0x26, 0xd4, 0xa4, 0xe8, 0x68, 0xb, 0x16, 0xa2, 0x6e, 0x52, 0x54, 0xe, 0x5c, 0x83, 0x17, 0x3, 0xea, 0xdd, 0xd5, 0xa7, 0xb2, 0x3f},
{0x3d, 0xf3, 0x66, 0xd4, 0x12, 0x40, 0x3f, 0x28, 0xeb, 0xe4, 0x19, 0x59, 0xae, 0xab, 0x4d, 0xf3, 0x98, 0x88, 0x7f, 0x1e, 0x58, 0xa, 0x5d, 0xd4, 0xeb, 0xe5, 0x5d, 0x3d, 0x11, 0x70, 0x24, 0x76},
{0xd6, 0x4c, 0xb1, 0xac, 0x61, 0x7, 0x26, 0xbb, 0xd3, 0x27, 0x2a, 0xcd, 0xdd, 0x55, 0xf, 0x2b, 0x6a, 0xe8, 0x1, 0x31, 0x48, 0x66, 0x2f, 0x98, 0x7b, 0x6d, 0x27, 0x69, 0xd9, 0x40, 0xcc, 0x37},
}
assert.DeepEqual(t, expected, root)
}
func TestComputeFieldRootsWithHasher_Bellatrix(t *testing.T) {
beaconState, err := util.NewBeaconStateBellatrix(util.FillRootsNaturalOptBellatrix)
require.NoError(t, err)
require.NoError(t, beaconState.SetGenesisTime(123))
require.NoError(t, beaconState.SetGenesisValidatorsRoot(genesisValidatorsRoot()))
require.NoError(t, beaconState.SetSlot(123))
require.NoError(t, beaconState.SetFork(fork()))
require.NoError(t, beaconState.SetLatestBlockHeader(latestBlockHeader()))
historicalRoots, err := util.PrepareRoots(int(params.BeaconConfig().SlotsPerHistoricalRoot))
require.NoError(t, err)
require.NoError(t, beaconState.SetHistoricalRoots(historicalRoots))
require.NoError(t, beaconState.SetEth1Data(eth1Data()))
require.NoError(t, beaconState.SetEth1DataVotes([]*ethpb.Eth1Data{eth1Data()}))
require.NoError(t, beaconState.SetEth1DepositIndex(123))
require.NoError(t, beaconState.SetValidators([]*ethpb.Validator{validator()}))
require.NoError(t, beaconState.SetBalances([]uint64{1, 2, 3}))
randaoMixes, err := util.PrepareRoots(int(params.BeaconConfig().EpochsPerHistoricalVector))
require.NoError(t, err)
require.NoError(t, beaconState.SetRandaoMixes(randaoMixes))
require.NoError(t, beaconState.SetSlashings([]uint64{1, 2, 3}))
require.NoError(t, beaconState.SetPreviousParticipationBits([]byte{1, 2, 3}))
require.NoError(t, beaconState.SetCurrentParticipationBits([]byte{1, 2, 3}))
require.NoError(t, beaconState.SetJustificationBits(justificationBits()))
require.NoError(t, beaconState.SetPreviousJustifiedCheckpoint(checkpoint("previous")))
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(checkpoint("current")))
require.NoError(t, beaconState.SetFinalizedCheckpoint(checkpoint("finalized")))
require.NoError(t, beaconState.SetInactivityScores([]uint64{1, 2, 3}))
require.NoError(t, beaconState.SetCurrentSyncCommittee(syncCommittee("current")))
require.NoError(t, beaconState.SetNextSyncCommittee(syncCommittee("next")))
require.NoError(t, beaconState.SetLatestExecutionPayloadHeader(executionPayloadHeader()))
v1State, ok := beaconState.(*v3.BeaconState)
require.Equal(t, true, ok)
protoState, ok := v1State.InnerStateUnsafe().(*ethpb.BeaconStateBellatrix)
require.Equal(t, true, ok)
initState, err := state_native.InitializeFromProtoBellatrix(protoState)
require.NoError(t, err)
s, ok := initState.(*state_native.BeaconState)
require.Equal(t, true, ok)
root, err := state_native.ComputeFieldRootsWithHasher(context.Background(), s)
require.NoError(t, err)
expected := [][]byte{
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x67, 0x76, 0x72, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x58, 0xba, 0xf, 0x9b, 0x4f, 0x63, 0x1c, 0xa6, 0x19, 0xb1, 0xa2, 0x1f, 0xd1, 0x29, 0xc7, 0x67, 0x9c, 0x32, 0x4, 0x1f, 0xcf, 0x4e, 0x64, 0x9b, 0x8f, 0x21, 0xb4, 0xe6, 0xa5, 0xc9, 0xc, 0x38},
{0x8b, 0x5, 0x59, 0x78, 0xed, 0xbe, 0x2c, 0xde, 0xa6, 0xf, 0x52, 0xdc, 0x16, 0x83, 0xa0, 0x5d, 0x8, 0xc3, 0x37, 0x91, 0x3a, 0xf6, 0xfa, 0x6, 0x62, 0xc9, 0x6, 0xb1, 0x41, 0x48, 0xaf, 0xec},
{0xcc, 0xa1, 0x69, 0xa8, 0x8b, 0x1e, 0x49, 0x5, 0x1f, 0xe4, 0xd8, 0xff, 0x82, 0xa2, 0x2e, 0xf0, 0x54, 0xd1, 0x13, 0xc9, 0x8e, 0xb9, 0x82, 0xa6, 0x9e, 0x42, 0x2, 0xec, 0x97, 0x6f, 0x33, 0x88},
{0xcc, 0xa1, 0x69, 0xa8, 0x8b, 0x1e, 0x49, 0x5, 0x1f, 0xe4, 0xd8, 0xff, 0x82, 0xa2, 0x2e, 0xf0, 0x54, 0xd1, 0x13, 0xc9, 0x8e, 0xb9, 0x82, 0xa6, 0x9e, 0x42, 0x2, 0xec, 0x97, 0x6f, 0x33, 0x88},
{0xf, 0xad, 0xd3, 0x92, 0x4b, 0xda, 0xfa, 0xc6, 0x61, 0x50, 0xb7, 0xdf, 0x5f, 0x2c, 0xd0, 0x94, 0xc3, 0xaf, 0x41, 0x9d, 0xa, 0xea, 0x50, 0x96, 0x82, 0x62, 0x1c, 0x72, 0x26, 0x20, 0x6b, 0xac},
{0xc9, 0x4e, 0x2c, 0xb0, 0x20, 0xe3, 0xe7, 0x8c, 0x5c, 0xbd, 0xeb, 0x9b, 0xa5, 0x7b, 0x53, 0x50, 0xca, 0xfe, 0xe9, 0x48, 0x9e, 0x8d, 0xf8, 0x4a, 0xe6, 0x8d, 0x9c, 0x97, 0x81, 0x74, 0xb, 0x5e},
{0x71, 0x52, 0xd2, 0x9b, 0x87, 0x3c, 0x8a, 0xd9, 0x51, 0x55, 0xc0, 0x42, 0xb, 0xc4, 0x12, 0xa4, 0x79, 0xf5, 0x7d, 0x37, 0x16, 0xf4, 0x90, 0x72, 0x5d, 0xe0, 0x34, 0xb4, 0x2, 0x8c, 0x39, 0xe4},
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0xf, 0xf7, 0x4f, 0xe1, 0xa9, 0x72, 0x9c, 0x95, 0xf0, 0xe1, 0xde, 0xa4, 0x32, 0xc, 0x67, 0x52, 0x23, 0x13, 0x9e, 0xe2, 0x40, 0x8d, 0xf6, 0x18, 0x57, 0xf0, 0x1a, 0x4a, 0xad, 0x46, 0xce, 0x42},
{0xf9, 0x11, 0x2c, 0xc2, 0x71, 0x70, 0xde, 0x47, 0x26, 0xeb, 0x26, 0xd4, 0xa4, 0xe8, 0x68, 0xb, 0x16, 0xa2, 0x6e, 0x52, 0x54, 0xe, 0x5c, 0x83, 0x17, 0x3, 0xea, 0xdd, 0xd5, 0xa7, 0xb2, 0x3f},
{0x64, 0xbd, 0x40, 0xa7, 0x10, 0x44, 0x84, 0xed, 0xf3, 0x5f, 0xc3, 0x5d, 0x7b, 0xbe, 0xe8, 0x75, 0xbf, 0x66, 0xcb, 0xce, 0x77, 0xfa, 0x0, 0x3, 0xdd, 0xfb, 0x80, 0xd2, 0x77, 0x1b, 0xc2, 0x8},
{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x75, 0xb2, 0xae, 0x1d, 0xd8, 0xca, 0xe6, 0x4d, 0xa8, 0xc5, 0xc9, 0x19, 0x8, 0x96, 0xaf, 0x9b, 0xe6, 0xf6, 0x99, 0xb9, 0x58, 0x56, 0x5b, 0x25, 0xea, 0x9c, 0x86, 0x5e, 0x96, 0x6a, 0x48, 0xb},
{0x75, 0xb2, 0xae, 0x1d, 0xd8, 0xca, 0xe6, 0x4d, 0xa8, 0xc5, 0xc9, 0x19, 0x8, 0x96, 0xaf, 0x9b, 0xe6, 0xf6, 0x99, 0xb9, 0x58, 0x56, 0x5b, 0x25, 0xea, 0x9c, 0x86, 0x5e, 0x96, 0x6a, 0x48, 0xb},
{0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
{0x76, 0x88, 0xa0, 0x68, 0x45, 0x25, 0x8f, 0xd5, 0xf9, 0xb2, 0xb0, 0x42, 0x68, 0x6b, 0x51, 0xcc, 0x29, 0x94, 0x63, 0x85, 0xec, 0xf5, 0x47, 0xf0, 0x9c, 0x46, 0x86, 0xa9, 0x99, 0x7d, 0x29, 0x6c},
{0x41, 0x44, 0x52, 0xff, 0x8c, 0xa6, 0xb3, 0x2e, 0xcc, 0x5e, 0x63, 0x8f, 0x8e, 0x7d, 0xe7, 0x52, 0x42, 0x94, 0x55, 0x2f, 0x89, 0xdd, 0x1e, 0x3c, 0xb0, 0xf4, 0x51, 0x51, 0x36, 0x81, 0x72, 0x1},
{0xa9, 0xbb, 0x6a, 0x1f, 0x5d, 0x86, 0x7d, 0xa7, 0x5a, 0x7d, 0x9d, 0x8d, 0xc0, 0x15, 0xb7, 0x0, 0xee, 0xa9, 0x68, 0x51, 0x88, 0x57, 0x5a, 0xd9, 0x4e, 0x1d, 0x8e, 0x44, 0xbf, 0xdc, 0x73, 0xff},
{0xf9, 0x11, 0x2c, 0xc2, 0x71, 0x70, 0xde, 0x47, 0x26, 0xeb, 0x26, 0xd4, 0xa4, 0xe8, 0x68, 0xb, 0x16, 0xa2, 0x6e, 0x52, 0x54, 0xe, 0x5c, 0x83, 0x17, 0x3, 0xea, 0xdd, 0xd5, 0xa7, 0xb2, 0x3f},
{0x3d, 0xf3, 0x66, 0xd4, 0x12, 0x40, 0x3f, 0x28, 0xeb, 0xe4, 0x19, 0x59, 0xae, 0xab, 0x4d, 0xf3, 0x98, 0x88, 0x7f, 0x1e, 0x58, 0xa, 0x5d, 0xd4, 0xeb, 0xe5, 0x5d, 0x3d, 0x11, 0x70, 0x24, 0x76},
{0xd6, 0x4c, 0xb1, 0xac, 0x61, 0x7, 0x26, 0xbb, 0xd3, 0x27, 0x2a, 0xcd, 0xdd, 0x55, 0xf, 0x2b, 0x6a, 0xe8, 0x1, 0x31, 0x48, 0x66, 0x2f, 0x98, 0x7b, 0x6d, 0x27, 0x69, 0xd9, 0x40, 0xcc, 0x37},
{0xbc, 0xbb, 0x39, 0x57, 0x61, 0x1d, 0x54, 0xd6, 0x1b, 0xfe, 0x7a, 0xbd, 0x29, 0x52, 0x57, 0xdd, 0x19, 0x1, 0x89, 0x22, 0x7d, 0xdf, 0x7b, 0x53, 0x9f, 0xb, 0x46, 0x5, 0x9f, 0x80, 0xcc, 0x8e},
}
assert.DeepEqual(t, expected, root)
}
func genesisValidatorsRoot() []byte {
gvr := bytesutil.ToBytes32([]byte("gvr"))
return gvr[:]
}
func fork() *ethpb.Fork {
prev := bytesutil.ToBytes4([]byte("prev"))
curr := bytesutil.ToBytes4([]byte("curr"))
return &ethpb.Fork{
PreviousVersion: prev[:],
CurrentVersion: curr[:],
Epoch: 123,
}
}
func latestBlockHeader() *ethpb.BeaconBlockHeader {
pr := bytesutil.ToBytes32([]byte("parent"))
sr := bytesutil.ToBytes32([]byte("state"))
br := bytesutil.ToBytes32([]byte("body"))
return &ethpb.BeaconBlockHeader{
Slot: 123,
ProposerIndex: 123,
ParentRoot: pr[:],
StateRoot: sr[:],
BodyRoot: br[:],
}
}
func eth1Data() *ethpb.Eth1Data {
dr := bytesutil.ToBytes32([]byte("deposit"))
bh := bytesutil.ToBytes32([]byte("block"))
return &ethpb.Eth1Data{
DepositRoot: dr[:],
DepositCount: 123,
BlockHash: bh[:],
}
}
func validator() *ethpb.Validator {
pk := bytesutil.ToBytes48([]byte("public"))
wc := bytesutil.ToBytes32([]byte("withdrawal"))
return &ethpb.Validator{
PublicKey: pk[:],
WithdrawalCredentials: wc[:],
EffectiveBalance: 123,
Slashed: true,
ActivationEligibilityEpoch: 123,
ActivationEpoch: 123,
ExitEpoch: 123,
WithdrawableEpoch: 123,
}
}
func pendingAttestation(prefix string) *ethpb.PendingAttestation {
bbr := bytesutil.ToBytes32([]byte(prefix + "beacon"))
r := bytesutil.ToBytes32([]byte(prefix + "root"))
return &ethpb.PendingAttestation{
AggregationBits: bitfield.Bitlist{0x00, 0xFF, 0xFF, 0xFF},
Data: &ethpb.AttestationData{
Slot: 123,
CommitteeIndex: 123,
BeaconBlockRoot: bbr[:],
Source: &ethpb.Checkpoint{
Epoch: 123,
Root: r[:],
},
Target: &ethpb.Checkpoint{
Epoch: 123,
Root: r[:],
},
},
InclusionDelay: 123,
ProposerIndex: 123,
}
}
func justificationBits() bitfield.Bitvector4 {
v := bitfield.NewBitvector4()
v.SetBitAt(1, true)
return v
}
func checkpoint(prefix string) *ethpb.Checkpoint {
r := bytesutil.ToBytes32([]byte(prefix + "root"))
return &ethpb.Checkpoint{
Epoch: 123,
Root: r[:],
}
}
func syncCommittee(prefix string) *ethpb.SyncCommittee {
pubkeys := make([][]byte, params.BeaconConfig().SyncCommitteeSize)
for i := range pubkeys {
key := bytesutil.ToBytes48([]byte(prefix + "pubkey"))
pubkeys[i] = key[:]
}
agg := bytesutil.ToBytes48([]byte(prefix + "aggregate"))
return &ethpb.SyncCommittee{
Pubkeys: pubkeys,
AggregatePubkey: agg[:],
}
}
func executionPayloadHeader() *ethpb.ExecutionPayloadHeader {
ph := bytesutil.ToBytes32([]byte("parent"))
fr := bytesutil.PadTo([]byte("fee"), 20)
sr := bytesutil.ToBytes32([]byte("state"))
rr := bytesutil.ToBytes32([]byte("receipts"))
lb := bytesutil.PadTo([]byte("logs"), 256)
pr := bytesutil.ToBytes32([]byte("prev"))
ed := bytesutil.ToBytes32([]byte("extra"))
bf := bytesutil.ToBytes32([]byte("base"))
bh := bytesutil.ToBytes32([]byte("block"))
tr := bytesutil.ToBytes32([]byte("transactions"))
return &ethpb.ExecutionPayloadHeader{
ParentHash: ph[:],
FeeRecipient: fr,
StateRoot: sr[:],
ReceiptsRoot: rr[:],
LogsBloom: lb,
PrevRandao: pr[:],
BlockNumber: 0,
GasLimit: 0,
GasUsed: 0,
Timestamp: 0,
ExtraData: ed[:],
BaseFeePerGas: bf[:],
BlockHash: bh[:],
TransactionsRoot: tr[:],
}
}

View File

@@ -1,11 +1,13 @@
package v3
package state_native
import (
"context"
"encoding/binary"
"github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/runtime/version"
)
const (
@@ -18,19 +20,32 @@ func FinalizedRootGeneralizedIndex() uint64 {
}
// CurrentSyncCommitteeGeneralizedIndex for the beacon state.
func CurrentSyncCommitteeGeneralizedIndex() uint64 {
return uint64(currentSyncCommittee)
func (b *BeaconState) CurrentSyncCommitteeGeneralizedIndex() (uint64, error) {
if b.version == version.Phase0 {
return 0, errNotSupported("CurrentSyncCommitteeGeneralizedIndex", b.version)
}
return uint64(nativetypes.CurrentSyncCommittee.RealPosition()), nil
}
// NextSyncCommitteeGeneralizedIndex for the beacon state.
func NextSyncCommitteeGeneralizedIndex() uint64 {
return uint64(nextSyncCommittee)
func (b *BeaconState) NextSyncCommitteeGeneralizedIndex() (uint64, error) {
if b.version == version.Phase0 {
return 0, errNotSupported("NextSyncCommitteeGeneralizedIndex", b.version)
}
return uint64(nativetypes.NextSyncCommittee.RealPosition()), nil
}
// CurrentSyncCommitteeProof from the state's Merkle trie representation.
func (b *BeaconState) CurrentSyncCommitteeProof(ctx context.Context) ([][]byte, error) {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return nil, errNotSupported("CurrentSyncCommitteeProof", b.version)
}
// In case the Merkle layers of the trie are not populated, we need
// to perform some initialization.
if err := b.initializeMerkleLayers(ctx); err != nil {
@@ -41,20 +56,25 @@ func (b *BeaconState) CurrentSyncCommitteeProof(ctx context.Context) ([][]byte,
if err := b.recomputeDirtyFields(ctx); err != nil {
return nil, err
}
return fieldtrie.ProofFromMerkleLayers(b.merkleLayers, currentSyncCommittee), nil
return fieldtrie.ProofFromMerkleLayers(b.merkleLayers, nativetypes.CurrentSyncCommittee.RealPosition()), nil
}
// NextSyncCommitteeProof from the state's Merkle trie representation.
func (b *BeaconState) NextSyncCommitteeProof(ctx context.Context) ([][]byte, error) {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return nil, errNotSupported("NextSyncCommitteeProof", b.version)
}
if err := b.initializeMerkleLayers(ctx); err != nil {
return nil, err
}
if err := b.recomputeDirtyFields(ctx); err != nil {
return nil, err
}
return fieldtrie.ProofFromMerkleLayers(b.merkleLayers, nextSyncCommittee), nil
return fieldtrie.ProofFromMerkleLayers(b.merkleLayers, nativetypes.NextSyncCommittee.RealPosition()), nil
}
// FinalizedRootProof crafts a Merkle proof for the finalized root
@@ -62,13 +82,18 @@ func (b *BeaconState) NextSyncCommitteeProof(ctx context.Context) ([][]byte, err
func (b *BeaconState) FinalizedRootProof(ctx context.Context) ([][]byte, error) {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return nil, errNotSupported("FinalizedRootProof", b.version)
}
if err := b.initializeMerkleLayers(ctx); err != nil {
return nil, err
}
if err := b.recomputeDirtyFields(ctx); err != nil {
return nil, err
}
cpt := b.finalizedCheckpoint
cpt := b.finalizedCheckpointVal()
// The epoch field of a finalized checkpoint is the neighbor
// index of the finalized root field in its Merkle tree representation
// of the checkpoint. This neighbor is the first element added to the proof.
@@ -77,7 +102,7 @@ func (b *BeaconState) FinalizedRootProof(ctx context.Context) ([][]byte, error)
epochRoot := bytesutil.ToBytes32(epochBuf)
proof := make([][]byte, 0)
proof = append(proof, epochRoot[:])
branch := fieldtrie.ProofFromMerkleLayers(b.merkleLayers, finalizedCheckpoint)
branch := fieldtrie.ProofFromMerkleLayers(b.merkleLayers, nativetypes.FinalizedCheckpoint.RealPosition())
proof = append(proof, branch...)
return proof, nil
}

View File

@@ -1,10 +1,10 @@
package v1_test
package state_native_test
import (
"context"
"testing"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
statenative "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/container/trie"
"github.com/prysmaticlabs/prysm/testing/require"
"github.com/prysmaticlabs/prysm/testing/util"
@@ -27,7 +27,7 @@ func TestBeaconStateMerkleProofs(t *testing.T) {
finalizedRoot := st.FinalizedCheckpoint().Root
proof, err := st.FinalizedRootProof(ctx)
require.NoError(t, err)
gIndex := v1.FinalizedRootGeneralizedIndex()
gIndex := statenative.FinalizedRootGeneralizedIndex()
valid := trie.VerifyMerkleProof(htr[:], finalizedRoot, gIndex, proof)
require.Equal(t, true, valid)
})
@@ -51,7 +51,7 @@ func TestBeaconStateMerkleProofs(t *testing.T) {
// changed and should have been marked as a dirty state field.
// The proof validity should be false for the old root, but true for the new.
finalizedRoot := st.FinalizedCheckpoint().Root
gIndex := v1.FinalizedRootGeneralizedIndex()
gIndex := statenative.FinalizedRootGeneralizedIndex()
valid := trie.VerifyMerkleProof(currentRoot[:], finalizedRoot, gIndex, proof)
require.Equal(t, false, valid)

View File

@@ -1,4 +1,4 @@
package v1
package state_native
import (
"github.com/pkg/errors"

View File

@@ -1,9 +1,9 @@
package v1_test
package state_native_test
import (
"testing"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
statenative "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
@@ -12,63 +12,63 @@ import (
)
func TestReadOnlyValidator_ReturnsErrorOnNil(t *testing.T) {
if _, err := v1.NewValidator(nil); err != v1.ErrNilWrappedValidator {
t.Errorf("Wrong error returned. Got %v, wanted %v", err, v1.ErrNilWrappedValidator)
if _, err := statenative.NewValidator(nil); err != statenative.ErrNilWrappedValidator {
t.Errorf("Wrong error returned. Got %v, wanted %v", err, statenative.ErrNilWrappedValidator)
}
}
func TestReadOnlyValidator_EffectiveBalance(t *testing.T) {
bal := uint64(234)
v, err := v1.NewValidator(&ethpb.Validator{EffectiveBalance: bal})
v, err := statenative.NewValidator(&ethpb.Validator{EffectiveBalance: bal})
require.NoError(t, err)
assert.Equal(t, bal, v.EffectiveBalance())
}
func TestReadOnlyValidator_ActivationEligibilityEpoch(t *testing.T) {
epoch := types.Epoch(234)
v, err := v1.NewValidator(&ethpb.Validator{ActivationEligibilityEpoch: epoch})
v, err := statenative.NewValidator(&ethpb.Validator{ActivationEligibilityEpoch: epoch})
require.NoError(t, err)
assert.Equal(t, epoch, v.ActivationEligibilityEpoch())
}
func TestReadOnlyValidator_ActivationEpoch(t *testing.T) {
epoch := types.Epoch(234)
v, err := v1.NewValidator(&ethpb.Validator{ActivationEpoch: epoch})
v, err := statenative.NewValidator(&ethpb.Validator{ActivationEpoch: epoch})
require.NoError(t, err)
assert.Equal(t, epoch, v.ActivationEpoch())
}
func TestReadOnlyValidator_WithdrawableEpoch(t *testing.T) {
epoch := types.Epoch(234)
v, err := v1.NewValidator(&ethpb.Validator{WithdrawableEpoch: epoch})
v, err := statenative.NewValidator(&ethpb.Validator{WithdrawableEpoch: epoch})
require.NoError(t, err)
assert.Equal(t, epoch, v.WithdrawableEpoch())
}
func TestReadOnlyValidator_ExitEpoch(t *testing.T) {
epoch := types.Epoch(234)
v, err := v1.NewValidator(&ethpb.Validator{ExitEpoch: epoch})
v, err := statenative.NewValidator(&ethpb.Validator{ExitEpoch: epoch})
require.NoError(t, err)
assert.Equal(t, epoch, v.ExitEpoch())
}
func TestReadOnlyValidator_PublicKey(t *testing.T) {
key := [fieldparams.BLSPubkeyLength]byte{0xFA, 0xCC}
v, err := v1.NewValidator(&ethpb.Validator{PublicKey: key[:]})
v, err := statenative.NewValidator(&ethpb.Validator{PublicKey: key[:]})
require.NoError(t, err)
assert.Equal(t, key, v.PublicKey())
}
func TestReadOnlyValidator_WithdrawalCredentials(t *testing.T) {
creds := []byte{0xFA, 0xCC}
v, err := v1.NewValidator(&ethpb.Validator{WithdrawalCredentials: creds})
v, err := statenative.NewValidator(&ethpb.Validator{WithdrawalCredentials: creds})
require.NoError(t, err)
assert.DeepEqual(t, creds, v.WithdrawalCredentials())
}
func TestReadOnlyValidator_Slashed(t *testing.T) {
slashed := true
v, err := v1.NewValidator(&ethpb.Validator{Slashed: slashed})
v, err := statenative.NewValidator(&ethpb.Validator{Slashed: slashed})
require.NoError(t, err)
assert.Equal(t, slashed, v.Slashed())
}

View File

@@ -0,0 +1,715 @@
package state_native
import (
"reflect"
"runtime"
"runtime/debug"
"testing"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
)
func TestStateReferenceSharing_Finalizer_Phase0(t *testing.T) {
// This test showcases the logic on the RandaoMixes field with the GC finalizer.
s, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{RandaoMixes: [][]byte{[]byte("foo")}})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(1), a.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
func() {
// Create object in a different scope for GC
b := a.Copy()
assert.Equal(t, uint(2), a.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
_ = b
}()
runtime.GC() // Should run finalizer on object b
assert.Equal(t, uint(1), a.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(2), b.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
if b.sharedFieldReferences[nativetypes.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[nativetypes.RandaoMixes].Refs() != 1 {
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
}
}
func TestStateReferenceSharing_Finalizer_Altair(t *testing.T) {
// This test showcases the logic on the RandaoMixes field with the GC finalizer.
s, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{RandaoMixes: [][]byte{[]byte("foo")}})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(1), a.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
func() {
// Create object in a different scope for GC
b := a.Copy()
assert.Equal(t, uint(2), a.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
_ = b
}()
runtime.GC() // Should run finalizer on object b
assert.Equal(t, uint(1), a.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(2), b.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
if b.sharedFieldReferences[nativetypes.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[nativetypes.RandaoMixes].Refs() != 1 {
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
}
}
func TestStateReferenceSharing_Finalizer_Bellatrix(t *testing.T) {
// This test showcases the logic on the RandaoMixes field with the GC finalizer.
s, err := InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{RandaoMixes: [][]byte{[]byte("foo")}})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(1), a.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
func() {
// Create object in a different scope for GC
b := a.Copy()
assert.Equal(t, uint(2), a.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
_ = b
}()
runtime.GC() // Should run finalizer on object b
assert.Equal(t, uint(1), a.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(2), b.sharedFieldReferences[nativetypes.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, []byte("bar")))
if b.sharedFieldReferences[nativetypes.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[nativetypes.RandaoMixes].Refs() != 1 {
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
}
}
func TestStateReferenceCopy_NoUnexpectedRootsMutation_Phase0(t *testing.T) {
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{
BlockRoots: [][]byte{
root1[:],
},
StateRoots: [][]byte{
root1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, nativetypes.BlockRoots, 1)
assertRefCount(t, a, nativetypes.StateRoots, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, nativetypes.BlockRoots, 2)
assertRefCount(t, a, nativetypes.StateRoots, 2)
assertRefCount(t, b, nativetypes.BlockRoots, 2)
assertRefCount(t, b, nativetypes.StateRoots, 2)
// Assert shared state.
blockRootsA := a.BlockRoots()
stateRootsA := a.StateRoots()
blockRootsB := b.BlockRoots()
stateRootsB := b.StateRoots()
assertValFound(t, blockRootsA, root1[:])
assertValFound(t, blockRootsB, root1[:])
assertValFound(t, stateRootsA, root1[:])
assertValFound(t, stateRootsB, root1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateBlockRootAtIndex(0, root2))
require.NoError(t, a.UpdateStateRootAtIndex(0, root2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValNotFound(t, a.BlockRoots(), root1[:])
assertValNotFound(t, a.StateRoots(), root1[:])
assertValFound(t, a.BlockRoots(), root2[:])
assertValFound(t, a.StateRoots(), root2[:])
assertValFound(t, b.BlockRoots(), root1[:])
assertValFound(t, b.StateRoots(), root1[:])
assert.DeepEqual(t, root2[:], a.BlockRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root2[:], a.StateRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, nativetypes.BlockRoots, 1)
assertRefCount(t, a, nativetypes.StateRoots, 1)
assertRefCount(t, b, nativetypes.BlockRoots, 1)
assertRefCount(t, b, nativetypes.StateRoots, 1)
}
func TestStateReferenceCopy_NoUnexpectedRootsMutation_Altair(t *testing.T) {
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{
BlockRoots: [][]byte{
root1[:],
},
StateRoots: [][]byte{
root1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, nativetypes.BlockRoots, 1)
assertRefCount(t, a, nativetypes.StateRoots, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, nativetypes.BlockRoots, 2)
assertRefCount(t, a, nativetypes.StateRoots, 2)
assertRefCount(t, b, nativetypes.BlockRoots, 2)
assertRefCount(t, b, nativetypes.StateRoots, 2)
// Assert shared state.
blockRootsA := a.BlockRoots()
stateRootsA := a.StateRoots()
blockRootsB := b.BlockRoots()
stateRootsB := b.StateRoots()
assertValFound(t, blockRootsA, root1[:])
assertValFound(t, blockRootsB, root1[:])
assertValFound(t, stateRootsA, root1[:])
assertValFound(t, stateRootsB, root1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateBlockRootAtIndex(0, root2))
require.NoError(t, a.UpdateStateRootAtIndex(0, root2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValNotFound(t, a.BlockRoots(), root1[:])
assertValNotFound(t, a.StateRoots(), root1[:])
assertValFound(t, a.BlockRoots(), root2[:])
assertValFound(t, a.StateRoots(), root2[:])
assertValFound(t, b.BlockRoots(), root1[:])
assertValFound(t, b.StateRoots(), root1[:])
assert.DeepEqual(t, root2[:], a.BlockRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root2[:], a.StateRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, nativetypes.BlockRoots, 1)
assertRefCount(t, a, nativetypes.StateRoots, 1)
assertRefCount(t, b, nativetypes.BlockRoots, 1)
assertRefCount(t, b, nativetypes.StateRoots, 1)
}
func TestStateReferenceCopy_NoUnexpectedRootsMutation_Bellatrix(t *testing.T) {
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{
BlockRoots: [][]byte{
root1[:],
},
StateRoots: [][]byte{
root1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, nativetypes.BlockRoots, 1)
assertRefCount(t, a, nativetypes.StateRoots, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, nativetypes.BlockRoots, 2)
assertRefCount(t, a, nativetypes.StateRoots, 2)
assertRefCount(t, b, nativetypes.BlockRoots, 2)
assertRefCount(t, b, nativetypes.StateRoots, 2)
// Assert shared state.
blockRootsA := a.BlockRoots()
stateRootsA := a.StateRoots()
blockRootsB := b.BlockRoots()
stateRootsB := b.StateRoots()
assertValFound(t, blockRootsA, root1[:])
assertValFound(t, blockRootsB, root1[:])
assertValFound(t, stateRootsA, root1[:])
assertValFound(t, stateRootsB, root1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateBlockRootAtIndex(0, root2))
require.NoError(t, a.UpdateStateRootAtIndex(0, root2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValNotFound(t, a.BlockRoots(), root1[:])
assertValNotFound(t, a.StateRoots(), root1[:])
assertValFound(t, a.BlockRoots(), root2[:])
assertValFound(t, a.StateRoots(), root2[:])
assertValFound(t, b.BlockRoots(), root1[:])
assertValFound(t, b.StateRoots(), root1[:])
assert.DeepEqual(t, root2[:], a.BlockRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root2[:], a.StateRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, nativetypes.BlockRoots, 1)
assertRefCount(t, a, nativetypes.StateRoots, 1)
assertRefCount(t, b, nativetypes.BlockRoots, 1)
assertRefCount(t, b, nativetypes.StateRoots, 1)
}
func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Phase0(t *testing.T) {
val1, val2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{
RandaoMixes: [][]byte{
val1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, nativetypes.RandaoMixes, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, nativetypes.RandaoMixes, 2)
assertRefCount(t, b, nativetypes.RandaoMixes, 2)
// Assert shared state.
mixesA := a.RandaoMixes()
mixesB := b.RandaoMixes()
assertValFound(t, mixesA, val1[:])
assertValFound(t, mixesB, val1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2[:]))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValFound(t, a.RandaoMixes(), val2[:])
assertValNotFound(t, a.RandaoMixes(), val1[:])
assertValFound(t, b.RandaoMixes(), val1[:])
assertValNotFound(t, b.RandaoMixes(), val2[:])
assertValFound(t, mixesB, val1[:])
assertValNotFound(t, mixesB, val2[:])
assert.DeepEqual(t, val2[:], a.RandaoMixes()[0], "Expected mutation not found")
assert.DeepEqual(t, val1[:], mixesB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, nativetypes.RandaoMixes, 1)
assertRefCount(t, b, nativetypes.RandaoMixes, 1)
}
func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Altair(t *testing.T) {
val1, val2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{
RandaoMixes: [][]byte{
val1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, nativetypes.RandaoMixes, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, nativetypes.RandaoMixes, 2)
assertRefCount(t, b, nativetypes.RandaoMixes, 2)
// Assert shared state.
mixesA := a.RandaoMixes()
mixesB := b.RandaoMixes()
assertValFound(t, mixesA, val1[:])
assertValFound(t, mixesB, val1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2[:]))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValFound(t, a.RandaoMixes(), val2[:])
assertValNotFound(t, a.RandaoMixes(), val1[:])
assertValFound(t, b.RandaoMixes(), val1[:])
assertValNotFound(t, b.RandaoMixes(), val2[:])
assertValFound(t, mixesB, val1[:])
assertValNotFound(t, mixesB, val2[:])
assert.DeepEqual(t, val2[:], a.RandaoMixes()[0], "Expected mutation not found")
assert.DeepEqual(t, val1[:], mixesB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, nativetypes.RandaoMixes, 1)
assertRefCount(t, b, nativetypes.RandaoMixes, 1)
}
func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Bellatrix(t *testing.T) {
val1, val2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{
RandaoMixes: [][]byte{
val1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, nativetypes.RandaoMixes, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, nativetypes.RandaoMixes, 2)
assertRefCount(t, b, nativetypes.RandaoMixes, 2)
// Assert shared state.
mixesA := a.RandaoMixes()
mixesB := b.RandaoMixes()
assertValFound(t, mixesA, val1[:])
assertValFound(t, mixesB, val1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2[:]))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValFound(t, a.RandaoMixes(), val2[:])
assertValNotFound(t, a.RandaoMixes(), val1[:])
assertValFound(t, b.RandaoMixes(), val1[:])
assertValNotFound(t, b.RandaoMixes(), val2[:])
assertValFound(t, mixesB, val1[:])
assertValNotFound(t, mixesB, val2[:])
assert.DeepEqual(t, val2[:], a.RandaoMixes()[0], "Expected mutation not found")
assert.DeepEqual(t, val1[:], mixesB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, nativetypes.RandaoMixes, 1)
assertRefCount(t, b, nativetypes.RandaoMixes, 1)
}
func TestStateReferenceCopy_NoUnexpectedAttestationsMutation(t *testing.T) {
assertAttFound := func(vals []*ethpb.PendingAttestation, val uint64) {
for i := range vals {
if reflect.DeepEqual(vals[i].AggregationBits, bitfield.NewBitlist(val)) {
return
}
}
t.Log(string(debug.Stack()))
t.Fatalf("Expected attestation not found (%v), want: %v", vals, val)
}
assertAttNotFound := func(vals []*ethpb.PendingAttestation, val uint64) {
for i := range vals {
if reflect.DeepEqual(vals[i].AggregationBits, bitfield.NewBitlist(val)) {
t.Log(string(debug.Stack()))
t.Fatalf("Unexpected attestation found (%v): %v", vals, val)
return
}
}
}
s, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, nativetypes.PreviousEpochAttestations, 1)
assertRefCount(t, a, nativetypes.CurrentEpochAttestations, 1)
// Update initial state.
atts := []*ethpb.PendingAttestation{
{AggregationBits: bitfield.NewBitlist(1)},
{AggregationBits: bitfield.NewBitlist(2)},
}
a.setPreviousEpochAttestations(atts[:1])
a.setCurrentEpochAttestations(atts[:1])
curAtt, err := a.CurrentEpochAttestations()
require.NoError(t, err)
assert.Equal(t, 1, len(curAtt), "Unexpected number of attestations")
preAtt, err := a.PreviousEpochAttestations()
require.NoError(t, err)
assert.Equal(t, 1, len(preAtt), "Unexpected number of attestations")
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, nativetypes.PreviousEpochAttestations, 2)
assertRefCount(t, a, nativetypes.CurrentEpochAttestations, 2)
assertRefCount(t, b, nativetypes.PreviousEpochAttestations, 2)
assertRefCount(t, b, nativetypes.CurrentEpochAttestations, 2)
prevAtts, err := b.PreviousEpochAttestations()
require.NoError(t, err)
assert.Equal(t, 1, len(prevAtts), "Unexpected number of attestations")
currAtts, err := b.CurrentEpochAttestations()
require.NoError(t, err)
assert.Equal(t, 1, len(currAtts), "Unexpected number of attestations")
// Assert shared state.
currAttsA, err := a.CurrentEpochAttestations()
require.NoError(t, err)
prevAttsA, err := a.PreviousEpochAttestations()
require.NoError(t, err)
currAttsB, err := b.CurrentEpochAttestations()
require.NoError(t, err)
prevAttsB, err := b.PreviousEpochAttestations()
require.NoError(t, err)
if len(currAttsA) != len(currAttsB) || len(currAttsA) < 1 {
t.Errorf("Unexpected number of attestations, want: %v", 1)
}
if len(prevAttsA) != len(prevAttsB) || len(prevAttsA) < 1 {
t.Errorf("Unexpected number of attestations, want: %v", 1)
}
assertAttFound(currAttsA, 1)
assertAttFound(prevAttsA, 1)
assertAttFound(currAttsB, 1)
assertAttFound(prevAttsB, 1)
// Extend state attestations.
require.NoError(t, a.AppendCurrentEpochAttestations(atts[1]))
require.NoError(t, a.AppendPreviousEpochAttestations(atts[1]))
curAtt, err = a.CurrentEpochAttestations()
require.NoError(t, err)
assert.Equal(t, 2, len(curAtt), "Unexpected number of attestations")
preAtt, err = a.PreviousEpochAttestations()
require.NoError(t, err)
assert.Equal(t, 2, len(preAtt), "Unexpected number of attestations")
currAttsA, err = a.CurrentEpochAttestations()
require.NoError(t, err)
prevAttsA, err = a.PreviousEpochAttestations()
require.NoError(t, err)
currAttsB, err = b.CurrentEpochAttestations()
require.NoError(t, err)
prevAttsB, err = b.PreviousEpochAttestations()
require.NoError(t, err)
assertAttFound(currAttsA, 1)
assertAttFound(prevAttsA, 1)
assertAttFound(currAttsA, 2)
assertAttFound(prevAttsA, 2)
assertAttFound(currAttsB, 1)
assertAttFound(prevAttsB, 1)
assertAttNotFound(currAttsB, 2)
assertAttNotFound(prevAttsB, 2)
// Mutator should only affect calling state: a.
applyToEveryAttestation := func(state *BeaconState) {
// One MUST copy on write.
currEpochAtts, err := state.CurrentEpochAttestations()
require.NoError(t, err)
atts = make([]*ethpb.PendingAttestation, len(currEpochAtts))
copy(atts, currEpochAtts)
state.setCurrentEpochAttestations(atts)
currEpochAtts, err = state.CurrentEpochAttestations()
require.NoError(t, err)
for i := range currEpochAtts {
att := ethpb.CopyPendingAttestation(currEpochAtts[i])
att.AggregationBits = bitfield.NewBitlist(3)
currEpochAtts[i] = att
}
state.setCurrentEpochAttestations(currEpochAtts)
prevEpochAtts, err := state.PreviousEpochAttestations()
require.NoError(t, err)
atts = make([]*ethpb.PendingAttestation, len(prevEpochAtts))
copy(atts, prevEpochAtts)
state.setPreviousEpochAttestations(atts)
prevEpochAtts, err = state.PreviousEpochAttestations()
require.NoError(t, err)
for i := range prevEpochAtts {
att := ethpb.CopyPendingAttestation(prevEpochAtts[i])
att.AggregationBits = bitfield.NewBitlist(3)
prevEpochAtts[i] = att
}
state.setPreviousEpochAttestations(prevEpochAtts)
}
applyToEveryAttestation(a)
// Assert no shared state mutation occurred only on state a (copy on write).
currAttsA, err = a.CurrentEpochAttestations()
require.NoError(t, err)
prevAttsA, err = a.PreviousEpochAttestations()
require.NoError(t, err)
assertAttFound(currAttsA, 3)
assertAttFound(prevAttsA, 3)
assertAttNotFound(currAttsA, 1)
assertAttNotFound(prevAttsA, 1)
assertAttNotFound(currAttsA, 2)
assertAttNotFound(prevAttsA, 2)
// State b must be unaffected.
currAttsB, err = b.CurrentEpochAttestations()
require.NoError(t, err)
prevAttsB, err = b.PreviousEpochAttestations()
require.NoError(t, err)
assertAttNotFound(currAttsB, 3)
assertAttNotFound(prevAttsB, 3)
assertAttFound(currAttsB, 1)
assertAttFound(prevAttsB, 1)
assertAttNotFound(currAttsB, 2)
assertAttNotFound(prevAttsB, 2)
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, nativetypes.CurrentEpochAttestations, 1)
assertRefCount(t, b, nativetypes.CurrentEpochAttestations, 1)
assertRefCount(t, a, nativetypes.PreviousEpochAttestations, 1)
assertRefCount(t, b, nativetypes.PreviousEpochAttestations, 1)
}
func TestValidatorReferences_RemainsConsistent_Phase0(t *testing.T) {
s, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{
Validators: []*ethpb.Validator{
{PublicKey: []byte{'A'}},
{PublicKey: []byte{'B'}},
{PublicKey: []byte{'C'}},
{PublicKey: []byte{'D'}},
{PublicKey: []byte{'E'}},
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
// Create a second state.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
// Update First Validator.
assert.NoError(t, a.UpdateValidatorAtIndex(0, &ethpb.Validator{PublicKey: []byte{'Z'}}))
assert.DeepNotEqual(t, a.Validators()[0], b.Validators()[0], "validators are equal when they are supposed to be different")
// Modify all validators from copied state.
assert.NoError(t, b.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
return true, &ethpb.Validator{PublicKey: []byte{'V'}}, nil
}))
// Ensure reference is properly accounted for.
assert.NoError(t, a.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
assert.NotEqual(t, bytesutil.ToBytes48([]byte{'V'}), val.PublicKey())
return nil
}))
}
func TestValidatorReferences_RemainsConsistent_Altair(t *testing.T) {
s, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{
Validators: []*ethpb.Validator{
{PublicKey: []byte{'A'}},
{PublicKey: []byte{'B'}},
{PublicKey: []byte{'C'}},
{PublicKey: []byte{'D'}},
{PublicKey: []byte{'E'}},
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
// Create a second state.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
// Update First Validator.
assert.NoError(t, a.UpdateValidatorAtIndex(0, &ethpb.Validator{PublicKey: []byte{'Z'}}))
assert.DeepNotEqual(t, a.Validators()[0], b.Validators()[0], "validators are equal when they are supposed to be different")
// Modify all validators from copied state.
assert.NoError(t, b.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
return true, &ethpb.Validator{PublicKey: []byte{'V'}}, nil
}))
// Ensure reference is properly accounted for.
assert.NoError(t, a.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
assert.NotEqual(t, bytesutil.ToBytes48([]byte{'V'}), val.PublicKey())
return nil
}))
}
func TestValidatorReferences_RemainsConsistent_Bellatrix(t *testing.T) {
s, err := InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{
Validators: []*ethpb.Validator{
{PublicKey: []byte{'A'}},
{PublicKey: []byte{'B'}},
{PublicKey: []byte{'C'}},
{PublicKey: []byte{'D'}},
{PublicKey: []byte{'E'}},
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
// Create a second state.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
// Update First Validator.
assert.NoError(t, a.UpdateValidatorAtIndex(0, &ethpb.Validator{PublicKey: []byte{'Z'}}))
assert.DeepNotEqual(t, a.Validators()[0], b.Validators()[0], "validators are equal when they are supposed to be different")
// Modify all validators from copied state.
assert.NoError(t, b.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
return true, &ethpb.Validator{PublicKey: []byte{'V'}}, nil
}))
// Ensure reference is properly accounted for.
assert.NoError(t, a.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
assert.NotEqual(t, bytesutil.ToBytes48([]byte{'V'}), val.PublicKey())
return nil
}))
}
// assertRefCount checks whether reference count for a given state
// at a given index is equal to expected amount.
func assertRefCount(t *testing.T, b *BeaconState, idx nativetypes.FieldIndex, want uint) {
if cnt := b.sharedFieldReferences[idx].Refs(); cnt != want {
t.Errorf("Unexpected count of references for index %d, want: %v, got: %v", idx, want, cnt)
}
}
// assertValFound checks whether item with a given value exists in list.
func assertValFound(t *testing.T, vals [][]byte, val []byte) {
for i := range vals {
if reflect.DeepEqual(vals[i], val) {
return
}
}
t.Log(string(debug.Stack()))
t.Fatalf("Expected value not found (%v), want: %v", vals, val)
}
// assertValNotFound checks whether item with a given value doesn't exist in list.
func assertValNotFound(t *testing.T, vals [][]byte, val []byte) {
for i := range vals {
if reflect.DeepEqual(vals[i], val) {
t.Log(string(debug.Stack()))
t.Errorf("Unexpected value found (%v),: %v", vals, val)
return
}
}
}

View File

@@ -1,11 +1,13 @@
package v1
package state_native
import (
"fmt"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// RotateAttestations sets the previous epoch attestations to the current epoch attestations and
@@ -14,27 +16,31 @@ func (b *BeaconState) RotateAttestations() error {
b.lock.Lock()
defer b.lock.Unlock()
if b.version != version.Phase0 {
return errNotSupported("RotateAttestations", b.version)
}
b.setPreviousEpochAttestations(b.currentEpochAttestationsVal())
b.setCurrentEpochAttestations([]*ethpb.PendingAttestation{})
return nil
}
func (b *BeaconState) setPreviousEpochAttestations(val []*ethpb.PendingAttestation) {
b.sharedFieldReferences[previousEpochAttestations].MinusRef()
b.sharedFieldReferences[previousEpochAttestations] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.PreviousEpochAttestations].MinusRef()
b.sharedFieldReferences[nativetypes.PreviousEpochAttestations] = stateutil.NewRef(1)
b.previousEpochAttestations = val
b.markFieldAsDirty(previousEpochAttestations)
b.rebuildTrie[previousEpochAttestations] = true
b.markFieldAsDirty(nativetypes.PreviousEpochAttestations)
b.rebuildTrie[nativetypes.PreviousEpochAttestations] = true
}
func (b *BeaconState) setCurrentEpochAttestations(val []*ethpb.PendingAttestation) {
b.sharedFieldReferences[currentEpochAttestations].MinusRef()
b.sharedFieldReferences[currentEpochAttestations] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.CurrentEpochAttestations].MinusRef()
b.sharedFieldReferences[nativetypes.CurrentEpochAttestations] = stateutil.NewRef(1)
b.currentEpochAttestations = val
b.markFieldAsDirty(currentEpochAttestations)
b.rebuildTrie[currentEpochAttestations] = true
b.markFieldAsDirty(nativetypes.CurrentEpochAttestations)
b.rebuildTrie[nativetypes.CurrentEpochAttestations] = true
}
// AppendCurrentEpochAttestations for the beacon state. Appends the new value
@@ -43,23 +49,27 @@ func (b *BeaconState) AppendCurrentEpochAttestations(val *ethpb.PendingAttestati
b.lock.Lock()
defer b.lock.Unlock()
if b.version != version.Phase0 {
return errNotSupported("AppendCurrentEpochAttestations", b.version)
}
atts := b.currentEpochAttestations
max := uint64(fieldparams.CurrentEpochAttestationsLength)
if uint64(len(atts)) >= max {
return fmt.Errorf("current pending attestation exceeds max length %d", max)
}
if b.sharedFieldReferences[currentEpochAttestations].Refs() > 1 {
if b.sharedFieldReferences[nativetypes.CurrentEpochAttestations].Refs() > 1 {
// Copy elements in underlying array by reference.
atts = make([]*ethpb.PendingAttestation, len(b.currentEpochAttestations))
copy(atts, b.currentEpochAttestations)
b.sharedFieldReferences[currentEpochAttestations].MinusRef()
b.sharedFieldReferences[currentEpochAttestations] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.CurrentEpochAttestations].MinusRef()
b.sharedFieldReferences[nativetypes.CurrentEpochAttestations] = stateutil.NewRef(1)
}
b.currentEpochAttestations = append(atts, val)
b.markFieldAsDirty(currentEpochAttestations)
b.addDirtyIndices(currentEpochAttestations, []uint64{uint64(len(b.currentEpochAttestations) - 1)})
b.markFieldAsDirty(nativetypes.CurrentEpochAttestations)
b.addDirtyIndices(nativetypes.CurrentEpochAttestations, []uint64{uint64(len(b.currentEpochAttestations) - 1)})
return nil
}
@@ -69,21 +79,25 @@ func (b *BeaconState) AppendPreviousEpochAttestations(val *ethpb.PendingAttestat
b.lock.Lock()
defer b.lock.Unlock()
if b.version != version.Phase0 {
return errNotSupported("AppendPreviousEpochAttestations", b.version)
}
atts := b.previousEpochAttestations
max := uint64(fieldparams.PreviousEpochAttestationsLength)
if uint64(len(atts)) >= max {
return fmt.Errorf("previous pending attestation exceeds max length %d", max)
}
if b.sharedFieldReferences[previousEpochAttestations].Refs() > 1 {
if b.sharedFieldReferences[nativetypes.PreviousEpochAttestations].Refs() > 1 {
atts = make([]*ethpb.PendingAttestation, len(b.previousEpochAttestations))
copy(atts, b.previousEpochAttestations)
b.sharedFieldReferences[previousEpochAttestations].MinusRef()
b.sharedFieldReferences[previousEpochAttestations] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.PreviousEpochAttestations].MinusRef()
b.sharedFieldReferences[nativetypes.PreviousEpochAttestations] = stateutil.NewRef(1)
}
b.previousEpochAttestations = append(atts, val)
b.markFieldAsDirty(previousEpochAttestations)
b.addDirtyIndices(previousEpochAttestations, []uint64{uint64(len(b.previousEpochAttestations) - 1)})
b.markFieldAsDirty(nativetypes.PreviousEpochAttestations)
b.addDirtyIndices(nativetypes.PreviousEpochAttestations, []uint64{uint64(len(b.previousEpochAttestations) - 1)})
return nil
}

View File

@@ -1,4 +1,4 @@
package v1
package state_native
import (
"testing"
@@ -9,7 +9,7 @@ import (
)
func TestBeaconState_RotateAttestations(t *testing.T) {
st, err := InitializeFromProto(&ethpb.BeaconState{
st, err := InitializeFromProtoPhase0(&ethpb.BeaconState{
Slot: 1,
CurrentEpochAttestations: []*ethpb.PendingAttestation{{Data: &ethpb.AttestationData{Slot: 456}}},
PreviousEpochAttestations: []*ethpb.PendingAttestation{{Data: &ethpb.AttestationData{Slot: 123}}},
@@ -17,10 +17,8 @@ func TestBeaconState_RotateAttestations(t *testing.T) {
require.NoError(t, err)
require.NoError(t, st.RotateAttestations())
currEpochAtts, err := st.CurrentEpochAttestations()
require.NoError(t, err)
require.Equal(t, 0, len(currEpochAtts))
prevEpochAtts, err := st.PreviousEpochAttestations()
require.NoError(t, err)
require.Equal(t, types.Slot(456), prevEpochAtts[0].Data.Slot)
s, ok := st.(*BeaconState)
require.Equal(t, true, ok)
require.Equal(t, 0, len(s.currentEpochAttestationsVal()))
require.Equal(t, types.Slot(456), s.previousEpochAttestationsVal()[0].Data.Slot)
}

View File

@@ -1,9 +1,10 @@
package v1
package state_native
import (
"fmt"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
@@ -15,7 +16,7 @@ func (b *BeaconState) SetLatestBlockHeader(val *ethpb.BeaconBlockHeader) error {
defer b.lock.Unlock()
b.latestBlockHeader = ethpb.CopyBeaconBlockHeader(val)
b.markFieldAsDirty(latestBlockHeader)
b.markFieldAsDirty(nativetypes.LatestBlockHeader)
return nil
}
@@ -25,8 +26,8 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[blockRoots].MinusRef()
b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.BlockRoots].MinusRef()
b.sharedFieldReferences[nativetypes.BlockRoots] = stateutil.NewRef(1)
var rootsArr [fieldparams.BlockRootsLength][32]byte
for i := 0; i < len(rootsArr); i++ {
@@ -34,8 +35,8 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
}
roots := customtypes.BlockRoots(rootsArr)
b.blockRoots = &roots
b.markFieldAsDirty(blockRoots)
b.rebuildTrie[blockRoots] = true
b.markFieldAsDirty(nativetypes.BlockRoots)
b.rebuildTrie[nativetypes.BlockRoots] = true
return nil
}
@@ -49,19 +50,19 @@ func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) err
defer b.lock.Unlock()
r := b.blockRoots
if ref := b.sharedFieldReferences[blockRoots]; ref.Refs() > 1 {
if ref := b.sharedFieldReferences[nativetypes.BlockRoots]; ref.Refs() > 1 {
// Copy elements in underlying array by reference.
roots := *b.blockRoots
rootsCopy := roots
r = &rootsCopy
ref.MinusRef()
b.sharedFieldReferences[blockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.BlockRoots] = stateutil.NewRef(1)
}
r[idx] = blockRoot
b.blockRoots = r
b.markFieldAsDirty(blockRoots)
b.addDirtyIndices(blockRoots, []uint64{idx})
b.markFieldAsDirty(nativetypes.BlockRoots)
b.addDirtyIndices(nativetypes.BlockRoots, []uint64{idx})
return nil
}

View File

@@ -1,7 +1,8 @@
package v2
package state_native
import (
"github.com/prysmaticlabs/go-bitfield"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
@@ -11,7 +12,7 @@ func (b *BeaconState) SetJustificationBits(val bitfield.Bitvector4) error {
defer b.lock.Unlock()
b.justificationBits = val
b.markFieldAsDirty(justificationBits)
b.markFieldAsDirty(nativetypes.JustificationBits)
return nil
}
@@ -21,7 +22,7 @@ func (b *BeaconState) SetPreviousJustifiedCheckpoint(val *ethpb.Checkpoint) erro
defer b.lock.Unlock()
b.previousJustifiedCheckpoint = val
b.markFieldAsDirty(previousJustifiedCheckpoint)
b.markFieldAsDirty(nativetypes.PreviousJustifiedCheckpoint)
return nil
}
@@ -31,7 +32,7 @@ func (b *BeaconState) SetCurrentJustifiedCheckpoint(val *ethpb.Checkpoint) error
defer b.lock.Unlock()
b.currentJustifiedCheckpoint = val
b.markFieldAsDirty(currentJustifiedCheckpoint)
b.markFieldAsDirty(nativetypes.CurrentJustifiedCheckpoint)
return nil
}
@@ -41,6 +42,6 @@ func (b *BeaconState) SetFinalizedCheckpoint(val *ethpb.Checkpoint) error {
defer b.lock.Unlock()
b.finalizedCheckpoint = val
b.markFieldAsDirty(finalizedCheckpoint)
b.markFieldAsDirty(nativetypes.FinalizedCheckpoint)
return nil
}

View File

@@ -1,6 +1,7 @@
package v3
package state_native
import (
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
)
@@ -11,7 +12,7 @@ func (b *BeaconState) SetEth1Data(val *ethpb.Eth1Data) error {
defer b.lock.Unlock()
b.eth1Data = val
b.markFieldAsDirty(eth1Data)
b.markFieldAsDirty(nativetypes.Eth1Data)
return nil
}
@@ -21,12 +22,12 @@ func (b *BeaconState) SetEth1DataVotes(val []*ethpb.Eth1Data) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[eth1DataVotes].MinusRef()
b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Eth1DataVotes].MinusRef()
b.sharedFieldReferences[nativetypes.Eth1DataVotes] = stateutil.NewRef(1)
b.eth1DataVotes = val
b.markFieldAsDirty(eth1DataVotes)
b.rebuildTrie[eth1DataVotes] = true
b.markFieldAsDirty(nativetypes.Eth1DataVotes)
b.rebuildTrie[nativetypes.Eth1DataVotes] = true
return nil
}
@@ -36,7 +37,7 @@ func (b *BeaconState) SetEth1DepositIndex(val uint64) error {
defer b.lock.Unlock()
b.eth1DepositIndex = val
b.markFieldAsDirty(eth1DepositIndex)
b.markFieldAsDirty(nativetypes.Eth1DepositIndex)
return nil
}
@@ -47,16 +48,16 @@ func (b *BeaconState) AppendEth1DataVotes(val *ethpb.Eth1Data) error {
defer b.lock.Unlock()
votes := b.eth1DataVotes
if b.sharedFieldReferences[eth1DataVotes].Refs() > 1 {
if b.sharedFieldReferences[nativetypes.Eth1DataVotes].Refs() > 1 {
// Copy elements in underlying array by reference.
votes = make([]*ethpb.Eth1Data, len(b.eth1DataVotes))
copy(votes, b.eth1DataVotes)
b.sharedFieldReferences[eth1DataVotes].MinusRef()
b.sharedFieldReferences[eth1DataVotes] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Eth1DataVotes].MinusRef()
b.sharedFieldReferences[nativetypes.Eth1DataVotes] = stateutil.NewRef(1)
}
b.eth1DataVotes = append(votes, val)
b.markFieldAsDirty(eth1DataVotes)
b.addDirtyIndices(eth1DataVotes, []uint64{uint64(len(b.eth1DataVotes) - 1)})
b.markFieldAsDirty(nativetypes.Eth1DataVotes)
b.addDirtyIndices(nativetypes.Eth1DataVotes, []uint64{uint64(len(b.eth1DataVotes) - 1)})
return nil
}

View File

@@ -1,9 +1,9 @@
package v1
package state_native
import (
"github.com/pkg/errors"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
stateTypes "github.com/prysmaticlabs/prysm/beacon-chain/state/types"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/crypto/hash"
@@ -46,7 +46,7 @@ func (b *BeaconState) SetGenesisTime(val uint64) error {
defer b.lock.Unlock()
b.genesisTime = val
b.markFieldAsDirty(genesisTime)
b.markFieldAsDirty(nativetypes.GenesisTime)
return nil
}
@@ -59,7 +59,7 @@ func (b *BeaconState) SetGenesisValidatorsRoot(val []byte) error {
return errors.New("incorrect validators root length")
}
b.genesisValidatorsRoot = bytesutil.ToBytes32(val)
b.markFieldAsDirty(genesisValidatorsRoot)
b.markFieldAsDirty(nativetypes.GenesisValidatorsRoot)
return nil
}
@@ -69,7 +69,7 @@ func (b *BeaconState) SetSlot(val types.Slot) error {
defer b.lock.Unlock()
b.slot = val
b.markFieldAsDirty(slot)
b.markFieldAsDirty(nativetypes.Slot)
return nil
}
@@ -83,7 +83,7 @@ func (b *BeaconState) SetFork(val *ethpb.Fork) error {
return errors.New("proto.Clone did not return a fork proto")
}
b.fork = fk
b.markFieldAsDirty(fork)
b.markFieldAsDirty(nativetypes.Fork)
return nil
}
@@ -93,15 +93,15 @@ func (b *BeaconState) SetHistoricalRoots(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[historicalRoots].MinusRef()
b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.HistoricalRoots].MinusRef()
b.sharedFieldReferences[nativetypes.HistoricalRoots] = stateutil.NewRef(1)
roots := make([][32]byte, len(val))
for i, r := range val {
copy(roots[i][:], r)
}
b.historicalRoots = roots
b.markFieldAsDirty(historicalRoots)
b.markFieldAsDirty(nativetypes.HistoricalRoots)
return nil
}
@@ -112,15 +112,15 @@ func (b *BeaconState) AppendHistoricalRoots(root [32]byte) error {
defer b.lock.Unlock()
roots := b.historicalRoots
if b.sharedFieldReferences[historicalRoots].Refs() > 1 {
if b.sharedFieldReferences[nativetypes.HistoricalRoots].Refs() > 1 {
roots = make([][32]byte, len(b.historicalRoots))
copy(roots, b.historicalRoots)
b.sharedFieldReferences[historicalRoots].MinusRef()
b.sharedFieldReferences[historicalRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.HistoricalRoots].MinusRef()
b.sharedFieldReferences[nativetypes.HistoricalRoots] = stateutil.NewRef(1)
}
b.historicalRoots = append(roots, root)
b.markFieldAsDirty(historicalRoots)
b.markFieldAsDirty(nativetypes.HistoricalRoots)
return nil
}
@@ -159,13 +159,13 @@ func (b *BeaconState) recomputeRoot(idx int) {
b.merkleLayers = layers
}
func (b *BeaconState) markFieldAsDirty(field stateTypes.FieldIndex) {
func (b *BeaconState) markFieldAsDirty(field nativetypes.FieldIndex) {
b.dirtyFields[field] = true
}
// addDirtyIndices adds the relevant dirty field indices, so that they
// can be recomputed.
func (b *BeaconState) addDirtyIndices(index stateTypes.FieldIndex, indices []uint64) {
func (b *BeaconState) addDirtyIndices(index nativetypes.FieldIndex, indices []uint64) {
if b.rebuildTrie[index] {
return
}

View File

@@ -0,0 +1,165 @@
package state_native
import (
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// SetPreviousParticipationBits for the beacon state. Updates the entire
// list to a new value by overwriting the previous one.
func (b *BeaconState) SetPreviousParticipationBits(val []byte) error {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return errNotSupported("SetPreviousParticipationBits", b.version)
}
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits].MinusRef()
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits] = stateutil.NewRef(1)
b.previousEpochParticipation = val
b.markFieldAsDirty(nativetypes.PreviousEpochParticipationBits)
b.rebuildTrie[nativetypes.PreviousEpochParticipationBits] = true
return nil
}
// SetCurrentParticipationBits for the beacon state. Updates the entire
// list to a new value by overwriting the previous one.
func (b *BeaconState) SetCurrentParticipationBits(val []byte) error {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return errNotSupported("SetCurrentParticipationBits", b.version)
}
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits].MinusRef()
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits] = stateutil.NewRef(1)
b.currentEpochParticipation = val
b.markFieldAsDirty(nativetypes.CurrentEpochParticipationBits)
b.rebuildTrie[nativetypes.CurrentEpochParticipationBits] = true
return nil
}
// AppendCurrentParticipationBits for the beacon state. Appends the new value
// to the the end of list.
func (b *BeaconState) AppendCurrentParticipationBits(val byte) error {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return errNotSupported("AppendCurrentParticipationBits", b.version)
}
participation := b.currentEpochParticipation
if b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits].Refs() > 1 {
// Copy elements in underlying array by reference.
participation = make([]byte, len(b.currentEpochParticipation))
copy(participation, b.currentEpochParticipation)
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits].MinusRef()
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits] = stateutil.NewRef(1)
}
b.currentEpochParticipation = append(participation, val)
b.markFieldAsDirty(nativetypes.CurrentEpochParticipationBits)
b.addDirtyIndices(nativetypes.CurrentEpochParticipationBits, []uint64{uint64(len(b.currentEpochParticipation) - 1)})
return nil
}
// AppendPreviousParticipationBits for the beacon state. Appends the new value
// to the the end of list.
func (b *BeaconState) AppendPreviousParticipationBits(val byte) error {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return errNotSupported("AppendPreviousParticipationBits", b.version)
}
bits := b.previousEpochParticipation
if b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits].Refs() > 1 {
bits = make([]byte, len(b.previousEpochParticipation))
copy(bits, b.previousEpochParticipation)
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits].MinusRef()
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits] = stateutil.NewRef(1)
}
b.previousEpochParticipation = append(bits, val)
b.markFieldAsDirty(nativetypes.PreviousEpochParticipationBits)
b.addDirtyIndices(nativetypes.PreviousEpochParticipationBits, []uint64{uint64(len(b.previousEpochParticipation) - 1)})
return nil
}
// ModifyPreviousParticipationBits modifies the previous participation bitfield via
// the provided mutator function.
func (b *BeaconState) ModifyPreviousParticipationBits(mutator func(val []byte) ([]byte, error)) error {
b.lock.Lock()
if b.version == version.Phase0 {
b.lock.Unlock()
return errNotSupported("ModifyPreviousParticipationBits", b.version)
}
participation := b.previousEpochParticipation
if b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits].Refs() > 1 {
// Copy elements in underlying array by reference.
participation = make([]byte, len(b.previousEpochParticipation))
copy(participation, b.previousEpochParticipation)
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits].MinusRef()
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits] = stateutil.NewRef(1)
}
// Lock is released so that mutator can
// acquire it.
b.lock.Unlock()
var err error
participation, err = mutator(participation)
if err != nil {
return err
}
b.lock.Lock()
defer b.lock.Unlock()
b.previousEpochParticipation = participation
b.markFieldAsDirty(nativetypes.PreviousEpochParticipationBits)
b.rebuildTrie[nativetypes.PreviousEpochParticipationBits] = true
return nil
}
// ModifyCurrentParticipationBits modifies the current participation bitfield via
// the provided mutator function.
func (b *BeaconState) ModifyCurrentParticipationBits(mutator func(val []byte) ([]byte, error)) error {
b.lock.Lock()
if b.version == version.Phase0 {
b.lock.Unlock()
return errNotSupported("ModifyCurrentParticipationBits", b.version)
}
participation := b.currentEpochParticipation
if b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits].Refs() > 1 {
// Copy elements in underlying array by reference.
participation = make([]byte, len(b.currentEpochParticipation))
copy(participation, b.currentEpochParticipation)
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits].MinusRef()
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits] = stateutil.NewRef(1)
}
// Lock is released so that mutator can
// acquire it.
b.lock.Unlock()
var err error
participation, err = mutator(participation)
if err != nil {
return err
}
b.lock.Lock()
defer b.lock.Unlock()
b.currentEpochParticipation = participation
b.markFieldAsDirty(nativetypes.CurrentEpochParticipationBits)
b.rebuildTrie[nativetypes.CurrentEpochParticipationBits] = true
return nil
}

View File

@@ -0,0 +1,21 @@
package state_native
import (
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// SetLatestExecutionPayloadHeader for the beacon state.
func (b *BeaconState) SetLatestExecutionPayloadHeader(val *ethpb.ExecutionPayloadHeader) error {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 || b.version == version.Altair {
return errNotSupported("SetLatestExecutionPayloadHeader", b.version)
}
b.latestExecutionPayloadHeader = val
b.markFieldAsDirty(nativetypes.LatestExecutionPayloadHeader)
return nil
}

View File

@@ -1,8 +1,9 @@
package v1
package state_native
import (
"github.com/pkg/errors"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
@@ -14,8 +15,8 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[randaoMixes].MinusRef()
b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.RandaoMixes].MinusRef()
b.sharedFieldReferences[nativetypes.RandaoMixes] = stateutil.NewRef(1)
var mixesArr [fieldparams.RandaoMixesLength][32]byte
for i := 0; i < len(mixesArr); i++ {
@@ -23,8 +24,8 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
}
mixes := customtypes.RandaoMixes(mixesArr)
b.randaoMixes = &mixes
b.markFieldAsDirty(randaoMixes)
b.rebuildTrie[randaoMixes] = true
b.markFieldAsDirty(nativetypes.RandaoMixes)
b.rebuildTrie[nativetypes.RandaoMixes] = true
return nil
}
@@ -38,19 +39,19 @@ func (b *BeaconState) UpdateRandaoMixesAtIndex(idx uint64, val []byte) error {
defer b.lock.Unlock()
mixes := b.randaoMixes
if refs := b.sharedFieldReferences[randaoMixes].Refs(); refs > 1 {
if refs := b.sharedFieldReferences[nativetypes.RandaoMixes].Refs(); refs > 1 {
// Copy elements in underlying array by reference.
m := *b.randaoMixes
mCopy := m
mixes = &mCopy
b.sharedFieldReferences[randaoMixes].MinusRef()
b.sharedFieldReferences[randaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.RandaoMixes].MinusRef()
b.sharedFieldReferences[nativetypes.RandaoMixes] = stateutil.NewRef(1)
}
mixes[idx] = bytesutil.ToBytes32(val)
b.randaoMixes = mixes
b.markFieldAsDirty(randaoMixes)
b.addDirtyIndices(randaoMixes, []uint64{idx})
b.markFieldAsDirty(nativetypes.RandaoMixes)
b.addDirtyIndices(nativetypes.RandaoMixes, []uint64{idx})
return nil
}

View File

@@ -1,8 +1,9 @@
package v1
package state_native
import (
"github.com/pkg/errors"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
)
@@ -13,8 +14,8 @@ func (b *BeaconState) SetStateRoots(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[stateRoots].MinusRef()
b.sharedFieldReferences[stateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.StateRoots].MinusRef()
b.sharedFieldReferences[nativetypes.StateRoots] = stateutil.NewRef(1)
var rootsArr [fieldparams.StateRootsLength][32]byte
for i := 0; i < len(rootsArr); i++ {
@@ -22,8 +23,8 @@ func (b *BeaconState) SetStateRoots(val [][]byte) error {
}
roots := customtypes.StateRoots(rootsArr)
b.stateRoots = &roots
b.markFieldAsDirty(stateRoots)
b.rebuildTrie[stateRoots] = true
b.markFieldAsDirty(nativetypes.StateRoots)
b.rebuildTrie[nativetypes.StateRoots] = true
return nil
}
@@ -42,19 +43,19 @@ func (b *BeaconState) UpdateStateRootAtIndex(idx uint64, stateRoot [32]byte) err
// Check if we hold the only reference to the shared state roots slice.
r := b.stateRoots
if ref := b.sharedFieldReferences[stateRoots]; ref.Refs() > 1 {
if ref := b.sharedFieldReferences[nativetypes.StateRoots]; ref.Refs() > 1 {
// Copy elements in underlying array by reference.
roots := *b.stateRoots
rootsCopy := roots
r = &rootsCopy
ref.MinusRef()
b.sharedFieldReferences[stateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.StateRoots] = stateutil.NewRef(1)
}
r[idx] = stateRoot
b.stateRoots = r
b.markFieldAsDirty(stateRoots)
b.addDirtyIndices(stateRoots, []uint64{idx})
b.markFieldAsDirty(nativetypes.StateRoots)
b.addDirtyIndices(nativetypes.StateRoots, []uint64{idx})
return nil
}

View File

@@ -1,7 +1,9 @@
package v3
package state_native
import (
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// SetCurrentSyncCommittee for the beacon state.
@@ -9,8 +11,12 @@ func (b *BeaconState) SetCurrentSyncCommittee(val *ethpb.SyncCommittee) error {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return errNotSupported("SetCurrentSyncCommittee", b.version)
}
b.currentSyncCommittee = val
b.markFieldAsDirty(currentSyncCommittee)
b.markFieldAsDirty(nativetypes.CurrentSyncCommittee)
return nil
}
@@ -19,7 +25,11 @@ func (b *BeaconState) SetNextSyncCommittee(val *ethpb.SyncCommittee) error {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return errNotSupported("SetNextSyncCommittee", b.version)
}
b.nextSyncCommittee = val
b.markFieldAsDirty(nextSyncCommittee)
b.markFieldAsDirty(nativetypes.NextSyncCommittee)
return nil
}

View File

@@ -1,11 +1,13 @@
package v3
package state_native
import (
"github.com/pkg/errors"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// SetValidators for the beacon state. Updates the entire
@@ -15,10 +17,10 @@ func (b *BeaconState) SetValidators(val []*ethpb.Validator) error {
defer b.lock.Unlock()
b.validators = val
b.sharedFieldReferences[validators].MinusRef()
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
b.markFieldAsDirty(validators)
b.rebuildTrie[validators] = true
b.sharedFieldReferences[nativetypes.Validators].MinusRef()
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
b.markFieldAsDirty(nativetypes.Validators)
b.rebuildTrie[nativetypes.Validators] = true
b.valMapHandler = stateutil.NewValMapHandler(b.validators)
return nil
}
@@ -28,10 +30,10 @@ func (b *BeaconState) SetValidators(val []*ethpb.Validator) error {
func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error)) error {
b.lock.Lock()
v := b.validators
if ref := b.sharedFieldReferences[validators]; ref.Refs() > 1 {
if ref := b.sharedFieldReferences[nativetypes.Validators]; ref.Refs() > 1 {
v = b.validatorsReferences()
ref.MinusRef()
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
}
b.lock.Unlock()
var changedVals []uint64
@@ -50,8 +52,8 @@ func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val *ethpb.Validator
defer b.lock.Unlock()
b.validators = v
b.markFieldAsDirty(validators)
b.addDirtyIndices(validators, changedVals)
b.markFieldAsDirty(nativetypes.Validators)
b.addDirtyIndices(nativetypes.Validators, changedVals)
return nil
}
@@ -66,16 +68,16 @@ func (b *BeaconState) UpdateValidatorAtIndex(idx types.ValidatorIndex, val *ethp
defer b.lock.Unlock()
v := b.validators
if ref := b.sharedFieldReferences[validators]; ref.Refs() > 1 {
if ref := b.sharedFieldReferences[nativetypes.Validators]; ref.Refs() > 1 {
v = b.validatorsReferences()
ref.MinusRef()
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
}
v[idx] = val
b.validators = v
b.markFieldAsDirty(validators)
b.addDirtyIndices(validators, []uint64{uint64(idx)})
b.markFieldAsDirty(nativetypes.Validators)
b.addDirtyIndices(nativetypes.Validators, []uint64{uint64(idx)})
return nil
}
@@ -86,12 +88,12 @@ func (b *BeaconState) SetBalances(val []uint64) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[balances].MinusRef()
b.sharedFieldReferences[balances] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Balances].MinusRef()
b.sharedFieldReferences[nativetypes.Balances] = stateutil.NewRef(1)
b.balances = val
b.markFieldAsDirty(balances)
b.rebuildTrie[balances] = true
b.markFieldAsDirty(nativetypes.Balances)
b.rebuildTrie[nativetypes.Balances] = true
return nil
}
@@ -105,16 +107,16 @@ func (b *BeaconState) UpdateBalancesAtIndex(idx types.ValidatorIndex, val uint64
defer b.lock.Unlock()
bals := b.balances
if b.sharedFieldReferences[balances].Refs() > 1 {
if b.sharedFieldReferences[nativetypes.Balances].Refs() > 1 {
bals = b.balancesVal()
b.sharedFieldReferences[balances].MinusRef()
b.sharedFieldReferences[balances] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Balances].MinusRef()
b.sharedFieldReferences[nativetypes.Balances] = stateutil.NewRef(1)
}
bals[idx] = val
b.balances = bals
b.markFieldAsDirty(balances)
b.addDirtyIndices(balances, []uint64{uint64(idx)})
b.markFieldAsDirty(nativetypes.Balances)
b.addDirtyIndices(nativetypes.Balances, []uint64{uint64(idx)})
return nil
}
@@ -124,11 +126,11 @@ func (b *BeaconState) SetSlashings(val []uint64) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[slashings].MinusRef()
b.sharedFieldReferences[slashings] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Slashings].MinusRef()
b.sharedFieldReferences[nativetypes.Slashings] = stateutil.NewRef(1)
b.slashings = val
b.markFieldAsDirty(slashings)
b.markFieldAsDirty(nativetypes.Slashings)
return nil
}
@@ -142,17 +144,17 @@ func (b *BeaconState) UpdateSlashingsAtIndex(idx, val uint64) error {
defer b.lock.Unlock()
s := b.slashings
if b.sharedFieldReferences[slashings].Refs() > 1 {
if b.sharedFieldReferences[nativetypes.Slashings].Refs() > 1 {
s = b.slashingsVal()
b.sharedFieldReferences[slashings].MinusRef()
b.sharedFieldReferences[slashings] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Slashings].MinusRef()
b.sharedFieldReferences[nativetypes.Slashings] = stateutil.NewRef(1)
}
s[idx] = val
b.slashings = s
b.markFieldAsDirty(slashings)
b.markFieldAsDirty(nativetypes.Slashings)
return nil
}
@@ -163,10 +165,10 @@ func (b *BeaconState) AppendValidator(val *ethpb.Validator) error {
defer b.lock.Unlock()
vals := b.validators
if b.sharedFieldReferences[validators].Refs() > 1 {
if b.sharedFieldReferences[nativetypes.Validators].Refs() > 1 {
vals = b.validatorsReferences()
b.sharedFieldReferences[validators].MinusRef()
b.sharedFieldReferences[validators] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Validators].MinusRef()
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
}
// append validator to slice
@@ -175,8 +177,8 @@ func (b *BeaconState) AppendValidator(val *ethpb.Validator) error {
b.valMapHandler.Set(bytesutil.ToBytes48(val.PublicKey), valIdx)
b.markFieldAsDirty(validators)
b.addDirtyIndices(validators, []uint64{uint64(valIdx)})
b.markFieldAsDirty(nativetypes.Validators)
b.addDirtyIndices(nativetypes.Validators, []uint64{uint64(valIdx)})
return nil
}
@@ -187,16 +189,16 @@ func (b *BeaconState) AppendBalance(bal uint64) error {
defer b.lock.Unlock()
bals := b.balances
if b.sharedFieldReferences[balances].Refs() > 1 {
if b.sharedFieldReferences[nativetypes.Balances].Refs() > 1 {
bals = b.balancesVal()
b.sharedFieldReferences[balances].MinusRef()
b.sharedFieldReferences[balances] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Balances].MinusRef()
b.sharedFieldReferences[nativetypes.Balances] = stateutil.NewRef(1)
}
b.balances = append(bals, bal)
balIdx := len(b.balances) - 1
b.markFieldAsDirty(balances)
b.addDirtyIndices(balances, []uint64{uint64(balIdx)})
b.markFieldAsDirty(nativetypes.Balances)
b.addDirtyIndices(nativetypes.Balances, []uint64{uint64(balIdx)})
return nil
}
@@ -205,15 +207,19 @@ func (b *BeaconState) AppendInactivityScore(s uint64) error {
b.lock.Lock()
defer b.lock.Unlock()
if b.version == version.Phase0 {
return errNotSupported("AppendInactivityScore", b.version)
}
scores := b.inactivityScores
if b.sharedFieldReferences[inactivityScores].Refs() > 1 {
if b.sharedFieldReferences[nativetypes.InactivityScores].Refs() > 1 {
scores = b.inactivityScoresVal()
b.sharedFieldReferences[inactivityScores].MinusRef()
b.sharedFieldReferences[inactivityScores] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.InactivityScores].MinusRef()
b.sharedFieldReferences[nativetypes.InactivityScores] = stateutil.NewRef(1)
}
b.inactivityScores = append(scores, s)
b.markFieldAsDirty(inactivityScores)
b.markFieldAsDirty(nativetypes.InactivityScores)
return nil
}
@@ -223,10 +229,14 @@ func (b *BeaconState) SetInactivityScores(val []uint64) error {
b.lock.Lock()
defer b.lock.Unlock()
b.sharedFieldReferences[inactivityScores].MinusRef()
b.sharedFieldReferences[inactivityScores] = stateutil.NewRef(1)
if b.version == version.Phase0 {
return errNotSupported("SetInactivityScores", b.version)
}
b.sharedFieldReferences[nativetypes.InactivityScores].MinusRef()
b.sharedFieldReferences[nativetypes.InactivityScores] = stateutil.NewRef(1)
b.inactivityScores = val
b.markFieldAsDirty(inactivityScores)
b.markFieldAsDirty(nativetypes.InactivityScores)
return nil
}

View File

@@ -0,0 +1,36 @@
package state_native
import (
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
)
var errAssertionFailed = errors.New("failed to convert interface to proto state")
var errUnsupportedVersion = errors.New("unsupported beacon state version")
func (b *BeaconState) MarshalSSZ() ([]byte, error) {
proto := b.ToProto()
switch b.Version() {
case version.Phase0:
s, ok := proto.(*ethpb.BeaconState)
if !ok {
return nil, errAssertionFailed
}
return s.MarshalSSZ()
case version.Altair:
s, ok := proto.(*ethpb.BeaconStateAltair)
if !ok {
return nil, errAssertionFailed
}
return s.MarshalSSZ()
case version.Bellatrix:
s, ok := proto.(*ethpb.BeaconStateBellatrix)
if !ok {
return nil, errAssertionFailed
}
return s.MarshalSSZ()
default:
return nil, errUnsupportedVersion
}
}

View File

@@ -1,4 +1,4 @@
package v1
package state_native
import (
"context"
@@ -7,6 +7,7 @@ import (
"testing"
"github.com/prysmaticlabs/go-bitfield"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
@@ -45,7 +46,7 @@ func TestValidatorMap_DistinctCopy(t *testing.T) {
assert.NotEqual(t, val1, val2, "Values are supposed to be unequal due to copy")
}
func TestBeaconState_NoDeadlock(t *testing.T) {
func TestBeaconState_NoDeadlock_Phase0(t *testing.T) {
count := uint64(100)
vals := make([]*ethpb.Validator, 0, count)
for i := uint64(1); i < count; i++ {
@@ -64,7 +65,63 @@ func TestBeaconState_NoDeadlock(t *testing.T) {
WithdrawableEpoch: 1,
})
}
st, err := InitializeFromProtoUnsafe(&ethpb.BeaconState{
newState, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{
Validators: vals,
})
assert.NoError(t, err)
st, ok := newState.(*BeaconState)
require.Equal(t, true, ok)
wg := new(sync.WaitGroup)
wg.Add(1)
go func() {
// Continuously lock and unlock the state
// by acquiring the lock.
for i := 0; i < 1000; i++ {
for _, f := range st.stateFieldLeaves {
f.Lock()
if f.Empty() {
f.InsertFieldLayer(make([][]*[32]byte, 10))
}
f.Unlock()
f.FieldReference().AddRef()
}
}
wg.Done()
}()
// Constantly read from the offending portion
// of the code to ensure there is no possible
// recursive read locking.
for i := 0; i < 1000; i++ {
go func() {
_ = st.FieldReferencesCount()
}()
}
// Test will not terminate in the event of a deadlock.
wg.Wait()
}
func TestBeaconState_NoDeadlock_Altair(t *testing.T) {
count := uint64(100)
vals := make([]*ethpb.Validator, 0, count)
for i := uint64(1); i < count; i++ {
someRoot := [32]byte{}
someKey := [fieldparams.BLSPubkeyLength]byte{}
copy(someRoot[:], strconv.Itoa(int(i)))
copy(someKey[:], strconv.Itoa(int(i)))
vals = append(vals, &ethpb.Validator{
PublicKey: someKey[:],
WithdrawalCredentials: someRoot[:],
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
Slashed: false,
ActivationEligibilityEpoch: 1,
ActivationEpoch: 1,
ExitEpoch: 1,
WithdrawableEpoch: 1,
})
}
st, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{
Validators: vals,
})
assert.NoError(t, err)
@@ -101,9 +158,60 @@ func TestBeaconState_NoDeadlock(t *testing.T) {
wg.Wait()
}
func TestStateTrie_IsNil(t *testing.T) {
var emptyState *BeaconState
assert.Equal(t, true, emptyState.IsNil())
func TestBeaconState_NoDeadlock_Bellatrix(t *testing.T) {
count := uint64(100)
vals := make([]*ethpb.Validator, 0, count)
for i := uint64(1); i < count; i++ {
someRoot := [32]byte{}
someKey := [fieldparams.BLSPubkeyLength]byte{}
copy(someRoot[:], strconv.Itoa(int(i)))
copy(someKey[:], strconv.Itoa(int(i)))
vals = append(vals, &ethpb.Validator{
PublicKey: someKey[:],
WithdrawalCredentials: someRoot[:],
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
Slashed: false,
ActivationEligibilityEpoch: 1,
ActivationEpoch: 1,
ExitEpoch: 1,
WithdrawableEpoch: 1,
})
}
st, err := InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{
Validators: vals,
})
assert.NoError(t, err)
s, ok := st.(*BeaconState)
require.Equal(t, true, ok)
wg := new(sync.WaitGroup)
wg.Add(1)
go func() {
// Continuously lock and unlock the state
// by acquiring the lock.
for i := 0; i < 1000; i++ {
for _, f := range s.stateFieldLeaves {
f.Lock()
if f.Empty() {
f.InsertFieldLayer(make([][]*[32]byte, 10))
}
f.Unlock()
f.FieldReference().AddRef()
}
}
wg.Done()
}()
// Constantly read from the offending portion
// of the code to ensure there is no possible
// recursive read locking.
for i := 0; i < 1000; i++ {
go func() {
_ = st.FieldReferencesCount()
}()
}
// Test will not terminate in the event of a deadlock.
wg.Wait()
}
func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
@@ -141,7 +249,7 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
for i := 0; i < len(mockrandaoMixes); i++ {
mockrandaoMixes[i] = zeroHash[:]
}
st, err := InitializeFromProto(&ethpb.BeaconState{
newState, err := InitializeFromProtoPhase0(&ethpb.BeaconState{
Slot: 1,
GenesisValidatorsRoot: make([]byte, 32),
Fork: &ethpb.Fork{
@@ -170,6 +278,8 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
})
assert.NoError(t, err)
st, ok := newState.(*BeaconState)
require.Equal(t, true, ok)
_, err = st.HashTreeRoot(context.Background())
assert.NoError(t, err)
@@ -183,26 +293,24 @@ func TestBeaconState_AppendBalanceWithTrie(t *testing.T) {
}
_, err = st.HashTreeRoot(context.Background())
assert.NoError(t, err)
s, ok := st.(*BeaconState)
require.Equal(t, true, ok)
newRt := bytesutil.ToBytes32(s.merkleLayers[0][balances])
wantedRt, err := stateutil.Uint64ListRootWithRegistryLimit(s.Balances())
newRt := bytesutil.ToBytes32(st.merkleLayers[0][nativetypes.Balances])
wantedRt, err := stateutil.Uint64ListRootWithRegistryLimit(st.Balances())
assert.NoError(t, err)
assert.Equal(t, wantedRt, newRt, "state roots are unequal")
}
func TestBeaconState_ModifyPreviousParticipationBits(t *testing.T) {
st, err := InitializeFromProtoUnsafe(&ethpb.BeaconState{})
st, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{})
assert.NoError(t, err)
assert.ErrorContains(t, "ModifyPreviousParticipationBits is not supported for phase 0 beacon state", st.ModifyPreviousParticipationBits(func(val []byte) ([]byte, error) {
assert.ErrorContains(t, "ModifyPreviousParticipationBits is not supported", st.ModifyPreviousParticipationBits(func(val []byte) ([]byte, error) {
return nil, nil
}))
}
func TestBeaconState_ModifyCurrentParticipationBits(t *testing.T) {
st, err := InitializeFromProtoUnsafe(&ethpb.BeaconState{})
st, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{})
assert.NoError(t, err)
assert.ErrorContains(t, "ModifyCurrentParticipationBits is not supported for phase 0 beacon state", st.ModifyCurrentParticipationBits(func(val []byte) ([]byte, error) {
assert.ErrorContains(t, "ModifyCurrentParticipationBits is not supported", st.ModifyCurrentParticipationBits(func(val []byte) ([]byte, error) {
return nil, nil
}))
}

View File

@@ -0,0 +1,792 @@
package state_native
import (
"context"
"runtime"
"sort"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie"
customtypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/custom-types"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/container/slice"
"github.com/prysmaticlabs/prysm/crypto/hash"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/encoding/ssz"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/runtime/version"
"go.opencensus.io/trace"
"google.golang.org/protobuf/proto"
)
var phase0Fields = []nativetypes.FieldIndex{
nativetypes.GenesisTime,
nativetypes.GenesisValidatorsRoot,
nativetypes.Slot,
nativetypes.Fork,
nativetypes.LatestBlockHeader,
nativetypes.BlockRoots,
nativetypes.StateRoots,
nativetypes.HistoricalRoots,
nativetypes.Eth1Data,
nativetypes.Eth1DataVotes,
nativetypes.Eth1DepositIndex,
nativetypes.Validators,
nativetypes.Balances,
nativetypes.RandaoMixes,
nativetypes.Slashings,
nativetypes.PreviousEpochAttestations,
nativetypes.CurrentEpochAttestations,
nativetypes.JustificationBits,
nativetypes.PreviousJustifiedCheckpoint,
nativetypes.CurrentJustifiedCheckpoint,
nativetypes.FinalizedCheckpoint,
}
var altairFields = []nativetypes.FieldIndex{
nativetypes.GenesisTime,
nativetypes.GenesisValidatorsRoot,
nativetypes.Slot,
nativetypes.Fork,
nativetypes.LatestBlockHeader,
nativetypes.BlockRoots,
nativetypes.StateRoots,
nativetypes.HistoricalRoots,
nativetypes.Eth1Data,
nativetypes.Eth1DataVotes,
nativetypes.Eth1DepositIndex,
nativetypes.Validators,
nativetypes.Balances,
nativetypes.RandaoMixes,
nativetypes.Slashings,
nativetypes.PreviousEpochParticipationBits,
nativetypes.CurrentEpochParticipationBits,
nativetypes.JustificationBits,
nativetypes.PreviousJustifiedCheckpoint,
nativetypes.CurrentJustifiedCheckpoint,
nativetypes.FinalizedCheckpoint,
nativetypes.InactivityScores,
nativetypes.CurrentSyncCommittee,
nativetypes.NextSyncCommittee,
}
var bellatrixFields = []nativetypes.FieldIndex{
nativetypes.GenesisTime,
nativetypes.GenesisValidatorsRoot,
nativetypes.Slot,
nativetypes.Fork,
nativetypes.LatestBlockHeader,
nativetypes.BlockRoots,
nativetypes.StateRoots,
nativetypes.HistoricalRoots,
nativetypes.Eth1Data,
nativetypes.Eth1DataVotes,
nativetypes.Eth1DepositIndex,
nativetypes.Validators,
nativetypes.Balances,
nativetypes.RandaoMixes,
nativetypes.Slashings,
nativetypes.PreviousEpochParticipationBits,
nativetypes.CurrentEpochParticipationBits,
nativetypes.JustificationBits,
nativetypes.PreviousJustifiedCheckpoint,
nativetypes.CurrentJustifiedCheckpoint,
nativetypes.FinalizedCheckpoint,
nativetypes.InactivityScores,
nativetypes.CurrentSyncCommittee,
nativetypes.NextSyncCommittee,
nativetypes.LatestExecutionPayloadHeader,
}
// InitializeFromProtoPhase0 the beacon state from a protobuf representation.
func InitializeFromProtoPhase0(st *ethpb.BeaconState) (state.BeaconState, error) {
return InitializeFromProtoUnsafePhase0(proto.Clone(st).(*ethpb.BeaconState))
}
// InitializeFromProtoAltair the beacon state from a protobuf representation.
func InitializeFromProtoAltair(st *ethpb.BeaconStateAltair) (state.BeaconState, error) {
return InitializeFromProtoUnsafeAltair(proto.Clone(st).(*ethpb.BeaconStateAltair))
}
// InitializeFromProtoBellatrix the beacon state from a protobuf representation.
func InitializeFromProtoBellatrix(st *ethpb.BeaconStateBellatrix) (state.BeaconState, error) {
return InitializeFromProtoUnsafeBellatrix(proto.Clone(st).(*ethpb.BeaconStateBellatrix))
}
// InitializeFromProtoUnsafePhase0 directly uses the beacon state protobuf fields
// and sets them as fields of the BeaconState type.
func InitializeFromProtoUnsafePhase0(st *ethpb.BeaconState) (state.BeaconState, error) {
if st == nil {
return nil, errors.New("received nil state")
}
var bRoots customtypes.BlockRoots
for i, r := range st.BlockRoots {
copy(bRoots[i][:], r)
}
var sRoots customtypes.StateRoots
for i, r := range st.StateRoots {
copy(sRoots[i][:], r)
}
hRoots := customtypes.HistoricalRoots(make([][32]byte, len(st.HistoricalRoots)))
for i, r := range st.HistoricalRoots {
copy(hRoots[i][:], r)
}
var mixes customtypes.RandaoMixes
for i, m := range st.RandaoMixes {
copy(mixes[i][:], m)
}
fieldCount := params.BeaconConfig().BeaconStateFieldCount
b := &BeaconState{
version: version.Phase0,
genesisTime: st.GenesisTime,
genesisValidatorsRoot: bytesutil.ToBytes32(st.GenesisValidatorsRoot),
slot: st.Slot,
fork: st.Fork,
latestBlockHeader: st.LatestBlockHeader,
blockRoots: &bRoots,
stateRoots: &sRoots,
historicalRoots: hRoots,
eth1Data: st.Eth1Data,
eth1DataVotes: st.Eth1DataVotes,
eth1DepositIndex: st.Eth1DepositIndex,
validators: st.Validators,
balances: st.Balances,
randaoMixes: &mixes,
slashings: st.Slashings,
previousEpochAttestations: st.PreviousEpochAttestations,
currentEpochAttestations: st.CurrentEpochAttestations,
justificationBits: st.JustificationBits,
previousJustifiedCheckpoint: st.PreviousJustifiedCheckpoint,
currentJustifiedCheckpoint: st.CurrentJustifiedCheckpoint,
finalizedCheckpoint: st.FinalizedCheckpoint,
dirtyFields: make(map[nativetypes.FieldIndex]bool, fieldCount),
dirtyIndices: make(map[nativetypes.FieldIndex][]uint64, fieldCount),
stateFieldLeaves: make(map[nativetypes.FieldIndex]*fieldtrie.FieldTrie, fieldCount),
sharedFieldReferences: make(map[nativetypes.FieldIndex]*stateutil.Reference, 10),
rebuildTrie: make(map[nativetypes.FieldIndex]bool, fieldCount),
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
for _, f := range phase0Fields {
b.dirtyFields[f] = true
b.rebuildTrie[f] = true
b.dirtyIndices[f] = []uint64{}
trie, err := fieldtrie.NewFieldTrie(f, types.BasicArray, nil, 0)
if err != nil {
return nil, err
}
b.stateFieldLeaves[f] = trie
}
// Initialize field reference tracking for shared data.
b.sharedFieldReferences[nativetypes.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.HistoricalRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Eth1DataVotes] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Slashings] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.PreviousEpochAttestations] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.CurrentEpochAttestations] = stateutil.NewRef(1)
state.StateCount.Inc()
return b, nil
}
// InitializeFromProtoUnsafeAltair directly uses the beacon state protobuf fields
// and sets them as fields of the BeaconState type.
func InitializeFromProtoUnsafeAltair(st *ethpb.BeaconStateAltair) (state.BeaconStateAltair, error) {
if st == nil {
return nil, errors.New("received nil state")
}
var bRoots customtypes.BlockRoots
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
var sRoots customtypes.StateRoots
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
}
hRoots := customtypes.HistoricalRoots(make([][32]byte, len(st.HistoricalRoots)))
for i, r := range st.HistoricalRoots {
hRoots[i] = bytesutil.ToBytes32(r)
}
var mixes customtypes.RandaoMixes
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
fieldCount := params.BeaconConfig().BeaconStateAltairFieldCount
b := &BeaconState{
version: version.Altair,
genesisTime: st.GenesisTime,
genesisValidatorsRoot: bytesutil.ToBytes32(st.GenesisValidatorsRoot),
slot: st.Slot,
fork: st.Fork,
latestBlockHeader: st.LatestBlockHeader,
blockRoots: &bRoots,
stateRoots: &sRoots,
historicalRoots: hRoots,
eth1Data: st.Eth1Data,
eth1DataVotes: st.Eth1DataVotes,
eth1DepositIndex: st.Eth1DepositIndex,
validators: st.Validators,
balances: st.Balances,
randaoMixes: &mixes,
slashings: st.Slashings,
previousEpochParticipation: st.PreviousEpochParticipation,
currentEpochParticipation: st.CurrentEpochParticipation,
justificationBits: st.JustificationBits,
previousJustifiedCheckpoint: st.PreviousJustifiedCheckpoint,
currentJustifiedCheckpoint: st.CurrentJustifiedCheckpoint,
finalizedCheckpoint: st.FinalizedCheckpoint,
inactivityScores: st.InactivityScores,
currentSyncCommittee: st.CurrentSyncCommittee,
nextSyncCommittee: st.NextSyncCommittee,
dirtyFields: make(map[nativetypes.FieldIndex]bool, fieldCount),
dirtyIndices: make(map[nativetypes.FieldIndex][]uint64, fieldCount),
stateFieldLeaves: make(map[nativetypes.FieldIndex]*fieldtrie.FieldTrie, fieldCount),
sharedFieldReferences: make(map[nativetypes.FieldIndex]*stateutil.Reference, 11),
rebuildTrie: make(map[nativetypes.FieldIndex]bool, fieldCount),
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
for _, f := range altairFields {
b.dirtyFields[f] = true
b.rebuildTrie[f] = true
b.dirtyIndices[f] = []uint64{}
trie, err := fieldtrie.NewFieldTrie(f, types.BasicArray, nil, 0)
if err != nil {
return nil, err
}
b.stateFieldLeaves[f] = trie
}
// Initialize field reference tracking for shared data.
b.sharedFieldReferences[nativetypes.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.HistoricalRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Eth1DataVotes] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Slashings] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits] = stateutil.NewRef(1) // New in Altair.
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits] = stateutil.NewRef(1) // New in Altair.
b.sharedFieldReferences[nativetypes.InactivityScores] = stateutil.NewRef(1) // New in Altair.
state.StateCount.Inc()
return b, nil
}
// InitializeFromProtoUnsafeBellatrix directly uses the beacon state protobuf fields
// and sets them as fields of the BeaconState type.
func InitializeFromProtoUnsafeBellatrix(st *ethpb.BeaconStateBellatrix) (state.BeaconStateBellatrix, error) {
if st == nil {
return nil, errors.New("received nil state")
}
var bRoots customtypes.BlockRoots
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
var sRoots customtypes.StateRoots
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
}
hRoots := customtypes.HistoricalRoots(make([][32]byte, len(st.HistoricalRoots)))
for i, r := range st.HistoricalRoots {
hRoots[i] = bytesutil.ToBytes32(r)
}
var mixes customtypes.RandaoMixes
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
fieldCount := params.BeaconConfig().BeaconStateBellatrixFieldCount
b := &BeaconState{
version: version.Bellatrix,
genesisTime: st.GenesisTime,
genesisValidatorsRoot: bytesutil.ToBytes32(st.GenesisValidatorsRoot),
slot: st.Slot,
fork: st.Fork,
latestBlockHeader: st.LatestBlockHeader,
blockRoots: &bRoots,
stateRoots: &sRoots,
historicalRoots: hRoots,
eth1Data: st.Eth1Data,
eth1DataVotes: st.Eth1DataVotes,
eth1DepositIndex: st.Eth1DepositIndex,
validators: st.Validators,
balances: st.Balances,
randaoMixes: &mixes,
slashings: st.Slashings,
previousEpochParticipation: st.PreviousEpochParticipation,
currentEpochParticipation: st.CurrentEpochParticipation,
justificationBits: st.JustificationBits,
previousJustifiedCheckpoint: st.PreviousJustifiedCheckpoint,
currentJustifiedCheckpoint: st.CurrentJustifiedCheckpoint,
finalizedCheckpoint: st.FinalizedCheckpoint,
inactivityScores: st.InactivityScores,
currentSyncCommittee: st.CurrentSyncCommittee,
nextSyncCommittee: st.NextSyncCommittee,
latestExecutionPayloadHeader: st.LatestExecutionPayloadHeader,
dirtyFields: make(map[nativetypes.FieldIndex]bool, fieldCount),
dirtyIndices: make(map[nativetypes.FieldIndex][]uint64, fieldCount),
stateFieldLeaves: make(map[nativetypes.FieldIndex]*fieldtrie.FieldTrie, fieldCount),
sharedFieldReferences: make(map[nativetypes.FieldIndex]*stateutil.Reference, 11),
rebuildTrie: make(map[nativetypes.FieldIndex]bool, fieldCount),
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
for _, f := range bellatrixFields {
b.dirtyFields[f] = true
b.rebuildTrie[f] = true
b.dirtyIndices[f] = []uint64{}
trie, err := fieldtrie.NewFieldTrie(f, types.BasicArray, nil, 0)
if err != nil {
return nil, err
}
b.stateFieldLeaves[f] = trie
}
// Initialize field reference tracking for shared data.
b.sharedFieldReferences[nativetypes.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.HistoricalRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Eth1DataVotes] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Validators] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.Slashings] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.PreviousEpochParticipationBits] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.InactivityScores] = stateutil.NewRef(1)
b.sharedFieldReferences[nativetypes.LatestExecutionPayloadHeader] = stateutil.NewRef(1) // New in Bellatrix.
state.StateCount.Inc()
return b, nil
}
// Copy returns a deep copy of the beacon state.
func (b *BeaconState) Copy() state.BeaconState {
b.lock.RLock()
defer b.lock.RUnlock()
var fieldCount int
switch b.version {
case version.Phase0:
fieldCount = params.BeaconConfig().BeaconStateFieldCount
case version.Altair:
fieldCount = params.BeaconConfig().BeaconStateAltairFieldCount
case version.Bellatrix:
fieldCount = params.BeaconConfig().BeaconStateBellatrixFieldCount
}
dst := &BeaconState{
version: b.version,
// Primitive nativetypes, safe to copy.
genesisTime: b.genesisTime,
slot: b.slot,
eth1DepositIndex: b.eth1DepositIndex,
// Large arrays, infrequently changed, constant size.
blockRoots: b.blockRoots,
stateRoots: b.stateRoots,
randaoMixes: b.randaoMixes,
previousEpochAttestations: b.previousEpochAttestations,
currentEpochAttestations: b.currentEpochAttestations,
eth1DataVotes: b.eth1DataVotes,
slashings: b.slashings,
// Large arrays, increases over time.
balances: b.balances,
historicalRoots: b.historicalRoots,
validators: b.validators,
previousEpochParticipation: b.previousEpochParticipation,
currentEpochParticipation: b.currentEpochParticipation,
inactivityScores: b.inactivityScores,
// Everything else, too small to be concerned about, constant size.
genesisValidatorsRoot: b.genesisValidatorsRoot,
justificationBits: b.justificationBitsVal(),
fork: b.forkVal(),
latestBlockHeader: b.latestBlockHeaderVal(),
eth1Data: b.eth1DataVal(),
previousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
currentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
finalizedCheckpoint: b.finalizedCheckpointVal(),
currentSyncCommittee: b.currentSyncCommitteeVal(),
nextSyncCommittee: b.nextSyncCommitteeVal(),
latestExecutionPayloadHeader: b.latestExecutionPayloadHeaderVal(),
dirtyFields: make(map[nativetypes.FieldIndex]bool, fieldCount),
dirtyIndices: make(map[nativetypes.FieldIndex][]uint64, fieldCount),
rebuildTrie: make(map[nativetypes.FieldIndex]bool, fieldCount),
stateFieldLeaves: make(map[nativetypes.FieldIndex]*fieldtrie.FieldTrie, fieldCount),
// Share the reference to validator index map.
valMapHandler: b.valMapHandler,
}
switch b.version {
case version.Phase0:
dst.sharedFieldReferences = make(map[nativetypes.FieldIndex]*stateutil.Reference, 10)
case version.Altair:
dst.sharedFieldReferences = make(map[nativetypes.FieldIndex]*stateutil.Reference, 11)
case version.Bellatrix:
dst.sharedFieldReferences = make(map[nativetypes.FieldIndex]*stateutil.Reference, 11)
}
for field, ref := range b.sharedFieldReferences {
ref.AddRef()
dst.sharedFieldReferences[field] = ref
}
// Increment ref for validator map
b.valMapHandler.AddRef()
for i := range b.dirtyFields {
dst.dirtyFields[i] = true
}
for i := range b.dirtyIndices {
indices := make([]uint64, len(b.dirtyIndices[i]))
copy(indices, b.dirtyIndices[i])
dst.dirtyIndices[i] = indices
}
for i := range b.rebuildTrie {
dst.rebuildTrie[i] = true
}
for fldIdx, fieldTrie := range b.stateFieldLeaves {
dst.stateFieldLeaves[fldIdx] = fieldTrie
if fieldTrie.FieldReference() != nil {
fieldTrie.Lock()
fieldTrie.FieldReference().AddRef()
fieldTrie.Unlock()
}
}
if b.merkleLayers != nil {
dst.merkleLayers = make([][][]byte, len(b.merkleLayers))
for i, layer := range b.merkleLayers {
dst.merkleLayers[i] = make([][]byte, len(layer))
for j, content := range layer {
dst.merkleLayers[i][j] = make([]byte, len(content))
copy(dst.merkleLayers[i][j], content)
}
}
}
state.StateCount.Inc()
// Finalizer runs when dst is being destroyed in garbage collection.
runtime.SetFinalizer(dst, func(b *BeaconState) {
for field, v := range b.sharedFieldReferences {
v.MinusRef()
if b.stateFieldLeaves[field].FieldReference() != nil {
b.stateFieldLeaves[field].FieldReference().MinusRef()
}
}
for i := range b.dirtyFields {
delete(b.dirtyFields, i)
}
for i := range b.rebuildTrie {
delete(b.rebuildTrie, i)
}
for i := range b.dirtyIndices {
delete(b.dirtyIndices, i)
}
for i := range b.sharedFieldReferences {
delete(b.sharedFieldReferences, i)
}
for i := range b.stateFieldLeaves {
delete(b.stateFieldLeaves, i)
}
state.StateCount.Sub(1)
})
return dst
}
// HashTreeRoot of the beacon state retrieves the Merkle root of the trie
// representation of the beacon state based on the Ethereum Simple Serialize specification.
func (b *BeaconState) HashTreeRoot(ctx context.Context) ([32]byte, error) {
ctx, span := trace.StartSpan(ctx, "beaconState.HashTreeRoot")
defer span.End()
b.lock.Lock()
defer b.lock.Unlock()
if err := b.initializeMerkleLayers(ctx); err != nil {
return [32]byte{}, err
}
if err := b.recomputeDirtyFields(ctx); err != nil {
return [32]byte{}, err
}
return bytesutil.ToBytes32(b.merkleLayers[len(b.merkleLayers)-1][0]), nil
}
// Initializes the Merkle layers for the beacon state if they are empty.
// WARNING: Caller must acquire the mutex before using.
func (b *BeaconState) initializeMerkleLayers(ctx context.Context) error {
if len(b.merkleLayers) > 0 {
return nil
}
fieldRoots, err := ComputeFieldRootsWithHasher(ctx, b)
if err != nil {
return err
}
layers := stateutil.Merkleize(fieldRoots)
b.merkleLayers = layers
switch b.version {
case version.Phase0:
b.dirtyFields = make(map[nativetypes.FieldIndex]bool, params.BeaconConfig().BeaconStateFieldCount)
case version.Altair:
b.dirtyFields = make(map[nativetypes.FieldIndex]bool, params.BeaconConfig().BeaconStateAltairFieldCount)
case version.Bellatrix:
b.dirtyFields = make(map[nativetypes.FieldIndex]bool, params.BeaconConfig().BeaconStateBellatrixFieldCount)
}
return nil
}
// Recomputes the Merkle layers for the dirty fields in the state.
// WARNING: Caller must acquire the mutex before using.
func (b *BeaconState) recomputeDirtyFields(ctx context.Context) error {
for field := range b.dirtyFields {
root, err := b.rootSelector(ctx, field)
if err != nil {
return err
}
idx := field.RealPosition()
b.merkleLayers[0][idx] = root[:]
b.recomputeRoot(idx)
delete(b.dirtyFields, field)
}
return nil
}
// FieldReferencesCount returns the reference count held by each field. This
// also includes the field trie held by each field.
func (b *BeaconState) FieldReferencesCount() map[string]uint64 {
refMap := make(map[string]uint64)
b.lock.RLock()
defer b.lock.RUnlock()
for i, f := range b.sharedFieldReferences {
refMap[i.String(b.version)] = uint64(f.Refs())
}
for i, f := range b.stateFieldLeaves {
numOfRefs := uint64(f.FieldReference().Refs())
f.RLock()
if !f.Empty() {
refMap[i.String(b.version)+"_trie"] = numOfRefs
}
f.RUnlock()
}
return refMap
}
// IsNil checks if the state and the underlying proto
// object are nil.
func (b *BeaconState) IsNil() bool {
return b == nil
}
func (b *BeaconState) rootSelector(ctx context.Context, field nativetypes.FieldIndex) ([32]byte, error) {
_, span := trace.StartSpan(ctx, "beaconState.rootSelector")
defer span.End()
span.AddAttributes(trace.StringAttribute("field", field.String(b.version)))
hasher := hash.CustomSHA256Hasher()
switch field {
case nativetypes.GenesisTime:
return ssz.Uint64Root(b.genesisTime), nil
case nativetypes.GenesisValidatorsRoot:
return b.genesisValidatorsRoot, nil
case nativetypes.Slot:
return ssz.Uint64Root(uint64(b.slot)), nil
case nativetypes.Eth1DepositIndex:
return ssz.Uint64Root(b.eth1DepositIndex), nil
case nativetypes.Fork:
return ssz.ForkRoot(b.fork)
case nativetypes.LatestBlockHeader:
return stateutil.BlockHeaderRoot(b.latestBlockHeader)
case nativetypes.BlockRoots:
if b.rebuildTrie[field] {
err := b.resetFieldTrie(field, b.blockRoots, fieldparams.BlockRootsLength)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
return b.recomputeFieldTrie(field, b.blockRoots)
case nativetypes.StateRoots:
if b.rebuildTrie[field] {
err := b.resetFieldTrie(field, b.stateRoots, fieldparams.StateRootsLength)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
return b.recomputeFieldTrie(field, b.stateRoots)
case nativetypes.HistoricalRoots:
hRoots := make([][]byte, len(b.historicalRoots))
for i := range hRoots {
hRoots[i] = b.historicalRoots[i][:]
}
return ssz.ByteArrayRootWithLimit(hRoots, fieldparams.HistoricalRootsLength)
case nativetypes.Eth1Data:
return stateutil.Eth1Root(hasher, b.eth1Data)
case nativetypes.Eth1DataVotes:
if b.rebuildTrie[field] {
err := b.resetFieldTrie(
field,
b.eth1DataVotes,
fieldparams.Eth1DataVotesLength,
)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
return b.recomputeFieldTrie(field, b.eth1DataVotes)
case nativetypes.Validators:
if b.rebuildTrie[field] {
err := b.resetFieldTrie(field, b.validators, fieldparams.ValidatorRegistryLimit)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
return b.recomputeFieldTrie(11, b.validators)
case nativetypes.Balances:
if b.rebuildTrie[field] {
maxBalCap := uint64(fieldparams.ValidatorRegistryLimit)
elemSize := uint64(8)
balLimit := (maxBalCap*elemSize + 31) / 32
err := b.resetFieldTrie(field, b.balances, balLimit)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
return b.recomputeFieldTrie(12, b.balances)
case nativetypes.RandaoMixes:
if b.rebuildTrie[field] {
err := b.resetFieldTrie(field, b.randaoMixes, fieldparams.RandaoMixesLength)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
return b.recomputeFieldTrie(13, b.randaoMixes)
case nativetypes.Slashings:
return ssz.SlashingsRoot(b.slashings)
case nativetypes.PreviousEpochAttestations:
if b.rebuildTrie[field] {
err := b.resetFieldTrie(
field,
b.previousEpochAttestations,
fieldparams.PreviousEpochAttestationsLength,
)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
return b.recomputeFieldTrie(field, b.previousEpochAttestations)
case nativetypes.CurrentEpochAttestations:
if b.rebuildTrie[field] {
err := b.resetFieldTrie(
field,
b.currentEpochAttestations,
fieldparams.CurrentEpochAttestationsLength,
)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
return b.recomputeFieldTrie(field, b.currentEpochAttestations)
case nativetypes.PreviousEpochParticipationBits:
return stateutil.ParticipationBitsRoot(b.previousEpochParticipation)
case nativetypes.CurrentEpochParticipationBits:
return stateutil.ParticipationBitsRoot(b.currentEpochParticipation)
case nativetypes.JustificationBits:
return bytesutil.ToBytes32(b.justificationBits), nil
case nativetypes.PreviousJustifiedCheckpoint:
return ssz.CheckpointRoot(hasher, b.previousJustifiedCheckpoint)
case nativetypes.CurrentJustifiedCheckpoint:
return ssz.CheckpointRoot(hasher, b.currentJustifiedCheckpoint)
case nativetypes.FinalizedCheckpoint:
return ssz.CheckpointRoot(hasher, b.finalizedCheckpoint)
case nativetypes.InactivityScores:
return stateutil.Uint64ListRootWithRegistryLimit(b.inactivityScores)
case nativetypes.CurrentSyncCommittee:
return stateutil.SyncCommitteeRoot(b.currentSyncCommittee)
case nativetypes.NextSyncCommittee:
return stateutil.SyncCommitteeRoot(b.nextSyncCommittee)
case nativetypes.LatestExecutionPayloadHeader:
return b.latestExecutionPayloadHeader.HashTreeRoot()
}
return [32]byte{}, errors.New("invalid field index provided")
}
func (b *BeaconState) recomputeFieldTrie(index nativetypes.FieldIndex, elements interface{}) ([32]byte, error) {
fTrie := b.stateFieldLeaves[index]
// We can't lock the trie directly because the trie's variable gets reassigned,
// and therefore we would call Unlock() on a different object.
fTrieMutex := fTrie.RWMutex
if fTrie.FieldReference().Refs() > 1 {
fTrieMutex.Lock()
fTrie.FieldReference().MinusRef()
newTrie := fTrie.CopyTrie()
b.stateFieldLeaves[index] = newTrie
fTrie = newTrie
fTrieMutex.Unlock()
}
// remove duplicate indexes
b.dirtyIndices[index] = slice.SetUint64(b.dirtyIndices[index])
// sort indexes again
sort.Slice(b.dirtyIndices[index], func(i int, j int) bool {
return b.dirtyIndices[index][i] < b.dirtyIndices[index][j]
})
root, err := fTrie.RecomputeTrie(b.dirtyIndices[index], elements)
if err != nil {
return [32]byte{}, err
}
b.dirtyIndices[index] = []uint64{}
return root, nil
}
func (b *BeaconState) resetFieldTrie(index nativetypes.FieldIndex, elements interface{}, length uint64) error {
fTrie, err := fieldtrie.NewFieldTrie(index, fieldMap[index], elements, length)
if err != nil {
return err
}
b.stateFieldLeaves[index] = fTrie
b.dirtyIndices[index] = []uint64{}
return nil
}

View File

@@ -1,4 +1,4 @@
package v1_test
package state_native_test
import (
"bytes"
@@ -6,7 +6,7 @@ import (
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
statenative "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
@@ -15,9 +15,9 @@ import (
"github.com/prysmaticlabs/prysm/testing/util"
)
func TestInitializeFromProto(t *testing.T) {
func TestInitializeFromProto_Phase0(t *testing.T) {
testState, _ := util.DeterministicGenesisState(t, 64)
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
pbState, err := statenative.ProtobufBeaconStatePhase0(testState.InnerStateUnsafe())
require.NoError(t, err)
type test struct {
name string
@@ -48,7 +48,7 @@ func TestInitializeFromProto(t *testing.T) {
}
for _, tt := range initTests {
t.Run(tt.name, func(t *testing.T) {
_, err := v1.InitializeFromProto(tt.state)
_, err := statenative.InitializeFromProtoUnsafePhase0(tt.state)
if tt.error != "" {
assert.ErrorContains(t, tt.error, err)
} else {
@@ -58,13 +58,10 @@ func TestInitializeFromProto(t *testing.T) {
}
}
func TestInitializeFromProtoUnsafe(t *testing.T) {
testState, _ := util.DeterministicGenesisState(t, 64)
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
require.NoError(t, err)
func TestInitializeFromProto_Altair(t *testing.T) {
type test struct {
name string
state *ethpb.BeaconState
state *ethpb.BeaconStateAltair
error string
}
initTests := []test{
@@ -73,6 +70,77 @@ func TestInitializeFromProtoUnsafe(t *testing.T) {
state: nil,
error: "received nil state",
},
{
name: "nil validators",
state: &ethpb.BeaconStateAltair{
Slot: 4,
Validators: nil,
},
},
{
name: "empty state",
state: &ethpb.BeaconStateAltair{},
},
// TODO: Add full state. Blocked by testutil migration.
}
for _, tt := range initTests {
t.Run(tt.name, func(t *testing.T) {
_, err := statenative.InitializeFromProtoAltair(tt.state)
if tt.error != "" {
require.ErrorContains(t, tt.error, err)
} else {
require.NoError(t, err)
}
})
}
}
func TestInitializeFromProto_Bellatrix(t *testing.T) {
type test struct {
name string
state *ethpb.BeaconStateBellatrix
error string
}
initTests := []test{
{
name: "nil state",
state: nil,
error: "received nil state",
},
{
name: "nil validators",
state: &ethpb.BeaconStateBellatrix{
Slot: 4,
Validators: nil,
},
},
{
name: "empty state",
state: &ethpb.BeaconStateBellatrix{},
},
}
for _, tt := range initTests {
t.Run(tt.name, func(t *testing.T) {
_, err := statenative.InitializeFromProtoBellatrix(tt.state)
if tt.error != "" {
require.ErrorContains(t, tt.error, err)
} else {
require.NoError(t, err)
}
})
}
}
func TestInitializeFromProtoUnsafe_Phase0(t *testing.T) {
testState, _ := util.DeterministicGenesisState(t, 64)
pbState, err := statenative.ProtobufBeaconStatePhase0(testState.InnerStateUnsafe())
require.NoError(t, err)
type test struct {
name string
state *ethpb.BeaconState
error string
}
initTests := []test{
{
name: "nil validators",
state: &ethpb.BeaconState{
@@ -91,7 +159,7 @@ func TestInitializeFromProtoUnsafe(t *testing.T) {
}
for _, tt := range initTests {
t.Run(tt.name, func(t *testing.T) {
_, err := v1.InitializeFromProtoUnsafe(tt.state)
_, err := statenative.InitializeFromProtoUnsafePhase0(tt.state)
if tt.error != "" {
assert.ErrorContains(t, tt.error, err)
} else {
@@ -101,6 +169,52 @@ func TestInitializeFromProtoUnsafe(t *testing.T) {
}
}
func TestInitializeFromProtoUnsafe_Altair(t *testing.T) {
type test struct {
name string
state *ethpb.BeaconStateAltair
error string
}
initTests := []test{
{
name: "nil validators",
state: &ethpb.BeaconStateAltair{
Slot: 4,
Validators: nil,
},
},
{
name: "empty state",
state: &ethpb.BeaconStateAltair{},
},
// TODO: Add full state. Blocked by testutil migration.
}
_ = initTests
}
func TestInitializeFromProtoUnsafe_Bellatrix(t *testing.T) {
type test struct {
name string
state *ethpb.BeaconStateBellatrix
error string
}
initTests := []test{
{
name: "nil validators",
state: &ethpb.BeaconStateBellatrix{
Slot: 4,
Validators: nil,
},
},
{
name: "empty state",
state: &ethpb.BeaconStateBellatrix{},
},
// TODO: Add full state. Blocked by testutil migration.
}
_ = initTests
}
func TestBeaconState_HashTreeRoot(t *testing.T) {
testState, _ := util.DeterministicGenesisState(t, 64)
@@ -154,7 +268,7 @@ func TestBeaconState_HashTreeRoot(t *testing.T) {
if err == nil && tt.error != "" {
t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
}
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
pbState, err := statenative.ProtobufBeaconStatePhase0(testState.InnerStateUnsafe())
require.NoError(t, err)
genericHTR, err := pbState.HashTreeRoot()
if err == nil && tt.error != "" {
@@ -170,6 +284,24 @@ func TestBeaconState_HashTreeRoot(t *testing.T) {
}
}
func BenchmarkBeaconState(b *testing.B) {
testState, _ := util.DeterministicGenesisState(b, 16000)
pbState, err := statenative.ProtobufBeaconStatePhase0(testState.InnerStateUnsafe())
require.NoError(b, err)
b.Run("Vectorized SHA256", func(b *testing.B) {
st, err := statenative.InitializeFromProtoUnsafePhase0(pbState)
require.NoError(b, err)
_, err = st.HashTreeRoot(context.Background())
assert.NoError(b, err)
})
b.Run("Current SHA256", func(b *testing.B) {
_, err := pbState.HashTreeRoot()
require.NoError(b, err)
})
}
func TestBeaconState_HashTreeRoot_FieldTrie(t *testing.T) {
testState, _ := util.DeterministicGenesisState(t, 64)
@@ -223,7 +355,7 @@ func TestBeaconState_HashTreeRoot_FieldTrie(t *testing.T) {
if err == nil && tt.error != "" {
t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
}
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
pbState, err := statenative.ProtobufBeaconStatePhase0(testState.InnerStateUnsafe())
require.NoError(t, err)
genericHTR, err := pbState.HashTreeRoot()
if err == nil && tt.error != "" {
@@ -251,21 +383,3 @@ func TestBeaconState_AppendValidator_DoesntMutateCopy(t *testing.T) {
_, ok := st1.ValidatorIndexByPubkey(bytesutil.ToBytes48(val.PublicKey))
assert.Equal(t, false, ok, "Expected no validator index to be present in st1 for the newly inserted pubkey")
}
func BenchmarkBeaconState(b *testing.B) {
testState, _ := util.DeterministicGenesisState(b, 16000)
pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
require.NoError(b, err)
b.Run("Vectorized SHA256", func(b *testing.B) {
st, err := v1.InitializeFromProtoUnsafe(pbState)
require.NoError(b, err)
_, err = st.HashTreeRoot(context.Background())
assert.NoError(b, err)
})
b.Run("Current SHA256", func(b *testing.B) {
_, err := pbState.HashTreeRoot()
require.NoError(b, err)
})
}

View File

@@ -0,0 +1,36 @@
package state_native
import (
"fmt"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
nativetypes "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/beacon-chain/state/types"
"github.com/prysmaticlabs/prysm/runtime/version"
)
// Ensure type BeaconState below implements BeaconState interface.
var _ state.BeaconState = (*BeaconState)(nil)
func init() {
fieldMap = make(map[nativetypes.FieldIndex]types.DataType)
// Initialize the fixed sized arrays.
fieldMap[nativetypes.BlockRoots] = types.BasicArray
fieldMap[nativetypes.StateRoots] = types.BasicArray
fieldMap[nativetypes.RandaoMixes] = types.BasicArray
// Initialize the composite arrays.
fieldMap[nativetypes.Eth1DataVotes] = types.CompositeArray
fieldMap[nativetypes.Validators] = types.CompositeArray
fieldMap[nativetypes.PreviousEpochAttestations] = types.CompositeArray
fieldMap[nativetypes.CurrentEpochAttestations] = types.CompositeArray
fieldMap[nativetypes.Balances] = types.CompressedArray
}
// fieldMap keeps track of each field
// to its corresponding data type.
var fieldMap map[nativetypes.FieldIndex]types.DataType
func errNotSupported(funcName string, ver int) error {
return fmt.Errorf("%s is not supported for %s", funcName, version.String(ver))
}

View File

@@ -0,0 +1,9 @@
load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["types.go"],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/types",
visibility = ["//visibility:public"],
deps = ["@com_github_pkg_errors//:go_default_library"],
)

View File

@@ -0,0 +1,181 @@
package types
import (
"github.com/pkg/errors"
)
// FieldIndex represents the relevant field position in the
// state struct for a field.
type FieldIndex int
// String returns the name of the field index.
func (f FieldIndex) String(_ int) string {
switch f {
case GenesisTime:
return "genesisTime"
case GenesisValidatorsRoot:
return "genesisValidatorsRoot"
case Slot:
return "slot"
case Fork:
return "fork"
case LatestBlockHeader:
return "latestBlockHeader"
case BlockRoots:
return "blockRoots"
case StateRoots:
return "stateRoots"
case HistoricalRoots:
return "historicalRoots"
case Eth1Data:
return "eth1Data"
case Eth1DataVotes:
return "eth1DataVotes"
case Eth1DepositIndex:
return "eth1DepositIndex"
case Validators:
return "validators"
case Balances:
return "balances"
case RandaoMixes:
return "randaoMixes"
case Slashings:
return "slashings"
case PreviousEpochAttestations:
return "previousEpochAttestations"
case CurrentEpochAttestations:
return "currentEpochAttestations"
case PreviousEpochParticipationBits:
return "previousEpochParticipationBits"
case CurrentEpochParticipationBits:
return "currentEpochParticipationBits"
case JustificationBits:
return "justificationBits"
case PreviousJustifiedCheckpoint:
return "previousJustifiedCheckpoint"
case CurrentJustifiedCheckpoint:
return "currentJustifiedCheckpoint"
case FinalizedCheckpoint:
return "finalizedCheckpoint"
case InactivityScores:
return "inactivityScores"
case CurrentSyncCommittee:
return "currentSyncCommittee"
case NextSyncCommittee:
return "nextSyncCommittee"
case LatestExecutionPayloadHeader:
return "latestExecutionPayloadHeader"
default:
return ""
}
}
// RealPosition denotes the position of the field in the beacon state.
// The value might differ for different state versions.
func (f FieldIndex) RealPosition() int {
switch f {
case GenesisTime:
return 0
case GenesisValidatorsRoot:
return 1
case Slot:
return 2
case Fork:
return 3
case LatestBlockHeader:
return 4
case BlockRoots:
return 5
case StateRoots:
return 6
case HistoricalRoots:
return 7
case Eth1Data:
return 8
case Eth1DataVotes:
return 9
case Eth1DepositIndex:
return 10
case Validators:
return 11
case Balances:
return 12
case RandaoMixes:
return 13
case Slashings:
return 14
case PreviousEpochAttestations, PreviousEpochParticipationBits:
return 15
case CurrentEpochAttestations, CurrentEpochParticipationBits:
return 16
case JustificationBits:
return 17
case PreviousJustifiedCheckpoint:
return 18
case CurrentJustifiedCheckpoint:
return 19
case FinalizedCheckpoint:
return 20
case InactivityScores:
return 21
case CurrentSyncCommittee:
return 22
case NextSyncCommittee:
return 23
case LatestExecutionPayloadHeader:
return 24
default:
return -1
}
}
// ElemsInChunk returns the number of elements in the chunk (number of
// elements that are able to be packed).
func (f FieldIndex) ElemsInChunk() (uint64, error) {
switch f {
case Balances:
return 4, nil
default:
return 0, errors.Errorf("field %d doesn't support element compression", f)
}
}
func (FieldIndex) Native() bool {
return true
}
// Below we define a set of useful enum values for the field
// indices of the beacon state. For example, genesisTime is the
// 0th field of the beacon state. This is helpful when we are
// updating the Merkle branches up the trie representation
// of the beacon state. The below field indexes correspond
// to the state.
const (
GenesisTime FieldIndex = iota
GenesisValidatorsRoot
Slot
Fork
LatestBlockHeader
BlockRoots
StateRoots
HistoricalRoots
Eth1Data
Eth1DataVotes
Eth1DepositIndex
Validators
Balances
RandaoMixes
Slashings
PreviousEpochAttestations
CurrentEpochAttestations
PreviousEpochParticipationBits
CurrentEpochParticipationBits
JustificationBits
PreviousJustifiedCheckpoint
CurrentJustifiedCheckpoint
FinalizedCheckpoint
InactivityScores
CurrentSyncCommittee
NextSyncCommittee
LatestExecutionPayloadHeader
)

View File

@@ -1,4 +1,4 @@
package v1_test
package state_native_test
import (
"context"
@@ -6,7 +6,7 @@ import (
"strconv"
"testing"
v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native/v1"
statenative "github.com/prysmaticlabs/prysm/beacon-chain/state/state-native"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/config/params"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
@@ -20,14 +20,9 @@ import (
func TestBeaconState_ProtoBeaconStateCompatibility(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.MinimalSpecConfig()
cfg.SlotsPerHistoricalRoot = fieldparams.BlockRootsLength
cfg.EpochsPerHistoricalVector = fieldparams.RandaoMixesLength
params.OverrideBeaconConfig(cfg)
ctx := context.Background()
genesis := setupGenesisState(t, 64)
customState, err := v1.InitializeFromProto(genesis)
customState, err := statenative.InitializeFromProtoPhase0(genesis)
require.NoError(t, err)
cloned, ok := proto.Clone(genesis).(*ethpb.BeaconState)
assert.Equal(t, true, ok, "Object is not of type *ethpb.BeaconState")
@@ -36,7 +31,7 @@ func TestBeaconState_ProtoBeaconStateCompatibility(t *testing.T) {
r1, err := customState.HashTreeRoot(ctx)
require.NoError(t, err)
beaconState, err := v1.InitializeFromProto(genesis)
beaconState, err := statenative.InitializeFromProtoPhase0(genesis)
require.NoError(t, err)
r2, err := beaconState.HashTreeRoot(context.Background())
require.NoError(t, err)
@@ -49,7 +44,7 @@ func TestBeaconState_ProtoBeaconStateCompatibility(t *testing.T) {
r1, err = customState.HashTreeRoot(ctx)
require.NoError(t, err)
genesis.Balances = balances
beaconState, err = v1.InitializeFromProto(genesis)
beaconState, err = statenative.InitializeFromProtoPhase0(genesis)
require.NoError(t, err)
r2, err = beaconState.HashTreeRoot(context.Background())
require.NoError(t, err)
@@ -142,7 +137,7 @@ func BenchmarkStateClone_Manual(b *testing.B) {
params.SetupTestConfigCleanup(b)
params.OverrideBeaconConfig(params.MinimalSpecConfig())
genesis := setupGenesisState(b, 64)
st, err := v1.InitializeFromProto(genesis)
st, err := statenative.InitializeFromProtoPhase0(genesis)
require.NoError(b, err)
b.StartTimer()
for i := 0; i < b.N; i++ {
@@ -184,7 +179,7 @@ func TestBeaconState_ImmutabilityWithSharedResources(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MinimalSpecConfig())
genesis := setupGenesisState(t, 64)
a, err := v1.InitializeFromProto(genesis)
a, err := statenative.InitializeFromProtoPhase0(genesis)
require.NoError(t, err)
b := a.Copy()
@@ -221,7 +216,7 @@ func TestForkManualCopy_OK(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MinimalSpecConfig())
genesis := setupGenesisState(t, 64)
a, err := v1.InitializeFromProto(genesis)
a, err := statenative.InitializeFromProtoPhase0(genesis)
require.NoError(t, err)
wantedFork := &ethpb.Fork{
PreviousVersion: []byte{'a', 'b', 'c'},
@@ -230,7 +225,7 @@ func TestForkManualCopy_OK(t *testing.T) {
}
require.NoError(t, a.SetFork(wantedFork))
pbState, err := v1.ProtobufBeaconState(a.InnerStateUnsafe())
pbState, err := statenative.ProtobufBeaconStatePhase0(a.InnerStateUnsafe())
require.NoError(t, err)
require.DeepEqual(t, pbState.Fork, wantedFork)
}

Some files were not shown because too many files have changed in this diff Show More