mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-02-01 16:45:04 -05:00
Compare commits
12 Commits
e2e-debugg
...
process-at
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
646e46aa32 | ||
|
|
eaaa4a868b | ||
|
|
4f5492c423 | ||
|
|
54e931e4bd | ||
|
|
95d5608b42 | ||
|
|
7b11b78ef8 | ||
|
|
a328eac43e | ||
|
|
995d53706c | ||
|
|
db54dc0e22 | ||
|
|
e2005cf8cf | ||
|
|
c617611b2f | ||
|
|
1a8c753f57 |
@@ -20,6 +20,7 @@ go_library(
|
|||||||
"//beacon-chain/core/blocks:go_default_library",
|
"//beacon-chain/core/blocks:go_default_library",
|
||||||
"//beacon-chain/core/epoch:go_default_library",
|
"//beacon-chain/core/epoch:go_default_library",
|
||||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||||
|
"//beacon-chain/core/gloas:go_default_library",
|
||||||
"//beacon-chain/core/helpers:go_default_library",
|
"//beacon-chain/core/helpers:go_default_library",
|
||||||
"//beacon-chain/core/signing:go_default_library",
|
"//beacon-chain/core/signing:go_default_library",
|
||||||
"//beacon-chain/core/time:go_default_library",
|
"//beacon-chain/core/time:go_default_library",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas"
|
||||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
||||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/time"
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/time"
|
||||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||||
@@ -75,7 +76,11 @@ func ProcessAttestationNoVerifySignature(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return SetParticipationAndRewardProposer(ctx, beaconState, att.GetData().Target.Epoch, indices, participatedFlags, totalBalance)
|
if err := beaconState.UpdatePendingPaymentWeight(att, indices, participatedFlags); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to update pending payment weight")
|
||||||
|
}
|
||||||
|
|
||||||
|
return SetParticipationAndRewardProposer(ctx, beaconState, att.GetData().Target.Epoch, indices, participatedFlags, totalBalance, att)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetParticipationAndRewardProposer retrieves and sets the epoch participation bits in state. Based on the epoch participation, it rewards
|
// SetParticipationAndRewardProposer retrieves and sets the epoch participation bits in state. Based on the epoch participation, it rewards
|
||||||
@@ -105,7 +110,9 @@ func SetParticipationAndRewardProposer(
|
|||||||
beaconState state.BeaconState,
|
beaconState state.BeaconState,
|
||||||
targetEpoch primitives.Epoch,
|
targetEpoch primitives.Epoch,
|
||||||
indices []uint64,
|
indices []uint64,
|
||||||
participatedFlags map[uint8]bool, totalBalance uint64) (state.BeaconState, error) {
|
participatedFlags map[uint8]bool,
|
||||||
|
totalBalance uint64,
|
||||||
|
att ethpb.Att) (state.BeaconState, error) {
|
||||||
var proposerRewardNumerator uint64
|
var proposerRewardNumerator uint64
|
||||||
currentEpoch := time.CurrentEpoch(beaconState)
|
currentEpoch := time.CurrentEpoch(beaconState)
|
||||||
var stateErr error
|
var stateErr error
|
||||||
@@ -299,6 +306,19 @@ func AttestationParticipationFlagIndices(beaconState state.ReadOnlyBeaconState,
|
|||||||
participatedFlags[targetFlagIndex] = true
|
participatedFlags[targetFlagIndex] = true
|
||||||
}
|
}
|
||||||
matchedSrcTgtHead := matchedHead && matchedSrcTgt
|
matchedSrcTgtHead := matchedHead && matchedSrcTgt
|
||||||
|
|
||||||
|
var beaconBlockRoot [32]byte
|
||||||
|
copy(beaconBlockRoot[:], data.BeaconBlockRoot)
|
||||||
|
matchingPayload, err := gloas.MatchingPayload(
|
||||||
|
beaconState,
|
||||||
|
beaconBlockRoot,
|
||||||
|
data.Slot,
|
||||||
|
uint64(data.CommitteeIndex),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
matchedSrcTgtHead = matchedSrcTgtHead && matchingPayload
|
||||||
if matchedSrcTgtHead && delay == cfg.MinAttestationInclusionDelay {
|
if matchedSrcTgtHead && delay == cfg.MinAttestationInclusionDelay {
|
||||||
participatedFlags[headFlagIndex] = true
|
participatedFlags[headFlagIndex] = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package altair_test
|
package altair_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/OffchainLabs/go-bitfield"
|
"github.com/OffchainLabs/go-bitfield"
|
||||||
@@ -556,7 +558,7 @@ func TestSetParticipationAndRewardProposer(t *testing.T) {
|
|||||||
|
|
||||||
b, err := helpers.TotalActiveBalance(beaconState)
|
b, err := helpers.TotalActiveBalance(beaconState)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
st, err := altair.SetParticipationAndRewardProposer(t.Context(), beaconState, test.epoch, test.indices, test.participatedFlags, b)
|
st, err := altair.SetParticipationAndRewardProposer(t.Context(), beaconState, test.epoch, test.indices, test.participatedFlags, b, ðpb.Attestation{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
i, err := helpers.BeaconProposerIndex(t.Context(), st)
|
i, err := helpers.BeaconProposerIndex(t.Context(), st)
|
||||||
@@ -775,11 +777,67 @@ func TestAttestationParticipationFlagIndices(t *testing.T) {
|
|||||||
headFlagIndex: true,
|
headFlagIndex: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "gloas same-slot committee index non-zero errors",
|
||||||
|
inputState: func() state.BeaconState {
|
||||||
|
stateSlot := primitives.Slot(5)
|
||||||
|
slot := primitives.Slot(3)
|
||||||
|
targetRoot := bytes.Repeat([]byte{0xAA}, 32)
|
||||||
|
headRoot := bytes.Repeat([]byte{0xBB}, 32)
|
||||||
|
prevRoot := bytes.Repeat([]byte{0xCC}, 32)
|
||||||
|
return buildGloasStateForFlags(t, stateSlot, slot, targetRoot, headRoot, prevRoot, 0, 0)
|
||||||
|
}(),
|
||||||
|
inputData: ðpb.AttestationData{
|
||||||
|
Slot: 3,
|
||||||
|
CommitteeIndex: 1, // invalid for same-slot
|
||||||
|
BeaconBlockRoot: bytes.Repeat([]byte{0xBB}, 32),
|
||||||
|
Source: ðpb.Checkpoint{Root: bytes.Repeat([]byte{0xDD}, 32)},
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: 0,
|
||||||
|
Root: bytes.Repeat([]byte{0xAA}, 32),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputDelay: 1,
|
||||||
|
participationIndices: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gloas payload availability matches committee index",
|
||||||
|
inputState: func() state.BeaconState {
|
||||||
|
stateSlot := primitives.Slot(5)
|
||||||
|
slot := primitives.Slot(3)
|
||||||
|
targetRoot := bytes.Repeat([]byte{0xAA}, 32)
|
||||||
|
headRoot := bytes.Repeat([]byte{0xBB}, 32)
|
||||||
|
// Same prev root to make SameSlotAttestation false and use payload availability.
|
||||||
|
return buildGloasStateForFlags(t, stateSlot, slot, targetRoot, headRoot, headRoot, 1, slot)
|
||||||
|
}(),
|
||||||
|
inputData: ðpb.AttestationData{
|
||||||
|
Slot: 3,
|
||||||
|
CommitteeIndex: 1,
|
||||||
|
BeaconBlockRoot: bytes.Repeat([]byte{0xBB}, 32),
|
||||||
|
Source: ðpb.Checkpoint{Root: bytes.Repeat([]byte{0xDD}, 32)},
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: 0,
|
||||||
|
Root: bytes.Repeat([]byte{0xAA}, 32),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputDelay: 1,
|
||||||
|
participationIndices: map[uint8]bool{
|
||||||
|
sourceFlagIndex: true,
|
||||||
|
targetFlagIndex: true,
|
||||||
|
headFlagIndex: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
flagIndices, err := altair.AttestationParticipationFlagIndices(test.inputState, test.inputData, test.inputDelay)
|
flagIndices, err := altair.AttestationParticipationFlagIndices(test.inputState, test.inputData, test.inputDelay)
|
||||||
|
if test.participationIndices == nil {
|
||||||
|
require.ErrorContains(t, "committee index", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.DeepEqual(t, test.participationIndices, flagIndices)
|
if !reflect.DeepEqual(test.participationIndices, flagIndices) {
|
||||||
|
t.Fatalf("unexpected participation indices: got %v want %v", flagIndices, test.participationIndices)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -858,3 +916,61 @@ func TestMatchingStatus(t *testing.T) {
|
|||||||
require.Equal(t, test.matchedHead, head)
|
require.Equal(t, test.matchedHead, head)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildGloasStateForFlags(t *testing.T, stateSlot, slot primitives.Slot, targetRoot, headRoot, prevRoot []byte, availabilityBit uint8, availabilitySlot primitives.Slot) state.BeaconState {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
cfg := params.BeaconConfig()
|
||||||
|
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||||
|
blockRoots[0] = targetRoot
|
||||||
|
blockRoots[slot%cfg.SlotsPerHistoricalRoot] = headRoot
|
||||||
|
blockRoots[(slot-1)%cfg.SlotsPerHistoricalRoot] = prevRoot
|
||||||
|
|
||||||
|
stateRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||||
|
for i := range stateRoots {
|
||||||
|
stateRoots[i] = make([]byte, fieldparams.RootLength)
|
||||||
|
}
|
||||||
|
randaoMixes := make([][]byte, cfg.EpochsPerHistoricalVector)
|
||||||
|
for i := range randaoMixes {
|
||||||
|
randaoMixes[i] = make([]byte, fieldparams.RootLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
execPayloadAvailability := make([]byte, cfg.SlotsPerHistoricalRoot/8)
|
||||||
|
idx := availabilitySlot % cfg.SlotsPerHistoricalRoot
|
||||||
|
byteIndex := idx / 8
|
||||||
|
bitIndex := idx % 8
|
||||||
|
if availabilityBit == 1 {
|
||||||
|
execPayloadAvailability[byteIndex] |= 1 << bitIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
checkpointRoot := bytes.Repeat([]byte{0xDD}, fieldparams.RootLength)
|
||||||
|
justified := ðpb.Checkpoint{Root: checkpointRoot}
|
||||||
|
|
||||||
|
stProto := ðpb.BeaconStateGloas{
|
||||||
|
Slot: stateSlot,
|
||||||
|
GenesisValidatorsRoot: bytes.Repeat([]byte{0x11}, fieldparams.RootLength),
|
||||||
|
BlockRoots: blockRoots,
|
||||||
|
StateRoots: stateRoots,
|
||||||
|
RandaoMixes: randaoMixes,
|
||||||
|
ExecutionPayloadAvailability: execPayloadAvailability,
|
||||||
|
CurrentJustifiedCheckpoint: justified,
|
||||||
|
PreviousJustifiedCheckpoint: justified,
|
||||||
|
Validators: []*ethpb.Validator{
|
||||||
|
{
|
||||||
|
EffectiveBalance: cfg.MinActivationBalance,
|
||||||
|
WithdrawalCredentials: append([]byte{cfg.ETH1AddressWithdrawalPrefixByte}, bytes.Repeat([]byte{0x01}, 31)...),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Balances: []uint64{cfg.MinActivationBalance},
|
||||||
|
BuilderPendingPayments: make([]*ethpb.BuilderPendingPayment, cfg.SlotsPerEpoch*2),
|
||||||
|
Fork: ðpb.Fork{
|
||||||
|
CurrentVersion: bytes.Repeat([]byte{0x01}, 4),
|
||||||
|
PreviousVersion: bytes.Repeat([]byte{0x01}, 4),
|
||||||
|
Epoch: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
beaconState, err := state_native.InitializeFromProtoGloas(stProto)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return beaconState
|
||||||
|
}
|
||||||
|
|||||||
@@ -111,10 +111,21 @@ func VerifyAttestationNoVerifySignature(
|
|||||||
var indexedAtt ethpb.IndexedAtt
|
var indexedAtt ethpb.IndexedAtt
|
||||||
|
|
||||||
if att.Version() >= version.Electra {
|
if att.Version() >= version.Electra {
|
||||||
if att.GetData().CommitteeIndex != 0 {
|
ci := att.GetData().CommitteeIndex
|
||||||
return errors.New("committee index must be 0 post-Electra")
|
// Spec v1.7.0-alpha pseudocode:
|
||||||
|
//
|
||||||
|
// # [Modified in Gloas:EIP7732]
|
||||||
|
// assert data.index < 2
|
||||||
|
//
|
||||||
|
if beaconState.Version() >= version.Gloas {
|
||||||
|
if ci >= 2 {
|
||||||
|
return fmt.Errorf("incorrect committee index %d", ci)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ci != 0 {
|
||||||
|
return errors.New("committee index must be 0 between Electra and Gloas forks")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aggBits := att.GetAggregationBits()
|
aggBits := att.GetAggregationBits()
|
||||||
committeeIndices := att.CommitteeBitsVal().BitIndices()
|
committeeIndices := att.CommitteeBitsVal().BitIndices()
|
||||||
committees := make([][]primitives.ValidatorIndex, len(committeeIndices))
|
committees := make([][]primitives.ValidatorIndex, len(committeeIndices))
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package blocks_test
|
package blocks_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -262,7 +263,7 @@ func TestVerifyAttestationNoVerifySignature_Electra(t *testing.T) {
|
|||||||
CommitteeBits: bitfield.NewBitvector64(),
|
CommitteeBits: bitfield.NewBitvector64(),
|
||||||
}
|
}
|
||||||
err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
|
err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
|
||||||
assert.ErrorContains(t, "committee index must be 0 post-Electra", err)
|
assert.ErrorContains(t, "committee index must be 0", err)
|
||||||
})
|
})
|
||||||
t.Run("index of committee too big", func(t *testing.T) {
|
t.Run("index of committee too big", func(t *testing.T) {
|
||||||
aggBits := bitfield.NewBitlist(3)
|
aggBits := bitfield.NewBitlist(3)
|
||||||
@@ -314,6 +315,75 @@ func TestVerifyAttestationNoVerifySignature_Electra(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVerifyAttestationNoVerifySignature_GloasCommitteeIndexLimit(t *testing.T) {
|
||||||
|
cfg := params.BeaconConfig()
|
||||||
|
stateSlot := cfg.MinAttestationInclusionDelay + 1
|
||||||
|
|
||||||
|
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||||
|
for i := range blockRoots {
|
||||||
|
blockRoots[i] = make([]byte, fieldparams.RootLength)
|
||||||
|
}
|
||||||
|
stateRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||||
|
for i := range stateRoots {
|
||||||
|
stateRoots[i] = make([]byte, fieldparams.RootLength)
|
||||||
|
}
|
||||||
|
randaoMixes := make([][]byte, cfg.EpochsPerHistoricalVector)
|
||||||
|
for i := range randaoMixes {
|
||||||
|
randaoMixes[i] = make([]byte, fieldparams.RootLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkpointRoot := bytes.Repeat([]byte{0xAA}, fieldparams.RootLength)
|
||||||
|
justified := ðpb.Checkpoint{Epoch: 0, Root: checkpointRoot}
|
||||||
|
|
||||||
|
gloasStateProto := ðpb.BeaconStateGloas{
|
||||||
|
Slot: stateSlot,
|
||||||
|
GenesisValidatorsRoot: bytes.Repeat([]byte{0x11}, fieldparams.RootLength),
|
||||||
|
BlockRoots: blockRoots,
|
||||||
|
StateRoots: stateRoots,
|
||||||
|
RandaoMixes: randaoMixes,
|
||||||
|
ExecutionPayloadAvailability: make([]byte, cfg.SlotsPerHistoricalRoot/8),
|
||||||
|
CurrentJustifiedCheckpoint: justified,
|
||||||
|
PreviousJustifiedCheckpoint: justified,
|
||||||
|
Validators: []*ethpb.Validator{
|
||||||
|
{
|
||||||
|
EffectiveBalance: cfg.MinActivationBalance,
|
||||||
|
WithdrawalCredentials: append([]byte{cfg.ETH1AddressWithdrawalPrefixByte}, bytes.Repeat([]byte{0x01}, 31)...),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Balances: []uint64{cfg.MinActivationBalance},
|
||||||
|
BuilderPendingPayments: make([]*ethpb.BuilderPendingPayment, cfg.SlotsPerEpoch*2),
|
||||||
|
Fork: ðpb.Fork{
|
||||||
|
CurrentVersion: bytes.Repeat([]byte{0x01}, 4),
|
||||||
|
PreviousVersion: bytes.Repeat([]byte{0x01}, 4),
|
||||||
|
Epoch: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
beaconState, err := state_native.InitializeFromProtoGloas(gloasStateProto)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
committeeBits := bitfield.NewBitvector64()
|
||||||
|
committeeBits.SetBitAt(0, true)
|
||||||
|
aggBits := bitfield.NewBitlist(1)
|
||||||
|
aggBits.SetBitAt(0, true)
|
||||||
|
|
||||||
|
att := ðpb.AttestationElectra{
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: 0,
|
||||||
|
CommitteeIndex: 2, // invalid for Gloas (must be <2)
|
||||||
|
BeaconBlockRoot: blockRoots[0],
|
||||||
|
Source: justified,
|
||||||
|
Target: justified,
|
||||||
|
},
|
||||||
|
AggregationBits: aggBits,
|
||||||
|
CommitteeBits: committeeBits,
|
||||||
|
Signature: bytes.Repeat([]byte{0x00}, fieldparams.BLSSignatureLength),
|
||||||
|
}
|
||||||
|
|
||||||
|
err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
|
||||||
|
assert.ErrorContains(t, "incorrect committee index 2", err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestConvertToIndexed_OK(t *testing.T) {
|
func TestConvertToIndexed_OK(t *testing.T) {
|
||||||
helpers.ClearCache()
|
helpers.ClearCache()
|
||||||
validators := make([]*ethpb.Validator, 2*params.BeaconConfig().SlotsPerEpoch)
|
validators := make([]*ethpb.Validator, 2*params.BeaconConfig().SlotsPerEpoch)
|
||||||
@@ -583,6 +653,7 @@ func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing.T) {
|
func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing.T) {
|
||||||
|
helpers.ClearCache()
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
numOfValidators := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(4))
|
numOfValidators := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(4))
|
||||||
validators := make([]*ethpb.Validator, numOfValidators)
|
validators := make([]*ethpb.Validator, numOfValidators)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"attestation.go",
|
||||||
"bid.go",
|
"bid.go",
|
||||||
"pending_payment.go",
|
"pending_payment.go",
|
||||||
"proposer_slashing.go",
|
"proposer_slashing.go",
|
||||||
@@ -21,6 +22,7 @@ go_library(
|
|||||||
"//crypto/bls:go_default_library",
|
"//crypto/bls:go_default_library",
|
||||||
"//crypto/bls/common:go_default_library",
|
"//crypto/bls/common:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
"//runtime/version:go_default_library",
|
||||||
"//time/slots:go_default_library",
|
"//time/slots:go_default_library",
|
||||||
"@com_github_pkg_errors//:go_default_library",
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
],
|
],
|
||||||
@@ -29,6 +31,7 @@ go_library(
|
|||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"attestation_test.go",
|
||||||
"bid_test.go",
|
"bid_test.go",
|
||||||
"pending_payment_test.go",
|
"pending_payment_test.go",
|
||||||
"proposer_slashing_test.go",
|
"proposer_slashing_test.go",
|
||||||
|
|||||||
52
beacon-chain/core/gloas/attestation.go
Normal file
52
beacon-chain/core/gloas/attestation.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package gloas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MatchingPayload returns true if the attestation's committee index matches the expected payload index.
|
||||||
|
//
|
||||||
|
// For pre-Gloas forks, this always returns true.
|
||||||
|
//
|
||||||
|
// Spec v1.7.0-alpha (pseudocode):
|
||||||
|
//
|
||||||
|
// # [New in Gloas:EIP7732]
|
||||||
|
// if is_attestation_same_slot(state, data):
|
||||||
|
// assert data.index == 0
|
||||||
|
// payload_matches = True
|
||||||
|
// else:
|
||||||
|
// slot_index = data.slot % SLOTS_PER_HISTORICAL_ROOT
|
||||||
|
// payload_index = state.execution_payload_availability[slot_index]
|
||||||
|
// payload_matches = data.index == payload_index
|
||||||
|
func MatchingPayload(
|
||||||
|
beaconState state.ReadOnlyBeaconState,
|
||||||
|
beaconBlockRoot [32]byte,
|
||||||
|
slot primitives.Slot,
|
||||||
|
committeeIndex uint64,
|
||||||
|
) (bool, error) {
|
||||||
|
if beaconState.Version() < version.Gloas {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sameSlot, err := beaconState.IsAttestationSameSlot(beaconBlockRoot, slot)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrap(err, "failed to get same slot attestation status")
|
||||||
|
}
|
||||||
|
if sameSlot {
|
||||||
|
if committeeIndex != 0 {
|
||||||
|
return false, fmt.Errorf("committee index %d for same slot attestation must be 0", committeeIndex)
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
executionPayloadAvail, err := beaconState.ExecutionPayloadAvailability(slot)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrap(err, "failed to get execution payload availability status")
|
||||||
|
}
|
||||||
|
return executionPayloadAvail == committeeIndex, nil
|
||||||
|
}
|
||||||
110
beacon-chain/core/gloas/attestation_test.go
Normal file
110
beacon-chain/core/gloas/attestation_test.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package gloas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||||
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildStateWithBlockRoots(t *testing.T, stateSlot primitives.Slot, roots map[primitives.Slot][]byte) *state_native.BeaconState {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
cfg := params.BeaconConfig()
|
||||||
|
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||||
|
for slot, root := range roots {
|
||||||
|
blockRoots[slot%cfg.SlotsPerHistoricalRoot] = root
|
||||||
|
}
|
||||||
|
|
||||||
|
stProto := ðpb.BeaconStateGloas{
|
||||||
|
Slot: stateSlot,
|
||||||
|
BlockRoots: blockRoots,
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err := state_native.InitializeFromProtoGloas(stProto)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return state.(*state_native.BeaconState)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMatchingPayload(t *testing.T) {
|
||||||
|
t.Run("pre-gloas always true", func(t *testing.T) {
|
||||||
|
stIface, err := state_native.InitializeFromProtoElectra(ðpb.BeaconStateElectra{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ok, err := MatchingPayload(stIface, [32]byte{}, 0, 123)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("same slot requires committee index 0", func(t *testing.T) {
|
||||||
|
root := bytes.Repeat([]byte{0xAA}, 32)
|
||||||
|
state := buildStateWithBlockRoots(t, 6, map[primitives.Slot][]byte{
|
||||||
|
4: root,
|
||||||
|
3: bytes.Repeat([]byte{0xBB}, 32),
|
||||||
|
})
|
||||||
|
|
||||||
|
var rootArr [32]byte
|
||||||
|
copy(rootArr[:], root)
|
||||||
|
|
||||||
|
ok, err := MatchingPayload(state, rootArr, 4, 1)
|
||||||
|
require.ErrorContains(t, "committee index", err)
|
||||||
|
require.Equal(t, false, ok)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("same slot matches when committee index is 0", func(t *testing.T) {
|
||||||
|
root := bytes.Repeat([]byte{0xAA}, 32)
|
||||||
|
state := buildStateWithBlockRoots(t, 6, map[primitives.Slot][]byte{
|
||||||
|
4: root,
|
||||||
|
3: bytes.Repeat([]byte{0xBB}, 32),
|
||||||
|
})
|
||||||
|
|
||||||
|
var rootArr [32]byte
|
||||||
|
copy(rootArr[:], root)
|
||||||
|
|
||||||
|
ok, err := MatchingPayload(state, rootArr, 4, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("non same slot checks payload availability", func(t *testing.T) {
|
||||||
|
cfg := params.BeaconConfig()
|
||||||
|
root := bytes.Repeat([]byte{0xAA}, 32)
|
||||||
|
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||||
|
blockRoots[4%cfg.SlotsPerHistoricalRoot] = bytes.Repeat([]byte{0xCC}, 32)
|
||||||
|
blockRoots[3%cfg.SlotsPerHistoricalRoot] = bytes.Repeat([]byte{0xBB}, 32)
|
||||||
|
|
||||||
|
availability := make([]byte, cfg.SlotsPerHistoricalRoot/8)
|
||||||
|
slotIndex := uint64(4)
|
||||||
|
availability[slotIndex/8] = byte(1 << (slotIndex % 8))
|
||||||
|
|
||||||
|
stIface, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{
|
||||||
|
Slot: 6,
|
||||||
|
BlockRoots: blockRoots,
|
||||||
|
ExecutionPayloadAvailability: availability,
|
||||||
|
Fork: ðpb.Fork{
|
||||||
|
CurrentVersion: bytes.Repeat([]byte{0x66}, 4),
|
||||||
|
PreviousVersion: bytes.Repeat([]byte{0x66}, 4),
|
||||||
|
Epoch: 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
state := stIface.(*state_native.BeaconState)
|
||||||
|
require.Equal(t, version.Gloas, state.Version())
|
||||||
|
|
||||||
|
var rootArr [32]byte
|
||||||
|
copy(rootArr[:], root)
|
||||||
|
|
||||||
|
ok, err := MatchingPayload(state, rootArr, 4, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
|
|
||||||
|
ok, err = MatchingPayload(state, rootArr, 4, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, false, ok)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ type writeOnlyGloasFields interface {
|
|||||||
RotateBuilderPendingPayments() error
|
RotateBuilderPendingPayments() error
|
||||||
AppendBuilderPendingWithdrawals([]*ethpb.BuilderPendingWithdrawal) error
|
AppendBuilderPendingWithdrawals([]*ethpb.BuilderPendingWithdrawal) error
|
||||||
UpdateExecutionPayloadAvailabilityAtIndex(idx uint64, val byte) error
|
UpdateExecutionPayloadAvailabilityAtIndex(idx uint64, val byte) error
|
||||||
|
UpdatePendingPaymentWeight(att ethpb.Att, indices []uint64, participatedFlags map[uint8]bool) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type readOnlyGloasFields interface {
|
type readOnlyGloasFields interface {
|
||||||
@@ -20,5 +21,8 @@ type readOnlyGloasFields interface {
|
|||||||
IsActiveBuilder(primitives.BuilderIndex) (bool, error)
|
IsActiveBuilder(primitives.BuilderIndex) (bool, error)
|
||||||
CanBuilderCoverBid(primitives.BuilderIndex, primitives.Gwei) (bool, error)
|
CanBuilderCoverBid(primitives.BuilderIndex, primitives.Gwei) (bool, error)
|
||||||
LatestBlockHash() ([32]byte, error)
|
LatestBlockHash() ([32]byte, error)
|
||||||
|
IsAttestationSameSlot(blockRoot [32]byte, slot primitives.Slot) (bool, error)
|
||||||
|
BuilderPendingPayment(index uint64) (*ethpb.BuilderPendingPayment, error)
|
||||||
BuilderPendingPayments() ([]*ethpb.BuilderPendingPayment, error)
|
BuilderPendingPayments() ([]*ethpb.BuilderPendingPayment, error)
|
||||||
|
ExecutionPayloadAvailability(slot primitives.Slot) (uint64, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
package state_native
|
package state_native
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
||||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LatestBlockHash returns the hash of the latest execution block.
|
// LatestBlockHash returns the hash of the latest execution block.
|
||||||
@@ -26,6 +29,45 @@ func (b *BeaconState) LatestBlockHash() ([32]byte, error) {
|
|||||||
return [32]byte(b.latestBlockHash), nil
|
return [32]byte(b.latestBlockHash), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsAttestationSameSlot checks if the attestation is for the same slot as the block root in the state.
|
||||||
|
// Spec v1.7.0-alpha pseudocode:
|
||||||
|
//
|
||||||
|
// is_attestation_same_slot(state, data):
|
||||||
|
// if data.slot == 0:
|
||||||
|
// return True
|
||||||
|
//
|
||||||
|
// blockroot = data.beacon_block_root
|
||||||
|
// slot_blockroot = get_block_root_at_slot(state, data.slot)
|
||||||
|
// prev_blockroot = get_block_root_at_slot(state, Slot(data.slot - 1))
|
||||||
|
//
|
||||||
|
// return blockroot == slot_blockroot and blockroot != prev_blockroot
|
||||||
|
func (b *BeaconState) IsAttestationSameSlot(blockRoot [32]byte, slot primitives.Slot) (bool, error) {
|
||||||
|
if b.version < version.Gloas {
|
||||||
|
return false, errNotSupported("IsAttestationSameSlot", b.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.lock.RLock()
|
||||||
|
defer b.lock.RUnlock()
|
||||||
|
|
||||||
|
if slot == 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
blockRootAtSlot, err := helpers.BlockRootAtSlot(b, slot)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrapf(err, "block root at slot %d", slot)
|
||||||
|
}
|
||||||
|
matchingBlockRoot := bytes.Equal(blockRoot[:], blockRootAtSlot)
|
||||||
|
|
||||||
|
blockRootAtPrevSlot, err := helpers.BlockRootAtSlot(b, slot-1)
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.Wrapf(err, "block root at slot %d", slot-1)
|
||||||
|
}
|
||||||
|
matchingPrevBlockRoot := bytes.Equal(blockRoot[:], blockRootAtPrevSlot)
|
||||||
|
|
||||||
|
return matchingBlockRoot && !matchingPrevBlockRoot, nil
|
||||||
|
}
|
||||||
|
|
||||||
// BuilderPubkey returns the builder pubkey at the provided index.
|
// BuilderPubkey returns the builder pubkey at the provided index.
|
||||||
func (b *BeaconState) BuilderPubkey(builderIndex primitives.BuilderIndex) ([fieldparams.BLSPubkeyLength]byte, error) {
|
func (b *BeaconState) BuilderPubkey(builderIndex primitives.BuilderIndex) ([fieldparams.BLSPubkeyLength]byte, error) {
|
||||||
if b.version < version.Gloas {
|
if b.version < version.Gloas {
|
||||||
@@ -147,3 +189,36 @@ func (b *BeaconState) BuilderPendingPayments() ([]*ethpb.BuilderPendingPayment,
|
|||||||
|
|
||||||
return b.builderPendingPaymentsVal(), nil
|
return b.builderPendingPaymentsVal(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BuilderPendingPayment returns the builder pending payment for the given index.
|
||||||
|
func (b *BeaconState) BuilderPendingPayment(index uint64) (*ethpb.BuilderPendingPayment, error) {
|
||||||
|
if b.version < version.Gloas {
|
||||||
|
return nil, errNotSupported("BuilderPendingPayment", b.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.lock.RLock()
|
||||||
|
defer b.lock.RUnlock()
|
||||||
|
|
||||||
|
if index >= uint64(len(b.builderPendingPayments)) {
|
||||||
|
return nil, fmt.Errorf("builder pending payment index %d out of range (len=%d)", index, len(b.builderPendingPayments))
|
||||||
|
}
|
||||||
|
return ethpb.CopyBuilderPendingPayment(b.builderPendingPayments[index]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecutionPayloadAvailability returns the execution payload availability bit for the given slot.
|
||||||
|
func (b *BeaconState) ExecutionPayloadAvailability(slot primitives.Slot) (uint64, error) {
|
||||||
|
if b.version < version.Gloas {
|
||||||
|
return 0, errNotSupported("ExecutionPayloadAvailability", b.version)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.lock.RLock()
|
||||||
|
defer b.lock.RUnlock()
|
||||||
|
|
||||||
|
slotIndex := slot % params.BeaconConfig().SlotsPerHistoricalRoot
|
||||||
|
byteIndex := slotIndex / 8
|
||||||
|
bitIndex := slotIndex % 8
|
||||||
|
|
||||||
|
bit := (b.executionPayloadAvailability[byteIndex] >> bitIndex) & 1
|
||||||
|
|
||||||
|
return uint64(bit), nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -44,6 +44,92 @@ func TestLatestBlockHash(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsAttestationSameSlot(t *testing.T) {
|
||||||
|
buildStateWithBlockRoots := func(t *testing.T, stateSlot primitives.Slot, roots map[primitives.Slot][]byte) *state_native.BeaconState {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
cfg := params.BeaconConfig()
|
||||||
|
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||||
|
for slot, root := range roots {
|
||||||
|
blockRoots[slot%cfg.SlotsPerHistoricalRoot] = root
|
||||||
|
}
|
||||||
|
|
||||||
|
stIface, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{
|
||||||
|
Slot: stateSlot,
|
||||||
|
BlockRoots: blockRoots,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
return stIface.(*state_native.BeaconState)
|
||||||
|
}
|
||||||
|
|
||||||
|
rootA := bytes.Repeat([]byte{0xAA}, 32)
|
||||||
|
rootB := bytes.Repeat([]byte{0xBB}, 32)
|
||||||
|
rootC := bytes.Repeat([]byte{0xCC}, 32)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
stateSlot primitives.Slot
|
||||||
|
slot primitives.Slot
|
||||||
|
blockRoot []byte
|
||||||
|
roots map[primitives.Slot][]byte
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "slot zero always true",
|
||||||
|
stateSlot: 1,
|
||||||
|
slot: 0,
|
||||||
|
blockRoot: rootA,
|
||||||
|
roots: map[primitives.Slot][]byte{},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matching current different previous",
|
||||||
|
stateSlot: 6,
|
||||||
|
slot: 4,
|
||||||
|
blockRoot: rootA,
|
||||||
|
roots: map[primitives.Slot][]byte{
|
||||||
|
4: rootA,
|
||||||
|
3: rootB,
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "matching current same previous",
|
||||||
|
stateSlot: 6,
|
||||||
|
slot: 4,
|
||||||
|
blockRoot: rootA,
|
||||||
|
roots: map[primitives.Slot][]byte{
|
||||||
|
4: rootA,
|
||||||
|
3: rootA,
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non matching current",
|
||||||
|
stateSlot: 6,
|
||||||
|
slot: 4,
|
||||||
|
blockRoot: rootC,
|
||||||
|
roots: map[primitives.Slot][]byte{
|
||||||
|
4: rootA,
|
||||||
|
3: rootB,
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
st := buildStateWithBlockRoots(t, tt.stateSlot, tt.roots)
|
||||||
|
var rootArr [32]byte
|
||||||
|
copy(rootArr[:], tt.blockRoot)
|
||||||
|
|
||||||
|
got, err := st.IsAttestationSameSlot(rootArr, tt.slot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBuilderPubkey(t *testing.T) {
|
func TestBuilderPubkey(t *testing.T) {
|
||||||
t.Run("returns error before gloas", func(t *testing.T) {
|
t.Run("returns error before gloas", func(t *testing.T) {
|
||||||
stIface, _ := util.DeterministicGenesisState(t, 1)
|
stIface, _ := util.DeterministicGenesisState(t, 1)
|
||||||
@@ -166,3 +252,79 @@ func TestBuilderPendingPayments_UnsupportedVersion(t *testing.T) {
|
|||||||
_, err = st.BuilderPendingPayments()
|
_, err = st.BuilderPendingPayments()
|
||||||
require.ErrorContains(t, "BuilderPendingPayments", err)
|
require.ErrorContains(t, "BuilderPendingPayments", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuilderPendingPayment(t *testing.T) {
|
||||||
|
t.Run("returns copy", func(t *testing.T) {
|
||||||
|
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
|
||||||
|
payments := make([]*ethpb.BuilderPendingPayment, 2*slotsPerEpoch)
|
||||||
|
target := uint64(slotsPerEpoch + 1)
|
||||||
|
payments[target] = ðpb.BuilderPendingPayment{Weight: 10}
|
||||||
|
|
||||||
|
st, err := state_native.InitializeFromProtoUnsafeGloas(ðpb.BeaconStateGloas{
|
||||||
|
BuilderPendingPayments: payments,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
payment, err := st.BuilderPendingPayment(target)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// mutate returned copy
|
||||||
|
payment.Weight = 99
|
||||||
|
|
||||||
|
original, err := st.BuilderPendingPayment(target)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, uint64(10), uint64(original.Weight))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("unsupported version", func(t *testing.T) {
|
||||||
|
stIface, err := state_native.InitializeFromProtoElectra(ðpb.BeaconStateElectra{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
st := stIface.(*state_native.BeaconState)
|
||||||
|
|
||||||
|
_, err = st.BuilderPendingPayment(0)
|
||||||
|
require.ErrorContains(t, "BuilderPendingPayment", err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("out of range", func(t *testing.T) {
|
||||||
|
stIface, err := state_native.InitializeFromProtoUnsafeGloas(ðpb.BeaconStateGloas{
|
||||||
|
BuilderPendingPayments: []*ethpb.BuilderPendingPayment{},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = stIface.BuilderPendingPayment(0)
|
||||||
|
require.ErrorContains(t, "out of range", err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecutionPayloadAvailability(t *testing.T) {
|
||||||
|
t.Run("unsupported version", func(t *testing.T) {
|
||||||
|
stIface, err := state_native.InitializeFromProtoElectra(ðpb.BeaconStateElectra{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
st := stIface.(*state_native.BeaconState)
|
||||||
|
|
||||||
|
_, err = st.ExecutionPayloadAvailability(0)
|
||||||
|
require.ErrorContains(t, "ExecutionPayloadAvailability", err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("reads expected bit", func(t *testing.T) {
|
||||||
|
// Ensure the backing slice is large enough.
|
||||||
|
availability := make([]byte, params.BeaconConfig().SlotsPerHistoricalRoot/8)
|
||||||
|
|
||||||
|
// Pick a slot and set its corresponding bit.
|
||||||
|
slot := primitives.Slot(9) // byteIndex=1, bitIndex=1
|
||||||
|
availability[1] = 0b00000010
|
||||||
|
|
||||||
|
stIface, err := state_native.InitializeFromProtoUnsafeGloas(ðpb.BeaconStateGloas{
|
||||||
|
ExecutionPayloadAvailability: availability,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
bit, err := stIface.ExecutionPayloadAvailability(slot)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, uint64(1), bit)
|
||||||
|
|
||||||
|
otherBit, err := stIface.ExecutionPayloadAvailability(8)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, uint64(0), otherBit)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RotateBuilderPendingPayments rotates the queue by dropping slots per epoch payments from the
|
// RotateBuilderPendingPayments rotates the queue by dropping slots per epoch payments from the
|
||||||
@@ -161,3 +162,123 @@ func (b *BeaconState) UpdateExecutionPayloadAvailabilityAtIndex(idx uint64, val
|
|||||||
b.markFieldAsDirty(types.ExecutionPayloadAvailability)
|
b.markFieldAsDirty(types.ExecutionPayloadAvailability)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdatePendingPaymentWeight updates the builder pending payment weight based on attestation participation.
|
||||||
|
//
|
||||||
|
// This is a no-op for pre-Gloas forks.
|
||||||
|
//
|
||||||
|
// Spec v1.7.0-alpha pseudocode:
|
||||||
|
//
|
||||||
|
// if data.target.epoch == get_current_epoch(state):
|
||||||
|
// current_epoch_target = True
|
||||||
|
// epoch_participation = state.current_epoch_participation
|
||||||
|
// payment = state.builder_pending_payments[SLOTS_PER_EPOCH + data.slot % SLOTS_PER_EPOCH]
|
||||||
|
// else:
|
||||||
|
// current_epoch_target = False
|
||||||
|
// epoch_participation = state.previous_epoch_participation
|
||||||
|
// payment = state.builder_pending_payments[data.slot % SLOTS_PER_EPOCH]
|
||||||
|
//
|
||||||
|
// proposer_reward_numerator = 0
|
||||||
|
// for index in get_attesting_indices(state, attestation):
|
||||||
|
// will_set_new_flag = False
|
||||||
|
// for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
|
||||||
|
// if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index):
|
||||||
|
// epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
|
||||||
|
// proposer_reward_numerator += get_base_reward(state, index) * weight
|
||||||
|
// # [New in Gloas:EIP7732]
|
||||||
|
// will_set_new_flag = True
|
||||||
|
// if (
|
||||||
|
// will_set_new_flag
|
||||||
|
// and is_attestation_same_slot(state, data)
|
||||||
|
// and payment.withdrawal.amount > 0
|
||||||
|
// ):
|
||||||
|
// payment.weight += state.validators[index].effective_balance
|
||||||
|
// if current_epoch_target:
|
||||||
|
// state.builder_pending_payments[SLOTS_PER_EPOCH + data.slot % SLOTS_PER_EPOCH] = payment
|
||||||
|
// else:
|
||||||
|
// state.builder_pending_payments[data.slot % SLOTS_PER_EPOCH] = payment
|
||||||
|
func (b *BeaconState) UpdatePendingPaymentWeight(att ethpb.Att, indices []uint64, participatedFlags map[uint8]bool) error {
|
||||||
|
var (
|
||||||
|
paymentSlot primitives.Slot
|
||||||
|
currentPayment *ethpb.BuilderPendingPayment
|
||||||
|
weight primitives.Gwei
|
||||||
|
)
|
||||||
|
|
||||||
|
early, err := func() (bool, error) {
|
||||||
|
b.lock.RLock()
|
||||||
|
defer b.lock.RUnlock()
|
||||||
|
|
||||||
|
if b.version < version.Gloas {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
data := att.GetData()
|
||||||
|
var beaconBlockRoot [32]byte
|
||||||
|
copy(beaconBlockRoot[:], data.BeaconBlockRoot)
|
||||||
|
sameSlot, err := b.IsAttestationSameSlot(beaconBlockRoot, data.Slot)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !sameSlot {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
|
||||||
|
var epochParticipation []byte
|
||||||
|
|
||||||
|
if data.Target != nil && data.Target.Epoch == slots.ToEpoch(b.slot) {
|
||||||
|
paymentSlot = slotsPerEpoch + (data.Slot % slotsPerEpoch)
|
||||||
|
epochParticipation = b.currentEpochParticipation
|
||||||
|
} else {
|
||||||
|
paymentSlot = data.Slot % slotsPerEpoch
|
||||||
|
epochParticipation = b.previousEpochParticipation
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint64(paymentSlot) >= uint64(len(b.builderPendingPayments)) {
|
||||||
|
return false, fmt.Errorf("builder pending payments index %d out of range (len=%d)", paymentSlot, len(b.builderPendingPayments))
|
||||||
|
}
|
||||||
|
currentPayment = b.builderPendingPayments[paymentSlot]
|
||||||
|
if currentPayment.Withdrawal.Amount == 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := params.BeaconConfig()
|
||||||
|
flagIndices := []uint8{cfg.TimelySourceFlagIndex, cfg.TimelyTargetFlagIndex, cfg.TimelyHeadFlagIndex}
|
||||||
|
for _, idx := range indices {
|
||||||
|
if idx >= uint64(len(epochParticipation)) {
|
||||||
|
return false, fmt.Errorf("index %d exceeds participation length %d", idx, len(epochParticipation))
|
||||||
|
}
|
||||||
|
participation := epochParticipation[idx]
|
||||||
|
for _, f := range flagIndices {
|
||||||
|
if !participatedFlags[f] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if participation&(1<<f) == 0 {
|
||||||
|
v, err := b.validatorAtIndexReadOnly(primitives.ValidatorIndex(idx))
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("validator at index %d: %w", idx, err)
|
||||||
|
}
|
||||||
|
weight += primitives.Gwei(v.EffectiveBalance())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if early || weight == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b.lock.Lock()
|
||||||
|
defer b.lock.Unlock()
|
||||||
|
|
||||||
|
newPayment := ethpb.CopyBuilderPendingPayment(currentPayment)
|
||||||
|
newPayment.Weight += weight
|
||||||
|
b.builderPendingPayments[paymentSlot] = newPayment
|
||||||
|
b.markFieldAsDirty(types.BuilderPendingPayments)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testExecutionPayloadBid struct {
|
type testExecutionPayloadBid struct {
|
||||||
@@ -181,6 +182,99 @@ func TestClearBuilderPendingPayment(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdatePendingPaymentWeight(t *testing.T) {
|
||||||
|
cfg := params.BeaconConfig()
|
||||||
|
slotsPerEpoch := cfg.SlotsPerEpoch
|
||||||
|
slot := primitives.Slot(4)
|
||||||
|
stateSlot := slot + 1
|
||||||
|
stateEpoch := slots.ToEpoch(stateSlot)
|
||||||
|
|
||||||
|
rootA := bytes.Repeat([]byte{0xAA}, 32)
|
||||||
|
rootB := bytes.Repeat([]byte{0xBB}, 32)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
targetEpoch primitives.Epoch
|
||||||
|
blockRoot []byte
|
||||||
|
initialAmount primitives.Gwei
|
||||||
|
initialWeight primitives.Gwei
|
||||||
|
wantWeight primitives.Gwei
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "same slot current epoch adds weight",
|
||||||
|
targetEpoch: stateEpoch,
|
||||||
|
blockRoot: rootA,
|
||||||
|
initialAmount: 1,
|
||||||
|
initialWeight: 0,
|
||||||
|
wantWeight: primitives.Gwei(cfg.MinActivationBalance),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "same slot zero amount no weight change",
|
||||||
|
targetEpoch: stateEpoch,
|
||||||
|
blockRoot: rootA,
|
||||||
|
initialAmount: 0,
|
||||||
|
initialWeight: 5,
|
||||||
|
wantWeight: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non matching block root no change",
|
||||||
|
targetEpoch: stateEpoch,
|
||||||
|
blockRoot: rootB,
|
||||||
|
initialAmount: 1,
|
||||||
|
initialWeight: 7,
|
||||||
|
wantWeight: 7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "previous epoch target uses earlier slot",
|
||||||
|
targetEpoch: stateEpoch - 1,
|
||||||
|
blockRoot: rootA,
|
||||||
|
initialAmount: 1,
|
||||||
|
initialWeight: 0,
|
||||||
|
wantWeight: primitives.Gwei(cfg.MinActivationBalance),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var paymentIdx int
|
||||||
|
if tt.targetEpoch == stateEpoch {
|
||||||
|
paymentIdx = int(slotsPerEpoch + (slot % slotsPerEpoch))
|
||||||
|
} else {
|
||||||
|
paymentIdx = int(slot % slotsPerEpoch)
|
||||||
|
}
|
||||||
|
state := buildGloasStateForPaymentWeightTest(t, stateSlot, paymentIdx, tt.initialAmount, tt.initialWeight, map[primitives.Slot][]byte{
|
||||||
|
slot: tt.blockRoot,
|
||||||
|
slot - 1: rootB,
|
||||||
|
})
|
||||||
|
|
||||||
|
att := ðpb.Attestation{
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: slot,
|
||||||
|
CommitteeIndex: 0,
|
||||||
|
BeaconBlockRoot: tt.blockRoot,
|
||||||
|
Source: ðpb.Checkpoint{},
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: tt.targetEpoch,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
participatedFlags := map[uint8]bool{
|
||||||
|
cfg.TimelySourceFlagIndex: true,
|
||||||
|
cfg.TimelyTargetFlagIndex: true,
|
||||||
|
cfg.TimelyHeadFlagIndex: true,
|
||||||
|
}
|
||||||
|
indices := []uint64{0}
|
||||||
|
|
||||||
|
require.NoError(t, state.UpdatePendingPaymentWeight(att, indices, participatedFlags))
|
||||||
|
|
||||||
|
payment, err := state.BuilderPendingPayment(uint64(paymentIdx))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tt.wantWeight, payment.Weight)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRotateBuilderPendingPayments(t *testing.T) {
|
func TestRotateBuilderPendingPayments(t *testing.T) {
|
||||||
totalPayments := 2 * params.BeaconConfig().SlotsPerEpoch
|
totalPayments := 2 * params.BeaconConfig().SlotsPerEpoch
|
||||||
payments := make([]*ethpb.BuilderPendingPayment, totalPayments)
|
payments := make([]*ethpb.BuilderPendingPayment, totalPayments)
|
||||||
@@ -318,6 +412,79 @@ func TestUpdateExecutionPayloadAvailabilityAtIndex_OutOfRange(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildGloasStateForPaymentWeightTest(
|
||||||
|
t *testing.T,
|
||||||
|
stateSlot primitives.Slot,
|
||||||
|
paymentIdx int,
|
||||||
|
amount primitives.Gwei,
|
||||||
|
weight primitives.Gwei,
|
||||||
|
roots map[primitives.Slot][]byte,
|
||||||
|
) *BeaconState {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
cfg := params.BeaconConfig()
|
||||||
|
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||||
|
for slot, root := range roots {
|
||||||
|
blockRoots[slot%cfg.SlotsPerHistoricalRoot] = root
|
||||||
|
}
|
||||||
|
|
||||||
|
stateRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||||
|
for i := range stateRoots {
|
||||||
|
stateRoots[i] = bytes.Repeat([]byte{0x44}, 32)
|
||||||
|
}
|
||||||
|
randaoMixes := make([][]byte, cfg.EpochsPerHistoricalVector)
|
||||||
|
for i := range randaoMixes {
|
||||||
|
randaoMixes[i] = bytes.Repeat([]byte{0x55}, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
validator := ðpb.Validator{
|
||||||
|
PublicKey: bytes.Repeat([]byte{0x01}, 48),
|
||||||
|
WithdrawalCredentials: append([]byte{cfg.ETH1AddressWithdrawalPrefixByte}, bytes.Repeat([]byte{0x02}, 31)...),
|
||||||
|
EffectiveBalance: cfg.MinActivationBalance,
|
||||||
|
}
|
||||||
|
|
||||||
|
payments := make([]*ethpb.BuilderPendingPayment, cfg.SlotsPerEpoch*2)
|
||||||
|
for i := range payments {
|
||||||
|
payments[i] = ðpb.BuilderPendingPayment{
|
||||||
|
Withdrawal: ðpb.BuilderPendingWithdrawal{
|
||||||
|
FeeRecipient: make([]byte, 20),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
payments[paymentIdx] = ðpb.BuilderPendingPayment{
|
||||||
|
Weight: weight,
|
||||||
|
Withdrawal: ðpb.BuilderPendingWithdrawal{
|
||||||
|
FeeRecipient: make([]byte, 20),
|
||||||
|
Amount: amount,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
execPayloadAvailability := make([]byte, cfg.SlotsPerHistoricalRoot/8)
|
||||||
|
|
||||||
|
stProto := ðpb.BeaconStateGloas{
|
||||||
|
Slot: stateSlot,
|
||||||
|
GenesisValidatorsRoot: bytes.Repeat([]byte{0x33}, 32),
|
||||||
|
BlockRoots: blockRoots,
|
||||||
|
StateRoots: stateRoots,
|
||||||
|
RandaoMixes: randaoMixes,
|
||||||
|
ExecutionPayloadAvailability: execPayloadAvailability,
|
||||||
|
Validators: []*ethpb.Validator{validator},
|
||||||
|
Balances: []uint64{cfg.MinActivationBalance},
|
||||||
|
CurrentEpochParticipation: []byte{0},
|
||||||
|
PreviousEpochParticipation: []byte{0},
|
||||||
|
BuilderPendingPayments: payments,
|
||||||
|
Fork: ðpb.Fork{
|
||||||
|
CurrentVersion: bytes.Repeat([]byte{0x66}, 4),
|
||||||
|
PreviousVersion: bytes.Repeat([]byte{0x66}, 4),
|
||||||
|
Epoch: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
statePb, err := InitializeFromProtoGloas(stProto)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return statePb.(*BeaconState)
|
||||||
|
}
|
||||||
|
|
||||||
func newGloasStateWithAvailability(t *testing.T, availability []byte) *BeaconState {
|
func newGloasStateWithAvailability(t *testing.T, availability []byte) *BeaconState {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
|||||||
3
changelog/t_gloas-process-attestations.md
Normal file
3
changelog/t_gloas-process-attestations.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
### Added
|
||||||
|
|
||||||
|
- Added process attestation for gloas
|
||||||
@@ -201,6 +201,7 @@ go_test(
|
|||||||
"fulu__sanity__slots_test.go",
|
"fulu__sanity__slots_test.go",
|
||||||
"fulu__ssz_static__ssz_static_test.go",
|
"fulu__ssz_static__ssz_static_test.go",
|
||||||
"gloas__epoch_processing__process_builder_pending_payments_test.go",
|
"gloas__epoch_processing__process_builder_pending_payments_test.go",
|
||||||
|
"gloas__operations__attestation_test.go",
|
||||||
"gloas__operations__execution_payload_header_test.go",
|
"gloas__operations__execution_payload_header_test.go",
|
||||||
"gloas__operations__proposer_slashing_test.go",
|
"gloas__operations__proposer_slashing_test.go",
|
||||||
"gloas__sanity__slots_test.go",
|
"gloas__sanity__slots_test.go",
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package mainnet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMainnet_Gloas_Operations_Attestation(t *testing.T) {
|
||||||
|
operations.RunAttestationTest(t, "mainnet")
|
||||||
|
}
|
||||||
@@ -207,6 +207,7 @@ go_test(
|
|||||||
"fulu__sanity__slots_test.go",
|
"fulu__sanity__slots_test.go",
|
||||||
"fulu__ssz_static__ssz_static_test.go",
|
"fulu__ssz_static__ssz_static_test.go",
|
||||||
"gloas__epoch_processing__process_builder_pending_payments_test.go",
|
"gloas__epoch_processing__process_builder_pending_payments_test.go",
|
||||||
|
"gloas__operations__attestation_test.go",
|
||||||
"gloas__operations__execution_payload_bid_test.go",
|
"gloas__operations__execution_payload_bid_test.go",
|
||||||
"gloas__operations__proposer_slashing_test.go",
|
"gloas__operations__proposer_slashing_test.go",
|
||||||
"gloas__sanity__slots_test.go",
|
"gloas__sanity__slots_test.go",
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package minimal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMinimal_Gloas_Operations_Attestation(t *testing.T) {
|
||||||
|
operations.RunAttestationTest(t, "minimal")
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ go_library(
|
|||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
testonly = True,
|
testonly = True,
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"attestation.go",
|
||||||
"execution_payload_bid.go",
|
"execution_payload_bid.go",
|
||||||
"helpers.go",
|
"helpers.go",
|
||||||
"proposer_slashing.go",
|
"proposer_slashing.go",
|
||||||
@@ -11,6 +12,7 @@ go_library(
|
|||||||
importpath = "github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations",
|
importpath = "github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//beacon-chain/core/altair:go_default_library",
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//beacon-chain/state/state-native:go_default_library",
|
"//beacon-chain/state/state-native:go_default_library",
|
||||||
"//consensus-types/blocks:go_default_library",
|
"//consensus-types/blocks:go_default_library",
|
||||||
|
|||||||
26
testing/spectest/shared/gloas/operations/attestation.go
Normal file
26
testing/spectest/shared/gloas/operations/attestation.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package operations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/altair"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||||
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||||
|
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||||
|
common "github.com/OffchainLabs/prysm/v7/testing/spectest/shared/common/operations"
|
||||||
|
)
|
||||||
|
|
||||||
|
func blockWithAttestation(attestationSSZ []byte) (interfaces.SignedBeaconBlock, error) {
|
||||||
|
att := ðpb.AttestationElectra{}
|
||||||
|
if err := att.UnmarshalSSZ(attestationSSZ); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b := ðpb.BeaconBlockGloas{}
|
||||||
|
b.Body = ðpb.BeaconBlockBodyGloas{Attestations: []*ethpb.AttestationElectra{att}}
|
||||||
|
return blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockGloas{Block: b})
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunAttestationTest(t *testing.T, config string) {
|
||||||
|
common.RunAttestationTest(t, config, version.String(version.Gloas), blockWithAttestation, altair.ProcessAttestationsNoVerifySignature, sszToState)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user