Compare commits

..

1 Commits

Author SHA1 Message Date
Bastin
06aaf4aa36 update lightclient code for gloas 2026-01-27 14:40:49 +01:00
57 changed files with 46 additions and 2333 deletions

View File

@@ -4,9 +4,6 @@ go_library(
name = "go_default_library",
srcs = [
"bid.go",
"deposit_request.go",
"log.go",
"payload.go",
"payload_attestation.go",
"pending_payment.go",
"proposer_slashing.go",
@@ -15,7 +12,6 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/requests:go_default_library",
"//beacon-chain/core/signing:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/state:go_default_library",
@@ -29,13 +25,9 @@ go_library(
"//crypto/bls/common:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],
)
@@ -43,9 +35,7 @@ go_test(
name = "go_default_test",
srcs = [
"bid_test.go",
"deposit_request_test.go",
"payload_attestation_test.go",
"payload_test.go",
"pending_payment_test.go",
"proposer_slashing_test.go",
],
@@ -55,7 +45,6 @@ go_test(
"//beacon-chain/core/signing:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//beacon-chain/state/testing:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
@@ -63,7 +52,6 @@ go_test(
"//crypto/bls:go_default_library",
"//crypto/bls/common:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",

View File

@@ -1,160 +0,0 @@
package gloas
import (
"context"
"fmt"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
func processDepositRequests(ctx context.Context, beaconState state.BeaconState, requests []*enginev1.DepositRequest) error {
if len(requests) == 0 {
return nil
}
for _, receipt := range requests {
if err := processDepositRequest(beaconState, receipt); err != nil {
return errors.Wrap(err, "could not apply deposit request")
}
}
return nil
}
// processDepositRequest processes the specific deposit request
// Spec v1.7.0-alpha.0 (pseudocode):
// def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None:
//
// # [New in Gloas:EIP7732]
// builder_pubkeys = [b.pubkey for b in state.builders]
// validator_pubkeys = [v.pubkey for v in state.validators]
//
// # [New in Gloas:EIP7732]
// # Regardless of the withdrawal credentials prefix, if a builder/validator
// # already exists with this pubkey, apply the deposit to their balance
// is_builder = deposit_request.pubkey in builder_pubkeys
// is_validator = deposit_request.pubkey in validator_pubkeys
// is_builder_prefix = is_builder_withdrawal_credential(deposit_request.withdrawal_credentials)
// if is_builder or (is_builder_prefix and not is_validator):
//
// # Apply builder deposits immediately
// apply_deposit_for_builder(
// state,
// deposit_request.pubkey,
// deposit_request.withdrawal_credentials,
// deposit_request.amount,
// deposit_request.signature,
// )
// return
//
// # Add validator deposits to the queue
// state.pending_deposits.append(
// PendingDeposit(
// pubkey=deposit_request.pubkey,
// withdrawal_credentials=deposit_request.withdrawal_credentials,
// amount=deposit_request.amount,
// signature=deposit_request.signature,
// slot=state.slot,
// )
// )
func processDepositRequest(beaconState state.BeaconState, request *enginev1.DepositRequest) error {
if request == nil {
return errors.New("nil deposit request")
}
if beaconState.Version() >= version.Gloas {
pubkey := bytesutil.ToBytes48(request.Pubkey)
_, isValidator := beaconState.ValidatorIndexByPubkey(pubkey)
_, isBuilder := beaconState.BuilderIndexByPubkey(pubkey)
isBuilderPrefix := IsBuilderWithdrawalCredential(request.WithdrawalCredentials)
if isBuilder || (isBuilderPrefix && !isValidator) {
if err := ApplyDepositForBuilder(
beaconState,
request.Pubkey,
request.WithdrawalCredentials,
request.Amount,
request.Signature,
); err != nil {
return errors.Wrap(err, "could not apply builder deposit")
}
return nil
}
}
if err := beaconState.AppendPendingDeposit(&ethpb.PendingDeposit{
PublicKey: request.Pubkey,
WithdrawalCredentials: request.WithdrawalCredentials,
Amount: request.Amount,
Signature: request.Signature,
Slot: beaconState.Slot(),
}); err != nil {
return errors.Wrap(err, "could not append deposit request")
}
return nil
}
// ApplyDepositForBuilder processes an execution-layer deposit for a builder.
// Spec v1.7.0-alpha.0 (pseudocode):
// def apply_deposit_for_builder(
//
// state: BeaconState,
// pubkey: BLSPubkey,
// withdrawal_credentials: Bytes32,
// amount: uint64,
// signature: BLSSignature,
//
// ) -> None:
//
// builder_pubkeys = [b.pubkey for b in state.builders]
// if pubkey not in builder_pubkeys:
// # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
// if is_valid_deposit_signature(pubkey, withdrawal_credentials, amount, signature):
// add_builder_to_registry(state, pubkey, withdrawal_credentials, amount)
// else:
// # Increase balance by deposit amount
// builder_index = builder_pubkeys.index(pubkey)
// state.builders[builder_index].balance += amount
func ApplyDepositForBuilder(
beaconState state.BeaconState,
pubkey []byte,
withdrawalCredentials []byte,
amount uint64,
signature []byte,
) error {
pubkeyBytes := bytesutil.ToBytes48(pubkey)
if idx, exists := beaconState.BuilderIndexByPubkey(pubkeyBytes); exists {
return beaconState.IncreaseBuilderBalance(idx, amount)
}
valid, err := helpers.IsValidDepositSignature(&ethpb.Deposit_Data{
PublicKey: pubkey,
WithdrawalCredentials: withdrawalCredentials,
Amount: amount,
Signature: signature,
})
if err != nil {
return errors.Wrap(err, "could not verify deposit signature")
}
if !valid {
log.WithFields(logrus.Fields{
"pubkey": fmt.Sprintf("%x", pubkey),
}).Warn("ignoring builder deposit: invalid signature")
return nil
}
withdrawalCredBytes := bytesutil.ToBytes32(withdrawalCredentials)
return beaconState.AddBuilderFromDeposit(pubkeyBytes, withdrawalCredBytes, amount)
}
func IsBuilderWithdrawalCredential(withdrawalCredentials []byte) bool {
return len(withdrawalCredentials) == fieldparams.RootLength &&
withdrawalCredentials[0] == params.BeaconConfig().BuilderWithdrawalPrefixByte
}

View File

@@ -1,150 +0,0 @@
package gloas
import (
"bytes"
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
stateTesting "github.com/OffchainLabs/prysm/v7/beacon-chain/state/testing"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/crypto/bls"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
)
func TestProcessDepositRequests_EmptyAndNil(t *testing.T) {
st := newGloasState(t, nil, nil)
t.Run("empty requests continues", func(t *testing.T) {
err := processDepositRequests(t.Context(), st, []*enginev1.DepositRequest{})
require.NoError(t, err)
})
t.Run("nil request errors", func(t *testing.T) {
err := processDepositRequests(t.Context(), st, []*enginev1.DepositRequest{nil})
require.ErrorContains(t, "nil deposit request", err)
})
}
func TestProcessDepositRequest_BuilderDepositAddsBuilder(t *testing.T) {
sk, err := bls.RandKey()
require.NoError(t, err)
cred := builderWithdrawalCredentials()
pd := stateTesting.GeneratePendingDeposit(t, sk, 1234, cred, 0)
req := depositRequestFromPending(pd, 1)
st := newGloasState(t, nil, nil)
err = processDepositRequest(st, req)
require.NoError(t, err)
idx, ok := st.BuilderIndexByPubkey(toBytes48(req.Pubkey))
require.Equal(t, true, ok)
builder, err := st.Builder(idx)
require.NoError(t, err)
require.NotNil(t, builder)
require.DeepEqual(t, req.Pubkey, builder.Pubkey)
require.DeepEqual(t, []byte{cred[0]}, builder.Version)
require.DeepEqual(t, cred[12:], builder.ExecutionAddress)
require.Equal(t, uint64(1234), uint64(builder.Balance))
require.Equal(t, params.BeaconConfig().FarFutureEpoch, builder.WithdrawableEpoch)
pending, err := st.PendingDeposits()
require.NoError(t, err)
require.Equal(t, 0, len(pending))
}
func TestProcessDepositRequest_ExistingBuilderIncreasesBalance(t *testing.T) {
sk, err := bls.RandKey()
require.NoError(t, err)
pubkey := sk.PublicKey().Marshal()
builders := []*ethpb.Builder{
{
Pubkey: pubkey,
Version: []byte{0},
ExecutionAddress: bytes.Repeat([]byte{0x11}, 20),
Balance: 5,
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
},
}
st := newGloasState(t, nil, builders)
cred := validatorWithdrawalCredentials()
pd := stateTesting.GeneratePendingDeposit(t, sk, 200, cred, 0)
req := depositRequestFromPending(pd, 9)
err = processDepositRequest(st, req)
require.NoError(t, err)
idx, ok := st.BuilderIndexByPubkey(toBytes48(pubkey))
require.Equal(t, true, ok)
builder, err := st.Builder(idx)
require.NoError(t, err)
require.Equal(t, uint64(205), uint64(builder.Balance))
pending, err := st.PendingDeposits()
require.NoError(t, err)
require.Equal(t, 0, len(pending))
}
func TestApplyDepositForBuilder_InvalidSignatureIgnoresDeposit(t *testing.T) {
sk, err := bls.RandKey()
require.NoError(t, err)
cred := builderWithdrawalCredentials()
st := newGloasState(t, nil, nil)
err = ApplyDepositForBuilder(st, sk.PublicKey().Marshal(), cred[:], 100, make([]byte, 96))
require.NoError(t, err)
_, ok := st.BuilderIndexByPubkey(toBytes48(sk.PublicKey().Marshal()))
require.Equal(t, false, ok)
}
func newGloasState(t *testing.T, validators []*ethpb.Validator, builders []*ethpb.Builder) state.BeaconState {
t.Helper()
st, err := state_native.InitializeFromProtoGloas(&ethpb.BeaconStateGloas{
DepositRequestsStartIndex: params.BeaconConfig().UnsetDepositRequestsStartIndex,
Validators: validators,
Balances: make([]uint64, len(validators)),
PendingDeposits: []*ethpb.PendingDeposit{},
Builders: builders,
})
require.NoError(t, err)
return st
}
func depositRequestFromPending(pd *ethpb.PendingDeposit, index uint64) *enginev1.DepositRequest {
return &enginev1.DepositRequest{
Pubkey: pd.PublicKey,
WithdrawalCredentials: pd.WithdrawalCredentials,
Amount: pd.Amount,
Signature: pd.Signature,
Index: index,
}
}
func builderWithdrawalCredentials() [32]byte {
var cred [32]byte
cred[0] = params.BeaconConfig().BuilderWithdrawalPrefixByte
copy(cred[12:], bytes.Repeat([]byte{0x22}, 20))
return cred
}
func validatorWithdrawalCredentials() [32]byte {
var cred [32]byte
cred[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
copy(cred[12:], bytes.Repeat([]byte{0x33}, 20))
return cred
}
func toBytes48(b []byte) [48]byte {
var out [48]byte
copy(out[:], b)
return out
}

View File

@@ -1,9 +0,0 @@
// Code generated by hack/gen-logs.sh; DO NOT EDIT.
// This file is created and regenerated automatically. Anything added here might get removed.
package gloas
import "github.com/sirupsen/logrus"
// The prefix for logs from this package will be the text after the last slash in the package path.
// If you wish to change this, you should add your desired name in the runtime/logging/logrus-prefixed-formatter/prefix-replacement.go file.
var log = logrus.WithField("package", "beacon-chain/core/gloas")

View File

@@ -1,330 +0,0 @@
package gloas
import (
"bytes"
"context"
"fmt"
requests "github.com/OffchainLabs/prysm/v7/beacon-chain/core/requests"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/crypto/bls"
"github.com/OffchainLabs/prysm/v7/encoding/ssz"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/pkg/errors"
)
// ProcessExecutionPayload processes the signed execution payload envelope for the Gloas fork.
// Spec v1.7.0-alpha.0 (pseudocode):
// def process_execution_payload(
//
// state: BeaconState,
// signed_envelope: SignedExecutionPayloadEnvelope,
// execution_engine: ExecutionEngine,
// verify: bool = True,
//
// ) -> None:
//
// envelope = signed_envelope.message
// payload = envelope.payload
//
// if verify:
// assert verify_execution_payload_envelope_signature(state, signed_envelope)
//
// previous_state_root = hash_tree_root(state)
// if state.latest_block_header.state_root == Root():
// state.latest_block_header.state_root = previous_state_root
//
// assert envelope.beacon_block_root == hash_tree_root(state.latest_block_header)
// assert envelope.slot == state.slot
//
// committed_bid = state.latest_execution_payload_bid
// assert envelope.builder_index == committed_bid.builder_index
// assert committed_bid.blob_kzg_commitments_root == hash_tree_root(envelope.blob_kzg_commitments)
// assert committed_bid.prev_randao == payload.prev_randao
//
// assert hash_tree_root(payload.withdrawals) == hash_tree_root(state.payload_expected_withdrawals)
//
// assert committed_bid.gas_limit == payload.gas_limit
// assert committed_bid.block_hash == payload.block_hash
// assert payload.parent_hash == state.latest_block_hash
// assert payload.timestamp == compute_time_at_slot(state, state.slot)
// assert (
// len(envelope.blob_kzg_commitments)
// <= get_blob_parameters(get_current_epoch(state)).max_blobs_per_block
// )
// versioned_hashes = [
// kzg_commitment_to_versioned_hash(commitment) for commitment in envelope.blob_kzg_commitments
// ]
// requests = envelope.execution_requests
// assert execution_engine.verify_and_notify_new_payload(
// NewPayloadRequest(
// execution_payload=payload,
// versioned_hashes=versioned_hashes,
// parent_beacon_block_root=state.latest_block_header.parent_root,
// execution_requests=requests,
// )
// )
//
// for op in requests.deposits: process_deposit_request(state, op)
// for op in requests.withdrawals: process_withdrawal_request(state, op)
// for op in requests.consolidations: process_consolidation_request(state, op)
//
// payment = state.builder_pending_payments[SLOTS_PER_EPOCH + state.slot % SLOTS_PER_EPOCH]
// amount = payment.withdrawal.amount
// if amount > 0:
// state.builder_pending_withdrawals.append(payment.withdrawal)
// state.builder_pending_payments[SLOTS_PER_EPOCH + state.slot % SLOTS_PER_EPOCH] = (
// BuilderPendingPayment()
// )
//
// state.execution_payload_availability[state.slot % SLOTS_PER_HISTORICAL_ROOT] = 0b1
// state.latest_block_hash = payload.block_hash
//
// if verify:
// assert envelope.state_root == hash_tree_root(state)
func ProcessExecutionPayload(
ctx context.Context,
st state.BeaconState,
signedEnvelope interfaces.ROSignedExecutionPayloadEnvelope,
) error {
if err := verifyExecutionPayloadEnvelopeSignature(st, signedEnvelope); err != nil {
return errors.Wrap(err, "signature verification failed")
}
latestHeader := st.LatestBlockHeader()
if len(latestHeader.StateRoot) == 0 || bytes.Equal(latestHeader.StateRoot, make([]byte, 32)) {
previousStateRoot, err := st.HashTreeRoot(ctx)
if err != nil {
return errors.Wrap(err, "could not compute state root")
}
latestHeader.StateRoot = previousStateRoot[:]
if err := st.SetLatestBlockHeader(latestHeader); err != nil {
return errors.Wrap(err, "could not set latest block header")
}
}
blockHeaderRoot, err := latestHeader.HashTreeRoot()
if err != nil {
return errors.Wrap(err, "could not compute block header root")
}
envelope, err := signedEnvelope.Envelope()
if err != nil {
return errors.Wrap(err, "could not get envelope from signed envelope")
}
beaconBlockRoot := envelope.BeaconBlockRoot()
if !bytes.Equal(beaconBlockRoot[:], blockHeaderRoot[:]) {
return errors.Errorf("envelope beacon block root does not match state latest block header root: envelope=%#x, header=%#x", beaconBlockRoot, blockHeaderRoot)
}
if envelope.Slot() != st.Slot() {
return errors.Errorf("envelope slot does not match state slot: envelope=%d, state=%d", envelope.Slot(), st.Slot())
}
latestBid, err := st.LatestExecutionPayloadBid()
if err != nil {
return errors.Wrap(err, "could not get latest execution payload bid")
}
if latestBid == nil {
return errors.New("latest execution payload bid is nil")
}
if envelope.BuilderIndex() != latestBid.BuilderIndex() {
return errors.Errorf("envelope builder index does not match committed bid builder index: envelope=%d, bid=%d", envelope.BuilderIndex(), latestBid.BuilderIndex())
}
envelopeBlobCommitments := envelope.BlobKzgCommitments()
envelopeBlobRoot, err := ssz.KzgCommitmentsRoot(envelopeBlobCommitments)
if err != nil {
return errors.Wrap(err, "could not compute envelope blob KZG commitments root")
}
committedBlobRoot := latestBid.BlobKzgCommitmentsRoot()
if !bytes.Equal(committedBlobRoot[:], envelopeBlobRoot[:]) {
return errors.Errorf("committed bid blob KZG commitments root does not match envelope: bid=%#x, envelope=%#x", committedBlobRoot, envelopeBlobRoot)
}
payload, err := envelope.Execution()
if err != nil {
return errors.Wrap(err, "could not get execution payload from envelope")
}
withdrawals, err := payload.Withdrawals()
if err != nil {
return errors.Wrap(err, "could not get withdrawals from payload")
}
ok, err := st.WithdrawalsMatchPayloadExpected(withdrawals)
if err != nil {
return errors.Wrap(err, "could not validate payload withdrawals")
}
if !ok {
return errors.New("payload withdrawals do not match expected withdrawals")
}
if latestBid.GasLimit() != payload.GasLimit() {
return errors.Errorf("committed bid gas limit does not match payload gas limit: bid=%d, payload=%d", latestBid.GasLimit(), payload.GasLimit())
}
latestBidPrevRandao := latestBid.PrevRandao()
if !bytes.Equal(payload.PrevRandao(), latestBidPrevRandao[:]) {
return errors.Errorf("payload prev randao does not match committed bid prev randao: payload=%#x, bid=%#x", payload.PrevRandao(), latestBidPrevRandao)
}
bidBlockHash := latestBid.BlockHash()
payloadBlockHash := payload.BlockHash()
if !bytes.Equal(bidBlockHash[:], payloadBlockHash) {
return errors.Errorf("committed bid block hash does not match payload block hash: bid=%#x, payload=%#x", bidBlockHash, payloadBlockHash)
}
latestBlockHash, err := st.LatestBlockHash()
if err != nil {
return errors.Wrap(err, "could not get latest block hash")
}
if !bytes.Equal(payload.ParentHash(), latestBlockHash[:]) {
return errors.Errorf("payload parent hash does not match state latest block hash: payload=%#x, state=%#x", payload.ParentHash(), latestBlockHash)
}
t, err := slots.StartTime(st.GenesisTime(), st.Slot())
if err != nil {
return errors.Wrap(err, "could not compute timestamp")
}
if payload.Timestamp() != uint64(t.Unix()) {
return errors.Errorf("payload timestamp does not match expected timestamp: payload=%d, expected=%d", payload.Timestamp(), uint64(t.Unix()))
}
cfg := params.BeaconConfig()
maxBlobsPerBlock := cfg.MaxBlobsPerBlock(envelope.Slot())
if len(envelopeBlobCommitments) > maxBlobsPerBlock {
return errors.Errorf("too many blob KZG commitments: got=%d, max=%d", len(envelopeBlobCommitments), maxBlobsPerBlock)
}
if err := processExecutionRequests(ctx, st, envelope.ExecutionRequests()); err != nil {
return errors.Wrap(err, "could not process execution requests")
}
if err := st.QueueBuilderPayment(); err != nil {
return errors.Wrap(err, "could not queue builder payment")
}
if err := st.SetExecutionPayloadAvailability(st.Slot(), true); err != nil {
return errors.Wrap(err, "could not set execution payload availability")
}
if err := st.SetLatestBlockHash([32]byte(payload.BlockHash())); err != nil {
return errors.Wrap(err, "could not set latest block hash")
}
r, err := st.HashTreeRoot(ctx)
if err != nil {
return errors.Wrap(err, "could not get hash tree root")
}
if r != envelope.StateRoot() {
return fmt.Errorf("state root mismatch: expected %#x, got %#x", envelope.StateRoot(), r)
}
return nil
}
// processExecutionRequests processes deposits, withdrawals, and consolidations from execution requests.
// Spec v1.7.0-alpha.0 (pseudocode):
// for op in requests.deposits: process_deposit_request(state, op)
// for op in requests.withdrawals: process_withdrawal_request(state, op)
// for op in requests.consolidations: process_consolidation_request(state, op)
func processExecutionRequests(ctx context.Context, st state.BeaconState, rqs *enginev1.ExecutionRequests) error {
if err := processDepositRequests(ctx, st, rqs.Deposits); err != nil {
return errors.Wrap(err, "could not process deposit requests")
}
var err error
st, err = requests.ProcessWithdrawalRequests(ctx, st, rqs.Withdrawals)
if err != nil {
return errors.Wrap(err, "could not process withdrawal requests")
}
err = requests.ProcessConsolidationRequests(ctx, st, rqs.Consolidations)
if err != nil {
return errors.Wrap(err, "could not process consolidation requests")
}
return nil
}
// verifyExecutionPayloadEnvelopeSignature verifies the BLS signature on a signed execution payload envelope.
// Spec v1.7.0-alpha.0 (pseudocode):
// builder_index = signed_envelope.message.builder_index
// if builder_index == BUILDER_INDEX_SELF_BUILD:
//
// validator_index = state.latest_block_header.proposer_index
// pubkey = state.validators[validator_index].pubkey
//
// else:
//
// pubkey = state.builders[builder_index].pubkey
//
// signing_root = compute_signing_root(
//
// signed_envelope.message, get_domain(state, DOMAIN_BEACON_BUILDER)
//
// )
// return bls.Verify(pubkey, signing_root, signed_envelope.signature)
func verifyExecutionPayloadEnvelopeSignature(st state.BeaconState, signedEnvelope interfaces.ROSignedExecutionPayloadEnvelope) error {
envelope, err := signedEnvelope.Envelope()
if err != nil {
return fmt.Errorf("failed to get envelope: %w", err)
}
builderIdx := envelope.BuilderIndex()
var publicKey bls.PublicKey
if builderIdx == params.BeaconConfig().BuilderIndexSelfBuild {
header := st.LatestBlockHeader()
if header == nil {
return fmt.Errorf("latest block header is nil")
}
proposerPubkey := st.PubkeyAtIndex(header.ProposerIndex)
key, err := bls.PublicKeyFromBytes(proposerPubkey[:])
if err != nil {
return fmt.Errorf("invalid proposer public key: %w", err)
}
publicKey = key
} else {
builder, err := st.Builder(builderIdx)
if err != nil {
return fmt.Errorf("failed to get builder: %w", err)
}
if builder == nil {
return fmt.Errorf("builder at index %d not found", builderIdx)
}
key, err := bls.PublicKeyFromBytes(builder.Pubkey)
if err != nil {
return fmt.Errorf("invalid builder public key: %w", err)
}
publicKey = key
}
signatureBytes := signedEnvelope.Signature()
signature, err := bls.SignatureFromBytes(signatureBytes[:])
if err != nil {
return fmt.Errorf("invalid signature format: %w", err)
}
currentEpoch := slots.ToEpoch(envelope.Slot())
domain, err := signing.Domain(
st.Fork(),
currentEpoch,
params.BeaconConfig().DomainBeaconBuilder,
st.GenesisValidatorsRoot(),
)
if err != nil {
return fmt.Errorf("failed to compute signing domain: %w", err)
}
signingRoot, err := signedEnvelope.SigningRoot(domain)
if err != nil {
return fmt.Errorf("failed to compute signing root: %w", err)
}
if !signature.Verify(publicKey, signingRoot[:]) {
return fmt.Errorf("signature verification failed: %w", signing.ErrSigFailedToVerify)
}
return nil
}

View File

@@ -1,360 +0,0 @@
package gloas
import (
"bytes"
"context"
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
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/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/crypto/bls"
"github.com/OffchainLabs/prysm/v7/encoding/ssz"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/time/slots"
"google.golang.org/protobuf/proto"
)
type payloadFixture struct {
state state.BeaconState
signed interfaces.ROSignedExecutionPayloadEnvelope
signedProto *ethpb.SignedExecutionPayloadEnvelope
envelope *ethpb.ExecutionPayloadEnvelope
payload *enginev1.ExecutionPayloadDeneb
slot primitives.Slot
}
func buildPayloadFixture(t *testing.T, mutate func(payload *enginev1.ExecutionPayloadDeneb, bid *ethpb.ExecutionPayloadBid, envelope *ethpb.ExecutionPayloadEnvelope)) payloadFixture {
t.Helper()
cfg := params.BeaconConfig()
slot := primitives.Slot(5)
builderIdx := primitives.BuilderIndex(0)
sk, err := bls.RandKey()
require.NoError(t, err)
pk := sk.PublicKey().Marshal()
randao := bytes.Repeat([]byte{0xAA}, 32)
parentHash := bytes.Repeat([]byte{0xBB}, 32)
blockHash := bytes.Repeat([]byte{0xCC}, 32)
withdrawals := []*enginev1.Withdrawal{
{Index: 0, ValidatorIndex: 1, Address: bytes.Repeat([]byte{0x01}, 20), Amount: 0},
}
blobCommitments := [][]byte{}
blobRoot, err := ssz.KzgCommitmentsRoot(blobCommitments)
require.NoError(t, err)
payload := &enginev1.ExecutionPayloadDeneb{
ParentHash: parentHash,
FeeRecipient: bytes.Repeat([]byte{0x01}, 20),
StateRoot: bytes.Repeat([]byte{0x02}, 32),
ReceiptsRoot: bytes.Repeat([]byte{0x03}, 32),
LogsBloom: bytes.Repeat([]byte{0x04}, 256),
PrevRandao: randao,
BlockNumber: 1,
GasLimit: 1,
GasUsed: 0,
Timestamp: 100,
ExtraData: []byte{},
BaseFeePerGas: bytes.Repeat([]byte{0x05}, 32),
BlockHash: blockHash,
Transactions: [][]byte{},
Withdrawals: withdrawals,
BlobGasUsed: 0,
ExcessBlobGas: 0,
}
bid := &ethpb.ExecutionPayloadBid{
ParentBlockHash: parentHash,
ParentBlockRoot: bytes.Repeat([]byte{0xDD}, 32),
BlockHash: blockHash,
PrevRandao: randao,
GasLimit: 1,
BuilderIndex: builderIdx,
Slot: slot,
Value: 0,
ExecutionPayment: 0,
BlobKzgCommitmentsRoot: blobRoot[:],
FeeRecipient: bytes.Repeat([]byte{0xEE}, 20),
}
header := &ethpb.BeaconBlockHeader{
Slot: slot,
ParentRoot: bytes.Repeat([]byte{0x11}, 32),
StateRoot: bytes.Repeat([]byte{0x22}, 32),
BodyRoot: bytes.Repeat([]byte{0x33}, 32),
}
headerRoot, err := header.HashTreeRoot()
require.NoError(t, err)
envelope := &ethpb.ExecutionPayloadEnvelope{
Slot: slot,
BuilderIndex: builderIdx,
BeaconBlockRoot: headerRoot[:],
Payload: payload,
BlobKzgCommitments: blobCommitments,
ExecutionRequests: &enginev1.ExecutionRequests{},
}
if mutate != nil {
mutate(payload, bid, envelope)
}
genesisRoot := bytes.Repeat([]byte{0xAB}, 32)
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
stateRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
for i := range blockRoots {
blockRoots[i] = bytes.Repeat([]byte{0x44}, 32)
stateRoots[i] = bytes.Repeat([]byte{0x55}, 32)
}
randaoMixes := make([][]byte, cfg.EpochsPerHistoricalVector)
for i := range randaoMixes {
randaoMixes[i] = randao
}
withdrawalCreds := make([]byte, 32)
withdrawalCreds[0] = cfg.ETH1AddressWithdrawalPrefixByte
eth1Data := &ethpb.Eth1Data{
DepositRoot: bytes.Repeat([]byte{0x66}, 32),
DepositCount: 0,
BlockHash: bytes.Repeat([]byte{0x77}, 32),
}
vals := []*ethpb.Validator{
{
PublicKey: pk,
WithdrawalCredentials: withdrawalCreds,
EffectiveBalance: cfg.MinActivationBalance + 1_000,
},
}
balances := []uint64{cfg.MinActivationBalance + 1_000}
payments := make([]*ethpb.BuilderPendingPayment, cfg.SlotsPerEpoch*2)
for i := range payments {
payments[i] = &ethpb.BuilderPendingPayment{
Withdrawal: &ethpb.BuilderPendingWithdrawal{
FeeRecipient: make([]byte, 20),
},
}
}
executionPayloadAvailability := make([]byte, cfg.SlotsPerHistoricalRoot/8)
builders := make([]*ethpb.Builder, builderIdx+1)
builders[builderIdx] = &ethpb.Builder{
Pubkey: pk,
Version: []byte{0},
ExecutionAddress: bytes.Repeat([]byte{0x09}, 20),
Balance: 0,
DepositEpoch: 0,
WithdrawableEpoch: 0,
}
genesisTime := uint64(0)
slotSeconds := cfg.SecondsPerSlot * uint64(slot)
if payload.Timestamp > slotSeconds {
genesisTime = payload.Timestamp - slotSeconds
}
stProto := &ethpb.BeaconStateGloas{
Slot: slot,
GenesisTime: genesisTime,
GenesisValidatorsRoot: genesisRoot,
Fork: &ethpb.Fork{
CurrentVersion: bytes.Repeat([]byte{0x01}, 4),
PreviousVersion: bytes.Repeat([]byte{0x01}, 4),
Epoch: 0,
},
LatestBlockHeader: header,
BlockRoots: blockRoots,
StateRoots: stateRoots,
RandaoMixes: randaoMixes,
Eth1Data: eth1Data,
Validators: vals,
Balances: balances,
LatestBlockHash: payload.ParentHash,
LatestExecutionPayloadBid: bid,
BuilderPendingPayments: payments,
ExecutionPayloadAvailability: executionPayloadAvailability,
BuilderPendingWithdrawals: []*ethpb.BuilderPendingWithdrawal{},
PayloadExpectedWithdrawals: payload.Withdrawals,
Builders: builders,
}
st, err := state_native.InitializeFromProtoGloas(stProto)
require.NoError(t, err)
expected := st.Copy()
ctx := context.Background()
require.NoError(t, processExecutionRequests(ctx, expected, envelope.ExecutionRequests))
require.NoError(t, expected.QueueBuilderPayment())
require.NoError(t, expected.SetExecutionPayloadAvailability(slot, true))
var blockHashArr [32]byte
copy(blockHashArr[:], payload.BlockHash)
require.NoError(t, expected.SetLatestBlockHash(blockHashArr))
expectedRoot, err := expected.HashTreeRoot(ctx)
require.NoError(t, err)
envelope.StateRoot = expectedRoot[:]
epoch := slots.ToEpoch(slot)
domain, err := signing.Domain(st.Fork(), epoch, cfg.DomainBeaconBuilder, st.GenesisValidatorsRoot())
require.NoError(t, err)
signingRoot, err := signing.ComputeSigningRoot(envelope, domain)
require.NoError(t, err)
signature := sk.Sign(signingRoot[:]).Marshal()
signedProto := &ethpb.SignedExecutionPayloadEnvelope{
Message: envelope,
Signature: signature,
}
signed, err := blocks.WrappedROSignedExecutionPayloadEnvelope(signedProto)
require.NoError(t, err)
return payloadFixture{
state: st,
signed: signed,
signedProto: signedProto,
envelope: envelope,
payload: payload,
slot: slot,
}
}
func TestProcessExecutionPayload_Success(t *testing.T) {
fixture := buildPayloadFixture(t, nil)
require.NoError(t, ProcessExecutionPayload(t.Context(), fixture.state, fixture.signed))
latestHash, err := fixture.state.LatestBlockHash()
require.NoError(t, err)
var expectedHash [32]byte
copy(expectedHash[:], fixture.payload.BlockHash)
require.Equal(t, expectedHash, latestHash)
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
paymentIndex := slotsPerEpoch + (fixture.slot % slotsPerEpoch)
payments, err := fixture.state.BuilderPendingPayments()
require.NoError(t, err)
payment := payments[paymentIndex]
require.NotNil(t, payment)
require.Equal(t, primitives.Gwei(0), payment.Withdrawal.Amount)
}
func TestProcessExecutionPayload_PrevRandaoMismatch(t *testing.T) {
fixture := buildPayloadFixture(t, func(_ *enginev1.ExecutionPayloadDeneb, bid *ethpb.ExecutionPayloadBid, _ *ethpb.ExecutionPayloadEnvelope) {
bid.PrevRandao = bytes.Repeat([]byte{0xFF}, 32)
})
err := ProcessExecutionPayload(t.Context(), fixture.state, fixture.signed)
require.ErrorContains(t, "prev randao", err)
}
func TestQueueBuilderPayment_ZeroAmountClearsSlot(t *testing.T) {
fixture := buildPayloadFixture(t, nil)
require.NoError(t, fixture.state.QueueBuilderPayment())
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
paymentIndex := slotsPerEpoch + (fixture.slot % slotsPerEpoch)
payments, err := fixture.state.BuilderPendingPayments()
require.NoError(t, err)
payment := payments[paymentIndex]
require.NotNil(t, payment)
require.Equal(t, primitives.Gwei(0), payment.Withdrawal.Amount)
}
func TestVerifyExecutionPayloadEnvelopeSignature(t *testing.T) {
fixture := buildPayloadFixture(t, nil)
t.Run("self build", func(t *testing.T) {
proposerSk, err := bls.RandKey()
require.NoError(t, err)
proposerPk := proposerSk.PublicKey().Marshal()
stPb, ok := fixture.state.ToProtoUnsafe().(*ethpb.BeaconStateGloas)
require.Equal(t, true, ok)
stPb = proto.Clone(stPb).(*ethpb.BeaconStateGloas)
stPb.Validators[0].PublicKey = proposerPk
st, err := state_native.InitializeFromProtoUnsafeGloas(stPb)
require.NoError(t, err)
msg := proto.Clone(fixture.signedProto.Message).(*ethpb.ExecutionPayloadEnvelope)
msg.BuilderIndex = params.BeaconConfig().BuilderIndexSelfBuild
msg.BlobKzgCommitments = []([]byte){}
epoch := slots.ToEpoch(msg.Slot)
domain, err := signing.Domain(st.Fork(), epoch, params.BeaconConfig().DomainBeaconBuilder, st.GenesisValidatorsRoot())
require.NoError(t, err)
signingRoot, err := signing.ComputeSigningRoot(msg, domain)
require.NoError(t, err)
signature := proposerSk.Sign(signingRoot[:]).Marshal()
signedProto := &ethpb.SignedExecutionPayloadEnvelope{
Message: msg,
Signature: signature,
}
signed, err := blocks.WrappedROSignedExecutionPayloadEnvelope(signedProto)
require.NoError(t, err)
require.NoError(t, verifyExecutionPayloadEnvelopeSignature(st, signed))
})
t.Run("builder", func(t *testing.T) {
signed, err := blocks.WrappedROSignedExecutionPayloadEnvelope(fixture.signedProto)
require.NoError(t, err)
require.NoError(t, verifyExecutionPayloadEnvelopeSignature(fixture.state, signed))
})
t.Run("invalid signature", func(t *testing.T) {
t.Run("self build", func(t *testing.T) {
proposerSk, err := bls.RandKey()
require.NoError(t, err)
proposerPk := proposerSk.PublicKey().Marshal()
stPb, ok := fixture.state.ToProtoUnsafe().(*ethpb.BeaconStateGloas)
require.Equal(t, true, ok)
stPb = proto.Clone(stPb).(*ethpb.BeaconStateGloas)
stPb.Validators[0].PublicKey = proposerPk
st, err := state_native.InitializeFromProtoUnsafeGloas(stPb)
require.NoError(t, err)
msg := proto.Clone(fixture.signedProto.Message).(*ethpb.ExecutionPayloadEnvelope)
msg.BuilderIndex = params.BeaconConfig().BuilderIndexSelfBuild
if msg.BlobKzgCommitments == nil {
msg.BlobKzgCommitments = [][]byte{}
}
signedProto := &ethpb.SignedExecutionPayloadEnvelope{
Message: msg,
Signature: bytes.Repeat([]byte{0xFF}, 96),
}
badSigned, err := blocks.WrappedROSignedExecutionPayloadEnvelope(signedProto)
require.NoError(t, err)
err = verifyExecutionPayloadEnvelopeSignature(st, badSigned)
require.ErrorContains(t, "invalid signature format", err)
})
t.Run("builder", func(t *testing.T) {
signedProto := &ethpb.SignedExecutionPayloadEnvelope{
Message: fixture.signedProto.Message,
Signature: bytes.Repeat([]byte{0xFF}, 96),
}
badSigned, err := blocks.WrappedROSignedExecutionPayloadEnvelope(signedProto)
require.NoError(t, err)
err = verifyExecutionPayloadEnvelopeSignature(fixture.state, badSigned)
require.ErrorContains(t, "invalid signature format", err)
})
})
}

View File

@@ -22,10 +22,6 @@ var ErrNotFoundFeeRecipient = errors.Wrap(ErrNotFound, "fee recipient")
// ErrNotFoundMetadataSeqNum is a not found error specifically for the metadata sequence number getter
var ErrNotFoundMetadataSeqNum = errors.Wrap(ErrNotFound, "metadata sequence number")
// ErrStateDiffIncompatible is returned when state-diff feature is enabled
// but the database was created without state-diff support.
var ErrStateDiffIncompatible = errors.New("state-diff feature enabled but database was created without state-diff support")
var errEmptyBlockSlice = errors.New("[]blocks.ROBlock is empty")
var errIncorrectBlockParent = errors.New("unexpected missing or forked blocks in a []ROBlock")
var errFinalizedChildNotFound = errors.New("unable to find finalized root descending from backfill batch")

View File

@@ -42,10 +42,6 @@ func (s *Store) SaveGenesisData(ctx context.Context, genesisState state.BeaconSt
if err := s.SaveGenesisBlockRoot(ctx, genesisBlkRoot); err != nil {
return errors.Wrap(err, "could not save genesis block root")
}
if err := s.initializeStateDiff(0, genesisState); err != nil {
return errors.Wrap(err, "failed to initialize state diff for genesis")
}
return nil
}

View File

@@ -203,47 +203,17 @@ func NewKVStore(ctx context.Context, dirPath string, opts ...KVStoreOption) (*St
return nil, err
}
if err := kv.startStateDiff(ctx); err != nil {
if errors.Is(err, ErrStateDiffIncompatible) {
return kv, err
if features.Get().EnableStateDiff {
sdCache, err := newStateDiffCache(kv)
if err != nil {
return nil, err
}
return nil, err
kv.stateDiffCache = sdCache
}
return kv, nil
}
func (kv *Store) startStateDiff(ctx context.Context) error {
if !features.Get().EnableStateDiff {
return nil
}
// Check if offset already exists (existing state-diff database).
hasOffset, err := kv.hasStateDiffOffset()
if err != nil {
return err
}
if hasOffset {
// Existing state-diff database - restarts not yet supported.
return errors.New("restarting with existing state-diff database not yet supported")
}
// Check if this is a new database (no head block).
headBlock, err := kv.HeadBlock(ctx)
if err != nil {
return errors.Wrap(err, "could not get head block")
}
if headBlock == nil {
// New database - will be initialized later during checkpoint/genesis sync.
// stateDiffCache stays nil until SaveOrigin or SaveGenesisData initializes it.
log.Info("State-diff enabled: will be initialized during checkpoint or genesis sync")
} else {
// Existing database without state-diff - return store with error for caller to handle.
return ErrStateDiffIncompatible
}
return nil
}
// ClearDB removes the previously stored database in the data directory.
func (s *Store) ClearDB() error {
if err := s.Close(); err != nil {

View File

@@ -9,13 +9,11 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
statenative "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
"github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/flags"
"github.com/OffchainLabs/prysm/v7/config/features"
"github.com/OffchainLabs/prysm/v7/consensus-types/hdiff"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/math"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/runtime/version"
pkgerrors "github.com/pkg/errors"
"go.etcd.io/bbolt"
)
@@ -124,66 +122,6 @@ func (s *Store) getOffset() uint64 {
return s.stateDiffCache.getOffset()
}
// hasStateDiffOffset checks if the state-diff offset has been set in the database.
// This is used to detect if an existing database has state-diff enabled.
func (s *Store) hasStateDiffOffset() (bool, error) {
var hasOffset bool
err := s.db.View(func(tx *bbolt.Tx) error {
bucket := tx.Bucket(stateDiffBucket)
if bucket == nil {
return nil
}
hasOffset = bucket.Get(offsetKey) != nil
return nil
})
return hasOffset, err
}
// initializeStateDiff sets up the state-diff schema for a new database.
// This should be called during checkpoint sync or genesis sync.
func (s *Store) initializeStateDiff(slot primitives.Slot, initialState state.ReadOnlyBeaconState) error {
// Return early if the feature is not set
if !features.Get().EnableStateDiff {
return nil
}
// Only reinitialize if the offset is different
if s.stateDiffCache != nil {
if s.stateDiffCache.getOffset() == uint64(slot) {
log.WithField("offset", slot).Warning("Ignoring state diff cache reinitialization")
return nil
}
}
// Write offset directly to the database (without using cache which doesn't exist yet).
err := s.db.Update(func(tx *bbolt.Tx) error {
bucket := tx.Bucket(stateDiffBucket)
if bucket == nil {
return bbolt.ErrBucketNotFound
}
offsetBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(offsetBytes, uint64(slot))
return bucket.Put(offsetKey, offsetBytes)
})
if err != nil {
return pkgerrors.Wrap(err, "failed to set offset")
}
// Create the state diff cache (this will read the offset from the database).
sdCache, err := newStateDiffCache(s)
if err != nil {
return pkgerrors.Wrap(err, "failed to create state diff cache")
}
s.stateDiffCache = sdCache
// Save the initial state as a full snapshot.
if err := s.saveFullSnapshot(initialState); err != nil {
return pkgerrors.Wrap(err, "failed to save initial snapshot")
}
log.WithField("offset", slot).Info("Initialized state-diff cache")
return nil
}
func keyForSnapshot(v int) ([]byte, error) {
switch v {
case version.Fulu:

View File

@@ -110,8 +110,6 @@ func (s *Store) SaveOrigin(ctx context.Context, serState, serBlock []byte) error
if err = s.SaveFinalizedCheckpoint(ctx, chkpt); err != nil {
return errors.Wrap(err, "save finalized checkpoint")
}
if err := s.initializeStateDiff(state.Slot(), state); err != nil {
return errors.Wrap(err, "failed to initialize state diff")
}
return nil
}

View File

@@ -413,7 +413,7 @@ func CreateDefaultLightClientUpdate(attestedBlock interfaces.ReadOnlySignedBeaco
SyncCommitteeSignature: make([]byte, 96),
},
}
case version.Electra, version.Fulu:
case version.Electra, version.Fulu, version.Gloas:
m = &pb.LightClientUpdateElectra{
AttestedHeader: &pb.LightClientHeaderDeneb{
Beacon: &pb.BeaconBlockHeader{
@@ -515,7 +515,7 @@ func ComputeWithdrawalsRoot(payload interfaces.ExecutionData) ([]byte, error) {
func BlockToLightClientHeader(
ctx context.Context,
attestedBlockVersion int, // this is the version that the light client header should be in, based on the attested block.
attestedBlockVersion int, // this is the version that the light client header should be in, based on the attested block.
block interfaces.ReadOnlySignedBeaconBlock, // this block is either the attested block, or the finalized block. in case of the latter, we might need to upgrade it to the attested block's version.
) (interfaces.LightClientHeader, error) {
if block.Version() > attestedBlockVersion {
@@ -543,7 +543,7 @@ func BlockToLightClientHeader(
Execution: payloadHeader,
ExecutionBranch: payloadProof,
}
case version.Deneb, version.Electra, version.Fulu:
case version.Deneb, version.Electra, version.Fulu, version.Gloas:
payloadHeader, payloadProof, err := makeExecutionAndProofDeneb(ctx, block)
if err != nil {
return nil, errors.Wrap(err, "could not make execution payload header and proof")

View File

@@ -535,12 +535,7 @@ func openDB(ctx context.Context, dbPath string, clearer *dbClearer) (*kv.Store,
log.WithField("databasePath", dbPath).Info("Checking DB")
d, err := kv.NewKVStore(ctx, dbPath)
if errors.Is(err, kv.ErrStateDiffIncompatible) {
log.WithError(err).Warn("Disabling state-diff feature")
cfg := features.Get()
cfg.EnableStateDiff = false
features.Init(cfg)
} else if err != nil {
if err != nil {
return nil, errors.Wrapf(err, "could not create database at %s", dbPath)
}

View File

@@ -83,10 +83,8 @@ func TestGetSpec(t *testing.T) {
config.ElectraForkEpoch = 107
config.FuluForkVersion = []byte("FuluForkVersion")
config.FuluForkEpoch = 109
config.GloasForkEpoch = 110
config.BLSWithdrawalPrefixByte = byte('b')
config.ETH1AddressWithdrawalPrefixByte = byte('c')
config.BuilderWithdrawalPrefixByte = byte('e')
config.GenesisDelay = 24
config.SecondsPerSlot = 25
config.SlotDurationMilliseconds = 120
@@ -136,10 +134,6 @@ func TestGetSpec(t *testing.T) {
config.AttestationDueBPS = primitives.BP(122)
config.AggregateDueBPS = primitives.BP(123)
config.ContributionDueBPS = primitives.BP(124)
config.AttestationDueBPSGloas = primitives.BP(126)
config.AggregateDueBPSGloas = primitives.BP(127)
config.SyncMessageDueBPSGloas = primitives.BP(128)
config.ContributionDueBPSGloas = primitives.BP(129)
config.TerminalBlockHash = common.HexToHash("TerminalBlockHash")
config.TerminalBlockHashActivationEpoch = 72
config.TerminalTotalDifficulty = "73"
@@ -221,7 +215,7 @@ func TestGetSpec(t *testing.T) {
require.NoError(t, json.Unmarshal(writer.Body.Bytes(), &resp))
data, ok := resp.Data.(map[string]any)
require.Equal(t, true, ok)
assert.Equal(t, 192, len(data))
assert.Equal(t, 187, len(data))
for k, v := range data {
t.Run(k, func(t *testing.T) {
switch k {
@@ -301,8 +295,6 @@ func TestGetSpec(t *testing.T) {
assert.Equal(t, "0x"+hex.EncodeToString([]byte("FuluForkVersion")), v)
case "FULU_FORK_EPOCH":
assert.Equal(t, "109", v)
case "GLOAS_FORK_EPOCH":
assert.Equal(t, "110", v)
case "MIN_ANCHOR_POW_BLOCK_DIFFICULTY":
assert.Equal(t, "1000", v)
case "BLS_WITHDRAWAL_PREFIX":
@@ -487,14 +479,6 @@ func TestGetSpec(t *testing.T) {
assert.Equal(t, "123", v)
case "CONTRIBUTION_DUE_BPS":
assert.Equal(t, "124", v)
case "ATTESTATION_DUE_BPS_GLOAS":
assert.Equal(t, "126", v)
case "AGGREGATE_DUE_BPS_GLOAS":
assert.Equal(t, "127", v)
case "SYNC_MESSAGE_DUE_BPS_GLOAS":
assert.Equal(t, "128", v)
case "CONTRIBUTION_DUE_BPS_GLOAS":
assert.Equal(t, "129", v)
case "MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT":
assert.Equal(t, "8", v)
case "MAX_REQUEST_LIGHT_CLIENT_UPDATES":

View File

@@ -1,51 +1,24 @@
package state
import (
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
)
type writeOnlyGloasFields interface {
// Bids.
SetExecutionPayloadBid(h interfaces.ROExecutionPayloadBid) error
// Builder pending payments / withdrawals.
SetBuilderPendingPayment(index primitives.Slot, payment *ethpb.BuilderPendingPayment) error
ClearBuilderPendingPayment(index primitives.Slot) error
QueueBuilderPayment() error
RotateBuilderPendingPayments() error
AppendBuilderPendingWithdrawals([]*ethpb.BuilderPendingWithdrawal) error
// Execution payload availability.
UpdateExecutionPayloadAvailabilityAtIndex(idx uint64, val byte) error
// Misc.
SetLatestBlockHash(hash [32]byte) error
SetExecutionPayloadAvailability(index primitives.Slot, available bool) error
// Builders.
IncreaseBuilderBalance(index primitives.BuilderIndex, amount uint64) error
AddBuilderFromDeposit(pubkey [fieldparams.BLSPubkeyLength]byte, withdrawalCredentials [fieldparams.RootLength]byte, amount uint64) error
}
type readOnlyGloasFields interface {
// Bids.
LatestExecutionPayloadBid() (interfaces.ROExecutionPayloadBid, error)
// Builder pending payments / withdrawals.
BuilderPendingPayments() ([]*ethpb.BuilderPendingPayment, error)
WithdrawalsMatchPayloadExpected(withdrawals []*enginev1.Withdrawal) (bool, error)
// Misc.
LatestBlockHash() ([32]byte, error)
// Builders.
Builder(index primitives.BuilderIndex) (*ethpb.Builder, error)
BuilderPubkey(primitives.BuilderIndex) ([48]byte, error)
BuilderIndexByPubkey(pubkey [fieldparams.BLSPubkeyLength]byte) (primitives.BuilderIndex, bool)
IsActiveBuilder(primitives.BuilderIndex) (bool, error)
CanBuilderCoverBid(primitives.BuilderIndex, primitives.Gwei) (bool, error)
LatestBlockHash() ([32]byte, error)
BuilderPendingPayments() ([]*ethpb.BuilderPendingPayment, error)
}

View File

@@ -1,16 +1,11 @@
package state_native
import (
"bytes"
"fmt"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/ssz"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/runtime/version"
)
@@ -152,78 +147,3 @@ func (b *BeaconState) BuilderPendingPayments() ([]*ethpb.BuilderPendingPayment,
return b.builderPendingPaymentsVal(), nil
}
// LatestExecutionPayloadBid returns the cached latest execution payload bid for Gloas.
func (b *BeaconState) LatestExecutionPayloadBid() (interfaces.ROExecutionPayloadBid, error) {
b.lock.RLock()
defer b.lock.RUnlock()
if b.latestExecutionPayloadBid == nil {
return nil, nil
}
return blocks.WrappedROExecutionPayloadBid(b.latestExecutionPayloadBid.Copy())
}
// WithdrawalsMatchPayloadExpected returns true if the given withdrawals root matches the state's
// payload_expected_withdrawals root.
func (b *BeaconState) WithdrawalsMatchPayloadExpected(withdrawals []*enginev1.Withdrawal) (bool, error) {
if b.version < version.Gloas {
return false, errNotSupported("WithdrawalsMatchPayloadExpected", b.version)
}
b.lock.RLock()
defer b.lock.RUnlock()
cfg := params.BeaconConfig()
withdrawalsRoot, err := ssz.WithdrawalSliceRoot(withdrawals, cfg.MaxWithdrawalsPerPayload)
if err != nil {
return false, fmt.Errorf("could not compute withdrawals root: %w", err)
}
expected := b.payloadExpectedWithdrawals
if expected == nil {
expected = []*enginev1.Withdrawal{}
}
expectedRoot, err := ssz.WithdrawalSliceRoot(expected, cfg.MaxWithdrawalsPerPayload)
if err != nil {
return false, fmt.Errorf("could not compute expected withdrawals root: %w", err)
}
return withdrawalsRoot == expectedRoot, nil
}
// Builder returns the builder at the given index.
func (b *BeaconState) Builder(index primitives.BuilderIndex) (*ethpb.Builder, error) {
b.lock.RLock()
defer b.lock.RUnlock()
if b.builders == nil {
return nil, nil
}
if uint64(index) >= uint64(len(b.builders)) {
return nil, fmt.Errorf("builder index %d out of bounds", index)
}
if b.builders[index] == nil {
return nil, nil
}
return ethpb.CopyBuilder(b.builders[index]), nil
}
// BuilderIndexByPubkey returns the builder index for the given pubkey, if present.
func (b *BeaconState) BuilderIndexByPubkey(pubkey [fieldparams.BLSPubkeyLength]byte) (primitives.BuilderIndex, bool) {
b.lock.RLock()
defer b.lock.RUnlock()
for i, builder := range b.builders {
if builder == nil {
continue
}
if bytes.Equal(builder.Pubkey, pubkey[:]) {
return primitives.BuilderIndex(i), true
}
}
return 0, false
}

View File

@@ -5,10 +5,8 @@ import (
"testing"
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/testing/util"
@@ -168,132 +166,3 @@ func TestBuilderPendingPayments_UnsupportedVersion(t *testing.T) {
_, err = st.BuilderPendingPayments()
require.ErrorContains(t, "BuilderPendingPayments", err)
}
func TestWithdrawalsMatchPayloadExpected(t *testing.T) {
t.Run("returns error before gloas", func(t *testing.T) {
stIface, _ := util.DeterministicGenesisState(t, 1)
native, ok := stIface.(*state_native.BeaconState)
require.Equal(t, true, ok)
_, err := native.WithdrawalsMatchPayloadExpected(nil)
require.ErrorContains(t, "is not supported", err)
})
t.Run("returns true when roots match", func(t *testing.T) {
withdrawals := []*enginev1.Withdrawal{
{Index: 0, ValidatorIndex: 1, Address: bytes.Repeat([]byte{0x01}, 20), Amount: 10},
}
st, err := state_native.InitializeFromProtoGloas(&ethpb.BeaconStateGloas{
PayloadExpectedWithdrawals: withdrawals,
})
require.NoError(t, err)
ok, err := st.WithdrawalsMatchPayloadExpected(withdrawals)
require.NoError(t, err)
require.Equal(t, true, ok)
})
t.Run("returns false when roots do not match", func(t *testing.T) {
expected := []*enginev1.Withdrawal{
{Index: 0, ValidatorIndex: 1, Address: bytes.Repeat([]byte{0x01}, 20), Amount: 10},
}
actual := []*enginev1.Withdrawal{
{Index: 0, ValidatorIndex: 1, Address: bytes.Repeat([]byte{0x01}, 20), Amount: 11},
}
st, err := state_native.InitializeFromProtoGloas(&ethpb.BeaconStateGloas{
PayloadExpectedWithdrawals: expected,
})
require.NoError(t, err)
ok, err := st.WithdrawalsMatchPayloadExpected(actual)
require.NoError(t, err)
require.Equal(t, false, ok)
})
}
func TestBuilder(t *testing.T) {
t.Run("nil builders returns nil", func(t *testing.T) {
st, err := state_native.InitializeFromProtoGloas(&ethpb.BeaconStateGloas{
Builders: nil,
})
require.NoError(t, err)
got, err := st.Builder(0)
require.NoError(t, err)
require.Equal(t, (*ethpb.Builder)(nil), got)
})
t.Run("out of bounds returns error", func(t *testing.T) {
st, err := state_native.InitializeFromProtoGloas(&ethpb.BeaconStateGloas{
Builders: []*ethpb.Builder{{}},
})
require.NoError(t, err)
_, err = st.Builder(1)
require.ErrorContains(t, "out of bounds", err)
})
t.Run("returns copy", func(t *testing.T) {
pubkey := bytes.Repeat([]byte{0xAA}, fieldparams.BLSPubkeyLength)
st, err := state_native.InitializeFromProtoGloas(&ethpb.BeaconStateGloas{
Builders: []*ethpb.Builder{
{
Pubkey: pubkey,
Balance: 42,
DepositEpoch: 3,
WithdrawableEpoch: 4,
},
},
})
require.NoError(t, err)
got1, err := st.Builder(0)
require.NoError(t, err)
require.NotEqual(t, (*ethpb.Builder)(nil), got1)
require.Equal(t, primitives.Gwei(42), got1.Balance)
require.DeepEqual(t, pubkey, got1.Pubkey)
// Mutate returned builder; state should be unchanged.
got1.Pubkey[0] = 0xFF
got2, err := st.Builder(0)
require.NoError(t, err)
require.Equal(t, byte(0xAA), got2.Pubkey[0])
})
}
func TestBuilderIndexByPubkey(t *testing.T) {
t.Run("not found returns false", func(t *testing.T) {
st, err := state_native.InitializeFromProtoGloas(&ethpb.BeaconStateGloas{
Builders: []*ethpb.Builder{
{Pubkey: bytes.Repeat([]byte{0x11}, fieldparams.BLSPubkeyLength)},
},
})
require.NoError(t, err)
var pk [fieldparams.BLSPubkeyLength]byte
copy(pk[:], bytes.Repeat([]byte{0x22}, fieldparams.BLSPubkeyLength))
idx, ok := st.BuilderIndexByPubkey(pk)
require.Equal(t, false, ok)
require.Equal(t, primitives.BuilderIndex(0), idx)
})
t.Run("skips nil entries and finds match", func(t *testing.T) {
wantIdx := primitives.BuilderIndex(1)
wantPkBytes := bytes.Repeat([]byte{0xAB}, fieldparams.BLSPubkeyLength)
st, err := state_native.InitializeFromProtoGloas(&ethpb.BeaconStateGloas{
Builders: []*ethpb.Builder{
nil,
{Pubkey: wantPkBytes},
},
})
require.NoError(t, err)
var pk [fieldparams.BLSPubkeyLength]byte
copy(pk[:], wantPkBytes)
idx, ok := st.BuilderIndexByPubkey(pk)
require.Equal(t, true, ok)
require.Equal(t, wantIdx, idx)
})
}

View File

@@ -5,14 +5,11 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/stateutil"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"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
@@ -124,41 +121,6 @@ func (b *BeaconState) ClearBuilderPendingPayment(index primitives.Slot) error {
return nil
}
// QueueBuilderPayment implements the builder payment queuing logic for Gloas.
// Spec v1.7.0-alpha.0 (pseudocode):
// payment = state.builder_pending_payments[SLOTS_PER_EPOCH + state.slot % SLOTS_PER_EPOCH]
// amount = payment.withdrawal.amount
// if amount > 0:
//
// state.builder_pending_withdrawals.append(payment.withdrawal)
//
// state.builder_pending_payments[SLOTS_PER_EPOCH + state.slot % SLOTS_PER_EPOCH] = BuilderPendingPayment()
func (b *BeaconState) QueueBuilderPayment() error {
if b.version < version.Gloas {
return errNotSupported("QueueBuilderPayment", b.version)
}
b.lock.Lock()
defer b.lock.Unlock()
slot := b.slot
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
paymentIndex := slotsPerEpoch + (slot % slotsPerEpoch)
if uint64(paymentIndex) >= uint64(len(b.builderPendingPayments)) {
return fmt.Errorf("builder pending payments index %d out of range (len=%d)", paymentIndex, len(b.builderPendingPayments))
}
payment := b.builderPendingPayments[paymentIndex]
if payment != nil && payment.Withdrawal != nil && payment.Withdrawal.Amount > 0 {
b.builderPendingWithdrawals = append(b.builderPendingWithdrawals, ethpb.CopyBuilderPendingWithdrawal(payment.Withdrawal))
b.markFieldAsDirty(types.BuilderPendingWithdrawals)
}
b.builderPendingPayments[paymentIndex] = emptyBuilderPendingPayment
b.markFieldAsDirty(types.BuilderPendingPayments)
return nil
}
// SetBuilderPendingPayment sets a builder pending payment at the specified index.
func (b *BeaconState) SetBuilderPendingPayment(index primitives.Slot, payment *ethpb.BuilderPendingPayment) error {
if b.version < version.Gloas {
@@ -199,91 +161,3 @@ func (b *BeaconState) UpdateExecutionPayloadAvailabilityAtIndex(idx uint64, val
b.markFieldAsDirty(types.ExecutionPayloadAvailability)
return nil
}
// SetLatestBlockHash sets the latest execution block hash.
func (b *BeaconState) SetLatestBlockHash(hash [32]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
b.latestBlockHash = hash[:]
b.markFieldAsDirty(types.LatestBlockHash)
return nil
}
// SetExecutionPayloadAvailability sets the execution payload availability bit for a specific slot.
func (b *BeaconState) SetExecutionPayloadAvailability(index primitives.Slot, available bool) error {
b.lock.Lock()
defer b.lock.Unlock()
bitIndex := index % params.BeaconConfig().SlotsPerHistoricalRoot
byteIndex := bitIndex / 8
bitPosition := bitIndex % 8
// Set or clear the bit
if available {
b.executionPayloadAvailability[byteIndex] |= 1 << bitPosition
} else {
b.executionPayloadAvailability[byteIndex] &^= 1 << bitPosition
}
b.markFieldAsDirty(types.ExecutionPayloadAvailability)
return nil
}
// IncreaseBuilderBalance increases the balance of the builder at the given index.
func (b *BeaconState) IncreaseBuilderBalance(index primitives.BuilderIndex, amount uint64) error {
b.lock.Lock()
defer b.lock.Unlock()
if b.builders == nil || uint64(index) >= uint64(len(b.builders)) {
return fmt.Errorf("builder index %d out of bounds", index)
}
if b.builders[index] == nil {
return fmt.Errorf("builder at index %d is nil", index)
}
builder := ethpb.CopyBuilder(b.builders[index])
builder.Balance += primitives.Gwei(amount)
b.builders[index] = builder
b.markFieldAsDirty(types.Builders)
return nil
}
// AddBuilderFromDeposit creates or replaces a builder entry derived from a deposit.
func (b *BeaconState) AddBuilderFromDeposit(pubkey [fieldparams.BLSPubkeyLength]byte, withdrawalCredentials [fieldparams.RootLength]byte, amount uint64) error {
b.lock.Lock()
defer b.lock.Unlock()
currentEpoch := slots.ToEpoch(b.slot)
index := b.builderInsertionIndex(currentEpoch)
builder := &ethpb.Builder{
Pubkey: bytesutil.SafeCopyBytes(pubkey[:]),
Version: []byte{withdrawalCredentials[0]},
ExecutionAddress: bytesutil.SafeCopyBytes(withdrawalCredentials[12:]),
Balance: primitives.Gwei(amount),
DepositEpoch: currentEpoch,
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
}
if index < primitives.BuilderIndex(len(b.builders)) {
b.builders[index] = builder
} else {
gap := index - primitives.BuilderIndex(len(b.builders)) + 1
b.builders = append(b.builders, make([]*ethpb.Builder, gap)...)
b.builders[index] = builder
}
b.markFieldAsDirty(types.Builders)
return nil
}
func (b *BeaconState) builderInsertionIndex(currentEpoch primitives.Epoch) primitives.BuilderIndex {
for i, builder := range b.builders {
if builder.WithdrawableEpoch <= currentEpoch && builder.Balance == 0 {
return primitives.BuilderIndex(i)
}
}
return primitives.BuilderIndex(len(b.builders))
}

View File

@@ -181,80 +181,6 @@ func TestClearBuilderPendingPayment(t *testing.T) {
})
}
func TestQueueBuilderPayment(t *testing.T) {
t.Run("previous fork returns expected error", func(t *testing.T) {
st := &BeaconState{version: version.Fulu}
err := st.QueueBuilderPayment()
require.ErrorContains(t, "is not supported", err)
})
t.Run("appends withdrawal, clears payment, and marks dirty", func(t *testing.T) {
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
slot := primitives.Slot(3)
paymentIndex := slotsPerEpoch + (slot % slotsPerEpoch)
st := &BeaconState{
version: version.Gloas,
slot: slot,
dirtyFields: make(map[types.FieldIndex]bool),
rebuildTrie: make(map[types.FieldIndex]bool),
sharedFieldReferences: make(map[types.FieldIndex]*stateutil.Reference),
builderPendingPayments: make([]*ethpb.BuilderPendingPayment, slotsPerEpoch*2),
builderPendingWithdrawals: []*ethpb.BuilderPendingWithdrawal{},
}
st.builderPendingPayments[paymentIndex] = &ethpb.BuilderPendingPayment{
Weight: 1,
Withdrawal: &ethpb.BuilderPendingWithdrawal{
FeeRecipient: bytes.Repeat([]byte{0xAB}, 20),
Amount: 99,
BuilderIndex: 1,
},
}
require.NoError(t, st.QueueBuilderPayment())
require.Equal(t, emptyBuilderPendingPayment, st.builderPendingPayments[paymentIndex])
require.Equal(t, true, st.dirtyFields[types.BuilderPendingPayments])
require.Equal(t, true, st.dirtyFields[types.BuilderPendingWithdrawals])
require.Equal(t, 1, len(st.builderPendingWithdrawals))
require.DeepEqual(t, bytes.Repeat([]byte{0xAB}, 20), st.builderPendingWithdrawals[0].FeeRecipient)
require.Equal(t, primitives.Gwei(99), st.builderPendingWithdrawals[0].Amount)
// Ensure copied withdrawal is not aliased.
st.builderPendingPayments[paymentIndex].Withdrawal.FeeRecipient[0] = 0x01
require.Equal(t, byte(0xAB), st.builderPendingWithdrawals[0].FeeRecipient[0])
})
t.Run("zero amount does not append withdrawal", func(t *testing.T) {
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
slot := primitives.Slot(3)
paymentIndex := slotsPerEpoch + (slot % slotsPerEpoch)
st := &BeaconState{
version: version.Gloas,
slot: slot,
dirtyFields: make(map[types.FieldIndex]bool),
rebuildTrie: make(map[types.FieldIndex]bool),
sharedFieldReferences: make(map[types.FieldIndex]*stateutil.Reference),
builderPendingPayments: make([]*ethpb.BuilderPendingPayment, slotsPerEpoch*2),
builderPendingWithdrawals: []*ethpb.BuilderPendingWithdrawal{},
}
st.builderPendingPayments[paymentIndex] = &ethpb.BuilderPendingPayment{
Weight: 1,
Withdrawal: &ethpb.BuilderPendingWithdrawal{
FeeRecipient: bytes.Repeat([]byte{0xAB}, 20),
Amount: 0,
BuilderIndex: 1,
},
}
require.NoError(t, st.QueueBuilderPayment())
require.Equal(t, emptyBuilderPendingPayment, st.builderPendingPayments[paymentIndex])
require.Equal(t, true, st.dirtyFields[types.BuilderPendingPayments])
require.Equal(t, false, st.dirtyFields[types.BuilderPendingWithdrawals])
require.Equal(t, 0, len(st.builderPendingWithdrawals))
})
}
func TestRotateBuilderPendingPayments(t *testing.T) {
totalPayments := 2 * params.BeaconConfig().SlotsPerEpoch
payments := make([]*ethpb.BuilderPendingPayment, totalPayments)
@@ -402,134 +328,3 @@ func newGloasStateWithAvailability(t *testing.T, availability []byte) *BeaconSta
return st.(*BeaconState)
}
func TestSetLatestBlockHash(t *testing.T) {
var hash [32]byte
copy(hash[:], []byte("latest-block-hash"))
state := &BeaconState{
dirtyFields: make(map[types.FieldIndex]bool),
}
require.NoError(t, state.SetLatestBlockHash(hash))
require.Equal(t, true, state.dirtyFields[types.LatestBlockHash])
require.DeepEqual(t, hash[:], state.latestBlockHash)
}
func TestSetExecutionPayloadAvailability(t *testing.T) {
state := &BeaconState{
executionPayloadAvailability: make([]byte, params.BeaconConfig().SlotsPerHistoricalRoot/8),
dirtyFields: make(map[types.FieldIndex]bool),
}
slot := primitives.Slot(10)
bitIndex := slot % params.BeaconConfig().SlotsPerHistoricalRoot
byteIndex := bitIndex / 8
bitPosition := bitIndex % 8
require.NoError(t, state.SetExecutionPayloadAvailability(slot, true))
require.Equal(t, true, state.dirtyFields[types.ExecutionPayloadAvailability])
require.Equal(t, byte(1<<bitPosition), state.executionPayloadAvailability[byteIndex]&(1<<bitPosition))
require.NoError(t, state.SetExecutionPayloadAvailability(slot, false))
require.Equal(t, byte(0), state.executionPayloadAvailability[byteIndex]&(1<<bitPosition))
}
func TestIncreaseBuilderBalance(t *testing.T) {
t.Run("out of bounds returns error", func(t *testing.T) {
st := &BeaconState{
version: version.Gloas,
dirtyFields: make(map[types.FieldIndex]bool),
builders: []*ethpb.Builder{},
}
err := st.IncreaseBuilderBalance(0, 1)
require.ErrorContains(t, "out of bounds", err)
require.Equal(t, false, st.dirtyFields[types.Builders])
})
t.Run("nil builder returns error", func(t *testing.T) {
st := &BeaconState{
version: version.Gloas,
dirtyFields: make(map[types.FieldIndex]bool),
builders: []*ethpb.Builder{nil},
}
err := st.IncreaseBuilderBalance(0, 1)
require.ErrorContains(t, "is nil", err)
require.Equal(t, false, st.dirtyFields[types.Builders])
})
t.Run("increments and marks dirty", func(t *testing.T) {
orig := &ethpb.Builder{Balance: 10}
st := &BeaconState{
version: version.Gloas,
dirtyFields: make(map[types.FieldIndex]bool),
builders: []*ethpb.Builder{orig},
}
require.NoError(t, st.IncreaseBuilderBalance(0, 5))
require.Equal(t, primitives.Gwei(15), st.builders[0].Balance)
require.Equal(t, true, st.dirtyFields[types.Builders])
// Copy-on-write semantics: builder pointer replaced.
require.NotEqual(t, orig, st.builders[0])
})
}
func TestAddBuilderFromDeposit(t *testing.T) {
t.Run("reuses empty withdrawable slot", func(t *testing.T) {
var pubkey [48]byte
copy(pubkey[:], bytes.Repeat([]byte{0xAA}, 48))
var wc [32]byte
copy(wc[:], bytes.Repeat([]byte{0xBB}, 32))
wc[0] = 0x42 // version byte
st := &BeaconState{
version: version.Gloas,
slot: 0, // epoch 0
dirtyFields: make(map[types.FieldIndex]bool),
builders: []*ethpb.Builder{
{
WithdrawableEpoch: 0,
Balance: 0,
},
},
}
require.NoError(t, st.AddBuilderFromDeposit(pubkey, wc, 123))
require.Equal(t, 1, len(st.builders))
got := st.builders[0]
require.NotNil(t, got)
require.DeepEqual(t, pubkey[:], got.Pubkey)
require.DeepEqual(t, []byte{0x42}, got.Version)
require.DeepEqual(t, wc[12:], got.ExecutionAddress)
require.Equal(t, primitives.Gwei(123), got.Balance)
require.Equal(t, primitives.Epoch(0), got.DepositEpoch)
require.Equal(t, params.BeaconConfig().FarFutureEpoch, got.WithdrawableEpoch)
require.Equal(t, true, st.dirtyFields[types.Builders])
})
t.Run("appends new builder when no reusable slot", func(t *testing.T) {
var pubkey [48]byte
copy(pubkey[:], bytes.Repeat([]byte{0xAA}, 48))
var wc [32]byte
copy(wc[:], bytes.Repeat([]byte{0xBB}, 32))
st := &BeaconState{
version: version.Gloas,
slot: 0,
dirtyFields: make(map[types.FieldIndex]bool),
builders: []*ethpb.Builder{
{
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
Balance: 1,
},
},
}
require.NoError(t, st.AddBuilderFromDeposit(pubkey, wc, 5))
require.Equal(t, 2, len(st.builders))
require.NotNil(t, st.builders[1])
require.Equal(t, primitives.Gwei(5), st.builders[1].Balance)
})
}

View File

@@ -137,7 +137,7 @@ func (s *State) migrateToColdHdiff(ctx context.Context, fRoot [32]byte) error {
if ctx.Err() != nil {
return ctx.Err()
}
offset, lvl, err := s.beaconDB.SlotInDiffTree(slot)
_, lvl, err := s.beaconDB.SlotInDiffTree(slot)
if err != nil {
log.WithError(err).Errorf("could not determine if slot %d is in diff tree", slot)
continue
@@ -145,9 +145,6 @@ func (s *State) migrateToColdHdiff(ctx context.Context, fRoot [32]byte) error {
if lvl == -1 {
continue
}
if uint64(slot) == offset {
continue
}
// The state needs to be saved.
// Try the epoch boundary cache first.
cached, exists, err := s.epochBoundaryStateCache.getBySlot(slot)

View File

@@ -1,3 +0,0 @@
### Ignored
- Added a field `path` for the ephemeral log file initialization log.

View File

@@ -1,3 +0,0 @@
### Added
- Initialize db with state-diff feature flag.

View File

@@ -1,2 +0,0 @@
### Added
- Add process execution payload for gloas

View File

@@ -1,2 +0,0 @@
### Added
- Gloas-specific timing intervals for validator attestation, aggregation, and sync duties.

View File

@@ -160,7 +160,6 @@ var appFlags = []cli.Flag{
dasFlags.BackfillOldestSlot,
dasFlags.BlobRetentionEpochFlag,
flags.BatchVerifierLimit,
flags.StateDiffExponents,
flags.DisableEphemeralLogFile,
}

View File

@@ -74,7 +74,6 @@ var appHelpFlagGroups = []flagGroup{
flags.RPCHost,
flags.RPCPort,
flags.BatchVerifierLimit,
flags.StateDiffExponents,
},
},
{

View File

@@ -280,7 +280,6 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{
DisableQUIC,
EnableDiscoveryReboot,
enableExperimentalAttestationPool,
EnableStateDiff,
forceHeadFlag,
blacklistRoots,
enableHashtree,

View File

@@ -91,10 +91,6 @@ type BeaconChainConfig struct {
AggregateDueBPS primitives.BP `yaml:"AGGREGATE_DUE_BPS" spec:"true"` // AggregateDueBPS defines the aggregate due time in basis points of the slot.
SyncMessageDueBPS primitives.BP `yaml:"SYNC_MESSAGE_DUE_BPS" spec:"true"` // SyncMessageDueBPS defines the sync message due time in basis points of the slot.
ContributionDueBPS primitives.BP `yaml:"CONTRIBUTION_DUE_BPS" spec:"true"` // ContributionDueBPS defines the contribution due time in basis points of the slot.
AttestationDueBPSGloas primitives.BP `yaml:"ATTESTATION_DUE_BPS_GLOAS" spec:"true"` // AttestationDueBPSGloas defines the attestation due time in basis points of the slot (Gloas).
AggregateDueBPSGloas primitives.BP `yaml:"AGGREGATE_DUE_BPS_GLOAS" spec:"true"` // AggregateDueBPSGloas defines the aggregate due time in basis points of the slot (Gloas).
SyncMessageDueBPSGloas primitives.BP `yaml:"SYNC_MESSAGE_DUE_BPS_GLOAS" spec:"true"` // SyncMessageDueBPSGloas defines the sync message due time in basis points of the slot (Gloas).
ContributionDueBPSGloas primitives.BP `yaml:"CONTRIBUTION_DUE_BPS_GLOAS" spec:"true"` // ContributionDueBPSGloas defines the contribution due time in basis points of the slot (Gloas).
// Ethereum PoW parameters.
DepositChainID uint64 `yaml:"DEPOSIT_CHAIN_ID" spec:"true"` // DepositChainID of the eth1 network. This used for replay protection.
@@ -192,7 +188,6 @@ type BeaconChainConfig struct {
ElectraForkEpoch primitives.Epoch `yaml:"ELECTRA_FORK_EPOCH" spec:"true"` // ElectraForkEpoch is used to represent the assigned fork epoch for electra.
FuluForkVersion []byte `yaml:"FULU_FORK_VERSION" spec:"true"` // FuluForkVersion is used to represent the fork version for fulu.
FuluForkEpoch primitives.Epoch `yaml:"FULU_FORK_EPOCH" spec:"true"` // FuluForkEpoch is used to represent the assigned fork epoch for fulu.
GloasForkEpoch primitives.Epoch `yaml:"GLOAS_FORK_EPOCH" spec:"true"` // GloasForkEpoch is used to represent the assigned fork epoch for gloas.
ForkVersionSchedule map[[fieldparams.VersionLength]byte]primitives.Epoch // Schedule of fork epochs by version.
ForkVersionNames map[[fieldparams.VersionLength]byte]string // Human-readable names of fork versions.
@@ -348,7 +343,6 @@ func (b *BeaconChainConfig) VersionToForkEpochMap() map[int]primitives.Epoch {
version.Deneb: b.DenebForkEpoch,
version.Electra: b.ElectraForkEpoch,
version.Fulu: b.FuluForkEpoch,
version.Gloas: b.GloasForkEpoch,
}
}

View File

@@ -98,7 +98,6 @@ func compareConfigs(t *testing.T, expected, actual *BeaconChainConfig) {
require.DeepEqual(t, expected.EjectionBalance, actual.EjectionBalance)
require.DeepEqual(t, expected.EffectiveBalanceIncrement, actual.EffectiveBalanceIncrement)
require.DeepEqual(t, expected.BLSWithdrawalPrefixByte, actual.BLSWithdrawalPrefixByte)
require.DeepEqual(t, expected.BuilderWithdrawalPrefixByte, actual.BuilderWithdrawalPrefixByte)
require.DeepEqual(t, expected.ZeroHash, actual.ZeroHash)
require.DeepEqual(t, expected.GenesisDelay, actual.GenesisDelay)
require.DeepEqual(t, expected.MinAttestationInclusionDelay, actual.MinAttestationInclusionDelay)

View File

@@ -224,7 +224,6 @@ func ConfigToYaml(cfg *BeaconChainConfig) []byte {
fmt.Sprintf("ELECTRA_FORK_VERSION: %#x", cfg.ElectraForkVersion),
fmt.Sprintf("FULU_FORK_EPOCH: %d", cfg.FuluForkEpoch),
fmt.Sprintf("FULU_FORK_VERSION: %#x", cfg.FuluForkVersion),
fmt.Sprintf("GLOAS_FORK_EPOCH: %d", cfg.GloasForkEpoch),
fmt.Sprintf("EPOCHS_PER_SUBNET_SUBSCRIPTION: %d", cfg.EpochsPerSubnetSubscription),
fmt.Sprintf("ATTESTATION_SUBNET_EXTRA_BITS: %d", cfg.AttestationSubnetExtraBits),
fmt.Sprintf("ATTESTATION_SUBNET_PREFIX_BITS: %d", cfg.AttestationSubnetPrefixBits),
@@ -247,10 +246,6 @@ func ConfigToYaml(cfg *BeaconChainConfig) []byte {
fmt.Sprintf("AGGREGATE_DUE_BPS: %d", cfg.AggregateDueBPS),
fmt.Sprintf("SYNC_MESSAGE_DUE_BPS: %d", cfg.SyncMessageDueBPS),
fmt.Sprintf("CONTRIBUTION_DUE_BPS: %d", cfg.ContributionDueBPS),
fmt.Sprintf("ATTESTATION_DUE_BPS_GLOAS: %d", cfg.AttestationDueBPSGloas),
fmt.Sprintf("AGGREGATE_DUE_BPS_GLOAS: %d", cfg.AggregateDueBPSGloas),
fmt.Sprintf("SYNC_MESSAGE_DUE_BPS_GLOAS: %d", cfg.SyncMessageDueBPSGloas),
fmt.Sprintf("CONTRIBUTION_DUE_BPS_GLOAS: %d", cfg.ContributionDueBPSGloas),
}
if len(cfg.BlobSchedule) > 0 {

View File

@@ -24,9 +24,12 @@ import (
// These are variables that we don't use in Prysm. (i.e. future hardfork, light client... etc)
// IMPORTANT: Use one field per line and sort these alphabetically to reduce conflicts.
var placeholderFields = []string{
"AGGREGATE_DUE_BPS_GLOAS",
"ATTESTATION_DEADLINE",
"ATTESTATION_DUE_BPS_GLOAS",
"BLOB_SIDECAR_SUBNET_COUNT_FULU",
"CELLS_PER_EXT_BLOB",
"CONTRIBUTION_DUE_BPS_GLOAS",
"EIP6110_FORK_EPOCH",
"EIP6110_FORK_VERSION",
"EIP7002_FORK_EPOCH",
@@ -42,6 +45,7 @@ var placeholderFields = []string{
"EPOCHS_PER_SHUFFLING_PHASE",
"FIELD_ELEMENTS_PER_CELL", // Configured as a constant in config/fieldparams/mainnet.go
"FIELD_ELEMENTS_PER_EXT_BLOB", // Configured in proto/ssz_proto_library.bzl
"GLOAS_FORK_EPOCH",
"GLOAS_FORK_VERSION",
"INCLUSION_LIST_SUBMISSION_DEADLINE",
"INCLUSION_LIST_SUBMISSION_DUE_BPS",
@@ -56,6 +60,7 @@ var placeholderFields = []string{
"PROPOSER_INCLUSION_LIST_CUTOFF",
"PROPOSER_INCLUSION_LIST_CUTOFF_BPS",
"PROPOSER_SELECTION_GAP",
"SYNC_MESSAGE_DUE_BPS_GLOAS",
"TARGET_NUMBER_OF_PEERS",
"UPDATE_TIMEOUT",
"VIEW_FREEZE_CUTOFF_BPS",
@@ -119,7 +124,6 @@ func assertEqualConfigs(t *testing.T, name string, fields []string, expected, ac
// Initial values.
assert.DeepEqual(t, expected.GenesisForkVersion, actual.GenesisForkVersion, "%s: GenesisForkVersion", name)
assert.DeepEqual(t, expected.BLSWithdrawalPrefixByte, actual.BLSWithdrawalPrefixByte, "%s: BLSWithdrawalPrefixByte", name)
assert.DeepEqual(t, expected.BuilderWithdrawalPrefixByte, actual.BuilderWithdrawalPrefixByte, "%s: BuilderWithdrawalPrefixByte", name)
assert.DeepEqual(t, expected.ETH1AddressWithdrawalPrefixByte, actual.ETH1AddressWithdrawalPrefixByte, "%s: ETH1AddressWithdrawalPrefixByte", name)
// Time parameters.

View File

@@ -32,8 +32,6 @@ const (
mainnetElectraForkEpoch = 364032 // May 7, 2025, 10:05:11 UTC
// Fulu Fork Epoch for mainnet config
mainnetFuluForkEpoch = 411392 // December 3, 2025, 09:49:11pm UTC
// Gloas Fork Epoch for mainnet config
mainnetGloasForkEpoch = math.MaxUint64
)
var mainnetNetworkConfig = &NetworkConfig{
@@ -123,15 +121,11 @@ var mainnetBeaconConfig = &BeaconChainConfig{
IntervalsPerSlot: 3,
// Time-based protocol parameters.
ProposerReorgCutoffBPS: primitives.BP(1667),
AttestationDueBPS: primitives.BP(3333),
AggregateDueBPS: primitives.BP(6667),
SyncMessageDueBPS: primitives.BP(3333),
ContributionDueBPS: primitives.BP(6667),
AttestationDueBPSGloas: primitives.BP(2500),
AggregateDueBPSGloas: primitives.BP(5000),
SyncMessageDueBPSGloas: primitives.BP(2500),
ContributionDueBPSGloas: primitives.BP(5000),
ProposerReorgCutoffBPS: primitives.BP(1667),
AttestationDueBPS: primitives.BP(3333),
AggregateDueBPS: primitives.BP(6667),
SyncMessageDueBPS: primitives.BP(3333),
ContributionDueBPS: primitives.BP(6667),
// Ethereum PoW parameters.
DepositChainID: 1, // Chain ID of eth1 mainnet.
@@ -241,7 +235,6 @@ var mainnetBeaconConfig = &BeaconChainConfig{
ElectraForkEpoch: mainnetElectraForkEpoch,
FuluForkVersion: []byte{6, 0, 0, 0},
FuluForkEpoch: mainnetFuluForkEpoch,
GloasForkEpoch: mainnetGloasForkEpoch,
// New values introduced in Altair hard fork 1.
// Participation flag indices.

View File

@@ -31,15 +31,10 @@ func MinimalSpecConfig() *BeaconChainConfig {
// Initial values
minimalConfig.BLSWithdrawalPrefixByte = byte(0)
minimalConfig.ETH1AddressWithdrawalPrefixByte = byte(1)
minimalConfig.BuilderWithdrawalPrefixByte = byte(3)
// Time parameters
minimalConfig.SecondsPerSlot = 6
minimalConfig.SlotDurationMilliseconds = 6000
minimalConfig.AttestationDueBPSGloas = 2500
minimalConfig.AggregateDueBPSGloas = 5000
minimalConfig.SyncMessageDueBPSGloas = 2500
minimalConfig.ContributionDueBPSGloas = 5000
minimalConfig.MinAttestationInclusionDelay = 1
minimalConfig.SlotsPerEpoch = 8
minimalConfig.SqrRootSlotsPerEpoch = 2
@@ -103,7 +98,6 @@ func MinimalSpecConfig() *BeaconChainConfig {
minimalConfig.ElectraForkEpoch = math.MaxUint64
minimalConfig.FuluForkVersion = []byte{6, 0, 0, 1}
minimalConfig.FuluForkEpoch = math.MaxUint64
minimalConfig.GloasForkEpoch = minimalConfig.FarFutureEpoch
minimalConfig.SyncCommitteeSize = 32
minimalConfig.InactivityScoreBias = 4

View File

@@ -54,7 +54,6 @@ func compareConfigs(t *testing.T, expected, actual *params.BeaconChainConfig) {
require.DeepEqual(t, expected.EjectionBalance, actual.EjectionBalance)
require.DeepEqual(t, expected.EffectiveBalanceIncrement, actual.EffectiveBalanceIncrement)
require.DeepEqual(t, expected.BLSWithdrawalPrefixByte, actual.BLSWithdrawalPrefixByte)
require.DeepEqual(t, expected.BuilderWithdrawalPrefixByte, actual.BuilderWithdrawalPrefixByte)
require.DeepEqual(t, expected.ZeroHash, actual.ZeroHash)
require.DeepEqual(t, expected.GenesisDelay, actual.GenesisDelay)
require.DeepEqual(t, expected.MinAttestationInclusionDelay, actual.MinAttestationInclusionDelay)

View File

@@ -4,7 +4,6 @@ go_library(
name = "go_default_library",
srcs = [
"execution.go",
"execution_payload_envelope.go",
"factory.go",
"get_payload.go",
"getters.go",
@@ -37,7 +36,6 @@ go_library(
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
@@ -47,7 +45,6 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"execution_payload_envelope_test.go",
"execution_test.go",
"factory_test.go",
"getters_test.go",

View File

@@ -1,153 +0,0 @@
package blocks
import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
field_params "github.com/OffchainLabs/prysm/v7/config/fieldparams"
consensus_types "github.com/OffchainLabs/prysm/v7/consensus-types"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/ssz"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/ethereum/go-ethereum/common"
"google.golang.org/protobuf/proto"
)
type signedExecutionPayloadEnvelope struct {
s *ethpb.SignedExecutionPayloadEnvelope
}
type executionPayloadEnvelope struct {
p *ethpb.ExecutionPayloadEnvelope
}
// WrappedROSignedExecutionPayloadEnvelope wraps a signed execution payload envelope proto in a read-only interface.
func WrappedROSignedExecutionPayloadEnvelope(s *ethpb.SignedExecutionPayloadEnvelope) (interfaces.ROSignedExecutionPayloadEnvelope, error) {
w := signedExecutionPayloadEnvelope{s: s}
if w.IsNil() {
return nil, consensus_types.ErrNilObjectWrapped
}
return w, nil
}
// WrappedROExecutionPayloadEnvelope wraps an execution payload envelope proto in a read-only interface.
func WrappedROExecutionPayloadEnvelope(p *ethpb.ExecutionPayloadEnvelope) (interfaces.ROExecutionPayloadEnvelope, error) {
w := &executionPayloadEnvelope{p: p}
if w.IsNil() {
return nil, consensus_types.ErrNilObjectWrapped
}
return w, nil
}
// Envelope returns the execution payload envelope as a read-only interface.
func (s signedExecutionPayloadEnvelope) Envelope() (interfaces.ROExecutionPayloadEnvelope, error) {
return WrappedROExecutionPayloadEnvelope(s.s.Message)
}
// Signature returns the BLS signature as a 96-byte array.
func (s signedExecutionPayloadEnvelope) Signature() [field_params.BLSSignatureLength]byte {
return [field_params.BLSSignatureLength]byte(s.s.Signature)
}
// IsNil reports whether the signed envelope or its contents are invalid.
func (s signedExecutionPayloadEnvelope) IsNil() bool {
if s.s == nil {
return true
}
if len(s.s.Signature) != field_params.BLSSignatureLength {
return true
}
w := executionPayloadEnvelope{p: s.s.Message}
return w.IsNil()
}
// SigningRoot computes the signing root for the signed envelope with the provided domain.
func (s signedExecutionPayloadEnvelope) SigningRoot(domain []byte) (root [32]byte, err error) {
return signing.ComputeSigningRoot(s.s.Message, domain)
}
// Proto returns the underlying protobuf message.
func (s signedExecutionPayloadEnvelope) Proto() proto.Message {
return s.s
}
// IsNil reports whether the envelope or its required fields are invalid.
func (p *executionPayloadEnvelope) IsNil() bool {
if p.p == nil {
return true
}
if p.p.Payload == nil {
return true
}
if len(p.p.BeaconBlockRoot) != field_params.RootLength {
return true
}
if p.p.BlobKzgCommitments == nil {
return true
}
return false
}
// IsBlinded reports whether the envelope contains a blinded payload.
func (p *executionPayloadEnvelope) IsBlinded() bool {
return !p.IsNil() && p.p.Payload == nil
}
// Execution returns the execution payload as a read-only interface.
func (p *executionPayloadEnvelope) Execution() (interfaces.ExecutionData, error) {
return WrappedExecutionPayloadDeneb(p.p.Payload)
}
// ExecutionRequests returns the execution requests attached to the envelope.
func (p *executionPayloadEnvelope) ExecutionRequests() *enginev1.ExecutionRequests {
return p.p.ExecutionRequests
}
// BuilderIndex returns the proposer/builder index for the envelope.
func (p *executionPayloadEnvelope) BuilderIndex() primitives.BuilderIndex {
return p.p.BuilderIndex
}
// BeaconBlockRoot returns the beacon block root referenced by the envelope.
func (p *executionPayloadEnvelope) BeaconBlockRoot() [field_params.RootLength]byte {
return [field_params.RootLength]byte(p.p.BeaconBlockRoot)
}
// BlobKzgCommitments returns a copy of the envelope's KZG commitments.
func (p *executionPayloadEnvelope) BlobKzgCommitments() [][]byte {
commitments := make([][]byte, len(p.p.BlobKzgCommitments))
for i, commit := range p.p.BlobKzgCommitments {
commitments[i] = make([]byte, len(commit))
copy(commitments[i], commit)
}
return commitments
}
// VersionedHashes returns versioned hashes derived from the KZG commitments.
func (p *executionPayloadEnvelope) VersionedHashes() []common.Hash {
commitments := p.p.BlobKzgCommitments
versionedHashes := make([]common.Hash, len(commitments))
for i, commitment := range commitments {
versionedHashes[i] = primitives.ConvertKzgCommitmentToVersionedHash(commitment)
}
return versionedHashes
}
// BlobKzgCommitmentsRoot returns the SSZ root of the envelope's KZG commitments.
func (p *executionPayloadEnvelope) BlobKzgCommitmentsRoot() ([field_params.RootLength]byte, error) {
if p.IsNil() || p.p.BlobKzgCommitments == nil {
return [field_params.RootLength]byte{}, consensus_types.ErrNilObjectWrapped
}
return ssz.KzgCommitmentsRoot(p.p.BlobKzgCommitments)
}
// Slot returns the slot of the envelope.
func (p *executionPayloadEnvelope) Slot() primitives.Slot {
return p.p.Slot
}
// StateRoot returns the state root carried by the envelope.
func (p *executionPayloadEnvelope) StateRoot() [field_params.RootLength]byte {
return [field_params.RootLength]byte(p.p.StateRoot)
}

View File

@@ -1,115 +0,0 @@
package blocks_test
import (
"bytes"
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
consensus_types "github.com/OffchainLabs/prysm/v7/consensus-types"
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/assert"
"github.com/OffchainLabs/prysm/v7/testing/require"
)
func validExecutionPayloadEnvelope() *ethpb.ExecutionPayloadEnvelope {
payload := &enginev1.ExecutionPayloadDeneb{
ParentHash: bytes.Repeat([]byte{0x01}, 32),
FeeRecipient: bytes.Repeat([]byte{0x02}, 20),
StateRoot: bytes.Repeat([]byte{0x03}, 32),
ReceiptsRoot: bytes.Repeat([]byte{0x04}, 32),
LogsBloom: bytes.Repeat([]byte{0x05}, 256),
PrevRandao: bytes.Repeat([]byte{0x06}, 32),
BlockNumber: 1,
GasLimit: 2,
GasUsed: 3,
Timestamp: 4,
BaseFeePerGas: bytes.Repeat([]byte{0x07}, 32),
BlockHash: bytes.Repeat([]byte{0x08}, 32),
Transactions: [][]byte{},
Withdrawals: []*enginev1.Withdrawal{},
BlobGasUsed: 0,
ExcessBlobGas: 0,
}
return &ethpb.ExecutionPayloadEnvelope{
Payload: payload,
ExecutionRequests: &enginev1.ExecutionRequests{},
BuilderIndex: 10,
BeaconBlockRoot: bytes.Repeat([]byte{0xAA}, 32),
Slot: 9,
BlobKzgCommitments: [][]byte{bytes.Repeat([]byte{0x0C}, 48)},
StateRoot: bytes.Repeat([]byte{0xBB}, 32),
}
}
func TestWrappedROExecutionPayloadEnvelope(t *testing.T) {
t.Run("returns error on invalid beacon root length", func(t *testing.T) {
invalid := validExecutionPayloadEnvelope()
invalid.BeaconBlockRoot = []byte{0x01}
_, err := blocks.WrappedROExecutionPayloadEnvelope(invalid)
require.Equal(t, consensus_types.ErrNilObjectWrapped, err)
})
t.Run("wraps and exposes fields", func(t *testing.T) {
env := validExecutionPayloadEnvelope()
wrapped, err := blocks.WrappedROExecutionPayloadEnvelope(env)
require.NoError(t, err)
require.Equal(t, primitives.BuilderIndex(10), wrapped.BuilderIndex())
require.Equal(t, primitives.Slot(9), wrapped.Slot())
assert.DeepEqual(t, [32]byte(bytes.Repeat([]byte{0xAA}, 32)), wrapped.BeaconBlockRoot())
assert.DeepEqual(t, [32]byte(bytes.Repeat([]byte{0xBB}, 32)), wrapped.StateRoot())
commitments := wrapped.BlobKzgCommitments()
assert.DeepEqual(t, env.BlobKzgCommitments, commitments)
versioned := wrapped.VersionedHashes()
require.Equal(t, 1, len(versioned))
reqs := wrapped.ExecutionRequests()
require.NotNil(t, reqs)
exec, err := wrapped.Execution()
require.NoError(t, err)
assert.DeepEqual(t, env.Payload.ParentHash, exec.ParentHash())
})
}
func TestWrappedROSignedExecutionPayloadEnvelope(t *testing.T) {
t.Run("returns error for invalid signature length", func(t *testing.T) {
signed := &ethpb.SignedExecutionPayloadEnvelope{
Message: validExecutionPayloadEnvelope(),
Signature: bytes.Repeat([]byte{0xAA}, 95),
}
_, err := blocks.WrappedROSignedExecutionPayloadEnvelope(signed)
require.Equal(t, consensus_types.ErrNilObjectWrapped, err)
})
t.Run("wraps and provides envelope/signing data", func(t *testing.T) {
sig := bytes.Repeat([]byte{0xAB}, 96)
signed := &ethpb.SignedExecutionPayloadEnvelope{
Message: validExecutionPayloadEnvelope(),
Signature: sig,
}
wrapped, err := blocks.WrappedROSignedExecutionPayloadEnvelope(signed)
require.NoError(t, err)
gotSig := wrapped.Signature()
assert.DeepEqual(t, [96]byte(sig), gotSig)
env, err := wrapped.Envelope()
require.NoError(t, err)
assert.DeepEqual(t, [32]byte(bytes.Repeat([]byte{0xAA}, 32)), env.BeaconBlockRoot())
domain := bytes.Repeat([]byte{0xCC}, 32)
wantRoot, err := signing.ComputeSigningRoot(signed.Message, domain)
require.NoError(t, err)
gotRoot, err := wrapped.SigningRoot(domain)
require.NoError(t, err)
require.Equal(t, wantRoot, gotRoot)
})
}

View File

@@ -111,7 +111,7 @@ func (h executionPayloadBidGloas) GasLimit() uint64 {
return h.payload.GasLimit
}
// BuilderIndex returns the builder index of the builder who created this bid.
// BuilderIndex returns the validator index of the builder who created this bid.
func (h executionPayloadBidGloas) BuilderIndex() primitives.BuilderIndex {
return h.payload.BuilderIndex
}

View File

@@ -5,7 +5,6 @@ go_library(
srcs = [
"beacon_block.go",
"error.go",
"execution_payload_envelope.go",
"light_client.go",
"signed_execution_payload_bid.go",
"utils.go",
@@ -20,7 +19,6 @@ go_library(
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",

View File

@@ -1,31 +0,0 @@
package interfaces
import (
field_params "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
"github.com/ethereum/go-ethereum/common"
"google.golang.org/protobuf/proto"
)
type ROSignedExecutionPayloadEnvelope interface {
Envelope() (ROExecutionPayloadEnvelope, error)
Signature() [field_params.BLSSignatureLength]byte
SigningRoot([]byte) ([32]byte, error)
IsNil() bool
Proto() proto.Message
}
type ROExecutionPayloadEnvelope interface {
Execution() (ExecutionData, error)
ExecutionRequests() *enginev1.ExecutionRequests
BuilderIndex() primitives.BuilderIndex
BeaconBlockRoot() [field_params.RootLength]byte
BlobKzgCommitments() [][]byte
BlobKzgCommitmentsRoot() ([field_params.RootLength]byte, error)
VersionedHashes() []common.Hash
Slot() primitives.Slot
StateRoot() [field_params.RootLength]byte
IsBlinded() bool
IsNil() bool
}

View File

@@ -5,7 +5,6 @@ import (
"encoding/binary"
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
"github.com/OffchainLabs/prysm/v7/crypto/hash/htr"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
@@ -142,24 +141,3 @@ func withdrawalRoot(w *enginev1.Withdrawal) ([32]byte, error) {
}
return w.HashTreeRoot()
}
// KzgCommitmentsRoot computes the HTR for a list of KZG commitments
func KzgCommitmentsRoot(commitments [][]byte) ([32]byte, error) {
roots := make([][32]byte, len(commitments))
for i, commitment := range commitments {
chunks, err := PackByChunk([][]byte{commitment})
if err != nil {
return [32]byte{}, err
}
roots[i] = htr.VectorizedSha256(chunks)[0]
}
commitmentsRoot, err := BitwiseMerkleize(roots, uint64(len(roots)), fieldparams.MaxBlobCommitmentsPerBlock)
if err != nil {
return [32]byte{}, errors.Wrap(err, "could not compute merkleization")
}
length := make([]byte, 32)
binary.LittleEndian.PutUint64(length[:8], uint64(len(roots)))
return MixInLength(commitmentsRoot, length), nil
}

View File

@@ -103,7 +103,7 @@ func ConfigureEphemeralLogFile(datadirPath string, app string) error {
AllowedLevels: logrus.AllLevels[:ephemeralLogFileVerbosity+1],
})
logrus.WithField("path", logFilePath).Debug("Ephemeral log file initialized")
logrus.Debug("Ephemeral log file initialized")
return nil
}

View File

@@ -97,7 +97,6 @@ go_test(
"endtoend_setup_test.go",
"endtoend_test.go",
"minimal_e2e_test.go",
"minimal_hdiff_e2e_test.go",
"minimal_slashing_e2e_test.go",
"slasher_simulator_e2e_test.go",
],

View File

@@ -1,16 +0,0 @@
package endtoend
import (
"testing"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/OffchainLabs/prysm/v7/testing/endtoend/types"
)
func TestEndToEnd_MinimalConfig_WithStateDiff(t *testing.T) {
r := e2eMinimal(t, types.InitForkCfg(version.Bellatrix, version.Electra, params.E2ETestConfig()),
types.WithStateDiff(),
)
r.run()
}

View File

@@ -76,15 +76,6 @@ func WithSSZOnly() E2EConfigOpt {
}
}
func WithStateDiff() E2EConfigOpt {
return func(cfg *E2EConfig) {
cfg.BeaconFlags = append(cfg.BeaconFlags,
"--enable-state-diff",
"--state-diff-exponents=6,5", // Small exponents for quick testing
)
}
}
// WithExitEpoch sets a custom epoch for voluntary exit submission.
// This affects ProposeVoluntaryExit, ValidatorsHaveExited, SubmitWithdrawal, and ValidatorsHaveWithdrawn evaluators.
func WithExitEpoch(e primitives.Epoch) E2EConfigOpt {

View File

@@ -202,7 +202,6 @@ go_test(
"fulu__ssz_static__ssz_static_test.go",
"gloas__epoch_processing__process_builder_pending_payments_test.go",
"gloas__operations__execution_payload_header_test.go",
"gloas__operations__execution_payload_test.go",
"gloas__operations__payload_attestation_test.go",
"gloas__operations__proposer_slashing_test.go",
"gloas__sanity__slots_test.go",

View File

@@ -1,11 +0,0 @@
package mainnet
import (
"testing"
"github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations"
)
func TestMainnet_Gloas_Operations_ExecutionPayloadEnvelope(t *testing.T) {
operations.RunExecutionPayloadTest(t, "mainnet")
}

View File

@@ -208,7 +208,6 @@ go_test(
"fulu__ssz_static__ssz_static_test.go",
"gloas__epoch_processing__process_builder_pending_payments_test.go",
"gloas__operations__execution_payload_bid_test.go",
"gloas__operations__execution_payload_test.go",
"gloas__operations__payload_attestation_test.go",
"gloas__operations__proposer_slashing_test.go",
"gloas__sanity__slots_test.go",

View File

@@ -1,11 +0,0 @@
package minimal
import (
"testing"
"github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations"
)
func TestMinimal_Gloas_Operations_ExecutionPayloadEnvelope(t *testing.T) {
operations.RunExecutionPayloadTest(t, "minimal")
}

View File

@@ -4,7 +4,6 @@ go_library(
name = "go_default_library",
testonly = True,
srcs = [
"execution_payload.go",
"execution_payload_bid.go",
"helpers.go",
"payload_attestation.go",
@@ -13,23 +12,12 @@ go_library(
importpath = "github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/core/gloas:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//testing/require:go_default_library",
"//testing/spectest/shared/common/operations:go_default_library",
"//testing/spectest/utils:go_default_library",
"//testing/util:go_default_library",
"@com_github_golang_snappy//:go_default_library",
"@com_github_google_go_cmp//cmp:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_google_protobuf//testing/protocmp:go_default_library",
],
)

View File

@@ -1,123 +0,0 @@
package operations
import (
"context"
"os"
"path"
"strings"
"testing"
"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/state"
"github.com/OffchainLabs/prysm/v7/config/params"
"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"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/testing/spectest/utils"
"github.com/OffchainLabs/prysm/v7/testing/util"
"github.com/bazelbuild/rules_go/go/tools/bazel"
"github.com/golang/snappy"
"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
)
type ExecutionConfig struct {
Valid bool `json:"execution_valid"`
}
func sszToSignedExecutionPayloadEnvelope(b []byte) (interfaces.ROSignedExecutionPayloadEnvelope, error) {
envelope := &ethpb.SignedExecutionPayloadEnvelope{}
if err := envelope.UnmarshalSSZ(b); err != nil {
return nil, err
}
return blocks.WrappedROSignedExecutionPayloadEnvelope(envelope)
}
func RunExecutionPayloadTest(t *testing.T, config string) {
require.NoError(t, utils.SetConfig(t, config))
cfg := params.BeaconConfig()
params.SetGenesisFork(t, cfg, version.Fulu)
testFolders, testsFolderPath := utils.TestFolders(t, config, "gloas", "operations/execution_payload/pyspec_tests")
if len(testFolders) == 0 {
t.Fatalf("No test folders found for %s/%s/%s", config, "gloas", "operations/execution_payload/pyspec_tests")
}
for _, folder := range testFolders {
t.Run(folder.Name(), func(t *testing.T) {
helpers.ClearCache()
// Check if signed_envelope.ssz_snappy exists, skip if not
_, err := bazel.Runfile(path.Join(testsFolderPath, folder.Name(), "signed_envelope.ssz_snappy"))
if err != nil && strings.Contains(err.Error(), "could not locate file") {
t.Skipf("Skipping test %s: signed_envelope.ssz_snappy not found", folder.Name())
return
}
// Read the signed execution payload envelope
envelopeFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "signed_envelope.ssz_snappy")
require.NoError(t, err)
envelopeSSZ, err := snappy.Decode(nil /* dst */, envelopeFile)
require.NoError(t, err, "Failed to decompress envelope")
signedEnvelope, err := sszToSignedExecutionPayloadEnvelope(envelopeSSZ)
require.NoError(t, err, "Failed to unmarshal signed envelope")
preBeaconStateFile, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "pre.ssz_snappy")
require.NoError(t, err)
preBeaconStateSSZ, err := snappy.Decode(nil /* dst */, preBeaconStateFile)
require.NoError(t, err, "Failed to decompress")
preBeaconState, err := sszToState(preBeaconStateSSZ)
require.NoError(t, err)
postSSZFilepath, err := bazel.Runfile(path.Join(testsFolderPath, folder.Name(), "post.ssz_snappy"))
postSSZExists := true
if err != nil && strings.Contains(err.Error(), "could not locate file") {
postSSZExists = false
} else {
require.NoError(t, err)
}
file, err := util.BazelFileBytes(testsFolderPath, folder.Name(), "execution.yaml")
require.NoError(t, err)
config := &ExecutionConfig{}
require.NoError(t, utils.UnmarshalYaml(file, config), "Failed to Unmarshal")
if !config.Valid {
t.Skip("Skipping invalid execution engine test as it's never supported")
}
err = gloas.ProcessExecutionPayload(context.Background(), preBeaconState, signedEnvelope)
if postSSZExists {
require.NoError(t, err)
comparePostState(t, postSSZFilepath, preBeaconState)
} else if config.Valid {
// Note: This doesn't test anything worthwhile. It essentially tests
// that *any* error has occurred, not any specific error.
if err == nil {
t.Fatal("Did not fail when expected")
}
t.Logf("Expected failure; failure reason = %v", err)
return
}
})
}
}
func comparePostState(t *testing.T, postSSZFilepath string, want state.BeaconState) {
postBeaconStateFile, err := os.ReadFile(postSSZFilepath) // #nosec G304
require.NoError(t, err)
postBeaconStateSSZ, err := snappy.Decode(nil /* dst */, postBeaconStateFile)
require.NoError(t, err, "Failed to decompress")
postBeaconState, err := sszToState(postBeaconStateSSZ)
require.NoError(t, err)
postBeaconStatePb, ok := postBeaconState.ToProtoUnsafe().(proto.Message)
require.Equal(t, true, ok, "post beacon state did not return a proto.Message")
pbState, ok := want.ToProtoUnsafe().(proto.Message)
require.Equal(t, true, ok, "beacon state did not return a proto.Message")
if !proto.Equal(postBeaconStatePb, pbState) {
diff := cmp.Diff(pbState, postBeaconStatePb, protocmp.Transform())
t.Fatalf("Post state does not match expected state, diff: %s", diff)
}
}

View File

@@ -66,7 +66,7 @@ func (v *validator) SubmitAggregateAndProof(ctx context.Context, slot primitives
// As specified in spec, an aggregator should wait until two thirds of the way through slot
// to broadcast the best aggregate to the global aggregate channel.
// https://github.com/ethereum/consensus-specs/blob/v0.9.3/specs/validator/0_beacon-chain-validator.md#broadcast-aggregate
v.waitUntilAggregateDue(ctx, slot)
v.waitToSlotTwoThirds(ctx, slot)
// In a DV setup, selection proofs need to be agreed upon by the DV.
// Checking for selection proofs at slot 0 of the epoch will result in an error, as the call to the DV executes slower than the start of this function.
@@ -203,18 +203,11 @@ func (v *validator) signSlotWithSelectionProof(ctx context.Context, pubKey [fiel
return sig.Marshal(), nil
}
// waitUntilAggregateDue waits until the configured aggregation due time within the current slot
// such that any attestations from this slot have time to reach the beacon node before creating
// the aggregated attestation.
//
// Note: Historically this was ~2/3 of the slot, but may differ across forks (e.g. Gloas).
func (v *validator) waitUntilAggregateDue(ctx context.Context, slot primitives.Slot) {
cfg := params.BeaconConfig()
component := cfg.AggregateDueBPS
if slots.ToEpoch(slot) >= cfg.GloasForkEpoch {
component = cfg.AggregateDueBPSGloas
}
v.waitUntilSlotComponent(ctx, slot, component)
// waitToSlotTwoThirds waits until two third through the current slot period
// such that any attestations from this slot have time to reach the beacon node
// before creating the aggregated attestation.
func (v *validator) waitToSlotTwoThirds(ctx context.Context, slot primitives.Slot) {
v.waitUntilSlotComponent(ctx, slot, params.BeaconConfig().AggregateDueBPS)
}
// This returns the signature of validator signing over aggregate and

View File

@@ -260,7 +260,7 @@ func TestWaitForSlotTwoThird_WaitCorrectly(t *testing.T) {
timeToSleep := params.BeaconConfig().SlotComponentDuration(params.BeaconConfig().AggregateDueBPS)
twoThirdTime := currentTime.Add(timeToSleep)
validator.waitUntilAggregateDue(t.Context(), numOfSlots)
validator.waitToSlotTwoThirds(t.Context(), numOfSlots)
currentTime = time.Now()
assert.Equal(t, twoThirdTime.Unix(), currentTime.Unix())
})
@@ -280,7 +280,7 @@ func TestWaitForSlotTwoThird_DoneContext_ReturnsImmediately(t *testing.T) {
expectedTime := time.Now()
ctx, cancel := context.WithCancel(t.Context())
cancel()
validator.waitUntilAggregateDue(ctx, numOfSlots)
validator.waitToSlotTwoThirds(ctx, numOfSlots)
currentTime = time.Now()
assert.Equal(t, expectedTime.Unix(), currentTime.Unix())
})

View File

@@ -37,7 +37,7 @@ func (v *validator) SubmitAttestation(ctx context.Context, slot primitives.Slot,
defer span.End()
span.SetAttributes(trace.StringAttribute("validator", fmt.Sprintf("%#x", pubKey)))
v.waitUntilAttestationDueOrValidBlock(ctx, slot)
v.waitOneThirdOrValidBlock(ctx, slot)
var b strings.Builder
if err := b.WriteByte(byte(iface.RoleAttester)); err != nil {
@@ -259,12 +259,12 @@ func (v *validator) setHighestSlot(slot primitives.Slot) {
}
}
// waitUntilAttestationDueOrValidBlock waits until (a) or (b) whichever comes first:
// waitOneThirdOrValidBlock waits until (a) or (b) whichever comes first:
//
// (a) the validator has received a valid block that is the same slot as input slot
// (b) the configured attestation due time has transpired (as basis points of the slot duration)
func (v *validator) waitUntilAttestationDueOrValidBlock(ctx context.Context, slot primitives.Slot) {
ctx, span := trace.StartSpan(ctx, "validator.waitUntilAttestationDueOrValidBlock")
// (b) one-third of the slot has transpired (SECONDS_PER_SLOT / 3 seconds after the start of slot)
func (v *validator) waitOneThirdOrValidBlock(ctx context.Context, slot primitives.Slot) {
ctx, span := trace.StartSpan(ctx, "validator.waitOneThirdOrValidBlock")
defer span.End()
// Don't need to wait if requested slot is the same as highest valid slot.
@@ -272,12 +272,7 @@ func (v *validator) waitUntilAttestationDueOrValidBlock(ctx context.Context, slo
return
}
cfg := params.BeaconConfig()
component := cfg.AttestationDueBPS
if slots.ToEpoch(slot) >= cfg.GloasForkEpoch {
component = cfg.AttestationDueBPSGloas
}
finalTime, err := v.slotComponentDeadline(slot, component)
finalTime, err := v.slotComponentDeadline(slot, params.BeaconConfig().AttestationDueBPS)
if err != nil {
log.WithError(err).WithField("slot", slot).Error("Slot overflows, unable to wait for attestation deadline")
return

View File

@@ -706,7 +706,7 @@ func TestServer_WaitToSlotOneThird_CanWait(t *testing.T) {
timeToSleep := params.BeaconConfig().SecondsPerSlot / 3
oneThird := currentTime.Add(time.Duration(timeToSleep) * time.Second)
v.waitUntilAttestationDueOrValidBlock(t.Context(), currentSlot)
v.waitOneThirdOrValidBlock(t.Context(), currentSlot)
if oneThird.Sub(time.Now()) > 10*time.Millisecond { // Allow for small diff due to execution time.
t.Errorf("Wanted %s time for slot one third but got %s", oneThird, currentTime)
@@ -724,7 +724,7 @@ func TestServer_WaitToSlotOneThird_SameReqSlot(t *testing.T) {
highestValidSlot: currentSlot,
}
v.waitUntilAttestationDueOrValidBlock(t.Context(), currentSlot)
v.waitOneThirdOrValidBlock(t.Context(), currentSlot)
if currentTime.Sub(time.Now()) > 10*time.Millisecond { // Allow for small diff due to execution time.
t.Errorf("Wanted %s time for slot one third but got %s", time.Now(), currentTime)
@@ -750,7 +750,7 @@ func TestServer_WaitToSlotOneThird_ReceiveBlockSlot(t *testing.T) {
v.slotFeed.Send(currentSlot)
})
v.waitUntilAttestationDueOrValidBlock(t.Context(), currentSlot)
v.waitOneThirdOrValidBlock(t.Context(), currentSlot)
if currentTime.Sub(time.Now()) > 10*time.Millisecond { // Allow for small diff due to execution time.
t.Errorf("Wanted %s time for slot one third but got %s", time.Now(), currentTime)

View File

@@ -29,7 +29,7 @@ func (v *validator) SubmitSyncCommitteeMessage(ctx context.Context, slot primiti
defer span.End()
span.SetAttributes(trace.StringAttribute("validator", fmt.Sprintf("%#x", pubKey)))
v.waitUntilAttestationDueOrValidBlock(ctx, slot)
v.waitOneThirdOrValidBlock(ctx, slot)
res, err := v.validatorClient.SyncMessageBlockRoot(ctx, &emptypb.Empty{})
if err != nil {
@@ -127,12 +127,7 @@ func (v *validator) SubmitSignedContributionAndProof(ctx context.Context, slot p
return
}
cfg := params.BeaconConfig()
component := cfg.ContributionDueBPS
if slots.ToEpoch(slot) >= cfg.GloasForkEpoch {
component = cfg.ContributionDueBPSGloas
}
v.waitUntilSlotComponent(ctx, slot, component)
v.waitUntilSlotComponent(ctx, slot, params.BeaconConfig().ContributionDueBPS)
coveredSubnets := make(map[uint64]bool)
for i, comIdx := range indexRes.Indices {

View File

@@ -51,20 +51,12 @@ func (v *validator) slotComponentSpanName(component primitives.BP) string {
switch component {
case cfg.AttestationDueBPS:
return "validator.waitAttestationWindow"
case cfg.AttestationDueBPSGloas:
return "validator.waitAttestationWindow"
case cfg.AggregateDueBPS:
return "validator.waitAggregateWindow"
case cfg.AggregateDueBPSGloas:
return "validator.waitAggregateWindow"
case cfg.SyncMessageDueBPS:
return "validator.waitSyncMessageWindow"
case cfg.SyncMessageDueBPSGloas:
return "validator.waitSyncMessageWindow"
case cfg.ContributionDueBPS:
return "validator.waitContributionWindow"
case cfg.ContributionDueBPSGloas:
return "validator.waitContributionWindow"
case cfg.ProposerReorgCutoffBPS:
return "validator.waitProposerReorgWindow"
default: