mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-11 06:18:05 -05:00
Compare commits
24 Commits
testRangeF
...
v5.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8cd77945d | ||
|
|
9a7f521f8a | ||
|
|
102f94f914 | ||
|
|
0c0a497651 | ||
|
|
e0785a8939 | ||
|
|
af098e737e | ||
|
|
1e4ede5585 | ||
|
|
fb2620364a | ||
|
|
68b38b6666 | ||
|
|
ff3e0856a1 | ||
|
|
85f334b663 | ||
|
|
10f520accb | ||
|
|
836608537e | ||
|
|
13e09c58f6 | ||
|
|
600ca08aa8 | ||
|
|
0ed74b3c4a | ||
|
|
7c69a9aa1c | ||
|
|
c50cfb044a | ||
|
|
38d4e179ba | ||
|
|
be80728320 | ||
|
|
09028033c0 | ||
|
|
52c036c3ab | ||
|
|
2fc7cdeba7 | ||
|
|
6f7976766d |
@@ -225,3 +225,19 @@ type IndividualVote struct {
|
||||
InclusionDistance string `json:"inclusion_distance"`
|
||||
InactivityScore string `json:"inactivity_score"`
|
||||
}
|
||||
|
||||
type ChainHead struct {
|
||||
HeadSlot string `json:"head_slot"`
|
||||
HeadEpoch string `json:"head_epoch"`
|
||||
HeadBlockRoot string `json:"head_block_root"`
|
||||
FinalizedSlot string `json:"finalized_slot"`
|
||||
FinalizedEpoch string `json:"finalized_epoch"`
|
||||
FinalizedBlockRoot string `json:"finalized_block_root"`
|
||||
JustifiedSlot string `json:"justified_slot"`
|
||||
JustifiedEpoch string `json:"justified_epoch"`
|
||||
JustifiedBlockRoot string `json:"justified_block_root"`
|
||||
PreviousJustifiedSlot string `json:"previous_justified_slot"`
|
||||
PreviousJustifiedEpoch string `json:"previous_justified_epoch"`
|
||||
PreviousJustifiedBlockRoot string `json:"previous_justified_block_root"`
|
||||
OptimisticStatus bool `json:"optimistic_status"`
|
||||
}
|
||||
|
||||
@@ -118,3 +118,34 @@ type GetValidatorPerformanceResponse struct {
|
||||
MissingValidators [][]byte `json:"missing_validators,omitempty"`
|
||||
InactivityScores []uint64 `json:"inactivity_scores,omitempty"`
|
||||
}
|
||||
|
||||
type GetValidatorParticipationResponse struct {
|
||||
Epoch string `json:"epoch"`
|
||||
Finalized bool `json:"finalized"`
|
||||
Participation *ValidatorParticipation `json:"participation"`
|
||||
}
|
||||
|
||||
type ValidatorParticipation struct {
|
||||
GlobalParticipationRate string `json:"global_participation_rate" deprecated:"true"`
|
||||
VotedEther string `json:"voted_ether" deprecated:"true"`
|
||||
EligibleEther string `json:"eligible_ether" deprecated:"true"`
|
||||
CurrentEpochActiveGwei string `json:"current_epoch_active_gwei"`
|
||||
CurrentEpochAttestingGwei string `json:"current_epoch_attesting_gwei"`
|
||||
CurrentEpochTargetAttestingGwei string `json:"current_epoch_target_attesting_gwei"`
|
||||
PreviousEpochActiveGwei string `json:"previous_epoch_active_gwei"`
|
||||
PreviousEpochAttestingGwei string `json:"previous_epoch_attesting_gwei"`
|
||||
PreviousEpochTargetAttestingGwei string `json:"previous_epoch_target_attesting_gwei"`
|
||||
PreviousEpochHeadAttestingGwei string `json:"previous_epoch_head_attesting_gwei"`
|
||||
}
|
||||
|
||||
type ActiveSetChanges struct {
|
||||
Epoch string `json:"epoch"`
|
||||
ActivatedPublicKeys []string `json:"activated_public_keys"`
|
||||
ActivatedIndices []string `json:"activated_indices"`
|
||||
ExitedPublicKeys []string `json:"exited_public_keys"`
|
||||
ExitedIndices []string `json:"exited_indices"`
|
||||
SlashedPublicKeys []string `json:"slashed_public_keys"`
|
||||
SlashedIndices []string `json:"slashed_indices"`
|
||||
EjectedPublicKeys []string `json:"ejected_public_keys"`
|
||||
EjectedIndices []string `json:"ejected_indices"`
|
||||
}
|
||||
|
||||
@@ -99,3 +99,10 @@ func (s *Service) FinalizedBlockHash() [32]byte {
|
||||
defer s.cfg.ForkChoiceStore.RUnlock()
|
||||
return s.cfg.ForkChoiceStore.FinalizedPayloadBlockHash()
|
||||
}
|
||||
|
||||
// ParentRoot wraps a call to the corresponding method in forkchoice
|
||||
func (s *Service) ParentRoot(root [32]byte) ([32]byte, error) {
|
||||
s.cfg.ForkChoiceStore.RLock()
|
||||
defer s.cfg.ForkChoiceStore.RUnlock()
|
||||
return s.cfg.ForkChoiceStore.ParentRoot(root)
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []consensusblocks.ROBlo
|
||||
b := blks[0].Block()
|
||||
|
||||
// Retrieve incoming block's pre state.
|
||||
if err := s.verifyBlkPreState(ctx, b); err != nil {
|
||||
if err := s.verifyBlkPreState(ctx, b.ParentRoot()); err != nil {
|
||||
return err
|
||||
}
|
||||
preState, err := s.cfg.StateGen.StateByRootInitialSync(ctx, b.ParentRoot())
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
@@ -285,7 +286,7 @@ func (s *Service) getBlockPreState(ctx context.Context, b interfaces.ReadOnlyBea
|
||||
defer span.End()
|
||||
|
||||
// Verify incoming block has a valid pre state.
|
||||
if err := s.verifyBlkPreState(ctx, b); err != nil {
|
||||
if err := s.verifyBlkPreState(ctx, b.ParentRoot()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -311,11 +312,10 @@ func (s *Service) getBlockPreState(ctx context.Context, b interfaces.ReadOnlyBea
|
||||
}
|
||||
|
||||
// verifyBlkPreState validates input block has a valid pre-state.
|
||||
func (s *Service) verifyBlkPreState(ctx context.Context, b interfaces.ReadOnlyBeaconBlock) error {
|
||||
func (s *Service) verifyBlkPreState(ctx context.Context, parentRoot [field_params.RootLength]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "blockChain.verifyBlkPreState")
|
||||
defer span.End()
|
||||
|
||||
parentRoot := b.ParentRoot()
|
||||
// Loosen the check to HasBlock because state summary gets saved in batches
|
||||
// during initial syncing. There's no risk given a state summary object is just a
|
||||
// subset of the block object.
|
||||
|
||||
@@ -117,7 +117,7 @@ func TestCachedPreState_CanGetFromStateSummary(t *testing.T) {
|
||||
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Slot: 1, Root: root[:]}))
|
||||
require.NoError(t, service.cfg.StateGen.SaveState(ctx, root, st))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, wsb.Block()))
|
||||
require.NoError(t, service.verifyBlkPreState(ctx, wsb.Block().ParentRoot()))
|
||||
}
|
||||
|
||||
func TestFillForkChoiceMissingBlocks_CanSave(t *testing.T) {
|
||||
|
||||
@@ -77,59 +77,20 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySig
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rob, err := blocks.NewROBlockWithRoot(block, blockRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
preState, err := s.getBlockPreState(ctx, blockCopy.Block())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get block's prestate")
|
||||
}
|
||||
// Save current justified and finalized epochs for future use.
|
||||
currStoreJustifiedEpoch := s.CurrentJustifiedCheckpt().Epoch
|
||||
currStoreFinalizedEpoch := s.FinalizedCheckpt().Epoch
|
||||
currentEpoch := coreTime.CurrentEpoch(preState)
|
||||
|
||||
preStateVersion, preStateHeader, err := getStateVersionAndPayload(preState)
|
||||
currentCheckpoints := s.saveCurrentCheckpoints(preState)
|
||||
postState, isValidPayload, err := s.validateExecutionAndConsensus(ctx, preState, blockCopy, blockRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
var postState state.BeaconState
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
postState, err = s.validateStateTransition(ctx, preState, blockCopy)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to validate consensus state transition function")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
var isValidPayload bool
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
isValidPayload, err = s.validateExecutionOnBlock(ctx, preStateVersion, preStateHeader, blockCopy, blockRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not notify the engine of the new payload")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err := eg.Wait(); err != nil {
|
||||
daWaitedTime, err := s.handleDA(ctx, blockCopy, blockRoot, avs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
daStartTime := time.Now()
|
||||
if avs != nil {
|
||||
if err := avs.IsDataAvailable(ctx, s.CurrentSlot(), rob); err != nil {
|
||||
return errors.Wrap(err, "could not validate blob data availability (AvailabilityStore.IsDataAvailable)")
|
||||
}
|
||||
} else {
|
||||
if err := s.isDataAvailable(ctx, blockRoot, blockCopy); err != nil {
|
||||
return errors.Wrap(err, "could not validate blob data availability")
|
||||
}
|
||||
}
|
||||
daWaitedTime := time.Since(daStartTime)
|
||||
dataAvailWaitedTime.Observe(float64(daWaitedTime.Milliseconds()))
|
||||
|
||||
// Defragment the state before continuing block processing.
|
||||
s.defragmentState(postState)
|
||||
|
||||
@@ -151,29 +112,9 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySig
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
if coreTime.CurrentEpoch(postState) > currentEpoch && s.cfg.ForkChoiceStore.IsCanonical(blockRoot) {
|
||||
headSt, err := s.HeadState(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get head state")
|
||||
}
|
||||
if err := reportEpochMetrics(ctx, postState, headSt); err != nil {
|
||||
log.WithError(err).Error("could not report epoch metrics")
|
||||
}
|
||||
if err := s.updateCheckpoints(ctx, currentCheckpoints, preState, postState, blockRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.updateJustificationOnBlock(ctx, preState, postState, currStoreJustifiedEpoch); err != nil {
|
||||
return errors.Wrap(err, "could not update justified checkpoint")
|
||||
}
|
||||
|
||||
newFinalized, err := s.updateFinalizationOnBlock(ctx, preState, postState, currStoreFinalizedEpoch)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not update finalized checkpoint")
|
||||
}
|
||||
// Send finalized events and finalized deposits in the background
|
||||
if newFinalized {
|
||||
// hook to process all post state finalization tasks
|
||||
s.executePostFinalizationTasks(ctx, postState)
|
||||
}
|
||||
|
||||
// If slasher is configured, forward the attestations in the block via an event feed for processing.
|
||||
if features.Get().EnableSlasher {
|
||||
go s.sendBlockAttestationsToSlasher(blockCopy, preState)
|
||||
@@ -193,31 +134,140 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySig
|
||||
if err := s.handleCaches(); err != nil {
|
||||
return err
|
||||
}
|
||||
s.reportPostBlockProcessing(blockCopy, blockRoot, receivedTime, daWaitedTime)
|
||||
return nil
|
||||
}
|
||||
|
||||
type ffgCheckpoints struct {
|
||||
j, f, c primitives.Epoch
|
||||
}
|
||||
|
||||
func (s *Service) saveCurrentCheckpoints(state state.BeaconState) (cp ffgCheckpoints) {
|
||||
// Save current justified and finalized epochs for future use.
|
||||
cp.j = s.CurrentJustifiedCheckpt().Epoch
|
||||
cp.f = s.FinalizedCheckpt().Epoch
|
||||
cp.c = coreTime.CurrentEpoch(state)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Service) updateCheckpoints(
|
||||
ctx context.Context,
|
||||
cp ffgCheckpoints,
|
||||
preState, postState state.BeaconState,
|
||||
blockRoot [32]byte,
|
||||
) error {
|
||||
if coreTime.CurrentEpoch(postState) > cp.c && s.cfg.ForkChoiceStore.IsCanonical(blockRoot) {
|
||||
headSt, err := s.HeadState(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get head state")
|
||||
}
|
||||
if err := reportEpochMetrics(ctx, postState, headSt); err != nil {
|
||||
log.WithError(err).Error("could not report epoch metrics")
|
||||
}
|
||||
}
|
||||
if err := s.updateJustificationOnBlock(ctx, preState, postState, cp.j); err != nil {
|
||||
return errors.Wrap(err, "could not update justified checkpoint")
|
||||
}
|
||||
|
||||
newFinalized, err := s.updateFinalizationOnBlock(ctx, preState, postState, cp.f)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not update finalized checkpoint")
|
||||
}
|
||||
// Send finalized events and finalized deposits in the background
|
||||
if newFinalized {
|
||||
// hook to process all post state finalization tasks
|
||||
s.executePostFinalizationTasks(ctx, postState)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) validateExecutionAndConsensus(
|
||||
ctx context.Context,
|
||||
preState state.BeaconState,
|
||||
block interfaces.SignedBeaconBlock,
|
||||
blockRoot [32]byte,
|
||||
) (state.BeaconState, bool, error) {
|
||||
preStateVersion, preStateHeader, err := getStateVersionAndPayload(preState)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
var postState state.BeaconState
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
postState, err = s.validateStateTransition(ctx, preState, block)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to validate consensus state transition function")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
var isValidPayload bool
|
||||
eg.Go(func() error {
|
||||
var err error
|
||||
isValidPayload, err = s.validateExecutionOnBlock(ctx, preStateVersion, preStateHeader, block, blockRoot)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not notify the engine of the new payload")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return postState, isValidPayload, nil
|
||||
}
|
||||
|
||||
func (s *Service) handleDA(
|
||||
ctx context.Context,
|
||||
block interfaces.SignedBeaconBlock,
|
||||
blockRoot [32]byte,
|
||||
avs das.AvailabilityStore,
|
||||
) (time.Duration, error) {
|
||||
daStartTime := time.Now()
|
||||
if avs != nil {
|
||||
rob, err := blocks.NewROBlockWithRoot(block, blockRoot)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := avs.IsDataAvailable(ctx, s.CurrentSlot(), rob); err != nil {
|
||||
return 0, errors.Wrap(err, "could not validate blob data availability (AvailabilityStore.IsDataAvailable)")
|
||||
}
|
||||
} else {
|
||||
if err := s.isDataAvailable(ctx, blockRoot, block); err != nil {
|
||||
return 0, errors.Wrap(err, "could not validate blob data availability")
|
||||
}
|
||||
}
|
||||
daWaitedTime := time.Since(daStartTime)
|
||||
dataAvailWaitedTime.Observe(float64(daWaitedTime.Milliseconds()))
|
||||
return daWaitedTime, nil
|
||||
}
|
||||
|
||||
func (s *Service) reportPostBlockProcessing(
|
||||
block interfaces.SignedBeaconBlock,
|
||||
blockRoot [32]byte,
|
||||
receivedTime time.Time,
|
||||
daWaitedTime time.Duration,
|
||||
) {
|
||||
// Reports on block and fork choice metrics.
|
||||
cp := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
|
||||
finalized := ðpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
|
||||
reportSlotMetrics(blockCopy.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized)
|
||||
reportSlotMetrics(block.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized)
|
||||
|
||||
// Log block sync status.
|
||||
cp = s.cfg.ForkChoiceStore.JustifiedCheckpoint()
|
||||
justified := ðpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
|
||||
if err := logBlockSyncStatus(blockCopy.Block(), blockRoot, justified, finalized, receivedTime, uint64(s.genesisTime.Unix()), daWaitedTime); err != nil {
|
||||
if err := logBlockSyncStatus(block.Block(), blockRoot, justified, finalized, receivedTime, uint64(s.genesisTime.Unix()), daWaitedTime); err != nil {
|
||||
log.WithError(err).Error("Unable to log block sync status")
|
||||
}
|
||||
// Log payload data
|
||||
if err := logPayload(blockCopy.Block()); err != nil {
|
||||
if err := logPayload(block.Block()); err != nil {
|
||||
log.WithError(err).Error("Unable to log debug block payload data")
|
||||
}
|
||||
// Log state transition data.
|
||||
if err := logStateTransitionData(blockCopy.Block()); err != nil {
|
||||
if err := logStateTransitionData(block.Block()); err != nil {
|
||||
log.WithError(err).Error("Unable to log state transition data")
|
||||
}
|
||||
|
||||
timeWithoutDaWait := time.Since(receivedTime) - daWaitedTime
|
||||
chainServiceProcessingTime.Observe(float64(timeWithoutDaWait.Milliseconds()))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) executePostFinalizationTasks(ctx context.Context, finalizedState state.BeaconState) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
package blocks
|
||||
|
||||
var ProcessBLSToExecutionChange = processBLSToExecutionChange
|
||||
|
||||
var VerifyBlobCommitmentCount = verifyBlobCommitmentCount
|
||||
|
||||
@@ -2,11 +2,13 @@ package blocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
@@ -200,13 +202,13 @@ func ValidatePayload(st state.BeaconState, payload interfaces.ExecutionData) err
|
||||
// block_hash=payload.block_hash,
|
||||
// transactions_root=hash_tree_root(payload.transactions),
|
||||
// )
|
||||
func ProcessPayload(st state.BeaconState, payload interfaces.ExecutionData) (state.BeaconState, error) {
|
||||
var err error
|
||||
if st.Version() >= version.Capella {
|
||||
st, err = ProcessWithdrawals(st, payload)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process withdrawals")
|
||||
}
|
||||
func ProcessPayload(st state.BeaconState, body interfaces.ReadOnlyBeaconBlockBody) (state.BeaconState, error) {
|
||||
payload, err := body.Execution()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := verifyBlobCommitmentCount(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ValidatePayloadWhenMergeCompletes(st, payload); err != nil {
|
||||
return nil, err
|
||||
@@ -220,70 +222,20 @@ func ProcessPayload(st state.BeaconState, payload interfaces.ExecutionData) (sta
|
||||
return st, nil
|
||||
}
|
||||
|
||||
// ValidatePayloadHeaderWhenMergeCompletes validates the payload header when the merge completes.
|
||||
func ValidatePayloadHeaderWhenMergeCompletes(st state.BeaconState, header interfaces.ExecutionData) error {
|
||||
// Skip validation if the state is not merge compatible.
|
||||
complete, err := IsMergeTransitionComplete(st)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !complete {
|
||||
func verifyBlobCommitmentCount(body interfaces.ReadOnlyBeaconBlockBody) error {
|
||||
if body.Version() < version.Deneb {
|
||||
return nil
|
||||
}
|
||||
// Validate current header's parent hash matches state header's block hash.
|
||||
h, err := st.LatestExecutionPayloadHeader()
|
||||
kzgs, err := body.BlobKzgCommitments()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(header.ParentHash(), h.BlockHash()) {
|
||||
return ErrInvalidPayloadBlockHash
|
||||
if len(kzgs) > field_params.MaxBlobsPerBlock {
|
||||
return fmt.Errorf("too many kzg commitments in block: %d", len(kzgs))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidatePayloadHeader validates the payload header.
|
||||
func ValidatePayloadHeader(st state.BeaconState, header interfaces.ExecutionData) error {
|
||||
// Validate header's random mix matches with state in current epoch
|
||||
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(header.PrevRandao(), random) {
|
||||
return ErrInvalidPayloadPrevRandao
|
||||
}
|
||||
|
||||
// Validate header's timestamp matches with state in current slot.
|
||||
t, err := slots.ToTime(st.GenesisTime(), st.Slot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if header.Timestamp() != uint64(t.Unix()) {
|
||||
return ErrInvalidPayloadTimeStamp
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProcessPayloadHeader processes the payload header.
|
||||
func ProcessPayloadHeader(st state.BeaconState, header interfaces.ExecutionData) (state.BeaconState, error) {
|
||||
var err error
|
||||
if st.Version() >= version.Capella {
|
||||
st, err = ProcessWithdrawals(st, header)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process withdrawals")
|
||||
}
|
||||
}
|
||||
if err := ValidatePayloadHeaderWhenMergeCompletes(st, header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ValidatePayloadHeader(st, header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := st.SetLatestExecutionPayloadHeader(header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
// GetBlockPayloadHash returns the hash of the execution payload of the block
|
||||
func GetBlockPayloadHash(blk interfaces.ReadOnlyBeaconBlock) ([32]byte, error) {
|
||||
var payloadHash [32]byte
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package blocks_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/ssz"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
@@ -581,14 +583,18 @@ func Test_ProcessPayload(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
wrappedPayload, err := consensusblocks.WrappedExecutionPayload(tt.payload)
|
||||
body, err := consensusblocks.NewBeaconBlockBody(ðpb.BeaconBlockBodyBellatrix{
|
||||
ExecutionPayload: tt.payload,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
st, err := blocks.ProcessPayload(st, wrappedPayload)
|
||||
st, err := blocks.ProcessPayload(st, body)
|
||||
if err != nil {
|
||||
require.Equal(t, tt.err.Error(), err.Error())
|
||||
} else {
|
||||
require.Equal(t, tt.err, err)
|
||||
want, err := consensusblocks.PayloadToHeader(wrappedPayload)
|
||||
payload, err := body.Execution()
|
||||
require.NoError(t, err)
|
||||
want, err := consensusblocks.PayloadToHeader(payload)
|
||||
require.Equal(t, tt.err, err)
|
||||
h, err := st.LatestExecutionPayloadHeader()
|
||||
require.NoError(t, err)
|
||||
@@ -609,13 +615,15 @@ func Test_ProcessPayloadCapella(t *testing.T) {
|
||||
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
||||
require.NoError(t, err)
|
||||
payload.PrevRandao = random
|
||||
wrapped, err := consensusblocks.WrappedExecutionPayloadCapella(payload)
|
||||
body, err := consensusblocks.NewBeaconBlockBody(ðpb.BeaconBlockBodyCapella{
|
||||
ExecutionPayload: payload,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = blocks.ProcessPayload(st, wrapped)
|
||||
_, err = blocks.ProcessPayload(st, body)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func Test_ProcessPayloadHeader(t *testing.T) {
|
||||
func Test_ProcessPayload_Blinded(t *testing.T) {
|
||||
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
||||
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
||||
require.NoError(t, err)
|
||||
@@ -663,7 +671,13 @@ func Test_ProcessPayloadHeader(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
st, err := blocks.ProcessPayloadHeader(st, tt.header)
|
||||
p, ok := tt.header.Proto().(*enginev1.ExecutionPayloadHeader)
|
||||
require.Equal(t, true, ok)
|
||||
body, err := consensusblocks.NewBeaconBlockBody(ðpb.BlindedBeaconBlockBodyBellatrix{
|
||||
ExecutionPayloadHeader: p,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
st, err := blocks.ProcessPayload(st, body)
|
||||
if err != nil {
|
||||
require.Equal(t, tt.err.Error(), err.Error())
|
||||
} else {
|
||||
@@ -728,7 +742,7 @@ func Test_ValidatePayloadHeader(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err = blocks.ValidatePayloadHeader(st, tt.header)
|
||||
err = blocks.ValidatePayload(st, tt.header)
|
||||
require.Equal(t, tt.err, err)
|
||||
})
|
||||
}
|
||||
@@ -785,7 +799,7 @@ func Test_ValidatePayloadHeaderWhenMergeCompletes(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err = blocks.ValidatePayloadHeaderWhenMergeCompletes(tt.state, tt.header)
|
||||
err = blocks.ValidatePayloadWhenMergeCompletes(tt.state, tt.header)
|
||||
require.Equal(t, tt.err, err)
|
||||
})
|
||||
}
|
||||
@@ -906,3 +920,15 @@ func emptyPayloadCapella() *enginev1.ExecutionPayloadCapella {
|
||||
Withdrawals: make([]*enginev1.Withdrawal, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyBlobCommitmentCount(t *testing.T) {
|
||||
b := ðpb.BeaconBlockDeneb{Body: ðpb.BeaconBlockBodyDeneb{}}
|
||||
rb, err := consensusblocks.NewBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, blocks.VerifyBlobCommitmentCount(rb.Body()))
|
||||
|
||||
b = ðpb.BeaconBlockDeneb{Body: ðpb.BeaconBlockBodyDeneb{BlobKzgCommitments: make([][]byte, fieldparams.MaxBlobsPerBlock+1)}}
|
||||
rb, err = consensusblocks.NewBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
require.ErrorContains(t, fmt.Sprintf("too many kzg commitments in block: %d", fieldparams.MaxBlobsPerBlock+1), blocks.VerifyBlobCommitmentCount(rb.Body()))
|
||||
}
|
||||
|
||||
@@ -22,29 +22,31 @@ var (
|
||||
//
|
||||
// Spec definition:
|
||||
//
|
||||
// def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||
// # [Modified in Electra:EIP6110]
|
||||
// # Disable former deposit mechanism once all prior deposits are processed
|
||||
// eth1_deposit_index_limit = min(state.eth1_data.deposit_count, state.deposit_requests_start_index)
|
||||
// if state.eth1_deposit_index < eth1_deposit_index_limit:
|
||||
// assert len(body.deposits) == min(MAX_DEPOSITS, eth1_deposit_index_limit - state.eth1_deposit_index)
|
||||
// else:
|
||||
// assert len(body.deposits) == 0
|
||||
// def process_operations(state: BeaconState, body: BeaconBlockBody) -> None:
|
||||
// # [Modified in Electra:EIP6110]
|
||||
// # Disable former deposit mechanism once all prior deposits are processed
|
||||
// eth1_deposit_index_limit = min(state.eth1_data.deposit_count, state.deposit_requests_start_index)
|
||||
// if state.eth1_deposit_index < eth1_deposit_index_limit:
|
||||
// assert len(body.deposits) == min(MAX_DEPOSITS, eth1_deposit_index_limit - state.eth1_deposit_index)
|
||||
// else:
|
||||
// assert len(body.deposits) == 0
|
||||
//
|
||||
// def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None:
|
||||
// for operation in operations:
|
||||
// fn(state, operation)
|
||||
// def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -> None:
|
||||
// for operation in operations:
|
||||
// fn(state, operation)
|
||||
//
|
||||
// for_ops(body.proposer_slashings, process_proposer_slashing)
|
||||
// for_ops(body.attester_slashings, process_attester_slashing)
|
||||
// for_ops(body.attestations, process_attestation) # [Modified in Electra:EIP7549]
|
||||
// for_ops(body.deposits, process_deposit) # [Modified in Electra:EIP7251]
|
||||
// for_ops(body.voluntary_exits, process_voluntary_exit) # [Modified in Electra:EIP7251]
|
||||
// for_ops(body.bls_to_execution_changes, process_bls_to_execution_change)
|
||||
// # [New in Electra:EIP7002:EIP7251]
|
||||
// for_ops(body.execution_payload.withdrawal_requests, process_execution_layer_withdrawal_request)
|
||||
// for_ops(body.execution_payload.deposit_requests, process_deposit_requests) # [New in Electra:EIP6110]
|
||||
// for_ops(body.consolidations, process_consolidation) # [New in Electra:EIP7251]
|
||||
// for_ops(body.proposer_slashings, process_proposer_slashing)
|
||||
// for_ops(body.attester_slashings, process_attester_slashing)
|
||||
// for_ops(body.attestations, process_attestation) # [Modified in Electra:EIP7549]
|
||||
// for_ops(body.deposits, process_deposit) # [Modified in Electra:EIP7251]
|
||||
// for_ops(body.voluntary_exits, process_voluntary_exit) # [Modified in Electra:EIP7251]
|
||||
// for_ops(body.bls_to_execution_changes, process_bls_to_execution_change)
|
||||
// for_ops(body.execution_payload.deposit_requests, process_deposit_request) # [New in Electra:EIP6110]
|
||||
// # [New in Electra:EIP7002:EIP7251]
|
||||
// for_ops(body.execution_payload.withdrawal_requests, process_withdrawal_request)
|
||||
// # [New in Electra:EIP7251]
|
||||
// for_ops(body.execution_payload.consolidation_requests, process_consolidation_request)
|
||||
|
||||
func ProcessOperations(
|
||||
ctx context.Context,
|
||||
st state.BeaconState,
|
||||
@@ -84,16 +86,14 @@ func ProcessOperations(
|
||||
if !ok {
|
||||
return nil, errors.New("could not cast execution data to electra execution data")
|
||||
}
|
||||
st, err = ProcessWithdrawalRequests(ctx, st, exe.WithdrawalRequests())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process execution layer withdrawal requests")
|
||||
}
|
||||
|
||||
st, err = ProcessDepositRequests(ctx, st, exe.DepositRequests())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process deposit receipts")
|
||||
}
|
||||
|
||||
st, err = ProcessWithdrawalRequests(ctx, st, exe.WithdrawalRequests())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process execution layer withdrawal requests")
|
||||
}
|
||||
if err := ProcessConsolidationRequests(ctx, st, exe.ConsolidationRequests()); err != nil {
|
||||
return nil, fmt.Errorf("could not process consolidation requests: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package electra_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
@@ -47,3 +51,68 @@ func TestVerifyOperationLengths_Electra(t *testing.T) {
|
||||
require.ErrorContains(t, "incorrect outstanding deposits in block body", err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestProcessEpoch_CanProcessElectra(t *testing.T) {
|
||||
st, _ := util.DeterministicGenesisStateElectra(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
||||
require.NoError(t, st.SetSlot(10*params.BeaconConfig().SlotsPerEpoch))
|
||||
require.NoError(t, st.SetDepositBalanceToConsume(100))
|
||||
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
|
||||
deps := make([]*ethpb.PendingBalanceDeposit, 20)
|
||||
for i := 0; i < len(deps); i += 1 {
|
||||
deps[i] = ðpb.PendingBalanceDeposit{
|
||||
Amount: uint64(amountAvailForProcessing) / 10,
|
||||
Index: primitives.ValidatorIndex(i),
|
||||
}
|
||||
}
|
||||
require.NoError(t, st.SetPendingBalanceDeposits(deps))
|
||||
require.NoError(t, st.SetPendingConsolidations([]*ethpb.PendingConsolidation{
|
||||
{
|
||||
SourceIndex: 2,
|
||||
TargetIndex: 3,
|
||||
},
|
||||
{
|
||||
SourceIndex: 0,
|
||||
TargetIndex: 1,
|
||||
},
|
||||
}))
|
||||
err := electra.ProcessEpoch(context.Background(), st)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(0), st.Slashings()[2], "Unexpected slashed balance")
|
||||
|
||||
b := st.Balances()
|
||||
require.Equal(t, params.BeaconConfig().MaxValidatorsPerCommittee, uint64(len(b)))
|
||||
require.Equal(t, uint64(44799839993), b[0])
|
||||
|
||||
s, err := st.InactivityScores()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MaxValidatorsPerCommittee, uint64(len(s)))
|
||||
|
||||
p, err := st.PreviousEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MaxValidatorsPerCommittee, uint64(len(p)))
|
||||
|
||||
p, err = st.CurrentEpochParticipation()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MaxValidatorsPerCommittee, uint64(len(p)))
|
||||
|
||||
sc, err := st.CurrentSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().SyncCommitteeSize, uint64(len(sc.Pubkeys)))
|
||||
|
||||
sc, err = st.NextSyncCommittee()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().SyncCommitteeSize, uint64(len(sc.Pubkeys)))
|
||||
|
||||
res, err := st.DepositBalanceToConsume()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, primitives.Gwei(100), res)
|
||||
|
||||
// Half of the balance deposits should have been processed.
|
||||
remaining, err := st.PendingBalanceDeposits()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 10, len(remaining))
|
||||
|
||||
num, err := st.NumPendingConsolidations()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(2), num)
|
||||
}
|
||||
|
||||
@@ -82,6 +82,47 @@ func AttestationCommittees(ctx context.Context, st state.ReadOnlyBeaconState, at
|
||||
return committees, nil
|
||||
}
|
||||
|
||||
// BeaconCommittees returns the list of all beacon committees for a given state at a given slot.
|
||||
func BeaconCommittees(ctx context.Context, state state.ReadOnlyBeaconState, slot primitives.Slot) ([][]primitives.ValidatorIndex, error) {
|
||||
epoch := slots.ToEpoch(slot)
|
||||
activeCount, err := ActiveValidatorCount(ctx, state, epoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute active validator count")
|
||||
}
|
||||
committeesPerSlot := SlotCommitteeCount(activeCount)
|
||||
seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get seed")
|
||||
}
|
||||
|
||||
committees := make([][]primitives.ValidatorIndex, committeesPerSlot)
|
||||
var activeIndices []primitives.ValidatorIndex
|
||||
|
||||
for idx := primitives.CommitteeIndex(0); idx < primitives.CommitteeIndex(len(committees)); idx++ {
|
||||
committee, err := committeeCache.Committee(ctx, slot, seed, idx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not interface with committee cache")
|
||||
}
|
||||
if committee != nil {
|
||||
committees[idx] = committee
|
||||
continue
|
||||
}
|
||||
|
||||
if len(activeIndices) == 0 {
|
||||
activeIndices, err = ActiveValidatorIndices(ctx, state, epoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get active indices")
|
||||
}
|
||||
}
|
||||
committee, err = BeaconCommittee(ctx, activeIndices, seed, slot, idx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute beacon committee")
|
||||
}
|
||||
committees[idx] = committee
|
||||
}
|
||||
return committees, nil
|
||||
}
|
||||
|
||||
// BeaconCommitteeFromState returns the crosslink committee of a given slot and committee index. This
|
||||
// is a spec implementation where state is used as an argument. In case of state retrieval
|
||||
// becomes expensive, consider using BeaconCommittee below.
|
||||
@@ -253,36 +294,22 @@ func CommitteeAssignments(ctx context.Context, state state.BeaconState, epoch pr
|
||||
if err := verifyAssignmentEpoch(epoch, state); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Retrieve active validator count for the specified epoch.
|
||||
activeValidatorCount, err := ActiveValidatorCount(ctx, state, epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Determine the number of committees per slot based on the number of active validator indices.
|
||||
numCommitteesPerSlot := SlotCommitteeCount(activeValidatorCount)
|
||||
|
||||
startSlot, err := slots.EpochStart(epoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
assignments := make(map[primitives.ValidatorIndex]*CommitteeAssignment)
|
||||
vals := make(map[primitives.ValidatorIndex]struct{})
|
||||
for _, v := range validators {
|
||||
vals[v] = struct{}{}
|
||||
}
|
||||
|
||||
assignments := make(map[primitives.ValidatorIndex]*CommitteeAssignment)
|
||||
// Compute committee assignments for each slot in the epoch.
|
||||
for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ {
|
||||
// Compute committees for the current slot.
|
||||
for j := uint64(0); j < numCommitteesPerSlot; j++ {
|
||||
committee, err := BeaconCommitteeFromState(ctx, state, slot, primitives.CommitteeIndex(j))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
committees, err := BeaconCommittees(ctx, state, slot)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute beacon committees")
|
||||
}
|
||||
for j, committee := range committees {
|
||||
for _, vIndex := range committee {
|
||||
if _, ok := vals[vIndex]; !ok { // Skip if the validator is not in the provided validators slice.
|
||||
continue
|
||||
@@ -296,7 +323,6 @@ func CommitteeAssignments(ctx context.Context, state state.BeaconState, epoch pr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return assignments, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
)
|
||||
|
||||
@@ -749,3 +750,27 @@ func TestAttestationCommittees(t *testing.T) {
|
||||
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[1])))
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeaconCommittees(t *testing.T) {
|
||||
prevConfig := params.BeaconConfig().Copy()
|
||||
defer params.OverrideBeaconConfig(prevConfig)
|
||||
c := params.BeaconConfig().Copy()
|
||||
c.MinGenesisActiveValidatorCount = 128
|
||||
c.SlotsPerEpoch = 4
|
||||
c.TargetCommitteeSize = 16
|
||||
params.OverrideBeaconConfig(c)
|
||||
|
||||
state, _ := util.DeterministicGenesisState(t, 256)
|
||||
|
||||
activeCount, err := helpers.ActiveValidatorCount(context.Background(), state, 0)
|
||||
require.NoError(t, err)
|
||||
committeesPerSlot := helpers.SlotCommitteeCount(activeCount)
|
||||
committees, err := helpers.BeaconCommittees(context.Background(), state, 0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, committeesPerSlot, uint64(len(committees)))
|
||||
for idx := primitives.CommitteeIndex(0); idx < primitives.CommitteeIndex(len(committees)); idx++ {
|
||||
committee, err := helpers.BeaconCommitteeFromState(context.Background(), state, 0, idx)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, committees[idx], committee)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ import (
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
type customProcessingFn func(context.Context, state.BeaconState) error
|
||||
|
||||
// ExecuteStateTransition defines the procedure for a state transition function.
|
||||
//
|
||||
// Note: This method differs from the spec pseudocode as it uses a batch signature verification.
|
||||
@@ -173,18 +175,7 @@ func ProcessSlotsIfPossible(ctx context.Context, state state.BeaconState, target
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// ProcessSlots process through skip slots and apply epoch transition when it's needed
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
//
|
||||
// def process_slots(state: BeaconState, slot: Slot) -> None:
|
||||
// assert state.slot < slot
|
||||
// while state.slot < slot:
|
||||
// process_slot(state)
|
||||
// # Process epoch on the start slot of the next epoch
|
||||
// if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
|
||||
// process_epoch(state)
|
||||
// state.slot = Slot(state.slot + 1)
|
||||
// ProcessSlots includes core slot processing as well as a cache
|
||||
func ProcessSlots(ctx context.Context, state state.BeaconState, slot primitives.Slot) (state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "core.state.ProcessSlots")
|
||||
defer span.End()
|
||||
@@ -231,42 +222,63 @@ func ProcessSlots(ctx context.Context, state state.BeaconState, slot primitives.
|
||||
defer func() {
|
||||
SkipSlotCache.MarkNotInProgress(key)
|
||||
}()
|
||||
state, err = ProcessSlotsCore(ctx, span, state, slot, cacheBestBeaconStateOnErrFn(highestSlot, key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if highestSlot < state.Slot() {
|
||||
SkipSlotCache.Put(ctx, key, state)
|
||||
}
|
||||
|
||||
for state.Slot() < slot {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func cacheBestBeaconStateOnErrFn(highestSlot primitives.Slot, key [32]byte) customProcessingFn {
|
||||
return func(ctx context.Context, state state.BeaconState) error {
|
||||
if ctx.Err() != nil {
|
||||
tracing.AnnotateError(span, ctx.Err())
|
||||
// Cache last best value.
|
||||
if highestSlot < state.Slot() {
|
||||
if SkipSlotCache.Put(ctx, key, state); err != nil {
|
||||
log.WithError(err).Error("Failed to put skip slot cache value")
|
||||
}
|
||||
SkipSlotCache.Put(ctx, key, state)
|
||||
}
|
||||
return ctx.Err()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessSlotsCore process through skip slots and apply epoch transition when it's needed
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
//
|
||||
// def process_slots(state: BeaconState, slot: Slot) -> None:
|
||||
// assert state.slot < slot
|
||||
// while state.slot < slot:
|
||||
// process_slot(state)
|
||||
// # Process epoch on the start slot of the next epoch
|
||||
// if (state.slot + 1) % SLOTS_PER_EPOCH == 0:
|
||||
// process_epoch(state)
|
||||
// state.slot = Slot(state.slot + 1)
|
||||
func ProcessSlotsCore(ctx context.Context, span *trace.Span, state state.BeaconState, slot primitives.Slot, fn customProcessingFn) (state.BeaconState, error) {
|
||||
var err error
|
||||
for state.Slot() < slot {
|
||||
if fn != nil {
|
||||
if err = fn(ctx, state); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
state, err = ProcessSlot(ctx, state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(err, "could not process slot")
|
||||
}
|
||||
if time.CanProcessEpoch(state) {
|
||||
if state.Version() == version.Phase0 {
|
||||
state, err = ProcessEpochPrecompute(ctx, state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(err, "could not process epoch with optimizations")
|
||||
}
|
||||
} else if state.Version() <= version.Deneb {
|
||||
if err = altair.ProcessEpoch(ctx, state); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("could not process %s epoch", version.String(state.Version())))
|
||||
}
|
||||
} else {
|
||||
if err = electra.ProcessEpoch(ctx, state); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("could not process %s epoch", version.String(state.Version())))
|
||||
}
|
||||
}
|
||||
|
||||
state, err = ProcessEpoch(ctx, state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := state.SetSlot(state.Slot() + 1); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(err, "failed to increment state slot")
|
||||
@@ -278,25 +290,46 @@ func ProcessSlots(ctx context.Context, state state.BeaconState, slot primitives.
|
||||
return nil, errors.Wrap(err, "failed to upgrade state")
|
||||
}
|
||||
}
|
||||
|
||||
if highestSlot < state.Slot() {
|
||||
SkipSlotCache.Put(ctx, key, state)
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// ProcessEpoch is a wrapper on fork specific epoch processing
|
||||
func ProcessEpoch(ctx context.Context, state state.BeaconState) (state.BeaconState, error) {
|
||||
var err error
|
||||
if time.CanProcessEpoch(state) {
|
||||
if state.Version() == version.Electra {
|
||||
if err = electra.ProcessEpoch(ctx, state); err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("could not process %s epoch", version.String(state.Version())))
|
||||
}
|
||||
} else if state.Version() >= version.Altair {
|
||||
if err = altair.ProcessEpoch(ctx, state); err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("could not process %s epoch", version.String(state.Version())))
|
||||
}
|
||||
} else {
|
||||
state, err = ProcessEpochPrecompute(ctx, state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process epoch with optimizations")
|
||||
}
|
||||
}
|
||||
}
|
||||
return state, err
|
||||
}
|
||||
|
||||
// UpgradeState upgrades the state to the next version if possible.
|
||||
func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "core.state.UpgradeState")
|
||||
defer span.End()
|
||||
|
||||
var err error
|
||||
upgraded := false
|
||||
|
||||
if time.CanUpgradeToAltair(state.Slot()) {
|
||||
state, err = altair.UpgradeToAltair(ctx, state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
upgraded = true
|
||||
}
|
||||
|
||||
if time.CanUpgradeToBellatrix(state.Slot()) {
|
||||
@@ -305,6 +338,7 @@ func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconSta
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
upgraded = true
|
||||
}
|
||||
|
||||
if time.CanUpgradeToCapella(state.Slot()) {
|
||||
@@ -313,6 +347,7 @@ func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconSta
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
upgraded = true
|
||||
}
|
||||
|
||||
if time.CanUpgradeToDeneb(state.Slot()) {
|
||||
@@ -321,6 +356,7 @@ func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconSta
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
upgraded = true
|
||||
}
|
||||
|
||||
if time.CanUpgradeToElectra(state.Slot()) {
|
||||
@@ -329,7 +365,13 @@ func UpgradeState(ctx context.Context, state state.BeaconState) (state.BeaconSta
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
upgraded = true
|
||||
}
|
||||
|
||||
if upgraded {
|
||||
log.Debugf("upgraded state to %s", version.String(state.Version()))
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition/interop"
|
||||
v "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
|
||||
@@ -328,20 +327,18 @@ func ProcessBlockForStateRoot(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if blk.IsBlinded() {
|
||||
state, err = b.ProcessPayloadHeader(state, executionData)
|
||||
} else {
|
||||
state, err = b.ProcessPayload(state, executionData)
|
||||
if state.Version() >= version.Capella {
|
||||
state, err = b.ProcessWithdrawals(state, executionData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process withdrawals")
|
||||
}
|
||||
}
|
||||
state, err = b.ProcessPayload(state, blk.Body())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process execution data")
|
||||
}
|
||||
}
|
||||
|
||||
if err := VerifyBlobCommitmentCount(blk); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
randaoReveal := signed.Block().Body().RandaoReveal()
|
||||
state, err = b.ProcessRandaoNoVerify(state, randaoReveal[:])
|
||||
if err != nil {
|
||||
@@ -377,20 +374,6 @@ func ProcessBlockForStateRoot(
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func VerifyBlobCommitmentCount(blk interfaces.ReadOnlyBeaconBlock) error {
|
||||
if blk.Version() < version.Deneb {
|
||||
return nil
|
||||
}
|
||||
kzgs, err := blk.Body().BlobKzgCommitments()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(kzgs) > field_params.MaxBlobsPerBlock {
|
||||
return fmt.Errorf("too many kzg commitments in block: %d", len(kzgs))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// This calls altair block operations.
|
||||
func altairOperations(
|
||||
ctx context.Context,
|
||||
|
||||
@@ -2,13 +2,11 @@ package transition_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
@@ -212,15 +210,3 @@ func TestProcessBlockDifferentVersion(t *testing.T) {
|
||||
_, _, err = transition.ProcessBlockNoVerifyAnySig(context.Background(), beaconState, wsb)
|
||||
require.ErrorContains(t, "state and block are different version. 0 != 1", err)
|
||||
}
|
||||
|
||||
func TestVerifyBlobCommitmentCount(t *testing.T) {
|
||||
b := ðpb.BeaconBlockDeneb{Body: ðpb.BeaconBlockBodyDeneb{}}
|
||||
rb, err := blocks.NewBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, transition.VerifyBlobCommitmentCount(rb))
|
||||
|
||||
b = ðpb.BeaconBlockDeneb{Body: ðpb.BeaconBlockBodyDeneb{BlobKzgCommitments: make([][]byte, field_params.MaxBlobsPerBlock+1)}}
|
||||
rb, err = blocks.NewBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
require.ErrorContains(t, fmt.Sprintf("too many kzg commitments in block: %d", field_params.MaxBlobsPerBlock+1), transition.VerifyBlobCommitmentCount(rb))
|
||||
}
|
||||
|
||||
@@ -84,11 +84,15 @@ func (s *mockEngine) callCount(method string) int {
|
||||
}
|
||||
|
||||
func mockParseUintList(t *testing.T, data json.RawMessage) []uint64 {
|
||||
var list []uint64
|
||||
var list []string
|
||||
if err := json.Unmarshal(data, &list); err != nil {
|
||||
t.Fatalf("failed to parse uint list: %v", err)
|
||||
}
|
||||
return list
|
||||
uints := make([]uint64, len(list))
|
||||
for i, u := range list {
|
||||
uints[i] = hexutil.MustDecodeUint64(u)
|
||||
}
|
||||
return uints
|
||||
}
|
||||
|
||||
func mockParseHexByteList(t *testing.T, data json.RawMessage) []hexutil.Bytes {
|
||||
@@ -117,7 +121,7 @@ func TestParseRequest(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cases := []struct {
|
||||
method string
|
||||
uintArgs []uint64
|
||||
hexArgs []string // uint64 as hex
|
||||
byteArgs []hexutil.Bytes
|
||||
}{
|
||||
{
|
||||
@@ -135,26 +139,28 @@ func TestParseRequest(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
method: GetPayloadBodiesByRangeV1,
|
||||
uintArgs: []uint64{0, 1},
|
||||
method: GetPayloadBodiesByRangeV1,
|
||||
hexArgs: []string{hexutil.EncodeUint64(0), hexutil.EncodeUint64(1)},
|
||||
},
|
||||
{
|
||||
method: GetPayloadBodiesByRangeV2,
|
||||
uintArgs: []uint64{math.MaxUint64, 1},
|
||||
method: GetPayloadBodiesByRangeV2,
|
||||
hexArgs: []string{hexutil.EncodeUint64(math.MaxUint64), hexutil.EncodeUint64(1)},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.method, func(t *testing.T) {
|
||||
cli, srv := newMockEngine(t)
|
||||
srv.register(c.method, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) {
|
||||
srv.register(c.method, func(msg *jsonrpcMessage, w http.ResponseWriter, _ *http.Request) {
|
||||
require.Equal(t, c.method, msg.Method)
|
||||
nr := uint64(len(c.byteArgs))
|
||||
if len(c.byteArgs) > 0 {
|
||||
require.DeepEqual(t, c.byteArgs, mockParseHexByteList(t, msg.Params))
|
||||
}
|
||||
if len(c.uintArgs) > 0 {
|
||||
if len(c.hexArgs) > 0 {
|
||||
rang := mockParseUintList(t, msg.Params)
|
||||
require.DeepEqual(t, c.uintArgs, rang)
|
||||
for i, r := range rang {
|
||||
require.Equal(t, c.hexArgs[i], hexutil.EncodeUint64(r))
|
||||
}
|
||||
nr = rang[1]
|
||||
}
|
||||
mockWriteResult(t, w, msg, make([]*pb.ExecutionPayloadBody, nr))
|
||||
@@ -165,18 +171,18 @@ func TestParseRequest(t *testing.T) {
|
||||
if len(c.byteArgs) > 0 {
|
||||
args = []interface{}{c.byteArgs}
|
||||
}
|
||||
if len(c.uintArgs) > 0 {
|
||||
args = make([]interface{}, len(c.uintArgs))
|
||||
for i := range c.uintArgs {
|
||||
args[i] = c.uintArgs[i]
|
||||
if len(c.hexArgs) > 0 {
|
||||
args = make([]interface{}, len(c.hexArgs))
|
||||
for i := range c.hexArgs {
|
||||
args[i] = c.hexArgs[i]
|
||||
}
|
||||
}
|
||||
require.NoError(t, cli.CallContext(ctx, &result, c.method, args...))
|
||||
if len(c.byteArgs) > 0 {
|
||||
require.Equal(t, len(c.byteArgs), len(result))
|
||||
}
|
||||
if len(c.uintArgs) > 0 {
|
||||
require.Equal(t, int(c.uintArgs[1]), len(result))
|
||||
if len(c.hexArgs) > 0 {
|
||||
require.Equal(t, int(hexutil.MustDecodeUint64(c.hexArgs[1])), len(result))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -203,7 +209,7 @@ func TestCallCount(t *testing.T) {
|
||||
for _, c := range cases {
|
||||
t.Run(c.method, func(t *testing.T) {
|
||||
cli, srv := newMockEngine(t)
|
||||
srv.register(c.method, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) {
|
||||
srv.register(c.method, func(msg *jsonrpcMessage, w http.ResponseWriter, _ *http.Request) {
|
||||
mockWriteResult(t, w, msg, nil)
|
||||
})
|
||||
for i := 0; i < c.count; i++ {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
@@ -160,7 +161,7 @@ func computeRanges(hbns []hashBlockNumber) []byRangeReq {
|
||||
|
||||
func (r *blindedBlockReconstructor) requestBodiesByRange(ctx context.Context, client RPCClient, method string, req byRangeReq) error {
|
||||
result := make([]*pb.ExecutionPayloadBody, 0)
|
||||
if err := client.CallContext(ctx, &result, method, req.start, req.count); err != nil {
|
||||
if err := client.CallContext(ctx, &result, method, hexutil.EncodeUint64(req.start), hexutil.EncodeUint64(req.count)); err != nil {
|
||||
return err
|
||||
}
|
||||
if uint64(len(result)) != req.count {
|
||||
|
||||
@@ -676,3 +676,18 @@ func (f *ForkChoice) TargetRootForEpoch(root [32]byte, epoch primitives.Epoch) (
|
||||
}
|
||||
return f.TargetRootForEpoch(targetNode.root, epoch)
|
||||
}
|
||||
|
||||
// ParentRoot returns the block root of the parent node if it is in forkchoice.
|
||||
// The exception is for the finalized checkpoint root which we return the zero
|
||||
// hash.
|
||||
func (f *ForkChoice) ParentRoot(root [32]byte) ([32]byte, error) {
|
||||
n, ok := f.store.nodeByRoot[root]
|
||||
if !ok || n == nil {
|
||||
return [32]byte{}, ErrNilNode
|
||||
}
|
||||
// Return the zero hash for the tree root
|
||||
if n.parent == nil {
|
||||
return [32]byte{}, nil
|
||||
}
|
||||
return n.parent.root, nil
|
||||
}
|
||||
|
||||
@@ -861,3 +861,29 @@ func TestForkChoiceSlot(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, primitives.Slot(3), slot)
|
||||
}
|
||||
|
||||
func TestForkchoiceParentRoot(t *testing.T) {
|
||||
f := setup(0, 0)
|
||||
ctx := context.Background()
|
||||
root1 := [32]byte{'a'}
|
||||
st, root, err := prepareForkchoiceState(ctx, 3, root1, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 0, 0)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.InsertNode(ctx, st, root))
|
||||
|
||||
root2 := [32]byte{'b'}
|
||||
st, root, err = prepareForkchoiceState(ctx, 3, root2, root1, [32]byte{'A'}, 0, 0)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.InsertNode(ctx, st, root))
|
||||
|
||||
root, err = f.ParentRoot(root2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, root1, root)
|
||||
|
||||
_, err = f.ParentRoot([32]byte{'c'})
|
||||
require.ErrorIs(t, err, ErrNilNode)
|
||||
|
||||
zeroHash := [32]byte{}
|
||||
root, err = f.ParentRoot(zeroHash)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, zeroHash, root)
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ type FastGetter interface {
|
||||
TargetRootForEpoch([32]byte, primitives.Epoch) ([32]byte, error)
|
||||
UnrealizedJustifiedPayloadBlockHash() [32]byte
|
||||
Weight(root [32]byte) (uint64, error)
|
||||
ParentRoot(root [32]byte) ([32]byte, error)
|
||||
}
|
||||
|
||||
// Setter allows to set forkchoice information
|
||||
|
||||
@@ -169,3 +169,10 @@ func (ro *ROForkChoice) TargetRootForEpoch(root [32]byte, epoch primitives.Epoch
|
||||
defer ro.l.RUnlock()
|
||||
return ro.getter.TargetRootForEpoch(root, epoch)
|
||||
}
|
||||
|
||||
// ParentRoot delegates to the underlying forkchoice call, under a lock.
|
||||
func (ro *ROForkChoice) ParentRoot(root [32]byte) ([32]byte, error) {
|
||||
ro.l.RLock()
|
||||
defer ro.l.RUnlock()
|
||||
return ro.getter.ParentRoot(root)
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ const (
|
||||
slotCalled
|
||||
lastRootCalled
|
||||
targetRootForEpochCalled
|
||||
parentRootCalled
|
||||
)
|
||||
|
||||
func _discard(t *testing.T, e error) {
|
||||
@@ -291,3 +292,8 @@ func (ro *mockROForkchoice) TargetRootForEpoch(_ [32]byte, _ primitives.Epoch) (
|
||||
ro.calls = append(ro.calls, targetRootForEpochCalled)
|
||||
return [32]byte{}, nil
|
||||
}
|
||||
|
||||
func (ro *mockROForkchoice) ParentRoot(_ [32]byte) ([32]byte, error) {
|
||||
ro.calls = append(ro.calls, parentRootCalled)
|
||||
return [32]byte{}, nil
|
||||
}
|
||||
|
||||
@@ -73,6 +73,21 @@ func configureBuilderCircuitBreaker(cliCtx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if cliCtx.IsSet(flags.MinBuilderBid.Name) {
|
||||
c := params.BeaconConfig().Copy()
|
||||
c.MinBuilderBid = cliCtx.Uint64(flags.MinBuilderBid.Name)
|
||||
if err := params.SetActive(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if cliCtx.IsSet(flags.MinBuilderDiff.Name) {
|
||||
c := params.BeaconConfig().Copy()
|
||||
c.MinBuilderDiff = cliCtx.Uint64(flags.MinBuilderDiff.Name)
|
||||
if err := params.SetActive(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"beacon.go",
|
||||
"errors.go",
|
||||
"log.go",
|
||||
"service.go",
|
||||
@@ -20,6 +21,8 @@ go_library(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/time:go_default_library",
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/forkchoice/types:go_default_library",
|
||||
"//beacon-chain/operations/synccommittee:go_default_library",
|
||||
"//beacon-chain/p2p:go_default_library",
|
||||
@@ -28,6 +31,7 @@ go_library(
|
||||
"//beacon-chain/sync:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//consensus-types/validator:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
|
||||
128
beacon-chain/rpc/core/beacon.go
Normal file
128
beacon-chain/rpc/core/beacon.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
)
|
||||
|
||||
// Retrieve chain head information from the DB and the current beacon state.
|
||||
func (s *Service) ChainHead(ctx context.Context) (*ethpb.ChainHead, *RpcError) {
|
||||
headBlock, err := s.HeadFetcher.HeadBlock(ctx)
|
||||
if err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrapf(err, "could not get head block"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
if err := consensusblocks.BeaconBlockIsNil(headBlock); err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrapf(err, "head block of chain was nil"),
|
||||
Reason: NotFound,
|
||||
}
|
||||
}
|
||||
optimisticStatus, err := s.OptimisticModeFetcher.IsOptimistic(ctx)
|
||||
if err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrapf(err, "could not get optimistic status"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
headBlockRoot, err := headBlock.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrapf(err, "could not get head block root"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
|
||||
validGenesis := false
|
||||
validateCP := func(cp *ethpb.Checkpoint, name string) error {
|
||||
if bytesutil.ToBytes32(cp.Root) == params.BeaconConfig().ZeroHash && cp.Epoch == 0 {
|
||||
if validGenesis {
|
||||
return nil
|
||||
}
|
||||
// Retrieve genesis block in the event we have genesis checkpoints.
|
||||
genBlock, err := s.BeaconDB.GenesisBlock(ctx)
|
||||
if err != nil || consensusblocks.BeaconBlockIsNil(genBlock) != nil {
|
||||
return errors.New("could not get genesis block")
|
||||
}
|
||||
validGenesis = true
|
||||
return nil
|
||||
}
|
||||
b, err := s.BeaconDB.Block(ctx, bytesutil.ToBytes32(cp.Root))
|
||||
if err != nil {
|
||||
return errors.Errorf("could not get %s block: %v", name, err)
|
||||
}
|
||||
if err := consensusblocks.BeaconBlockIsNil(b); err != nil {
|
||||
return errors.Errorf("could not get %s block: %v", name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
finalizedCheckpoint := s.FinalizedFetcher.FinalizedCheckpt()
|
||||
if err := validateCP(finalizedCheckpoint, "finalized"); err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrap(err, "could not get finalized checkpoint"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
|
||||
justifiedCheckpoint := s.FinalizedFetcher.CurrentJustifiedCheckpt()
|
||||
if err := validateCP(justifiedCheckpoint, "justified"); err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrap(err, "could not get current justified checkpoint"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
|
||||
prevJustifiedCheckpoint := s.FinalizedFetcher.PreviousJustifiedCheckpt()
|
||||
if err := validateCP(prevJustifiedCheckpoint, "prev justified"); err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrap(err, "could not get previous justified checkpoint"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
|
||||
fSlot, err := slots.EpochStart(finalizedCheckpoint.Epoch)
|
||||
if err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrapf(err, "could not get epoch start slot from finalized checkpoint epoch"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
jSlot, err := slots.EpochStart(justifiedCheckpoint.Epoch)
|
||||
if err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrapf(err, "could not get epoch start slot from justified checkpoint epoch"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
pjSlot, err := slots.EpochStart(prevJustifiedCheckpoint.Epoch)
|
||||
if err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrapf(err, "could not get epoch start slot from prev justified checkpoint epoch"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
return ðpb.ChainHead{
|
||||
HeadSlot: headBlock.Block().Slot(),
|
||||
HeadEpoch: slots.ToEpoch(headBlock.Block().Slot()),
|
||||
HeadBlockRoot: headBlockRoot[:],
|
||||
FinalizedSlot: fSlot,
|
||||
FinalizedEpoch: finalizedCheckpoint.Epoch,
|
||||
FinalizedBlockRoot: finalizedCheckpoint.Root,
|
||||
JustifiedSlot: jSlot,
|
||||
JustifiedEpoch: justifiedCheckpoint.Epoch,
|
||||
JustifiedBlockRoot: justifiedCheckpoint.Root,
|
||||
PreviousJustifiedSlot: pjSlot,
|
||||
PreviousJustifiedEpoch: prevJustifiedCheckpoint.Epoch,
|
||||
PreviousJustifiedBlockRoot: prevJustifiedCheckpoint.Root,
|
||||
OptimisticStatus: optimisticStatus,
|
||||
}, nil
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/cache"
|
||||
opfeed "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/feed/operation"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/operations/synccommittee"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen"
|
||||
@@ -11,6 +12,8 @@ import (
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
BeaconDB db.ReadOnlyDatabase
|
||||
ChainInfoFetcher blockchain.ChainInfoFetcher
|
||||
HeadFetcher blockchain.HeadFetcher
|
||||
FinalizedFetcher blockchain.FinalizationFetcher
|
||||
GenesisTimeFetcher blockchain.TimeFetcher
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
coreTime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators"
|
||||
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
|
||||
beaconState "github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
@@ -752,3 +753,177 @@ func subnetsFromCommittee(pubkey []byte, comm *ethpb.SyncCommittee) []uint64 {
|
||||
}
|
||||
return positions
|
||||
}
|
||||
|
||||
// ValidatorParticipation retrieves the validator participation information for a given epoch,
|
||||
// it returns the information about validator's participation rate in voting on the proof of stake
|
||||
// rules based on their balance compared to the total active validator balance.
|
||||
func (s *Service) ValidatorParticipation(
|
||||
ctx context.Context,
|
||||
requestedEpoch primitives.Epoch,
|
||||
) (
|
||||
*ethpb.ValidatorParticipationResponse,
|
||||
*RpcError,
|
||||
) {
|
||||
currentSlot := s.GenesisTimeFetcher.CurrentSlot()
|
||||
currentEpoch := slots.ToEpoch(currentSlot)
|
||||
|
||||
if requestedEpoch > currentEpoch {
|
||||
return nil, &RpcError{
|
||||
Err: fmt.Errorf("cannot retrieve information about an epoch greater than current epoch, current epoch %d, requesting %d", currentEpoch, requestedEpoch),
|
||||
Reason: BadRequest,
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
endSlot, err := slots.EpochEnd(requestedEpoch)
|
||||
if err != nil {
|
||||
return nil, &RpcError{Reason: Internal, Err: errors.Wrap(err, "could not get slot from requested epoch")}
|
||||
}
|
||||
// Get as close as we can to the end of the current epoch without going past the current slot.
|
||||
// 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 endSlot > currentSlot {
|
||||
endSlot = currentSlot
|
||||
}
|
||||
|
||||
// ReplayerBuilder ensures that a canonical chain is followed to the slot
|
||||
beaconSt, err := s.ReplayerBuilder.ReplayerForSlot(endSlot).ReplayBlocks(ctx)
|
||||
if err != nil {
|
||||
return nil, &RpcError{Reason: Internal, Err: errors.Wrapf(err, "error replaying blocks for state at slot %d", endSlot)}
|
||||
}
|
||||
var v []*precompute.Validator
|
||||
var b *precompute.Balance
|
||||
|
||||
if beaconSt.Version() == version.Phase0 {
|
||||
v, b, err = precompute.New(ctx, beaconSt)
|
||||
if err != nil {
|
||||
return nil, &RpcError{Reason: Internal, Err: errors.Wrap(err, "could not set up pre compute instance")}
|
||||
}
|
||||
_, b, err = precompute.ProcessAttestations(ctx, beaconSt, v, b)
|
||||
if err != nil {
|
||||
return nil, &RpcError{Reason: Internal, Err: errors.Wrap(err, "could not pre compute attestations")}
|
||||
}
|
||||
} else if beaconSt.Version() >= version.Altair {
|
||||
v, b, err = altair.InitializePrecomputeValidators(ctx, beaconSt)
|
||||
if err != nil {
|
||||
return nil, &RpcError{Reason: Internal, Err: errors.Wrap(err, "could not set up altair pre compute instance")}
|
||||
}
|
||||
_, b, err = altair.ProcessEpochParticipation(ctx, beaconSt, b, v)
|
||||
if err != nil {
|
||||
return nil, &RpcError{Reason: Internal, Err: errors.Wrap(err, "could not pre compute attestations: %v")}
|
||||
}
|
||||
} else {
|
||||
return nil, &RpcError{Reason: Internal, Err: fmt.Errorf("invalid state type retrieved with a version of %s", version.String(beaconSt.Version()))}
|
||||
}
|
||||
|
||||
cp := s.FinalizedFetcher.FinalizedCheckpt()
|
||||
p := ðpb.ValidatorParticipationResponse{
|
||||
Epoch: requestedEpoch,
|
||||
Finalized: requestedEpoch <= cp.Epoch,
|
||||
Participation: ðpb.ValidatorParticipation{
|
||||
// TODO(7130): Remove these three deprecated fields.
|
||||
GlobalParticipationRate: float32(b.PrevEpochTargetAttested) / float32(b.ActivePrevEpoch),
|
||||
VotedEther: b.PrevEpochTargetAttested,
|
||||
EligibleEther: b.ActivePrevEpoch,
|
||||
CurrentEpochActiveGwei: b.ActiveCurrentEpoch,
|
||||
CurrentEpochAttestingGwei: b.CurrentEpochAttested,
|
||||
CurrentEpochTargetAttestingGwei: b.CurrentEpochTargetAttested,
|
||||
PreviousEpochActiveGwei: b.ActivePrevEpoch,
|
||||
PreviousEpochAttestingGwei: b.PrevEpochAttested,
|
||||
PreviousEpochTargetAttestingGwei: b.PrevEpochTargetAttested,
|
||||
PreviousEpochHeadAttestingGwei: b.PrevEpochHeadAttested,
|
||||
},
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// ValidatorActiveSetChanges retrieves the active set changes for a given epoch.
|
||||
//
|
||||
// This data includes any activations, voluntary exits, and involuntary
|
||||
// ejections.
|
||||
func (s *Service) ValidatorActiveSetChanges(
|
||||
ctx context.Context,
|
||||
requestedEpoch primitives.Epoch,
|
||||
) (
|
||||
*ethpb.ActiveSetChanges,
|
||||
*RpcError,
|
||||
) {
|
||||
currentEpoch := slots.ToEpoch(s.GenesisTimeFetcher.CurrentSlot())
|
||||
if requestedEpoch > currentEpoch {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Errorf("cannot retrieve information about an epoch in the future, current epoch %d, requesting %d", currentEpoch, requestedEpoch),
|
||||
Reason: BadRequest,
|
||||
}
|
||||
}
|
||||
|
||||
slot, err := slots.EpochStart(requestedEpoch)
|
||||
if err != nil {
|
||||
return nil, &RpcError{Err: err, Reason: BadRequest}
|
||||
}
|
||||
requestedState, err := s.ReplayerBuilder.ReplayerForSlot(slot).ReplayBlocks(ctx)
|
||||
if err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrapf(err, "error replaying blocks for state at slot %d", slot),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
|
||||
activeValidatorCount, err := helpers.ActiveValidatorCount(ctx, requestedState, coreTime.CurrentEpoch(requestedState))
|
||||
if err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrap(err, "could not get active validator count"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
vs := requestedState.Validators()
|
||||
activatedIndices := validators.ActivatedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs)
|
||||
exitedIndices, err := validators.ExitedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs, activeValidatorCount)
|
||||
if err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrap(err, "could not determine exited validator indices"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
slashedIndices := validators.SlashedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs)
|
||||
ejectedIndices, err := validators.EjectedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs, activeValidatorCount)
|
||||
if err != nil {
|
||||
return nil, &RpcError{
|
||||
Err: errors.Wrap(err, "could not determine ejected validator indices"),
|
||||
Reason: Internal,
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve public keys for the indices.
|
||||
activatedKeys := make([][]byte, len(activatedIndices))
|
||||
exitedKeys := make([][]byte, len(exitedIndices))
|
||||
slashedKeys := make([][]byte, len(slashedIndices))
|
||||
ejectedKeys := make([][]byte, len(ejectedIndices))
|
||||
for i, idx := range activatedIndices {
|
||||
pubkey := requestedState.PubkeyAtIndex(idx)
|
||||
activatedKeys[i] = pubkey[:]
|
||||
}
|
||||
for i, idx := range exitedIndices {
|
||||
pubkey := requestedState.PubkeyAtIndex(idx)
|
||||
exitedKeys[i] = pubkey[:]
|
||||
}
|
||||
for i, idx := range slashedIndices {
|
||||
pubkey := requestedState.PubkeyAtIndex(idx)
|
||||
slashedKeys[i] = pubkey[:]
|
||||
}
|
||||
for i, idx := range ejectedIndices {
|
||||
pubkey := requestedState.PubkeyAtIndex(idx)
|
||||
ejectedKeys[i] = pubkey[:]
|
||||
}
|
||||
return ðpb.ActiveSetChanges{
|
||||
Epoch: requestedEpoch,
|
||||
ActivatedPublicKeys: activatedKeys,
|
||||
ActivatedIndices: activatedIndices,
|
||||
ExitedPublicKeys: exitedKeys,
|
||||
ExitedIndices: exitedIndices,
|
||||
SlashedPublicKeys: slashedKeys,
|
||||
SlashedIndices: slashedIndices,
|
||||
EjectedPublicKeys: ejectedKeys,
|
||||
EjectedIndices: ejectedIndices,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func (s *Service) endpoints(
|
||||
endpoints = append(endpoints, s.eventsEndpoints()...)
|
||||
endpoints = append(endpoints, s.prysmBeaconEndpoints(ch, stater, coreService)...)
|
||||
endpoints = append(endpoints, s.prysmNodeEndpoints()...)
|
||||
endpoints = append(endpoints, s.prysmValidatorEndpoints(coreService)...)
|
||||
endpoints = append(endpoints, s.prysmValidatorEndpoints(stater, coreService)...)
|
||||
if enableDebug {
|
||||
endpoints = append(endpoints, s.debugEndpoints(stater)...)
|
||||
}
|
||||
@@ -983,6 +983,15 @@ func (s *Service) prysmBeaconEndpoints(
|
||||
handler: server.GetIndividualVotes,
|
||||
methods: []string{http.MethodPost},
|
||||
},
|
||||
{
|
||||
template: "/prysm/v1/beacon/chain_head",
|
||||
name: namespace + ".GetChainHead",
|
||||
middleware: []mux.MiddlewareFunc{
|
||||
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
|
||||
},
|
||||
handler: server.GetChainHead,
|
||||
methods: []string{http.MethodGet},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1060,32 +1069,52 @@ func (s *Service) prysmNodeEndpoints() []endpoint {
|
||||
}
|
||||
}
|
||||
|
||||
func (*Service) prysmValidatorEndpoints(coreService *core.Service) []endpoint {
|
||||
func (s *Service) prysmValidatorEndpoints(stater lookup.Stater, coreService *core.Service) []endpoint {
|
||||
server := &validatorprysm.Server{
|
||||
CoreService: coreService,
|
||||
ChainInfoFetcher: s.cfg.ChainInfoFetcher,
|
||||
Stater: stater,
|
||||
CoreService: coreService,
|
||||
}
|
||||
|
||||
const namespace = "prysm.validator"
|
||||
return []endpoint{
|
||||
{
|
||||
template: "/prysm/validators/performance",
|
||||
name: namespace + ".GetValidatorPerformance",
|
||||
name: namespace + ".GetPerformance",
|
||||
middleware: []mux.MiddlewareFunc{
|
||||
middleware.ContentTypeHandler([]string{api.JsonMediaType}),
|
||||
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
|
||||
},
|
||||
handler: server.GetValidatorPerformance,
|
||||
handler: server.GetPerformance,
|
||||
methods: []string{http.MethodPost},
|
||||
},
|
||||
{
|
||||
template: "/prysm/v1/validators/performance",
|
||||
name: namespace + ".GetValidatorPerformance",
|
||||
name: namespace + ".GetPerformance",
|
||||
middleware: []mux.MiddlewareFunc{
|
||||
middleware.ContentTypeHandler([]string{api.JsonMediaType}),
|
||||
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
|
||||
},
|
||||
handler: server.GetValidatorPerformance,
|
||||
handler: server.GetPerformance,
|
||||
methods: []string{http.MethodPost},
|
||||
},
|
||||
{
|
||||
template: "/prysm/v1/validators/participation",
|
||||
name: namespace + ".GetParticipation",
|
||||
middleware: []mux.MiddlewareFunc{
|
||||
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
|
||||
},
|
||||
handler: server.GetParticipation,
|
||||
methods: []string{http.MethodGet},
|
||||
},
|
||||
{
|
||||
template: "/prysm/v1/validators/active_set_changes",
|
||||
name: namespace + ".GetActiveSetChanges",
|
||||
middleware: []mux.MiddlewareFunc{
|
||||
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
|
||||
},
|
||||
handler: server.GetActiveSetChanges,
|
||||
methods: []string{http.MethodGet},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ func Test_endpoints(t *testing.T) {
|
||||
"/prysm/v1/beacon/weak_subjectivity": {http.MethodGet},
|
||||
"/eth/v1/beacon/states/{state_id}/validator_count": {http.MethodGet},
|
||||
"/prysm/v1/beacon/states/{state_id}/validator_count": {http.MethodGet},
|
||||
"/prysm/v1/beacon/chain_head": {http.MethodGet},
|
||||
}
|
||||
|
||||
prysmNodeRoutes := map[string][]string{
|
||||
@@ -124,8 +125,10 @@ func Test_endpoints(t *testing.T) {
|
||||
}
|
||||
|
||||
prysmValidatorRoutes := map[string][]string{
|
||||
"/prysm/validators/performance": {http.MethodPost},
|
||||
"/prysm/v1/validators/performance": {http.MethodPost},
|
||||
"/prysm/validators/performance": {http.MethodPost},
|
||||
"/prysm/v1/validators/performance": {http.MethodPost},
|
||||
"/prysm/v1/validators/participation": {http.MethodGet},
|
||||
"/prysm/v1/validators/active_set_changes": {http.MethodGet},
|
||||
}
|
||||
|
||||
s := &Service{cfg: &Config{}}
|
||||
|
||||
@@ -116,9 +116,11 @@ func (s *Server) getBlockV2Ssz(w http.ResponseWriter, blk interfaces.ReadOnlySig
|
||||
result, err := s.getBlockResponseBodySsz(blk)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Could not get signed beacon block: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if result == nil {
|
||||
httputil.HandleError(w, fmt.Sprintf("Unknown block type %T", blk), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set(api.VersionHeader, version.String(blk.Version()))
|
||||
httputil.WriteSsz(w, result, "beacon_block.ssz")
|
||||
@@ -149,6 +151,11 @@ func (s *Server) getBlockV2Json(ctx context.Context, w http.ResponseWriter, blk
|
||||
result, err := s.getBlockResponseBodyJson(ctx, blk)
|
||||
if err != nil {
|
||||
httputil.HandleError(w, "Error processing request: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if result == nil {
|
||||
httputil.HandleError(w, fmt.Sprintf("Unknown block type %T", blk), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set(api.VersionHeader, result.Version)
|
||||
httputil.WriteJson(w, result)
|
||||
|
||||
@@ -52,10 +52,14 @@ go_test(
|
||||
"//beacon-chain/rpc/lookup:go_default_library",
|
||||
"//beacon-chain/rpc/testutil:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
"//beacon-chain/state/stategen/mock:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//network/httputil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
|
||||
@@ -154,3 +154,32 @@ func (s *Server) GetIndividualVotes(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
|
||||
// GetChainHead retrieves information about the head of the beacon chain from
|
||||
// the view of the beacon chain node.
|
||||
func (s *Server) GetChainHead(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "beacon.GetChainHead")
|
||||
defer span.End()
|
||||
|
||||
ch, rpcError := s.CoreService.ChainHead(ctx)
|
||||
if rpcError != nil {
|
||||
httputil.HandleError(w, rpcError.Err.Error(), core.ErrorReasonToHTTP(rpcError.Reason))
|
||||
return
|
||||
}
|
||||
response := &structs.ChainHead{
|
||||
HeadSlot: fmt.Sprintf("%d", ch.HeadSlot),
|
||||
HeadEpoch: fmt.Sprintf("%d", ch.HeadEpoch),
|
||||
HeadBlockRoot: hexutil.Encode(ch.HeadBlockRoot),
|
||||
FinalizedSlot: fmt.Sprintf("%d", ch.FinalizedSlot),
|
||||
FinalizedEpoch: fmt.Sprintf("%d", ch.FinalizedEpoch),
|
||||
FinalizedBlockRoot: hexutil.Encode(ch.FinalizedBlockRoot),
|
||||
JustifiedSlot: fmt.Sprintf("%d", ch.JustifiedSlot),
|
||||
JustifiedEpoch: fmt.Sprintf("%d", ch.JustifiedEpoch),
|
||||
JustifiedBlockRoot: hexutil.Encode(ch.JustifiedBlockRoot),
|
||||
PreviousJustifiedSlot: fmt.Sprintf("%d", ch.PreviousJustifiedSlot),
|
||||
PreviousJustifiedEpoch: fmt.Sprintf("%d", ch.PreviousJustifiedEpoch),
|
||||
PreviousJustifiedBlockRoot: hexutil.Encode(ch.PreviousJustifiedBlockRoot),
|
||||
OptimisticStatus: ch.OptimisticStatus,
|
||||
}
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
|
||||
@@ -19,11 +19,15 @@ import (
|
||||
dbTest "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core"
|
||||
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen"
|
||||
mockstategen "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen/mock"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
@@ -227,11 +231,11 @@ func TestServer_GetIndividualVotes_Working(t *testing.T) {
|
||||
require.NoError(t, beaconState.SetBlockRoots(br))
|
||||
att2.Data.Target.Root = rt[:]
|
||||
att2.Data.BeaconBlockRoot = newRt[:]
|
||||
err = beaconState.AppendPreviousEpochAttestations(ð.PendingAttestation{
|
||||
err = beaconState.AppendPreviousEpochAttestations(ðpb.PendingAttestation{
|
||||
Data: att1.Data, AggregationBits: bf, InclusionDelay: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = beaconState.AppendCurrentEpochAttestations(ð.PendingAttestation{
|
||||
err = beaconState.AppendCurrentEpochAttestations(ðpb.PendingAttestation{
|
||||
Data: att2.Data, AggregationBits: bf, InclusionDelay: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -658,3 +662,211 @@ func TestServer_GetIndividualVotes_CapellaEndOfEpoch(t *testing.T) {
|
||||
}
|
||||
assert.DeepEqual(t, want, resp, "Unexpected response")
|
||||
}
|
||||
|
||||
// ensures that if any of the checkpoints are zero-valued, an error will be generated without genesis being present
|
||||
func TestServer_GetChainHead_NoGenesis(t *testing.T) {
|
||||
db := dbTest.SetupDB(t)
|
||||
|
||||
s, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, s.SetSlot(1))
|
||||
|
||||
genBlock := util.NewBeaconBlock()
|
||||
genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, fieldparams.RootLength)
|
||||
util.SaveBlock(t, context.Background(), db, genBlock)
|
||||
gRoot, err := genBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cases := []struct {
|
||||
name string
|
||||
zeroSetter func(val *ethpb.Checkpoint) error
|
||||
}{
|
||||
{
|
||||
name: "zero-value prev justified",
|
||||
zeroSetter: s.SetPreviousJustifiedCheckpoint,
|
||||
},
|
||||
{
|
||||
name: "zero-value current justified",
|
||||
zeroSetter: s.SetCurrentJustifiedCheckpoint,
|
||||
},
|
||||
{
|
||||
name: "zero-value finalized",
|
||||
zeroSetter: s.SetFinalizedCheckpoint,
|
||||
},
|
||||
}
|
||||
finalized := ðpb.Checkpoint{Epoch: 1, Root: gRoot[:]}
|
||||
prevJustified := ðpb.Checkpoint{Epoch: 2, Root: gRoot[:]}
|
||||
justified := ðpb.Checkpoint{Epoch: 3, Root: gRoot[:]}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
require.NoError(t, s.SetPreviousJustifiedCheckpoint(prevJustified))
|
||||
require.NoError(t, s.SetCurrentJustifiedCheckpoint(justified))
|
||||
require.NoError(t, s.SetFinalizedCheckpoint(finalized))
|
||||
require.NoError(t, c.zeroSetter(ðpb.Checkpoint{Epoch: 0, Root: params.BeaconConfig().ZeroHash[:]}))
|
||||
})
|
||||
wsb, err := blocks.NewSignedBeaconBlock(genBlock)
|
||||
require.NoError(t, err)
|
||||
s := &Server{
|
||||
CoreService: &core.Service{
|
||||
BeaconDB: db,
|
||||
HeadFetcher: &chainMock.ChainService{Block: wsb, State: s},
|
||||
FinalizedFetcher: &chainMock.ChainService{
|
||||
FinalizedCheckPoint: s.FinalizedCheckpoint(),
|
||||
CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(),
|
||||
PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint(),
|
||||
},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
},
|
||||
}
|
||||
url := "http://example.com"
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetChainHead(writer, request)
|
||||
require.Equal(t, http.StatusInternalServerError, writer.Code)
|
||||
require.StringContains(t, "could not get genesis block", writer.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestServer_GetChainHead_NoFinalizedBlock(t *testing.T) {
|
||||
db := dbTest.SetupDB(t)
|
||||
|
||||
bs, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, bs.SetSlot(1))
|
||||
require.NoError(t, bs.SetPreviousJustifiedCheckpoint(ðpb.Checkpoint{Epoch: 3, Root: bytesutil.PadTo([]byte{'A'}, fieldparams.RootLength)}))
|
||||
require.NoError(t, bs.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{Epoch: 2, Root: bytesutil.PadTo([]byte{'B'}, fieldparams.RootLength)}))
|
||||
require.NoError(t, bs.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'C'}, fieldparams.RootLength)}))
|
||||
|
||||
genBlock := util.NewBeaconBlock()
|
||||
genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, fieldparams.RootLength)
|
||||
util.SaveBlock(t, context.Background(), db, genBlock)
|
||||
gRoot, err := genBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(context.Background(), gRoot))
|
||||
|
||||
wsb, err := blocks.NewSignedBeaconBlock(genBlock)
|
||||
require.NoError(t, err)
|
||||
|
||||
s := &Server{
|
||||
CoreService: &core.Service{
|
||||
BeaconDB: db,
|
||||
HeadFetcher: &chainMock.ChainService{Block: wsb, State: bs},
|
||||
FinalizedFetcher: &chainMock.ChainService{
|
||||
FinalizedCheckPoint: bs.FinalizedCheckpoint(),
|
||||
CurrentJustifiedCheckPoint: bs.CurrentJustifiedCheckpoint(),
|
||||
PreviousJustifiedCheckPoint: bs.PreviousJustifiedCheckpoint()},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
},
|
||||
}
|
||||
|
||||
url := "http://example.com"
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetChainHead(writer, request)
|
||||
require.Equal(t, http.StatusInternalServerError, writer.Code)
|
||||
require.StringContains(t, "ould not get finalized block", writer.Body.String())
|
||||
}
|
||||
|
||||
func TestServer_GetChainHead_NoHeadBlock(t *testing.T) {
|
||||
s := &Server{
|
||||
CoreService: &core.Service{
|
||||
HeadFetcher: &chainMock.ChainService{Block: nil},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
},
|
||||
}
|
||||
url := "http://example.com"
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetChainHead(writer, request)
|
||||
require.Equal(t, http.StatusNotFound, writer.Code)
|
||||
require.StringContains(t, "head block of chain was nil", writer.Body.String())
|
||||
}
|
||||
|
||||
func TestServer_GetChainHead(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
params.OverrideBeaconConfig(params.MinimalSpecConfig())
|
||||
|
||||
db := dbTest.SetupDB(t)
|
||||
genBlock := util.NewBeaconBlock()
|
||||
genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, fieldparams.RootLength)
|
||||
util.SaveBlock(t, context.Background(), db, genBlock)
|
||||
gRoot, err := genBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(context.Background(), gRoot))
|
||||
|
||||
finalizedBlock := util.NewBeaconBlock()
|
||||
finalizedBlock.Block.Slot = 1
|
||||
finalizedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'A'}, fieldparams.RootLength)
|
||||
util.SaveBlock(t, context.Background(), db, finalizedBlock)
|
||||
fRoot, err := finalizedBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
justifiedBlock := util.NewBeaconBlock()
|
||||
justifiedBlock.Block.Slot = 2
|
||||
justifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'B'}, fieldparams.RootLength)
|
||||
util.SaveBlock(t, context.Background(), db, justifiedBlock)
|
||||
jRoot, err := justifiedBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
prevJustifiedBlock := util.NewBeaconBlock()
|
||||
prevJustifiedBlock.Block.Slot = 3
|
||||
prevJustifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'C'}, fieldparams.RootLength)
|
||||
util.SaveBlock(t, context.Background(), db, prevJustifiedBlock)
|
||||
pjRoot, err := prevJustifiedBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
st, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||
Slot: 1,
|
||||
PreviousJustifiedCheckpoint: ðpb.Checkpoint{Epoch: 3, Root: pjRoot[:]},
|
||||
CurrentJustifiedCheckpoint: ðpb.Checkpoint{Epoch: 2, Root: jRoot[:]},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 1, Root: fRoot[:]},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Slot, err = slots.EpochStart(st.PreviousJustifiedCheckpoint().Epoch)
|
||||
require.NoError(t, err)
|
||||
b.Block.Slot++
|
||||
wsb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
s := &Server{
|
||||
CoreService: &core.Service{
|
||||
BeaconDB: db,
|
||||
HeadFetcher: &chainMock.ChainService{Block: wsb, State: st},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
FinalizedFetcher: &chainMock.ChainService{
|
||||
FinalizedCheckPoint: st.FinalizedCheckpoint(),
|
||||
CurrentJustifiedCheckPoint: st.CurrentJustifiedCheckpoint(),
|
||||
PreviousJustifiedCheckPoint: st.PreviousJustifiedCheckpoint()},
|
||||
},
|
||||
}
|
||||
|
||||
url := "http://example.com"
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetChainHead(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
var ch *structs.ChainHead
|
||||
err = json.NewDecoder(writer.Body).Decode(&ch)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "3", ch.PreviousJustifiedEpoch, "Unexpected PreviousJustifiedEpoch")
|
||||
assert.Equal(t, "2", ch.JustifiedEpoch, "Unexpected JustifiedEpoch")
|
||||
assert.Equal(t, "1", ch.FinalizedEpoch, "Unexpected FinalizedEpoch")
|
||||
assert.Equal(t, "24", ch.PreviousJustifiedSlot, "Unexpected PreviousJustifiedSlot")
|
||||
assert.Equal(t, "16", ch.JustifiedSlot, "Unexpected JustifiedSlot")
|
||||
assert.Equal(t, "8", ch.FinalizedSlot, "Unexpected FinalizedSlot")
|
||||
assert.DeepEqual(t, hexutil.Encode(pjRoot[:]), ch.PreviousJustifiedBlockRoot, "Unexpected PreviousJustifiedBlockRoot")
|
||||
assert.DeepEqual(t, hexutil.Encode(jRoot[:]), ch.JustifiedBlockRoot, "Unexpected JustifiedBlockRoot")
|
||||
assert.DeepEqual(t, hexutil.Encode(fRoot[:]), ch.FinalizedBlockRoot, "Unexpected FinalizedBlockRoot")
|
||||
assert.Equal(t, false, ch.OptimisticStatus)
|
||||
}
|
||||
|
||||
@@ -19,15 +19,12 @@ go_library(
|
||||
"//api/pagination:go_default_library",
|
||||
"//beacon-chain/blockchain:go_default_library",
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/feed/block:go_default_library",
|
||||
"//beacon-chain/core/feed/operation:go_default_library",
|
||||
"//beacon-chain/core/feed/state:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/time:go_default_library",
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/db/filters:go_default_library",
|
||||
"//beacon-chain/execution:go_default_library",
|
||||
|
||||
@@ -7,13 +7,12 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/pagination"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filters"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core"
|
||||
"github.com/prysmaticlabs/prysm/v5/cmd"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
@@ -244,91 +243,9 @@ func (bs *Server) listBlocksForGenesis(ctx context.Context, _ *ethpb.ListBlocksR
|
||||
// the most recent finalized and justified slots.
|
||||
// DEPRECATED: This endpoint is superseded by the /eth/v1/beacon API endpoint
|
||||
func (bs *Server) GetChainHead(ctx context.Context, _ *emptypb.Empty) (*ethpb.ChainHead, error) {
|
||||
return bs.chainHeadRetrieval(ctx)
|
||||
}
|
||||
|
||||
// Retrieve chain head information from the DB and the current beacon state.
|
||||
func (bs *Server) chainHeadRetrieval(ctx context.Context) (*ethpb.ChainHead, error) {
|
||||
headBlock, err := bs.HeadFetcher.HeadBlock(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not get head block")
|
||||
}
|
||||
optimisticStatus, err := bs.OptimisticModeFetcher.IsOptimistic(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "Could not get optimistic status")
|
||||
}
|
||||
if err := consensusblocks.BeaconBlockIsNil(headBlock); err != nil {
|
||||
return nil, status.Errorf(codes.NotFound, "Head block of chain was nil: %v", err)
|
||||
}
|
||||
headBlockRoot, err := headBlock.Block().HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not get head block root: %v", err)
|
||||
}
|
||||
|
||||
validGenesis := false
|
||||
validateCP := func(cp *ethpb.Checkpoint, name string) error {
|
||||
if bytesutil.ToBytes32(cp.Root) == params.BeaconConfig().ZeroHash && cp.Epoch == 0 {
|
||||
if validGenesis {
|
||||
return nil
|
||||
}
|
||||
// Retrieve genesis block in the event we have genesis checkpoints.
|
||||
genBlock, err := bs.BeaconDB.GenesisBlock(ctx)
|
||||
if err != nil || consensusblocks.BeaconBlockIsNil(genBlock) != nil {
|
||||
return status.Error(codes.Internal, "Could not get genesis block")
|
||||
}
|
||||
validGenesis = true
|
||||
return nil
|
||||
}
|
||||
b, err := bs.BeaconDB.Block(ctx, bytesutil.ToBytes32(cp.Root))
|
||||
if err != nil {
|
||||
return status.Errorf(codes.Internal, "Could not get %s block: %v", name, err)
|
||||
}
|
||||
if err := consensusblocks.BeaconBlockIsNil(b); err != nil {
|
||||
return status.Errorf(codes.Internal, "Could not get %s block: %v", name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
finalizedCheckpoint := bs.FinalizationFetcher.FinalizedCheckpt()
|
||||
if err := validateCP(finalizedCheckpoint, "finalized"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
justifiedCheckpoint := bs.FinalizationFetcher.CurrentJustifiedCheckpt()
|
||||
if err := validateCP(justifiedCheckpoint, "justified"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prevJustifiedCheckpoint := bs.FinalizationFetcher.PreviousJustifiedCheckpt()
|
||||
if err := validateCP(prevJustifiedCheckpoint, "prev justified"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fSlot, err := slots.EpochStart(finalizedCheckpoint.Epoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get epoch start slot from finalized checkpoint epoch")
|
||||
}
|
||||
jSlot, err := slots.EpochStart(justifiedCheckpoint.Epoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get epoch start slot from justified checkpoint epoch")
|
||||
}
|
||||
pjSlot, err := slots.EpochStart(prevJustifiedCheckpoint.Epoch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get epoch start slot from prev justified checkpoint epoch")
|
||||
}
|
||||
return ðpb.ChainHead{
|
||||
HeadSlot: headBlock.Block().Slot(),
|
||||
HeadEpoch: slots.ToEpoch(headBlock.Block().Slot()),
|
||||
HeadBlockRoot: headBlockRoot[:],
|
||||
FinalizedSlot: fSlot,
|
||||
FinalizedEpoch: finalizedCheckpoint.Epoch,
|
||||
FinalizedBlockRoot: finalizedCheckpoint.Root,
|
||||
JustifiedSlot: jSlot,
|
||||
JustifiedEpoch: justifiedCheckpoint.Epoch,
|
||||
JustifiedBlockRoot: justifiedCheckpoint.Root,
|
||||
PreviousJustifiedSlot: pjSlot,
|
||||
PreviousJustifiedEpoch: prevJustifiedCheckpoint.Epoch,
|
||||
PreviousJustifiedBlockRoot: prevJustifiedCheckpoint.Root,
|
||||
OptimisticStatus: optimisticStatus,
|
||||
}, nil
|
||||
ch, err := bs.CoreService.ChainHead(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(core.ErrorReasonToGRPC(err.Reason), "Could not retrieve chain head: %v", err.Err)
|
||||
}
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
chainMock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing"
|
||||
dbTest "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core"
|
||||
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
@@ -68,16 +69,19 @@ func TestServer_GetChainHead_NoGenesis(t *testing.T) {
|
||||
wsb, err := blocks.NewSignedBeaconBlock(genBlock)
|
||||
require.NoError(t, err)
|
||||
bs := &Server{
|
||||
BeaconDB: db,
|
||||
HeadFetcher: &chainMock.ChainService{Block: wsb, State: s},
|
||||
FinalizationFetcher: &chainMock.ChainService{
|
||||
FinalizedCheckPoint: s.FinalizedCheckpoint(),
|
||||
CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(),
|
||||
PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
CoreService: &core.Service{
|
||||
BeaconDB: db,
|
||||
HeadFetcher: &chainMock.ChainService{Block: wsb, State: s},
|
||||
FinalizedFetcher: &chainMock.ChainService{
|
||||
FinalizedCheckPoint: s.FinalizedCheckpoint(),
|
||||
CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(),
|
||||
PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint(),
|
||||
},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
},
|
||||
}
|
||||
_, err = bs.GetChainHead(context.Background(), nil)
|
||||
require.ErrorContains(t, "Could not get genesis block", err)
|
||||
require.ErrorContains(t, "could not get genesis block", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,26 +106,30 @@ func TestServer_GetChainHead_NoFinalizedBlock(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
bs := &Server{
|
||||
BeaconDB: db,
|
||||
HeadFetcher: &chainMock.ChainService{Block: wsb, State: s},
|
||||
FinalizationFetcher: &chainMock.ChainService{
|
||||
FinalizedCheckPoint: s.FinalizedCheckpoint(),
|
||||
CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(),
|
||||
PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
CoreService: &core.Service{
|
||||
BeaconDB: db,
|
||||
HeadFetcher: &chainMock.ChainService{Block: wsb, State: s},
|
||||
FinalizedFetcher: &chainMock.ChainService{
|
||||
FinalizedCheckPoint: s.FinalizedCheckpoint(),
|
||||
CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(),
|
||||
PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
},
|
||||
}
|
||||
|
||||
_, err = bs.GetChainHead(context.Background(), nil)
|
||||
require.ErrorContains(t, "Could not get finalized block", err)
|
||||
require.ErrorContains(t, "could not get finalized block", err)
|
||||
}
|
||||
|
||||
func TestServer_GetChainHead_NoHeadBlock(t *testing.T) {
|
||||
bs := &Server{
|
||||
HeadFetcher: &chainMock.ChainService{Block: nil},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
CoreService: &core.Service{
|
||||
HeadFetcher: &chainMock.ChainService{Block: nil},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
},
|
||||
}
|
||||
_, err := bs.GetChainHead(context.Background(), nil)
|
||||
assert.ErrorContains(t, "Head block of chain was nil", err)
|
||||
assert.ErrorContains(t, "head block of chain was nil", err)
|
||||
}
|
||||
|
||||
func TestServer_GetChainHead(t *testing.T) {
|
||||
@@ -172,13 +180,15 @@ func TestServer_GetChainHead(t *testing.T) {
|
||||
wsb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
bs := &Server{
|
||||
BeaconDB: db,
|
||||
HeadFetcher: &chainMock.ChainService{Block: wsb, State: s},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
FinalizationFetcher: &chainMock.ChainService{
|
||||
FinalizedCheckPoint: s.FinalizedCheckpoint(),
|
||||
CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(),
|
||||
PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()},
|
||||
CoreService: &core.Service{
|
||||
BeaconDB: db,
|
||||
HeadFetcher: &chainMock.ChainService{Block: wsb, State: s},
|
||||
OptimisticModeFetcher: &chainMock.ChainService{},
|
||||
FinalizedFetcher: &chainMock.ChainService{
|
||||
FinalizedCheckPoint: s.FinalizedCheckpoint(),
|
||||
CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(),
|
||||
PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()},
|
||||
},
|
||||
}
|
||||
|
||||
head, err := bs.GetChainHead(context.Background(), nil)
|
||||
|
||||
@@ -7,12 +7,9 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/api/pagination"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
coreTime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/cmd"
|
||||
@@ -392,7 +389,7 @@ func (bs *Server) GetValidator(
|
||||
func (bs *Server) GetValidatorActiveSetChanges(
|
||||
ctx context.Context, req *ethpb.GetValidatorActiveSetChangesRequest,
|
||||
) (*ethpb.ActiveSetChanges, error) {
|
||||
currentEpoch := slots.ToEpoch(bs.GenesisTimeFetcher.CurrentSlot())
|
||||
currentEpoch := slots.ToEpoch(bs.CoreService.GenesisTimeFetcher.CurrentSlot())
|
||||
|
||||
var requestedEpoch primitives.Epoch
|
||||
switch q := req.QueryFilter.(type) {
|
||||
@@ -403,72 +400,12 @@ func (bs *Server) GetValidatorActiveSetChanges(
|
||||
default:
|
||||
requestedEpoch = currentEpoch
|
||||
}
|
||||
if requestedEpoch > currentEpoch {
|
||||
return nil, status.Errorf(
|
||||
codes.InvalidArgument,
|
||||
errEpoch,
|
||||
currentEpoch,
|
||||
requestedEpoch,
|
||||
)
|
||||
}
|
||||
|
||||
s, err := slots.EpochStart(requestedEpoch)
|
||||
as, err := bs.CoreService.ValidatorActiveSetChanges(ctx, requestedEpoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, status.Errorf(core.ErrorReasonToGRPC(err.Reason), "Could not retrieve validator active set changes: %v", err.Err)
|
||||
}
|
||||
requestedState, err := bs.ReplayerBuilder.ReplayerForSlot(s).ReplayBlocks(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, fmt.Sprintf("error replaying blocks for state at slot %d: %v", s, err))
|
||||
}
|
||||
|
||||
activeValidatorCount, err := helpers.ActiveValidatorCount(ctx, requestedState, coreTime.CurrentEpoch(requestedState))
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not get active validator count: %v", err)
|
||||
}
|
||||
vs := requestedState.Validators()
|
||||
activatedIndices := validators.ActivatedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs)
|
||||
exitedIndices, err := validators.ExitedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs, activeValidatorCount)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not determine exited validator indices: %v", err)
|
||||
}
|
||||
slashedIndices := validators.SlashedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs)
|
||||
ejectedIndices, err := validators.EjectedValidatorIndices(coreTime.CurrentEpoch(requestedState), vs, activeValidatorCount)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not determine ejected validator indices: %v", err)
|
||||
}
|
||||
|
||||
// Retrieve public keys for the indices.
|
||||
activatedKeys := make([][]byte, len(activatedIndices))
|
||||
exitedKeys := make([][]byte, len(exitedIndices))
|
||||
slashedKeys := make([][]byte, len(slashedIndices))
|
||||
ejectedKeys := make([][]byte, len(ejectedIndices))
|
||||
for i, idx := range activatedIndices {
|
||||
pubkey := requestedState.PubkeyAtIndex(idx)
|
||||
activatedKeys[i] = pubkey[:]
|
||||
}
|
||||
for i, idx := range exitedIndices {
|
||||
pubkey := requestedState.PubkeyAtIndex(idx)
|
||||
exitedKeys[i] = pubkey[:]
|
||||
}
|
||||
for i, idx := range slashedIndices {
|
||||
pubkey := requestedState.PubkeyAtIndex(idx)
|
||||
slashedKeys[i] = pubkey[:]
|
||||
}
|
||||
for i, idx := range ejectedIndices {
|
||||
pubkey := requestedState.PubkeyAtIndex(idx)
|
||||
ejectedKeys[i] = pubkey[:]
|
||||
}
|
||||
return ðpb.ActiveSetChanges{
|
||||
Epoch: requestedEpoch,
|
||||
ActivatedPublicKeys: activatedKeys,
|
||||
ActivatedIndices: activatedIndices,
|
||||
ExitedPublicKeys: exitedKeys,
|
||||
ExitedIndices: exitedIndices,
|
||||
SlashedPublicKeys: slashedKeys,
|
||||
SlashedIndices: slashedIndices,
|
||||
EjectedPublicKeys: ejectedKeys,
|
||||
EjectedIndices: ejectedIndices,
|
||||
}, nil
|
||||
return as, nil
|
||||
}
|
||||
|
||||
// GetValidatorParticipation retrieves the validator participation information for a given epoch,
|
||||
@@ -477,7 +414,7 @@ func (bs *Server) GetValidatorActiveSetChanges(
|
||||
func (bs *Server) GetValidatorParticipation(
|
||||
ctx context.Context, req *ethpb.GetValidatorParticipationRequest,
|
||||
) (*ethpb.ValidatorParticipationResponse, error) {
|
||||
currentSlot := bs.GenesisTimeFetcher.CurrentSlot()
|
||||
currentSlot := bs.CoreService.GenesisTimeFetcher.CurrentSlot()
|
||||
currentEpoch := slots.ToEpoch(currentSlot)
|
||||
|
||||
var requestedEpoch primitives.Epoch
|
||||
@@ -489,79 +426,11 @@ func (bs *Server) GetValidatorParticipation(
|
||||
default:
|
||||
requestedEpoch = currentEpoch
|
||||
}
|
||||
|
||||
if requestedEpoch > currentEpoch {
|
||||
return nil, status.Errorf(
|
||||
codes.InvalidArgument,
|
||||
"Cannot retrieve information about an epoch greater than current epoch, current epoch %d, requesting %d",
|
||||
currentEpoch,
|
||||
requestedEpoch,
|
||||
)
|
||||
}
|
||||
// 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.
|
||||
endSlot, err := slots.EpochEnd(requestedEpoch)
|
||||
vp, err := bs.CoreService.ValidatorParticipation(ctx, requestedEpoch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, status.Errorf(core.ErrorReasonToGRPC(err.Reason), "Could not retrieve validator participation: %v", err.Err)
|
||||
}
|
||||
// Get as close as we can to the end of the current epoch without going past the current slot.
|
||||
// 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 endSlot > currentSlot {
|
||||
endSlot = currentSlot
|
||||
}
|
||||
|
||||
// ReplayerBuilder ensures that a canonical chain is followed to the slot
|
||||
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", endSlot, err))
|
||||
}
|
||||
var v []*precompute.Validator
|
||||
var b *precompute.Balance
|
||||
|
||||
if beaconState.Version() == version.Phase0 {
|
||||
v, b, err = precompute.New(ctx, beaconState)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not set up pre compute instance: %v", err)
|
||||
}
|
||||
_, b, err = precompute.ProcessAttestations(ctx, beaconState, v, b)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err)
|
||||
}
|
||||
} else if beaconState.Version() >= version.Altair {
|
||||
v, b, err = altair.InitializePrecomputeValidators(ctx, beaconState)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not set up altair pre compute instance: %v", err)
|
||||
}
|
||||
_, b, err = altair.ProcessEpochParticipation(ctx, beaconState, b, v)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "Could not pre compute attestations: %v", err)
|
||||
}
|
||||
} else {
|
||||
return nil, status.Errorf(codes.Internal, "Invalid state type retrieved with a version of %d", beaconState.Version())
|
||||
}
|
||||
|
||||
cp := bs.FinalizationFetcher.FinalizedCheckpt()
|
||||
p := ðpb.ValidatorParticipationResponse{
|
||||
Epoch: requestedEpoch,
|
||||
Finalized: requestedEpoch <= cp.Epoch,
|
||||
Participation: ðpb.ValidatorParticipation{
|
||||
// TODO(7130): Remove these three deprecated fields.
|
||||
GlobalParticipationRate: float32(b.PrevEpochTargetAttested) / float32(b.ActivePrevEpoch),
|
||||
VotedEther: b.PrevEpochTargetAttested,
|
||||
EligibleEther: b.ActivePrevEpoch,
|
||||
CurrentEpochActiveGwei: b.ActiveCurrentEpoch,
|
||||
CurrentEpochAttestingGwei: b.CurrentEpochAttested,
|
||||
CurrentEpochTargetAttestingGwei: b.CurrentEpochTargetAttested,
|
||||
PreviousEpochActiveGwei: b.ActivePrevEpoch,
|
||||
PreviousEpochAttestingGwei: b.PrevEpochAttested,
|
||||
PreviousEpochTargetAttestingGwei: b.PrevEpochTargetAttested,
|
||||
PreviousEpochHeadAttestingGwei: b.PrevEpochHeadAttested,
|
||||
},
|
||||
}
|
||||
|
||||
return p, nil
|
||||
return vp, nil
|
||||
}
|
||||
|
||||
// GetValidatorQueue retrieves the current validator queue information.
|
||||
|
||||
@@ -54,11 +54,13 @@ func TestServer_GetValidatorActiveSetChanges_CannotRequestFutureEpoch(t *testing
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(0))
|
||||
bs := &Server{
|
||||
GenesisTimeFetcher: &mock.ChainService{},
|
||||
HeadFetcher: &mock.ChainService{
|
||||
State: st,
|
||||
CoreService: &core.Service{
|
||||
BeaconDB: beaconDB,
|
||||
GenesisTimeFetcher: &mock.ChainService{},
|
||||
HeadFetcher: &mock.ChainService{
|
||||
State: st,
|
||||
},
|
||||
},
|
||||
BeaconDB: beaconDB,
|
||||
}
|
||||
|
||||
wanted := errNoEpochInfoError
|
||||
@@ -66,7 +68,7 @@ func TestServer_GetValidatorActiveSetChanges_CannotRequestFutureEpoch(t *testing
|
||||
ctx,
|
||||
ðpb.GetValidatorActiveSetChangesRequest{
|
||||
QueryFilter: ðpb.GetValidatorActiveSetChangesRequest_Epoch{
|
||||
Epoch: slots.ToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) + 1,
|
||||
Epoch: slots.ToEpoch(bs.CoreService.GenesisTimeFetcher.CurrentSlot()) + 1,
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -1029,7 +1031,7 @@ func TestServer_ListValidators_FromOldEpoch(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
slot := primitives.Slot(0)
|
||||
epochs := 10
|
||||
epochs := primitives.Epoch(10)
|
||||
numVals := uint64(10)
|
||||
|
||||
beaconDB := dbTest.SetupDB(t)
|
||||
@@ -1065,7 +1067,7 @@ func TestServer_ListValidators_FromOldEpoch(t *testing.T) {
|
||||
}
|
||||
res, err := bs.ListValidators(context.Background(), req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, epochs, len(res.ValidatorList))
|
||||
assert.Equal(t, int(numVals), len(res.ValidatorList))
|
||||
|
||||
vals := st.Validators()
|
||||
want := make([]*ethpb.Validators_ValidatorContainer, 0)
|
||||
@@ -1077,7 +1079,7 @@ func TestServer_ListValidators_FromOldEpoch(t *testing.T) {
|
||||
}
|
||||
req = ðpb.ListValidatorsRequest{
|
||||
QueryFilter: ðpb.ListValidatorsRequest_Epoch{
|
||||
Epoch: 10,
|
||||
Epoch: epochs,
|
||||
},
|
||||
}
|
||||
res, err = bs.ListValidators(context.Background(), req)
|
||||
@@ -1283,10 +1285,12 @@ func TestServer_GetValidatorActiveSetChanges(t *testing.T) {
|
||||
require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot))
|
||||
|
||||
bs := &Server{
|
||||
FinalizationFetcher: &mock.ChainService{
|
||||
FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, fieldparams.RootLength)},
|
||||
CoreService: &core.Service{
|
||||
FinalizedFetcher: &mock.ChainService{
|
||||
FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, fieldparams.RootLength)},
|
||||
},
|
||||
GenesisTimeFetcher: &mock.ChainService{},
|
||||
},
|
||||
GenesisTimeFetcher: &mock.ChainService{},
|
||||
}
|
||||
addDefaultReplayerBuilder(bs, beaconDB)
|
||||
res, err := bs.GetValidatorActiveSetChanges(ctx, ðpb.GetValidatorActiveSetChangesRequest{
|
||||
@@ -1476,27 +1480,25 @@ func TestServer_GetValidatorQueue_PendingExit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_GetValidatorParticipation_CannotRequestFutureEpoch(t *testing.T) {
|
||||
beaconDB := dbTest.SetupDB(t)
|
||||
|
||||
ctx := context.Background()
|
||||
headState, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, headState.SetSlot(0))
|
||||
bs := &Server{
|
||||
BeaconDB: beaconDB,
|
||||
HeadFetcher: &mock.ChainService{
|
||||
State: headState,
|
||||
CoreService: &core.Service{
|
||||
HeadFetcher: &mock.ChainService{
|
||||
State: headState,
|
||||
},
|
||||
GenesisTimeFetcher: &mock.ChainService{},
|
||||
},
|
||||
GenesisTimeFetcher: &mock.ChainService{},
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
}
|
||||
|
||||
wanted := "Cannot retrieve information about an epoch"
|
||||
wanted := "cannot retrieve information about an epoch"
|
||||
_, err = bs.GetValidatorParticipation(
|
||||
ctx,
|
||||
ðpb.GetValidatorParticipationRequest{
|
||||
QueryFilter: ðpb.GetValidatorParticipationRequest_Epoch{
|
||||
Epoch: slots.ToEpoch(bs.GenesisTimeFetcher.CurrentSlot()) + 1,
|
||||
Epoch: slots.ToEpoch(bs.CoreService.GenesisTimeFetcher.CurrentSlot()) + 1,
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -1549,18 +1551,20 @@ func TestServer_GetValidatorParticipation_CurrentAndPrevEpoch(t *testing.T) {
|
||||
m := &mock.ChainService{State: headState}
|
||||
offset := int64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
|
||||
bs := &Server{
|
||||
BeaconDB: beaconDB,
|
||||
HeadFetcher: m,
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
GenesisTimeFetcher: &mock.ChainService{
|
||||
Genesis: prysmTime.Now().Add(time.Duration(-1*offset) * time.Second),
|
||||
BeaconDB: beaconDB,
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
CoreService: &core.Service{
|
||||
HeadFetcher: m,
|
||||
GenesisTimeFetcher: &mock.ChainService{
|
||||
Genesis: prysmTime.Now().Add(time.Duration(-1*offset) * time.Second),
|
||||
},
|
||||
FinalizedFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}},
|
||||
},
|
||||
CanonicalFetcher: &mock.ChainService{
|
||||
CanonicalRoots: map[[32]byte]bool{
|
||||
bRoot: true,
|
||||
},
|
||||
},
|
||||
FinalizationFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}},
|
||||
}
|
||||
addDefaultReplayerBuilder(bs, beaconDB)
|
||||
|
||||
@@ -1628,18 +1632,20 @@ func TestServer_GetValidatorParticipation_OrphanedUntilGenesis(t *testing.T) {
|
||||
m := &mock.ChainService{State: headState}
|
||||
offset := int64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
|
||||
bs := &Server{
|
||||
BeaconDB: beaconDB,
|
||||
HeadFetcher: m,
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
GenesisTimeFetcher: &mock.ChainService{
|
||||
Genesis: prysmTime.Now().Add(time.Duration(-1*offset) * time.Second),
|
||||
BeaconDB: beaconDB,
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
CoreService: &core.Service{
|
||||
HeadFetcher: m,
|
||||
GenesisTimeFetcher: &mock.ChainService{
|
||||
Genesis: prysmTime.Now().Add(time.Duration(-1*offset) * time.Second),
|
||||
},
|
||||
FinalizedFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}},
|
||||
},
|
||||
CanonicalFetcher: &mock.ChainService{
|
||||
CanonicalRoots: map[[32]byte]bool{
|
||||
bRoot: true,
|
||||
},
|
||||
},
|
||||
FinalizationFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}},
|
||||
}
|
||||
addDefaultReplayerBuilder(bs, beaconDB)
|
||||
|
||||
@@ -1744,13 +1750,15 @@ func runGetValidatorParticipationCurrentAndPrevEpoch(t *testing.T, genState stat
|
||||
m := &mock.ChainService{State: genState}
|
||||
offset := int64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
|
||||
bs := &Server{
|
||||
BeaconDB: beaconDB,
|
||||
BeaconDB: beaconDB,
|
||||
CoreService: &core.Service{
|
||||
GenesisTimeFetcher: &mock.ChainService{
|
||||
Genesis: prysmTime.Now().Add(time.Duration(-1*offset) * time.Second),
|
||||
},
|
||||
FinalizedFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}},
|
||||
},
|
||||
HeadFetcher: m,
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
GenesisTimeFetcher: &mock.ChainService{
|
||||
Genesis: prysmTime.Now().Add(time.Duration(-1*offset) * time.Second),
|
||||
},
|
||||
FinalizationFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}},
|
||||
}
|
||||
addDefaultReplayerBuilder(bs, beaconDB)
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
@@ -112,18 +113,12 @@ func (vs *Server) packAttestations(ctx context.Context, latestState state.Beacon
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sorted, err := deduped.sortByProfitability()
|
||||
sorted, err := deduped.sort()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
atts = sorted.limitToMaxAttestations()
|
||||
|
||||
atts, err = vs.filterAttestationBySignature(ctx, atts, latestState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return atts, nil
|
||||
return vs.filterAttestationBySignature(ctx, atts, latestState)
|
||||
}
|
||||
|
||||
// filter separates attestation list into two groups: valid and invalid attestations.
|
||||
@@ -143,14 +138,6 @@ func (a proposerAtts) filter(ctx context.Context, st state.BeaconState) (propose
|
||||
return validAtts, invalidAtts
|
||||
}
|
||||
|
||||
// sortByProfitability orders attestations by highest slot and by highest aggregation bit count.
|
||||
func (a proposerAtts) sortByProfitability() (proposerAtts, error) {
|
||||
if len(a) < 2 {
|
||||
return a, nil
|
||||
}
|
||||
return a.sortByProfitabilityUsingMaxCover()
|
||||
}
|
||||
|
||||
// sortByProfitabilityUsingMaxCover orders attestations by highest slot and by highest aggregation bit count.
|
||||
// Duplicate bits are counted only once, using max-cover algorithm.
|
||||
func (a proposerAtts) sortByProfitabilityUsingMaxCover() (proposerAtts, error) {
|
||||
@@ -218,6 +205,143 @@ func (a proposerAtts) sortByProfitabilityUsingMaxCover() (proposerAtts, error) {
|
||||
return sortedAtts, nil
|
||||
}
|
||||
|
||||
// sort attestations as follows:
|
||||
//
|
||||
// - all attestations selected by max-cover are taken, leftover attestations are discarded
|
||||
// (with current parameters all bits of a leftover attestation are already covered by selected attestations)
|
||||
// - selected attestations are ordered by slot, with higher slot coming first
|
||||
// - within a slot, all top attestations (one per committee) are ordered before any second-best attestations, second-best before third-best etc.
|
||||
// - within top/second-best/etc. attestations (one per committee), attestations are ordered by bit count, with higher bit count coming first
|
||||
func (a proposerAtts) sort() (proposerAtts, error) {
|
||||
if len(a) < 2 {
|
||||
return a, nil
|
||||
}
|
||||
|
||||
if features.Get().EnableCommitteeAwarePacking {
|
||||
return a.sortBySlotAndCommittee()
|
||||
}
|
||||
return a.sortByProfitabilityUsingMaxCover()
|
||||
}
|
||||
|
||||
// Separate attestations by slot, as slot number takes higher precedence when sorting.
|
||||
// Also separate by committee index because maxcover will prefer attestations for the same
|
||||
// committee with disjoint bits over attestations for different committees with overlapping
|
||||
// bits, even though same bits for different committees are separate votes.
|
||||
func (a proposerAtts) sortBySlotAndCommittee() (proposerAtts, error) {
|
||||
type slotAtts struct {
|
||||
candidates map[primitives.CommitteeIndex]proposerAtts
|
||||
selected map[primitives.CommitteeIndex]proposerAtts
|
||||
leftover map[primitives.CommitteeIndex]proposerAtts
|
||||
}
|
||||
|
||||
var slots []primitives.Slot
|
||||
attsBySlot := map[primitives.Slot]*slotAtts{}
|
||||
for _, att := range a {
|
||||
slot := att.GetData().Slot
|
||||
ci := att.GetData().CommitteeIndex
|
||||
if _, ok := attsBySlot[slot]; !ok {
|
||||
attsBySlot[slot] = &slotAtts{}
|
||||
attsBySlot[slot].candidates = make(map[primitives.CommitteeIndex]proposerAtts)
|
||||
slots = append(slots, slot)
|
||||
}
|
||||
attsBySlot[slot].candidates[ci] = append(attsBySlot[slot].candidates[ci], att)
|
||||
}
|
||||
|
||||
var err error
|
||||
for _, sa := range attsBySlot {
|
||||
sa.selected = make(map[primitives.CommitteeIndex]proposerAtts)
|
||||
sa.leftover = make(map[primitives.CommitteeIndex]proposerAtts)
|
||||
for ci, committeeAtts := range sa.candidates {
|
||||
sa.selected[ci], err = committeeAtts.sortByProfitabilityUsingMaxCover_committeeAwarePacking()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sortedAtts proposerAtts
|
||||
sort.Slice(slots, func(i, j int) bool {
|
||||
return slots[i] > slots[j]
|
||||
})
|
||||
for _, slot := range slots {
|
||||
sortedAtts = append(sortedAtts, sortSlotAttestations(attsBySlot[slot].selected)...)
|
||||
}
|
||||
for _, slot := range slots {
|
||||
sortedAtts = append(sortedAtts, sortSlotAttestations(attsBySlot[slot].leftover)...)
|
||||
}
|
||||
|
||||
return sortedAtts, nil
|
||||
}
|
||||
|
||||
// sortByProfitabilityUsingMaxCover orders attestations by highest aggregation bit count.
|
||||
// Duplicate bits are counted only once, using max-cover algorithm.
|
||||
func (a proposerAtts) sortByProfitabilityUsingMaxCover_committeeAwarePacking() (proposerAtts, error) {
|
||||
if len(a) < 2 {
|
||||
return a, nil
|
||||
}
|
||||
candidates := make([]*bitfield.Bitlist64, len(a))
|
||||
for i := 0; i < len(a); i++ {
|
||||
var err error
|
||||
candidates[i], err = a[i].GetAggregationBits().ToBitlist64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Add selected candidates on top, those that are not selected - append at bottom.
|
||||
selectedKeys, _, err := aggregation.MaxCover(candidates, len(candidates), true /* allowOverlaps */)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("MaxCover aggregation failed")
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Pick selected attestations first, leftover attestations will be appended at the end.
|
||||
// Both lists will be sorted by number of bits set.
|
||||
selected := make(proposerAtts, selectedKeys.Count())
|
||||
for i, key := range selectedKeys.BitIndices() {
|
||||
selected[i] = a[key]
|
||||
}
|
||||
sort.Slice(selected, func(i, j int) bool {
|
||||
return selected[i].GetAggregationBits().Count() > selected[j].GetAggregationBits().Count()
|
||||
})
|
||||
return selected, nil
|
||||
}
|
||||
|
||||
// sortSlotAttestations assumes each proposerAtts value in the map is ordered by profitability.
|
||||
// The function takes the first attestation from each value, orders these attestations by bit count
|
||||
// and places them at the start of the resulting slice. It then takes the second attestation for each value,
|
||||
// orders these attestations by bit count and appends them to the end.
|
||||
// It continues this pattern until all attestations are processed.
|
||||
func sortSlotAttestations(slotAtts map[primitives.CommitteeIndex]proposerAtts) proposerAtts {
|
||||
attCount := 0
|
||||
for _, committeeAtts := range slotAtts {
|
||||
attCount += len(committeeAtts)
|
||||
}
|
||||
|
||||
sorted := make([]ethpb.Att, 0, attCount)
|
||||
|
||||
processedCount := 0
|
||||
index := 0
|
||||
for processedCount < attCount {
|
||||
var atts []ethpb.Att
|
||||
|
||||
for _, committeeAtts := range slotAtts {
|
||||
if len(committeeAtts) > index {
|
||||
atts = append(atts, committeeAtts[index])
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(atts, func(i, j int) bool {
|
||||
return atts[i].GetAggregationBits().Count() > atts[j].GetAggregationBits().Count()
|
||||
})
|
||||
sorted = append(sorted, atts...)
|
||||
|
||||
processedCount += len(atts)
|
||||
index++
|
||||
}
|
||||
|
||||
return sorted
|
||||
}
|
||||
|
||||
// limitToMaxAttestations limits attestations to maximum attestations per block.
|
||||
func (a proposerAtts) limitToMaxAttestations() proposerAtts {
|
||||
if len(a) == 0 {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
chainMock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/crypto/bls/blst"
|
||||
@@ -19,31 +20,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
)
|
||||
|
||||
func TestProposer_ProposerAtts_sortByProfitability(t *testing.T) {
|
||||
atts := proposerAtts([]ethpb.Att{
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 4}, AggregationBits: bitfield.Bitlist{0b11100000}}),
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b11000000}}),
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b11100000}}),
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 4}, AggregationBits: bitfield.Bitlist{0b11110000}}),
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b11100000}}),
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 3}, AggregationBits: bitfield.Bitlist{0b11000000}}),
|
||||
})
|
||||
want := proposerAtts([]ethpb.Att{
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 4}, AggregationBits: bitfield.Bitlist{0b11110000}}),
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 4}, AggregationBits: bitfield.Bitlist{0b11100000}}),
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 3}, AggregationBits: bitfield.Bitlist{0b11000000}}),
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b11100000}}),
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b11100000}}),
|
||||
util.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b11000000}}),
|
||||
})
|
||||
atts, err := atts.sortByProfitability()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.DeepEqual(t, want, atts)
|
||||
}
|
||||
|
||||
func TestProposer_ProposerAtts_sortByProfitabilityUsingMaxCover(t *testing.T) {
|
||||
func TestProposer_ProposerAtts_sort(t *testing.T) {
|
||||
type testData struct {
|
||||
slot primitives.Slot
|
||||
bits bitfield.Bitlist
|
||||
@@ -60,7 +37,7 @@ func TestProposer_ProposerAtts_sortByProfitabilityUsingMaxCover(t *testing.T) {
|
||||
t.Run("no atts", func(t *testing.T) {
|
||||
atts := getAtts([]testData{})
|
||||
want := getAtts([]testData{})
|
||||
atts, err := atts.sortByProfitability()
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -74,7 +51,7 @@ func TestProposer_ProposerAtts_sortByProfitabilityUsingMaxCover(t *testing.T) {
|
||||
want := getAtts([]testData{
|
||||
{4, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sortByProfitability()
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -90,7 +67,7 @@ func TestProposer_ProposerAtts_sortByProfitabilityUsingMaxCover(t *testing.T) {
|
||||
{4, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sortByProfitability()
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -108,7 +85,7 @@ func TestProposer_ProposerAtts_sortByProfitabilityUsingMaxCover(t *testing.T) {
|
||||
{4, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sortByProfitability()
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -129,7 +106,7 @@ func TestProposer_ProposerAtts_sortByProfitabilityUsingMaxCover(t *testing.T) {
|
||||
{1, bitfield.Bitlist{0b00001100, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11001000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sortByProfitability()
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -154,14 +131,14 @@ func TestProposer_ProposerAtts_sortByProfitabilityUsingMaxCover(t *testing.T) {
|
||||
{1, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sortByProfitability()
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.DeepEqual(t, want, atts)
|
||||
})
|
||||
|
||||
t.Run("selected and non selected atts sorted by bit count", func(t *testing.T) {
|
||||
t.Run("follows max-cover", func(t *testing.T) {
|
||||
// Items at slot 4, must be first split into two lists by max-cover, with
|
||||
// 0b10000011 scoring higher (as it provides more info in addition to already selected
|
||||
// attestations) than 0b11100001 (despite naive bit count suggesting otherwise). Then,
|
||||
@@ -186,7 +163,7 @@ func TestProposer_ProposerAtts_sortByProfitabilityUsingMaxCover(t *testing.T) {
|
||||
{1, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sortByProfitability()
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -194,6 +171,241 @@ func TestProposer_ProposerAtts_sortByProfitabilityUsingMaxCover(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestProposer_ProposerAtts_committeeAwareSort(t *testing.T) {
|
||||
type testData struct {
|
||||
slot primitives.Slot
|
||||
bits bitfield.Bitlist
|
||||
}
|
||||
getAtts := func(data []testData) proposerAtts {
|
||||
var atts proposerAtts
|
||||
for _, att := range data {
|
||||
atts = append(atts, util.HydrateAttestation(ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{Slot: att.slot}, AggregationBits: att.bits}))
|
||||
}
|
||||
return atts
|
||||
}
|
||||
|
||||
t.Run("no atts", func(t *testing.T) {
|
||||
feat := features.Get()
|
||||
feat.EnableCommitteeAwarePacking = true
|
||||
reset := features.InitWithReset(feat)
|
||||
defer reset()
|
||||
|
||||
atts := getAtts([]testData{})
|
||||
want := getAtts([]testData{})
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.DeepEqual(t, want, atts)
|
||||
})
|
||||
|
||||
t.Run("single att", func(t *testing.T) {
|
||||
feat := features.Get()
|
||||
feat.EnableCommitteeAwarePacking = true
|
||||
reset := features.InitWithReset(feat)
|
||||
defer reset()
|
||||
|
||||
atts := getAtts([]testData{
|
||||
{4, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
})
|
||||
want := getAtts([]testData{
|
||||
{4, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.DeepEqual(t, want, atts)
|
||||
})
|
||||
|
||||
t.Run("single att per slot", func(t *testing.T) {
|
||||
feat := features.Get()
|
||||
feat.EnableCommitteeAwarePacking = true
|
||||
reset := features.InitWithReset(feat)
|
||||
defer reset()
|
||||
|
||||
atts := getAtts([]testData{
|
||||
{1, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
{4, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
})
|
||||
want := getAtts([]testData{
|
||||
{4, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.DeepEqual(t, want, atts)
|
||||
})
|
||||
|
||||
t.Run("two atts on one of the slots", func(t *testing.T) {
|
||||
feat := features.Get()
|
||||
feat.EnableCommitteeAwarePacking = true
|
||||
reset := features.InitWithReset(feat)
|
||||
defer reset()
|
||||
|
||||
atts := getAtts([]testData{
|
||||
{1, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
{4, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{4, bitfield.Bitlist{0b11110000, 0b1}},
|
||||
})
|
||||
want := getAtts([]testData{
|
||||
{4, bitfield.Bitlist{0b11110000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.DeepEqual(t, want, atts)
|
||||
})
|
||||
|
||||
t.Run("compare to native sort", func(t *testing.T) {
|
||||
feat := features.Get()
|
||||
feat.EnableCommitteeAwarePacking = true
|
||||
reset := features.InitWithReset(feat)
|
||||
defer reset()
|
||||
|
||||
// The max-cover based approach will select 0b00001100 instead, despite lower bit count
|
||||
// (since it has two new/unknown bits).
|
||||
t.Run("max-cover", func(t *testing.T) {
|
||||
atts := getAtts([]testData{
|
||||
{1, bitfield.Bitlist{0b11000011, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11001000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b00001100, 0b1}},
|
||||
})
|
||||
want := getAtts([]testData{
|
||||
{1, bitfield.Bitlist{0b11000011, 0b1}},
|
||||
{1, bitfield.Bitlist{0b00001100, 0b1}},
|
||||
})
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.DeepEqual(t, want, atts)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("multiple slots", func(t *testing.T) {
|
||||
feat := features.Get()
|
||||
feat.EnableCommitteeAwarePacking = true
|
||||
reset := features.InitWithReset(feat)
|
||||
defer reset()
|
||||
|
||||
atts := getAtts([]testData{
|
||||
{2, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{4, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
{4, bitfield.Bitlist{0b11110000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{3, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
})
|
||||
want := getAtts([]testData{
|
||||
{4, bitfield.Bitlist{0b11110000, 0b1}},
|
||||
{3, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
{2, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.DeepEqual(t, want, atts)
|
||||
})
|
||||
|
||||
t.Run("follows max-cover", func(t *testing.T) {
|
||||
feat := features.Get()
|
||||
feat.EnableCommitteeAwarePacking = true
|
||||
reset := features.InitWithReset(feat)
|
||||
defer reset()
|
||||
|
||||
// Items at slot 4 must be first split into two lists by max-cover, with
|
||||
// 0b10000011 being selected and 0b11100001 being leftover (despite naive bit count suggesting otherwise).
|
||||
atts := getAtts([]testData{
|
||||
{4, bitfield.Bitlist{0b00000001, 0b1}},
|
||||
{4, bitfield.Bitlist{0b11100001, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
{2, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{4, bitfield.Bitlist{0b10000011, 0b1}},
|
||||
{4, bitfield.Bitlist{0b11111000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{3, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
})
|
||||
want := getAtts([]testData{
|
||||
{4, bitfield.Bitlist{0b11111000, 0b1}},
|
||||
{4, bitfield.Bitlist{0b10000011, 0b1}},
|
||||
{3, bitfield.Bitlist{0b11000000, 0b1}},
|
||||
{2, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
{1, bitfield.Bitlist{0b11100000, 0b1}},
|
||||
})
|
||||
atts, err := atts.sort()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.DeepEqual(t, want, atts)
|
||||
})
|
||||
}
|
||||
|
||||
func TestProposer_sort_DifferentCommittees(t *testing.T) {
|
||||
t.Run("one att per committee", func(t *testing.T) {
|
||||
feat := features.Get()
|
||||
feat.EnableCommitteeAwarePacking = true
|
||||
reset := features.InitWithReset(feat)
|
||||
defer reset()
|
||||
|
||||
c1_a1 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11111000, 0b1}, Data: ðpb.AttestationData{CommitteeIndex: 1}})
|
||||
c2_a1 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11100000, 0b1}, Data: ðpb.AttestationData{CommitteeIndex: 2}})
|
||||
atts := proposerAtts{c1_a1, c2_a1}
|
||||
atts, err := atts.sort()
|
||||
require.NoError(t, err)
|
||||
want := proposerAtts{c1_a1, c2_a1}
|
||||
assert.DeepEqual(t, want, atts)
|
||||
})
|
||||
t.Run("multiple atts per committee", func(t *testing.T) {
|
||||
feat := features.Get()
|
||||
feat.EnableCommitteeAwarePacking = true
|
||||
reset := features.InitWithReset(feat)
|
||||
defer reset()
|
||||
|
||||
c1_a1 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11111100, 0b1}, Data: ðpb.AttestationData{CommitteeIndex: 1}})
|
||||
c1_a2 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b10000010, 0b1}, Data: ðpb.AttestationData{CommitteeIndex: 1}})
|
||||
c2_a1 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11110000, 0b1}, Data: ðpb.AttestationData{CommitteeIndex: 2}})
|
||||
c2_a2 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11100000, 0b1}, Data: ðpb.AttestationData{CommitteeIndex: 2}})
|
||||
atts := proposerAtts{c1_a1, c1_a2, c2_a1, c2_a2}
|
||||
atts, err := atts.sort()
|
||||
require.NoError(t, err)
|
||||
|
||||
want := proposerAtts{c1_a1, c2_a1, c1_a2}
|
||||
assert.DeepEqual(t, want, atts)
|
||||
})
|
||||
t.Run("multiple atts per committee, multiple slots", func(t *testing.T) {
|
||||
feat := features.Get()
|
||||
feat.EnableCommitteeAwarePacking = true
|
||||
reset := features.InitWithReset(feat)
|
||||
defer reset()
|
||||
|
||||
s2_c1_a1 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11111100, 0b1}, Data: ðpb.AttestationData{Slot: 2, CommitteeIndex: 1}})
|
||||
s2_c1_a2 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b10000010, 0b1}, Data: ðpb.AttestationData{Slot: 2, CommitteeIndex: 1}})
|
||||
s2_c2_a1 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11110000, 0b1}, Data: ðpb.AttestationData{Slot: 2, CommitteeIndex: 2}})
|
||||
s2_c2_a2 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11000000, 0b1}, Data: ðpb.AttestationData{Slot: 2, CommitteeIndex: 2}})
|
||||
s1_c1_a1 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11111100, 0b1}, Data: ðpb.AttestationData{Slot: 1, CommitteeIndex: 1}})
|
||||
s1_c1_a2 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b10000010, 0b1}, Data: ðpb.AttestationData{Slot: 1, CommitteeIndex: 1}})
|
||||
s1_c2_a1 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11110000, 0b1}, Data: ðpb.AttestationData{Slot: 1, CommitteeIndex: 2}})
|
||||
s1_c2_a2 := util.HydrateAttestation(ðpb.Attestation{AggregationBits: bitfield.Bitlist{0b11000000, 0b1}, Data: ðpb.AttestationData{Slot: 1, CommitteeIndex: 2}})
|
||||
|
||||
// Arrange in some random order
|
||||
atts := proposerAtts{s1_c1_a1, s2_c1_a2, s1_c2_a2, s2_c2_a2, s1_c2_a1, s2_c2_a1, s1_c1_a2, s2_c1_a1}
|
||||
|
||||
atts, err := atts.sort()
|
||||
require.NoError(t, err)
|
||||
|
||||
want := proposerAtts{s2_c1_a1, s2_c2_a1, s2_c1_a2, s1_c1_a1, s1_c2_a1, s1_c1_a2}
|
||||
assert.DeepEqual(t, want, atts)
|
||||
})
|
||||
}
|
||||
|
||||
func TestProposer_ProposerAtts_dedup(t *testing.T) {
|
||||
data1 := util.HydrateAttestationData(ðpb.AttestationData{
|
||||
Slot: 4,
|
||||
|
||||
@@ -96,6 +96,27 @@ func setExecutionData(ctx context.Context, blk interfaces.SignedBeaconBlock, loc
|
||||
// Compare payload values between local and builder. Default to the local value if it is higher.
|
||||
localValueGwei := primitives.WeiToGwei(local.Bid)
|
||||
builderValueGwei := primitives.WeiToGwei(bid.Value())
|
||||
minBid := primitives.Gwei(params.BeaconConfig().MinBuilderBid)
|
||||
// Use local block if min bid is not attained
|
||||
if builderValueGwei < minBid {
|
||||
log.WithFields(logrus.Fields{
|
||||
"minBuilderBid": minBid,
|
||||
"builderGweiValue": builderValueGwei,
|
||||
}).Warn("Proposer: using local execution payload because min bid not attained")
|
||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
||||
}
|
||||
|
||||
// Use local block if min difference is not attained
|
||||
minDiff := localValueGwei + primitives.Gwei(params.BeaconConfig().MinBuilderDiff)
|
||||
if builderValueGwei < minDiff {
|
||||
log.WithFields(logrus.Fields{
|
||||
"localGweiValue": localValueGwei,
|
||||
"minBidDiff": minDiff,
|
||||
"builderGweiValue": builderValueGwei,
|
||||
}).Warn("Proposer: using local execution payload because min difference with local value was not attained")
|
||||
return local.Bid, local.BlobsBundle, setLocalExecution(blk, local)
|
||||
}
|
||||
|
||||
// Use builder payload if the following in true:
|
||||
// builder_bid_value * builderBoostFactor(default 100) > local_block_value * (local-block-value-boost + 100)
|
||||
boost := primitives.Gwei(params.BeaconConfig().LocalBlockValueBoost)
|
||||
|
||||
@@ -420,7 +420,41 @@ func TestServer_setExecutionData(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(3), e.BlockNumber()) // Local block
|
||||
|
||||
require.LogsContain(t, hook, "builderGweiValue=1 localBoostPercentage=0 localGweiValue=2")
|
||||
require.LogsContain(t, hook, "\"Proposer: using local execution payload because min difference with local value was not attained\" builderGweiValue=1 localGweiValue=2")
|
||||
})
|
||||
t.Run("Builder configured. Builder block does not achieve min bid", func(t *testing.T) {
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
cfg.MinBuilderBid = 5
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
blk, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockCapella())
|
||||
require.NoError(t, err)
|
||||
elBid := primitives.Uint64ToWei(2 * 1e9)
|
||||
ed, err := blocks.NewWrappedExecutionData(&v1.ExecutionPayloadCapella{BlockNumber: 3})
|
||||
require.NoError(t, err)
|
||||
vs.ExecutionEngineCaller = &powtesting.EngineClient{PayloadIDBytes: id, GetPayloadResponse: &blocks.GetPayloadResponse{ExecutionData: ed, Bid: elBid}}
|
||||
b := blk.Block()
|
||||
res, err := vs.getLocalPayload(ctx, b, capellaTransitionState)
|
||||
require.NoError(t, err)
|
||||
builderBid, err := vs.getBuilderPayloadAndBlobs(ctx, b.Slot(), b.ProposerIndex())
|
||||
require.NoError(t, err)
|
||||
_, err = builderBid.Header()
|
||||
require.NoError(t, err)
|
||||
builderKzgCommitments, err := builderBid.BlobKzgCommitments()
|
||||
if builderBid.Version() >= version.Deneb {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
require.DeepEqual(t, [][]uint8{}, builderKzgCommitments)
|
||||
_, bundle, err := setExecutionData(context.Background(), blk, res, builderBid, defaultBuilderBoostFactor)
|
||||
require.NoError(t, err)
|
||||
require.IsNil(t, bundle)
|
||||
e, err := blk.Block().Body().Execution()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(3), e.BlockNumber()) // Local block
|
||||
|
||||
require.LogsContain(t, hook, "\"Proposer: using local execution payload because min bid not attained\" builderGweiValue=1 minBuilderBid=5")
|
||||
cfg.MinBuilderBid = 0
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
})
|
||||
t.Run("Builder configured. Local block and local boost has higher value", func(t *testing.T) {
|
||||
cfg := params.BeaconConfig().Copy()
|
||||
|
||||
@@ -49,7 +49,7 @@ func BenchmarkProposerAtts_sortByProfitability(b *testing.B) {
|
||||
for i, att := range atts {
|
||||
attsCopy[i] = att.(*ethpb.Attestation).Copy()
|
||||
}
|
||||
_, err := attsCopy.sortByProfitability()
|
||||
_, err := attsCopy.sort()
|
||||
require.NoError(b, err, "Could not sort attestations by profitability")
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"handlers.go",
|
||||
"server.go",
|
||||
"validator_performance.go",
|
||||
],
|
||||
@@ -10,9 +11,17 @@ go_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api/server/structs:go_default_library",
|
||||
"//beacon-chain/blockchain:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/rpc/core:go_default_library",
|
||||
"//beacon-chain/rpc/eth/shared:go_default_library",
|
||||
"//beacon-chain/rpc/lookup:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//network/httputil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_gorilla_mux//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
],
|
||||
@@ -20,23 +29,42 @@ go_library(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["validator_performance_test.go"],
|
||||
srcs = [
|
||||
"handlers_test.go",
|
||||
"validator_performance_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//api/server/structs:go_default_library",
|
||||
"//beacon-chain/blockchain/testing:go_default_library",
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
"//beacon-chain/db/testing:go_default_library",
|
||||
"//beacon-chain/forkchoice/doubly-linked-tree:go_default_library",
|
||||
"//beacon-chain/rpc/core:go_default_library",
|
||||
"//beacon-chain/rpc/testutil:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/stategen:go_default_library",
|
||||
"//beacon-chain/state/stategen/mock:go_default_library",
|
||||
"//beacon-chain/sync/initial-sync/testing:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/blocks/testing:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"//time:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_gorilla_mux//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
117
beacon-chain/rpc/prysm/validator/handlers.go
Normal file
117
beacon-chain/rpc/prysm/validator/handlers.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/network/httputil"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// GetParticipation retrieves the validator participation information for a given epoch,
|
||||
// it returns the information about validator's participation rate in voting on the proof of stake
|
||||
// rules based on their balance compared to the total active validator balance.
|
||||
func (s *Server) GetParticipation(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.GetParticipation")
|
||||
defer span.End()
|
||||
|
||||
stateId := mux.Vars(r)["state_id"]
|
||||
if stateId == "" {
|
||||
httputil.HandleError(w, "state_id is required in URL params", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
st, err := s.Stater.State(ctx, []byte(stateId))
|
||||
if err != nil {
|
||||
shared.WriteStateFetchError(w, err)
|
||||
return
|
||||
}
|
||||
stEpoch := slots.ToEpoch(st.Slot())
|
||||
vp, rpcError := s.CoreService.ValidatorParticipation(ctx, stEpoch)
|
||||
if rpcError != nil {
|
||||
httputil.HandleError(w, rpcError.Err.Error(), core.ErrorReasonToHTTP(rpcError.Reason))
|
||||
return
|
||||
}
|
||||
|
||||
response := &structs.GetValidatorParticipationResponse{
|
||||
Epoch: fmt.Sprintf("%d", vp.Epoch),
|
||||
Finalized: vp.Finalized,
|
||||
Participation: &structs.ValidatorParticipation{
|
||||
GlobalParticipationRate: fmt.Sprintf("%f", vp.Participation.GlobalParticipationRate),
|
||||
VotedEther: fmt.Sprintf("%d", vp.Participation.VotedEther),
|
||||
EligibleEther: fmt.Sprintf("%d", vp.Participation.EligibleEther),
|
||||
CurrentEpochActiveGwei: fmt.Sprintf("%d", vp.Participation.CurrentEpochActiveGwei),
|
||||
CurrentEpochAttestingGwei: fmt.Sprintf("%d", vp.Participation.CurrentEpochAttestingGwei),
|
||||
CurrentEpochTargetAttestingGwei: fmt.Sprintf("%d", vp.Participation.CurrentEpochTargetAttestingGwei),
|
||||
PreviousEpochActiveGwei: fmt.Sprintf("%d", vp.Participation.PreviousEpochActiveGwei),
|
||||
PreviousEpochAttestingGwei: fmt.Sprintf("%d", vp.Participation.PreviousEpochAttestingGwei),
|
||||
PreviousEpochTargetAttestingGwei: fmt.Sprintf("%d", vp.Participation.PreviousEpochTargetAttestingGwei),
|
||||
PreviousEpochHeadAttestingGwei: fmt.Sprintf("%d", vp.Participation.PreviousEpochHeadAttestingGwei),
|
||||
},
|
||||
}
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
|
||||
// GetActiveSetChanges retrieves the active set changes for a given epoch.
|
||||
//
|
||||
// This data includes any activations, voluntary exits, and involuntary
|
||||
// ejections.
|
||||
func (s *Server) GetActiveSetChanges(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.GetActiveSetChanges")
|
||||
defer span.End()
|
||||
|
||||
stateId := mux.Vars(r)["state_id"]
|
||||
if stateId == "" {
|
||||
httputil.HandleError(w, "state_id is required in URL params", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
st, err := s.Stater.State(ctx, []byte(stateId))
|
||||
if err != nil {
|
||||
shared.WriteStateFetchError(w, err)
|
||||
return
|
||||
}
|
||||
stEpoch := slots.ToEpoch(st.Slot())
|
||||
|
||||
as, rpcError := s.CoreService.ValidatorActiveSetChanges(ctx, stEpoch)
|
||||
if rpcError != nil {
|
||||
httputil.HandleError(w, rpcError.Err.Error(), core.ErrorReasonToHTTP(rpcError.Reason))
|
||||
return
|
||||
}
|
||||
|
||||
response := &structs.ActiveSetChanges{
|
||||
Epoch: fmt.Sprintf("%d", as.Epoch),
|
||||
ActivatedPublicKeys: byteSlice2dToStringSlice(as.ActivatedPublicKeys),
|
||||
ActivatedIndices: uint64SliceToStringSlice(as.ActivatedIndices),
|
||||
ExitedPublicKeys: byteSlice2dToStringSlice(as.ExitedPublicKeys),
|
||||
ExitedIndices: uint64SliceToStringSlice(as.ExitedIndices),
|
||||
SlashedPublicKeys: byteSlice2dToStringSlice(as.SlashedPublicKeys),
|
||||
SlashedIndices: uint64SliceToStringSlice(as.SlashedIndices),
|
||||
EjectedPublicKeys: byteSlice2dToStringSlice(as.EjectedPublicKeys),
|
||||
EjectedIndices: uint64SliceToStringSlice(as.EjectedIndices),
|
||||
}
|
||||
httputil.WriteJson(w, response)
|
||||
}
|
||||
|
||||
func byteSlice2dToStringSlice(byteArrays [][]byte) []string {
|
||||
s := make([]string, len(byteArrays))
|
||||
for i, b := range byteArrays {
|
||||
s[i] = hexutil.Encode(b)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func uint64SliceToStringSlice(indices []primitives.ValidatorIndex) []string {
|
||||
s := make([]string, len(indices))
|
||||
for i, u := range indices {
|
||||
s[i] = fmt.Sprintf("%d", u)
|
||||
}
|
||||
return s
|
||||
}
|
||||
558
beacon-chain/rpc/prysm/validator/handlers_test.go
Normal file
558
beacon-chain/rpc/prysm/validator/handlers_test.go
Normal file
@@ -0,0 +1,558 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
|
||||
mock "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
dbTest "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/testutil"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen"
|
||||
mockstategen "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen/mock"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
blocktest "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks/testing"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
prysmTime "github.com/prysmaticlabs/prysm/v5/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
)
|
||||
|
||||
func addDefaultReplayerBuilder(s *Server, h stategen.HistoryAccessor) {
|
||||
cc := &mockstategen.CanonicalChecker{Is: true, Err: nil}
|
||||
cs := &mockstategen.CurrentSlotter{Slot: math.MaxUint64 - 1}
|
||||
s.CoreService.ReplayerBuilder = stategen.NewCanonicalHistory(h, cc, cs)
|
||||
}
|
||||
|
||||
func TestServer_GetValidatorParticipation_NoState(t *testing.T) {
|
||||
headState, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, headState.SetSlot(0))
|
||||
|
||||
var st state.BeaconState
|
||||
st, _ = util.DeterministicGenesisState(t, 4)
|
||||
|
||||
s := &Server{
|
||||
Stater: &testutil.MockStater{
|
||||
BeaconState: st,
|
||||
},
|
||||
CoreService: &core.Service{
|
||||
HeadFetcher: &mock.ChainService{
|
||||
State: headState,
|
||||
},
|
||||
GenesisTimeFetcher: &mock.ChainService{},
|
||||
},
|
||||
}
|
||||
|
||||
url := "http://example.com" + fmt.Sprintf("%d", slots.ToEpoch(s.CoreService.GenesisTimeFetcher.CurrentSlot())+1)
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetParticipation(writer, request)
|
||||
require.Equal(t, http.StatusBadRequest, writer.Code)
|
||||
require.StringContains(t, "state_id is required in URL params", writer.Body.String())
|
||||
}
|
||||
|
||||
func TestServer_GetValidatorParticipation_CurrentAndPrevEpoch(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
beaconDB := dbTest.SetupDB(t)
|
||||
|
||||
ctx := context.Background()
|
||||
validatorCount := uint64(32)
|
||||
|
||||
validators := make([]*ethpb.Validator, validatorCount)
|
||||
balances := make([]uint64, validatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
PublicKey: bytesutil.ToBytes(uint64(i), 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
}
|
||||
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||
}
|
||||
|
||||
atts := []*ethpb.PendingAttestation{{
|
||||
Data: util.HydrateAttestationData(ðpb.AttestationData{}),
|
||||
InclusionDelay: 1,
|
||||
AggregationBits: bitfield.NewBitlist(validatorCount / uint64(params.BeaconConfig().SlotsPerEpoch)),
|
||||
}}
|
||||
headState, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, headState.SetSlot(8))
|
||||
require.NoError(t, headState.SetValidators(validators))
|
||||
require.NoError(t, headState.SetBalances(balances))
|
||||
require.NoError(t, headState.AppendCurrentEpochAttestations(atts[0]))
|
||||
require.NoError(t, headState.AppendPreviousEpochAttestations(atts[0]))
|
||||
|
||||
b := util.NewBeaconBlock()
|
||||
b.Block.Slot = 8
|
||||
util.SaveBlock(t, ctx, beaconDB, b)
|
||||
bRoot, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, beaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Root: bRoot[:]}))
|
||||
require.NoError(t, beaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Root: params.BeaconConfig().ZeroHash[:]}))
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bRoot))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveState(ctx, headState, bRoot))
|
||||
require.NoError(t, beaconDB.SaveState(ctx, headState, params.BeaconConfig().ZeroHash))
|
||||
|
||||
m := &mock.ChainService{State: headState}
|
||||
offset := int64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
|
||||
|
||||
var st state.BeaconState
|
||||
st, _ = util.DeterministicGenesisState(t, 4)
|
||||
|
||||
s := &Server{
|
||||
Stater: &testutil.MockStater{
|
||||
BeaconState: st,
|
||||
},
|
||||
BeaconDB: beaconDB,
|
||||
CoreService: &core.Service{
|
||||
HeadFetcher: m,
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
GenesisTimeFetcher: &mock.ChainService{
|
||||
Genesis: prysmTime.Now().Add(time.Duration(-1*offset) * time.Second),
|
||||
},
|
||||
FinalizedFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}},
|
||||
},
|
||||
CanonicalFetcher: &mock.ChainService{
|
||||
CanonicalRoots: map[[32]byte]bool{
|
||||
bRoot: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
addDefaultReplayerBuilder(s, beaconDB)
|
||||
|
||||
url := "http://example.com"
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetParticipation(writer, request)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
want := &structs.GetValidatorParticipationResponse{
|
||||
Participation: &structs.ValidatorParticipation{
|
||||
GlobalParticipationRate: fmt.Sprintf("%f", float32(params.BeaconConfig().EffectiveBalanceIncrement)/float32(validatorCount*params.BeaconConfig().MaxEffectiveBalance)),
|
||||
VotedEther: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
EligibleEther: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
CurrentEpochActiveGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
CurrentEpochAttestingGwei: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
CurrentEpochTargetAttestingGwei: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
PreviousEpochActiveGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
PreviousEpochAttestingGwei: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
PreviousEpochTargetAttestingGwei: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
PreviousEpochHeadAttestingGwei: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
},
|
||||
}
|
||||
var vp *structs.GetValidatorParticipationResponse
|
||||
err = json.NewDecoder(writer.Body).Decode(&vp)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Compare the response with the expected values
|
||||
assert.Equal(t, true, vp.Finalized, "Incorrect validator participation response")
|
||||
assert.Equal(t, *want.Participation, *vp.Participation, "Incorrect validator participation response")
|
||||
}
|
||||
|
||||
func TestServer_GetValidatorParticipation_OrphanedUntilGenesis(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
params.SetupTestConfigCleanup(t)
|
||||
params.OverrideBeaconConfig(params.BeaconConfig())
|
||||
|
||||
beaconDB := dbTest.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
validatorCount := uint64(100)
|
||||
|
||||
validators := make([]*ethpb.Validator, validatorCount)
|
||||
balances := make([]uint64, validatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
PublicKey: bytesutil.ToBytes(uint64(i), 48),
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
}
|
||||
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||
}
|
||||
|
||||
atts := []*ethpb.PendingAttestation{{
|
||||
Data: util.HydrateAttestationData(ðpb.AttestationData{}),
|
||||
InclusionDelay: 1,
|
||||
AggregationBits: bitfield.NewBitlist(validatorCount / uint64(params.BeaconConfig().SlotsPerEpoch)),
|
||||
}}
|
||||
headState, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, headState.SetSlot(0))
|
||||
require.NoError(t, headState.SetValidators(validators))
|
||||
require.NoError(t, headState.SetBalances(balances))
|
||||
require.NoError(t, headState.AppendCurrentEpochAttestations(atts[0]))
|
||||
require.NoError(t, headState.AppendPreviousEpochAttestations(atts[0]))
|
||||
|
||||
b := util.NewBeaconBlock()
|
||||
util.SaveBlock(t, ctx, beaconDB, b)
|
||||
bRoot, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bRoot))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveState(ctx, headState, bRoot))
|
||||
require.NoError(t, beaconDB.SaveState(ctx, headState, params.BeaconConfig().ZeroHash))
|
||||
|
||||
m := &mock.ChainService{State: headState}
|
||||
offset := int64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
|
||||
|
||||
var st state.BeaconState
|
||||
st, _ = util.DeterministicGenesisState(t, 4)
|
||||
s := &Server{
|
||||
BeaconDB: beaconDB,
|
||||
Stater: &testutil.MockStater{
|
||||
BeaconState: st,
|
||||
},
|
||||
CoreService: &core.Service{
|
||||
HeadFetcher: m,
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
GenesisTimeFetcher: &mock.ChainService{
|
||||
Genesis: prysmTime.Now().Add(time.Duration(-1*offset) * time.Second),
|
||||
},
|
||||
FinalizedFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}},
|
||||
},
|
||||
CanonicalFetcher: &mock.ChainService{
|
||||
CanonicalRoots: map[[32]byte]bool{
|
||||
bRoot: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
addDefaultReplayerBuilder(s, beaconDB)
|
||||
|
||||
url := "http://example.com"
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetParticipation(writer, request)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
want := &structs.GetValidatorParticipationResponse{
|
||||
Participation: &structs.ValidatorParticipation{
|
||||
GlobalParticipationRate: fmt.Sprintf("%f", float32(params.BeaconConfig().EffectiveBalanceIncrement)/float32(validatorCount*params.BeaconConfig().MaxEffectiveBalance)),
|
||||
VotedEther: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
EligibleEther: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
CurrentEpochActiveGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
CurrentEpochAttestingGwei: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
CurrentEpochTargetAttestingGwei: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
PreviousEpochActiveGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
PreviousEpochAttestingGwei: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
PreviousEpochTargetAttestingGwei: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
PreviousEpochHeadAttestingGwei: fmt.Sprintf("%d", params.BeaconConfig().EffectiveBalanceIncrement),
|
||||
},
|
||||
}
|
||||
var vp *structs.GetValidatorParticipationResponse
|
||||
err = json.NewDecoder(writer.Body).Decode(&vp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.DeepEqual(t, true, vp.Finalized, "Incorrect validator participation respond")
|
||||
assert.DeepEqual(t, want.Participation, vp.Participation, "Incorrect validator participation respond")
|
||||
}
|
||||
|
||||
func TestServer_GetValidatorParticipation_CurrentAndPrevEpochWithBits(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
params.OverrideBeaconConfig(params.BeaconConfig())
|
||||
transition.SkipSlotCache.Disable()
|
||||
|
||||
t.Run("altair", func(t *testing.T) {
|
||||
validatorCount := uint64(32)
|
||||
genState, _ := util.DeterministicGenesisStateAltair(t, validatorCount)
|
||||
|
||||
c, err := altair.NextSyncCommittee(context.Background(), genState)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, genState.SetCurrentSyncCommittee(c))
|
||||
|
||||
bits := make([]byte, validatorCount)
|
||||
for i := range bits {
|
||||
bits[i] = 0xff
|
||||
}
|
||||
require.NoError(t, genState.SetCurrentParticipationBits(bits))
|
||||
require.NoError(t, genState.SetPreviousParticipationBits(bits))
|
||||
gb, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockAltair())
|
||||
assert.NoError(t, err)
|
||||
runGetValidatorParticipationCurrentEpoch(t, genState, gb)
|
||||
})
|
||||
|
||||
t.Run("bellatrix", func(t *testing.T) {
|
||||
validatorCount := uint64(32)
|
||||
genState, _ := util.DeterministicGenesisStateBellatrix(t, validatorCount)
|
||||
c, err := altair.NextSyncCommittee(context.Background(), genState)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, genState.SetCurrentSyncCommittee(c))
|
||||
|
||||
bits := make([]byte, validatorCount)
|
||||
for i := range bits {
|
||||
bits[i] = 0xff
|
||||
}
|
||||
require.NoError(t, genState.SetCurrentParticipationBits(bits))
|
||||
require.NoError(t, genState.SetPreviousParticipationBits(bits))
|
||||
gb, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockBellatrix())
|
||||
assert.NoError(t, err)
|
||||
runGetValidatorParticipationCurrentEpoch(t, genState, gb)
|
||||
})
|
||||
|
||||
t.Run("capella", func(t *testing.T) {
|
||||
validatorCount := uint64(32)
|
||||
genState, _ := util.DeterministicGenesisStateCapella(t, validatorCount)
|
||||
c, err := altair.NextSyncCommittee(context.Background(), genState)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, genState.SetCurrentSyncCommittee(c))
|
||||
|
||||
bits := make([]byte, validatorCount)
|
||||
for i := range bits {
|
||||
bits[i] = 0xff
|
||||
}
|
||||
require.NoError(t, genState.SetCurrentParticipationBits(bits))
|
||||
require.NoError(t, genState.SetPreviousParticipationBits(bits))
|
||||
gb, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlockCapella())
|
||||
assert.NoError(t, err)
|
||||
runGetValidatorParticipationCurrentEpoch(t, genState, gb)
|
||||
})
|
||||
}
|
||||
|
||||
func runGetValidatorParticipationCurrentEpoch(t *testing.T, genState state.BeaconState, gb interfaces.SignedBeaconBlock) {
|
||||
helpers.ClearCache()
|
||||
beaconDB := dbTest.SetupDB(t)
|
||||
|
||||
ctx := context.Background()
|
||||
validatorCount := uint64(32)
|
||||
|
||||
gsr, err := genState.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
gb, err = blocktest.SetBlockStateRoot(gb, gsr)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
gRoot, err := gb.Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, beaconDB.SaveState(ctx, genState, gRoot))
|
||||
require.NoError(t, beaconDB.SaveBlock(ctx, gb))
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot))
|
||||
|
||||
m := &mock.ChainService{State: genState}
|
||||
offset := int64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().SecondsPerSlot))
|
||||
|
||||
s := &Server{
|
||||
BeaconDB: beaconDB,
|
||||
Stater: &testutil.MockStater{
|
||||
BeaconState: genState,
|
||||
},
|
||||
CoreService: &core.Service{
|
||||
HeadFetcher: m,
|
||||
StateGen: stategen.New(beaconDB, doublylinkedtree.New()),
|
||||
GenesisTimeFetcher: &mock.ChainService{
|
||||
Genesis: prysmTime.Now().Add(time.Duration(-1*offset) * time.Second),
|
||||
},
|
||||
FinalizedFetcher: &mock.ChainService{FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 100}},
|
||||
},
|
||||
}
|
||||
addDefaultReplayerBuilder(s, beaconDB)
|
||||
|
||||
url := "http://example.com"
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
request = mux.SetURLVars(request, map[string]string{"state_id": "head"})
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetParticipation(writer, request)
|
||||
assert.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
want := &structs.GetValidatorParticipationResponse{
|
||||
Participation: &structs.ValidatorParticipation{
|
||||
GlobalParticipationRate: "1.000000",
|
||||
VotedEther: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
EligibleEther: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
CurrentEpochActiveGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
CurrentEpochAttestingGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
CurrentEpochTargetAttestingGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
PreviousEpochActiveGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
PreviousEpochAttestingGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
PreviousEpochTargetAttestingGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
PreviousEpochHeadAttestingGwei: fmt.Sprintf("%d", validatorCount*params.BeaconConfig().MaxEffectiveBalance),
|
||||
},
|
||||
}
|
||||
|
||||
var vp *structs.GetValidatorParticipationResponse
|
||||
err = json.NewDecoder(writer.Body).Decode(&vp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.DeepEqual(t, true, vp.Finalized, "Incorrect validator participation respond")
|
||||
assert.DeepEqual(t, *want.Participation, *vp.Participation, "Incorrect validator participation respond")
|
||||
}
|
||||
|
||||
func TestServer_GetValidatorActiveSetChanges_NoState(t *testing.T) {
|
||||
beaconDB := dbTest.SetupDB(t)
|
||||
var st state.BeaconState
|
||||
st, _ = util.DeterministicGenesisState(t, 4)
|
||||
|
||||
s := &Server{
|
||||
Stater: &testutil.MockStater{
|
||||
BeaconState: st,
|
||||
},
|
||||
CoreService: &core.Service{
|
||||
BeaconDB: beaconDB,
|
||||
GenesisTimeFetcher: &mock.ChainService{},
|
||||
HeadFetcher: &mock.ChainService{
|
||||
State: st,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
url := "http://example.com" + fmt.Sprintf("%d", slots.ToEpoch(s.CoreService.GenesisTimeFetcher.CurrentSlot())+1)
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
request = mux.SetURLVars(request, map[string]string{"state_id": ""})
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetActiveSetChanges(writer, request)
|
||||
require.Equal(t, http.StatusBadRequest, writer.Code)
|
||||
require.StringContains(t, "state_id is required in URL params", writer.Body.String())
|
||||
}
|
||||
|
||||
func TestServer_GetValidatorActiveSetChanges(t *testing.T) {
|
||||
beaconDB := dbTest.SetupDB(t)
|
||||
|
||||
ctx := context.Background()
|
||||
validators := make([]*ethpb.Validator, 8)
|
||||
headState, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, headState.SetSlot(0))
|
||||
require.NoError(t, headState.SetValidators(validators))
|
||||
for i := 0; i < len(validators); i++ {
|
||||
activationEpoch := params.BeaconConfig().FarFutureEpoch
|
||||
withdrawableEpoch := params.BeaconConfig().FarFutureEpoch
|
||||
exitEpoch := params.BeaconConfig().FarFutureEpoch
|
||||
slashed := false
|
||||
balance := params.BeaconConfig().MaxEffectiveBalance
|
||||
// Mark indices divisible by two as activated.
|
||||
if i%2 == 0 {
|
||||
activationEpoch = 0
|
||||
} else if i%3 == 0 {
|
||||
// Mark indices divisible by 3 as slashed.
|
||||
withdrawableEpoch = params.BeaconConfig().EpochsPerSlashingsVector
|
||||
slashed = true
|
||||
} else if i%5 == 0 {
|
||||
// Mark indices divisible by 5 as exited.
|
||||
exitEpoch = 0
|
||||
withdrawableEpoch = params.BeaconConfig().MinValidatorWithdrawabilityDelay
|
||||
} else if i%7 == 0 {
|
||||
// Mark indices divisible by 7 as ejected.
|
||||
exitEpoch = 0
|
||||
withdrawableEpoch = params.BeaconConfig().MinValidatorWithdrawabilityDelay
|
||||
balance = params.BeaconConfig().EjectionBalance
|
||||
}
|
||||
err := headState.UpdateValidatorAtIndex(primitives.ValidatorIndex(i), ðpb.Validator{
|
||||
ActivationEpoch: activationEpoch,
|
||||
PublicKey: pubKey(uint64(i)),
|
||||
EffectiveBalance: balance,
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
WithdrawableEpoch: withdrawableEpoch,
|
||||
Slashed: slashed,
|
||||
ExitEpoch: exitEpoch,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
b := util.NewBeaconBlock()
|
||||
util.SaveBlock(t, ctx, beaconDB, b)
|
||||
|
||||
gRoot, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot))
|
||||
require.NoError(t, beaconDB.SaveState(ctx, headState, gRoot))
|
||||
|
||||
var st state.BeaconState
|
||||
st, _ = util.DeterministicGenesisState(t, 4)
|
||||
s := &Server{
|
||||
Stater: &testutil.MockStater{
|
||||
BeaconState: st,
|
||||
},
|
||||
CoreService: &core.Service{
|
||||
FinalizedFetcher: &mock.ChainService{
|
||||
FinalizedCheckPoint: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, fieldparams.RootLength)},
|
||||
},
|
||||
GenesisTimeFetcher: &mock.ChainService{},
|
||||
},
|
||||
}
|
||||
addDefaultReplayerBuilder(s, beaconDB)
|
||||
|
||||
url := "http://example.com"
|
||||
request := httptest.NewRequest(http.MethodGet, url, nil)
|
||||
request = mux.SetURLVars(request, map[string]string{"state_id": "genesis"})
|
||||
writer := httptest.NewRecorder()
|
||||
writer.Body = &bytes.Buffer{}
|
||||
|
||||
s.GetActiveSetChanges(writer, request)
|
||||
require.Equal(t, http.StatusOK, writer.Code)
|
||||
|
||||
wantedActive := []string{
|
||||
hexutil.Encode(pubKey(0)),
|
||||
hexutil.Encode(pubKey(2)),
|
||||
hexutil.Encode(pubKey(4)),
|
||||
hexutil.Encode(pubKey(6)),
|
||||
}
|
||||
wantedActiveIndices := []string{"0", "2", "4", "6"}
|
||||
wantedExited := []string{
|
||||
hexutil.Encode(pubKey(5)),
|
||||
}
|
||||
wantedExitedIndices := []string{"5"}
|
||||
wantedSlashed := []string{
|
||||
hexutil.Encode(pubKey(3)),
|
||||
}
|
||||
wantedSlashedIndices := []string{"3"}
|
||||
wantedEjected := []string{
|
||||
hexutil.Encode(pubKey(7)),
|
||||
}
|
||||
wantedEjectedIndices := []string{"7"}
|
||||
want := &structs.ActiveSetChanges{
|
||||
Epoch: "0",
|
||||
ActivatedPublicKeys: wantedActive,
|
||||
ActivatedIndices: wantedActiveIndices,
|
||||
ExitedPublicKeys: wantedExited,
|
||||
ExitedIndices: wantedExitedIndices,
|
||||
SlashedPublicKeys: wantedSlashed,
|
||||
SlashedIndices: wantedSlashedIndices,
|
||||
EjectedPublicKeys: wantedEjected,
|
||||
EjectedIndices: wantedEjectedIndices,
|
||||
}
|
||||
|
||||
var as *structs.ActiveSetChanges
|
||||
err = json.NewDecoder(writer.Body).Decode(&as)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, *want, *as)
|
||||
}
|
||||
|
||||
func pubKey(i uint64) []byte {
|
||||
pubKey := make([]byte, params.BeaconConfig().BLSPubkeyLength)
|
||||
binary.LittleEndian.PutUint64(pubKey, i)
|
||||
return pubKey
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/core"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/lookup"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
CoreService *core.Service
|
||||
BeaconDB db.ReadOnlyDatabase
|
||||
Stater lookup.Stater
|
||||
CanonicalFetcher blockchain.CanonicalFetcher
|
||||
FinalizationFetcher blockchain.FinalizationFetcher
|
||||
ChainInfoFetcher blockchain.ChainInfoFetcher
|
||||
CoreService *core.Service
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// GetValidatorPerformance is an HTTP handler for GetValidatorPerformance.
|
||||
func (s *Server) GetValidatorPerformance(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.GetValidatorPerformance")
|
||||
// GetPerformance is an HTTP handler for GetPerformance.
|
||||
func (s *Server) GetPerformance(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := trace.StartSpan(r.Context(), "validator.GetPerformance")
|
||||
defer span.End()
|
||||
|
||||
var req structs.GetValidatorPerformanceRequest
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance))
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance))
|
||||
req := httptest.NewRequest("POST", "/foo", nil)
|
||||
|
||||
client := &http.Client{}
|
||||
@@ -86,7 +86,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) {
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance))
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance))
|
||||
req := httptest.NewRequest("POST", "/foo", &buf)
|
||||
client := &http.Client{}
|
||||
rawResp, err := client.Post(srv.URL, "application/json", req.Body)
|
||||
@@ -151,7 +151,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) {
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance))
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance))
|
||||
req := httptest.NewRequest("POST", "/foo", &buf)
|
||||
client := &http.Client{}
|
||||
rawResp, err := client.Post(srv.URL, "application/json", req.Body)
|
||||
@@ -216,7 +216,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) {
|
||||
err = json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance))
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance))
|
||||
req := httptest.NewRequest("POST", "/foo", &buf)
|
||||
client := &http.Client{}
|
||||
rawResp, err := client.Post(srv.URL, "application/json", req.Body)
|
||||
@@ -278,7 +278,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) {
|
||||
err := json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance))
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance))
|
||||
req := httptest.NewRequest("POST", "/foo", &buf)
|
||||
client := &http.Client{}
|
||||
rawResp, err := client.Post(srv.URL, "application/json", req.Body)
|
||||
@@ -340,7 +340,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) {
|
||||
err := json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance))
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance))
|
||||
req := httptest.NewRequest("POST", "/foo", &buf)
|
||||
client := &http.Client{}
|
||||
rawResp, err := client.Post(srv.URL, "application/json", req.Body)
|
||||
@@ -402,7 +402,7 @@ func TestServer_GetValidatorPerformance(t *testing.T) {
|
||||
err := json.NewEncoder(&buf).Encode(request)
|
||||
require.NoError(t, err)
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetValidatorPerformance))
|
||||
srv := httptest.NewServer(http.HandlerFunc(vs.GetPerformance))
|
||||
req := httptest.NewRequest("POST", "/foo", &buf)
|
||||
client := &http.Client{}
|
||||
rawResp, err := client.Post(srv.URL, "application/json", req.Body)
|
||||
|
||||
@@ -215,6 +215,7 @@ func NewService(ctx context.Context, cfg *Config) *Service {
|
||||
}
|
||||
rewardFetcher := &rewards.BlockRewardService{Replayer: ch, DB: s.cfg.BeaconDB}
|
||||
coreService := &core.Service{
|
||||
BeaconDB: s.cfg.BeaconDB,
|
||||
HeadFetcher: s.cfg.HeadFetcher,
|
||||
GenesisTimeFetcher: s.cfg.GenesisTimeFetcher,
|
||||
SyncChecker: s.cfg.SyncService,
|
||||
@@ -225,6 +226,7 @@ func NewService(ctx context.Context, cfg *Config) *Service {
|
||||
StateGen: s.cfg.StateGen,
|
||||
P2P: s.cfg.Broadcaster,
|
||||
FinalizedFetcher: s.cfg.FinalizationFetcher,
|
||||
ReplayerBuilder: ch,
|
||||
OptimisticModeFetcher: s.cfg.OptimisticModeFetcher,
|
||||
}
|
||||
validatorServer := &validatorv1alpha1.Server{
|
||||
|
||||
@@ -43,17 +43,17 @@ func TestBeaconStateMerkleProofs_altair(t *testing.T) {
|
||||
t.Run("current sync committee", func(t *testing.T) {
|
||||
cscp, err := altair.CurrentSyncCommitteeProof(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(cscp), 5)
|
||||
require.Equal(t, 5, len(cscp))
|
||||
for i, bytes := range cscp {
|
||||
require.Equal(t, hexutil.Encode(bytes), results[i])
|
||||
require.Equal(t, results[i], hexutil.Encode(bytes))
|
||||
}
|
||||
})
|
||||
t.Run("next sync committee", func(t *testing.T) {
|
||||
nscp, err := altair.NextSyncCommitteeProof(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(nscp), 5)
|
||||
require.Equal(t, 5, len(nscp))
|
||||
for i, bytes := range nscp {
|
||||
require.Equal(t, hexutil.Encode(bytes), results[i])
|
||||
require.Equal(t, results[i], hexutil.Encode(bytes))
|
||||
}
|
||||
})
|
||||
t.Run("finalized root", func(t *testing.T) {
|
||||
@@ -112,17 +112,17 @@ func TestBeaconStateMerkleProofs_bellatrix(t *testing.T) {
|
||||
t.Run("current sync committee", func(t *testing.T) {
|
||||
cscp, err := bellatrix.CurrentSyncCommitteeProof(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(cscp), 5)
|
||||
require.Equal(t, 5, len(cscp))
|
||||
for i, bytes := range cscp {
|
||||
require.Equal(t, hexutil.Encode(bytes), results[i])
|
||||
require.Equal(t, results[i], hexutil.Encode(bytes))
|
||||
}
|
||||
})
|
||||
t.Run("next sync committee", func(t *testing.T) {
|
||||
nscp, err := bellatrix.NextSyncCommitteeProof(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(nscp), 5)
|
||||
require.Equal(t, 5, len(nscp))
|
||||
for i, bytes := range nscp {
|
||||
require.Equal(t, hexutil.Encode(bytes), results[i])
|
||||
require.Equal(t, results[i], hexutil.Encode(bytes))
|
||||
}
|
||||
})
|
||||
t.Run("finalized root", func(t *testing.T) {
|
||||
|
||||
@@ -48,7 +48,7 @@ func (b *BeaconState) SetPendingConsolidations(val []*ethpb.PendingConsolidation
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetEarliestConsolidationEpoch is a mutating call to the beacon state which sets the earlest
|
||||
// SetEarliestConsolidationEpoch is a mutating call to the beacon state which sets the earliest
|
||||
// consolidation epoch value. This method requires access to the Lock on the state and only applies
|
||||
// in electra or later.
|
||||
func (b *BeaconState) SetEarliestConsolidationEpoch(epoch primitives.Epoch) error {
|
||||
|
||||
@@ -20,11 +20,6 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stategen",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/capella:go_default_library",
|
||||
"//beacon-chain/core/deneb:go_default_library",
|
||||
"//beacon-chain/core/electra:go_default_library",
|
||||
"//beacon-chain/core/execution:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/time:go_default_library",
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
@@ -40,9 +35,7 @@ go_library(
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//monitoring/tracing:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_hashicorp_golang_lru//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
|
||||
@@ -6,20 +6,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/capella"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/deneb"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/execution"
|
||||
prysmtime "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filters"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -185,7 +177,6 @@ func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot primi
|
||||
if state == nil || state.IsNil() {
|
||||
return nil, errUnknownState
|
||||
}
|
||||
|
||||
if state.Slot() > slot {
|
||||
err := fmt.Errorf("expected state.slot %d <= slot %d", state.Slot(), slot)
|
||||
return nil, err
|
||||
@@ -195,74 +186,7 @@ func ReplayProcessSlots(ctx context.Context, state state.BeaconState, slot primi
|
||||
return state, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
for state.Slot() < slot {
|
||||
state, err = transition.ProcessSlot(ctx, state)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process slot")
|
||||
}
|
||||
if prysmtime.CanProcessEpoch(state) {
|
||||
if state.Version() == version.Phase0 {
|
||||
state, err = transition.ProcessEpochPrecompute(ctx, state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(err, "could not process epoch with optimizations")
|
||||
}
|
||||
} else {
|
||||
err = altair.ProcessEpoch(ctx, state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(err, "could not process epoch")
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := state.SetSlot(state.Slot() + 1); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(err, "failed to increment state slot")
|
||||
}
|
||||
|
||||
if prysmtime.CanUpgradeToAltair(state.Slot()) {
|
||||
state, err = altair.UpgradeToAltair(ctx, state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if prysmtime.CanUpgradeToBellatrix(state.Slot()) {
|
||||
state, err = execution.UpgradeToBellatrix(state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if prysmtime.CanUpgradeToCapella(state.Slot()) {
|
||||
state, err = capella.UpgradeToCapella(state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if prysmtime.CanUpgradeToDeneb(state.Slot()) {
|
||||
state, err = deneb.UpgradeToDeneb(state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if prysmtime.CanUpgradeToElectra(state.Slot()) {
|
||||
state, err = electra.UpgradeToElectra(state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state, nil
|
||||
return transition.ProcessSlotsCore(ctx, span, state, slot, nil)
|
||||
}
|
||||
|
||||
// Given the start slot and the end slot, this returns the finalized beacon blocks in between.
|
||||
|
||||
@@ -5,12 +5,14 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db"
|
||||
testDB "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
@@ -197,6 +199,52 @@ func TestReplayBlocks_ThroughFutureForkBoundaries(t *testing.T) {
|
||||
assert.Equal(t, version.Electra, newState.Version())
|
||||
}
|
||||
|
||||
func TestReplayBlocks_ProcessEpoch_Electra(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
bCfg := params.BeaconConfig().Copy()
|
||||
bCfg.ElectraForkEpoch = 1
|
||||
bCfg.ForkVersionSchedule[bytesutil.ToBytes4(bCfg.ElectraForkVersion)] = 1
|
||||
params.OverrideBeaconConfig(bCfg)
|
||||
|
||||
beaconState, _ := util.DeterministicGenesisStateElectra(t, 1)
|
||||
require.NoError(t, beaconState.SetDepositBalanceToConsume(100))
|
||||
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
|
||||
require.NoError(t, beaconState.SetPendingBalanceDeposits([]*ethpb.PendingBalanceDeposit{
|
||||
{
|
||||
Amount: uint64(amountAvailForProcessing) / 10,
|
||||
Index: primitives.ValidatorIndex(0),
|
||||
},
|
||||
}))
|
||||
genesisBlock := util.NewBeaconBlockElectra()
|
||||
bodyRoot, err := genesisBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
err = beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
||||
Slot: genesisBlock.Block.Slot,
|
||||
ParentRoot: genesisBlock.Block.ParentRoot,
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
BodyRoot: bodyRoot[:],
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, version.Electra, beaconState.Version())
|
||||
require.Equal(t, params.BeaconConfig().MinActivationBalance, beaconState.Balances()[0])
|
||||
service := New(testDB.SetupDB(t), doublylinkedtree.New())
|
||||
targetSlot := (params.BeaconConfig().SlotsPerEpoch * 2) - 1
|
||||
newState, err := service.replayBlocks(context.Background(), beaconState, []interfaces.ReadOnlySignedBeaconBlock{}, targetSlot)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, version.Electra, newState.Version())
|
||||
res, err := newState.DepositBalanceToConsume()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, primitives.Gwei(0), res)
|
||||
|
||||
remaining, err := newState.PendingBalanceDeposits()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(remaining))
|
||||
|
||||
require.Equal(t, params.BeaconConfig().MinActivationBalance+(uint64(amountAvailForProcessing)/10), newState.Balances()[0])
|
||||
}
|
||||
|
||||
func TestLoadBlocks_FirstBranch(t *testing.T) {
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -684,9 +684,9 @@ func TestService_AddPendingBlockToQueueOverMax(t *testing.T) {
|
||||
}
|
||||
|
||||
b := util.NewBeaconBlock()
|
||||
b1 := ethpb.CopySignedBeaconBlock(b)
|
||||
b1 := b.Copy()
|
||||
b1.Block.StateRoot = []byte{'a'}
|
||||
b2 := ethpb.CopySignedBeaconBlock(b)
|
||||
b2 := b.Copy()
|
||||
b2.Block.StateRoot = []byte{'b'}
|
||||
wsb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
@@ -698,7 +698,7 @@ func TestService_AddPendingBlockToQueueOverMax(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, r.insertBlockToPendingQueue(0, wsb, [32]byte{2}))
|
||||
|
||||
b3 := ethpb.CopySignedBeaconBlock(b)
|
||||
b3 := b.Copy()
|
||||
b3.Block.StateRoot = []byte{'c'}
|
||||
wsb, err = blocks.NewSignedBeaconBlock(b2)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -113,46 +113,19 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
|
||||
committeeIndex = data.CommitteeIndex
|
||||
}
|
||||
|
||||
if features.Get().EnableSlasher {
|
||||
// Feed the indexed attestation to slasher if enabled. This action
|
||||
// is done in the background to avoid adding more load to this critical code path.
|
||||
go func() {
|
||||
// Using a different context to prevent timeouts as this operation can be expensive
|
||||
// and we want to avoid affecting the critical code path.
|
||||
ctx := context.TODO()
|
||||
preState, err := s.cfg.chain.AttestationTargetState(ctx, data.Target)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not retrieve pre state")
|
||||
tracing.AnnotateError(span, err)
|
||||
return
|
||||
}
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, preState, data.Slot, committeeIndex)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get attestation committee")
|
||||
tracing.AnnotateError(span, err)
|
||||
return
|
||||
}
|
||||
indexedAtt, err := attestation.ConvertToIndexed(ctx, att, committee)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not convert to indexed attestation")
|
||||
tracing.AnnotateError(span, err)
|
||||
return
|
||||
}
|
||||
s.cfg.slasherAttestationsFeed.Send(&types.WrappedIndexedAtt{IndexedAtt: indexedAtt})
|
||||
}()
|
||||
}
|
||||
if !features.Get().EnableSlasher {
|
||||
// Verify this the first attestation received for the participating validator for the slot.
|
||||
if s.hasSeenCommitteeIndicesSlot(data.Slot, data.CommitteeIndex, att.GetAggregationBits()) {
|
||||
return pubsub.ValidationIgnore, nil
|
||||
}
|
||||
|
||||
// Verify this the first attestation received for the participating validator for the slot.
|
||||
if s.hasSeenCommitteeIndicesSlot(data.Slot, data.CommitteeIndex, att.GetAggregationBits()) {
|
||||
return pubsub.ValidationIgnore, nil
|
||||
}
|
||||
|
||||
// Reject an attestation if it references an invalid block.
|
||||
if s.hasBadBlock(bytesutil.ToBytes32(data.BeaconBlockRoot)) ||
|
||||
s.hasBadBlock(bytesutil.ToBytes32(data.Target.Root)) ||
|
||||
s.hasBadBlock(bytesutil.ToBytes32(data.Source.Root)) {
|
||||
attBadBlockCount.Inc()
|
||||
return pubsub.ValidationReject, errors.New("attestation data references bad block root")
|
||||
// Reject an attestation if it references an invalid block.
|
||||
if s.hasBadBlock(bytesutil.ToBytes32(data.BeaconBlockRoot)) ||
|
||||
s.hasBadBlock(bytesutil.ToBytes32(data.Target.Root)) ||
|
||||
s.hasBadBlock(bytesutil.ToBytes32(data.Source.Root)) {
|
||||
attBadBlockCount.Inc()
|
||||
return pubsub.ValidationReject, errors.New("attestation data references bad block root")
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the block being voted and the processed state is in beaconDB and the block has passed validation if it's in the beaconDB.
|
||||
@@ -203,6 +176,35 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
|
||||
return validationRes, err
|
||||
}
|
||||
|
||||
if features.Get().EnableSlasher {
|
||||
// Feed the indexed attestation to slasher if enabled. This action
|
||||
// is done in the background to avoid adding more load to this critical code path.
|
||||
go func() {
|
||||
// Using a different context to prevent timeouts as this operation can be expensive
|
||||
// and we want to avoid affecting the critical code path.
|
||||
ctx := context.TODO()
|
||||
preState, err := s.cfg.chain.AttestationTargetState(ctx, data.Target)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not retrieve pre state")
|
||||
tracing.AnnotateError(span, err)
|
||||
return
|
||||
}
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, preState, data.Slot, committeeIndex)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get attestation committee")
|
||||
tracing.AnnotateError(span, err)
|
||||
return
|
||||
}
|
||||
indexedAtt, err := attestation.ConvertToIndexed(ctx, att, committee)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not convert to indexed attestation")
|
||||
tracing.AnnotateError(span, err)
|
||||
return
|
||||
}
|
||||
s.cfg.slasherAttestationsFeed.Send(&types.WrappedIndexedAtt{IndexedAtt: indexedAtt})
|
||||
}()
|
||||
}
|
||||
|
||||
s.setSeenCommitteeIndicesSlot(data.Slot, data.CommitteeIndex, att.GetAggregationBits())
|
||||
|
||||
msg.ValidatorData = att
|
||||
|
||||
@@ -31,6 +31,23 @@ var (
|
||||
"Boost is an additional percentage to multiple local block value. Use builder block if: builder_bid_value * 100 > local_block_value * (local-block-value-boost + 100)",
|
||||
Value: 10,
|
||||
}
|
||||
// MinBuilderBid sets an absolute value for the builder bid that this
|
||||
// node will accept without reverting to local building
|
||||
MinBuilderBid = &cli.Uint64Flag{
|
||||
Name: "min-builder-bid",
|
||||
Usage: "An absolute value in Gwei that the builder bid has to have in order for this beacon node to use the builder's block. Anything less than this value" +
|
||||
" and the beacon will revert to local building.",
|
||||
Value: 0,
|
||||
}
|
||||
// MinBuilderDiff sets an absolute value for the difference between the
|
||||
// builder's bid and the local block value that this node will accept
|
||||
// without reverting to local building
|
||||
MinBuilderDiff = &cli.Uint64Flag{
|
||||
Name: "min-builder-to-local-difference",
|
||||
Usage: "An absolute value in Gwei that the builder bid has to have in order for this beacon node to use the builder's block. Anything less than this value" +
|
||||
" and the beacon will revert to local building.",
|
||||
Value: 0,
|
||||
}
|
||||
// ExecutionEngineEndpoint provides an HTTP access endpoint to connect to an execution client on the execution layer
|
||||
ExecutionEngineEndpoint = &cli.StringFlag{
|
||||
Name: "execution-endpoint",
|
||||
|
||||
@@ -82,6 +82,8 @@ var appFlags = []cli.Flag{
|
||||
flags.MaxBuilderConsecutiveMissedSlots,
|
||||
flags.EngineEndpointTimeoutSeconds,
|
||||
flags.LocalBlockValueBoost,
|
||||
flags.MinBuilderBid,
|
||||
flags.MinBuilderDiff,
|
||||
cmd.BackupWebhookOutputDir,
|
||||
cmd.MinimalConfigFlag,
|
||||
cmd.E2EConfigFlag,
|
||||
|
||||
@@ -131,6 +131,8 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.EngineEndpointTimeoutSeconds,
|
||||
flags.SlasherDirFlag,
|
||||
flags.LocalBlockValueBoost,
|
||||
flags.MinBuilderBid,
|
||||
flags.MinBuilderDiff,
|
||||
flags.JwtId,
|
||||
checkpoint.BlockPath,
|
||||
checkpoint.StatePath,
|
||||
|
||||
@@ -48,6 +48,7 @@ type Flags struct {
|
||||
EnableDoppelGanger bool // EnableDoppelGanger enables doppelganger protection on startup for the validator.
|
||||
EnableHistoricalSpaceRepresentation bool // EnableHistoricalSpaceRepresentation enables the saving of registry validators in separate buckets to save space
|
||||
EnableBeaconRESTApi bool // EnableBeaconRESTApi enables experimental usage of the beacon REST API by the validator when querying a beacon node
|
||||
EnableCommitteeAwarePacking bool // EnableCommitteeAwarePacking TODO
|
||||
// Logging related toggles.
|
||||
DisableGRPCConnectionLogs bool // Disables logging when a new grpc client has connected.
|
||||
EnableFullSSZDataLogging bool // Enables logging for full ssz data on rejected gossip messages
|
||||
@@ -254,6 +255,10 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
|
||||
logEnabled(EnableQUIC)
|
||||
cfg.EnableQUIC = true
|
||||
}
|
||||
if ctx.IsSet(EnableCommitteeAwarePacking.Name) {
|
||||
logEnabled(EnableCommitteeAwarePacking)
|
||||
cfg.EnableCommitteeAwarePacking = true
|
||||
}
|
||||
|
||||
cfg.AggregateIntervals = [3]time.Duration{aggregateFirstInterval.Value, aggregateSecondInterval.Value, aggregateThirdInterval.Value}
|
||||
Init(cfg)
|
||||
|
||||
@@ -166,6 +166,10 @@ var (
|
||||
Name: "enable-quic",
|
||||
Usage: "Enables connection using the QUIC protocol for peers which support it.",
|
||||
}
|
||||
EnableCommitteeAwarePacking = &cli.BoolFlag{
|
||||
Name: "enable-committee-aware-packing",
|
||||
Usage: "Changes the attestation packing algorithm to one that is aware of attesting committees.",
|
||||
}
|
||||
)
|
||||
|
||||
// devModeFlags holds list of flags that are set when development mode is on.
|
||||
@@ -223,6 +227,7 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
|
||||
EnableLightClient,
|
||||
BlobSaveFsync,
|
||||
EnableQUIC,
|
||||
EnableCommitteeAwarePacking,
|
||||
}...)...)
|
||||
|
||||
// E2EBeaconChainFlags contains a list of the beacon chain feature flags to be tested in E2E.
|
||||
|
||||
@@ -222,7 +222,8 @@ type BeaconChainConfig struct {
|
||||
MaxBuilderConsecutiveMissedSlots primitives.Slot // MaxBuilderConsecutiveMissedSlots defines the number of consecutive skip slot to fallback from using relay/builder to local execution engine for block construction.
|
||||
MaxBuilderEpochMissedSlots primitives.Slot // MaxBuilderEpochMissedSlots is defining the number of total skip slot (per epoch rolling windows) to fallback from using relay/builder to local execution engine for block construction.
|
||||
LocalBlockValueBoost uint64 // LocalBlockValueBoost is the value boost for local block construction. This is used to prioritize local block construction over relay/builder block construction.
|
||||
|
||||
MinBuilderBid uint64 // MinBuilderBid is the minimum value that the builder's block can have to be considered by this node.
|
||||
MinBuilderDiff uint64 // MinBuilderDiff is the minimum value above the local block value that the builder has to bid to be considered by this node
|
||||
// Execution engine timeout value
|
||||
ExecutionEngineTimeoutValue uint64 // ExecutionEngineTimeoutValue defines the seconds to wait before timing out engine endpoints with execution payload execution semantics (newPayload, forkchoiceUpdated).
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ type Settings struct {
|
||||
DefaultConfig *Option
|
||||
}
|
||||
|
||||
// ShouldBeSaved goes through checks to see if the value should be savable
|
||||
// ShouldBeSaved goes through checks to see if the value should be saveable
|
||||
// Pseudocode: conditions for being saved into the database
|
||||
// 1. settings are not nil
|
||||
// 2. proposeconfig is not nil (this defines specific settings for each validator key), default config can be nil in this case and fall back to beacon node settings
|
||||
|
||||
@@ -52,40 +52,29 @@ func (b *SignedBeaconBlock) Copy() (interfaces.SignedBeaconBlock, error) {
|
||||
}
|
||||
switch b.version {
|
||||
case version.Phase0:
|
||||
cp := eth.CopySignedBeaconBlock(pb.(*eth.SignedBeaconBlock))
|
||||
return initSignedBlockFromProtoPhase0(cp)
|
||||
return initSignedBlockFromProtoPhase0(pb.(*eth.SignedBeaconBlock).Copy())
|
||||
case version.Altair:
|
||||
cp := eth.CopySignedBeaconBlockAltair(pb.(*eth.SignedBeaconBlockAltair))
|
||||
return initSignedBlockFromProtoAltair(cp)
|
||||
return initSignedBlockFromProtoAltair(pb.(*eth.SignedBeaconBlockAltair).Copy())
|
||||
case version.Bellatrix:
|
||||
if b.IsBlinded() {
|
||||
cp := eth.CopySignedBlindedBeaconBlockBellatrix(pb.(*eth.SignedBlindedBeaconBlockBellatrix))
|
||||
return initBlindedSignedBlockFromProtoBellatrix(cp)
|
||||
return initBlindedSignedBlockFromProtoBellatrix(pb.(*eth.SignedBlindedBeaconBlockBellatrix).Copy())
|
||||
}
|
||||
cp := eth.CopySignedBeaconBlockBellatrix(pb.(*eth.SignedBeaconBlockBellatrix))
|
||||
return initSignedBlockFromProtoBellatrix(cp)
|
||||
return initSignedBlockFromProtoBellatrix(pb.(*eth.SignedBeaconBlockBellatrix).Copy())
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
cp := eth.CopySignedBlindedBeaconBlockCapella(pb.(*eth.SignedBlindedBeaconBlockCapella))
|
||||
return initBlindedSignedBlockFromProtoCapella(cp)
|
||||
return initBlindedSignedBlockFromProtoCapella(pb.(*eth.SignedBlindedBeaconBlockCapella).Copy())
|
||||
}
|
||||
cp := eth.CopySignedBeaconBlockCapella(pb.(*eth.SignedBeaconBlockCapella))
|
||||
return initSignedBlockFromProtoCapella(cp)
|
||||
return initSignedBlockFromProtoCapella(pb.(*eth.SignedBeaconBlockCapella).Copy())
|
||||
case version.Deneb:
|
||||
if b.IsBlinded() {
|
||||
cp := eth.CopySignedBlindedBeaconBlockDeneb(pb.(*eth.SignedBlindedBeaconBlockDeneb))
|
||||
return initBlindedSignedBlockFromProtoDeneb(cp)
|
||||
return initBlindedSignedBlockFromProtoDeneb(pb.(*eth.SignedBlindedBeaconBlockDeneb).Copy())
|
||||
}
|
||||
cp := eth.CopySignedBeaconBlockDeneb(pb.(*eth.SignedBeaconBlockDeneb))
|
||||
return initSignedBlockFromProtoDeneb(cp)
|
||||
return initSignedBlockFromProtoDeneb(pb.(*eth.SignedBeaconBlockDeneb).Copy())
|
||||
case version.Electra:
|
||||
if b.IsBlinded() {
|
||||
cp := eth.CopySignedBlindedBeaconBlockElectra(pb.(*eth.SignedBlindedBeaconBlockElectra))
|
||||
return initBlindedSignedBlockFromProtoElectra(cp)
|
||||
return initBlindedSignedBlockFromProtoElectra(pb.(*eth.SignedBlindedBeaconBlockElectra).Copy())
|
||||
}
|
||||
cp := eth.CopySignedBeaconBlockElectra(pb.(*eth.SignedBeaconBlockElectra))
|
||||
return initSignedBlockFromProtoElectra(cp)
|
||||
|
||||
return initSignedBlockFromProtoElectra(pb.(*eth.SignedBeaconBlockElectra).Copy())
|
||||
default:
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
@@ -972,39 +961,29 @@ func (b *BeaconBlock) Copy() (interfaces.ReadOnlyBeaconBlock, error) {
|
||||
}
|
||||
switch b.version {
|
||||
case version.Phase0:
|
||||
cp := eth.CopyBeaconBlock(pb.(*eth.BeaconBlock))
|
||||
return initBlockFromProtoPhase0(cp)
|
||||
return initBlockFromProtoPhase0(pb.(*eth.BeaconBlock).Copy())
|
||||
case version.Altair:
|
||||
cp := eth.CopyBeaconBlockAltair(pb.(*eth.BeaconBlockAltair))
|
||||
return initBlockFromProtoAltair(cp)
|
||||
return initBlockFromProtoAltair(pb.(*eth.BeaconBlockAltair).Copy())
|
||||
case version.Bellatrix:
|
||||
if b.IsBlinded() {
|
||||
cp := eth.CopyBlindedBeaconBlockBellatrix(pb.(*eth.BlindedBeaconBlockBellatrix))
|
||||
return initBlindedBlockFromProtoBellatrix(cp)
|
||||
return initBlindedBlockFromProtoBellatrix(pb.(*eth.BlindedBeaconBlockBellatrix).Copy())
|
||||
}
|
||||
cp := eth.CopyBeaconBlockBellatrix(pb.(*eth.BeaconBlockBellatrix))
|
||||
return initBlockFromProtoBellatrix(cp)
|
||||
return initBlockFromProtoBellatrix(pb.(*eth.BeaconBlockBellatrix).Copy())
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
cp := eth.CopyBlindedBeaconBlockCapella(pb.(*eth.BlindedBeaconBlockCapella))
|
||||
return initBlindedBlockFromProtoCapella(cp)
|
||||
return initBlindedBlockFromProtoCapella(pb.(*eth.BlindedBeaconBlockCapella).Copy())
|
||||
}
|
||||
cp := eth.CopyBeaconBlockCapella(pb.(*eth.BeaconBlockCapella))
|
||||
return initBlockFromProtoCapella(cp)
|
||||
return initBlockFromProtoCapella(pb.(*eth.BeaconBlockCapella).Copy())
|
||||
case version.Deneb:
|
||||
if b.IsBlinded() {
|
||||
cp := eth.CopyBlindedBeaconBlockDeneb(pb.(*eth.BlindedBeaconBlockDeneb))
|
||||
return initBlindedBlockFromProtoDeneb(cp)
|
||||
return initBlindedBlockFromProtoDeneb(pb.(*eth.BlindedBeaconBlockDeneb).Copy())
|
||||
}
|
||||
cp := eth.CopyBeaconBlockDeneb(pb.(*eth.BeaconBlockDeneb))
|
||||
return initBlockFromProtoDeneb(cp)
|
||||
return initBlockFromProtoDeneb(pb.(*eth.BeaconBlockDeneb).Copy())
|
||||
case version.Electra:
|
||||
if b.IsBlinded() {
|
||||
cp := eth.CopyBlindedBeaconBlockElectra(pb.(*eth.BlindedBeaconBlockElectra))
|
||||
return initBlindedBlockFromProtoElectra(cp)
|
||||
return initBlindedBlockFromProtoElectra(pb.(*eth.BlindedBeaconBlockElectra).Copy())
|
||||
}
|
||||
cp := eth.CopyBeaconBlockElectra(pb.(*eth.BeaconBlockElectra))
|
||||
return initBlockFromProtoElectra(cp)
|
||||
return initBlockFromProtoElectra(pb.(*eth.BeaconBlockElectra).Copy())
|
||||
default:
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ $ go tool trace trace.out
|
||||
#### How to collect additional traces
|
||||
|
||||
We use the OpenCensus library to create traces. To trace the execution of a p2p
|
||||
message through the system, we must define [spans](https://godoc.org/go.opencensus.io/trace#Span) around the code that handles the message. To correlate the trace with other spans defined for the same message, use the context passed inside the [Message](https://godoc.org/github.com/prysmaticlabs/prysm/shared/deprecated-p2p#Message) struct to create a span:
|
||||
message through the system, we must define [spans](https://godoc.org/go.opencensus.io/trace#Span) around the code that handles the message. To correlate the trace with other spans defined for the same message, use the context passed inside the Message struct to create a span:
|
||||
|
||||
```go
|
||||
var msg p2p.Message
|
||||
|
||||
@@ -32,7 +32,7 @@ func (e Endpoint) Equals(other Endpoint) bool {
|
||||
return e.Url == other.Url && e.Auth.Equals(other.Auth)
|
||||
}
|
||||
|
||||
// HttpClient creates a http client object dependant
|
||||
// HttpClient creates a http client object dependent
|
||||
// on the properties of the network endpoint.
|
||||
func (e Endpoint) HttpClient() *http.Client {
|
||||
if e.Auth.Method != authorization.Bearer {
|
||||
|
||||
@@ -663,6 +663,18 @@ func TestMaxCover_MaxCover(t *testing.T) {
|
||||
}},
|
||||
wantedErr: "empty bitlists: invalid max_cover problem",
|
||||
},
|
||||
{
|
||||
name: "doesn't select bitlist which is a subset of another bitlist",
|
||||
args: args{k: 3, allowOverlaps: true, candidates: []*bitfield.Bitlist64{
|
||||
bitfield.NewBitlist64From([]uint64{0b00011100}),
|
||||
bitfield.NewBitlist64From([]uint64{0b00011110}),
|
||||
bitfield.NewBitlist64From([]uint64{0b00000001}),
|
||||
}},
|
||||
want: &BitSetAggregation{
|
||||
Coverage: bitfield.NewBitlist64From([]uint64{0b00011111}),
|
||||
Keys: []int{1, 2},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -2,6 +2,458 @@ package eth
|
||||
|
||||
import "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
|
||||
// Copy --
|
||||
func (sigBlock *SignedBeaconBlock) Copy() *SignedBeaconBlock {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlock{
|
||||
Block: sigBlock.Block.Copy(),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (block *BeaconBlock) Copy() *BeaconBlock {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlock{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: block.Body.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (body *BeaconBlockBody) Copy() *BeaconBlockBody {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBody{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (sigBlock *SignedBeaconBlockAltair) Copy() *SignedBeaconBlockAltair {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlockAltair{
|
||||
Block: sigBlock.Block.Copy(),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (block *BeaconBlockAltair) Copy() *BeaconBlockAltair {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockAltair{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: block.Body.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (body *BeaconBlockBodyAltair) Copy() *BeaconBlockBodyAltair {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBodyAltair{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (sigBlock *SignedBeaconBlockBellatrix) Copy() *SignedBeaconBlockBellatrix {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlockBellatrix{
|
||||
Block: sigBlock.Block.Copy(),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (block *BeaconBlockBellatrix) Copy() *BeaconBlockBellatrix {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBellatrix{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: block.Body.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (body *BeaconBlockBodyBellatrix) Copy() *BeaconBlockBodyBellatrix {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBodyBellatrix{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayload: body.ExecutionPayload.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (sigBlock *SignedBeaconBlockCapella) Copy() *SignedBeaconBlockCapella {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlockCapella{
|
||||
Block: sigBlock.Block.Copy(),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (block *BeaconBlockCapella) Copy() *BeaconBlockCapella {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockCapella{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: block.Body.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (body *BeaconBlockBodyCapella) Copy() *BeaconBlockBodyCapella {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBodyCapella{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayload: body.ExecutionPayload.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (sigBlock *SignedBlindedBeaconBlockCapella) Copy() *SignedBlindedBeaconBlockCapella {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBlindedBeaconBlockCapella{
|
||||
Block: sigBlock.Block.Copy(),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (block *BlindedBeaconBlockCapella) Copy() *BlindedBeaconBlockCapella {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockCapella{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: block.Body.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (body *BlindedBeaconBlockBodyCapella) Copy() *BlindedBeaconBlockBodyCapella {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockBodyCapella{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayloadHeader: body.ExecutionPayloadHeader.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (sigBlock *SignedBlindedBeaconBlockDeneb) Copy() *SignedBlindedBeaconBlockDeneb {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBlindedBeaconBlockDeneb{
|
||||
Message: sigBlock.Message.Copy(),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (block *BlindedBeaconBlockDeneb) Copy() *BlindedBeaconBlockDeneb {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockDeneb{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: block.Body.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (body *BlindedBeaconBlockBodyDeneb) Copy() *BlindedBeaconBlockBodyDeneb {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockBodyDeneb{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayloadHeader: body.ExecutionPayloadHeader.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
BlobKzgCommitments: CopyBlobKZGs(body.BlobKzgCommitments),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (sigBlock *SignedBlindedBeaconBlockElectra) Copy() *SignedBlindedBeaconBlockElectra {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBlindedBeaconBlockElectra{
|
||||
Message: sigBlock.Message.Copy(),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (block *BlindedBeaconBlockElectra) Copy() *BlindedBeaconBlockElectra {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockElectra{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: block.Body.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (body *BlindedBeaconBlockBodyElectra) Copy() *BlindedBeaconBlockBodyElectra {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockBodyElectra{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayloadHeader: body.ExecutionPayloadHeader.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
BlobKzgCommitments: CopyBlobKZGs(body.BlobKzgCommitments),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (sigBlock *SignedBlindedBeaconBlockBellatrix) Copy() *SignedBlindedBeaconBlockBellatrix {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBlindedBeaconBlockBellatrix{
|
||||
Block: sigBlock.Block.Copy(),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (block *BlindedBeaconBlockBellatrix) Copy() *BlindedBeaconBlockBellatrix {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockBellatrix{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: block.Body.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (body *BlindedBeaconBlockBodyBellatrix) Copy() *BlindedBeaconBlockBodyBellatrix {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockBodyBellatrix{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayloadHeader: body.ExecutionPayloadHeader.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBlobKZGs copies the provided blob kzgs object.
|
||||
func CopyBlobKZGs(b [][]byte) [][]byte {
|
||||
return bytesutil.SafeCopy2dBytes(b)
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (sigBlock *SignedBeaconBlockDeneb) Copy() *SignedBeaconBlockDeneb {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlockDeneb{
|
||||
Block: sigBlock.Block.Copy(),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (block *BeaconBlockDeneb) Copy() *BeaconBlockDeneb {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockDeneb{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: block.Body.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (body *BeaconBlockBodyDeneb) Copy() *BeaconBlockBodyDeneb {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBodyDeneb{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayload: body.ExecutionPayload.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
BlobKzgCommitments: CopyBlobKZGs(body.BlobKzgCommitments),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (sigBlock *SignedBeaconBlockElectra) Copy() *SignedBeaconBlockElectra {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlockElectra{
|
||||
Block: sigBlock.Block.Copy(),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (block *BeaconBlockElectra) Copy() *BeaconBlockElectra {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockElectra{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: block.Body.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (body *BeaconBlockBodyElectra) Copy() *BeaconBlockBodyElectra {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBodyElectra{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayload: body.ExecutionPayload.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
BlobKzgCommitments: CopyBlobKZGs(body.BlobKzgCommitments),
|
||||
}
|
||||
}
|
||||
|
||||
// Copy --
|
||||
func (data *Eth1Data) Copy() *Eth1Data {
|
||||
if data == nil {
|
||||
|
||||
@@ -6,6 +6,49 @@ import (
|
||||
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
func TestBeaconBlock_Fuzz(t *testing.T) {
|
||||
// Phase 0 Full
|
||||
fuzzCopies(t, ð.SignedBeaconBlock{})
|
||||
fuzzCopies(t, ð.BeaconBlock{})
|
||||
fuzzCopies(t, ð.BeaconBlockBody{})
|
||||
// Altair Full
|
||||
fuzzCopies(t, ð.SignedBeaconBlockAltair{})
|
||||
fuzzCopies(t, ð.BeaconBlockAltair{})
|
||||
fuzzCopies(t, ð.BeaconBlockBodyAltair{})
|
||||
// Bellatrix Full
|
||||
fuzzCopies(t, ð.SignedBeaconBlockBellatrix{})
|
||||
fuzzCopies(t, ð.BeaconBlockBellatrix{})
|
||||
fuzzCopies(t, ð.BeaconBlockBodyBellatrix{})
|
||||
// Bellatrix Blinded
|
||||
fuzzCopies(t, ð.SignedBlindedBeaconBlockBellatrix{})
|
||||
fuzzCopies(t, ð.BlindedBeaconBlockBellatrix{})
|
||||
fuzzCopies(t, ð.BlindedBeaconBlockBodyBellatrix{})
|
||||
// Capella Full
|
||||
fuzzCopies(t, ð.SignedBeaconBlockCapella{})
|
||||
fuzzCopies(t, ð.BeaconBlockCapella{})
|
||||
fuzzCopies(t, ð.BeaconBlockBodyCapella{})
|
||||
// Capella Blinded
|
||||
fuzzCopies(t, ð.SignedBlindedBeaconBlockCapella{})
|
||||
fuzzCopies(t, ð.BlindedBeaconBlockCapella{})
|
||||
fuzzCopies(t, ð.BlindedBeaconBlockBodyCapella{})
|
||||
// Deneb Full
|
||||
fuzzCopies(t, ð.SignedBeaconBlockDeneb{})
|
||||
fuzzCopies(t, ð.BeaconBlockDeneb{})
|
||||
fuzzCopies(t, ð.BeaconBlockBodyDeneb{})
|
||||
// Deneb Blinded
|
||||
fuzzCopies(t, ð.SignedBlindedBeaconBlockDeneb{})
|
||||
fuzzCopies(t, ð.BlindedBeaconBlockDeneb{})
|
||||
fuzzCopies(t, ð.BlindedBeaconBlockBodyDeneb{})
|
||||
// Electra Full
|
||||
fuzzCopies(t, ð.SignedBeaconBlockElectra{})
|
||||
fuzzCopies(t, ð.BeaconBlockElectra{})
|
||||
fuzzCopies(t, ð.BeaconBlockBodyElectra{})
|
||||
// Electra Blinded
|
||||
fuzzCopies(t, ð.SignedBlindedBeaconBlockElectra{})
|
||||
fuzzCopies(t, ð.BlindedBeaconBlockElectra{})
|
||||
fuzzCopies(t, ð.BlindedBeaconBlockBodyElectra{})
|
||||
}
|
||||
|
||||
func TestCopyBeaconBlockFields_Fuzz(t *testing.T) {
|
||||
fuzzCopies(t, ð.Eth1Data{})
|
||||
fuzzCopies(t, ð.ProposerSlashing{})
|
||||
|
||||
@@ -17,91 +17,6 @@ func CopySlice[T any, C copier[T]](original []C) []T {
|
||||
return newSlice
|
||||
}
|
||||
|
||||
// CopySignedBeaconBlock copies the provided SignedBeaconBlock.
|
||||
func CopySignedBeaconBlock(sigBlock *SignedBeaconBlock) *SignedBeaconBlock {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlock{
|
||||
Block: CopyBeaconBlock(sigBlock.Block),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlock copies the provided BeaconBlock.
|
||||
func CopyBeaconBlock(block *BeaconBlock) *BeaconBlock {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlock{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: CopyBeaconBlockBody(block.Body),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockBody copies the provided BeaconBlockBody.
|
||||
func CopyBeaconBlockBody(body *BeaconBlockBody) *BeaconBlockBody {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBody{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
}
|
||||
}
|
||||
|
||||
// CopySignedBeaconBlockAltair copies the provided SignedBeaconBlock.
|
||||
func CopySignedBeaconBlockAltair(sigBlock *SignedBeaconBlockAltair) *SignedBeaconBlockAltair {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlockAltair{
|
||||
Block: CopyBeaconBlockAltair(sigBlock.Block),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockAltair copies the provided BeaconBlock.
|
||||
func CopyBeaconBlockAltair(block *BeaconBlockAltair) *BeaconBlockAltair {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockAltair{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: CopyBeaconBlockBodyAltair(block.Body),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockBodyAltair copies the provided BeaconBlockBody.
|
||||
func CopyBeaconBlockBodyAltair(body *BeaconBlockBodyAltair) *BeaconBlockBodyAltair {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBodyAltair{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyValidator copies the provided validator.
|
||||
func CopyValidator(val *Validator) *Validator {
|
||||
pubKey := make([]byte, len(val.PublicKey))
|
||||
@@ -146,370 +61,3 @@ func CopySyncCommitteeContribution(c *SyncCommitteeContribution) *SyncCommitteeC
|
||||
Signature: bytesutil.SafeCopyBytes(c.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopySignedBeaconBlockBellatrix copies the provided SignedBeaconBlockBellatrix.
|
||||
func CopySignedBeaconBlockBellatrix(sigBlock *SignedBeaconBlockBellatrix) *SignedBeaconBlockBellatrix {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlockBellatrix{
|
||||
Block: CopyBeaconBlockBellatrix(sigBlock.Block),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockBellatrix copies the provided BeaconBlockBellatrix.
|
||||
func CopyBeaconBlockBellatrix(block *BeaconBlockBellatrix) *BeaconBlockBellatrix {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBellatrix{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: CopyBeaconBlockBodyBellatrix(block.Body),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockBodyBellatrix copies the provided BeaconBlockBodyBellatrix.
|
||||
func CopyBeaconBlockBodyBellatrix(body *BeaconBlockBodyBellatrix) *BeaconBlockBodyBellatrix {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBodyBellatrix{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayload: body.ExecutionPayload.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// CopySignedBeaconBlockCapella copies the provided SignedBeaconBlockCapella.
|
||||
func CopySignedBeaconBlockCapella(sigBlock *SignedBeaconBlockCapella) *SignedBeaconBlockCapella {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlockCapella{
|
||||
Block: CopyBeaconBlockCapella(sigBlock.Block),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockCapella copies the provided BeaconBlockCapella.
|
||||
func CopyBeaconBlockCapella(block *BeaconBlockCapella) *BeaconBlockCapella {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockCapella{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: CopyBeaconBlockBodyCapella(block.Body),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockBodyCapella copies the provided BeaconBlockBodyCapella.
|
||||
func CopyBeaconBlockBodyCapella(body *BeaconBlockBodyCapella) *BeaconBlockBodyCapella {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBodyCapella{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayload: body.ExecutionPayload.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
}
|
||||
}
|
||||
|
||||
// CopySignedBlindedBeaconBlockCapella copies the provided SignedBlindedBeaconBlockCapella.
|
||||
func CopySignedBlindedBeaconBlockCapella(sigBlock *SignedBlindedBeaconBlockCapella) *SignedBlindedBeaconBlockCapella {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBlindedBeaconBlockCapella{
|
||||
Block: CopyBlindedBeaconBlockCapella(sigBlock.Block),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBlindedBeaconBlockCapella copies the provided BlindedBeaconBlockCapella.
|
||||
func CopyBlindedBeaconBlockCapella(block *BlindedBeaconBlockCapella) *BlindedBeaconBlockCapella {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockCapella{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: CopyBlindedBeaconBlockBodyCapella(block.Body),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBlindedBeaconBlockBodyCapella copies the provided BlindedBeaconBlockBodyCapella.
|
||||
func CopyBlindedBeaconBlockBodyCapella(body *BlindedBeaconBlockBodyCapella) *BlindedBeaconBlockBodyCapella {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockBodyCapella{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayloadHeader: body.ExecutionPayloadHeader.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
}
|
||||
}
|
||||
|
||||
// CopySignedBlindedBeaconBlockDeneb copies the provided SignedBlindedBeaconBlockDeneb.
|
||||
func CopySignedBlindedBeaconBlockDeneb(sigBlock *SignedBlindedBeaconBlockDeneb) *SignedBlindedBeaconBlockDeneb {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBlindedBeaconBlockDeneb{
|
||||
Message: CopyBlindedBeaconBlockDeneb(sigBlock.Message),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBlindedBeaconBlockDeneb copies the provided BlindedBeaconBlockDeneb.
|
||||
func CopyBlindedBeaconBlockDeneb(block *BlindedBeaconBlockDeneb) *BlindedBeaconBlockDeneb {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockDeneb{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: CopyBlindedBeaconBlockBodyDeneb(block.Body),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBlindedBeaconBlockBodyDeneb copies the provided BlindedBeaconBlockBodyDeneb.
|
||||
func CopyBlindedBeaconBlockBodyDeneb(body *BlindedBeaconBlockBodyDeneb) *BlindedBeaconBlockBodyDeneb {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockBodyDeneb{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayloadHeader: body.ExecutionPayloadHeader.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
BlobKzgCommitments: CopyBlobKZGs(body.BlobKzgCommitments),
|
||||
}
|
||||
}
|
||||
|
||||
// CopySignedBlindedBeaconBlockElectra copies the provided SignedBlindedBeaconBlockElectra.
|
||||
func CopySignedBlindedBeaconBlockElectra(sigBlock *SignedBlindedBeaconBlockElectra) *SignedBlindedBeaconBlockElectra {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBlindedBeaconBlockElectra{
|
||||
Message: CopyBlindedBeaconBlockElectra(sigBlock.Message),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBlindedBeaconBlockElectra copies the provided BlindedBeaconBlockElectra.
|
||||
func CopyBlindedBeaconBlockElectra(block *BlindedBeaconBlockElectra) *BlindedBeaconBlockElectra {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockElectra{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: CopyBlindedBeaconBlockBodyElectra(block.Body),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBlindedBeaconBlockBodyElectra copies the provided BlindedBeaconBlockBodyElectra.
|
||||
func CopyBlindedBeaconBlockBodyElectra(body *BlindedBeaconBlockBodyElectra) *BlindedBeaconBlockBodyElectra {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockBodyElectra{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayloadHeader: body.ExecutionPayloadHeader.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
BlobKzgCommitments: CopyBlobKZGs(body.BlobKzgCommitments),
|
||||
}
|
||||
}
|
||||
|
||||
// CopySignedBlindedBeaconBlockBellatrix copies the provided SignedBlindedBeaconBlockBellatrix.
|
||||
func CopySignedBlindedBeaconBlockBellatrix(sigBlock *SignedBlindedBeaconBlockBellatrix) *SignedBlindedBeaconBlockBellatrix {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBlindedBeaconBlockBellatrix{
|
||||
Block: CopyBlindedBeaconBlockBellatrix(sigBlock.Block),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBlindedBeaconBlockBellatrix copies the provided BlindedBeaconBlockBellatrix.
|
||||
func CopyBlindedBeaconBlockBellatrix(block *BlindedBeaconBlockBellatrix) *BlindedBeaconBlockBellatrix {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockBellatrix{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: CopyBlindedBeaconBlockBodyBellatrix(block.Body),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBlindedBeaconBlockBodyBellatrix copies the provided BlindedBeaconBlockBodyBellatrix.
|
||||
func CopyBlindedBeaconBlockBodyBellatrix(body *BlindedBeaconBlockBodyBellatrix) *BlindedBeaconBlockBodyBellatrix {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BlindedBeaconBlockBodyBellatrix{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayloadHeader: body.ExecutionPayloadHeader.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBlobKZGs copies the provided blob kzgs object.
|
||||
func CopyBlobKZGs(b [][]byte) [][]byte {
|
||||
return bytesutil.SafeCopy2dBytes(b)
|
||||
}
|
||||
|
||||
// CopySignedBeaconBlockDeneb copies the provided SignedBeaconBlockDeneb.
|
||||
func CopySignedBeaconBlockDeneb(sigBlock *SignedBeaconBlockDeneb) *SignedBeaconBlockDeneb {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlockDeneb{
|
||||
Block: CopyBeaconBlockDeneb(sigBlock.Block),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockDeneb copies the provided BeaconBlockDeneb.
|
||||
func CopyBeaconBlockDeneb(block *BeaconBlockDeneb) *BeaconBlockDeneb {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockDeneb{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: CopyBeaconBlockBodyDeneb(block.Body),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockBodyDeneb copies the provided BeaconBlockBodyDeneb.
|
||||
func CopyBeaconBlockBodyDeneb(body *BeaconBlockBodyDeneb) *BeaconBlockBodyDeneb {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBodyDeneb{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayload: body.ExecutionPayload.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
BlobKzgCommitments: CopyBlobKZGs(body.BlobKzgCommitments),
|
||||
}
|
||||
}
|
||||
|
||||
// CopySignedBeaconBlockElectra copies the provided SignedBeaconBlockElectra.
|
||||
func CopySignedBeaconBlockElectra(sigBlock *SignedBeaconBlockElectra) *SignedBeaconBlockElectra {
|
||||
if sigBlock == nil {
|
||||
return nil
|
||||
}
|
||||
return &SignedBeaconBlockElectra{
|
||||
Block: CopyBeaconBlockElectra(sigBlock.Block),
|
||||
Signature: bytesutil.SafeCopyBytes(sigBlock.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockElectra copies the provided BeaconBlockElectra.
|
||||
func CopyBeaconBlockElectra(block *BeaconBlockElectra) *BeaconBlockElectra {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockElectra{
|
||||
Slot: block.Slot,
|
||||
ProposerIndex: block.ProposerIndex,
|
||||
ParentRoot: bytesutil.SafeCopyBytes(block.ParentRoot),
|
||||
StateRoot: bytesutil.SafeCopyBytes(block.StateRoot),
|
||||
Body: CopyBeaconBlockBodyElectra(block.Body),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBeaconBlockBodyElectra copies the provided BeaconBlockBodyElectra.
|
||||
func CopyBeaconBlockBodyElectra(body *BeaconBlockBodyElectra) *BeaconBlockBodyElectra {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return &BeaconBlockBodyElectra{
|
||||
RandaoReveal: bytesutil.SafeCopyBytes(body.RandaoReveal),
|
||||
Eth1Data: body.Eth1Data.Copy(),
|
||||
Graffiti: bytesutil.SafeCopyBytes(body.Graffiti),
|
||||
ProposerSlashings: CopySlice(body.ProposerSlashings),
|
||||
AttesterSlashings: CopySlice(body.AttesterSlashings),
|
||||
Attestations: CopySlice(body.Attestations),
|
||||
Deposits: CopySlice(body.Deposits),
|
||||
VoluntaryExits: CopySlice(body.VoluntaryExits),
|
||||
SyncAggregate: body.SyncAggregate.Copy(),
|
||||
ExecutionPayload: body.ExecutionPayload.Copy(),
|
||||
BlsToExecutionChanges: CopySlice(body.BlsToExecutionChanges),
|
||||
BlobKzgCommitments: CopyBlobKZGs(body.BlobKzgCommitments),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
func TestCopySignedBeaconBlock(t *testing.T) {
|
||||
blk := genSignedBeaconBlock()
|
||||
|
||||
got := v1alpha1.CopySignedBeaconBlock(blk)
|
||||
got := blk.Copy()
|
||||
if !reflect.DeepEqual(got, blk) {
|
||||
t.Errorf("CopySignedBeaconBlock() = %v, want %v", got, blk)
|
||||
}
|
||||
@@ -23,7 +23,7 @@ func TestCopySignedBeaconBlock(t *testing.T) {
|
||||
func TestCopyBeaconBlock(t *testing.T) {
|
||||
blk := genBeaconBlock()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlock(blk)
|
||||
got := blk.Copy()
|
||||
if !reflect.DeepEqual(got, blk) {
|
||||
t.Errorf("CopyBeaconBlock() = %v, want %v", got, blk)
|
||||
}
|
||||
@@ -33,7 +33,7 @@ func TestCopyBeaconBlock(t *testing.T) {
|
||||
func TestCopyBeaconBlockBody(t *testing.T) {
|
||||
body := genBeaconBlockBody()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockBody(body)
|
||||
got := body.Copy()
|
||||
if !reflect.DeepEqual(got, body) {
|
||||
t.Errorf("CopyBeaconBlockBody() = %v, want %v", got, body)
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func TestCopyBeaconBlockBody(t *testing.T) {
|
||||
func TestCopySignedBeaconBlockAltair(t *testing.T) {
|
||||
sbb := genSignedBeaconBlockAltair()
|
||||
|
||||
got := v1alpha1.CopySignedBeaconBlockAltair(sbb)
|
||||
got := sbb.Copy()
|
||||
if !reflect.DeepEqual(got, sbb) {
|
||||
t.Errorf("CopySignedBeaconBlockAltair() = %v, want %v", got, sbb)
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func TestCopySignedBeaconBlockAltair(t *testing.T) {
|
||||
func TestCopyBeaconBlockAltair(t *testing.T) {
|
||||
b := genBeaconBlockAltair()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockAltair(b)
|
||||
got := b.Copy()
|
||||
if !reflect.DeepEqual(got, b) {
|
||||
t.Errorf("CopyBeaconBlockAltair() = %v, want %v", got, b)
|
||||
}
|
||||
@@ -63,7 +63,7 @@ func TestCopyBeaconBlockAltair(t *testing.T) {
|
||||
func TestCopyBeaconBlockBodyAltair(t *testing.T) {
|
||||
bb := genBeaconBlockBodyAltair()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockBodyAltair(bb)
|
||||
got := bb.Copy()
|
||||
if !reflect.DeepEqual(got, bb) {
|
||||
t.Errorf("CopyBeaconBlockBodyAltair() = %v, want %v", got, bb)
|
||||
}
|
||||
@@ -133,7 +133,7 @@ func TestCopyPendingAttestationSlice(t *testing.T) {
|
||||
func TestCopySignedBeaconBlockBellatrix(t *testing.T) {
|
||||
sbb := genSignedBeaconBlockBellatrix()
|
||||
|
||||
got := v1alpha1.CopySignedBeaconBlockBellatrix(sbb)
|
||||
got := sbb.Copy()
|
||||
if !reflect.DeepEqual(got, sbb) {
|
||||
t.Errorf("CopySignedBeaconBlockBellatrix() = %v, want %v", got, sbb)
|
||||
}
|
||||
@@ -143,7 +143,7 @@ func TestCopySignedBeaconBlockBellatrix(t *testing.T) {
|
||||
func TestCopyBeaconBlockBellatrix(t *testing.T) {
|
||||
b := genBeaconBlockBellatrix()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockBellatrix(b)
|
||||
got := b.Copy()
|
||||
if !reflect.DeepEqual(got, b) {
|
||||
t.Errorf("CopyBeaconBlockBellatrix() = %v, want %v", got, b)
|
||||
}
|
||||
@@ -153,7 +153,7 @@ func TestCopyBeaconBlockBellatrix(t *testing.T) {
|
||||
func TestCopyBeaconBlockBodyBellatrix(t *testing.T) {
|
||||
bb := genBeaconBlockBodyBellatrix()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockBodyBellatrix(bb)
|
||||
got := bb.Copy()
|
||||
if !reflect.DeepEqual(got, bb) {
|
||||
t.Errorf("CopyBeaconBlockBodyBellatrix() = %v, want %v", got, bb)
|
||||
}
|
||||
@@ -163,7 +163,7 @@ func TestCopyBeaconBlockBodyBellatrix(t *testing.T) {
|
||||
func TestCopySignedBlindedBeaconBlockBellatrix(t *testing.T) {
|
||||
sbb := genSignedBeaconBlockBellatrix()
|
||||
|
||||
got := v1alpha1.CopySignedBeaconBlockBellatrix(sbb)
|
||||
got := sbb.Copy()
|
||||
if !reflect.DeepEqual(got, sbb) {
|
||||
t.Errorf("CopySignedBeaconBlockBellatrix() = %v, want %v", got, sbb)
|
||||
}
|
||||
@@ -173,7 +173,7 @@ func TestCopySignedBlindedBeaconBlockBellatrix(t *testing.T) {
|
||||
func TestCopyBlindedBeaconBlockBellatrix(t *testing.T) {
|
||||
b := genBeaconBlockBellatrix()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockBellatrix(b)
|
||||
got := b.Copy()
|
||||
if !reflect.DeepEqual(got, b) {
|
||||
t.Errorf("CopyBeaconBlockBellatrix() = %v, want %v", got, b)
|
||||
}
|
||||
@@ -183,7 +183,7 @@ func TestCopyBlindedBeaconBlockBellatrix(t *testing.T) {
|
||||
func TestCopyBlindedBeaconBlockBodyBellatrix(t *testing.T) {
|
||||
bb := genBeaconBlockBodyBellatrix()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockBodyBellatrix(bb)
|
||||
got := bb.Copy()
|
||||
if !reflect.DeepEqual(got, bb) {
|
||||
t.Errorf("CopyBeaconBlockBodyBellatrix() = %v, want %v", got, bb)
|
||||
}
|
||||
@@ -193,7 +193,7 @@ func TestCopyBlindedBeaconBlockBodyBellatrix(t *testing.T) {
|
||||
func TestCopySignedBeaconBlockCapella(t *testing.T) {
|
||||
sbb := genSignedBeaconBlockCapella()
|
||||
|
||||
got := v1alpha1.CopySignedBeaconBlockCapella(sbb)
|
||||
got := sbb.Copy()
|
||||
if !reflect.DeepEqual(got, sbb) {
|
||||
t.Errorf("CopySignedBeaconBlockCapella() = %v, want %v", got, sbb)
|
||||
}
|
||||
@@ -203,7 +203,7 @@ func TestCopySignedBeaconBlockCapella(t *testing.T) {
|
||||
func TestCopyBeaconBlockCapella(t *testing.T) {
|
||||
b := genBeaconBlockCapella()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockCapella(b)
|
||||
got := b.Copy()
|
||||
if !reflect.DeepEqual(got, b) {
|
||||
t.Errorf("CopyBeaconBlockCapella() = %v, want %v", got, b)
|
||||
}
|
||||
@@ -213,7 +213,7 @@ func TestCopyBeaconBlockCapella(t *testing.T) {
|
||||
func TestCopyBeaconBlockBodyCapella(t *testing.T) {
|
||||
bb := genBeaconBlockBodyCapella()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockBodyCapella(bb)
|
||||
got := bb.Copy()
|
||||
if !reflect.DeepEqual(got, bb) {
|
||||
t.Errorf("CopyBeaconBlockBodyCapella() = %v, want %v", got, bb)
|
||||
}
|
||||
@@ -223,7 +223,7 @@ func TestCopyBeaconBlockBodyCapella(t *testing.T) {
|
||||
func TestCopySignedBlindedBeaconBlockCapella(t *testing.T) {
|
||||
sbb := genSignedBlindedBeaconBlockCapella()
|
||||
|
||||
got := v1alpha1.CopySignedBlindedBeaconBlockCapella(sbb)
|
||||
got := sbb.Copy()
|
||||
if !reflect.DeepEqual(got, sbb) {
|
||||
t.Errorf("CopySignedBlindedBeaconBlockCapella() = %v, want %v", got, sbb)
|
||||
}
|
||||
@@ -233,7 +233,7 @@ func TestCopySignedBlindedBeaconBlockCapella(t *testing.T) {
|
||||
func TestCopyBlindedBeaconBlockCapella(t *testing.T) {
|
||||
b := genBlindedBeaconBlockCapella()
|
||||
|
||||
got := v1alpha1.CopyBlindedBeaconBlockCapella(b)
|
||||
got := b.Copy()
|
||||
if !reflect.DeepEqual(got, b) {
|
||||
t.Errorf("CopyBlindedBeaconBlockCapella() = %v, want %v", got, b)
|
||||
}
|
||||
@@ -243,7 +243,7 @@ func TestCopyBlindedBeaconBlockCapella(t *testing.T) {
|
||||
func TestCopyBlindedBeaconBlockBodyCapella(t *testing.T) {
|
||||
bb := genBlindedBeaconBlockBodyCapella()
|
||||
|
||||
got := v1alpha1.CopyBlindedBeaconBlockBodyCapella(bb)
|
||||
got := bb.Copy()
|
||||
if !reflect.DeepEqual(got, bb) {
|
||||
t.Errorf("CopyBlindedBeaconBlockBodyCapella() = %v, want %v", got, bb)
|
||||
}
|
||||
@@ -253,7 +253,7 @@ func TestCopyBlindedBeaconBlockBodyCapella(t *testing.T) {
|
||||
func TestCopySignedBeaconBlockDeneb(t *testing.T) {
|
||||
sbb := genSignedBeaconBlockDeneb()
|
||||
|
||||
got := v1alpha1.CopySignedBeaconBlockDeneb(sbb)
|
||||
got := sbb.Copy()
|
||||
if !reflect.DeepEqual(got, sbb) {
|
||||
t.Errorf("CopySignedBeaconBlockDeneb() = %v, want %v", got, sbb)
|
||||
}
|
||||
@@ -263,7 +263,7 @@ func TestCopySignedBeaconBlockDeneb(t *testing.T) {
|
||||
func TestCopyBeaconBlockDeneb(t *testing.T) {
|
||||
b := genBeaconBlockDeneb()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockDeneb(b)
|
||||
got := b.Copy()
|
||||
if !reflect.DeepEqual(got, b) {
|
||||
t.Errorf("CopyBeaconBlockDeneb() = %v, want %v", got, b)
|
||||
}
|
||||
@@ -273,7 +273,7 @@ func TestCopyBeaconBlockDeneb(t *testing.T) {
|
||||
func TestCopyBeaconBlockBodyDeneb(t *testing.T) {
|
||||
bb := genBeaconBlockBodyDeneb()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockBodyDeneb(bb)
|
||||
got := bb.Copy()
|
||||
if !reflect.DeepEqual(got, bb) {
|
||||
t.Errorf("CopyBeaconBlockBodyDeneb() = %v, want %v", got, bb)
|
||||
}
|
||||
@@ -283,7 +283,7 @@ func TestCopyBeaconBlockBodyDeneb(t *testing.T) {
|
||||
func TestCopySignedBlindedBeaconBlockDeneb(t *testing.T) {
|
||||
sbb := genSignedBlindedBeaconBlockDeneb()
|
||||
|
||||
got := v1alpha1.CopySignedBlindedBeaconBlockDeneb(sbb)
|
||||
got := sbb.Copy()
|
||||
if !reflect.DeepEqual(got, sbb) {
|
||||
t.Errorf("CopySignedBlindedBeaconBlockDeneb() = %v, want %v", got, sbb)
|
||||
}
|
||||
@@ -293,7 +293,7 @@ func TestCopySignedBlindedBeaconBlockDeneb(t *testing.T) {
|
||||
func TestCopyBlindedBeaconBlockDeneb(t *testing.T) {
|
||||
b := genBlindedBeaconBlockDeneb()
|
||||
|
||||
got := v1alpha1.CopyBlindedBeaconBlockDeneb(b)
|
||||
got := b.Copy()
|
||||
if !reflect.DeepEqual(got, b) {
|
||||
t.Errorf("CopyBlindedBeaconBlockDeneb() = %v, want %v", got, b)
|
||||
}
|
||||
@@ -303,7 +303,7 @@ func TestCopyBlindedBeaconBlockDeneb(t *testing.T) {
|
||||
func TestCopyBlindedBeaconBlockBodyDeneb(t *testing.T) {
|
||||
bb := genBlindedBeaconBlockBodyDeneb()
|
||||
|
||||
got := v1alpha1.CopyBlindedBeaconBlockBodyDeneb(bb)
|
||||
got := bb.Copy()
|
||||
if !reflect.DeepEqual(got, bb) {
|
||||
t.Errorf("CopyBlindedBeaconBlockBodyDeneb() = %v, want %v", got, bb)
|
||||
}
|
||||
@@ -321,7 +321,7 @@ func bytes(length int) []byte {
|
||||
func TestCopySignedBlindedBeaconBlockElectra(t *testing.T) {
|
||||
sbb := genSignedBlindedBeaconBlockElectra()
|
||||
|
||||
got := v1alpha1.CopySignedBlindedBeaconBlockElectra(sbb)
|
||||
got := sbb.Copy()
|
||||
if !reflect.DeepEqual(got, sbb) {
|
||||
t.Errorf("TestCopySignedBlindedBeaconBlockElectra() = %v, want %v", got, sbb)
|
||||
}
|
||||
@@ -330,7 +330,7 @@ func TestCopySignedBlindedBeaconBlockElectra(t *testing.T) {
|
||||
func TestCopyBlindedBeaconBlockElectra(t *testing.T) {
|
||||
b := genBlindedBeaconBlockElectra()
|
||||
|
||||
got := v1alpha1.CopyBlindedBeaconBlockElectra(b)
|
||||
got := b.Copy()
|
||||
if !reflect.DeepEqual(got, b) {
|
||||
t.Errorf("TestCopyBlindedBeaconBlockElectra() = %v, want %v", got, b)
|
||||
}
|
||||
@@ -339,7 +339,7 @@ func TestCopyBlindedBeaconBlockElectra(t *testing.T) {
|
||||
func TestCopyBlindedBeaconBlockBodyElectra(t *testing.T) {
|
||||
bb := genBlindedBeaconBlockBodyElectra()
|
||||
|
||||
got := v1alpha1.CopyBlindedBeaconBlockBodyElectra(bb)
|
||||
got := bb.Copy()
|
||||
if !reflect.DeepEqual(got, bb) {
|
||||
t.Errorf("TestCopyBlindedBeaconBlockBodyElectra() = %v, want %v", got, bb)
|
||||
}
|
||||
@@ -348,7 +348,7 @@ func TestCopyBlindedBeaconBlockBodyElectra(t *testing.T) {
|
||||
func TestCopySignedBeaconBlockElectra(t *testing.T) {
|
||||
sbb := genSignedBeaconBlockElectra()
|
||||
|
||||
got := v1alpha1.CopySignedBeaconBlockElectra(sbb)
|
||||
got := sbb.Copy()
|
||||
if !reflect.DeepEqual(got, sbb) {
|
||||
t.Errorf("TestCopySignedBeaconBlockElectra() = %v, want %v", got, sbb)
|
||||
}
|
||||
@@ -357,7 +357,7 @@ func TestCopySignedBeaconBlockElectra(t *testing.T) {
|
||||
func TestCopyBeaconBlockElectra(t *testing.T) {
|
||||
b := genBeaconBlockElectra()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockElectra(b)
|
||||
got := b.Copy()
|
||||
if !reflect.DeepEqual(got, b) {
|
||||
t.Errorf("TestCopyBeaconBlockElectra() = %v, want %v", got, b)
|
||||
}
|
||||
@@ -366,7 +366,7 @@ func TestCopyBeaconBlockElectra(t *testing.T) {
|
||||
func TestCopyBeaconBlockBodyElectra(t *testing.T) {
|
||||
bb := genBeaconBlockBodyElectra()
|
||||
|
||||
got := v1alpha1.CopyBeaconBlockBodyElectra(bb)
|
||||
got := bb.Copy()
|
||||
if !reflect.DeepEqual(got, bb) {
|
||||
t.Errorf("TestCopyBeaconBlockBodyElectra() = %v, want %v", got, bb)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ Originally from [github.com/x-cray/logrus-prefixed-formatter(https://github.com/
|
||||
modified colored output and support for log entry prefixes, e.g. message source followed by a colon. In addition, custom
|
||||
color themes are supported.
|
||||
|
||||

|
||||

|
||||
|
||||
Just like with the original `logrus.TextFormatter` when a TTY is not attached, the output is compatible with the
|
||||
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||
|
||||
@@ -17,21 +17,13 @@ go_library(
|
||||
visibility = ["//testing/spectest:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/spectest/utils:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//testing/spectest/shared/common/operations:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"@com_github_golang_snappy//:go_default_library",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//testing/protocmp:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,59 +1,27 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
b "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunAttestationTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "altair", "operations/attestation/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "altair", "operations/attestation/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
attestationFile, err := util.BazelFileBytes(folderPath, "attestation.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
attestationSSZ, err := snappy.Decode(nil /* dst */, attestationFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
att := ðpb.Attestation{}
|
||||
require.NoError(t, att.UnmarshalSSZ(attestationSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyAltair{Attestations: []*ethpb.Attestation{att}}
|
||||
processAtt := func(ctx context.Context, st state.BeaconState, blk interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
st, err = altair.ProcessAttestationsNoVerifySignature(ctx, st, blk.Block())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aSet, err := b.AttestationSignatureBatch(ctx, st, blk.Block().Body().Attestations())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
verified, err := aSet.Verify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !verified {
|
||||
return nil, errors.New("could not batch verify attestation signature")
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
RunBlockOperationTest(t, folderPath, body, processAtt)
|
||||
})
|
||||
func blockWithAttestation(attestationSSZ []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
att := ðpb.Attestation{}
|
||||
if err := att.UnmarshalSSZ(attestationSSZ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockAltair()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyAltair{Attestations: []*ethpb.Attestation{att}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunAttestationTest(t *testing.T, config string) {
|
||||
common.RunAttestationTest(t, config, version.String(version.Altair), blockWithAttestation, altair.ProcessAttestationsNoVerifySignature, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,26 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunAttesterSlashingTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "altair", "operations/attester_slashing/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "altair", "operations/attester_slashing/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
attSlashingFile, err := util.BazelFileBytes(folderPath, "attester_slashing.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
attSlashingSSZ, err := snappy.Decode(nil /* dst */, attSlashingFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
attSlashing := ðpb.AttesterSlashing{}
|
||||
require.NoError(t, attSlashing.UnmarshalSSZ(attSlashingSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyAltair{AttesterSlashings: []*ethpb.AttesterSlashing{attSlashing}}
|
||||
RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
return blocks.ProcessAttesterSlashings(ctx, s, b.Block().Body().AttesterSlashings(), validators.SlashValidator)
|
||||
})
|
||||
})
|
||||
func blockWithAttesterSlashing(asSSZ []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
as := ðpb.AttesterSlashing{}
|
||||
if err := as.UnmarshalSSZ(asSSZ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockAltair()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyAltair{AttesterSlashings: []*ethpb.AttesterSlashing{as}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunAttesterSlashingTest(t *testing.T, config string) {
|
||||
common.RunAttesterSlashingTest(t, config, version.String(version.Altair), blockWithAttesterSlashing, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,90 +1,12 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/golang/snappy"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
)
|
||||
|
||||
func RunBlockHeaderTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "altair", "operations/block_header/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "altair", "operations/block_header/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
|
||||
blockFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "block.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
blockSSZ, err := snappy.Decode(nil /* dst */, blockFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
block := ðpb.BeaconBlockAltair{}
|
||||
require.NoError(t, block.UnmarshalSSZ(blockSSZ), "Failed to unmarshal")
|
||||
|
||||
preBeaconStateFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
preBeaconStateSSZ, err := snappy.Decode(nil /* dst */, preBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
preBeaconStateBase := ðpb.BeaconStateAltair{}
|
||||
require.NoError(t, preBeaconStateBase.UnmarshalSSZ(preBeaconStateSSZ), "Failed to unmarshal")
|
||||
preBeaconState, err := state_native.InitializeFromProtoAltair(preBeaconStateBase)
|
||||
require.NoError(t, err)
|
||||
|
||||
// If the post.ssz is not present, it means the test should fail on our end.
|
||||
postSSZFilepath, err := bazel.Runfile(path.Join(testsFolderPath, folder.Name(), "post.ssz_snappy"))
|
||||
postSSZExists := true
|
||||
if err != nil && strings.Contains(err.Error(), "could not locate file") {
|
||||
postSSZExists = false
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Spectest blocks are not signed, so we'll call NoVerify to skip sig verification.
|
||||
bodyRoot, err := block.Body.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
beaconState, err := blocks.ProcessBlockHeaderNoVerify(context.Background(), preBeaconState, block.Slot, block.ProposerIndex, block.ParentRoot, bodyRoot[:])
|
||||
if postSSZExists {
|
||||
require.NoError(t, err)
|
||||
|
||||
postBeaconStateFile, err := os.ReadFile(postSSZFilepath) // #nosec G304
|
||||
require.NoError(t, err)
|
||||
postBeaconStateSSZ, err := snappy.Decode(nil /* dst */, postBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
|
||||
postBeaconState := ðpb.BeaconStateAltair{}
|
||||
require.NoError(t, postBeaconState.UnmarshalSSZ(postBeaconStateSSZ), "Failed to unmarshal")
|
||||
pbState, err := state_native.ProtobufBeaconStateAltair(beaconState.ToProto())
|
||||
require.NoError(t, err)
|
||||
if !proto.Equal(pbState, postBeaconState) {
|
||||
t.Log(cmp.Diff(postBeaconState, pbState, protocmp.Transform()))
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
} else {
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
t.Logf("Expected failure; failure reason = %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
common.RunBlockHeaderTest(t, config, version.String(version.Altair), sszToBlock, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,27 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunDepositTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "altair", "operations/deposit/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "altair", "operations/deposit/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
depositFile, err := util.BazelFileBytes(folderPath, "deposit.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
depositSSZ, err := snappy.Decode(nil /* dst */, depositFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
deposit := ðpb.Deposit{}
|
||||
require.NoError(t, deposit.UnmarshalSSZ(depositSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyAltair{Deposits: []*ethpb.Deposit{deposit}}
|
||||
processDepositsFunc := func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
return altair.ProcessDeposits(ctx, s, b.Block().Body().Deposits())
|
||||
}
|
||||
RunBlockOperationTest(t, folderPath, body, processDepositsFunc)
|
||||
})
|
||||
func blockWithDeposit(ssz []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
d := ðpb.Deposit{}
|
||||
if err := d.UnmarshalSSZ(ssz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockAltair()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyAltair{Deposits: []*ethpb.Deposit{d}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunDepositTest(t *testing.T, config string) {
|
||||
common.RunDepositTest(t, config, version.String(version.Altair), blockWithDeposit, altair.ProcessDeposits, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,88 +1,25 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/golang/snappy"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
)
|
||||
|
||||
type blockOperation func(context.Context, state.BeaconState, interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error)
|
||||
|
||||
// RunBlockOperationTest takes in the prestate and the beacon block body, processes it through the
|
||||
// passed in block operation function and checks the post state with the expected post state.
|
||||
func RunBlockOperationTest(
|
||||
t *testing.T,
|
||||
folderPath string,
|
||||
body *ethpb.BeaconBlockBodyAltair,
|
||||
operationFn blockOperation,
|
||||
) {
|
||||
preBeaconStateFile, err := util.BazelFileBytes(path.Join(folderPath, "pre.ssz_snappy"))
|
||||
require.NoError(t, err)
|
||||
preBeaconStateSSZ, err := snappy.Decode(nil /* dst */, preBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
preStateBase := ðpb.BeaconStateAltair{}
|
||||
if err := preStateBase.UnmarshalSSZ(preBeaconStateSSZ); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
preState, err := state_native.InitializeFromProtoAltair(preStateBase)
|
||||
require.NoError(t, err)
|
||||
|
||||
// If the post.ssz is not present, it means the test should fail on our end.
|
||||
postSSZFilepath, err := bazel.Runfile(path.Join(folderPath, "post.ssz_snappy"))
|
||||
postSSZExists := true
|
||||
if err != nil && strings.Contains(err.Error(), "could not locate file") {
|
||||
postSSZExists = false
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
helpers.ClearCache()
|
||||
b := util.NewBeaconBlockAltair()
|
||||
b.Block.Body = body
|
||||
wsb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
beaconState, err := operationFn(context.Background(), preState, wsb)
|
||||
if postSSZExists {
|
||||
require.NoError(t, err)
|
||||
|
||||
postBeaconStateFile, err := os.ReadFile(postSSZFilepath) // #nosec G304
|
||||
require.NoError(t, err)
|
||||
postBeaconStateSSZ, err := snappy.Decode(nil /* dst */, postBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
|
||||
postBeaconState := ðpb.BeaconStateAltair{}
|
||||
if err := postBeaconState.UnmarshalSSZ(postBeaconStateSSZ); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
pbState, err := state_native.ProtobufBeaconStateAltair(beaconState.ToProtoUnsafe())
|
||||
require.NoError(t, err)
|
||||
if !proto.Equal(pbState, postBeaconState) {
|
||||
t.Log(cmp.Diff(postBeaconState, pbState, protocmp.Transform()))
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
} else {
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
t.Logf("Expected failure; failure reason = %v", err)
|
||||
return
|
||||
func sszToState(b []byte) (state.BeaconState, error) {
|
||||
base := ðpb.BeaconStateAltair{}
|
||||
if err := base.UnmarshalSSZ(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return state_native.InitializeFromProtoAltair(base)
|
||||
}
|
||||
|
||||
func sszToBlock(b []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
base := ðpb.BeaconBlockAltair{}
|
||||
if err := base.UnmarshalSSZ(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockAltair{Block: base})
|
||||
}
|
||||
|
||||
@@ -1,41 +1,26 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunProposerSlashingTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "altair", "operations/proposer_slashing/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "altair", "operations/proposer_slashing/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
proposerSlashingFile, err := util.BazelFileBytes(folderPath, "proposer_slashing.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
proposerSlashingSSZ, err := snappy.Decode(nil /* dst */, proposerSlashingFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
proposerSlashing := ðpb.ProposerSlashing{}
|
||||
require.NoError(t, proposerSlashing.UnmarshalSSZ(proposerSlashingSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyAltair{ProposerSlashings: []*ethpb.ProposerSlashing{proposerSlashing}}
|
||||
RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
return blocks.ProcessProposerSlashings(ctx, s, b.Block().Body().ProposerSlashings(), validators.SlashValidator)
|
||||
})
|
||||
})
|
||||
func blockWithProposerSlashing(ssz []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
ps := ðpb.ProposerSlashing{}
|
||||
if err := ps.UnmarshalSSZ(ssz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockAltair()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyAltair{ProposerSlashings: []*ethpb.ProposerSlashing{ps}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunProposerSlashingTest(t *testing.T, config string) {
|
||||
common.RunProposerSlashingTest(t, config, version.String(version.Altair), blockWithProposerSlashing, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,44 +1,26 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunSyncCommitteeTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "altair", "operations/sync_aggregate/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "altair", "operations/sync_aggregate/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
syncCommitteeFile, err := util.BazelFileBytes(folderPath, "sync_aggregate.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
syncCommitteeSSZ, err := snappy.Decode(nil /* dst */, syncCommitteeFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
sc := ðpb.SyncAggregate{}
|
||||
require.NoError(t, sc.UnmarshalSSZ(syncCommitteeSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyAltair{SyncAggregate: sc}
|
||||
RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
st, _, err := altair.ProcessSyncAggregate(context.Background(), s, body.SyncAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st, nil
|
||||
})
|
||||
})
|
||||
func blockWithSyncAggregate(ssz []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
sa := ðpb.SyncAggregate{}
|
||||
if err := sa.UnmarshalSSZ(ssz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockAltair()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyAltair{SyncAggregate: sa}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunSyncCommitteeTest(t *testing.T, config string) {
|
||||
common.RunSyncCommitteeTest(t, config, version.String(version.Altair), blockWithSyncAggregate, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,40 +1,26 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunVoluntaryExitTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "altair", "operations/voluntary_exit/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "altair", "operations/voluntary_exit/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
exitFile, err := util.BazelFileBytes(folderPath, "voluntary_exit.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
exitSSZ, err := snappy.Decode(nil /* dst */, exitFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
voluntaryExit := ðpb.SignedVoluntaryExit{}
|
||||
require.NoError(t, voluntaryExit.UnmarshalSSZ(exitSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyAltair{VoluntaryExits: []*ethpb.SignedVoluntaryExit{voluntaryExit}}
|
||||
RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
return blocks.ProcessVoluntaryExits(ctx, s, b.Block().Body().VoluntaryExits())
|
||||
})
|
||||
})
|
||||
func blockWithVoluntaryExit(ssz []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
e := ðpb.SignedVoluntaryExit{}
|
||||
if err := e.UnmarshalSSZ(ssz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockAltair()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyAltair{VoluntaryExits: []*ethpb.SignedVoluntaryExit{e}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunVoluntaryExitTest(t *testing.T, config string) {
|
||||
common.RunVoluntaryExitTest(t, config, version.String(version.Altair), blockWithVoluntaryExit, sszToState)
|
||||
}
|
||||
|
||||
@@ -18,21 +18,13 @@ go_library(
|
||||
visibility = ["//testing/spectest:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/spectest/utils:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//testing/spectest/shared/common/operations:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"@com_github_golang_snappy//:go_default_library",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//testing/protocmp:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,59 +1,27 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
b "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunAttestationTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "bellatrix", "operations/attestation/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "bellatrix", "operations/attestation/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
attestationFile, err := util.BazelFileBytes(folderPath, "attestation.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
attestationSSZ, err := snappy.Decode(nil /* dst */, attestationFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
att := ðpb.Attestation{}
|
||||
require.NoError(t, att.UnmarshalSSZ(attestationSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyBellatrix{Attestations: []*ethpb.Attestation{att}}
|
||||
processAtt := func(ctx context.Context, st state.BeaconState, blk interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
st, err = altair.ProcessAttestationsNoVerifySignature(ctx, st, blk.Block())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aSet, err := b.AttestationSignatureBatch(ctx, st, blk.Block().Body().Attestations())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
verified, err := aSet.Verify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !verified {
|
||||
return nil, errors.New("could not batch verify attestation signature")
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
RunBlockOperationTest(t, folderPath, body, processAtt)
|
||||
})
|
||||
func blockWithAttestation(attestationSSZ []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
att := ðpb.Attestation{}
|
||||
if err := att.UnmarshalSSZ(attestationSSZ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockBellatrix()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyBellatrix{Attestations: []*ethpb.Attestation{att}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunAttestationTest(t *testing.T, config string) {
|
||||
common.RunAttestationTest(t, config, version.String(version.Bellatrix), blockWithAttestation, altair.ProcessAttestationsNoVerifySignature, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,26 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunAttesterSlashingTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "bellatrix", "operations/attester_slashing/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "bellatrix", "operations/attester_slashing/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
attSlashingFile, err := util.BazelFileBytes(folderPath, "attester_slashing.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
attSlashingSSZ, err := snappy.Decode(nil /* dst */, attSlashingFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
attSlashing := ðpb.AttesterSlashing{}
|
||||
require.NoError(t, attSlashing.UnmarshalSSZ(attSlashingSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyBellatrix{AttesterSlashings: []*ethpb.AttesterSlashing{attSlashing}}
|
||||
RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
return blocks.ProcessAttesterSlashings(ctx, s, b.Block().Body().AttesterSlashings(), validators.SlashValidator)
|
||||
})
|
||||
})
|
||||
func blockWithAttesterSlashing(asSSZ []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
as := ðpb.AttesterSlashing{}
|
||||
if err := as.UnmarshalSSZ(asSSZ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockBellatrix()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyBellatrix{AttesterSlashings: []*ethpb.AttesterSlashing{as}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunAttesterSlashingTest(t *testing.T, config string) {
|
||||
common.RunAttesterSlashingTest(t, config, version.String(version.Bellatrix), blockWithAttesterSlashing, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,90 +1,12 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/golang/snappy"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
)
|
||||
|
||||
func RunBlockHeaderTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "bellatrix", "operations/block_header/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "bellatrix", "operations/block_header/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
|
||||
blockFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "block.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
blockSSZ, err := snappy.Decode(nil /* dst */, blockFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
block := ðpb.BeaconBlockBellatrix{}
|
||||
require.NoError(t, block.UnmarshalSSZ(blockSSZ), "Failed to unmarshal")
|
||||
|
||||
preBeaconStateFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
preBeaconStateSSZ, err := snappy.Decode(nil /* dst */, preBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
preBeaconStateBase := ðpb.BeaconStateBellatrix{}
|
||||
require.NoError(t, preBeaconStateBase.UnmarshalSSZ(preBeaconStateSSZ), "Failed to unmarshal")
|
||||
preBeaconState, err := state_native.InitializeFromProtoBellatrix(preBeaconStateBase)
|
||||
require.NoError(t, err)
|
||||
|
||||
// If the post.ssz is not present, it means the test should fail on our end.
|
||||
postSSZFilepath, err := bazel.Runfile(path.Join(testsFolderPath, folder.Name(), "post.ssz_snappy"))
|
||||
postSSZExists := true
|
||||
if err != nil && strings.Contains(err.Error(), "could not locate file") {
|
||||
postSSZExists = false
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Spectest blocks are not signed, so we'll call NoVerify to skip sig verification.
|
||||
bodyRoot, err := block.Body.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
beaconState, err := blocks.ProcessBlockHeaderNoVerify(context.Background(), preBeaconState, block.Slot, block.ProposerIndex, block.ParentRoot, bodyRoot[:])
|
||||
if postSSZExists {
|
||||
require.NoError(t, err)
|
||||
|
||||
postBeaconStateFile, err := os.ReadFile(postSSZFilepath) // #nosec G304
|
||||
require.NoError(t, err)
|
||||
postBeaconStateSSZ, err := snappy.Decode(nil /* dst */, postBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
|
||||
postBeaconState := ðpb.BeaconStateBellatrix{}
|
||||
require.NoError(t, postBeaconState.UnmarshalSSZ(postBeaconStateSSZ), "Failed to unmarshal")
|
||||
pbState, err := state_native.ProtobufBeaconStateBellatrix(beaconState.ToProto())
|
||||
require.NoError(t, err)
|
||||
if !proto.Equal(pbState, postBeaconState) {
|
||||
t.Log(cmp.Diff(postBeaconState, pbState, protocmp.Transform()))
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
} else {
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
t.Logf("Expected failure; failure reason = %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
common.RunBlockHeaderTest(t, config, version.String(version.Bellatrix), sszToBlock, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,27 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunDepositTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "bellatrix", "operations/deposit/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "bellatrix", "operations/deposit/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
depositFile, err := util.BazelFileBytes(folderPath, "deposit.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
depositSSZ, err := snappy.Decode(nil /* dst */, depositFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
deposit := ðpb.Deposit{}
|
||||
require.NoError(t, deposit.UnmarshalSSZ(depositSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyBellatrix{Deposits: []*ethpb.Deposit{deposit}}
|
||||
processDepositsFunc := func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
return altair.ProcessDeposits(ctx, s, b.Block().Body().Deposits())
|
||||
}
|
||||
RunBlockOperationTest(t, folderPath, body, processDepositsFunc)
|
||||
})
|
||||
func blockWithDeposit(ssz []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
d := ðpb.Deposit{}
|
||||
if err := d.UnmarshalSSZ(ssz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockBellatrix()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyBellatrix{Deposits: []*ethpb.Deposit{d}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunDepositTest(t *testing.T, config string) {
|
||||
common.RunDepositTest(t, config, version.String(version.Bellatrix), blockWithDeposit, altair.ProcessDeposits, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,98 +1,12 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/golang/snappy"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
|
||||
blocks2 "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
)
|
||||
|
||||
func RunExecutionPayloadTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "bellatrix", "operations/execution_payload/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "bellatrix", "operations/execution_payload/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
|
||||
blockBodyFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "body.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
blockSSZ, err := snappy.Decode(nil /* dst */, blockBodyFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
block := ðpb.BeaconBlockBodyBellatrix{}
|
||||
require.NoError(t, block.UnmarshalSSZ(blockSSZ), "Failed to unmarshal")
|
||||
|
||||
preBeaconStateFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
preBeaconStateSSZ, err := snappy.Decode(nil /* dst */, preBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
preBeaconStateBase := ðpb.BeaconStateBellatrix{}
|
||||
require.NoError(t, preBeaconStateBase.UnmarshalSSZ(preBeaconStateSSZ), "Failed to unmarshal")
|
||||
preBeaconState, err := state_native.InitializeFromProtoBellatrix(preBeaconStateBase)
|
||||
require.NoError(t, err)
|
||||
|
||||
postSSZFilepath, err := bazel.Runfile(path.Join(testsFolderPath, folder.Name(), "post.ssz_snappy"))
|
||||
postSSZExists := true
|
||||
if err != nil && strings.Contains(err.Error(), "could not locate file") {
|
||||
postSSZExists = false
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
payload, err := blocks2.WrappedExecutionPayload(block.ExecutionPayload)
|
||||
require.NoError(t, err)
|
||||
|
||||
file, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "execution.yaml")
|
||||
require.NoError(t, err)
|
||||
config := &ExecutionConfig{}
|
||||
require.NoError(t, utils.UnmarshalYaml(file, config), "Failed to Unmarshal")
|
||||
|
||||
gotState, err := blocks.ProcessPayload(preBeaconState, payload)
|
||||
if postSSZExists {
|
||||
require.NoError(t, err)
|
||||
|
||||
postBeaconStateFile, err := os.ReadFile(postSSZFilepath) // #nosec G304
|
||||
require.NoError(t, err)
|
||||
postBeaconStateSSZ, err := snappy.Decode(nil /* dst */, postBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
|
||||
postBeaconState := ðpb.BeaconStateBellatrix{}
|
||||
require.NoError(t, postBeaconState.UnmarshalSSZ(postBeaconStateSSZ), "Failed to unmarshal")
|
||||
pbState, err := state_native.ProtobufBeaconStateBellatrix(gotState.ToProto())
|
||||
require.NoError(t, err)
|
||||
if !proto.Equal(pbState, postBeaconState) {
|
||||
t.Log(cmp.Diff(postBeaconState, pbState, protocmp.Transform()))
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
} else if config.Valid {
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
t.Logf("Expected failure; failure reason = %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type ExecutionConfig struct {
|
||||
Valid bool `json:"execution_valid"`
|
||||
common.RunExecutionPayloadTest(t, config, version.String(version.Bellatrix), sszToBlockBody, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,88 +1,33 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/golang/snappy"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
)
|
||||
|
||||
type blockOperation func(context.Context, state.BeaconState, interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error)
|
||||
|
||||
// RunBlockOperationTest takes in the prestate and the beacon block body, processes it through the
|
||||
// passed in block operation function and checks the post state with the expected post state.
|
||||
func RunBlockOperationTest(
|
||||
t *testing.T,
|
||||
folderPath string,
|
||||
body *ethpb.BeaconBlockBodyBellatrix,
|
||||
operationFn blockOperation,
|
||||
) {
|
||||
preBeaconStateFile, err := util.BazelFileBytes(path.Join(folderPath, "pre.ssz_snappy"))
|
||||
require.NoError(t, err)
|
||||
preBeaconStateSSZ, err := snappy.Decode(nil /* dst */, preBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
preStateBase := ðpb.BeaconStateBellatrix{}
|
||||
if err := preStateBase.UnmarshalSSZ(preBeaconStateSSZ); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
preState, err := state_native.InitializeFromProtoBellatrix(preStateBase)
|
||||
require.NoError(t, err)
|
||||
|
||||
// If the post.ssz is not present, it means the test should fail on our end.
|
||||
postSSZFilepath, err := bazel.Runfile(path.Join(folderPath, "post.ssz_snappy"))
|
||||
postSSZExists := true
|
||||
if err != nil && strings.Contains(err.Error(), "could not locate file") {
|
||||
postSSZExists = false
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
helpers.ClearCache()
|
||||
b := util.NewBeaconBlockBellatrix()
|
||||
b.Block.Body = body
|
||||
wsb, err := blocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
beaconState, err := operationFn(context.Background(), preState, wsb)
|
||||
if postSSZExists {
|
||||
require.NoError(t, err)
|
||||
|
||||
postBeaconStateFile, err := os.ReadFile(postSSZFilepath) // #nosec G304
|
||||
require.NoError(t, err)
|
||||
postBeaconStateSSZ, err := snappy.Decode(nil /* dst */, postBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
|
||||
postBeaconState := ðpb.BeaconStateBellatrix{}
|
||||
if err := postBeaconState.UnmarshalSSZ(postBeaconStateSSZ); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
pbState, err := state_native.ProtobufBeaconStateBellatrix(beaconState.ToProtoUnsafe())
|
||||
require.NoError(t, err)
|
||||
if !proto.Equal(pbState, postBeaconState) {
|
||||
t.Log(cmp.Diff(postBeaconState, pbState, protocmp.Transform()))
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
} else {
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
t.Logf("Expected failure; failure reason = %v", err)
|
||||
return
|
||||
func sszToState(b []byte) (state.BeaconState, error) {
|
||||
base := ðpb.BeaconStateBellatrix{}
|
||||
if err := base.UnmarshalSSZ(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return state_native.InitializeFromProtoBellatrix(base)
|
||||
}
|
||||
|
||||
func sszToBlock(b []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
base := ðpb.BeaconBlockBellatrix{}
|
||||
if err := base.UnmarshalSSZ(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: base})
|
||||
}
|
||||
|
||||
func sszToBlockBody(b []byte) (interfaces.ReadOnlyBeaconBlockBody, error) {
|
||||
base := ðpb.BeaconBlockBodyBellatrix{}
|
||||
if err := base.UnmarshalSSZ(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return blocks.NewBeaconBlockBody(base)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,26 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunProposerSlashingTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "bellatrix", "operations/proposer_slashing/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "bellatrix", "operations/proposer_slashing/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
proposerSlashingFile, err := util.BazelFileBytes(folderPath, "proposer_slashing.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
proposerSlashingSSZ, err := snappy.Decode(nil /* dst */, proposerSlashingFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
proposerSlashing := ðpb.ProposerSlashing{}
|
||||
require.NoError(t, proposerSlashing.UnmarshalSSZ(proposerSlashingSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyBellatrix{ProposerSlashings: []*ethpb.ProposerSlashing{proposerSlashing}}
|
||||
RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
return blocks.ProcessProposerSlashings(ctx, s, b.Block().Body().ProposerSlashings(), validators.SlashValidator)
|
||||
})
|
||||
})
|
||||
func blockWithProposerSlashing(ssz []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
ps := ðpb.ProposerSlashing{}
|
||||
if err := ps.UnmarshalSSZ(ssz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockBellatrix()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyBellatrix{ProposerSlashings: []*ethpb.ProposerSlashing{ps}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunProposerSlashingTest(t *testing.T, config string) {
|
||||
common.RunProposerSlashingTest(t, config, version.String(version.Bellatrix), blockWithProposerSlashing, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,44 +1,26 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunSyncCommitteeTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "bellatrix", "operations/sync_aggregate/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "bellatrix", "operations/sync_aggregate/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
syncCommitteeFile, err := util.BazelFileBytes(folderPath, "sync_aggregate.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
syncCommitteeSSZ, err := snappy.Decode(nil /* dst */, syncCommitteeFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
sc := ðpb.SyncAggregate{}
|
||||
require.NoError(t, sc.UnmarshalSSZ(syncCommitteeSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyBellatrix{SyncAggregate: sc}
|
||||
RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
st, _, err := altair.ProcessSyncAggregate(context.Background(), s, body.SyncAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st, nil
|
||||
})
|
||||
})
|
||||
func blockWithSyncAggregate(ssz []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
sa := ðpb.SyncAggregate{}
|
||||
if err := sa.UnmarshalSSZ(ssz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockBellatrix()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyBellatrix{SyncAggregate: sa}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunSyncCommitteeTest(t *testing.T, config string) {
|
||||
common.RunSyncCommitteeTest(t, config, version.String(version.Bellatrix), blockWithSyncAggregate, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,40 +1,26 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunVoluntaryExitTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "bellatrix", "operations/voluntary_exit/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "bellatrix", "operations/voluntary_exit/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
exitFile, err := util.BazelFileBytes(folderPath, "voluntary_exit.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
exitSSZ, err := snappy.Decode(nil /* dst */, exitFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
voluntaryExit := ðpb.SignedVoluntaryExit{}
|
||||
require.NoError(t, voluntaryExit.UnmarshalSSZ(exitSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyBellatrix{VoluntaryExits: []*ethpb.SignedVoluntaryExit{voluntaryExit}}
|
||||
RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
return blocks.ProcessVoluntaryExits(ctx, s, b.Block().Body().VoluntaryExits())
|
||||
})
|
||||
})
|
||||
func blockWithVoluntaryExit(ssz []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
e := ðpb.SignedVoluntaryExit{}
|
||||
if err := e.UnmarshalSSZ(ssz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockBellatrix()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyBellatrix{VoluntaryExits: []*ethpb.SignedVoluntaryExit{e}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunVoluntaryExitTest(t *testing.T, config string) {
|
||||
common.RunVoluntaryExitTest(t, config, version.String(version.Bellatrix), blockWithVoluntaryExit, sszToState)
|
||||
}
|
||||
|
||||
@@ -20,23 +20,14 @@ go_library(
|
||||
visibility = ["//testing/spectest:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/spectest/utils:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//testing/spectest/shared/common/operations:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"@com_github_golang_snappy//:go_default_library",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
"@org_golang_google_protobuf//testing/protocmp:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,59 +1,27 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
b "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunAttestationTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "capella", "operations/attestation/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "capella", "operations/attestation/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
attestationFile, err := util.BazelFileBytes(folderPath, "attestation.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
attestationSSZ, err := snappy.Decode(nil /* dst */, attestationFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
att := ðpb.Attestation{}
|
||||
require.NoError(t, att.UnmarshalSSZ(attestationSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyCapella{Attestations: []*ethpb.Attestation{att}}
|
||||
processAtt := func(ctx context.Context, st state.BeaconState, blk interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
st, err = altair.ProcessAttestationsNoVerifySignature(ctx, st, blk.Block())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aSet, err := b.AttestationSignatureBatch(ctx, st, blk.Block().Body().Attestations())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
verified, err := aSet.Verify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !verified {
|
||||
return nil, errors.New("could not batch verify attestation signature")
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
RunBlockOperationTest(t, folderPath, body, processAtt)
|
||||
})
|
||||
func blockWithAttestation(attestationSSZ []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
att := ðpb.Attestation{}
|
||||
if err := att.UnmarshalSSZ(attestationSSZ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockCapella()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyCapella{Attestations: []*ethpb.Attestation{att}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunAttestationTest(t *testing.T, config string) {
|
||||
common.RunAttestationTest(t, config, version.String(version.Capella), blockWithAttestation, altair.ProcessAttestationsNoVerifySignature, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,26 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunAttesterSlashingTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "capella", "operations/attester_slashing/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "capella", "operations/attester_slashing/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
attSlashingFile, err := util.BazelFileBytes(folderPath, "attester_slashing.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
attSlashingSSZ, err := snappy.Decode(nil /* dst */, attSlashingFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
attSlashing := ðpb.AttesterSlashing{}
|
||||
require.NoError(t, attSlashing.UnmarshalSSZ(attSlashingSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyCapella{AttesterSlashings: []*ethpb.AttesterSlashing{attSlashing}}
|
||||
RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
return blocks.ProcessAttesterSlashings(ctx, s, b.Block().Body().AttesterSlashings(), validators.SlashValidator)
|
||||
})
|
||||
})
|
||||
func blockWithAttesterSlashing(asSSZ []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
as := ðpb.AttesterSlashing{}
|
||||
if err := as.UnmarshalSSZ(asSSZ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockCapella()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyCapella{AttesterSlashings: []*ethpb.AttesterSlashing{as}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunAttesterSlashingTest(t *testing.T, config string) {
|
||||
common.RunAttesterSlashingTest(t, config, version.String(version.Capella), blockWithAttesterSlashing, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,90 +1,12 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/golang/snappy"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
)
|
||||
|
||||
func RunBlockHeaderTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "capella", "operations/block_header/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "capella", "operations/block_header/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
|
||||
blockFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "block.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
blockSSZ, err := snappy.Decode(nil /* dst */, blockFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
block := ðpb.BeaconBlockCapella{}
|
||||
require.NoError(t, block.UnmarshalSSZ(blockSSZ), "Failed to unmarshal")
|
||||
|
||||
preBeaconStateFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
preBeaconStateSSZ, err := snappy.Decode(nil /* dst */, preBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
preBeaconStateBase := ðpb.BeaconStateCapella{}
|
||||
require.NoError(t, preBeaconStateBase.UnmarshalSSZ(preBeaconStateSSZ), "Failed to unmarshal")
|
||||
preBeaconState, err := state_native.InitializeFromProtoCapella(preBeaconStateBase)
|
||||
require.NoError(t, err)
|
||||
|
||||
// If the post.ssz is not present, it means the test should fail on our end.
|
||||
postSSZFilepath, err := bazel.Runfile(path.Join(testsFolderPath, folder.Name(), "post.ssz_snappy"))
|
||||
postSSZExists := true
|
||||
if err != nil && strings.Contains(err.Error(), "could not locate file") {
|
||||
postSSZExists = false
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Spectest blocks are not signed, so we'll call NoVerify to skip sig verification.
|
||||
bodyRoot, err := block.Body.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
beaconState, err := blocks.ProcessBlockHeaderNoVerify(context.Background(), preBeaconState, block.Slot, block.ProposerIndex, block.ParentRoot, bodyRoot[:])
|
||||
if postSSZExists {
|
||||
require.NoError(t, err)
|
||||
|
||||
postBeaconStateFile, err := os.ReadFile(postSSZFilepath) // #nosec G304
|
||||
require.NoError(t, err)
|
||||
postBeaconStateSSZ, err := snappy.Decode(nil /* dst */, postBeaconStateFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
|
||||
postBeaconState := ðpb.BeaconStateCapella{}
|
||||
require.NoError(t, postBeaconState.UnmarshalSSZ(postBeaconStateSSZ), "Failed to unmarshal")
|
||||
pbState, err := state_native.ProtobufBeaconStateCapella(beaconState.ToProto())
|
||||
require.NoError(t, err)
|
||||
if !proto.Equal(pbState, postBeaconState) {
|
||||
t.Log(cmp.Diff(postBeaconState, pbState, protocmp.Transform()))
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
} else {
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
t.Logf("Expected failure; failure reason = %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
common.RunBlockHeaderTest(t, config, version.String(version.Capella), sszToBlock, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,62 +1,26 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunBLSToExecutionChangeTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "capella", "operations/bls_to_execution_change/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "capella", "operations/bls_to_execution_change/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
changeFile, err := util.BazelFileBytes(folderPath, "address_change.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
changeSSZ, err := snappy.Decode(nil /* dst */, changeFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
change := ðpb.SignedBLSToExecutionChange{}
|
||||
require.NoError(t, change.UnmarshalSSZ(changeSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyCapella{
|
||||
BlsToExecutionChanges: []*ethpb.SignedBLSToExecutionChange{change},
|
||||
}
|
||||
RunBlockOperationTest(t, folderPath, body, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
st, err := blocks.ProcessBLSToExecutionChanges(s, b.Block())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes, err := b.Block().Body().BLSToExecutionChanges()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cSet, err := blocks.BLSChangesSignatureBatch(st, changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ok, err := cSet.Verify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
return nil, errors.New("signature did not verify")
|
||||
}
|
||||
return st, nil
|
||||
})
|
||||
})
|
||||
func blockWithBlsChange(ssz []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
c := ðpb.SignedBLSToExecutionChange{}
|
||||
if err := c.UnmarshalSSZ(ssz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockCapella()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyCapella{BlsToExecutionChanges: []*ethpb.SignedBLSToExecutionChange{c}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunBLSToExecutionChangeTest(t *testing.T, config string) {
|
||||
common.RunBLSToExecutionChangeTest(t, config, version.String(version.Capella), blockWithBlsChange, sszToState)
|
||||
}
|
||||
|
||||
@@ -1,41 +1,27 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
common "github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/common/operations"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunDepositTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "capella", "operations/deposit/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, "capella", "operations/deposit/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
depositFile, err := util.BazelFileBytes(folderPath, "deposit.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
depositSSZ, err := snappy.Decode(nil /* dst */, depositFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
deposit := ðpb.Deposit{}
|
||||
require.NoError(t, deposit.UnmarshalSSZ(depositSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyCapella{Deposits: []*ethpb.Deposit{deposit}}
|
||||
processDepositsFunc := func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
return altair.ProcessDeposits(ctx, s, b.Block().Body().Deposits())
|
||||
}
|
||||
RunBlockOperationTest(t, folderPath, body, processDepositsFunc)
|
||||
})
|
||||
func blockWithDeposit(ssz []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
d := ðpb.Deposit{}
|
||||
if err := d.UnmarshalSSZ(ssz); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := util.NewBeaconBlockCapella()
|
||||
b.Block.Body = ðpb.BeaconBlockBodyCapella{Deposits: []*ethpb.Deposit{d}}
|
||||
return blocks.NewSignedBeaconBlock(b)
|
||||
}
|
||||
|
||||
func RunDepositTest(t *testing.T, config string) {
|
||||
common.RunDepositTest(t, config, version.String(version.Capella), blockWithDeposit, altair.ProcessDeposits, sszToState)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user