Compare commits

..

2 Commits

Author SHA1 Message Date
nisdas
ef92530045 Logging 2024-11-04 13:15:42 +08:00
nisdas
7879732c55 Hack 2024-11-04 13:12:35 +08:00
75 changed files with 797 additions and 2846 deletions

View File

@@ -12,18 +12,12 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Add Bellatrix tests for light client functions.
- Add Discovery Rebooter Feature.
- Added GetBlockAttestationsV2 endpoint.
- Light client support: Consensus types for Electra.
- Light client support: Consensus types for Electra
- Added SubmitPoolAttesterSlashingV2 endpoint.
- Added SubmitAggregateAndProofsRequestV2 endpoint.
- Updated the `beacon-chain/monitor` package to Electra. [PR](https://github.com/prysmaticlabs/prysm/pull/14562)
- Added ListAttestationsV2 endpoint.
- Add ability to rollback node's internal state during processing.
- Change how unsafe protobuf state is created to prevent unnecessary copies.
- Added benchmarks for process slots for Capella, Deneb, Electra
- Add helper to cast bytes to string without allocating memory.
- Added GetAggregatedAttestationV2 endpoint.
- Added SubmitAttestationsV2 endpoint.
- Validator REST mode Electra block support
### Changed
@@ -38,22 +32,12 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Use read only validator for core processing to avoid unnecessary copying.
- Use ROBlock across block processing pipeline.
- Added missing Eth-Consensus-Version headers to GetBlockAttestationsV2 and GetAttesterSlashingsV2 endpoints.
- When instantiating new validators, explicit set `Slashed` to false and move `EffectiveBalance` to match struct definition.
- Updated pgo profile for beacon chain with holesky data. This improves the profile guided
optimizations in the go compiler.
- Use read only state when computing the active validator list.
- Simplified `ExitedValidatorIndices`.
- Simplified `EjectedValidatorIndices`.
- `engine_newPayloadV4`,`engine_getPayloadV4` are changes due to new execution request serialization decisions, [PR](https://github.com/prysmaticlabs/prysm/pull/14580)
- Fixed various small things in state-native code.
- Use ROBlock earlier in block syncing pipeline.
- Changed the signature of `ProcessPayload`.
- Only Build the Protobuf state once during serialization.
- Capella blocks are execution.
- Fixed panic when http request to subscribe to event stream fails.
- Return early for blob reconstructor during capella fork
- Updated block endpoint from V1 to V2
- Rename instances of "deposit receipts" to "deposit requests".
### Deprecated
@@ -63,7 +47,6 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Removed finalized validator index cache, no longer needed.
- Removed validator queue position log on key reload and wait for activation.
- Removed outdated spectest exclusions for EIP-6110.
### Fixed
@@ -78,8 +61,7 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Fix keymanager API so that get keys returns an empty response instead of a 500 error when using an unsupported keystore.
- Small log imporvement, removing some redundant or duplicate logs
- EIP7521 - Fixes withdrawal bug by accounting for pending partial withdrawals and deducting already withdrawn amounts from the sweep balance. [PR](https://github.com/prysmaticlabs/prysm/pull/14578)
- unskip electra merkle spec test
- Fix panic in validator REST mode when checking status after removing all keys
### Security
@@ -193,7 +175,6 @@ Updating to this release is recommended at your convenience.
- Light client support: fix light client attested header execution fields' wrong version bug.
- Testing: added custom matcher for better push settings testing.
- Registered `GetDepositSnapshot` Beacon API endpoint.
- Fix rolling back of a block due to a context deadline.
### Security

View File

@@ -93,7 +93,6 @@ func (h *EventStream) Subscribe(eventsChannel chan<- *Event) {
EventType: EventConnectionError,
Data: []byte(errors.Wrap(err, client.ErrConnectionIssue.Error()).Error()),
}
return
}
defer func() {

View File

@@ -40,7 +40,7 @@ func TestNewEventStream(t *testing.T) {
func TestEventStream(t *testing.T) {
mux := http.NewServeMux()
mux.HandleFunc("/eth/v1/events", func(w http.ResponseWriter, _ *http.Request) {
mux.HandleFunc("/eth/v1/events", func(w http.ResponseWriter, r *http.Request) {
flusher, ok := w.(http.Flusher)
require.Equal(t, true, ok)
for i := 1; i <= 3; i++ {
@@ -79,23 +79,3 @@ func TestEventStream(t *testing.T) {
}
}
}
func TestEventStreamRequestError(t *testing.T) {
topics := []string{"head"}
eventsChannel := make(chan *Event, 1)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// use valid url that will result in failed request with nil body
stream, err := NewEventStream(ctx, http.DefaultClient, "http://badhost:1234", topics)
require.NoError(t, err)
// error will happen when request is made, should be received over events channel
go stream.Subscribe(eventsChannel)
event := <-eventsChannel
if event.EventType != EventConnectionError {
t.Errorf("Expected event type %q, got %q", EventConnectionError, event.EventType)
}
}

View File

@@ -26,7 +26,7 @@ type ListAttestationsResponse struct {
}
type SubmitAttestationsRequest struct {
Data json.RawMessage `json:"data"`
Data []*Attestation `json:"data"`
}
type ListVoluntaryExitsResponse struct {

View File

@@ -7,8 +7,7 @@ import (
)
type AggregateAttestationResponse struct {
Version string `json:"version,omitempty"`
Data json.RawMessage `json:"data"`
Data *Attestation `json:"data"`
}
type SubmitContributionAndProofsRequest struct {

View File

@@ -57,21 +57,33 @@ type fcuConfig struct {
// always updates the shuffling caches and handles epoch transitions when the
// incoming block is late, preparing payload attributes in this case while it
// only sends a message with empty attributes for early blocks.
func (s *Service) sendFCU(cfg *postBlockProcessConfig, fcuArgs *fcuConfig) {
s.ForkChoicer().RLock()
defer s.ForkChoicer().RUnlock()
if err := s.getFCUArgs(cfg, fcuArgs); err != nil {
log.WithError(err).Error("Could not get forkchoice update argument")
return
}
func (s *Service) sendFCU(cfg *postBlockProcessConfig, fcuArgs *fcuConfig) error {
if !s.isNewHead(cfg.headRoot) {
return
return nil
}
if fcuArgs.attributes != nil && !fcuArgs.attributes.IsEmpty() && s.shouldOverrideFCU(cfg.headRoot, s.CurrentSlot()+1) {
return nil
}
return s.forkchoiceUpdateWithExecution(cfg.ctx, fcuArgs)
}
// sendFCUWithAttributes computes the payload attributes and sends an FCU message
// to the engine if needed
func (s *Service) sendFCUWithAttributes(cfg *postBlockProcessConfig, fcuArgs *fcuConfig) {
slotCtx, cancel := context.WithTimeout(context.Background(), slotDeadline)
defer cancel()
cfg.ctx = slotCtx
s.cfg.ForkChoiceStore.RLock()
defer s.cfg.ForkChoiceStore.RUnlock()
if err := s.computePayloadAttributes(cfg, fcuArgs); err != nil {
log.WithError(err).Error("could not compute payload attributes")
return
}
if err := s.forkchoiceUpdateWithExecution(cfg.ctx, fcuArgs); err != nil {
log.WithError(err).Warn("could not update forkchoice with the engine")
if fcuArgs.attributes.IsEmpty() {
return
}
if _, err := s.notifyForkchoiceUpdate(cfg.ctx, fcuArgs); err != nil {
log.WithError(err).Error("could not update forkchoice with payload attributes for proposal")
}
}

View File

@@ -66,6 +66,9 @@ func (s *Service) postBlockProcess(cfg *postBlockProcessConfig) error {
startTime := time.Now()
fcuArgs := &fcuConfig{}
if s.inRegularSync() {
defer s.handleSecondFCUCall(cfg, fcuArgs)
}
defer s.sendLightClientFeeds(cfg)
defer s.sendStateFeedOnBlock(cfg)
defer reportProcessingTime(startTime)
@@ -73,8 +76,6 @@ func (s *Service) postBlockProcess(cfg *postBlockProcessConfig) error {
err := s.cfg.ForkChoiceStore.InsertNode(ctx, cfg.postState, cfg.roblock)
if err != nil {
// Do not use parent context in the event it deadlined
ctx = trace.NewContext(context.Background(), span)
s.rollbackBlock(ctx, cfg.roblock.Root())
return errors.Wrapf(err, "could not insert block %d to fork choice store", cfg.roblock.Block().Slot())
}
@@ -98,9 +99,14 @@ func (s *Service) postBlockProcess(cfg *postBlockProcessConfig) error {
s.logNonCanonicalBlockReceived(cfg.roblock.Root(), cfg.headRoot)
return nil
}
if s.inRegularSync() {
go s.sendFCU(cfg, fcuArgs)
if err := s.getFCUArgs(cfg, fcuArgs); err != nil {
log.WithError(err).Error("Could not get forkchoice update argument")
return nil
}
if err := s.sendFCU(cfg, fcuArgs); err != nil {
return errors.Wrap(err, "could not send FCU to engine")
}
return nil
}

View File

@@ -40,6 +40,13 @@ func (s *Service) getFCUArgs(cfg *postBlockProcessConfig, fcuArgs *fcuConfig) er
if err := s.getFCUArgsEarlyBlock(cfg, fcuArgs); err != nil {
return err
}
if !s.inRegularSync() {
return nil
}
slot := cfg.roblock.Block().Slot()
if slots.WithinVotingWindow(uint64(s.genesisTime.Unix()), slot) {
return nil
}
return s.computePayloadAttributes(cfg, fcuArgs)
}
@@ -256,6 +263,15 @@ func (s *Service) updateCachesPostBlockProcessing(cfg *postBlockProcessConfig) e
return s.handleEpochBoundary(cfg.ctx, slot, cfg.postState, root[:])
}
// handleSecondFCUCall handles a second call to FCU when syncing a new block.
// This is useful when proposing in the next block and we want to defer the
// computation of the next slot shuffling.
func (s *Service) handleSecondFCUCall(cfg *postBlockProcessConfig, fcuArgs *fcuConfig) {
if (fcuArgs.attributes == nil || fcuArgs.attributes.IsEmpty()) && cfg.headRoot == cfg.roblock.Root() {
go s.sendFCUWithAttributes(cfg, fcuArgs)
}
}
// reportProcessingTime reports the metric of how long it took to process the
// current block
func reportProcessingTime(startTime time.Time) {

View File

@@ -1520,9 +1520,7 @@ func TestStore_NoViableHead_NewPayload(t *testing.T) {
require.NoError(t, err)
preStateVersion, preStateHeader, err := getStateVersionAndPayload(preState)
require.NoError(t, err)
rowsb, err := consensusblocks.NewROBlockWithRoot(wsb, root)
require.NoError(t, err)
_, err = service.validateExecutionOnBlock(ctx, preStateVersion, preStateHeader, rowsb)
_, err = service.validateExecutionOnBlock(ctx, preStateVersion, preStateHeader, wsb, root)
require.ErrorContains(t, "received an INVALID payload from execution engine", err)
// Check that forkchoice's head and store's headroot are the previous head (since the invalid block did
// not finish importing and it was never imported to forkchoice). Check
@@ -1716,9 +1714,7 @@ func TestStore_NoViableHead_Liveness(t *testing.T) {
require.NoError(t, err)
preStateVersion, preStateHeader, err := getStateVersionAndPayload(preState)
require.NoError(t, err)
rowsb, err := consensusblocks.NewROBlockWithRoot(wsb, root)
require.NoError(t, err)
_, err = service.validateExecutionOnBlock(ctx, preStateVersion, preStateHeader, rowsb)
_, err = service.validateExecutionOnBlock(ctx, preStateVersion, preStateHeader, wsb, root)
require.ErrorContains(t, "received an INVALID payload from execution engine", err)
// Check that forkchoice's head and store's headroot are the previous head (since the invalid block did
@@ -1968,9 +1964,7 @@ func TestNoViableHead_Reboot(t *testing.T) {
require.NoError(t, err)
preStateVersion, preStateHeader, err := getStateVersionAndPayload(preState)
require.NoError(t, err)
rowsb, err := consensusblocks.NewROBlockWithRoot(wsb, root)
require.NoError(t, err)
_, err = service.validateExecutionOnBlock(ctx, preStateVersion, preStateHeader, rowsb)
_, err = service.validateExecutionOnBlock(ctx, preStateVersion, preStateHeader, wsb, root)
require.ErrorContains(t, "received an INVALID payload from execution engine", err)
// Check that the headroot/state are not in DB and restart the node
@@ -2352,85 +2346,6 @@ func TestRollbackBlock(t *testing.T) {
require.Equal(t, false, hasState)
}
func TestRollbackBlock_ContextDeadline(t *testing.T) {
service, tr := minimalTestService(t)
ctx := tr.ctx
st, keys := util.DeterministicGenesisState(t, 64)
stateRoot, err := st.HashTreeRoot(ctx)
require.NoError(t, err, "Could not hash genesis state")
require.NoError(t, service.saveGenesisData(ctx, st))
genesis := blocks.NewGenesisBlock(stateRoot[:])
wsb, err := consensusblocks.NewSignedBeaconBlock(genesis)
require.NoError(t, err)
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb), "Could not save genesis block")
parentRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err, "Could not get signing root")
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, st, parentRoot), "Could not save genesis state")
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
require.NoError(t, service.cfg.BeaconDB.SaveJustifiedCheckpoint(ctx, &ethpb.Checkpoint{Root: parentRoot[:]}))
require.NoError(t, service.cfg.BeaconDB.SaveFinalizedCheckpoint(ctx, &ethpb.Checkpoint{Root: parentRoot[:]}))
st, err = service.HeadState(ctx)
require.NoError(t, err)
b, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 33)
require.NoError(t, err)
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
root, err := b.Block.HashTreeRoot()
require.NoError(t, err)
preState, err := service.getBlockPreState(ctx, wsb.Block())
require.NoError(t, err)
postState, err := service.validateStateTransition(ctx, preState, wsb)
require.NoError(t, err)
require.NoError(t, service.savePostStateInfo(ctx, root, wsb, postState))
roblock, err := consensusblocks.NewROBlockWithRoot(wsb, root)
require.NoError(t, err)
require.NoError(t, service.postBlockProcess(&postBlockProcessConfig{ctx, roblock, [32]byte{}, postState, false}))
b, err = util.GenerateFullBlock(postState, keys, util.DefaultBlockGenConfig(), 34)
require.NoError(t, err)
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
require.NoError(t, err)
root, err = b.Block.HashTreeRoot()
require.NoError(t, err)
preState, err = service.getBlockPreState(ctx, wsb.Block())
require.NoError(t, err)
postState, err = service.validateStateTransition(ctx, preState, wsb)
require.NoError(t, err)
require.NoError(t, service.savePostStateInfo(ctx, root, wsb, postState))
require.Equal(t, true, service.cfg.BeaconDB.HasBlock(ctx, root))
hasState, err := service.cfg.StateGen.HasState(ctx, root)
require.NoError(t, err)
require.Equal(t, true, hasState)
// Set deadlined context when processing the block
cancCtx, canc := context.WithCancel(context.Background())
canc()
roblock, err = consensusblocks.NewROBlockWithRoot(wsb, root)
require.NoError(t, err)
parentRoot = roblock.Block().ParentRoot()
cj := &ethpb.Checkpoint{}
cj.Epoch = 1
cj.Root = parentRoot[:]
require.NoError(t, postState.SetCurrentJustifiedCheckpoint(cj))
require.NoError(t, postState.SetFinalizedCheckpoint(cj))
// Rollback block insertion into db and caches.
require.ErrorContains(t, "context canceled", service.postBlockProcess(&postBlockProcessConfig{cancCtx, roblock, [32]byte{}, postState, false}))
// The block should no longer exist.
require.Equal(t, false, service.cfg.BeaconDB.HasBlock(ctx, root))
hasState, err = service.cfg.StateGen.HasState(ctx, root)
require.NoError(t, err)
require.Equal(t, false, hasState)
}
func fakeCommitments(n int) [][]byte {
f := make([][]byte, n)
for i := range f {

View File

@@ -18,7 +18,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/features"
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
consensus_blocks "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
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"
@@ -85,12 +84,7 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySig
}
currentCheckpoints := s.saveCurrentCheckpoints(preState)
roblock, err := consensus_blocks.NewROBlockWithRoot(blockCopy, blockRoot)
if err != nil {
return err
}
postState, isValidPayload, err := s.validateExecutionAndConsensus(ctx, preState, roblock)
postState, isValidPayload, err := s.validateExecutionAndConsensus(ctx, preState, blockCopy, blockRoot)
if err != nil {
return err
}
@@ -107,6 +101,10 @@ func (s *Service) ReceiveBlock(ctx context.Context, block interfaces.ReadOnlySig
if err := s.savePostStateInfo(ctx, blockRoot, blockCopy, postState); err != nil {
return errors.Wrap(err, "could not save post state info")
}
roblock, err := consensus_blocks.NewROBlockWithRoot(blockCopy, blockRoot)
if err != nil {
return err
}
args := &postBlockProcessConfig{
ctx: ctx,
roblock: roblock,
@@ -190,7 +188,8 @@ func (s *Service) updateCheckpoints(
func (s *Service) validateExecutionAndConsensus(
ctx context.Context,
preState state.BeaconState,
block consensusblocks.ROBlock,
block interfaces.SignedBeaconBlock,
blockRoot [32]byte,
) (state.BeaconState, bool, error) {
preStateVersion, preStateHeader, err := getStateVersionAndPayload(preState)
if err != nil {
@@ -209,7 +208,7 @@ func (s *Service) validateExecutionAndConsensus(
var isValidPayload bool
eg.Go(func() error {
var err error
isValidPayload, err = s.validateExecutionOnBlock(ctx, preStateVersion, preStateHeader, block)
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")
}
@@ -560,16 +559,16 @@ func (s *Service) sendBlockAttestationsToSlasher(signed interfaces.ReadOnlySigne
}
// validateExecutionOnBlock notifies the engine of the incoming block execution payload and returns true if the payload is valid
func (s *Service) validateExecutionOnBlock(ctx context.Context, ver int, header interfaces.ExecutionData, block consensusblocks.ROBlock) (bool, error) {
isValidPayload, err := s.notifyNewPayload(ctx, ver, header, block)
func (s *Service) validateExecutionOnBlock(ctx context.Context, ver int, header interfaces.ExecutionData, signed interfaces.ReadOnlySignedBeaconBlock, blockRoot [32]byte) (bool, error) {
isValidPayload, err := s.notifyNewPayload(ctx, ver, header, signed)
if err != nil {
s.cfg.ForkChoiceStore.Lock()
err = s.handleInvalidExecutionError(ctx, err, block.Root(), block.Block().ParentRoot())
err = s.handleInvalidExecutionError(ctx, err, blockRoot, signed.Block().ParentRoot())
s.cfg.ForkChoiceStore.Unlock()
return false, err
}
if block.Block().Version() < version.Capella && isValidPayload {
if err := s.validateMergeTransitionBlock(ctx, ver, header, block); err != nil {
if signed.Version() < version.Capella && isValidPayload {
if err := s.validateMergeTransitionBlock(ctx, ver, header, signed); err != nil {
return isValidPayload, err
}
}

View File

@@ -187,12 +187,11 @@ func AddValidatorToRegistry(beaconState state.BeaconState, pubKey []byte, withdr
// return Validator(
// pubkey=pubkey,
// withdrawal_credentials=withdrawal_credentials,
// effective_balance=effective_balance,
// slashed=False,
// activation_eligibility_epoch=FAR_FUTURE_EPOCH,
// activation_epoch=FAR_FUTURE_EPOCH,
// exit_epoch=FAR_FUTURE_EPOCH,
// withdrawable_epoch=FAR_FUTURE_EPOCH,
// effective_balance=effective_balance,
// )
func GetValidatorFromDeposit(pubKey []byte, withdrawalCredentials []byte, amount uint64) *ethpb.Validator {
effectiveBalance := amount - (amount % params.BeaconConfig().EffectiveBalanceIncrement)
@@ -203,11 +202,10 @@ func GetValidatorFromDeposit(pubKey []byte, withdrawalCredentials []byte, amount
return &ethpb.Validator{
PublicKey: pubKey,
WithdrawalCredentials: withdrawalCredentials,
EffectiveBalance: effectiveBalance,
Slashed: false,
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: effectiveBalance,
}
}

View File

@@ -61,9 +61,6 @@ func IsExecutionBlock(body interfaces.ReadOnlyBeaconBlockBody) (bool, error) {
if body == nil {
return false, errors.New("nil block body")
}
if body.Version() >= version.Capella {
return true, nil
}
payload, err := body.Execution()
switch {
case errors.Is(err, consensus_types.ErrUnsupportedField):
@@ -205,24 +202,24 @@ 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, body interfaces.ReadOnlyBeaconBlockBody) error {
func ProcessPayload(st state.BeaconState, body interfaces.ReadOnlyBeaconBlockBody) (state.BeaconState, error) {
payload, err := body.Execution()
if err != nil {
return err
return nil, err
}
if err := verifyBlobCommitmentCount(body); err != nil {
return err
return nil, err
}
if err := ValidatePayloadWhenMergeCompletes(st, payload); err != nil {
return err
return nil, err
}
if err := ValidatePayload(st, payload); err != nil {
return err
return nil, err
}
if err := st.SetLatestExecutionPayloadHeader(payload); err != nil {
return err
return nil, err
}
return nil
return st, nil
}
func verifyBlobCommitmentCount(body interfaces.ReadOnlyBeaconBlockBody) error {

View File

@@ -253,8 +253,7 @@ func Test_IsExecutionBlockCapella(t *testing.T) {
require.NoError(t, err)
got, err := blocks.IsExecutionBlock(wrappedBlock.Body())
require.NoError(t, err)
// #14614
require.Equal(t, true, got)
require.Equal(t, false, got)
}
func Test_IsExecutionEnabled(t *testing.T) {
@@ -588,7 +587,8 @@ func Test_ProcessPayload(t *testing.T) {
ExecutionPayload: tt.payload,
})
require.NoError(t, err)
if err := blocks.ProcessPayload(st, body); err != nil {
st, err := blocks.ProcessPayload(st, body)
if err != nil {
require.Equal(t, tt.err.Error(), err.Error())
} else {
require.Equal(t, tt.err, err)
@@ -619,7 +619,8 @@ func Test_ProcessPayloadCapella(t *testing.T) {
ExecutionPayload: payload,
})
require.NoError(t, err)
require.NoError(t, blocks.ProcessPayload(st, body))
_, err = blocks.ProcessPayload(st, body)
require.NoError(t, err)
}
func Test_ProcessPayload_Blinded(t *testing.T) {
@@ -676,7 +677,8 @@ func Test_ProcessPayload_Blinded(t *testing.T) {
ExecutionPayloadHeader: p,
})
require.NoError(t, err)
if err := blocks.ProcessPayload(st, body); err != nil {
st, err := blocks.ProcessPayload(st, body)
if err != nil {
require.Equal(t, tt.err.Error(), err.Error())
} else {
require.Equal(t, tt.err, err)

View File

@@ -193,7 +193,7 @@ func ProcessWithdrawals(st state.BeaconState, executionData interfaces.Execution
}
if st.Version() >= version.Electra {
if err := st.DequeuePendingPartialWithdrawals(processedPartialWithdrawalsCount); err != nil {
if err := st.DequeuePartialWithdrawals(processedPartialWithdrawalsCount); err != nil {
return nil, fmt.Errorf("unable to dequeue partial withdrawals from state: %w", err)
}
}

View File

@@ -508,12 +508,11 @@ func AddValidatorToRegistry(beaconState state.BeaconState, pubKey []byte, withdr
// validator = Validator(
// pubkey=pubkey,
// withdrawal_credentials=withdrawal_credentials,
// effective_balance=Gwei(0),
// slashed=False,
// activation_eligibility_epoch=FAR_FUTURE_EPOCH,
// activation_epoch=FAR_FUTURE_EPOCH,
// exit_epoch=FAR_FUTURE_EPOCH,
// withdrawable_epoch=FAR_FUTURE_EPOCH,
// effective_balance=Gwei(0),
// )
//
// # [Modified in Electra:EIP7251]
@@ -525,12 +524,11 @@ func GetValidatorFromDeposit(pubKey []byte, withdrawalCredentials []byte, amount
validator := &ethpb.Validator{
PublicKey: pubKey,
WithdrawalCredentials: withdrawalCredentials,
EffectiveBalance: 0,
Slashed: false,
ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: 0,
}
v, err := state_native.NewValidator(validator)
if err != nil {
@@ -560,7 +558,7 @@ func ProcessDepositRequests(ctx context.Context, beaconState state.BeaconState,
return beaconState, nil
}
// processDepositRequest processes the specific deposit request
// processDepositRequest processes the specific deposit receipt
// def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None:
//
// # Set deposit request start index
@@ -590,8 +588,8 @@ func processDepositRequest(beaconState state.BeaconState, request *enginev1.Depo
}
if err := beaconState.AppendPendingDeposit(&ethpb.PendingDeposit{
PublicKey: bytesutil.SafeCopyBytes(request.Pubkey),
WithdrawalCredentials: bytesutil.SafeCopyBytes(request.WithdrawalCredentials),
Amount: request.Amount,
WithdrawalCredentials: bytesutil.SafeCopyBytes(request.WithdrawalCredentials),
Signature: bytesutil.SafeCopyBytes(request.Signature),
Slot: beaconState.Slot(),
}); err != nil {

View File

@@ -29,6 +29,7 @@ var (
ProcessParticipationFlagUpdates = altair.ProcessParticipationFlagUpdates
ProcessSyncCommitteeUpdates = altair.ProcessSyncCommitteeUpdates
AttestationsDelta = altair.AttestationsDelta
ProcessSyncAggregate = altair.ProcessSyncAggregate
)
// ProcessEpoch describes the per epoch operations that are performed on the beacon state.

View File

@@ -84,11 +84,11 @@ func ProcessOperations(
}
st, err = ProcessDepositRequests(ctx, st, requests.Deposits)
if err != nil {
return nil, errors.Wrap(err, "could not process deposit requests")
return nil, errors.Wrap(err, "could not process deposit receipts")
}
st, err = ProcessWithdrawalRequests(ctx, st, requests.Withdrawals)
if err != nil {
return nil, errors.Wrap(err, "could not process withdrawal requests")
return nil, errors.Wrap(err, "could not process execution layer withdrawal requests")
}
if err := ProcessConsolidationRequests(ctx, st, requests.Consolidations); err != nil {
return nil, fmt.Errorf("could not process consolidation requests: %w", err)

View File

@@ -333,7 +333,8 @@ func ProcessBlockForStateRoot(
return nil, errors.Wrap(err, "could not process withdrawals")
}
}
if err = b.ProcessPayload(state, blk.Body()); err != nil {
state, err = b.ProcessPayload(state, blk.Body())
if err != nil {
return nil, errors.Wrap(err, "could not process execution data")
}
}

View File

@@ -698,45 +698,3 @@ func TestProcessSlotsConditionally(t *testing.T) {
assert.Equal(t, primitives.Slot(6), s.Slot())
})
}
func BenchmarkProcessSlots_Capella(b *testing.B) {
st, _ := util.DeterministicGenesisStateCapella(b, params.BeaconConfig().MaxValidatorsPerCommittee)
var err error
b.ResetTimer()
for i := 0; i < b.N; i++ {
st, err = transition.ProcessSlots(context.Background(), st, st.Slot()+1)
if err != nil {
b.Fatalf("Failed to process slot %v", err)
}
}
}
func BenchmarkProcessSlots_Deneb(b *testing.B) {
st, _ := util.DeterministicGenesisStateDeneb(b, params.BeaconConfig().MaxValidatorsPerCommittee)
var err error
b.ResetTimer()
for i := 0; i < b.N; i++ {
st, err = transition.ProcessSlots(context.Background(), st, st.Slot()+1)
if err != nil {
b.Fatalf("Failed to process slot %v", err)
}
}
}
func BenchmarkProcessSlots_Electra(b *testing.B) {
st, _ := util.DeterministicGenesisStateElectra(b, params.BeaconConfig().MaxValidatorsPerCommittee)
var err error
b.ResetTimer()
for i := 0; i < b.N; i++ {
st, err = transition.ProcessSlots(context.Background(), st, st.Slot()+1)
if err != nil {
b.Fatalf("Failed to process slot %v", err)
}
}
}

View File

@@ -18,7 +18,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing"
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time"
"github.com/prysmaticlabs/prysm/v5/time/slots"
bolt "go.etcd.io/bbolt"
@@ -140,6 +139,7 @@ func (s *Store) SaveStates(ctx context.Context, states []state.ReadOnlyBeaconSta
}
multipleEncs[i] = stateBytes
}
log.Infof("Total serialization: %s", time.Since(startTime).String())
if err := s.db.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket(stateBucket)
@@ -604,14 +604,14 @@ func (s *Store) unmarshalState(_ context.Context, enc []byte, validatorEntries [
// marshal versioned state from struct type down to bytes.
func marshalState(ctx context.Context, st state.ReadOnlyBeaconState) ([]byte, error) {
switch st.Version() {
case version.Phase0:
switch st.ToProtoUnsafe().(type) {
case *ethpb.BeaconState:
rState, ok := st.ToProtoUnsafe().(*ethpb.BeaconState)
if !ok {
return nil, errors.New("non valid inner state")
}
return encode(ctx, rState)
case version.Altair:
case *ethpb.BeaconStateAltair:
rState, ok := st.ToProtoUnsafe().(*ethpb.BeaconStateAltair)
if !ok {
return nil, errors.New("non valid inner state")
@@ -624,7 +624,7 @@ func marshalState(ctx context.Context, st state.ReadOnlyBeaconState) ([]byte, er
return nil, err
}
return snappy.Encode(nil, append(altairKey, rawObj...)), nil
case version.Bellatrix:
case *ethpb.BeaconStateBellatrix:
rState, ok := st.ToProtoUnsafe().(*ethpb.BeaconStateBellatrix)
if !ok {
return nil, errors.New("non valid inner state")
@@ -637,7 +637,7 @@ func marshalState(ctx context.Context, st state.ReadOnlyBeaconState) ([]byte, er
return nil, err
}
return snappy.Encode(nil, append(bellatrixKey, rawObj...)), nil
case version.Capella:
case *ethpb.BeaconStateCapella:
rState, ok := st.ToProtoUnsafe().(*ethpb.BeaconStateCapella)
if !ok {
return nil, errors.New("non valid inner state")
@@ -650,7 +650,7 @@ func marshalState(ctx context.Context, st state.ReadOnlyBeaconState) ([]byte, er
return nil, err
}
return snappy.Encode(nil, append(capellaKey, rawObj...)), nil
case version.Deneb:
case *ethpb.BeaconStateDeneb:
rState, ok := st.ToProtoUnsafe().(*ethpb.BeaconStateDeneb)
if !ok {
return nil, errors.New("non valid inner state")
@@ -663,7 +663,7 @@ func marshalState(ctx context.Context, st state.ReadOnlyBeaconState) ([]byte, er
return nil, err
}
return snappy.Encode(nil, append(denebKey, rawObj...)), nil
case version.Electra:
case *ethpb.BeaconStateElectra:
rState, ok := st.ToProtoUnsafe().(*ethpb.BeaconStateElectra)
if !ok {
return nil, errors.New("non valid inner state")

View File

@@ -29,7 +29,7 @@ func MsgID(genesisValidatorsRoot []byte, pmsg *pubsubpb.Message) string {
// never be hit.
msg := make([]byte, 20)
copy(msg, "invalid")
return bytesutil.UnsafeCastToString(msg)
return string(msg)
}
digest, err := ExtractGossipDigest(*pmsg.Topic)
if err != nil {
@@ -37,7 +37,7 @@ func MsgID(genesisValidatorsRoot []byte, pmsg *pubsubpb.Message) string {
// never be hit.
msg := make([]byte, 20)
copy(msg, "invalid")
return bytesutil.UnsafeCastToString(msg)
return string(msg)
}
_, fEpoch, err := forks.RetrieveForkDataFromDigest(digest, genesisValidatorsRoot)
if err != nil {
@@ -45,7 +45,7 @@ func MsgID(genesisValidatorsRoot []byte, pmsg *pubsubpb.Message) string {
// never be hit.
msg := make([]byte, 20)
copy(msg, "invalid")
return bytesutil.UnsafeCastToString(msg)
return string(msg)
}
if fEpoch >= params.BeaconConfig().AltairForkEpoch {
return postAltairMsgID(pmsg, fEpoch)
@@ -54,11 +54,11 @@ func MsgID(genesisValidatorsRoot []byte, pmsg *pubsubpb.Message) string {
if err != nil {
combinedData := append(params.BeaconConfig().MessageDomainInvalidSnappy[:], pmsg.Data...)
h := hash.Hash(combinedData)
return bytesutil.UnsafeCastToString(h[:20])
return string(h[:20])
}
combinedData := append(params.BeaconConfig().MessageDomainValidSnappy[:], decodedData...)
h := hash.Hash(combinedData)
return bytesutil.UnsafeCastToString(h[:20])
return string(h[:20])
}
// Spec:
@@ -93,13 +93,13 @@ func postAltairMsgID(pmsg *pubsubpb.Message, fEpoch primitives.Epoch) string {
// should never happen
msg := make([]byte, 20)
copy(msg, "invalid")
return bytesutil.UnsafeCastToString(msg)
return string(msg)
}
if uint64(totalLength) > gossipPubSubSize {
// this should never happen
msg := make([]byte, 20)
copy(msg, "invalid")
return bytesutil.UnsafeCastToString(msg)
return string(msg)
}
combinedData := make([]byte, 0, totalLength)
combinedData = append(combinedData, params.BeaconConfig().MessageDomainInvalidSnappy[:]...)
@@ -107,7 +107,7 @@ func postAltairMsgID(pmsg *pubsubpb.Message, fEpoch primitives.Epoch) string {
combinedData = append(combinedData, topic...)
combinedData = append(combinedData, pmsg.Data...)
h := hash.Hash(combinedData)
return bytesutil.UnsafeCastToString(h[:20])
return string(h[:20])
}
totalLength, err := math.AddInt(
len(params.BeaconConfig().MessageDomainValidSnappy),
@@ -120,7 +120,7 @@ func postAltairMsgID(pmsg *pubsubpb.Message, fEpoch primitives.Epoch) string {
// should never happen
msg := make([]byte, 20)
copy(msg, "invalid")
return bytesutil.UnsafeCastToString(msg)
return string(msg)
}
combinedData := make([]byte, 0, totalLength)
combinedData = append(combinedData, params.BeaconConfig().MessageDomainValidSnappy[:]...)
@@ -128,5 +128,5 @@ func postAltairMsgID(pmsg *pubsubpb.Message, fEpoch primitives.Epoch) string {
combinedData = append(combinedData, topic...)
combinedData = append(combinedData, decodedData...)
h := hash.Hash(combinedData)
return bytesutil.UnsafeCastToString(h[:20])
return string(h[:20])
}

View File

@@ -199,15 +199,6 @@ func (s *Service) validatorEndpoints(
handler: server.GetAggregateAttestation,
methods: []string{http.MethodGet},
},
{
template: "/eth/v2/validator/aggregate_attestation",
name: namespace + ".GetAggregateAttestationV2",
middleware: []middleware.Middleware{
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
},
handler: server.GetAggregateAttestationV2,
methods: []string{http.MethodGet},
},
{
template: "/eth/v1/validator/contribution_and_proofs",
name: namespace + ".SubmitContributionAndProofs",
@@ -610,7 +601,7 @@ func (s *Service) beaconEndpoints(
middleware: []middleware.Middleware{
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
},
handler: server.GetBlockAttestationsV2,
handler: server.GetBlockAttestations,
methods: []string{http.MethodGet},
},
{
@@ -659,16 +650,6 @@ func (s *Service) beaconEndpoints(
handler: server.SubmitAttestations,
methods: []string{http.MethodPost},
},
{
template: "/eth/v2/beacon/pool/attestations",
name: namespace + ".SubmitAttestationsV2",
middleware: []middleware.Middleware{
middleware.ContentTypeHandler([]string{api.JsonMediaType}),
middleware.AcceptHeaderHandler([]string{api.JsonMediaType}),
},
handler: server.SubmitAttestationsV2,
methods: []string{http.MethodPost},
},
{
template: "/eth/v1/beacon/pool/voluntary_exits",
name: namespace + ".ListVoluntaryExits",

View File

@@ -41,7 +41,7 @@ func Test_endpoints(t *testing.T) {
"/eth/v1/beacon/deposit_snapshot": {http.MethodGet},
"/eth/v1/beacon/blinded_blocks/{block_id}": {http.MethodGet},
"/eth/v1/beacon/pool/attestations": {http.MethodGet, http.MethodPost},
"/eth/v2/beacon/pool/attestations": {http.MethodGet, http.MethodPost},
"/eth/v2/beacon/pool/attestations": {http.MethodGet},
"/eth/v1/beacon/pool/attester_slashings": {http.MethodGet, http.MethodPost},
"/eth/v2/beacon/pool/attester_slashings": {http.MethodGet, http.MethodPost},
"/eth/v1/beacon/pool/proposer_slashings": {http.MethodGet, http.MethodPost},
@@ -101,7 +101,6 @@ func Test_endpoints(t *testing.T) {
"/eth/v1/validator/blinded_blocks/{slot}": {http.MethodGet},
"/eth/v1/validator/attestation_data": {http.MethodGet},
"/eth/v1/validator/aggregate_attestation": {http.MethodGet},
"/eth/v2/validator/aggregate_attestation": {http.MethodGet},
"/eth/v1/validator/aggregate_and_proofs": {http.MethodPost},
"/eth/v2/validator/aggregate_and_proofs": {http.MethodPost},
"/eth/v1/validator/beacon_committee_subscriptions": {http.MethodPost},

View File

@@ -3,14 +3,13 @@ package beacon
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/api"
"github.com/prysmaticlabs/prysm/v5/api/server"
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
@@ -190,180 +189,14 @@ func (s *Server) SubmitAttestations(w http.ResponseWriter, r *http.Request) {
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
return
}
attFailures, failedBroadcasts, err := s.handleAttestations(ctx, req.Data)
if err != nil {
httputil.HandleError(w, err.Error(), http.StatusBadRequest)
return
}
if len(failedBroadcasts) > 0 {
httputil.HandleError(
w,
fmt.Sprintf("Attestations at index %s could not be broadcasted", strings.Join(failedBroadcasts, ", ")),
http.StatusInternalServerError,
)
return
}
if len(attFailures) > 0 {
failuresErr := &server.IndexedVerificationFailureError{
Code: http.StatusBadRequest,
Message: "One or more attestations failed validation",
Failures: attFailures,
}
httputil.WriteError(w, failuresErr)
}
}
// SubmitAttestationsV2 submits an attestation object to node. If the attestation passes all validation
// constraints, node MUST publish the attestation on an appropriate subnet.
func (s *Server) SubmitAttestationsV2(w http.ResponseWriter, r *http.Request) {
ctx, span := trace.StartSpan(r.Context(), "beacon.SubmitAttestationsV2")
defer span.End()
versionHeader := r.Header.Get(api.VersionHeader)
if versionHeader == "" {
httputil.HandleError(w, api.VersionHeader+" header is required", http.StatusBadRequest)
return
}
v, err := version.FromString(versionHeader)
if err != nil {
httputil.HandleError(w, "Invalid version: "+err.Error(), http.StatusBadRequest)
return
}
var req structs.SubmitAttestationsRequest
err = json.NewDecoder(r.Body).Decode(&req.Data)
switch {
case errors.Is(err, io.EOF):
if len(req.Data) == 0 {
httputil.HandleError(w, "No data submitted", http.StatusBadRequest)
return
case err != nil:
httputil.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
return
}
var attFailures []*server.IndexedVerificationFailure
var failedBroadcasts []string
if v >= version.Electra {
attFailures, failedBroadcasts, err = s.handleAttestationsElectra(ctx, req.Data)
} else {
attFailures, failedBroadcasts, err = s.handleAttestations(ctx, req.Data)
}
if err != nil {
httputil.HandleError(w, fmt.Sprintf("Failed to handle attestations: %v", err), http.StatusBadRequest)
return
}
if len(failedBroadcasts) > 0 {
httputil.HandleError(
w,
fmt.Sprintf("Attestations at index %s could not be broadcasted", strings.Join(failedBroadcasts, ", ")),
http.StatusInternalServerError,
)
return
}
if len(attFailures) > 0 {
failuresErr := &server.IndexedVerificationFailureError{
Code: http.StatusBadRequest,
Message: "One or more attestations failed validation",
Failures: attFailures,
}
httputil.WriteError(w, failuresErr)
}
}
func (s *Server) handleAttestationsElectra(ctx context.Context, data json.RawMessage) (attFailures []*server.IndexedVerificationFailure, failedBroadcasts []string, err error) {
var sourceAttestations []*structs.AttestationElectra
if err = json.Unmarshal(data, &sourceAttestations); err != nil {
return nil, nil, errors.Wrap(err, "failed to unmarshal attestation")
}
if len(sourceAttestations) == 0 {
return nil, nil, errors.New("no data submitted")
}
var validAttestations []*eth.AttestationElectra
for i, sourceAtt := range sourceAttestations {
att, err := sourceAtt.ToConsensus()
if err != nil {
attFailures = append(attFailures, &server.IndexedVerificationFailure{
Index: i,
Message: "Could not convert request attestation to consensus attestation: " + err.Error(),
})
continue
}
if _, err = bls.SignatureFromBytes(att.Signature); err != nil {
attFailures = append(attFailures, &server.IndexedVerificationFailure{
Index: i,
Message: "Incorrect attestation signature: " + err.Error(),
})
continue
}
validAttestations = append(validAttestations, att)
}
for i, att := range validAttestations {
// Broadcast the unaggregated attestation on a feed to notify other services in the beacon node
// of a received unaggregated attestation.
// Note we can't send for aggregated att because we don't have selection proof.
if !corehelpers.IsAggregated(att) {
s.OperationNotifier.OperationFeed().Send(&feed.Event{
Type: operation.UnaggregatedAttReceived,
Data: &operation.UnAggregatedAttReceivedData{
Attestation: att,
},
})
}
wantedEpoch := slots.ToEpoch(att.Data.Slot)
vals, err := s.HeadFetcher.HeadValidatorsIndices(ctx, wantedEpoch)
if err != nil {
failedBroadcasts = append(failedBroadcasts, strconv.Itoa(i))
continue
}
committeeIndex, err := att.GetCommitteeIndex()
if err != nil {
return nil, nil, errors.Wrap(err, "failed to retrieve attestation committee index")
}
subnet := corehelpers.ComputeSubnetFromCommitteeAndSlot(uint64(len(vals)), committeeIndex, att.Data.Slot)
if err = s.Broadcaster.BroadcastAttestation(ctx, subnet, att); err != nil {
log.WithError(err).Errorf("could not broadcast attestation at index %d", i)
failedBroadcasts = append(failedBroadcasts, strconv.Itoa(i))
continue
}
if corehelpers.IsAggregated(att) {
if err = s.AttestationsPool.SaveAggregatedAttestation(att); err != nil {
log.WithError(err).Error("could not save aggregated attestation")
}
} else {
if err = s.AttestationsPool.SaveUnaggregatedAttestation(att); err != nil {
log.WithError(err).Error("could not save unaggregated attestation")
}
}
}
return attFailures, failedBroadcasts, nil
}
func (s *Server) handleAttestations(ctx context.Context, data json.RawMessage) (attFailures []*server.IndexedVerificationFailure, failedBroadcasts []string, err error) {
var sourceAttestations []*structs.Attestation
if err = json.Unmarshal(data, &sourceAttestations); err != nil {
return nil, nil, errors.Wrap(err, "failed to unmarshal attestation")
}
if len(sourceAttestations) == 0 {
return nil, nil, errors.New("no data submitted")
}
var validAttestations []*eth.Attestation
for i, sourceAtt := range sourceAttestations {
var attFailures []*server.IndexedVerificationFailure
for i, sourceAtt := range req.Data {
att, err := sourceAtt.ToConsensus()
if err != nil {
attFailures = append(attFailures, &server.IndexedVerificationFailure{
@@ -379,10 +212,7 @@ func (s *Server) handleAttestations(ctx context.Context, data json.RawMessage) (
})
continue
}
validAttestations = append(validAttestations, att)
}
for i, att := range validAttestations {
// Broadcast the unaggregated attestation on a feed to notify other services in the beacon node
// of a received unaggregated attestation.
// Note we can't send for aggregated att because we don't have selection proof.
@@ -395,18 +225,22 @@ func (s *Server) handleAttestations(ctx context.Context, data json.RawMessage) (
})
}
validAttestations = append(validAttestations, att)
}
failedBroadcasts := make([]string, 0)
for i, att := range validAttestations {
// Determine subnet to broadcast attestation to
wantedEpoch := slots.ToEpoch(att.Data.Slot)
vals, err := s.HeadFetcher.HeadValidatorsIndices(ctx, wantedEpoch)
if err != nil {
failedBroadcasts = append(failedBroadcasts, strconv.Itoa(i))
continue
httputil.HandleError(w, "Could not get head validator indices: "+err.Error(), http.StatusInternalServerError)
return
}
subnet := corehelpers.ComputeSubnetFromCommitteeAndSlot(uint64(len(vals)), att.Data.CommitteeIndex, att.Data.Slot)
if err = s.Broadcaster.BroadcastAttestation(ctx, subnet, att); err != nil {
log.WithError(err).Errorf("could not broadcast attestation at index %d", i)
failedBroadcasts = append(failedBroadcasts, strconv.Itoa(i))
continue
}
if corehelpers.IsAggregated(att) {
@@ -419,8 +253,23 @@ func (s *Server) handleAttestations(ctx context.Context, data json.RawMessage) (
}
}
}
if len(failedBroadcasts) > 0 {
httputil.HandleError(
w,
fmt.Sprintf("Attestations at index %s could not be broadcasted", strings.Join(failedBroadcasts, ", ")),
http.StatusInternalServerError,
)
return
}
return attFailures, failedBroadcasts, nil
if len(attFailures) > 0 {
failuresErr := &server.IndexedVerificationFailureError{
Code: http.StatusBadRequest,
Message: "One or more attestations failed validation",
Failures: attFailures,
}
httputil.WriteError(w, failuresErr)
}
}
// ListVoluntaryExits retrieves voluntary exits known by the node but

View File

@@ -500,292 +500,95 @@ func TestSubmitAttestations(t *testing.T) {
ChainInfoFetcher: chainService,
OperationNotifier: &blockchainmock.MockOperationNotifier{},
}
t.Run("V1", func(t *testing.T) {
t.Run("single", func(t *testing.T) {
broadcaster := &p2pMock.MockBroadcaster{}
s.Broadcaster = broadcaster
s.AttestationsPool = attestations.NewPool()
var body bytes.Buffer
_, err := body.WriteString(singleAtt)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
t.Run("single", func(t *testing.T) {
broadcaster := &p2pMock.MockBroadcaster{}
s.Broadcaster = broadcaster
s.AttestationsPool = attestations.NewPool()
s.SubmitAttestations(writer, request)
var body bytes.Buffer
_, err := body.WriteString(singleAtt)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
assert.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, true, broadcaster.BroadcastCalled.Load())
assert.Equal(t, 1, broadcaster.NumAttestations())
assert.Equal(t, "0x03", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetAggregationBits()))
assert.Equal(t, "0x8146f4397bfd8fd057ebbcd6a67327bdc7ed5fb650533edcb6377b650dea0b6da64c14ecd60846d5c0a0cd43893d6972092500f82c9d8a955e2b58c5ed3cbe885d84008ace6bd86ba9e23652f58e2ec207cec494c916063257abf285b9b15b15", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetSignature()))
assert.Equal(t, primitives.Slot(0), broadcaster.BroadcastAttestations[0].GetData().Slot)
assert.Equal(t, primitives.CommitteeIndex(0), broadcaster.BroadcastAttestations[0].GetData().CommitteeIndex)
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().BeaconBlockRoot))
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().Source.Root))
assert.Equal(t, primitives.Epoch(0), broadcaster.BroadcastAttestations[0].GetData().Source.Epoch)
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().Target.Root))
assert.Equal(t, primitives.Epoch(0), broadcaster.BroadcastAttestations[0].GetData().Target.Epoch)
assert.Equal(t, 1, s.AttestationsPool.UnaggregatedAttestationCount())
})
t.Run("multiple", func(t *testing.T) {
broadcaster := &p2pMock.MockBroadcaster{}
s.Broadcaster = broadcaster
s.AttestationsPool = attestations.NewPool()
var body bytes.Buffer
_, err := body.WriteString(multipleAtts)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestations(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, true, broadcaster.BroadcastCalled.Load())
assert.Equal(t, 2, broadcaster.NumAttestations())
assert.Equal(t, 2, s.AttestationsPool.UnaggregatedAttestationCount())
})
t.Run("no body", func(t *testing.T) {
request := httptest.NewRequest(http.MethodPost, "http://example.com", nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestations(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "No data submitted"))
})
t.Run("empty", func(t *testing.T) {
var body bytes.Buffer
_, err := body.WriteString("[]")
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestations(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "no data submitted"))
})
t.Run("invalid", func(t *testing.T) {
var body bytes.Buffer
_, err := body.WriteString(invalidAtt)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestations(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &server.IndexedVerificationFailureError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
require.Equal(t, 1, len(e.Failures))
assert.Equal(t, true, strings.Contains(e.Failures[0].Message, "Incorrect attestation signature"))
})
s.SubmitAttestations(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, true, broadcaster.BroadcastCalled.Load())
assert.Equal(t, 1, broadcaster.NumAttestations())
assert.Equal(t, "0x03", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetAggregationBits()))
assert.Equal(t, "0x8146f4397bfd8fd057ebbcd6a67327bdc7ed5fb650533edcb6377b650dea0b6da64c14ecd60846d5c0a0cd43893d6972092500f82c9d8a955e2b58c5ed3cbe885d84008ace6bd86ba9e23652f58e2ec207cec494c916063257abf285b9b15b15", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetSignature()))
assert.Equal(t, primitives.Slot(0), broadcaster.BroadcastAttestations[0].GetData().Slot)
assert.Equal(t, primitives.CommitteeIndex(0), broadcaster.BroadcastAttestations[0].GetData().CommitteeIndex)
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().BeaconBlockRoot))
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().Source.Root))
assert.Equal(t, primitives.Epoch(0), broadcaster.BroadcastAttestations[0].GetData().Source.Epoch)
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().Target.Root))
assert.Equal(t, primitives.Epoch(0), broadcaster.BroadcastAttestations[0].GetData().Target.Epoch)
assert.Equal(t, 1, s.AttestationsPool.UnaggregatedAttestationCount())
})
t.Run("V2", func(t *testing.T) {
t.Run("pre-electra", func(t *testing.T) {
t.Run("single", func(t *testing.T) {
broadcaster := &p2pMock.MockBroadcaster{}
s.Broadcaster = broadcaster
s.AttestationsPool = attestations.NewPool()
t.Run("multiple", func(t *testing.T) {
broadcaster := &p2pMock.MockBroadcaster{}
s.Broadcaster = broadcaster
s.AttestationsPool = attestations.NewPool()
var body bytes.Buffer
_, err := body.WriteString(singleAtt)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
request.Header.Set(api.VersionHeader, version.String(version.Phase0))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
var body bytes.Buffer
_, err := body.WriteString(multipleAtts)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestationsV2(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, true, broadcaster.BroadcastCalled.Load())
assert.Equal(t, 1, broadcaster.NumAttestations())
assert.Equal(t, "0x03", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetAggregationBits()))
assert.Equal(t, "0x8146f4397bfd8fd057ebbcd6a67327bdc7ed5fb650533edcb6377b650dea0b6da64c14ecd60846d5c0a0cd43893d6972092500f82c9d8a955e2b58c5ed3cbe885d84008ace6bd86ba9e23652f58e2ec207cec494c916063257abf285b9b15b15", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetSignature()))
assert.Equal(t, primitives.Slot(0), broadcaster.BroadcastAttestations[0].GetData().Slot)
assert.Equal(t, primitives.CommitteeIndex(0), broadcaster.BroadcastAttestations[0].GetData().CommitteeIndex)
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().BeaconBlockRoot))
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().Source.Root))
assert.Equal(t, primitives.Epoch(0), broadcaster.BroadcastAttestations[0].GetData().Source.Epoch)
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().Target.Root))
assert.Equal(t, primitives.Epoch(0), broadcaster.BroadcastAttestations[0].GetData().Target.Epoch)
assert.Equal(t, 1, s.AttestationsPool.UnaggregatedAttestationCount())
})
t.Run("multiple", func(t *testing.T) {
broadcaster := &p2pMock.MockBroadcaster{}
s.Broadcaster = broadcaster
s.AttestationsPool = attestations.NewPool()
var body bytes.Buffer
_, err := body.WriteString(multipleAtts)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
request.Header.Set(api.VersionHeader, version.String(version.Phase0))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestationsV2(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, true, broadcaster.BroadcastCalled.Load())
assert.Equal(t, 2, broadcaster.NumAttestations())
assert.Equal(t, 2, s.AttestationsPool.UnaggregatedAttestationCount())
})
t.Run("no body", func(t *testing.T) {
request := httptest.NewRequest(http.MethodPost, "http://example.com", nil)
request.Header.Set(api.VersionHeader, version.String(version.Phase0))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestationsV2(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "No data submitted"))
})
t.Run("empty", func(t *testing.T) {
var body bytes.Buffer
_, err := body.WriteString("[]")
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
request.Header.Set(api.VersionHeader, version.String(version.Phase0))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestationsV2(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "no data submitted"))
})
t.Run("invalid", func(t *testing.T) {
var body bytes.Buffer
_, err := body.WriteString(invalidAtt)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
request.Header.Set(api.VersionHeader, version.String(version.Phase0))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestationsV2(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &server.IndexedVerificationFailureError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
require.Equal(t, 1, len(e.Failures))
assert.Equal(t, true, strings.Contains(e.Failures[0].Message, "Incorrect attestation signature"))
})
})
t.Run("post-electra", func(t *testing.T) {
t.Run("single", func(t *testing.T) {
broadcaster := &p2pMock.MockBroadcaster{}
s.Broadcaster = broadcaster
s.AttestationsPool = attestations.NewPool()
var body bytes.Buffer
_, err := body.WriteString(singleAttElectra)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
request.Header.Set(api.VersionHeader, version.String(version.Electra))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestationsV2(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, true, broadcaster.BroadcastCalled.Load())
assert.Equal(t, 1, broadcaster.NumAttestations())
assert.Equal(t, "0x03", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetAggregationBits()))
assert.Equal(t, "0x8146f4397bfd8fd057ebbcd6a67327bdc7ed5fb650533edcb6377b650dea0b6da64c14ecd60846d5c0a0cd43893d6972092500f82c9d8a955e2b58c5ed3cbe885d84008ace6bd86ba9e23652f58e2ec207cec494c916063257abf285b9b15b15", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetSignature()))
assert.Equal(t, primitives.Slot(0), broadcaster.BroadcastAttestations[0].GetData().Slot)
assert.Equal(t, primitives.CommitteeIndex(0), broadcaster.BroadcastAttestations[0].GetData().CommitteeIndex)
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().BeaconBlockRoot))
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().Source.Root))
assert.Equal(t, primitives.Epoch(0), broadcaster.BroadcastAttestations[0].GetData().Source.Epoch)
assert.Equal(t, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", hexutil.Encode(broadcaster.BroadcastAttestations[0].GetData().Target.Root))
assert.Equal(t, primitives.Epoch(0), broadcaster.BroadcastAttestations[0].GetData().Target.Epoch)
assert.Equal(t, 1, s.AttestationsPool.UnaggregatedAttestationCount())
})
t.Run("multiple", func(t *testing.T) {
broadcaster := &p2pMock.MockBroadcaster{}
s.Broadcaster = broadcaster
s.AttestationsPool = attestations.NewPool()
var body bytes.Buffer
_, err := body.WriteString(multipleAttsElectra)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
request.Header.Set(api.VersionHeader, version.String(version.Electra))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestationsV2(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, true, broadcaster.BroadcastCalled.Load())
assert.Equal(t, 2, broadcaster.NumAttestations())
assert.Equal(t, 2, s.AttestationsPool.UnaggregatedAttestationCount())
})
t.Run("no body", func(t *testing.T) {
request := httptest.NewRequest(http.MethodPost, "http://example.com", nil)
request.Header.Set(api.VersionHeader, version.String(version.Electra))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestationsV2(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "No data submitted"))
})
t.Run("empty", func(t *testing.T) {
var body bytes.Buffer
_, err := body.WriteString("[]")
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
request.Header.Set(api.VersionHeader, version.String(version.Electra))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestationsV2(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "no data submitted"))
})
t.Run("invalid", func(t *testing.T) {
var body bytes.Buffer
_, err := body.WriteString(invalidAttElectra)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
request.Header.Set(api.VersionHeader, version.String(version.Electra))
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestationsV2(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &server.IndexedVerificationFailureError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
require.Equal(t, 1, len(e.Failures))
assert.Equal(t, true, strings.Contains(e.Failures[0].Message, "Incorrect attestation signature"))
})
})
s.SubmitAttestations(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
assert.Equal(t, true, broadcaster.BroadcastCalled.Load())
assert.Equal(t, 2, broadcaster.NumAttestations())
assert.Equal(t, 2, s.AttestationsPool.UnaggregatedAttestationCount())
})
t.Run("no body", func(t *testing.T) {
request := httptest.NewRequest(http.MethodPost, "http://example.com", nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestations(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "No data submitted"))
})
t.Run("empty", func(t *testing.T) {
var body bytes.Buffer
_, err := body.WriteString("[]")
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestations(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "No data submitted"))
})
t.Run("invalid", func(t *testing.T) {
var body bytes.Buffer
_, err := body.WriteString(invalidAtt)
require.NoError(t, err)
request := httptest.NewRequest(http.MethodPost, "http://example.com", &body)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.SubmitAttestations(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &server.IndexedVerificationFailureError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
require.Equal(t, 1, len(e.Failures))
assert.Equal(t, true, strings.Contains(e.Failures[0].Message, "Incorrect attestation signature"))
})
}
func TestListVoluntaryExits(t *testing.T) {
@@ -2260,85 +2063,6 @@ var (
}
}
}
]`
singleAttElectra = `[
{
"aggregation_bits": "0x03",
"committee_bits": "0x0100000000000000",
"signature": "0x8146f4397bfd8fd057ebbcd6a67327bdc7ed5fb650533edcb6377b650dea0b6da64c14ecd60846d5c0a0cd43893d6972092500f82c9d8a955e2b58c5ed3cbe885d84008ace6bd86ba9e23652f58e2ec207cec494c916063257abf285b9b15b15",
"data": {
"slot": "0",
"index": "0",
"beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"source": {
"epoch": "0",
"root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
},
"target": {
"epoch": "0",
"root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
}
}
}
]`
multipleAttsElectra = `[
{
"aggregation_bits": "0x03",
"committee_bits": "0x0100000000000000",
"signature": "0x8146f4397bfd8fd057ebbcd6a67327bdc7ed5fb650533edcb6377b650dea0b6da64c14ecd60846d5c0a0cd43893d6972092500f82c9d8a955e2b58c5ed3cbe885d84008ace6bd86ba9e23652f58e2ec207cec494c916063257abf285b9b15b15",
"data": {
"slot": "0",
"index": "0",
"beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"source": {
"epoch": "0",
"root": "0x736f75726365726f6f7431000000000000000000000000000000000000000000"
},
"target": {
"epoch": "0",
"root": "0x746172676574726f6f7431000000000000000000000000000000000000000000"
}
}
},
{
"aggregation_bits": "0x03",
"committee_bits": "0x0100000000000000",
"signature": "0x8146f4397bfd8fd057ebbcd6a67327bdc7ed5fb650533edcb6377b650dea0b6da64c14ecd60846d5c0a0cd43893d6972092500f82c9d8a955e2b58c5ed3cbe885d84008ace6bd86ba9e23652f58e2ec207cec494c916063257abf285b9b15b15",
"data": {
"slot": "0",
"index": "0",
"beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"source": {
"epoch": "0",
"root": "0x736f75726365726f6f7431000000000000000000000000000000000000000000"
},
"target": {
"epoch": "0",
"root": "0x746172676574726f6f7432000000000000000000000000000000000000000000"
}
}
}
]`
// signature is invalid
invalidAttElectra = `[
{
"aggregation_bits": "0x03",
"committee_bits": "0x0100000000000000",
"signature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"data": {
"slot": "0",
"index": "0",
"beacon_block_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"source": {
"epoch": "0",
"root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
},
"target": {
"epoch": "0",
"root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"
}
}
}
]`
exit1 = `{
"message": {

View File

@@ -40,7 +40,6 @@ go_library(
"//monitoring/tracing/trace:go_default_library",
"//network/httputil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation/aggregation/attestations:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
@@ -83,7 +82,6 @@ go_test(
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//crypto/bls/common:go_default_library",
"//encoding/bytesutil:go_default_library",
"//network/httputil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
@@ -95,7 +93,6 @@ go_test(
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
"@org_uber_go_mock//gomock:go_default_library",
],

View File

@@ -2,13 +2,11 @@ package validator
import (
"bytes"
"cmp"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"slices"
"sort"
"strconv"
"time"
@@ -34,7 +32,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace"
"github.com/prysmaticlabs/prysm/v5/network/httputil"
ethpbalpha "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation/aggregation/attestations"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"github.com/sirupsen/logrus"
@@ -51,159 +48,71 @@ func (s *Server) GetAggregateAttestation(w http.ResponseWriter, r *http.Request)
if !ok {
return
}
_, slot, ok := shared.UintFromQuery(w, r, "slot", true)
if !ok {
return
}
agg := s.aggregatedAttestation(w, primitives.Slot(slot), attDataRoot, 0)
if agg == nil {
return
}
typedAgg, ok := agg.(*ethpbalpha.Attestation)
if !ok {
httputil.HandleError(w, fmt.Sprintf("Attestation is not of type %T", &ethpbalpha.Attestation{}), http.StatusInternalServerError)
return
}
data, err := json.Marshal(structs.AttFromConsensus(typedAgg))
if err != nil {
httputil.HandleError(w, "Could not marshal attestation: "+err.Error(), http.StatusInternalServerError)
return
}
httputil.WriteJson(w, &structs.AggregateAttestationResponse{Data: data})
}
// GetAggregateAttestationV2 aggregates all attestations matching the given attestation data root and slot, returning the aggregated result.
func (s *Server) GetAggregateAttestationV2(w http.ResponseWriter, r *http.Request) {
_, span := trace.StartSpan(r.Context(), "validator.GetAggregateAttestationV2")
defer span.End()
_, attDataRoot, ok := shared.HexFromQuery(w, r, "attestation_data_root", fieldparams.RootLength, true)
if !ok {
return
}
_, slot, ok := shared.UintFromQuery(w, r, "slot", true)
if !ok {
return
}
_, index, ok := shared.UintFromQuery(w, r, "committee_index", true)
if !ok {
return
}
agg := s.aggregatedAttestation(w, primitives.Slot(slot), attDataRoot, primitives.CommitteeIndex(index))
if agg == nil {
return
}
resp := &structs.AggregateAttestationResponse{
Version: version.String(agg.Version()),
}
if agg.Version() >= version.Electra {
typedAgg, ok := agg.(*ethpbalpha.AttestationElectra)
if !ok {
httputil.HandleError(w, fmt.Sprintf("Attestation is not of type %T", &ethpbalpha.AttestationElectra{}), http.StatusInternalServerError)
return
}
data, err := json.Marshal(structs.AttElectraFromConsensus(typedAgg))
if err != nil {
httputil.HandleError(w, "Could not marshal attestation: "+err.Error(), http.StatusInternalServerError)
return
}
resp.Data = data
} else {
typedAgg, ok := agg.(*ethpbalpha.Attestation)
if !ok {
httputil.HandleError(w, fmt.Sprintf("Attestation is not of type %T", &ethpbalpha.Attestation{}), http.StatusInternalServerError)
return
}
data, err := json.Marshal(structs.AttFromConsensus(typedAgg))
if err != nil {
httputil.HandleError(w, "Could not marshal attestation: "+err.Error(), http.StatusInternalServerError)
return
}
resp.Data = data
}
httputil.WriteJson(w, resp)
}
func (s *Server) aggregatedAttestation(w http.ResponseWriter, slot primitives.Slot, attDataRoot []byte, index primitives.CommitteeIndex) ethpbalpha.Att {
var match ethpbalpha.Att
var err error
match, err := matchingAtts(s.AttestationsPool.AggregatedAttestations(), slot, attDataRoot, index)
match, err = matchingAtt(s.AttestationsPool.AggregatedAttestations(), primitives.Slot(slot), attDataRoot)
if err != nil {
httputil.HandleError(w, "Could not get matching attestations: "+err.Error(), http.StatusInternalServerError)
return nil
httputil.HandleError(w, "Could not get matching attestation: "+err.Error(), http.StatusInternalServerError)
return
}
if len(match) > 0 {
// If there are multiple matching aggregated attestations,
// then we return the one with the most aggregation bits.
slices.SortFunc(match, func(a, b ethpbalpha.Att) int {
return cmp.Compare(b.GetAggregationBits().Count(), a.GetAggregationBits().Count())
})
return match[0]
if match == nil {
atts, err := s.AttestationsPool.UnaggregatedAttestations()
if err != nil {
httputil.HandleError(w, "Could not get unaggregated attestations: "+err.Error(), http.StatusInternalServerError)
return
}
match, err = matchingAtt(atts, primitives.Slot(slot), attDataRoot)
if err != nil {
httputil.HandleError(w, "Could not get matching attestation: "+err.Error(), http.StatusInternalServerError)
return
}
}
if match == nil {
httputil.HandleError(w, "No matching attestation found", http.StatusNotFound)
return
}
atts, err := s.AttestationsPool.UnaggregatedAttestations()
if err != nil {
httputil.HandleError(w, "Could not get unaggregated attestations: "+err.Error(), http.StatusInternalServerError)
return nil
}
match, err = matchingAtts(atts, slot, attDataRoot, index)
if err != nil {
httputil.HandleError(w, "Could not get matching attestations: "+err.Error(), http.StatusInternalServerError)
return nil
}
if len(match) == 0 {
httputil.HandleError(w, "No matching attestations found", http.StatusNotFound)
return nil
}
agg, err := attestations.Aggregate(match)
if err != nil {
httputil.HandleError(w, "Could not aggregate unaggregated attestations: "+err.Error(), http.StatusInternalServerError)
return nil
}
// Aggregating unaggregated attestations will in theory always return just one aggregate,
// so we can take the first one and be done with it.
return agg[0]
response := &structs.AggregateAttestationResponse{
Data: &structs.Attestation{
AggregationBits: hexutil.Encode(match.GetAggregationBits()),
Data: &structs.AttestationData{
Slot: strconv.FormatUint(uint64(match.GetData().Slot), 10),
CommitteeIndex: strconv.FormatUint(uint64(match.GetData().CommitteeIndex), 10),
BeaconBlockRoot: hexutil.Encode(match.GetData().BeaconBlockRoot),
Source: &structs.Checkpoint{
Epoch: strconv.FormatUint(uint64(match.GetData().Source.Epoch), 10),
Root: hexutil.Encode(match.GetData().Source.Root),
},
Target: &structs.Checkpoint{
Epoch: strconv.FormatUint(uint64(match.GetData().Target.Epoch), 10),
Root: hexutil.Encode(match.GetData().Target.Root),
},
},
Signature: hexutil.Encode(match.GetSignature()),
}}
httputil.WriteJson(w, response)
}
func matchingAtts(atts []ethpbalpha.Att, slot primitives.Slot, attDataRoot []byte, index primitives.CommitteeIndex) ([]ethpbalpha.Att, error) {
if len(atts) == 0 {
return []ethpbalpha.Att{}, nil
}
postElectra := atts[0].Version() >= version.Electra
result := make([]ethpbalpha.Att, 0)
func matchingAtt(atts []ethpbalpha.Att, slot primitives.Slot, attDataRoot []byte) (ethpbalpha.Att, error) {
for _, att := range atts {
if att.GetData().Slot != slot {
continue
}
// We ignore the committee index from the request before Electra.
// This is because before Electra the committee index is part of the attestation data,
// meaning that comparing the data root is sufficient.
// Post-Electra the committee index in the data root is always 0, so we need to
// compare the committee index separately.
if postElectra {
ci, err := att.GetCommitteeIndex()
if att.GetData().Slot == slot {
root, err := att.GetData().HashTreeRoot()
if err != nil {
return nil, err
return nil, errors.Wrap(err, "could not get attestation data root")
}
if ci != index {
continue
if bytes.Equal(root[:], attDataRoot) {
return att, nil
}
}
root, err := att.GetData().HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "could not get attestation data root")
}
if bytes.Equal(root[:], attDataRoot) {
result = append(result, att)
}
}
return result, nil
return nil, nil
}
// SubmitContributionAndProofs publishes multiple signed sync committee contribution and proofs.

View File

@@ -14,7 +14,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/v5/api"
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
mockChain "github.com/prysmaticlabs/prysm/v5/beacon-chain/blockchain/testing"
@@ -36,7 +35,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
"github.com/prysmaticlabs/prysm/v5/crypto/bls/common"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/network/httputil"
ethpbalpha "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@@ -50,337 +48,292 @@ import (
func TestGetAggregateAttestation(t *testing.T) {
root1 := bytesutil.PadTo([]byte("root1"), 32)
root2 := bytesutil.PadTo([]byte("root2"), 32)
key, err := bls.RandKey()
require.NoError(t, err)
sig := key.Sign([]byte("sig"))
sig1 := bytesutil.PadTo([]byte("sig1"), fieldparams.BLSSignatureLength)
attSlot1 := &ethpbalpha.Attestation{
AggregationBits: []byte{0, 1},
Data: &ethpbalpha.AttestationData{
Slot: 1,
CommitteeIndex: 1,
BeaconBlockRoot: root1,
Source: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root1,
},
Target: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root1,
},
},
Signature: sig1,
}
root21 := bytesutil.PadTo([]byte("root2_1"), 32)
sig21 := bytesutil.PadTo([]byte("sig2_1"), fieldparams.BLSSignatureLength)
attslot21 := &ethpbalpha.Attestation{
AggregationBits: []byte{0, 1, 1},
Data: &ethpbalpha.AttestationData{
Slot: 2,
CommitteeIndex: 1,
BeaconBlockRoot: root21,
Source: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root21,
},
Target: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root21,
},
},
Signature: sig21,
}
root22 := bytesutil.PadTo([]byte("root2_2"), 32)
sig22 := bytesutil.PadTo([]byte("sig2_2"), fieldparams.BLSSignatureLength)
attslot22 := &ethpbalpha.Attestation{
AggregationBits: []byte{0, 1, 1, 1},
Data: &ethpbalpha.AttestationData{
Slot: 2,
CommitteeIndex: 1,
BeaconBlockRoot: root22,
Source: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root22,
},
Target: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root22,
},
},
Signature: sig22,
}
root31 := bytesutil.PadTo([]byte("root3_1"), 32)
sig31 := bls.NewAggregateSignature().Marshal()
attslot31 := &ethpbalpha.Attestation{
AggregationBits: []byte{1, 0},
Data: &ethpbalpha.AttestationData{
Slot: 3,
CommitteeIndex: 1,
BeaconBlockRoot: root31,
Source: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root31,
},
Target: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root31,
},
},
Signature: sig31,
}
root32 := bytesutil.PadTo([]byte("root3_2"), 32)
sig32 := bls.NewAggregateSignature().Marshal()
attslot32 := &ethpbalpha.Attestation{
AggregationBits: []byte{0, 1},
Data: &ethpbalpha.AttestationData{
Slot: 3,
CommitteeIndex: 1,
BeaconBlockRoot: root32,
Source: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root32,
},
Target: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root32,
},
},
Signature: sig32,
}
t.Run("V1", func(t *testing.T) {
createAttestation := func(slot primitives.Slot, aggregationBits bitfield.Bitlist, root []byte) *ethpbalpha.Attestation {
return &ethpbalpha.Attestation{
AggregationBits: aggregationBits,
Data: createAttestationData(slot, 1, 1, root),
Signature: sig.Marshal(),
}
}
pool := attestations.NewPool()
err := pool.SaveAggregatedAttestations([]ethpbalpha.Att{attSlot1, attslot21, attslot22})
assert.NoError(t, err)
err = pool.SaveUnaggregatedAttestations([]ethpbalpha.Att{attslot31, attslot32})
assert.NoError(t, err)
aggSlot1_Root1_1 := createAttestation(1, bitfield.Bitlist{0b11100}, root1)
aggSlot1_Root1_2 := createAttestation(1, bitfield.Bitlist{0b10111}, root1)
aggSlot1_Root2 := createAttestation(1, bitfield.Bitlist{0b11100}, root2)
aggSlot2 := createAttestation(2, bitfield.Bitlist{0b11100}, root1)
unaggSlot3_Root1_1 := createAttestation(3, bitfield.Bitlist{0b11000}, root1)
unaggSlot3_Root1_2 := createAttestation(3, bitfield.Bitlist{0b10100}, root1)
unaggSlot3_Root2 := createAttestation(3, bitfield.Bitlist{0b11000}, root2)
unaggSlot4 := createAttestation(4, bitfield.Bitlist{0b11000}, root1)
s := &Server{
AttestationsPool: pool,
}
compareResult := func(
t *testing.T,
attestation structs.Attestation,
expectedSlot string,
expectedAggregationBits string,
expectedRoot []byte,
expectedSig []byte,
) {
assert.Equal(t, expectedAggregationBits, attestation.AggregationBits, "Unexpected aggregation bits in attestation")
assert.Equal(t, hexutil.Encode(expectedSig), attestation.Signature, "Signature mismatch")
assert.Equal(t, expectedSlot, attestation.Data.Slot, "Slot mismatch in attestation data")
assert.Equal(t, "1", attestation.Data.CommitteeIndex, "Committee index mismatch")
assert.Equal(t, hexutil.Encode(expectedRoot), attestation.Data.BeaconBlockRoot, "Beacon block root mismatch")
// Source checkpoint checks
require.NotNil(t, attestation.Data.Source, "Source checkpoint should not be nil")
assert.Equal(t, "1", attestation.Data.Source.Epoch, "Source epoch mismatch")
assert.Equal(t, hexutil.Encode(expectedRoot), attestation.Data.Source.Root, "Source root mismatch")
// Target checkpoint checks
require.NotNil(t, attestation.Data.Target, "Target checkpoint should not be nil")
assert.Equal(t, "1", attestation.Data.Target.Epoch, "Target epoch mismatch")
assert.Equal(t, hexutil.Encode(expectedRoot), attestation.Data.Target.Root, "Target root mismatch")
}
pool := attestations.NewPool()
require.NoError(t, pool.SaveUnaggregatedAttestations([]ethpbalpha.Att{unaggSlot3_Root1_1, unaggSlot3_Root1_2, unaggSlot3_Root2, unaggSlot4}), "Failed to save unaggregated attestations")
unagg, err := pool.UnaggregatedAttestations()
t.Run("matching aggregated att", func(t *testing.T) {
reqRoot, err := attslot22.Data.HashTreeRoot()
require.NoError(t, err)
require.Equal(t, 4, len(unagg), "Expected 4 unaggregated attestations")
require.NoError(t, pool.SaveAggregatedAttestations([]ethpbalpha.Att{aggSlot1_Root1_1, aggSlot1_Root1_2, aggSlot1_Root2, aggSlot2}), "Failed to save aggregated attestations")
agg := pool.AggregatedAttestations()
require.Equal(t, 4, len(agg), "Expected 4 aggregated attestations")
s := &Server{
AttestationsPool: pool,
}
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=2"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
t.Run("non-matching attestation request", func(t *testing.T) {
reqRoot, err := aggSlot2.Data.HashTreeRoot()
require.NoError(t, err, "Failed to generate attestation data hash tree root")
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=1"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
s.GetAggregateAttestation(writer, request)
assert.Equal(t, http.StatusNotFound, writer.Code, "Expected HTTP status NotFound for non-matching request")
})
t.Run("1 matching aggregated attestation", func(t *testing.T) {
reqRoot, err := aggSlot2.Data.HashTreeRoot()
require.NoError(t, err, "Failed to generate attestation data hash tree root")
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=2"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
s.GetAggregateAttestation(writer, request)
require.Equal(t, http.StatusOK, writer.Code, "Expected HTTP status OK")
var resp structs.AggregateAttestationResponse
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp), "Failed to unmarshal response")
require.NotNil(t, resp.Data, "Response data should not be nil")
var attestation structs.Attestation
require.NoError(t, json.Unmarshal(resp.Data, &attestation), "Failed to unmarshal attestation data")
compareResult(t, attestation, "2", hexutil.Encode(aggSlot2.AggregationBits), root1, sig.Marshal())
})
t.Run("multiple matching aggregated attestations - return the one with most bits", func(t *testing.T) {
reqRoot, err := aggSlot1_Root1_1.Data.HashTreeRoot()
require.NoError(t, err, "Failed to generate attestation data hash tree root")
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=1"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
s.GetAggregateAttestation(writer, request)
require.Equal(t, http.StatusOK, writer.Code, "Expected HTTP status OK")
var resp structs.AggregateAttestationResponse
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp), "Failed to unmarshal response")
require.NotNil(t, resp.Data, "Response data should not be nil")
var attestation structs.Attestation
require.NoError(t, json.Unmarshal(resp.Data, &attestation), "Failed to unmarshal attestation data")
compareResult(t, attestation, "1", hexutil.Encode(aggSlot1_Root1_2.AggregationBits), root1, sig.Marshal())
})
t.Run("1 matching unaggregated attestation", func(t *testing.T) {
reqRoot, err := unaggSlot4.Data.HashTreeRoot()
require.NoError(t, err, "Failed to generate attestation data hash tree root")
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=4"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
s.GetAggregateAttestation(writer, request)
require.Equal(t, http.StatusOK, writer.Code, "Expected HTTP status OK")
var resp structs.AggregateAttestationResponse
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp), "Failed to unmarshal response")
require.NotNil(t, resp.Data, "Response data should not be nil")
var attestation structs.Attestation
require.NoError(t, json.Unmarshal(resp.Data, &attestation), "Failed to unmarshal attestation data")
compareResult(t, attestation, "4", hexutil.Encode(unaggSlot4.AggregationBits), root1, sig.Marshal())
})
t.Run("multiple matching unaggregated attestations - their aggregate is returned", func(t *testing.T) {
reqRoot, err := unaggSlot3_Root1_1.Data.HashTreeRoot()
require.NoError(t, err, "Failed to generate attestation data hash tree root")
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=3"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
s.GetAggregateAttestation(writer, request)
require.Equal(t, http.StatusOK, writer.Code, "Expected HTTP status OK")
var resp structs.AggregateAttestationResponse
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp), "Failed to unmarshal response")
require.NotNil(t, resp.Data, "Response data should not be nil")
var attestation structs.Attestation
require.NoError(t, json.Unmarshal(resp.Data, &attestation), "Failed to unmarshal attestation data")
sig1, err := bls.SignatureFromBytes(unaggSlot3_Root1_1.Signature)
require.NoError(t, err)
sig2, err := bls.SignatureFromBytes(unaggSlot3_Root1_2.Signature)
require.NoError(t, err)
expectedSig := bls.AggregateSignatures([]common.Signature{sig1, sig2})
compareResult(t, attestation, "3", hexutil.Encode(bitfield.Bitlist{0b11100}), root1, expectedSig.Marshal())
})
s.GetAggregateAttestation(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
resp := &structs.AggregateAttestationResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.NotNil(t, resp)
require.NotNil(t, resp.Data)
assert.DeepEqual(t, "0x00010101", resp.Data.AggregationBits)
assert.DeepEqual(t, hexutil.Encode(sig22), resp.Data.Signature)
assert.Equal(t, "2", resp.Data.Data.Slot)
assert.Equal(t, "1", resp.Data.Data.CommitteeIndex)
assert.DeepEqual(t, hexutil.Encode(root22), resp.Data.Data.BeaconBlockRoot)
require.NotNil(t, resp.Data.Data.Source)
assert.Equal(t, "1", resp.Data.Data.Source.Epoch)
assert.DeepEqual(t, hexutil.Encode(root22), resp.Data.Data.Source.Root)
require.NotNil(t, resp.Data.Data.Target)
assert.Equal(t, "1", resp.Data.Data.Target.Epoch)
assert.DeepEqual(t, hexutil.Encode(root22), resp.Data.Data.Target.Root)
})
t.Run("V2", func(t *testing.T) {
createAttestation := func(slot primitives.Slot, aggregationBits bitfield.Bitlist, root []byte, bits uint64) *ethpbalpha.AttestationElectra {
committeeBits := bitfield.NewBitvector64()
committeeBits.SetBitAt(bits, true)
return &ethpbalpha.AttestationElectra{
CommitteeBits: committeeBits,
AggregationBits: aggregationBits,
Data: createAttestationData(slot, 0, 1, root),
Signature: sig.Marshal(),
}
}
aggSlot1_Root1_1 := createAttestation(1, bitfield.Bitlist{0b11100}, root1, 1)
aggSlot1_Root1_2 := createAttestation(1, bitfield.Bitlist{0b10111}, root1, 1)
aggSlot1_Root2 := createAttestation(1, bitfield.Bitlist{0b11100}, root2, 1)
aggSlot2 := createAttestation(2, bitfield.Bitlist{0b11100}, root1, 1)
unaggSlot3_Root1_1 := createAttestation(3, bitfield.Bitlist{0b11000}, root1, 1)
unaggSlot3_Root1_2 := createAttestation(3, bitfield.Bitlist{0b10100}, root1, 1)
unaggSlot3_Root2 := createAttestation(3, bitfield.Bitlist{0b11000}, root2, 1)
unaggSlot4 := createAttestation(4, bitfield.Bitlist{0b11000}, root1, 1)
compareResult := func(
t *testing.T,
attestation structs.AttestationElectra,
expectedSlot string,
expectedAggregationBits string,
expectedRoot []byte,
expectedSig []byte,
expectedCommitteeBits string,
) {
assert.Equal(t, expectedAggregationBits, attestation.AggregationBits, "Unexpected aggregation bits in attestation")
assert.Equal(t, expectedCommitteeBits, attestation.CommitteeBits)
assert.Equal(t, hexutil.Encode(expectedSig), attestation.Signature, "Signature mismatch")
assert.Equal(t, expectedSlot, attestation.Data.Slot, "Slot mismatch in attestation data")
assert.Equal(t, "0", attestation.Data.CommitteeIndex, "Committee index mismatch")
assert.Equal(t, hexutil.Encode(expectedRoot), attestation.Data.BeaconBlockRoot, "Beacon block root mismatch")
// Source checkpoint checks
require.NotNil(t, attestation.Data.Source, "Source checkpoint should not be nil")
assert.Equal(t, "1", attestation.Data.Source.Epoch, "Source epoch mismatch")
assert.Equal(t, hexutil.Encode(expectedRoot), attestation.Data.Source.Root, "Source root mismatch")
// Target checkpoint checks
require.NotNil(t, attestation.Data.Target, "Target checkpoint should not be nil")
assert.Equal(t, "1", attestation.Data.Target.Epoch, "Target epoch mismatch")
assert.Equal(t, hexutil.Encode(expectedRoot), attestation.Data.Target.Root, "Target root mismatch")
}
pool := attestations.NewPool()
require.NoError(t, pool.SaveUnaggregatedAttestations([]ethpbalpha.Att{unaggSlot3_Root1_1, unaggSlot3_Root1_2, unaggSlot3_Root2, unaggSlot4}), "Failed to save unaggregated attestations")
unagg, err := pool.UnaggregatedAttestations()
t.Run("matching unaggregated att", func(t *testing.T) {
reqRoot, err := attslot32.Data.HashTreeRoot()
require.NoError(t, err)
require.Equal(t, 4, len(unagg), "Expected 4 unaggregated attestations")
require.NoError(t, pool.SaveAggregatedAttestations([]ethpbalpha.Att{aggSlot1_Root1_1, aggSlot1_Root1_2, aggSlot1_Root2, aggSlot2}), "Failed to save aggregated attestations")
agg := pool.AggregatedAttestations()
require.Equal(t, 4, len(agg), "Expected 4 aggregated attestations")
s := &Server{
AttestationsPool: pool,
}
t.Run("non-matching attestation request", func(t *testing.T) {
reqRoot, err := aggSlot2.Data.HashTreeRoot()
require.NoError(t, err, "Failed to generate attestation data hash tree root")
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=1" + "&committee_index=1"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=3"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetAggregateAttestationV2(writer, request)
assert.Equal(t, http.StatusNotFound, writer.Code, "Expected HTTP status NotFound for non-matching request")
})
t.Run("1 matching aggregated attestation", func(t *testing.T) {
reqRoot, err := aggSlot2.Data.HashTreeRoot()
require.NoError(t, err, "Failed to generate attestation data hash tree root")
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=2" + "&committee_index=1"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
s.GetAggregateAttestation(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
resp := &structs.AggregateAttestationResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.NotNil(t, resp)
require.NotNil(t, resp.Data)
assert.DeepEqual(t, "0x0001", resp.Data.AggregationBits)
assert.DeepEqual(t, hexutil.Encode(sig32), resp.Data.Signature)
assert.Equal(t, "3", resp.Data.Data.Slot)
assert.Equal(t, "1", resp.Data.Data.CommitteeIndex)
assert.DeepEqual(t, hexutil.Encode(root32), resp.Data.Data.BeaconBlockRoot)
require.NotNil(t, resp.Data.Data.Source)
assert.Equal(t, "1", resp.Data.Data.Source.Epoch)
assert.DeepEqual(t, hexutil.Encode(root32), resp.Data.Data.Source.Root)
require.NotNil(t, resp.Data.Data.Target)
assert.Equal(t, "1", resp.Data.Data.Target.Epoch)
assert.DeepEqual(t, hexutil.Encode(root32), resp.Data.Data.Target.Root)
})
t.Run("no matching attestation", func(t *testing.T) {
attDataRoot := hexutil.Encode(bytesutil.PadTo([]byte("foo"), 32))
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=2"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetAggregateAttestationV2(writer, request)
require.Equal(t, http.StatusOK, writer.Code, "Expected HTTP status OK")
s.GetAggregateAttestation(writer, request)
assert.Equal(t, http.StatusNotFound, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusNotFound, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "No matching attestation found"))
})
t.Run("no attestation_data_root provided", func(t *testing.T) {
url := "http://example.com?slot=2"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
var resp structs.AggregateAttestationResponse
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp), "Failed to unmarshal response")
require.NotNil(t, resp.Data, "Response data should not be nil")
s.GetAggregateAttestation(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "attestation_data_root is required"))
})
t.Run("invalid attestation_data_root provided", func(t *testing.T) {
url := "http://example.com?attestation_data_root=foo&slot=2"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
var attestation structs.AttestationElectra
require.NoError(t, json.Unmarshal(resp.Data, &attestation), "Failed to unmarshal attestation data")
s.GetAggregateAttestation(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "attestation_data_root is invalid"))
})
t.Run("no slot provided", func(t *testing.T) {
attDataRoot := hexutil.Encode(bytesutil.PadTo([]byte("foo"), 32))
url := "http://example.com?attestation_data_root=" + attDataRoot
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
compareResult(t, attestation, "2", hexutil.Encode(aggSlot2.AggregationBits), root1, sig.Marshal(), hexutil.Encode(aggSlot2.CommitteeBits))
})
t.Run("multiple matching aggregated attestations - return the one with most bits", func(t *testing.T) {
reqRoot, err := aggSlot1_Root1_1.Data.HashTreeRoot()
require.NoError(t, err, "Failed to generate attestation data hash tree root")
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=1" + "&committee_index=1"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
s.GetAggregateAttestation(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "slot is required"))
})
t.Run("invalid slot provided", func(t *testing.T) {
attDataRoot := hexutil.Encode(bytesutil.PadTo([]byte("foo"), 32))
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=foo"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetAggregateAttestationV2(writer, request)
require.Equal(t, http.StatusOK, writer.Code, "Expected HTTP status OK")
var resp structs.AggregateAttestationResponse
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp), "Failed to unmarshal response")
require.NotNil(t, resp.Data, "Response data should not be nil")
var attestation structs.AttestationElectra
require.NoError(t, json.Unmarshal(resp.Data, &attestation), "Failed to unmarshal attestation data")
compareResult(t, attestation, "1", hexutil.Encode(aggSlot1_Root1_2.AggregationBits), root1, sig.Marshal(), hexutil.Encode(aggSlot1_Root1_1.CommitteeBits))
})
t.Run("1 matching unaggregated attestation", func(t *testing.T) {
reqRoot, err := unaggSlot4.Data.HashTreeRoot()
require.NoError(t, err, "Failed to generate attestation data hash tree root")
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=4" + "&committee_index=1"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
s.GetAggregateAttestationV2(writer, request)
require.Equal(t, http.StatusOK, writer.Code, "Expected HTTP status OK")
var resp structs.AggregateAttestationResponse
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp), "Failed to unmarshal response")
require.NotNil(t, resp.Data, "Response data should not be nil")
var attestation structs.AttestationElectra
require.NoError(t, json.Unmarshal(resp.Data, &attestation), "Failed to unmarshal attestation data")
compareResult(t, attestation, "4", hexutil.Encode(unaggSlot4.AggregationBits), root1, sig.Marshal(), hexutil.Encode(unaggSlot4.CommitteeBits))
})
t.Run("multiple matching unaggregated attestations - their aggregate is returned", func(t *testing.T) {
reqRoot, err := unaggSlot3_Root1_1.Data.HashTreeRoot()
require.NoError(t, err, "Failed to generate attestation data hash tree root")
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=3" + "&committee_index=1"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
s.GetAggregateAttestationV2(writer, request)
require.Equal(t, http.StatusOK, writer.Code, "Expected HTTP status OK")
var resp structs.AggregateAttestationResponse
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp), "Failed to unmarshal response")
require.NotNil(t, resp.Data, "Response data should not be nil")
var attestation structs.AttestationElectra
require.NoError(t, json.Unmarshal(resp.Data, &attestation), "Failed to unmarshal attestation data")
sig1, err := bls.SignatureFromBytes(unaggSlot3_Root1_1.Signature)
require.NoError(t, err)
sig2, err := bls.SignatureFromBytes(unaggSlot3_Root1_2.Signature)
require.NoError(t, err)
expectedSig := bls.AggregateSignatures([]common.Signature{sig1, sig2})
compareResult(t, attestation, "3", hexutil.Encode(bitfield.Bitlist{0b11100}), root1, expectedSig.Marshal(), hexutil.Encode(unaggSlot3_Root1_1.CommitteeBits))
})
s.GetAggregateAttestation(writer, request)
assert.Equal(t, http.StatusBadRequest, writer.Code)
e := &httputil.DefaultJsonError{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), e))
assert.Equal(t, http.StatusBadRequest, e.Code)
assert.Equal(t, true, strings.Contains(e.Message, "slot is invalid"))
})
}
func createAttestationData(
slot primitives.Slot,
committeeIndex primitives.CommitteeIndex,
epoch primitives.Epoch,
root []byte,
) *ethpbalpha.AttestationData {
return &ethpbalpha.AttestationData{
Slot: slot,
CommitteeIndex: committeeIndex,
BeaconBlockRoot: root,
Source: &ethpbalpha.Checkpoint{
Epoch: epoch,
Root: root,
},
Target: &ethpbalpha.Checkpoint{
Epoch: epoch,
Root: root,
func TestGetAggregateAttestation_SameSlotAndRoot_ReturnMostAggregationBits(t *testing.T) {
root := bytesutil.PadTo([]byte("root"), 32)
sig := bytesutil.PadTo([]byte("sig"), fieldparams.BLSSignatureLength)
att1 := &ethpbalpha.Attestation{
AggregationBits: []byte{3, 0, 0, 1},
Data: &ethpbalpha.AttestationData{
Slot: 1,
CommitteeIndex: 1,
BeaconBlockRoot: root,
Source: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root,
},
Target: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root,
},
},
Signature: sig,
}
att2 := &ethpbalpha.Attestation{
AggregationBits: []byte{0, 3, 0, 1},
Data: &ethpbalpha.AttestationData{
Slot: 1,
CommitteeIndex: 1,
BeaconBlockRoot: root,
Source: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root,
},
Target: &ethpbalpha.Checkpoint{
Epoch: 1,
Root: root,
},
},
Signature: sig,
}
pool := attestations.NewPool()
err := pool.SaveAggregatedAttestations([]ethpbalpha.Att{att1, att2})
assert.NoError(t, err)
s := &Server{
AttestationsPool: pool,
}
reqRoot, err := att1.Data.HashTreeRoot()
require.NoError(t, err)
attDataRoot := hexutil.Encode(reqRoot[:])
url := "http://example.com?attestation_data_root=" + attDataRoot + "&slot=1"
request := httptest.NewRequest(http.MethodGet, url, nil)
writer := httptest.NewRecorder()
writer.Body = &bytes.Buffer{}
s.GetAggregateAttestation(writer, request)
assert.Equal(t, http.StatusOK, writer.Code)
resp := &structs.AggregateAttestationResponse{}
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), resp))
require.NotNil(t, resp)
assert.DeepEqual(t, "0x03000001", resp.Data.AggregationBits)
}
func TestSubmitContributionAndProofs(t *testing.T) {

View File

@@ -287,9 +287,6 @@ func (vs *Server) validatorStatus(
Status: ethpb.ValidatorStatus_UNKNOWN_STATUS,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
}
if len(pubKey) == 0 {
return resp, nonExistentIndex
}
vStatus, idx, err := statusForPubKey(headState, pubKey)
if err != nil && !errors.Is(err, errPubkeyDoesNotExist) {
tracing.AnnotateError(span, err)

View File

@@ -316,7 +316,7 @@ type WriteOnlySyncCommittee interface {
type WriteOnlyWithdrawals interface {
AppendPendingPartialWithdrawal(ppw *ethpb.PendingPartialWithdrawal) error
DequeuePendingPartialWithdrawals(num uint64) error
DequeuePartialWithdrawals(num uint64) error
SetNextWithdrawalIndex(i uint64) error
SetNextWithdrawalValidatorIndex(i primitives.ValidatorIndex) error
}

View File

@@ -82,6 +82,7 @@ go_library(
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
],
)

View File

@@ -29,6 +29,7 @@ type BeaconState struct {
stateRoots customtypes.StateRoots
stateRootsMultiValue *MultiValueStateRoots
historicalRoots customtypes.HistoricalRoots
historicalSummaries []*ethpb.HistoricalSummary
eth1Data *ethpb.Eth1Data
eth1DataVotes []*ethpb.Eth1Data
eth1DepositIndex uint64
@@ -54,11 +55,8 @@ type BeaconState struct {
latestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader
latestExecutionPayloadHeaderCapella *enginev1.ExecutionPayloadHeaderCapella
latestExecutionPayloadHeaderDeneb *enginev1.ExecutionPayloadHeaderDeneb
// Capella fields
nextWithdrawalIndex uint64
nextWithdrawalValidatorIndex primitives.ValidatorIndex
historicalSummaries []*ethpb.HistoricalSummary
nextWithdrawalIndex uint64
nextWithdrawalValidatorIndex primitives.ValidatorIndex
// Electra fields
depositRequestsStartIndex uint64
@@ -92,6 +90,7 @@ type beaconStateMarshalable struct {
BlockRoots customtypes.BlockRoots `json:"block_roots" yaml:"block_roots"`
StateRoots customtypes.StateRoots `json:"state_roots" yaml:"state_roots"`
HistoricalRoots customtypes.HistoricalRoots `json:"historical_roots" yaml:"historical_roots"`
HistoricalSummaries []*ethpb.HistoricalSummary `json:"historical_summaries" yaml:"historical_summaries"`
Eth1Data *ethpb.Eth1Data `json:"eth_1_data" yaml:"eth_1_data"`
Eth1DataVotes []*ethpb.Eth1Data `json:"eth_1_data_votes" yaml:"eth_1_data_votes"`
Eth1DepositIndex uint64 `json:"eth_1_deposit_index" yaml:"eth_1_deposit_index"`
@@ -115,7 +114,6 @@ type beaconStateMarshalable struct {
LatestExecutionPayloadHeaderDeneb *enginev1.ExecutionPayloadHeaderDeneb `json:"latest_execution_payload_header_deneb" yaml:"latest_execution_payload_header_deneb"`
NextWithdrawalIndex uint64 `json:"next_withdrawal_index" yaml:"next_withdrawal_index"`
NextWithdrawalValidatorIndex primitives.ValidatorIndex `json:"next_withdrawal_validator_index" yaml:"next_withdrawal_validator_index"`
HistoricalSummaries []*ethpb.HistoricalSummary `json:"historical_summaries" yaml:"historical_summaries"`
DepositRequestsStartIndex uint64 `json:"deposit_requests_start_index" yaml:"deposit_requests_start_index"`
DepositBalanceToConsume primitives.Gwei `json:"deposit_balance_to_consume" yaml:"deposit_balance_to_consume"`
ExitBalanceToConsume primitives.Gwei `json:"exit_balance_to_consume" yaml:"exit_balance_to_consume"`
@@ -161,6 +159,7 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
BlockRoots: bRoots,
StateRoots: sRoots,
HistoricalRoots: b.historicalRoots,
HistoricalSummaries: b.historicalSummaries,
Eth1Data: b.eth1Data,
Eth1DataVotes: b.eth1DataVotes,
Eth1DepositIndex: b.eth1DepositIndex,
@@ -184,7 +183,6 @@ func (b *BeaconState) MarshalJSON() ([]byte, error) {
LatestExecutionPayloadHeaderDeneb: b.latestExecutionPayloadHeaderDeneb,
NextWithdrawalIndex: b.nextWithdrawalIndex,
NextWithdrawalValidatorIndex: b.nextWithdrawalValidatorIndex,
HistoricalSummaries: b.historicalSummaries,
DepositRequestsStartIndex: b.depositRequestsStartIndex,
DepositBalanceToConsume: b.depositBalanceToConsume,
ExitBalanceToConsume: b.exitBalanceToConsume,

View File

@@ -4,7 +4,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/runtime/version"
)
// DepositRequestsStartIndex is used for returning the deposit requests start index which is used for eip6110
// DepositRequestsStartIndex is used for returning the deposit receipts start index which is used for eip6110
func (b *BeaconState) DepositRequestsStartIndex() (uint64, error) {
if b.version < version.Electra {
return 0, errNotSupported("DepositRequestsStartIndex", b.version)

View File

@@ -1,12 +1,15 @@
package state_native
import (
"time"
"github.com/pkg/errors"
customtypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/custom-types"
"github.com/prysmaticlabs/prysm/v5/config/features"
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
log "github.com/sirupsen/logrus"
)
// ToProtoUnsafe returns the pointer value of the underlying
@@ -15,29 +18,22 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
if b == nil {
return nil
}
startTime := time.Now()
gvrCopy := b.genesisValidatorsRoot
br := b.blockRootsVal().Slice()
sr := b.stateRootsVal().Slice()
rm := b.randaoMixesVal().Slice()
log.Infof("Generated slices for state in %s", time.Since(startTime).String())
var vals []*ethpb.Validator
var bals []uint64
var inactivityScores []uint64
if features.Get().EnableExperimentalState {
if b.balancesMultiValue != nil {
bals = b.balancesMultiValue.Value(b)
}
if b.inactivityScoresMultiValue != nil {
inactivityScores = b.inactivityScoresMultiValue.Value(b)
}
if b.validatorsMultiValue != nil {
vals = b.validatorsMultiValue.Value(b)
}
vals = b.validatorsVal()
log.Infof("Generated validators for state in %s", time.Since(startTime).String())
bals = b.balancesVal()
log.Infof("Generated balances for state in %s", time.Since(startTime).String())
} else {
bals = b.balances
inactivityScores = b.inactivityScores
vals = b.validators
bals = b.balances
}
switch b.version {
@@ -88,7 +84,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: inactivityScores,
InactivityScores: b.inactivityScoresVal(),
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
}
@@ -115,7 +111,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: inactivityScores,
InactivityScores: b.inactivityScoresVal(),
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeader,
@@ -143,7 +139,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: inactivityScores,
InactivityScores: b.inactivityScoresVal(),
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderCapella,
@@ -152,6 +148,9 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
HistoricalSummaries: b.historicalSummaries,
}
case version.Deneb:
defer func() {
log.Infof("Generated roots and inactivitu scores for state in %s", time.Since(startTime).String())
}()
return &ethpb.BeaconStateDeneb{
GenesisTime: b.genesisTime,
GenesisValidatorsRoot: gvrCopy[:],
@@ -174,7 +173,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: inactivityScores,
InactivityScores: b.inactivityScoresVal(),
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderDeneb,
@@ -205,7 +204,7 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
FinalizedCheckpoint: b.finalizedCheckpoint,
InactivityScores: inactivityScores,
InactivityScores: b.inactivityScoresVal(),
CurrentSyncCommittee: b.currentSyncCommittee,
NextSyncCommittee: b.nextSyncCommittee,
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderDeneb,

View File

@@ -1,8 +1,6 @@
package state_native
import (
"errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
@@ -17,9 +15,6 @@ func (b *BeaconState) AppendPendingConsolidation(val *ethpb.PendingConsolidation
if b.version < version.Electra {
return errNotSupported("AppendPendingConsolidation", b.version)
}
if val == nil {
return errors.New("cannot append nil pending consolidation")
}
b.lock.Lock()
defer b.lock.Unlock()

View File

@@ -1,8 +1,6 @@
package state_native
import (
"errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native/types"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
@@ -17,9 +15,6 @@ func (b *BeaconState) AppendPendingDeposit(pd *ethpb.PendingDeposit) error {
if b.version < version.Electra {
return errNotSupported("AppendPendingDeposit", b.version)
}
if pd == nil {
return errors.New("cannot append nil pending deposit")
}
b.lock.Lock()
defer b.lock.Unlock()

View File

@@ -64,10 +64,10 @@ func (b *BeaconState) AppendPendingPartialWithdrawal(ppw *eth.PendingPartialWith
return nil
}
// DequeuePendingPartialWithdrawals removes the partial withdrawals from the beginning of the partial withdrawals list.
func (b *BeaconState) DequeuePendingPartialWithdrawals(n uint64) error {
// DequeuePartialWithdrawals removes the partial withdrawals from the beginning of the partial withdrawals list.
func (b *BeaconState) DequeuePartialWithdrawals(n uint64) error {
if b.version < version.Electra {
return errNotSupported("DequeuePendingPartialWithdrawals", b.version)
return errNotSupported("DequeuePartialWithdrawals", b.version)
}
if n > uint64(len(b.pendingPartialWithdrawals)) {

View File

@@ -68,7 +68,7 @@ func TestDequeuePendingWithdrawals(t *testing.T) {
num, err := s.NumPendingPartialWithdrawals()
require.NoError(t, err)
require.Equal(t, uint64(3), num)
require.NoError(t, s.DequeuePendingPartialWithdrawals(2))
require.NoError(t, s.DequeuePartialWithdrawals(2))
num, err = s.NumPendingPartialWithdrawals()
require.NoError(t, err)
require.Equal(t, uint64(1), num)
@@ -77,13 +77,13 @@ func TestDequeuePendingWithdrawals(t *testing.T) {
num, err = s.NumPendingPartialWithdrawals()
require.NoError(t, err)
require.Equal(t, uint64(1), num)
require.ErrorContains(t, "cannot dequeue more withdrawals than are in the queue", s.DequeuePendingPartialWithdrawals(2))
require.ErrorContains(t, "cannot dequeue more withdrawals than are in the queue", s.DequeuePartialWithdrawals(2))
// Removing all pending partial withdrawals should be OK.
num, err = s.NumPendingPartialWithdrawals()
require.NoError(t, err)
require.Equal(t, uint64(1), num)
require.NoError(t, s.DequeuePendingPartialWithdrawals(1))
require.NoError(t, s.DequeuePartialWithdrawals(1))
num, err = s.Copy().NumPendingPartialWithdrawals()
require.NoError(t, err)
require.Equal(t, uint64(0), num)
@@ -91,7 +91,7 @@ func TestDequeuePendingWithdrawals(t *testing.T) {
s, err = InitializeFromProtoDeneb(&eth.BeaconStateDeneb{})
require.NoError(t, err)
require.ErrorContains(t, "is not supported", s.DequeuePendingPartialWithdrawals(0))
require.ErrorContains(t, "is not supported", s.DequeuePartialWithdrawals(0))
}
func TestAppendPendingWithdrawals(t *testing.T) {

View File

@@ -14,7 +14,7 @@ func (b *BeaconState) ProportionalSlashingMultiplier() (uint64, error) {
case version.Phase0:
return params.BeaconConfig().ProportionalSlashingMultiplier, nil
}
return 0, errNotSupported("ProportionalSlashingMultiplier", b.version)
return 0, errNotSupported("ProportionalSlashingMultiplier()", b.version)
}
func (b *BeaconState) InactivityPenaltyQuotient() (uint64, error) {
@@ -26,5 +26,5 @@ func (b *BeaconState) InactivityPenaltyQuotient() (uint64, error) {
case version.Phase0:
return params.BeaconConfig().InactivityPenaltyQuotient, nil
}
return 0, errNotSupported("InactivityPenaltyQuotient", b.version)
return 0, errNotSupported("InactivityPenaltyQuotient()", b.version)
}

View File

@@ -96,10 +96,10 @@ var denebFields = append(
var electraFields = append(
altairFields,
types.LatestExecutionPayloadHeaderDeneb,
types.NextWithdrawalIndex,
types.NextWithdrawalValidatorIndex,
types.HistoricalSummaries,
types.LatestExecutionPayloadHeaderDeneb,
types.DepositRequestsStartIndex,
types.DepositBalanceToConsume,
types.ExitBalanceToConsume,

View File

@@ -44,7 +44,7 @@ func (s *State) MigrateToCold(ctx context.Context, fRoot [32]byte) error {
return ctx.Err()
}
if slot%s.slotsPerArchivedPoint == 0 && slot != 0 {
if slot%128 == 0 && slot != 0 {
cached, exists, err := s.epochBoundaryStateCache.getBySlot(slot)
if err != nil {
return fmt.Errorf("could not get epoch boundary state for slot %d", slot)

View File

@@ -12,7 +12,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/io/file"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/time/slots"
"google.golang.org/protobuf/proto"
)
@@ -63,10 +62,6 @@ func (s *Service) beaconBlockSubscriber(ctx context.Context, msg proto.Message)
// This function reconstructs the blob sidecars from the EL using the block's KZG commitments,
// broadcasts the reconstructed blobs over P2P, and saves them into the blob storage.
func (s *Service) reconstructAndBroadcastBlobs(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock) {
if block.Version() < version.Deneb {
return
}
startTime, err := slots.ToTime(uint64(s.cfg.chain.GenesisTime().Unix()), block.Block().Slot())
if err != nil {
log.WithError(err).Error("Failed to convert slot to time")

View File

@@ -3,7 +3,6 @@ package bytesutil
import (
"fmt"
"unsafe"
"github.com/ethereum/go-ethereum/common/hexutil"
)
@@ -146,10 +145,3 @@ func ReverseByteOrder(input []byte) []byte {
}
return b
}
// UnsafeCastToString casts a byte slice to a string object without performing a copy. Changes
// to byteSlice will also modify the contents of the string, so it is the caller's responsibility
// to ensure that the byte slice will not modified after the string is created.
func UnsafeCastToString(byteSlice []byte) string {
return *(*string)(unsafe.Pointer(&byteSlice)) // #nosec G103
}

View File

@@ -217,50 +217,6 @@ func TestToBytes20(t *testing.T) {
}
}
func TestCastToString(t *testing.T) {
bSlice := []byte{'a', 'b', 'c'}
bString := bytesutil.UnsafeCastToString(bSlice)
originalString := "abc"
// Mutate original slice to make sure that a copy was not performed.
bSlice[0] = 'd'
assert.NotEqual(t, originalString, bString)
assert.Equal(t, "dbc", bString)
}
func BenchmarkUnsafeCastToString(b *testing.B) {
data := []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
empty := []byte{}
var nilData []byte
b.Run("string(b)", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = string(data)
_ = string(empty)
_ = string(nilData)
}
})
b.Run("bytesutil.UnsafeCastToString(b)", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = bytesutil.UnsafeCastToString(data)
_ = bytesutil.UnsafeCastToString(empty)
_ = bytesutil.UnsafeCastToString(nilData)
}
})
}
func FuzzUnsafeCastToString(f *testing.F) {
f.Fuzz(func(t *testing.T, input []byte) {
want := string(input)
result := bytesutil.UnsafeCastToString(input)
if result != want {
t.Fatalf("input (%v) result (%s) did not match expected (%s)", input, result, want)
}
})
}
func BenchmarkToBytes32(b *testing.B) {
x := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}
for i := 0; i < b.N; i++ {

View File

@@ -141,7 +141,7 @@ func WithdrawalSliceRoot(withdrawals []*enginev1.Withdrawal, limit uint64) ([32]
return MixInLength(bytesRoot, bytesRootBufRoot), nil
}
// DepositRequestsSliceRoot computes the HTR of a slice of deposit requests.
// DepositRequestsSliceRoot computes the HTR of a slice of deposit receipts.
// The limit parameter is used as input to the bitwise merkleization algorithm.
func DepositRequestsSliceRoot(depositRequests []*enginev1.DepositRequest, limit uint64) ([32]byte, error) {
return SliceRoot(depositRequests, limit)

View File

@@ -24,6 +24,179 @@ tests/general/phase0/ssz_generic/boolean
tests/general/phase0/ssz_generic/containers
tests/general/phase0/ssz_generic/uints
# EIP6110
tests/mainnet/eip6110/epoch_processing/effective_balance_updates
tests/mainnet/eip6110/epoch_processing/eth1_data_reset
tests/mainnet/eip6110/epoch_processing/historical_summaries_update
tests/mainnet/eip6110/epoch_processing/inactivity_updates
tests/mainnet/eip6110/epoch_processing/justification_and_finalization
tests/mainnet/eip6110/epoch_processing/participation_flag_updates
tests/mainnet/eip6110/epoch_processing/randao_mixes_reset
tests/mainnet/eip6110/epoch_processing/registry_updates
tests/mainnet/eip6110/epoch_processing/rewards_and_penalties
tests/mainnet/eip6110/epoch_processing/slashings
tests/mainnet/eip6110/epoch_processing/slashings_reset
tests/mainnet/eip6110/finality/finality
tests/mainnet/eip6110/fork_choice/ex_ante
tests/mainnet/eip6110/fork_choice/get_head
tests/mainnet/eip6110/fork_choice/get_proposer_head
tests/mainnet/eip6110/fork_choice/on_block
tests/mainnet/eip6110/fork_choice/should_override_forkchoice_update
tests/mainnet/eip6110/operations/attestation
tests/mainnet/eip6110/operations/attester_slashing
tests/mainnet/eip6110/operations/block_header
tests/mainnet/eip6110/operations/bls_to_execution_change
tests/mainnet/eip6110/operations/deposit
tests/mainnet/eip6110/operations/execution_payload
tests/mainnet/eip6110/operations/proposer_slashing
tests/mainnet/eip6110/operations/sync_aggregate
tests/mainnet/eip6110/operations/voluntary_exit
tests/mainnet/eip6110/operations/withdrawals
tests/mainnet/eip6110/rewards/basic
tests/mainnet/eip6110/rewards/leak
tests/mainnet/eip6110/rewards/random
tests/mainnet/eip6110/sanity/blocks
tests/mainnet/eip6110/sanity/slots
tests/mainnet/eip6110/ssz_static/AggregateAndProof
tests/mainnet/eip6110/ssz_static/Attestation
tests/mainnet/eip6110/ssz_static/AttestationData
tests/mainnet/eip6110/ssz_static/AttesterSlashing
tests/mainnet/eip6110/ssz_static/BLSToExecutionChange
tests/mainnet/eip6110/ssz_static/BeaconBlock
tests/mainnet/eip6110/ssz_static/BeaconBlockBody
tests/mainnet/eip6110/ssz_static/BeaconBlockHeader
tests/mainnet/eip6110/ssz_static/BeaconState
tests/mainnet/eip6110/ssz_static/BlobIdentifier
tests/mainnet/eip6110/ssz_static/BlobSidecar
tests/mainnet/eip6110/ssz_static/Checkpoint
tests/mainnet/eip6110/ssz_static/ContributionAndProof
tests/mainnet/eip6110/ssz_static/Deposit
tests/mainnet/eip6110/ssz_static/DepositData
tests/mainnet/eip6110/ssz_static/DepositMessage
tests/mainnet/eip6110/ssz_static/DepositReceipt
tests/mainnet/eip6110/ssz_static/Eth1Block
tests/mainnet/eip6110/ssz_static/Eth1Data
tests/mainnet/eip6110/ssz_static/ExecutionPayload
tests/mainnet/eip6110/ssz_static/ExecutionPayloadHeader
tests/mainnet/eip6110/ssz_static/Fork
tests/mainnet/eip6110/ssz_static/ForkData
tests/mainnet/eip6110/ssz_static/HistoricalBatch
tests/mainnet/eip6110/ssz_static/HistoricalSummary
tests/mainnet/eip6110/ssz_static/IndexedAttestation
tests/mainnet/eip6110/ssz_static/LightClientBootstrap
tests/mainnet/eip6110/ssz_static/LightClientFinalityUpdate
tests/mainnet/eip6110/ssz_static/LightClientHeader
tests/mainnet/eip6110/ssz_static/LightClientOptimisticUpdate
tests/mainnet/eip6110/ssz_static/LightClientUpdate
tests/mainnet/eip6110/ssz_static/PendingAttestation
tests/mainnet/eip6110/ssz_static/PowBlock
tests/mainnet/eip6110/ssz_static/ProposerSlashing
tests/mainnet/eip6110/ssz_static/SignedAggregateAndProof
tests/mainnet/eip6110/ssz_static/SignedBLSToExecutionChange
tests/mainnet/eip6110/ssz_static/SignedBeaconBlock
tests/mainnet/eip6110/ssz_static/SignedBeaconBlockHeader
tests/mainnet/eip6110/ssz_static/SignedContributionAndProof
tests/mainnet/eip6110/ssz_static/SignedVoluntaryExit
tests/mainnet/eip6110/ssz_static/SigningData
tests/mainnet/eip6110/ssz_static/SyncAggregate
tests/mainnet/eip6110/ssz_static/SyncAggregatorSelectionData
tests/mainnet/eip6110/ssz_static/SyncCommittee
tests/mainnet/eip6110/ssz_static/SyncCommitteeContribution
tests/mainnet/eip6110/ssz_static/SyncCommitteeMessage
tests/mainnet/eip6110/ssz_static/Validator
tests/mainnet/eip6110/ssz_static/VoluntaryExit
tests/mainnet/eip6110/ssz_static/Withdrawal
tests/mainnet/eip6110/sync/optimistic
tests/mainnet/eip6110/transition/core
tests/minimal/eip6110/epoch_processing/effective_balance_updates
tests/minimal/eip6110/epoch_processing/eth1_data_reset
tests/minimal/eip6110/epoch_processing/historical_summaries_update
tests/minimal/eip6110/epoch_processing/inactivity_updates
tests/minimal/eip6110/epoch_processing/justification_and_finalization
tests/minimal/eip6110/epoch_processing/participation_flag_updates
tests/minimal/eip6110/epoch_processing/randao_mixes_reset
tests/minimal/eip6110/epoch_processing/registry_updates
tests/minimal/eip6110/epoch_processing/rewards_and_penalties
tests/minimal/eip6110/epoch_processing/slashings
tests/minimal/eip6110/epoch_processing/slashings_reset
tests/minimal/eip6110/epoch_processing/sync_committee_updates
tests/minimal/eip6110/finality/finality
tests/minimal/eip6110/fork_choice/ex_ante
tests/minimal/eip6110/fork_choice/get_head
tests/minimal/eip6110/fork_choice/get_proposer_head
tests/minimal/eip6110/fork_choice/on_block
tests/minimal/eip6110/fork_choice/reorg
tests/minimal/eip6110/fork_choice/should_override_forkchoice_update
tests/minimal/eip6110/fork_choice/withholding
tests/minimal/eip6110/genesis/initialization
tests/minimal/eip6110/genesis/validity
tests/minimal/eip6110/operations/attestation
tests/minimal/eip6110/operations/attester_slashing
tests/minimal/eip6110/operations/block_header
tests/minimal/eip6110/operations/bls_to_execution_change
tests/minimal/eip6110/operations/deposit
tests/minimal/eip6110/operations/execution_payload
tests/minimal/eip6110/operations/proposer_slashing
tests/minimal/eip6110/operations/sync_aggregate
tests/minimal/eip6110/operations/voluntary_exit
tests/minimal/eip6110/operations/withdrawals
tests/minimal/eip6110/rewards/basic
tests/minimal/eip6110/rewards/leak
tests/minimal/eip6110/rewards/random
tests/minimal/eip6110/sanity/blocks
tests/minimal/eip6110/sanity/slots
tests/minimal/eip6110/ssz_static/AggregateAndProof
tests/minimal/eip6110/ssz_static/Attestation
tests/minimal/eip6110/ssz_static/AttestationData
tests/minimal/eip6110/ssz_static/AttesterSlashing
tests/minimal/eip6110/ssz_static/BLSToExecutionChange
tests/minimal/eip6110/ssz_static/BeaconBlock
tests/minimal/eip6110/ssz_static/BeaconBlockBody
tests/minimal/eip6110/ssz_static/BeaconBlockHeader
tests/minimal/eip6110/ssz_static/BeaconState
tests/minimal/eip6110/ssz_static/BlobIdentifier
tests/minimal/eip6110/ssz_static/BlobSidecar
tests/minimal/eip6110/ssz_static/Checkpoint
tests/minimal/eip6110/ssz_static/ContributionAndProof
tests/minimal/eip6110/ssz_static/Deposit
tests/minimal/eip6110/ssz_static/DepositData
tests/minimal/eip6110/ssz_static/DepositMessage
tests/minimal/eip6110/ssz_static/DepositReceipt
tests/minimal/eip6110/ssz_static/Eth1Block
tests/minimal/eip6110/ssz_static/Eth1Data
tests/minimal/eip6110/ssz_static/ExecutionPayload
tests/minimal/eip6110/ssz_static/ExecutionPayloadHeader
tests/minimal/eip6110/ssz_static/Fork
tests/minimal/eip6110/ssz_static/ForkData
tests/minimal/eip6110/ssz_static/HistoricalBatch
tests/minimal/eip6110/ssz_static/HistoricalSummary
tests/minimal/eip6110/ssz_static/IndexedAttestation
tests/minimal/eip6110/ssz_static/LightClientBootstrap
tests/minimal/eip6110/ssz_static/LightClientFinalityUpdate
tests/minimal/eip6110/ssz_static/LightClientHeader
tests/minimal/eip6110/ssz_static/LightClientOptimisticUpdate
tests/minimal/eip6110/ssz_static/LightClientUpdate
tests/minimal/eip6110/ssz_static/PendingAttestation
tests/minimal/eip6110/ssz_static/PowBlock
tests/minimal/eip6110/ssz_static/ProposerSlashing
tests/minimal/eip6110/ssz_static/SignedAggregateAndProof
tests/minimal/eip6110/ssz_static/SignedBLSToExecutionChange
tests/minimal/eip6110/ssz_static/SignedBeaconBlock
tests/minimal/eip6110/ssz_static/SignedBeaconBlockHeader
tests/minimal/eip6110/ssz_static/SignedContributionAndProof
tests/minimal/eip6110/ssz_static/SignedVoluntaryExit
tests/minimal/eip6110/ssz_static/SigningData
tests/minimal/eip6110/ssz_static/SyncAggregate
tests/minimal/eip6110/ssz_static/SyncAggregatorSelectionData
tests/minimal/eip6110/ssz_static/SyncCommittee
tests/minimal/eip6110/ssz_static/SyncCommitteeContribution
tests/minimal/eip6110/ssz_static/SyncCommitteeMessage
tests/minimal/eip6110/ssz_static/Validator
tests/minimal/eip6110/ssz_static/VoluntaryExit
tests/minimal/eip6110/ssz_static/Withdrawal
tests/minimal/eip6110/sync/optimistic
tests/minimal/eip6110/transition/core
# Whisk
tests/mainnet/whisk/ssz_static/AggregateAndProof
tests/mainnet/whisk/ssz_static/Attestation

View File

@@ -7,5 +7,6 @@ import (
)
func TestMainnet_Electra_MerkleProof(t *testing.T) {
t.Skip("TODO: Electra") // These spectests are missing?
merkle_proof.RunMerkleProofTests(t, "mainnet")
}

View File

@@ -7,5 +7,6 @@ import (
)
func TestMinimal_Electra_MerkleProof(t *testing.T) {
t.Skip("TODO: Electra") // These spectests are missing?
merkle_proof.RunMerkleProofTests(t, "minimal")
}

View File

@@ -56,10 +56,10 @@ func RunBlockHeaderTest(t *testing.T, config string, fork string, sszToBlock SSZ
bodyRoot, err := block.Block().Body().HashTreeRoot()
require.NoError(t, err)
pr := block.Block().ParentRoot()
_, err = blocks.ProcessBlockHeaderNoVerify(context.Background(), preBeaconState, block.Block().Slot(), block.Block().ProposerIndex(), pr[:], bodyRoot[:])
beaconState, err := blocks.ProcessBlockHeaderNoVerify(context.Background(), preBeaconState, block.Block().Slot(), block.Block().ProposerIndex(), pr[:], bodyRoot[:])
if postSSZExists {
require.NoError(t, err)
comparePostState(t, postSSZFilepath, sszToState, preBeaconState)
comparePostState(t, postSSZFilepath, sszToState, preBeaconState, beaconState)
} else {
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.

View File

@@ -54,10 +54,10 @@ func RunExecutionPayloadTest(t *testing.T, config string, fork string, sszToBloc
config := &ExecutionConfig{}
require.NoError(t, utils.UnmarshalYaml(file, config), "Failed to Unmarshal")
err = blocks.ProcessPayload(preBeaconState, body)
gotState, err := blocks.ProcessPayload(preBeaconState, body)
if postSSZExists {
require.NoError(t, err)
comparePostState(t, postSSZFilepath, sszToState, preBeaconState)
comparePostState(t, postSSZFilepath, sszToState, preBeaconState, gotState)
} else if config.Valid {
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.

View File

@@ -50,10 +50,10 @@ func RunBlockOperationTest(
}
helpers.ClearCache()
_, err = operationFn(context.Background(), preState, wsb)
beaconState, err := operationFn(context.Background(), preState, wsb)
if postSSZExists {
require.NoError(t, err)
comparePostState(t, postSSZFilepath, sszToState, preState)
comparePostState(t, postSSZFilepath, sszToState, preState, beaconState)
} else {
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
@@ -65,7 +65,7 @@ func RunBlockOperationTest(
}
}
func comparePostState(t *testing.T, postSSZFilepath string, sszToState SSZToState, want state.BeaconState) {
func comparePostState(t *testing.T, postSSZFilepath string, sszToState SSZToState, want state.BeaconState, got state.BeaconState) {
postBeaconStateFile, err := os.ReadFile(postSSZFilepath) // #nosec G304
require.NoError(t, err)
postBeaconStateSSZ, err := snappy.Decode(nil /* dst */, postBeaconStateFile)

View File

@@ -97,10 +97,8 @@ go_test(
"propose_beacon_block_blinded_bellatrix_test.go",
"propose_beacon_block_blinded_capella_test.go",
"propose_beacon_block_blinded_deneb_test.go",
"propose_beacon_block_blinded_electra_test.go",
"propose_beacon_block_capella_test.go",
"propose_beacon_block_deneb_test.go",
"propose_beacon_block_electra_test.go",
"propose_beacon_block_phase0_test.go",
"propose_beacon_block_test.go",
"propose_exit_test.go",

View File

@@ -139,7 +139,7 @@ func TestBeaconApiValidatorClient_ProposeBeaconBlockValid(t *testing.T) {
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blocks",
"/eth/v1/beacon/blocks",
map[string]string{"Eth-Consensus-Version": "phase0"},
gomock.Any(),
nil,
@@ -175,7 +175,7 @@ func TestBeaconApiValidatorClient_ProposeBeaconBlockError(t *testing.T) {
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blocks",
"/eth/v1/beacon/blocks",
map[string]string{"Eth-Consensus-Version": "phase0"},
gomock.Any(),
nil,

View File

@@ -69,14 +69,8 @@ func (c *beaconApiValidatorClient) beaconBlock(ctx context.Context, slot primiti
blinded = produceBlockV3ResponseJson.ExecutionPayloadBlinded
decoder = json.NewDecoder(bytes.NewReader(produceBlockV3ResponseJson.Data))
}
return processBlockResponse(ver, blinded, decoder)
}
func processBlockResponse(ver string, isBlinded bool, decoder *json.Decoder) (*ethpb.GenericBeaconBlock, error) {
var response *ethpb.GenericBeaconBlock
if decoder == nil {
return nil, errors.New("no produce block json decoder found")
}
switch ver {
case version.String(version.Phase0):
jsonPhase0Block := structs.BeaconBlock{}
@@ -99,7 +93,7 @@ func processBlockResponse(ver string, isBlinded bool, decoder *json.Decoder) (*e
}
response = genericBlock
case version.String(version.Bellatrix):
if isBlinded {
if blinded {
jsonBellatrixBlock := structs.BlindedBeaconBlockBellatrix{}
if err := decoder.Decode(&jsonBellatrixBlock); err != nil {
return nil, errors.Wrap(err, "failed to decode blinded bellatrix block response json")
@@ -121,7 +115,7 @@ func processBlockResponse(ver string, isBlinded bool, decoder *json.Decoder) (*e
response = genericBlock
}
case version.String(version.Capella):
if isBlinded {
if blinded {
jsonCapellaBlock := structs.BlindedBeaconBlockCapella{}
if err := decoder.Decode(&jsonCapellaBlock); err != nil {
return nil, errors.Wrap(err, "failed to decode blinded capella block response json")
@@ -143,7 +137,7 @@ func processBlockResponse(ver string, isBlinded bool, decoder *json.Decoder) (*e
response = genericBlock
}
case version.String(version.Deneb):
if isBlinded {
if blinded {
jsonDenebBlock := structs.BlindedBeaconBlockDeneb{}
if err := decoder.Decode(&jsonDenebBlock); err != nil {
return nil, errors.Wrap(err, "failed to decode blinded deneb block response json")
@@ -164,28 +158,6 @@ func processBlockResponse(ver string, isBlinded bool, decoder *json.Decoder) (*e
}
response = genericBlock
}
case version.String(version.Electra):
if isBlinded {
jsonElectraBlock := structs.BlindedBeaconBlockElectra{}
if err := decoder.Decode(&jsonElectraBlock); err != nil {
return nil, errors.Wrap(err, "failed to decode blinded electra block response json")
}
genericBlock, err := jsonElectraBlock.ToGeneric()
if err != nil {
return nil, errors.Wrap(err, "failed to get blinded electra block")
}
response = genericBlock
} else {
jsonElectraBlockContents := structs.BeaconBlockContentsElectra{}
if err := decoder.Decode(&jsonElectraBlockContents); err != nil {
return nil, errors.Wrap(err, "failed to decode electra block response json")
}
genericBlock, err := jsonElectraBlockContents.ToGeneric()
if err != nil {
return nil, errors.Wrap(err, "failed to get electra block")
}
response = genericBlock
}
default:
return nil, errors.Errorf("unsupported consensus version `%s`", ver)
}

View File

@@ -500,96 +500,6 @@ func TestGetBeaconBlock_BlindedDenebValid(t *testing.T) {
assert.DeepEqual(t, expectedBeaconBlock, beaconBlock)
}
func TestGetBeaconBlock_ElectraValid(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
proto := testhelpers.GenerateProtoElectraBeaconBlockContents()
block := testhelpers.GenerateJsonElectraBeaconBlockContents()
bytes, err := json.Marshal(block)
require.NoError(t, err)
const slot = primitives.Slot(1)
randaoReveal := []byte{2}
graffiti := []byte{3}
ctx := context.Background()
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
jsonRestHandler.EXPECT().Get(
gomock.Any(),
fmt.Sprintf("/eth/v3/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)),
&structs.ProduceBlockV3Response{},
).SetArg(
2,
structs.ProduceBlockV3Response{
Version: "electra",
ExecutionPayloadBlinded: false,
Data: bytes,
},
).Return(
nil,
).Times(1)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
beaconBlock, err := validatorClient.beaconBlock(ctx, slot, randaoReveal, graffiti)
require.NoError(t, err)
expectedBeaconBlock := &ethpb.GenericBeaconBlock{
Block: &ethpb.GenericBeaconBlock_Electra{
Electra: proto,
},
IsBlinded: false,
}
assert.DeepEqual(t, expectedBeaconBlock, beaconBlock)
}
func TestGetBeaconBlock_BlindedElectraValid(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
proto := testhelpers.GenerateProtoBlindedElectraBeaconBlock()
block := testhelpers.GenerateJsonBlindedElectraBeaconBlock()
bytes, err := json.Marshal(block)
require.NoError(t, err)
const slot = primitives.Slot(1)
randaoReveal := []byte{2}
graffiti := []byte{3}
ctx := context.Background()
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
jsonRestHandler.EXPECT().Get(
gomock.Any(),
fmt.Sprintf("/eth/v3/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)),
&structs.ProduceBlockV3Response{},
).SetArg(
2,
structs.ProduceBlockV3Response{
Version: "electra",
ExecutionPayloadBlinded: true,
Data: bytes,
},
).Return(
nil,
).Times(1)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
beaconBlock, err := validatorClient.beaconBlock(ctx, slot, randaoReveal, graffiti)
require.NoError(t, err)
expectedBeaconBlock := &ethpb.GenericBeaconBlock{
Block: &ethpb.GenericBeaconBlock_BlindedElectra{
BlindedElectra: proto,
},
IsBlinded: true,
}
assert.DeepEqual(t, expectedBeaconBlock, beaconBlock)
}
func TestGetBeaconBlock_FallbackToBlindedBlock(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

View File

@@ -120,35 +120,6 @@ func (c *beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *e
if err != nil {
return nil, errors.Wrap(err, "failed to marshal blinded deneb beacon block contents")
}
case *ethpb.GenericSignedBeaconBlock_Electra:
consensusVersion = "electra"
beaconBlockRoot, err = blockType.Electra.Block.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "failed to compute block root for electra beacon block")
}
signedBlock, err := structs.SignedBeaconBlockContentsElectraFromConsensus(blockType.Electra)
if err != nil {
return nil, errors.Wrap(err, "failed to convert electra beacon block contents")
}
marshalledSignedBeaconBlockJson, err = json.Marshal(signedBlock)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal electra beacon block contents")
}
case *ethpb.GenericSignedBeaconBlock_BlindedElectra:
blinded = true
consensusVersion = "electra"
beaconBlockRoot, err = blockType.BlindedElectra.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "failed to compute block root for blinded electra beacon block")
}
signedBlock, err := structs.SignedBlindedBeaconBlockElectraFromConsensus(blockType.BlindedElectra)
if err != nil {
return nil, errors.Wrap(err, "failed to convert blinded electra beacon block contents")
}
marshalledSignedBeaconBlockJson, err = json.Marshal(signedBlock)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal blinded electra beacon block contents")
}
default:
return nil, errors.Errorf("unsupported block type %T", in.Block)
}
@@ -156,9 +127,9 @@ func (c *beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *e
var endpoint string
if blinded {
endpoint = "/eth/v2/beacon/blinded_blocks"
endpoint = "/eth/v1/beacon/blinded_blocks"
} else {
endpoint = "/eth/v2/beacon/blocks"
endpoint = "/eth/v1/beacon/blocks"
}
headers := map[string]string{"Eth-Consensus-Version": consensusVersion}

View File

@@ -59,7 +59,7 @@ func TestProposeBeaconBlock_Altair(t *testing.T) {
headers := map[string]string{"Eth-Consensus-Version": "altair"}
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blocks",
"/eth/v1/beacon/blocks",
headers,
bytes.NewBuffer(marshalledBlock),
nil,

View File

@@ -76,7 +76,7 @@ func TestProposeBeaconBlock_Bellatrix(t *testing.T) {
headers := map[string]string{"Eth-Consensus-Version": "bellatrix"}
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blocks",
"/eth/v1/beacon/blocks",
headers,
bytes.NewBuffer(marshalledBlock),
nil,

View File

@@ -77,7 +77,7 @@ func TestProposeBeaconBlock_BlindedBellatrix(t *testing.T) {
headers := map[string]string{"Eth-Consensus-Version": "bellatrix"}
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blinded_blocks",
"/eth/v1/beacon/blinded_blocks",
headers,
bytes.NewBuffer(marshalledBlock),
nil,

View File

@@ -79,7 +79,7 @@ func TestProposeBeaconBlock_BlindedCapella(t *testing.T) {
headers := map[string]string{"Eth-Consensus-Version": "capella"}
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blinded_blocks",
"/eth/v1/beacon/blinded_blocks",
headers,
bytes.NewBuffer(marshalledBlock),
nil,

View File

@@ -15,6 +15,7 @@ import (
)
func TestProposeBeaconBlock_BlindedDeneb(t *testing.T) {
t.Skip("TODO: Fix this in the beacon-API PR")
ctrl := gomock.NewController(t)
defer ctrl.Finish()
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
@@ -31,7 +32,7 @@ func TestProposeBeaconBlock_BlindedDeneb(t *testing.T) {
headers := map[string]string{"Eth-Consensus-Version": "deneb"}
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blinded_blocks",
"/eth/v1/beacon/blinded_blocks",
headers,
bytes.NewBuffer(denebBytes),
nil,

View File

@@ -1,50 +0,0 @@
package beacon_api
import (
"bytes"
"context"
"encoding/json"
"testing"
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
rpctesting "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared/testing"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/validator/client/beacon-api/mock"
"go.uber.org/mock/gomock"
)
func TestProposeBeaconBlock_BlindedElectra(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
var block structs.SignedBlindedBeaconBlockElectra
err := json.Unmarshal([]byte(rpctesting.BlindedElectraBlock), &block)
require.NoError(t, err)
genericSignedBlock, err := block.ToGeneric()
require.NoError(t, err)
electraBytes, err := json.Marshal(block)
require.NoError(t, err)
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
headers := map[string]string{"Eth-Consensus-Version": "electra"}
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blinded_blocks",
headers,
bytes.NewBuffer(electraBytes),
nil,
)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
proposeResponse, err := validatorClient.proposeBeaconBlock(context.Background(), genericSignedBlock)
assert.NoError(t, err)
require.NotNil(t, proposeResponse)
expectedBlockRoot, err := genericSignedBlock.GetBlindedElectra().HashTreeRoot()
require.NoError(t, err)
// Make sure that the block root is set
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
}

View File

@@ -76,7 +76,7 @@ func TestProposeBeaconBlock_Capella(t *testing.T) {
headers := map[string]string{"Eth-Consensus-Version": "capella"}
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blocks",
"/eth/v1/beacon/blocks",
headers,
bytes.NewBuffer(marshalledBlock),
nil,

View File

@@ -15,6 +15,8 @@ import (
)
func TestProposeBeaconBlock_Deneb(t *testing.T) {
t.Skip("TODO: Fix this in the beacon-API PR")
ctrl := gomock.NewController(t)
defer ctrl.Finish()
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
@@ -31,7 +33,7 @@ func TestProposeBeaconBlock_Deneb(t *testing.T) {
headers := map[string]string{"Eth-Consensus-Version": "deneb"}
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blocks",
"/eth/v1/beacon/blocks",
headers,
bytes.NewBuffer(denebBytes),
nil,

View File

@@ -1,50 +0,0 @@
package beacon_api
import (
"bytes"
"context"
"encoding/json"
"testing"
"github.com/prysmaticlabs/prysm/v5/api/server/structs"
rpctesting "github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared/testing"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/validator/client/beacon-api/mock"
"go.uber.org/mock/gomock"
)
func TestProposeBeaconBlock_Electra(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
var blockContents structs.SignedBeaconBlockContentsElectra
err := json.Unmarshal([]byte(rpctesting.ElectraBlockContents), &blockContents)
require.NoError(t, err)
genericSignedBlock, err := blockContents.ToGeneric()
require.NoError(t, err)
electraBytes, err := json.Marshal(blockContents)
require.NoError(t, err)
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
headers := map[string]string{"Eth-Consensus-Version": "electra"}
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blocks",
headers,
bytes.NewBuffer(electraBytes),
nil,
)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
proposeResponse, err := validatorClient.proposeBeaconBlock(context.Background(), genericSignedBlock)
assert.NoError(t, err)
require.NotNil(t, proposeResponse)
expectedBlockRoot, err := genericSignedBlock.GetElectra().Block.HashTreeRoot()
require.NoError(t, err)
// Make sure that the block root is set
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
}

View File

@@ -55,7 +55,7 @@ func TestProposeBeaconBlock_Phase0(t *testing.T) {
headers := map[string]string{"Eth-Consensus-Version": "phase0"}
jsonRestHandler.EXPECT().Post(
gomock.Any(),
"/eth/v2/beacon/blocks",
"/eth/v1/beacon/blocks",
headers,
bytes.NewBuffer(marshalledBlock),
nil,

View File

@@ -51,7 +51,7 @@ func TestProposeBeaconBlock_Error(t *testing.T) {
{
name: "phase0",
consensusVersion: "phase0",
endpoint: "/eth/v2/beacon/blocks",
endpoint: "/eth/v1/beacon/blocks",
block: &ethpb.GenericSignedBeaconBlock{
Block: generateSignedPhase0Block(),
},
@@ -59,7 +59,7 @@ func TestProposeBeaconBlock_Error(t *testing.T) {
{
name: "altair",
consensusVersion: "altair",
endpoint: "/eth/v2/beacon/blocks",
endpoint: "/eth/v1/beacon/blocks",
block: &ethpb.GenericSignedBeaconBlock{
Block: generateSignedAltairBlock(),
},
@@ -67,7 +67,7 @@ func TestProposeBeaconBlock_Error(t *testing.T) {
{
name: "bellatrix",
consensusVersion: "bellatrix",
endpoint: "/eth/v2/beacon/blocks",
endpoint: "/eth/v1/beacon/blocks",
block: &ethpb.GenericSignedBeaconBlock{
Block: generateSignedBellatrixBlock(),
},
@@ -75,23 +75,15 @@ func TestProposeBeaconBlock_Error(t *testing.T) {
{
name: "blinded bellatrix",
consensusVersion: "bellatrix",
endpoint: "/eth/v2/beacon/blinded_blocks",
endpoint: "/eth/v1/beacon/blinded_blocks",
block: &ethpb.GenericSignedBeaconBlock{
Block: generateSignedBlindedBellatrixBlock(),
},
},
{
name: "capella",
consensusVersion: "capella",
endpoint: "/eth/v2/beacon/blocks",
block: &ethpb.GenericSignedBeaconBlock{
Block: generateSignedCapellaBlock(),
},
},
{
name: "blinded capella",
consensusVersion: "capella",
endpoint: "/eth/v2/beacon/blinded_blocks",
endpoint: "/eth/v1/beacon/blinded_blocks",
block: &ethpb.GenericSignedBeaconBlock{
Block: generateSignedBlindedCapellaBlock(),
},

View File

@@ -50,10 +50,6 @@ func (c *beaconApiValidatorClient) validatorsStatusResponse(ctx context.Context,
[]*ethpb.ValidatorStatusResponse,
error,
) {
// if no parameters are provided we should just return an empty response
if len(inPubKeys) == 0 && len(inIndexes) == 0 {
return [][]byte{}, []primitives.ValidatorIndex{}, []*ethpb.ValidatorStatusResponse{}, nil
}
// Represents the target set of keys
stringTargetPubKeysToPubKeys := make(map[string][]byte, len(inPubKeys))
stringTargetPubKeys := make([]string, len(inPubKeys))
@@ -82,7 +78,6 @@ func (c *beaconApiValidatorClient) validatorsStatusResponse(ctx context.Context,
return nil, nil, nil, errors.Wrap(err, "failed to get state validators")
}
// TODO: we should remove this API call
validatorsCountResponse, err := c.prysmChainClient.ValidatorCount(ctx, "head", nil)
if err != nil && !errors.Is(err, iface.ErrNotSupported) {
return nil, nil, nil, errors.Wrap(err, "failed to get total validator count")

View File

@@ -215,23 +215,32 @@ func TestMultipleValidatorStatus_Nominal(t *testing.T) {
assert.DeepEqual(t, &expectedValidatorStatusResponse, actualValidatorStatusResponse)
}
func TestMultipleValidatorStatus_No_Keys(t *testing.T) {
func TestMultipleValidatorStatus_Error(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
stateValidatorsProvider := mock.NewMockStateValidatorsProvider(ctrl)
stateValidatorsProvider.EXPECT().StateValidators(
gomock.Any(),
gomock.Any(),
[]primitives.ValidatorIndex{},
nil,
).Return(
&structs.GetValidatorsResponse{},
errors.New("a specific error"),
).Times(1)
validatorClient := beaconApiValidatorClient{stateValidatorsProvider: stateValidatorsProvider}
resp, err := validatorClient.MultipleValidatorStatus(
_, err := validatorClient.MultipleValidatorStatus(
ctx,
&ethpb.MultipleValidatorStatusRequest{
PublicKeys: [][]byte{},
},
)
require.NoError(t, err)
require.DeepEqual(t, &ethpb.MultipleValidatorStatusResponse{}, resp)
require.ErrorContains(t, "failed to get validators status response", err)
}
func TestGetValidatorsStatusResponse_Nominal_SomeActiveValidators(t *testing.T) {

View File

@@ -2,7 +2,6 @@ package beacon_api
import (
"context"
"encoding/json"
"net/url"
"strconv"
@@ -53,12 +52,7 @@ func (c *beaconApiValidatorClient) submitAggregateSelectionProof(
return nil, err
}
var attData *structs.Attestation
if err := json.Unmarshal(aggregateAttestationResponse.Data, &attData); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal aggregate attestation data")
}
aggregatedAttestation, err := convertAttestationToProto(attData)
aggregatedAttestation, err := convertAttestationToProto(aggregateAttestationResponse.Data)
if err != nil {
return nil, errors.Wrap(err, "failed to convert aggregate attestation json to proto")
}

View File

@@ -2,7 +2,6 @@ package beacon_api
import (
"context"
"encoding/json"
"errors"
"fmt"
"testing"
@@ -125,9 +124,6 @@ func TestSubmitAggregateSelectionProof(t *testing.T) {
test.attestationDataErr,
).Times(test.attestationDataCalled)
attestationJSON, err := json.Marshal(jsonifyAttestation(aggregateAttestation))
require.NoError(t, err)
// Call attestation data to get attestation data root to query aggregate attestation.
jsonRestHandler.EXPECT().Get(
gomock.Any(),
@@ -136,7 +132,7 @@ func TestSubmitAggregateSelectionProof(t *testing.T) {
).SetArg(
2,
structs.AggregateAttestationResponse{
Data: attestationJSON,
Data: jsonifyAttestation(aggregateAttestation),
},
).Return(
test.aggregateAttestationErr,

View File

@@ -8,7 +8,6 @@ go_library(
"bellatrix_beacon_block_test_helpers.go",
"capella_beacon_block_test_helpers.go",
"deneb_beacon_block_test_helpers.go",
"electra_beacon_block_test_helpers.go",
"phase0_beacon_block_test_helpers.go",
"test_helpers.go",
],

View File

@@ -1224,10 +1224,6 @@ func (v *validator) filterAndCacheActiveKeys(ctx context.Context, pubkeys [][fie
// updateValidatorStatusCache updates the validator statuses cache, a map of keys currently used by the validator client
func (v *validator) updateValidatorStatusCache(ctx context.Context, pubkeys [][fieldparams.BLSPubkeyLength]byte) error {
if len(pubkeys) == 0 {
v.pubkeyToStatus = make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus, 0)
return nil
}
statusRequestKeys := make([][]byte, 0)
for _, k := range pubkeys {
statusRequestKeys = append(statusRequestKeys, k[:])

View File

@@ -2899,9 +2899,4 @@ func TestUpdateValidatorStatusCache(t *testing.T) {
require.Equal(t, mockResponse.Statuses[i], status.status)
require.Equal(t, mockResponse.Indices[i], status.index)
}
err = v.updateValidatorStatusCache(ctx, nil)
assert.NoError(t, err)
// make sure the value is 0
assert.Equal(t, 0, len(v.pubkeyToStatus))
}