Files
prysm/testing/util/block_test.go
james-prysm ce9c968dcc adding gloas block support to /eth/v2/beacon/blocks/{block_id} and /eth/v1/beacon/blocks/{block_id}/root (#16278)
**What type of PR is this?**
Feature

**What does this PR do? Why is it needed?**

adding gloas block return on `/eth/v2/beacon/blocks/{block_id}` endpoint

-
[/eth/v1/beacon/blocks/{block_id}/root](https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Beacon/getBlockRoot)
should inherit this as well

reference
https://github.com/ethereum/beacon-APIs/pull/552/files#r2722805266

**Which issues(s) does this PR fix?**

Fixes #

**Other notes for review**

**Acknowledgements**

- [x] I have read
[CONTRIBUTING.md](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md).
- [x] I have included a uniquely named [changelog fragment
file](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md#maintaining-changelogmd).
- [x] I have added a description with sufficient context for reviewers
to understand this PR.
- [x] I have tested that my changes work as expected and I added a
testing plan to the PR description (if applicable).
2026-01-27 00:02:16 +00:00

429 lines
14 KiB
Go

package util
import (
"testing"
coreBlock "github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition/stateutils"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
ethpbv1 "github.com/OffchainLabs/prysm/v7/proto/eth/v1"
ethpbalpha "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
)
func TestGenerateFullBlock_PassesStateTransition(t *testing.T) {
beaconState, privs := DeterministicGenesisState(t, 128)
conf := &BlockGenConfig{
NumAttestations: 1,
}
block, err := GenerateFullBlock(beaconState, privs, conf, beaconState.Slot())
require.NoError(t, err)
wsb, err := blocks.NewSignedBeaconBlock(block)
require.NoError(t, err)
_, err = transition.ExecuteStateTransition(t.Context(), beaconState, wsb)
require.NoError(t, err)
}
func TestGenerateFullBlock_ThousandValidators(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
beaconState, privs := DeterministicGenesisState(t, 1024)
conf := &BlockGenConfig{
NumAttestations: 4,
}
block, err := GenerateFullBlock(beaconState, privs, conf, beaconState.Slot())
require.NoError(t, err)
wsb, err := blocks.NewSignedBeaconBlock(block)
require.NoError(t, err)
_, err = transition.ExecuteStateTransition(t.Context(), beaconState, wsb)
require.NoError(t, err)
}
func TestGenerateFullBlock_Passes4Epochs(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
beaconState, privs := DeterministicGenesisState(t, 64)
conf := &BlockGenConfig{
NumAttestations: 2,
}
finalSlot := params.BeaconConfig().SlotsPerEpoch*4 + 3
for i := 0; i < int(finalSlot); i++ {
helpers.ClearCache()
block, err := GenerateFullBlock(beaconState, privs, conf, beaconState.Slot())
require.NoError(t, err)
wsb, err := blocks.NewSignedBeaconBlock(block)
require.NoError(t, err)
beaconState, err = transition.ExecuteStateTransition(t.Context(), beaconState, wsb)
require.NoError(t, err)
}
// Blocks are one slot ahead of beacon state.
if finalSlot != beaconState.Slot() {
t.Fatalf("expected output slot to be %d, received %d", finalSlot, beaconState.Slot())
}
if beaconState.CurrentJustifiedCheckpoint().Epoch != 3 {
t.Fatalf("expected justified epoch to change to 3, received %d", beaconState.CurrentJustifiedCheckpoint().Epoch)
}
if beaconState.FinalizedCheckpointEpoch() != 2 {
t.Fatalf("expected finalized epoch to change to 2, received %d", beaconState.FinalizedCheckpointEpoch())
}
}
func TestGenerateFullBlock_ValidProposerSlashings(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
beaconState, privs := DeterministicGenesisState(t, 32)
conf := &BlockGenConfig{
NumProposerSlashings: 1,
}
block, err := GenerateFullBlock(beaconState, privs, conf, beaconState.Slot()+1)
require.NoError(t, err)
wsb, err := blocks.NewSignedBeaconBlock(block)
require.NoError(t, err)
beaconState, err = transition.ExecuteStateTransition(t.Context(), beaconState, wsb)
require.NoError(t, err)
slashableIndice := block.Block.Body.ProposerSlashings[0].Header_1.Header.ProposerIndex
if val, err := beaconState.ValidatorAtIndexReadOnly(slashableIndice); err != nil || !val.Slashed() {
require.NoError(t, err)
t.Fatal("expected validator to be slashed")
}
}
func TestGenerateFullBlock_ValidAttesterSlashings(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
beaconState, privs := DeterministicGenesisState(t, 256)
conf := &BlockGenConfig{
NumAttesterSlashings: 1,
}
block, err := GenerateFullBlock(beaconState, privs, conf, beaconState.Slot())
require.NoError(t, err)
wsb, err := blocks.NewSignedBeaconBlock(block)
require.NoError(t, err)
beaconState, err = transition.ExecuteStateTransition(t.Context(), beaconState, wsb)
require.NoError(t, err)
slashableIndices := block.Block.Body.AttesterSlashings[0].Attestation_1.AttestingIndices
if val, err := beaconState.ValidatorAtIndexReadOnly(primitives.ValidatorIndex(slashableIndices[0])); err != nil || !val.Slashed() {
require.NoError(t, err)
t.Fatal("expected validator to be slashed")
}
}
func TestGenerateFullBlock_ValidAttestations(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
beaconState, privs := DeterministicGenesisState(t, 256)
conf := &BlockGenConfig{
NumAttestations: 4,
}
block, err := GenerateFullBlock(beaconState, privs, conf, beaconState.Slot())
require.NoError(t, err)
wsb, err := blocks.NewSignedBeaconBlock(block)
require.NoError(t, err)
beaconState, err = transition.ExecuteStateTransition(t.Context(), beaconState, wsb)
require.NoError(t, err)
atts, err := beaconState.CurrentEpochAttestations()
require.NoError(t, err)
if len(atts) != 4 {
t.Fatal("expected 4 attestations to be saved to the beacon state")
}
}
func TestGenerateFullBlock_ValidDeposits(t *testing.T) {
beaconState, privs := DeterministicGenesisState(t, 256)
deposits, _, err := DeterministicDepositsAndKeys(257)
require.NoError(t, err)
eth1Data, err := DeterministicEth1Data(len(deposits))
require.NoError(t, err)
require.NoError(t, beaconState.SetEth1Data(eth1Data))
conf := &BlockGenConfig{
NumDeposits: 1,
}
block, err := GenerateFullBlock(beaconState, privs, conf, beaconState.Slot())
require.NoError(t, err)
wsb, err := blocks.NewSignedBeaconBlock(block)
require.NoError(t, err)
beaconState, err = transition.ExecuteStateTransition(t.Context(), beaconState, wsb)
require.NoError(t, err)
depositedPubkey := block.Block.Body.Deposits[0].Data.PublicKey
valIndexMap := stateutils.ValidatorIndexMap(beaconState.Validators())
index := valIndexMap[bytesutil.ToBytes48(depositedPubkey)]
val, err := beaconState.ValidatorAtIndexReadOnly(index)
require.NoError(t, err)
if val.EffectiveBalance() != params.BeaconConfig().MaxEffectiveBalance {
t.Fatalf(
"expected validator balance to be max effective balance, received %d",
val.EffectiveBalance(),
)
}
}
func TestGenerateFullBlock_ValidVoluntaryExits(t *testing.T) {
beaconState, privs := DeterministicGenesisState(t, 256)
// Moving the state 2048 epochs forward due to PERSISTENT_COMMITTEE_PERIOD.
err := beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().ShardCommitteePeriod)).Add(3))
require.NoError(t, err)
conf := &BlockGenConfig{
NumVoluntaryExits: 1,
}
block, err := GenerateFullBlock(beaconState, privs, conf, beaconState.Slot())
require.NoError(t, err)
wsb, err := blocks.NewSignedBeaconBlock(block)
require.NoError(t, err)
beaconState, err = transition.ExecuteStateTransition(t.Context(), beaconState, wsb)
require.NoError(t, err)
exitedIndex := block.Block.Body.VoluntaryExits[0].Exit.ValidatorIndex
val, err := beaconState.ValidatorAtIndexReadOnly(exitedIndex)
require.NoError(t, err)
if val.ExitEpoch() == params.BeaconConfig().FarFutureEpoch {
t.Fatal("expected exiting validator index to be marked as exiting")
}
}
func TestHydrateSignedBeaconBlock_NoError(t *testing.T) {
b := &ethpbalpha.SignedBeaconBlock{}
b = HydrateSignedBeaconBlock(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.Body.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateV1SignedBeaconBlock_NoError(t *testing.T) {
b := &ethpbv1.SignedBeaconBlock{}
b = HydrateV1SignedBeaconBlock(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.Body.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateSignedBeaconBlockAltair_NoError(t *testing.T) {
b := &ethpbalpha.SignedBeaconBlockAltair{}
b = HydrateSignedBeaconBlockAltair(b)
// HTR should not error. It errors with incorrect field length sizes.
_, err := b.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.Body.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateSignedBlindedBeaconBlockBellatrix_NoError(t *testing.T) {
b := &ethpbalpha.SignedBlindedBeaconBlockBellatrix{}
b = HydrateSignedBlindedBeaconBlockBellatrix(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.Body.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateBlindedBeaconBlockBellatrix_NoError(t *testing.T) {
b := &ethpbalpha.BlindedBeaconBlockBellatrix{}
b = HydrateBlindedBeaconBlockBellatrix(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
_, err = b.Body.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateBlindedBeaconBlockBodyBellatrix_NoError(t *testing.T) {
b := &ethpbalpha.BlindedBeaconBlockBodyBellatrix{}
b = HydrateBlindedBeaconBlockBodyBellatrix(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateSignedBeaconBlockCapella_NoError(t *testing.T) {
b := &ethpbalpha.SignedBeaconBlockCapella{}
b = HydrateSignedBeaconBlockCapella(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.Body.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateBeaconBlockCapella_NoError(t *testing.T) {
b := &ethpbalpha.BeaconBlockCapella{}
b = HydrateBeaconBlockCapella(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
_, err = b.Body.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateBeaconBlockBodyCapella_NoError(t *testing.T) {
b := &ethpbalpha.BeaconBlockBodyCapella{}
b = HydrateBeaconBlockBodyCapella(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateSignedBlindedBeaconBlockCapella_NoError(t *testing.T) {
b := &ethpbalpha.SignedBlindedBeaconBlockCapella{}
b = HydrateSignedBlindedBeaconBlockCapella(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.Body.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateBlindedBeaconBlockCapella_NoError(t *testing.T) {
b := &ethpbalpha.BlindedBeaconBlockCapella{}
b = HydrateBlindedBeaconBlockCapella(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
_, err = b.Body.HashTreeRoot()
require.NoError(t, err)
}
func TestHydrateBlindedBeaconBlockBodyCapella_NoError(t *testing.T) {
b := &ethpbalpha.BlindedBeaconBlockBodyCapella{}
b = HydrateBlindedBeaconBlockBodyCapella(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
}
func TestGenerateVoluntaryExits(t *testing.T) {
params.SetupTestConfigCleanup(t)
config := params.BeaconConfig()
config.ShardCommitteePeriod = 0
params.OverrideBeaconConfig(config)
beaconState, privKeys := DeterministicGenesisState(t, 256)
exit, err := GenerateVoluntaryExits(beaconState, privKeys[0], 0)
require.NoError(t, err)
val, err := beaconState.ValidatorAtIndexReadOnly(0)
require.NoError(t, err)
require.NoError(t, coreBlock.VerifyExitAndSignature(val, beaconState, exit))
}
func Test_PostDenebPbGenericBlock_ErrorsForPlainBlock(t *testing.T) {
t.Run("Deneb block returns type error", func(t *testing.T) {
eb := NewBeaconBlockDeneb()
b, err := blocks.NewSignedBeaconBlock(eb)
require.NoError(t, err)
_, err = b.PbGenericBlock()
require.ErrorContains(t, "PbGenericBlock() only supports block content type but got", err)
})
t.Run("Electra block returns type error", func(t *testing.T) {
eb := NewBeaconBlockElectra()
b, err := blocks.NewSignedBeaconBlock(eb)
require.NoError(t, err)
_, err = b.PbGenericBlock()
require.ErrorContains(t, "PbGenericBlock() only supports block content type but got", err)
})
t.Run("Fulu block returns type error", func(t *testing.T) {
eb := NewBeaconBlockFulu()
b, err := blocks.NewSignedBeaconBlock(eb)
require.NoError(t, err)
_, err = b.PbGenericBlock()
require.ErrorContains(t, "PbGenericBlock() only supports block content type but got", err)
})
}
func TestHydrateSignedBeaconBlockGloas_NoError(t *testing.T) {
b := &ethpbalpha.SignedBeaconBlockGloas{}
b = HydrateSignedBeaconBlockGloas(b)
_, err := b.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.HashTreeRoot()
require.NoError(t, err)
_, err = b.Block.Body.HashTreeRoot()
require.NoError(t, err)
}
func TestHydratePayloadAttestation_NoError(t *testing.T) {
p := &ethpbalpha.PayloadAttestation{}
p = HydratePayloadAttestation(p)
_, err := p.HashTreeRoot()
require.NoError(t, err)
_, err = p.Data.HashTreeRoot()
require.NoError(t, err)
}
func TestGenerateTestPayloadAttestations(t *testing.T) {
slot := primitives.Slot(123)
attestations := GenerateTestPayloadAttestations(3, slot)
require.Equal(t, 3, len(attestations))
for i, att := range attestations {
// Verify non-nil fields
require.NotNil(t, att.AggregationBits)
require.NotNil(t, att.Signature)
require.NotNil(t, att.Data)
require.NotNil(t, att.Data.BeaconBlockRoot)
// Verify slot is set correctly
require.Equal(t, slot, att.Data.Slot)
// Verify PayloadPresent and BlobDataAvailable are set
require.Equal(t, true, att.Data.PayloadPresent)
require.Equal(t, true, att.Data.BlobDataAvailable)
// Verify unique values
require.Equal(t, byte(i+1), att.Signature[0])
require.Equal(t, byte(i+1), att.Data.BeaconBlockRoot[0])
// Verify HashTreeRoot works
_, err := att.HashTreeRoot()
require.NoError(t, err)
}
}
func TestGenerateTestSignedExecutionPayloadBid(t *testing.T) {
slot := primitives.Slot(456)
bid := GenerateTestSignedExecutionPayloadBid(slot)
require.NotNil(t, bid)
require.NotNil(t, bid.Message)
require.NotNil(t, bid.Signature)
// Verify slot is set correctly
require.Equal(t, slot, bid.Message.Slot)
// Verify non-zero test values
require.Equal(t, primitives.BuilderIndex(1), bid.Message.BuilderIndex)
require.Equal(t, uint64(30000000), bid.Message.GasLimit)
require.Equal(t, primitives.Gwei(1000000), bid.Message.Value)
// Verify fields are populated
require.NotNil(t, bid.Message.ParentBlockHash)
require.NotNil(t, bid.Message.ParentBlockRoot)
require.NotNil(t, bid.Message.BlockHash)
require.NotNil(t, bid.Message.PrevRandao)
require.NotNil(t, bid.Message.FeeRecipient)
require.NotNil(t, bid.Message.BlobKzgCommitmentsRoot)
// Verify HashTreeRoot works
_, err := bid.HashTreeRoot()
require.NoError(t, err)
}