mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-04-19 03:01:06 -04:00
This PR moves kzg commitments to bid. The rationale behind is captured in this [issue](https://github.com/ethereum/consensus-specs/issues/4870) * Moves blob KZG commitments to the earlier point where builder intent is known * Removes duplicated commitments from data column sidecars which saves descent b/w per slot * Enables nodes to start fetching blobs via getBlobs as soon as the bid is received * Slightly increases bid size and may add minor bidding channel latency but the tradeoff favors lower network load and simpler DA handling
431 lines
14 KiB
Go
431 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 := ðpbalpha.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 := ðpbv1.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 := ðpbalpha.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 := ðpbalpha.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 := ðpbalpha.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 := ðpbalpha.BlindedBeaconBlockBodyBellatrix{}
|
|
b = HydrateBlindedBeaconBlockBodyBellatrix(b)
|
|
_, err := b.HashTreeRoot()
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestHydrateSignedBeaconBlockCapella_NoError(t *testing.T) {
|
|
b := ðpbalpha.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 := ðpbalpha.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 := ðpbalpha.BeaconBlockBodyCapella{}
|
|
b = HydrateBeaconBlockBodyCapella(b)
|
|
_, err := b.HashTreeRoot()
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestHydrateSignedBlindedBeaconBlockCapella_NoError(t *testing.T) {
|
|
b := ðpbalpha.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 := ðpbalpha.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 := ðpbalpha.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 := ðpbalpha.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 := ðpbalpha.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)
|
|
require.Equal(t, primitives.Gwei(2000000), bid.Message.ExecutionPayment)
|
|
|
|
// 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.BlobKzgCommitments)
|
|
require.Equal(t, 1, len(bid.Message.BlobKzgCommitments))
|
|
|
|
// Verify HashTreeRoot works
|
|
_, err := bid.HashTreeRoot()
|
|
require.NoError(t, err)
|
|
}
|