mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-17 01:08:05 -05:00
Compare commits
8 Commits
hdiff_star
...
use-delay
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9de4eec82a | ||
|
|
a08f185170 | ||
|
|
15b1d68249 | ||
|
|
885d9cc478 | ||
|
|
511248213c | ||
|
|
1a936e2ffa | ||
|
|
6027518ad5 | ||
|
|
e4a6bc7065 |
10
BUILD.bazel
10
BUILD.bazel
@@ -1,5 +1,4 @@
|
||||
load("@bazel_gazelle//:def.bzl", "gazelle")
|
||||
load("@com_github_atlassian_bazel_tools//gometalinter:def.bzl", "gometalinter")
|
||||
load("@com_github_atlassian_bazel_tools//goimports:def.bzl", "goimports")
|
||||
load("@io_kubernetes_build//defs:run_in_workspace.bzl", "workspace_binary")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "nogo")
|
||||
@@ -55,15 +54,6 @@ alias(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
gometalinter(
|
||||
name = "gometalinter",
|
||||
config = "//:.gometalinter.json",
|
||||
paths = [
|
||||
"./...",
|
||||
],
|
||||
prefix = prefix,
|
||||
)
|
||||
|
||||
goimports(
|
||||
name = "goimports",
|
||||
display_diffs = True,
|
||||
|
||||
@@ -423,10 +423,6 @@ load("@prysm//testing/endtoend:deps.bzl", "e2e_deps")
|
||||
|
||||
e2e_deps()
|
||||
|
||||
load("@com_github_atlassian_bazel_tools//gometalinter:deps.bzl", "gometalinter_dependencies")
|
||||
|
||||
gometalinter_dependencies()
|
||||
|
||||
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
|
||||
|
||||
gazelle_dependencies(go_sdk = "go_sdk")
|
||||
|
||||
@@ -13,7 +13,7 @@ go_library(
|
||||
deps = [
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"@com_github_crate_crypto_go_kzg_4844//:go_default_library",
|
||||
"@com_github_ethereum_c_kzg_4844//bindings/go:go_default_library",
|
||||
"@com_github_ethereum_c_kzg_4844_v2//bindings/go:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//crypto/kzg4844:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
|
||||
@@ -221,6 +221,19 @@ var (
|
||||
Buckets: []float64{1, 2, 4, 8, 16, 32},
|
||||
},
|
||||
)
|
||||
commitmentCount = promauto.NewHistogram(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "commitment_count_max_21",
|
||||
Help: "The number of blob KZG commitments per block.",
|
||||
Buckets: []float64{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21},
|
||||
},
|
||||
)
|
||||
maxBlobsPerBlock = promauto.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "max_blobs_per_block",
|
||||
Help: "The maximum number of blobs allowed in a block.",
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
// reportSlotMetrics reports slot related metrics.
|
||||
|
||||
@@ -94,6 +94,7 @@ func (s *Service) spawnProcessAttestationsRoutine() {
|
||||
for {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
ticker.Done()
|
||||
return
|
||||
case slotInterval := <-ticker.C():
|
||||
if slotInterval.Interval > 0 {
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/slasher/types"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||
"github.com/OffchainLabs/prysm/v7/config/features"
|
||||
"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"
|
||||
@@ -258,32 +259,55 @@ func (s *Service) handleDA(ctx context.Context, avs das.AvailabilityChecker, blo
|
||||
}
|
||||
|
||||
func (s *Service) reportPostBlockProcessing(
|
||||
block interfaces.SignedBeaconBlock,
|
||||
signedBlock interfaces.SignedBeaconBlock,
|
||||
blockRoot [32]byte,
|
||||
receivedTime time.Time,
|
||||
daWaitedTime time.Duration,
|
||||
) {
|
||||
block := signedBlock.Block()
|
||||
if block == nil {
|
||||
log.WithField("blockRoot", blockRoot).Error("Nil block")
|
||||
return
|
||||
}
|
||||
|
||||
// Reports on block and fork choice metrics.
|
||||
cp := s.cfg.ForkChoiceStore.FinalizedCheckpoint()
|
||||
finalized := ðpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
|
||||
reportSlotMetrics(block.Block().Slot(), s.HeadSlot(), s.CurrentSlot(), finalized)
|
||||
reportSlotMetrics(block.Slot(), s.HeadSlot(), s.CurrentSlot(), finalized)
|
||||
|
||||
// Log block sync status.
|
||||
cp = s.cfg.ForkChoiceStore.JustifiedCheckpoint()
|
||||
justified := ðpb.Checkpoint{Epoch: cp.Epoch, Root: bytesutil.SafeCopyBytes(cp.Root[:])}
|
||||
if err := logBlockSyncStatus(block.Block(), blockRoot, justified, finalized, receivedTime, s.genesisTime, daWaitedTime); err != nil {
|
||||
if err := logBlockSyncStatus(block, blockRoot, justified, finalized, receivedTime, s.genesisTime, daWaitedTime); err != nil {
|
||||
log.WithError(err).Error("Unable to log block sync status")
|
||||
}
|
||||
|
||||
// Log payload data
|
||||
if err := logPayload(block.Block()); err != nil {
|
||||
if err := logPayload(block); err != nil {
|
||||
log.WithError(err).Error("Unable to log debug block payload data")
|
||||
}
|
||||
|
||||
// Log state transition data.
|
||||
if err := logStateTransitionData(block.Block()); err != nil {
|
||||
if err := logStateTransitionData(block); err != nil {
|
||||
log.WithError(err).Error("Unable to log state transition data")
|
||||
}
|
||||
|
||||
timeWithoutDaWait := time.Since(receivedTime) - daWaitedTime
|
||||
chainServiceProcessingTime.Observe(float64(timeWithoutDaWait.Milliseconds()))
|
||||
|
||||
body := block.Body()
|
||||
if body == nil {
|
||||
log.WithField("blockRoot", blockRoot).Error("Nil block body")
|
||||
return
|
||||
}
|
||||
|
||||
commitments, err := body.BlobKzgCommitments()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Unable to get blob KZG commitments")
|
||||
}
|
||||
|
||||
commitmentCount.Observe(float64(len(commitments)))
|
||||
maxBlobsPerBlock.Set(float64(params.BeaconConfig().MaxBlobsPerBlock(block.Slot())))
|
||||
}
|
||||
|
||||
func (s *Service) executePostFinalizationTasks(ctx context.Context, finalizedState state.BeaconState) {
|
||||
|
||||
45
beacon-chain/core/gloas/BUILD.bazel
Normal file
45
beacon-chain/core/gloas/BUILD.bazel
Normal file
@@ -0,0 +1,45 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["bid.go"],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/blocks:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["bid_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/interfaces:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//crypto/bls/common:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
193
beacon-chain/core/gloas/bid.go
Normal file
193
beacon-chain/core/gloas/bid.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package gloas
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
||||
"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/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls/common"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ProcessExecutionPayloadBid processes a signed execution payload bid in the Gloas fork.
|
||||
// Spec v1.7.0-alpha.0 (pseudocode):
|
||||
// process_execution_payload_bid(state: BeaconState, block: BeaconBlock):
|
||||
//
|
||||
// signed_bid = block.body.signed_execution_payload_bid
|
||||
// bid = signed_bid.message
|
||||
// builder_index = bid.builder_index
|
||||
// amount = bid.value
|
||||
// if builder_index == BUILDER_INDEX_SELF_BUILD:
|
||||
// assert amount == 0
|
||||
// assert signed_bid.signature == G2_POINT_AT_INFINITY
|
||||
// else:
|
||||
// assert is_active_builder(state, builder_index)
|
||||
// assert can_builder_cover_bid(state, builder_index, amount)
|
||||
// assert verify_execution_payload_bid_signature(state, signed_bid)
|
||||
// assert bid.slot == block.slot
|
||||
// assert bid.parent_block_hash == state.latest_block_hash
|
||||
// assert bid.parent_block_root == block.parent_root
|
||||
// assert bid.prev_randao == get_randao_mix(state, get_current_epoch(state))
|
||||
// if amount > 0:
|
||||
// state.builder_pending_payments[...] = BuilderPendingPayment(weight=0, withdrawal=BuilderPendingWithdrawal(fee_recipient=bid.fee_recipient, amount=amount, builder_index=builder_index))
|
||||
// state.latest_execution_payload_bid = bid
|
||||
func ProcessExecutionPayloadBid(st state.BeaconState, block interfaces.ReadOnlyBeaconBlock) error {
|
||||
signedBid, err := block.Body().SignedExecutionPayloadBid()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get signed execution payload bid")
|
||||
}
|
||||
|
||||
wrappedBid, err := blocks.WrappedROSignedExecutionPayloadBid(signedBid)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to wrap signed bid")
|
||||
}
|
||||
|
||||
bid, err := wrappedBid.Bid()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get bid from wrapped bid")
|
||||
}
|
||||
|
||||
builderIndex := bid.BuilderIndex()
|
||||
amount := bid.Value()
|
||||
|
||||
if builderIndex == params.BeaconConfig().BuilderIndexSelfBuild {
|
||||
if amount != 0 {
|
||||
return fmt.Errorf("self-build amount must be zero, got %d", amount)
|
||||
}
|
||||
if wrappedBid.Signature() != common.InfiniteSignature {
|
||||
return errors.New("self-build signature must be point at infinity")
|
||||
}
|
||||
} else {
|
||||
ok, err := st.IsActiveBuilder(builderIndex)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "builder active check failed")
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("builder %d is not active", builderIndex)
|
||||
}
|
||||
|
||||
ok, err = st.CanBuilderCoverBid(builderIndex, amount)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "builder balance check failed")
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("builder %d cannot cover bid amount %d", builderIndex, amount)
|
||||
}
|
||||
|
||||
if err := validatePayloadBidSignature(st, wrappedBid); err != nil {
|
||||
return errors.Wrap(err, "bid signature validation failed")
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateBidConsistency(st, bid, block); err != nil {
|
||||
return errors.Wrap(err, "bid consistency validation failed")
|
||||
}
|
||||
|
||||
if amount > 0 {
|
||||
feeRecipient := bid.FeeRecipient()
|
||||
pendingPayment := ðpb.BuilderPendingPayment{
|
||||
Weight: 0,
|
||||
Withdrawal: ðpb.BuilderPendingWithdrawal{
|
||||
FeeRecipient: feeRecipient[:],
|
||||
Amount: amount,
|
||||
BuilderIndex: builderIndex,
|
||||
},
|
||||
}
|
||||
slotIndex := params.BeaconConfig().SlotsPerEpoch + (bid.Slot() % params.BeaconConfig().SlotsPerEpoch)
|
||||
if err := st.SetBuilderPendingPayment(slotIndex, pendingPayment); err != nil {
|
||||
return errors.Wrap(err, "failed to set pending payment")
|
||||
}
|
||||
}
|
||||
|
||||
if err := st.SetExecutionPayloadBid(bid); err != nil {
|
||||
return errors.Wrap(err, "failed to cache execution payload bid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateBidConsistency checks that the bid is consistent with the current beacon state.
|
||||
func validateBidConsistency(st state.BeaconState, bid interfaces.ROExecutionPayloadBid, block interfaces.ReadOnlyBeaconBlock) error {
|
||||
if bid.Slot() != block.Slot() {
|
||||
return fmt.Errorf("bid slot %d does not match block slot %d", bid.Slot(), block.Slot())
|
||||
}
|
||||
|
||||
latestBlockHash, err := st.LatestBlockHash()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get latest block hash")
|
||||
}
|
||||
if bid.ParentBlockHash() != latestBlockHash {
|
||||
return fmt.Errorf("bid parent block hash mismatch: got %x, expected %x",
|
||||
bid.ParentBlockHash(), latestBlockHash)
|
||||
}
|
||||
|
||||
if bid.ParentBlockRoot() != block.ParentRoot() {
|
||||
return fmt.Errorf("bid parent block root mismatch: got %x, expected %x",
|
||||
bid.ParentBlockRoot(), block.ParentRoot())
|
||||
}
|
||||
|
||||
randaoMix, err := helpers.RandaoMix(st, slots.ToEpoch(st.Slot()))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get randao mix")
|
||||
}
|
||||
if bid.PrevRandao() != [32]byte(randaoMix) {
|
||||
return fmt.Errorf("bid prev randao mismatch: got %x, expected %x", bid.PrevRandao(), randaoMix)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validatePayloadBidSignature verifies the BLS signature on a signed execution payload bid.
|
||||
// It validates that the signature was created by the builder specified in the bid
|
||||
// using the appropriate domain for the beacon builder.
|
||||
func validatePayloadBidSignature(st state.ReadOnlyBeaconState, signedBid interfaces.ROSignedExecutionPayloadBid) error {
|
||||
bid, err := signedBid.Bid()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get bid")
|
||||
}
|
||||
|
||||
pubkey, err := st.BuilderPubkey(bid.BuilderIndex())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get builder pubkey")
|
||||
}
|
||||
|
||||
publicKey, err := bls.PublicKeyFromBytes(pubkey[:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid builder public key")
|
||||
}
|
||||
|
||||
signatureBytes := signedBid.Signature()
|
||||
signature, err := bls.SignatureFromBytes(signatureBytes[:])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid signature format")
|
||||
}
|
||||
|
||||
currentEpoch := slots.ToEpoch(bid.Slot())
|
||||
domain, err := signing.Domain(
|
||||
st.Fork(),
|
||||
currentEpoch,
|
||||
params.BeaconConfig().DomainBeaconBuilder,
|
||||
st.GenesisValidatorsRoot(),
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to compute signing domain")
|
||||
}
|
||||
|
||||
signingRoot, err := signedBid.SigningRoot(domain)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to compute signing root")
|
||||
}
|
||||
|
||||
if !signature.Verify(publicKey, signingRoot[:]) {
|
||||
return signing.ErrSigFailedToVerify
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
633
beacon-chain/core/gloas/bid_test.go
Normal file
633
beacon-chain/core/gloas/bid_test.go
Normal file
@@ -0,0 +1,633 @@
|
||||
package gloas
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
|
||||
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/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls/common"
|
||||
"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"
|
||||
validatorpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/time/slots"
|
||||
fastssz "github.com/prysmaticlabs/fastssz"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type stubBlockBody struct {
|
||||
signedBid *ethpb.SignedExecutionPayloadBid
|
||||
}
|
||||
|
||||
func (s stubBlockBody) Version() int { return version.Gloas }
|
||||
func (s stubBlockBody) RandaoReveal() [96]byte { return [96]byte{} }
|
||||
func (s stubBlockBody) Eth1Data() *ethpb.Eth1Data { return nil }
|
||||
func (s stubBlockBody) Graffiti() [32]byte { return [32]byte{} }
|
||||
func (s stubBlockBody) ProposerSlashings() []*ethpb.ProposerSlashing { return nil }
|
||||
func (s stubBlockBody) AttesterSlashings() []ethpb.AttSlashing { return nil }
|
||||
func (s stubBlockBody) Attestations() []ethpb.Att { return nil }
|
||||
func (s stubBlockBody) Deposits() []*ethpb.Deposit { return nil }
|
||||
func (s stubBlockBody) VoluntaryExits() []*ethpb.SignedVoluntaryExit { return nil }
|
||||
func (s stubBlockBody) SyncAggregate() (*ethpb.SyncAggregate, error) { return nil, nil }
|
||||
func (s stubBlockBody) IsNil() bool { return s.signedBid == nil }
|
||||
func (s stubBlockBody) HashTreeRoot() ([32]byte, error) { return [32]byte{}, nil }
|
||||
func (s stubBlockBody) Proto() (proto.Message, error) { return nil, nil }
|
||||
func (s stubBlockBody) Execution() (interfaces.ExecutionData, error) { return nil, nil }
|
||||
func (s stubBlockBody) BLSToExecutionChanges() ([]*ethpb.SignedBLSToExecutionChange, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s stubBlockBody) BlobKzgCommitments() ([][]byte, error) { return nil, nil }
|
||||
func (s stubBlockBody) ExecutionRequests() (*enginev1.ExecutionRequests, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s stubBlockBody) PayloadAttestations() ([]*ethpb.PayloadAttestation, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s stubBlockBody) SignedExecutionPayloadBid() (*ethpb.SignedExecutionPayloadBid, error) {
|
||||
return s.signedBid, nil
|
||||
}
|
||||
func (s stubBlockBody) MarshalSSZ() ([]byte, error) { return nil, nil }
|
||||
func (s stubBlockBody) MarshalSSZTo([]byte) ([]byte, error) { return nil, nil }
|
||||
func (s stubBlockBody) UnmarshalSSZ([]byte) error { return nil }
|
||||
func (s stubBlockBody) SizeSSZ() int { return 0 }
|
||||
|
||||
type stubBlock struct {
|
||||
slot primitives.Slot
|
||||
proposer primitives.ValidatorIndex
|
||||
parentRoot [32]byte
|
||||
body stubBlockBody
|
||||
v int
|
||||
}
|
||||
|
||||
var (
|
||||
_ interfaces.ReadOnlyBeaconBlockBody = (*stubBlockBody)(nil)
|
||||
_ interfaces.ReadOnlyBeaconBlock = (*stubBlock)(nil)
|
||||
)
|
||||
|
||||
func (s stubBlock) Slot() primitives.Slot { return s.slot }
|
||||
func (s stubBlock) ProposerIndex() primitives.ValidatorIndex { return s.proposer }
|
||||
func (s stubBlock) ParentRoot() [32]byte { return s.parentRoot }
|
||||
func (s stubBlock) StateRoot() [32]byte { return [32]byte{} }
|
||||
func (s stubBlock) Body() interfaces.ReadOnlyBeaconBlockBody { return s.body }
|
||||
func (s stubBlock) IsNil() bool { return false }
|
||||
func (s stubBlock) IsBlinded() bool { return false }
|
||||
func (s stubBlock) HashTreeRoot() ([32]byte, error) { return [32]byte{}, nil }
|
||||
func (s stubBlock) Proto() (proto.Message, error) { return nil, nil }
|
||||
func (s stubBlock) MarshalSSZ() ([]byte, error) { return nil, nil }
|
||||
func (s stubBlock) MarshalSSZTo([]byte) ([]byte, error) { return nil, nil }
|
||||
func (s stubBlock) UnmarshalSSZ([]byte) error { return nil }
|
||||
func (s stubBlock) SizeSSZ() int { return 0 }
|
||||
func (s stubBlock) Version() int { return s.v }
|
||||
func (s stubBlock) AsSignRequestObject() (validatorpb.SignRequestObject, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s stubBlock) HashTreeRootWith(*fastssz.Hasher) error { return nil }
|
||||
|
||||
func buildGloasState(t *testing.T, slot primitives.Slot, proposerIdx primitives.ValidatorIndex, builderIdx primitives.BuilderIndex, balance uint64, randao [32]byte, latestHash [32]byte, builderPubkey [48]byte) *state_native.BeaconState {
|
||||
t.Helper()
|
||||
|
||||
cfg := params.BeaconConfig()
|
||||
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||
stateRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
|
||||
for i := range blockRoots {
|
||||
blockRoots[i] = bytes.Repeat([]byte{0xAA}, 32)
|
||||
stateRoots[i] = bytes.Repeat([]byte{0xBB}, 32)
|
||||
}
|
||||
randaoMixes := make([][]byte, cfg.EpochsPerHistoricalVector)
|
||||
for i := range randaoMixes {
|
||||
randaoMixes[i] = randao[:]
|
||||
}
|
||||
|
||||
withdrawalCreds := make([]byte, 32)
|
||||
withdrawalCreds[0] = cfg.BuilderWithdrawalPrefixByte
|
||||
|
||||
validatorCount := int(proposerIdx) + 1
|
||||
validators := make([]*ethpb.Validator, validatorCount)
|
||||
balances := make([]uint64, validatorCount)
|
||||
for i := range validatorCount {
|
||||
validators[i] = ðpb.Validator{
|
||||
PublicKey: builderPubkey[:],
|
||||
WithdrawalCredentials: withdrawalCreds,
|
||||
EffectiveBalance: balance,
|
||||
Slashed: false,
|
||||
ActivationEligibilityEpoch: 0,
|
||||
ActivationEpoch: 0,
|
||||
ExitEpoch: cfg.FarFutureEpoch,
|
||||
WithdrawableEpoch: cfg.FarFutureEpoch,
|
||||
}
|
||||
balances[i] = balance
|
||||
}
|
||||
|
||||
payments := make([]*ethpb.BuilderPendingPayment, cfg.SlotsPerEpoch*2)
|
||||
for i := range payments {
|
||||
payments[i] = ðpb.BuilderPendingPayment{Withdrawal: ðpb.BuilderPendingWithdrawal{}}
|
||||
}
|
||||
|
||||
var builders []*ethpb.Builder
|
||||
if builderIdx != params.BeaconConfig().BuilderIndexSelfBuild {
|
||||
builderCount := int(builderIdx) + 1
|
||||
builders = make([]*ethpb.Builder, builderCount)
|
||||
builders[builderCount-1] = ðpb.Builder{
|
||||
Pubkey: builderPubkey[:],
|
||||
Version: []byte{0},
|
||||
ExecutionAddress: bytes.Repeat([]byte{0x01}, 20),
|
||||
Balance: primitives.Gwei(balance),
|
||||
DepositEpoch: 0,
|
||||
WithdrawableEpoch: cfg.FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
stProto := ðpb.BeaconStateGloas{
|
||||
Slot: slot,
|
||||
GenesisValidatorsRoot: bytes.Repeat([]byte{0x11}, 32),
|
||||
Fork: ðpb.Fork{
|
||||
CurrentVersion: bytes.Repeat([]byte{0x22}, 4),
|
||||
PreviousVersion: bytes.Repeat([]byte{0x22}, 4),
|
||||
Epoch: 0,
|
||||
},
|
||||
BlockRoots: blockRoots,
|
||||
StateRoots: stateRoots,
|
||||
RandaoMixes: randaoMixes,
|
||||
Validators: validators,
|
||||
Balances: balances,
|
||||
LatestBlockHash: latestHash[:],
|
||||
BuilderPendingPayments: payments,
|
||||
BuilderPendingWithdrawals: []*ethpb.BuilderPendingWithdrawal{},
|
||||
Builders: builders,
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
},
|
||||
}
|
||||
|
||||
st, err := state_native.InitializeFromProtoGloas(stProto)
|
||||
require.NoError(t, err)
|
||||
return st.(*state_native.BeaconState)
|
||||
}
|
||||
|
||||
func signBid(t *testing.T, sk common.SecretKey, bid *ethpb.ExecutionPayloadBid, fork *ethpb.Fork, genesisRoot [32]byte) [96]byte {
|
||||
t.Helper()
|
||||
epoch := slots.ToEpoch(primitives.Slot(bid.Slot))
|
||||
domain, err := signing.Domain(fork, epoch, params.BeaconConfig().DomainBeaconBuilder, genesisRoot[:])
|
||||
require.NoError(t, err)
|
||||
root, err := signing.ComputeSigningRoot(bid, domain)
|
||||
require.NoError(t, err)
|
||||
sig := sk.Sign(root[:]).Marshal()
|
||||
var out [96]byte
|
||||
copy(out[:], sig)
|
||||
return out
|
||||
}
|
||||
|
||||
func TestProcessExecutionPayloadBid_SelfBuildSuccess(t *testing.T) {
|
||||
slot := primitives.Slot(12)
|
||||
proposerIdx := primitives.ValidatorIndex(0)
|
||||
builderIdx := params.BeaconConfig().BuilderIndexSelfBuild
|
||||
randao := [32]byte(bytes.Repeat([]byte{0xAA}, 32))
|
||||
latestHash := [32]byte(bytes.Repeat([]byte{0xBB}, 32))
|
||||
pubKey := [48]byte{}
|
||||
state := buildGloasState(t, slot, proposerIdx, builderIdx, params.BeaconConfig().MinActivationBalance+1000, randao, latestHash, pubKey)
|
||||
|
||||
bid := ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: latestHash[:],
|
||||
ParentBlockRoot: bytes.Repeat([]byte{0xCC}, 32),
|
||||
BlockHash: bytes.Repeat([]byte{0xDD}, 32),
|
||||
PrevRandao: randao[:],
|
||||
GasLimit: 1,
|
||||
BuilderIndex: builderIdx,
|
||||
Slot: slot,
|
||||
Value: 0,
|
||||
ExecutionPayment: 0,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0xEE}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0xFF}, 20),
|
||||
}
|
||||
signed := ðpb.SignedExecutionPayloadBid{
|
||||
Message: bid,
|
||||
Signature: common.InfiniteSignature[:],
|
||||
}
|
||||
|
||||
block := stubBlock{
|
||||
slot: slot,
|
||||
proposer: proposerIdx,
|
||||
parentRoot: bytesutil.ToBytes32(bid.ParentBlockRoot),
|
||||
body: stubBlockBody{signedBid: signed},
|
||||
v: version.Gloas,
|
||||
}
|
||||
|
||||
require.NoError(t, ProcessExecutionPayloadBid(state, block))
|
||||
|
||||
stateProto, ok := state.ToProto().(*ethpb.BeaconStateGloas)
|
||||
require.Equal(t, true, ok)
|
||||
slotIndex := params.BeaconConfig().SlotsPerEpoch + (slot % params.BeaconConfig().SlotsPerEpoch)
|
||||
require.Equal(t, primitives.Gwei(0), stateProto.BuilderPendingPayments[slotIndex].Withdrawal.Amount)
|
||||
}
|
||||
|
||||
func TestProcessExecutionPayloadBid_SelfBuildNonZeroAmountFails(t *testing.T) {
|
||||
slot := primitives.Slot(2)
|
||||
proposerIdx := primitives.ValidatorIndex(0)
|
||||
builderIdx := params.BeaconConfig().BuilderIndexSelfBuild
|
||||
randao := [32]byte{}
|
||||
latestHash := [32]byte{1}
|
||||
state := buildGloasState(t, slot, proposerIdx, builderIdx, params.BeaconConfig().MinActivationBalance+1000, randao, latestHash, [48]byte{})
|
||||
|
||||
bid := ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: latestHash[:],
|
||||
ParentBlockRoot: bytes.Repeat([]byte{0xAA}, 32),
|
||||
BlockHash: bytes.Repeat([]byte{0xBB}, 32),
|
||||
PrevRandao: randao[:],
|
||||
BuilderIndex: builderIdx,
|
||||
Slot: slot,
|
||||
Value: 10,
|
||||
ExecutionPayment: 0,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0xCC}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0xDD}, 20),
|
||||
}
|
||||
signed := ðpb.SignedExecutionPayloadBid{
|
||||
Message: bid,
|
||||
Signature: common.InfiniteSignature[:],
|
||||
}
|
||||
block := stubBlock{
|
||||
slot: slot,
|
||||
proposer: proposerIdx,
|
||||
parentRoot: bytesutil.ToBytes32(bid.ParentBlockRoot),
|
||||
body: stubBlockBody{signedBid: signed},
|
||||
v: version.Gloas,
|
||||
}
|
||||
|
||||
err := ProcessExecutionPayloadBid(state, block)
|
||||
require.ErrorContains(t, "self-build amount must be zero", err)
|
||||
}
|
||||
|
||||
func TestProcessExecutionPayloadBid_PendingPaymentAndCacheBid(t *testing.T) {
|
||||
slot := primitives.Slot(8)
|
||||
builderIdx := primitives.BuilderIndex(1)
|
||||
proposerIdx := primitives.ValidatorIndex(2)
|
||||
randao := [32]byte(bytes.Repeat([]byte{0xAA}, 32))
|
||||
latestHash := [32]byte(bytes.Repeat([]byte{0xBB}, 32))
|
||||
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
pub := sk.PublicKey().Marshal()
|
||||
var pubKey [48]byte
|
||||
copy(pubKey[:], pub)
|
||||
|
||||
balance := params.BeaconConfig().MinActivationBalance + 1_000_000
|
||||
state := buildGloasState(t, slot, proposerIdx, builderIdx, balance, randao, latestHash, pubKey)
|
||||
|
||||
bid := ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: latestHash[:],
|
||||
ParentBlockRoot: bytes.Repeat([]byte{0xCC}, 32),
|
||||
BlockHash: bytes.Repeat([]byte{0xDD}, 32),
|
||||
PrevRandao: randao[:],
|
||||
GasLimit: 1,
|
||||
BuilderIndex: builderIdx,
|
||||
Slot: slot,
|
||||
Value: 500_000,
|
||||
ExecutionPayment: 1,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0xEE}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0xFF}, 20),
|
||||
}
|
||||
|
||||
genesis := bytesutil.ToBytes32(state.GenesisValidatorsRoot())
|
||||
sig := signBid(t, sk, bid, state.Fork(), genesis)
|
||||
signed := ðpb.SignedExecutionPayloadBid{
|
||||
Message: bid,
|
||||
Signature: sig[:],
|
||||
}
|
||||
|
||||
block := stubBlock{
|
||||
slot: slot,
|
||||
proposer: proposerIdx, // not self-build
|
||||
parentRoot: bytesutil.ToBytes32(bid.ParentBlockRoot),
|
||||
body: stubBlockBody{signedBid: signed},
|
||||
v: version.Gloas,
|
||||
}
|
||||
|
||||
require.NoError(t, ProcessExecutionPayloadBid(state, block))
|
||||
|
||||
stateProto, ok := state.ToProto().(*ethpb.BeaconStateGloas)
|
||||
require.Equal(t, true, ok)
|
||||
slotIndex := params.BeaconConfig().SlotsPerEpoch + (slot % params.BeaconConfig().SlotsPerEpoch)
|
||||
require.Equal(t, primitives.Gwei(500_000), stateProto.BuilderPendingPayments[slotIndex].Withdrawal.Amount)
|
||||
|
||||
require.NotNil(t, stateProto.LatestExecutionPayloadBid)
|
||||
require.Equal(t, primitives.BuilderIndex(1), stateProto.LatestExecutionPayloadBid.BuilderIndex)
|
||||
require.Equal(t, primitives.Gwei(500_000), stateProto.LatestExecutionPayloadBid.Value)
|
||||
}
|
||||
|
||||
func TestProcessExecutionPayloadBid_BuilderNotActive(t *testing.T) {
|
||||
slot := primitives.Slot(4)
|
||||
builderIdx := primitives.BuilderIndex(1)
|
||||
proposerIdx := primitives.ValidatorIndex(2)
|
||||
randao := [32]byte(bytes.Repeat([]byte{0x01}, 32))
|
||||
latestHash := [32]byte(bytes.Repeat([]byte{0x02}, 32))
|
||||
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
var pubKey [48]byte
|
||||
copy(pubKey[:], sk.PublicKey().Marshal())
|
||||
|
||||
state := buildGloasState(t, slot, proposerIdx, builderIdx, params.BeaconConfig().MinDepositAmount+1000, randao, latestHash, pubKey)
|
||||
// Make builder inactive by setting withdrawable_epoch.
|
||||
stateProto := state.ToProto().(*ethpb.BeaconStateGloas)
|
||||
stateProto.Builders[int(builderIdx)].WithdrawableEpoch = 0
|
||||
stateIface, err := state_native.InitializeFromProtoGloas(stateProto)
|
||||
require.NoError(t, err)
|
||||
state = stateIface.(*state_native.BeaconState)
|
||||
|
||||
bid := ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: latestHash[:],
|
||||
ParentBlockRoot: bytes.Repeat([]byte{0x03}, 32),
|
||||
BlockHash: bytes.Repeat([]byte{0x04}, 32),
|
||||
PrevRandao: randao[:],
|
||||
GasLimit: 1,
|
||||
BuilderIndex: builderIdx,
|
||||
Slot: slot,
|
||||
Value: 10,
|
||||
ExecutionPayment: 0,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0x05}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0x06}, 20),
|
||||
}
|
||||
genesis := bytesutil.ToBytes32(state.GenesisValidatorsRoot())
|
||||
sig := signBid(t, sk, bid, state.Fork(), genesis)
|
||||
signed := ðpb.SignedExecutionPayloadBid{Message: bid, Signature: sig[:]}
|
||||
block := stubBlock{
|
||||
slot: slot,
|
||||
proposer: proposerIdx,
|
||||
parentRoot: bytesutil.ToBytes32(bid.ParentBlockRoot),
|
||||
body: stubBlockBody{signedBid: signed},
|
||||
v: version.Gloas,
|
||||
}
|
||||
|
||||
err = ProcessExecutionPayloadBid(state, block)
|
||||
require.ErrorContains(t, "is not active", err)
|
||||
}
|
||||
|
||||
func TestProcessExecutionPayloadBid_CannotCoverBid(t *testing.T) {
|
||||
slot := primitives.Slot(5)
|
||||
builderIdx := primitives.BuilderIndex(1)
|
||||
proposerIdx := primitives.ValidatorIndex(2)
|
||||
randao := [32]byte(bytes.Repeat([]byte{0x0A}, 32))
|
||||
latestHash := [32]byte(bytes.Repeat([]byte{0x0B}, 32))
|
||||
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
var pubKey [48]byte
|
||||
copy(pubKey[:], sk.PublicKey().Marshal())
|
||||
|
||||
state := buildGloasState(t, slot, proposerIdx, builderIdx, params.BeaconConfig().MinDepositAmount+10, randao, latestHash, pubKey)
|
||||
stateProto := state.ToProto().(*ethpb.BeaconStateGloas)
|
||||
// Add pending balances to push below required balance.
|
||||
stateProto.BuilderPendingWithdrawals = []*ethpb.BuilderPendingWithdrawal{
|
||||
{Amount: 15, BuilderIndex: builderIdx},
|
||||
}
|
||||
stateProto.BuilderPendingPayments = []*ethpb.BuilderPendingPayment{
|
||||
{Withdrawal: ðpb.BuilderPendingWithdrawal{Amount: 20, BuilderIndex: builderIdx}},
|
||||
}
|
||||
stateIface, err := state_native.InitializeFromProtoGloas(stateProto)
|
||||
require.NoError(t, err)
|
||||
state = stateIface.(*state_native.BeaconState)
|
||||
|
||||
bid := ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: latestHash[:],
|
||||
ParentBlockRoot: bytes.Repeat([]byte{0xCC}, 32),
|
||||
BlockHash: bytes.Repeat([]byte{0xDD}, 32),
|
||||
PrevRandao: randao[:],
|
||||
GasLimit: 1,
|
||||
BuilderIndex: builderIdx,
|
||||
Slot: slot,
|
||||
Value: 25,
|
||||
ExecutionPayment: 0,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0xEE}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0xFF}, 20),
|
||||
}
|
||||
genesis := bytesutil.ToBytes32(state.GenesisValidatorsRoot())
|
||||
sig := signBid(t, sk, bid, state.Fork(), genesis)
|
||||
signed := ðpb.SignedExecutionPayloadBid{Message: bid, Signature: sig[:]}
|
||||
block := stubBlock{
|
||||
slot: slot,
|
||||
proposer: proposerIdx,
|
||||
parentRoot: bytesutil.ToBytes32(bid.ParentBlockRoot),
|
||||
body: stubBlockBody{signedBid: signed},
|
||||
v: version.Gloas,
|
||||
}
|
||||
|
||||
err = ProcessExecutionPayloadBid(state, block)
|
||||
require.ErrorContains(t, "cannot cover bid amount", err)
|
||||
}
|
||||
|
||||
func TestProcessExecutionPayloadBid_InvalidSignature(t *testing.T) {
|
||||
slot := primitives.Slot(6)
|
||||
builderIdx := primitives.BuilderIndex(1)
|
||||
proposerIdx := primitives.ValidatorIndex(2)
|
||||
randao := [32]byte(bytes.Repeat([]byte{0xAA}, 32))
|
||||
latestHash := [32]byte(bytes.Repeat([]byte{0xBB}, 32))
|
||||
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
var pubKey [48]byte
|
||||
copy(pubKey[:], sk.PublicKey().Marshal())
|
||||
|
||||
state := buildGloasState(t, slot, proposerIdx, builderIdx, params.BeaconConfig().MinDepositAmount+1000, randao, latestHash, pubKey)
|
||||
|
||||
bid := ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: latestHash[:],
|
||||
ParentBlockRoot: bytes.Repeat([]byte{0xCC}, 32),
|
||||
BlockHash: bytes.Repeat([]byte{0xDD}, 32),
|
||||
PrevRandao: randao[:],
|
||||
GasLimit: 1,
|
||||
BuilderIndex: builderIdx,
|
||||
Slot: slot,
|
||||
Value: 10,
|
||||
ExecutionPayment: 0,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0xEE}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0xFF}, 20),
|
||||
}
|
||||
// Use an invalid signature.
|
||||
invalidSig := [96]byte{1}
|
||||
signed := ðpb.SignedExecutionPayloadBid{Message: bid, Signature: invalidSig[:]}
|
||||
block := stubBlock{
|
||||
slot: slot,
|
||||
proposer: proposerIdx,
|
||||
parentRoot: bytesutil.ToBytes32(bid.ParentBlockRoot),
|
||||
body: stubBlockBody{signedBid: signed},
|
||||
v: version.Gloas,
|
||||
}
|
||||
|
||||
err = ProcessExecutionPayloadBid(state, block)
|
||||
require.ErrorContains(t, "bid signature validation failed", err)
|
||||
}
|
||||
|
||||
func TestProcessExecutionPayloadBid_SlotMismatch(t *testing.T) {
|
||||
slot := primitives.Slot(10)
|
||||
builderIdx := primitives.BuilderIndex(1)
|
||||
proposerIdx := primitives.ValidatorIndex(2)
|
||||
randao := [32]byte(bytes.Repeat([]byte{0xAA}, 32))
|
||||
latestHash := [32]byte(bytes.Repeat([]byte{0xBB}, 32))
|
||||
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
var pubKey [48]byte
|
||||
copy(pubKey[:], sk.PublicKey().Marshal())
|
||||
|
||||
state := buildGloasState(t, slot, proposerIdx, builderIdx, params.BeaconConfig().MinDepositAmount+1000, randao, latestHash, pubKey)
|
||||
|
||||
bid := ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: latestHash[:],
|
||||
ParentBlockRoot: bytes.Repeat([]byte{0xAA}, 32),
|
||||
BlockHash: bytes.Repeat([]byte{0xBB}, 32),
|
||||
PrevRandao: randao[:],
|
||||
GasLimit: 1,
|
||||
BuilderIndex: builderIdx,
|
||||
Slot: slot + 1, // mismatch
|
||||
Value: 1,
|
||||
ExecutionPayment: 0,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0xCC}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0xDD}, 20),
|
||||
}
|
||||
genesis := bytesutil.ToBytes32(state.GenesisValidatorsRoot())
|
||||
sig := signBid(t, sk, bid, state.Fork(), genesis)
|
||||
signed := ðpb.SignedExecutionPayloadBid{Message: bid, Signature: sig[:]}
|
||||
block := stubBlock{
|
||||
slot: slot,
|
||||
proposer: proposerIdx,
|
||||
parentRoot: bytesutil.ToBytes32(bid.ParentBlockRoot),
|
||||
body: stubBlockBody{signedBid: signed},
|
||||
v: version.Gloas,
|
||||
}
|
||||
|
||||
err = ProcessExecutionPayloadBid(state, block)
|
||||
require.ErrorContains(t, "bid slot", err)
|
||||
}
|
||||
|
||||
func TestProcessExecutionPayloadBid_ParentHashMismatch(t *testing.T) {
|
||||
slot := primitives.Slot(11)
|
||||
builderIdx := primitives.BuilderIndex(1)
|
||||
proposerIdx := primitives.ValidatorIndex(2)
|
||||
randao := [32]byte(bytes.Repeat([]byte{0xAA}, 32))
|
||||
latestHash := [32]byte(bytes.Repeat([]byte{0xBB}, 32))
|
||||
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
var pubKey [48]byte
|
||||
copy(pubKey[:], sk.PublicKey().Marshal())
|
||||
|
||||
state := buildGloasState(t, slot, proposerIdx, builderIdx, params.BeaconConfig().MinDepositAmount+1000, randao, latestHash, pubKey)
|
||||
|
||||
bid := ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: bytes.Repeat([]byte{0x11}, 32), // mismatch
|
||||
ParentBlockRoot: bytes.Repeat([]byte{0x22}, 32),
|
||||
BlockHash: bytes.Repeat([]byte{0x33}, 32),
|
||||
PrevRandao: randao[:],
|
||||
GasLimit: 1,
|
||||
BuilderIndex: builderIdx,
|
||||
Slot: slot,
|
||||
Value: 1,
|
||||
ExecutionPayment: 0,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0x44}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0x55}, 20),
|
||||
}
|
||||
genesis := bytesutil.ToBytes32(state.GenesisValidatorsRoot())
|
||||
sig := signBid(t, sk, bid, state.Fork(), genesis)
|
||||
signed := ðpb.SignedExecutionPayloadBid{Message: bid, Signature: sig[:]}
|
||||
block := stubBlock{
|
||||
slot: slot,
|
||||
proposer: proposerIdx,
|
||||
parentRoot: bytesutil.ToBytes32(bid.ParentBlockRoot),
|
||||
body: stubBlockBody{signedBid: signed},
|
||||
v: version.Gloas,
|
||||
}
|
||||
|
||||
err = ProcessExecutionPayloadBid(state, block)
|
||||
require.ErrorContains(t, "parent block hash mismatch", err)
|
||||
}
|
||||
|
||||
func TestProcessExecutionPayloadBid_ParentRootMismatch(t *testing.T) {
|
||||
slot := primitives.Slot(12)
|
||||
builderIdx := primitives.BuilderIndex(1)
|
||||
proposerIdx := primitives.ValidatorIndex(2)
|
||||
randao := [32]byte(bytes.Repeat([]byte{0xAA}, 32))
|
||||
latestHash := [32]byte(bytes.Repeat([]byte{0xBB}, 32))
|
||||
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
var pubKey [48]byte
|
||||
copy(pubKey[:], sk.PublicKey().Marshal())
|
||||
|
||||
state := buildGloasState(t, slot, proposerIdx, builderIdx, params.BeaconConfig().MinDepositAmount+1000, randao, latestHash, pubKey)
|
||||
|
||||
parentRoot := bytes.Repeat([]byte{0x22}, 32)
|
||||
bid := ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: latestHash[:],
|
||||
ParentBlockRoot: parentRoot,
|
||||
BlockHash: bytes.Repeat([]byte{0x33}, 32),
|
||||
PrevRandao: randao[:],
|
||||
GasLimit: 1,
|
||||
BuilderIndex: builderIdx,
|
||||
Slot: slot,
|
||||
Value: 1,
|
||||
ExecutionPayment: 0,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0x44}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0x55}, 20),
|
||||
}
|
||||
genesis := bytesutil.ToBytes32(state.GenesisValidatorsRoot())
|
||||
sig := signBid(t, sk, bid, state.Fork(), genesis)
|
||||
signed := ðpb.SignedExecutionPayloadBid{Message: bid, Signature: sig[:]}
|
||||
block := stubBlock{
|
||||
slot: slot,
|
||||
proposer: proposerIdx,
|
||||
parentRoot: bytesutil.ToBytes32(bytes.Repeat([]byte{0x99}, 32)), // mismatch
|
||||
body: stubBlockBody{signedBid: signed},
|
||||
v: version.Gloas,
|
||||
}
|
||||
|
||||
err = ProcessExecutionPayloadBid(state, block)
|
||||
require.ErrorContains(t, "parent block root mismatch", err)
|
||||
}
|
||||
|
||||
func TestProcessExecutionPayloadBid_PrevRandaoMismatch(t *testing.T) {
|
||||
slot := primitives.Slot(13)
|
||||
builderIdx := primitives.BuilderIndex(1)
|
||||
proposerIdx := primitives.ValidatorIndex(2)
|
||||
randao := [32]byte(bytes.Repeat([]byte{0xAA}, 32))
|
||||
latestHash := [32]byte(bytes.Repeat([]byte{0xBB}, 32))
|
||||
|
||||
sk, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
var pubKey [48]byte
|
||||
copy(pubKey[:], sk.PublicKey().Marshal())
|
||||
|
||||
state := buildGloasState(t, slot, proposerIdx, builderIdx, params.BeaconConfig().MinDepositAmount+1000, randao, latestHash, pubKey)
|
||||
|
||||
bid := ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: latestHash[:],
|
||||
ParentBlockRoot: bytes.Repeat([]byte{0x22}, 32),
|
||||
BlockHash: bytes.Repeat([]byte{0x33}, 32),
|
||||
PrevRandao: bytes.Repeat([]byte{0x01}, 32), // mismatch
|
||||
GasLimit: 1,
|
||||
BuilderIndex: builderIdx,
|
||||
Slot: slot,
|
||||
Value: 1,
|
||||
ExecutionPayment: 0,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0x44}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0x55}, 20),
|
||||
}
|
||||
genesis := bytesutil.ToBytes32(state.GenesisValidatorsRoot())
|
||||
sig := signBid(t, sk, bid, state.Fork(), genesis)
|
||||
signed := ðpb.SignedExecutionPayloadBid{Message: bid, Signature: sig[:]}
|
||||
block := stubBlock{
|
||||
slot: slot,
|
||||
proposer: proposerIdx,
|
||||
parentRoot: bytesutil.ToBytes32(bid.ParentBlockRoot),
|
||||
body: stubBlockBody{signedBid: signed},
|
||||
v: version.Gloas,
|
||||
}
|
||||
|
||||
err = ProcessExecutionPayloadBid(state, block)
|
||||
require.ErrorContains(t, "prev randao mismatch", err)
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
|
||||
dbIface "github.com/OffchainLabs/prysm/v7/beacon-chain/db/iface"
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||
"github.com/OffchainLabs/prysm/v7/config/features"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/ssz/detect"
|
||||
"github.com/OffchainLabs/prysm/v7/genesis"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
@@ -43,15 +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")
|
||||
}
|
||||
|
||||
// Initialize state-diff if enabled and not yet initialized.
|
||||
if features.Get().EnableStateDiff && s.stateDiffCache == nil {
|
||||
if err := s.initializeStateDiff(0, genesisState); err != nil {
|
||||
return errors.Wrap(err, "failed to initialize state diff for genesis")
|
||||
}
|
||||
log.Info("Initialized state-diff with genesis state")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -204,31 +204,11 @@ func NewKVStore(ctx context.Context, dirPath string, opts ...KVStoreOption) (*St
|
||||
}
|
||||
|
||||
if features.Get().EnableStateDiff {
|
||||
// Check if offset already exists (existing state-diff database).
|
||||
hasOffset, err := kv.hasStateDiffOffset()
|
||||
sdCache, err := newStateDiffCache(kv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if hasOffset {
|
||||
// Existing state-diff database - restarts not yet supported.
|
||||
return nil, 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 nil, 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 kv, ErrStateDiffIncompatible
|
||||
}
|
||||
kv.stateDiffCache = sdCache
|
||||
}
|
||||
|
||||
return kv, nil
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -120,54 +119,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 {
|
||||
// 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")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func keyForSnapshot(v int) ([]byte, error) {
|
||||
switch v {
|
||||
case version.Fulu:
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/config/features"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/ssz/detect"
|
||||
@@ -112,13 +111,5 @@ func (s *Store) SaveOrigin(ctx context.Context, serState, serBlock []byte) error
|
||||
return errors.Wrap(err, "save finalized checkpoint")
|
||||
}
|
||||
|
||||
// Initialize state-diff if enabled and not yet initialized.
|
||||
if features.Get().EnableStateDiff && s.stateDiffCache == nil {
|
||||
if err := s.initializeStateDiff(state.Slot(), state); err != nil {
|
||||
return errors.Wrap(err, "failed to initialize state diff")
|
||||
}
|
||||
log.WithField("slot", state.Slot()).Info("Initialized state-diff with checkpoint state")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -540,12 +540,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)
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ func (s *Service) prepareForkChoiceAtts() {
|
||||
}
|
||||
case <-s.ctx.Done():
|
||||
log.Debug("Context closed, exiting routine")
|
||||
ticker.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +168,8 @@ func TestGetSpec(t *testing.T) {
|
||||
config.BlobsidecarSubnetCount = 101
|
||||
config.BlobsidecarSubnetCountElectra = 102
|
||||
config.SyncMessageDueBPS = 103
|
||||
config.BuilderWithdrawalPrefixByte = byte('b')
|
||||
config.BuilderIndexSelfBuild = primitives.BuilderIndex(125)
|
||||
|
||||
var dbp [4]byte
|
||||
copy(dbp[:], []byte{'0', '0', '0', '1'})
|
||||
@@ -190,6 +192,9 @@ func TestGetSpec(t *testing.T) {
|
||||
var daap [4]byte
|
||||
copy(daap[:], []byte{'0', '0', '0', '7'})
|
||||
config.DomainAggregateAndProof = daap
|
||||
var dbb [4]byte
|
||||
copy(dbb[:], []byte{'0', '0', '0', '8'})
|
||||
config.DomainBeaconBuilder = dbb
|
||||
var dam [4]byte
|
||||
copy(dam[:], []byte{'1', '0', '0', '0'})
|
||||
config.DomainApplicationMask = dam
|
||||
@@ -205,7 +210,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, 175, len(data))
|
||||
assert.Equal(t, 178, len(data))
|
||||
for k, v := range data {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
switch k {
|
||||
@@ -419,8 +424,14 @@ func TestGetSpec(t *testing.T) {
|
||||
assert.Equal(t, "0x0a000000", v)
|
||||
case "DOMAIN_APPLICATION_BUILDER":
|
||||
assert.Equal(t, "0x00000001", v)
|
||||
case "DOMAIN_BEACON_BUILDER":
|
||||
assert.Equal(t, "0x30303038", v)
|
||||
case "DOMAIN_BLOB_SIDECAR":
|
||||
assert.Equal(t, "0x00000000", v)
|
||||
case "BUILDER_WITHDRAWAL_PREFIX":
|
||||
assert.Equal(t, "0x62", v)
|
||||
case "BUILDER_INDEX_SELF_BUILD":
|
||||
assert.Equal(t, "125", v)
|
||||
case "TRANSITION_TOTAL_DIFFICULTY":
|
||||
assert.Equal(t, "0", v)
|
||||
case "TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH":
|
||||
|
||||
@@ -5,6 +5,7 @@ go_library(
|
||||
srcs = [
|
||||
"error.go",
|
||||
"interfaces.go",
|
||||
"interfaces_gloas.go",
|
||||
"prometheus.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/beacon-chain/state",
|
||||
|
||||
@@ -66,6 +66,7 @@ type ReadOnlyBeaconState interface {
|
||||
ReadOnlyDeposits
|
||||
ReadOnlyConsolidations
|
||||
ReadOnlyProposerLookahead
|
||||
readOnlyGloasFields
|
||||
ToProtoUnsafe() any
|
||||
ToProto() any
|
||||
GenesisTime() time.Time
|
||||
@@ -101,6 +102,7 @@ type WriteOnlyBeaconState interface {
|
||||
WriteOnlyWithdrawals
|
||||
WriteOnlyDeposits
|
||||
WriteOnlyProposerLookahead
|
||||
writeOnlyGloasFields
|
||||
SetGenesisTime(val time.Time) error
|
||||
SetGenesisValidatorsRoot(val []byte) error
|
||||
SetSlot(val primitives.Slot) error
|
||||
|
||||
19
beacon-chain/state/interfaces_gloas.go
Normal file
19
beacon-chain/state/interfaces_gloas.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
type writeOnlyGloasFields interface {
|
||||
SetExecutionPayloadBid(h interfaces.ROExecutionPayloadBid) error
|
||||
SetBuilderPendingPayment(index primitives.Slot, payment *ethpb.BuilderPendingPayment) error
|
||||
}
|
||||
|
||||
type readOnlyGloasFields interface {
|
||||
BuilderPubkey(primitives.BuilderIndex) ([48]byte, error)
|
||||
IsActiveBuilder(primitives.BuilderIndex) (bool, error)
|
||||
CanBuilderCoverBid(primitives.BuilderIndex, primitives.Gwei) (bool, error)
|
||||
LatestBlockHash() ([32]byte, error)
|
||||
}
|
||||
@@ -14,6 +14,7 @@ go_library(
|
||||
"getters_deposits.go",
|
||||
"getters_eth1.go",
|
||||
"getters_exit.go",
|
||||
"getters_gloas.go",
|
||||
"getters_misc.go",
|
||||
"getters_participation.go",
|
||||
"getters_payload_header.go",
|
||||
@@ -36,6 +37,7 @@ go_library(
|
||||
"setters_deposit_requests.go",
|
||||
"setters_deposits.go",
|
||||
"setters_eth1.go",
|
||||
"setters_gloas.go",
|
||||
"setters_misc.go",
|
||||
"setters_participation.go",
|
||||
"setters_payload_header.go",
|
||||
@@ -97,6 +99,7 @@ go_test(
|
||||
"getters_deposit_requests_test.go",
|
||||
"getters_deposits_test.go",
|
||||
"getters_exit_test.go",
|
||||
"getters_gloas_test.go",
|
||||
"getters_participation_test.go",
|
||||
"getters_setters_lookahead_test.go",
|
||||
"getters_test.go",
|
||||
@@ -114,6 +117,7 @@ go_test(
|
||||
"setters_deposit_requests_test.go",
|
||||
"setters_deposits_test.go",
|
||||
"setters_eth1_test.go",
|
||||
"setters_gloas_test.go",
|
||||
"setters_misc_test.go",
|
||||
"setters_participation_test.go",
|
||||
"setters_payload_header_test.go",
|
||||
|
||||
137
beacon-chain/state/state-native/getters_gloas.go
Normal file
137
beacon-chain/state/state-native/getters_gloas.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
)
|
||||
|
||||
// LatestBlockHash returns the hash of the latest execution block.
|
||||
func (b *BeaconState) LatestBlockHash() ([32]byte, error) {
|
||||
if b.version < version.Gloas {
|
||||
return [32]byte{}, errNotSupported("LatestBlockHash", b.version)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
if b.latestBlockHash == nil {
|
||||
return [32]byte{}, nil
|
||||
}
|
||||
|
||||
return [32]byte(b.latestBlockHash), nil
|
||||
}
|
||||
|
||||
// BuilderPubkey returns the builder pubkey at the provided index.
|
||||
func (b *BeaconState) BuilderPubkey(builderIndex primitives.BuilderIndex) ([fieldparams.BLSPubkeyLength]byte, error) {
|
||||
if b.version < version.Gloas {
|
||||
return [fieldparams.BLSPubkeyLength]byte{}, errNotSupported("BuilderPubkey", b.version)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
builder, err := b.builderAtIndex(builderIndex)
|
||||
if err != nil {
|
||||
return [fieldparams.BLSPubkeyLength]byte{}, err
|
||||
}
|
||||
|
||||
var pk [fieldparams.BLSPubkeyLength]byte
|
||||
copy(pk[:], builder.Pubkey)
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// IsActiveBuilder returns true if the builder placement is finalized and it has not initiated exit.
|
||||
// Spec v1.7.0-alpha.0 (pseudocode):
|
||||
// def is_active_builder(state: BeaconState, builder_index: BuilderIndex) -> bool:
|
||||
//
|
||||
// builder = state.builders[builder_index]
|
||||
// return (
|
||||
// builder.deposit_epoch < state.finalized_checkpoint.epoch
|
||||
// and builder.withdrawable_epoch == FAR_FUTURE_EPOCH
|
||||
// )
|
||||
func (b *BeaconState) IsActiveBuilder(builderIndex primitives.BuilderIndex) (bool, error) {
|
||||
if b.version < version.Gloas {
|
||||
return false, errNotSupported("IsActiveBuilder", b.version)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
builder, err := b.builderAtIndex(builderIndex)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
finalizedEpoch := b.finalizedCheckpoint.Epoch
|
||||
return builder.DepositEpoch < finalizedEpoch && builder.WithdrawableEpoch == params.BeaconConfig().FarFutureEpoch, nil
|
||||
}
|
||||
|
||||
// CanBuilderCoverBid returns true if the builder has enough balance to cover the given bid amount.
|
||||
// Spec v1.7.0-alpha.0 (pseudocode):
|
||||
// def can_builder_cover_bid(state: BeaconState, builder_index: BuilderIndex, bid_amount: Gwei) -> bool:
|
||||
//
|
||||
// builder_balance = state.builders[builder_index].balance
|
||||
// pending_withdrawals_amount = get_pending_balance_to_withdraw_for_builder(state, builder_index)
|
||||
// min_balance = MIN_DEPOSIT_AMOUNT + pending_withdrawals_amount
|
||||
// if builder_balance < min_balance:
|
||||
// return False
|
||||
// return builder_balance - min_balance >= bid_amount
|
||||
func (b *BeaconState) CanBuilderCoverBid(builderIndex primitives.BuilderIndex, bidAmount primitives.Gwei) (bool, error) {
|
||||
if b.version < version.Gloas {
|
||||
return false, errNotSupported("CanBuilderCoverBid", b.version)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
builder, err := b.builderAtIndex(builderIndex)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
pendingBalanceToWithdraw := b.builderPendingBalanceToWithdraw(builderIndex)
|
||||
minBalance := params.BeaconConfig().MinDepositAmount + pendingBalanceToWithdraw
|
||||
|
||||
balance := uint64(builder.Balance)
|
||||
if balance < minBalance {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return balance-minBalance >= uint64(bidAmount), nil
|
||||
}
|
||||
|
||||
// builderAtIndex intentionally returns the underlying pointer without copying.
|
||||
func (b *BeaconState) builderAtIndex(builderIndex primitives.BuilderIndex) (*ethpb.Builder, error) {
|
||||
idx := uint64(builderIndex)
|
||||
if idx >= uint64(len(b.builders)) {
|
||||
return nil, fmt.Errorf("builder index %d out of range (len=%d)", builderIndex, len(b.builders))
|
||||
}
|
||||
|
||||
builder := b.builders[idx]
|
||||
if builder == nil {
|
||||
return nil, fmt.Errorf("builder at index %d is nil", builderIndex)
|
||||
}
|
||||
return builder, nil
|
||||
}
|
||||
|
||||
// builderPendingBalanceToWithdraw mirrors get_pending_balance_to_withdraw_for_builder in the spec,
|
||||
// summing both pending withdrawals and pending payments for a builder.
|
||||
func (b *BeaconState) builderPendingBalanceToWithdraw(builderIndex primitives.BuilderIndex) uint64 {
|
||||
var total uint64
|
||||
for _, withdrawal := range b.builderPendingWithdrawals {
|
||||
if withdrawal.BuilderIndex == builderIndex {
|
||||
total += uint64(withdrawal.Amount)
|
||||
}
|
||||
}
|
||||
for _, payment := range b.builderPendingPayments {
|
||||
if payment.Withdrawal.BuilderIndex == builderIndex {
|
||||
total += uint64(payment.Withdrawal.Amount)
|
||||
}
|
||||
}
|
||||
return total
|
||||
}
|
||||
159
beacon-chain/state/state-native/getters_gloas_test.go
Normal file
159
beacon-chain/state/state-native/getters_gloas_test.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package state_native_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
|
||||
"github.com/OffchainLabs/prysm/v7/config/params"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
)
|
||||
|
||||
func TestLatestBlockHash(t *testing.T) {
|
||||
t.Run("returns error before gloas", func(t *testing.T) {
|
||||
st, _ := util.DeterministicGenesisState(t, 1)
|
||||
_, err := st.LatestBlockHash()
|
||||
require.ErrorContains(t, "is not supported", err)
|
||||
})
|
||||
|
||||
t.Run("returns zero hash when unset", func(t *testing.T) {
|
||||
st, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{})
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := st.LatestBlockHash()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, [32]byte{}, got)
|
||||
})
|
||||
|
||||
t.Run("returns configured hash", func(t *testing.T) {
|
||||
hashBytes := bytes.Repeat([]byte{0xAB}, 32)
|
||||
var want [32]byte
|
||||
copy(want[:], hashBytes)
|
||||
|
||||
st, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{
|
||||
LatestBlockHash: hashBytes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := st.LatestBlockHash()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, want, got)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderPubkey(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.BuilderPubkey(0)
|
||||
require.ErrorContains(t, "is not supported", err)
|
||||
})
|
||||
|
||||
t.Run("returns pubkey copy", func(t *testing.T) {
|
||||
pubkey := bytes.Repeat([]byte{0xAA}, 48)
|
||||
stIface, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{
|
||||
Builders: []*ethpb.Builder{
|
||||
{
|
||||
Pubkey: pubkey,
|
||||
Balance: 42,
|
||||
DepositEpoch: 3,
|
||||
WithdrawableEpoch: 4,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
gotPk, err := stIface.BuilderPubkey(0)
|
||||
require.NoError(t, err)
|
||||
var wantPk [48]byte
|
||||
copy(wantPk[:], pubkey)
|
||||
require.Equal(t, wantPk, gotPk)
|
||||
|
||||
// Mutate original to ensure copy.
|
||||
pubkey[0] = 0
|
||||
require.Equal(t, byte(0xAA), gotPk[0])
|
||||
})
|
||||
|
||||
t.Run("out of range returns error", func(t *testing.T) {
|
||||
stIface, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{
|
||||
Builders: []*ethpb.Builder{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
st := stIface.(*state_native.BeaconState)
|
||||
_, err = st.BuilderPubkey(1)
|
||||
require.ErrorContains(t, "out of range", err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderHelpers(t *testing.T) {
|
||||
t.Run("is active builder", func(t *testing.T) {
|
||||
st, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{
|
||||
Builders: []*ethpb.Builder{
|
||||
{
|
||||
Balance: 10,
|
||||
DepositEpoch: 0,
|
||||
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
},
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 1},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
active, err := st.IsActiveBuilder(0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, active)
|
||||
|
||||
// Not active when withdrawable epoch is set.
|
||||
stProto := ðpb.BeaconStateGloas{
|
||||
Builders: []*ethpb.Builder{
|
||||
{
|
||||
Balance: 10,
|
||||
DepositEpoch: 0,
|
||||
WithdrawableEpoch: 1,
|
||||
},
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 2},
|
||||
}
|
||||
stInactive, err := state_native.InitializeFromProtoGloas(stProto)
|
||||
require.NoError(t, err)
|
||||
|
||||
active, err = stInactive.IsActiveBuilder(0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, active)
|
||||
})
|
||||
|
||||
t.Run("can builder cover bid", func(t *testing.T) {
|
||||
stIface, err := state_native.InitializeFromProtoGloas(ðpb.BeaconStateGloas{
|
||||
Builders: []*ethpb.Builder{
|
||||
{
|
||||
Balance: primitives.Gwei(params.BeaconConfig().MinDepositAmount + 50),
|
||||
DepositEpoch: 0,
|
||||
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
},
|
||||
},
|
||||
BuilderPendingWithdrawals: []*ethpb.BuilderPendingWithdrawal{
|
||||
{Amount: 10, BuilderIndex: 0},
|
||||
},
|
||||
BuilderPendingPayments: []*ethpb.BuilderPendingPayment{
|
||||
{Withdrawal: ðpb.BuilderPendingWithdrawal{Amount: 15, BuilderIndex: 0}},
|
||||
},
|
||||
FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 1},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
st := stIface.(*state_native.BeaconState)
|
||||
ok, err := st.CanBuilderCoverBid(0, 20)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, ok)
|
||||
|
||||
ok, err = st.CanBuilderCoverBid(0, 30)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, ok)
|
||||
})
|
||||
}
|
||||
63
beacon-chain/state/state-native/setters_gloas.go
Normal file
63
beacon-chain/state/state-native/setters_gloas.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/types"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
)
|
||||
|
||||
// SetExecutionPayloadBid sets the latest execution payload bid in the state.
|
||||
func (b *BeaconState) SetExecutionPayloadBid(h interfaces.ROExecutionPayloadBid) error {
|
||||
if b.version < version.Gloas {
|
||||
return errNotSupported("SetExecutionPayloadBid", b.version)
|
||||
}
|
||||
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
parentBlockHash := h.ParentBlockHash()
|
||||
parentBlockRoot := h.ParentBlockRoot()
|
||||
blockHash := h.BlockHash()
|
||||
randao := h.PrevRandao()
|
||||
blobKzgCommitmentsRoot := h.BlobKzgCommitmentsRoot()
|
||||
feeRecipient := h.FeeRecipient()
|
||||
b.latestExecutionPayloadBid = ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: parentBlockHash[:],
|
||||
ParentBlockRoot: parentBlockRoot[:],
|
||||
BlockHash: blockHash[:],
|
||||
PrevRandao: randao[:],
|
||||
GasLimit: h.GasLimit(),
|
||||
BuilderIndex: h.BuilderIndex(),
|
||||
Slot: h.Slot(),
|
||||
Value: h.Value(),
|
||||
ExecutionPayment: h.ExecutionPayment(),
|
||||
BlobKzgCommitmentsRoot: blobKzgCommitmentsRoot[:],
|
||||
FeeRecipient: feeRecipient[:],
|
||||
}
|
||||
b.markFieldAsDirty(types.LatestExecutionPayloadBid)
|
||||
|
||||
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 {
|
||||
return errNotSupported("SetBuilderPendingPayment", b.version)
|
||||
}
|
||||
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
if uint64(index) >= uint64(len(b.builderPendingPayments)) {
|
||||
return fmt.Errorf("builder pending payments index %d out of range (len=%d)", index, len(b.builderPendingPayments))
|
||||
}
|
||||
|
||||
b.builderPendingPayments[index] = ethpb.CopyBuilderPendingPayment(payment)
|
||||
|
||||
b.markFieldAsDirty(types.BuilderPendingPayments)
|
||||
return nil
|
||||
}
|
||||
140
beacon-chain/state/state-native/setters_gloas_test.go
Normal file
140
beacon-chain/state/state-native/setters_gloas_test.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native/types"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
)
|
||||
|
||||
type testExecutionPayloadBid struct {
|
||||
parentBlockHash [32]byte
|
||||
parentBlockRoot [32]byte
|
||||
blockHash [32]byte
|
||||
prevRandao [32]byte
|
||||
blobKzgCommitmentsRoot [32]byte
|
||||
feeRecipient [20]byte
|
||||
gasLimit uint64
|
||||
builderIndex primitives.BuilderIndex
|
||||
slot primitives.Slot
|
||||
value primitives.Gwei
|
||||
executionPayment primitives.Gwei
|
||||
}
|
||||
|
||||
func (t testExecutionPayloadBid) ParentBlockHash() [32]byte { return t.parentBlockHash }
|
||||
func (t testExecutionPayloadBid) ParentBlockRoot() [32]byte { return t.parentBlockRoot }
|
||||
func (t testExecutionPayloadBid) PrevRandao() [32]byte { return t.prevRandao }
|
||||
func (t testExecutionPayloadBid) BlockHash() [32]byte { return t.blockHash }
|
||||
func (t testExecutionPayloadBid) GasLimit() uint64 { return t.gasLimit }
|
||||
func (t testExecutionPayloadBid) BuilderIndex() primitives.BuilderIndex {
|
||||
return t.builderIndex
|
||||
}
|
||||
func (t testExecutionPayloadBid) Slot() primitives.Slot { return t.slot }
|
||||
func (t testExecutionPayloadBid) Value() primitives.Gwei { return t.value }
|
||||
func (t testExecutionPayloadBid) ExecutionPayment() primitives.Gwei {
|
||||
return t.executionPayment
|
||||
}
|
||||
func (t testExecutionPayloadBid) BlobKzgCommitmentsRoot() [32]byte { return t.blobKzgCommitmentsRoot }
|
||||
func (t testExecutionPayloadBid) FeeRecipient() [20]byte { return t.feeRecipient }
|
||||
func (t testExecutionPayloadBid) IsNil() bool { return false }
|
||||
|
||||
func TestSetExecutionPayloadBid(t *testing.T) {
|
||||
t.Run("previous fork returns expected error", func(t *testing.T) {
|
||||
st := &BeaconState{version: version.Fulu}
|
||||
err := st.SetExecutionPayloadBid(testExecutionPayloadBid{})
|
||||
require.ErrorContains(t, "is not supported", err)
|
||||
})
|
||||
|
||||
t.Run("sets bid and marks dirty", func(t *testing.T) {
|
||||
var (
|
||||
parentBlockHash = [32]byte(bytes.Repeat([]byte{0xAB}, 32))
|
||||
parentBlockRoot = [32]byte(bytes.Repeat([]byte{0xCD}, 32))
|
||||
blockHash = [32]byte(bytes.Repeat([]byte{0xEF}, 32))
|
||||
prevRandao = [32]byte(bytes.Repeat([]byte{0x11}, 32))
|
||||
blobRoot = [32]byte(bytes.Repeat([]byte{0x22}, 32))
|
||||
feeRecipient [20]byte
|
||||
)
|
||||
copy(feeRecipient[:], bytes.Repeat([]byte{0x33}, len(feeRecipient)))
|
||||
st := &BeaconState{
|
||||
version: version.Gloas,
|
||||
dirtyFields: make(map[types.FieldIndex]bool),
|
||||
}
|
||||
bid := testExecutionPayloadBid{
|
||||
parentBlockHash: parentBlockHash,
|
||||
parentBlockRoot: parentBlockRoot,
|
||||
blockHash: blockHash,
|
||||
prevRandao: prevRandao,
|
||||
blobKzgCommitmentsRoot: blobRoot,
|
||||
feeRecipient: feeRecipient,
|
||||
gasLimit: 123,
|
||||
builderIndex: 7,
|
||||
slot: 9,
|
||||
value: 11,
|
||||
executionPayment: 22,
|
||||
}
|
||||
|
||||
require.NoError(t, st.SetExecutionPayloadBid(bid))
|
||||
|
||||
require.NotNil(t, st.latestExecutionPayloadBid)
|
||||
require.DeepEqual(t, parentBlockHash[:], st.latestExecutionPayloadBid.ParentBlockHash)
|
||||
require.DeepEqual(t, parentBlockRoot[:], st.latestExecutionPayloadBid.ParentBlockRoot)
|
||||
require.DeepEqual(t, blockHash[:], st.latestExecutionPayloadBid.BlockHash)
|
||||
require.DeepEqual(t, prevRandao[:], st.latestExecutionPayloadBid.PrevRandao)
|
||||
require.DeepEqual(t, blobRoot[:], st.latestExecutionPayloadBid.BlobKzgCommitmentsRoot)
|
||||
require.DeepEqual(t, feeRecipient[:], st.latestExecutionPayloadBid.FeeRecipient)
|
||||
require.Equal(t, uint64(123), st.latestExecutionPayloadBid.GasLimit)
|
||||
require.Equal(t, primitives.BuilderIndex(7), st.latestExecutionPayloadBid.BuilderIndex)
|
||||
require.Equal(t, primitives.Slot(9), st.latestExecutionPayloadBid.Slot)
|
||||
require.Equal(t, primitives.Gwei(11), st.latestExecutionPayloadBid.Value)
|
||||
require.Equal(t, primitives.Gwei(22), st.latestExecutionPayloadBid.ExecutionPayment)
|
||||
require.Equal(t, true, st.dirtyFields[types.LatestExecutionPayloadBid])
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetBuilderPendingPayment(t *testing.T) {
|
||||
t.Run("previous fork returns expected error", func(t *testing.T) {
|
||||
st := &BeaconState{version: version.Fulu}
|
||||
err := st.SetBuilderPendingPayment(0, ðpb.BuilderPendingPayment{})
|
||||
require.ErrorContains(t, "is not supported", err)
|
||||
})
|
||||
|
||||
t.Run("sets copy and marks dirty", func(t *testing.T) {
|
||||
st := &BeaconState{
|
||||
version: version.Gloas,
|
||||
dirtyFields: make(map[types.FieldIndex]bool),
|
||||
builderPendingPayments: make([]*ethpb.BuilderPendingPayment, 2),
|
||||
}
|
||||
payment := ðpb.BuilderPendingPayment{
|
||||
Weight: 2,
|
||||
Withdrawal: ðpb.BuilderPendingWithdrawal{
|
||||
Amount: 99,
|
||||
BuilderIndex: 1,
|
||||
},
|
||||
}
|
||||
|
||||
require.NoError(t, st.SetBuilderPendingPayment(1, payment))
|
||||
require.DeepEqual(t, payment, st.builderPendingPayments[1])
|
||||
require.Equal(t, true, st.dirtyFields[types.BuilderPendingPayments])
|
||||
|
||||
// Mutating the original should not affect the state copy.
|
||||
payment.Withdrawal.Amount = 12345
|
||||
require.Equal(t, primitives.Gwei(99), st.builderPendingPayments[1].Withdrawal.Amount)
|
||||
})
|
||||
|
||||
t.Run("returns error on out of range index", func(t *testing.T) {
|
||||
st := &BeaconState{
|
||||
version: version.Gloas,
|
||||
dirtyFields: make(map[types.FieldIndex]bool),
|
||||
builderPendingPayments: make([]*ethpb.BuilderPendingPayment, 1),
|
||||
}
|
||||
|
||||
err := st.SetBuilderPendingPayment(2, ðpb.BuilderPendingPayment{})
|
||||
|
||||
require.ErrorContains(t, "out of range", err)
|
||||
require.Equal(t, false, st.dirtyFields[types.BuilderPendingPayments])
|
||||
})
|
||||
}
|
||||
@@ -510,6 +510,13 @@ func (s *Service) fetchOriginDataColumnSidecars(roBlock blocks.ROBlock, delay ti
|
||||
}
|
||||
|
||||
logFunc("Failed to fetch some origin data column sidecars, retrying later")
|
||||
|
||||
// Wait before retrying, respecting context cancellation.
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return s.ctx.Err()
|
||||
case <-time.After(delay):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
changelog/farazdagi_fix-prysmctl-timestamp.md
Normal file
3
changelog/farazdagi_fix-prysmctl-timestamp.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- Fix `prysmctl testnet generate-genesis` to use the timestamp from `--geth-genesis-json-in` when `--genesis-time` is not explicitly provided.
|
||||
3
changelog/farazdagi_remove-gometalinter-refs.md
Normal file
3
changelog/farazdagi_remove-gometalinter-refs.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Ignored
|
||||
|
||||
- Removed deprecated gometalinter references from Bazel configuration.
|
||||
3
changelog/galoretka_fix-leak.md
Normal file
3
changelog/galoretka_fix-leak.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- stop SlotIntervalTicker goroutine leaks [#16241](https://github.com/OffchainLabs/prysm/pull/16241)
|
||||
2
changelog/manu_blob_commitment_count_metric.md
Normal file
2
changelog/manu_blob_commitment_count_metric.md
Normal file
@@ -0,0 +1,2 @@
|
||||
### Added
|
||||
- `commitment_count_in_gossip_processed_blocks` gauge metric to track the number of blob KZG commitments in processed beacon blocks.
|
||||
3
changelog/pvl-gazelle-repos-check.md
Normal file
3
changelog/pvl-gazelle-repos-check.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Ignored
|
||||
|
||||
- Gazelle update-repos is now enforced via ./hack/check_gazelle.sh
|
||||
3
changelog/pvl-geth-v1.16.8.md
Normal file
3
changelog/pvl-geth-v1.16.8.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Security
|
||||
|
||||
- Update go-ethereum to v1.16.8
|
||||
3
changelog/satushh-delay.md
Normal file
3
changelog/satushh-delay.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Changed
|
||||
|
||||
- Use delay in fetchOriginDataColumnSidecars. Currently it is simply logged.
|
||||
3
changelog/ttsao_add-gloas-bid-processing.md
Normal file
3
changelog/ttsao_add-gloas-bid-processing.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- Add Gloas latest execution bid processing
|
||||
@@ -158,7 +158,6 @@ var appFlags = []cli.Flag{
|
||||
dasFlags.BackfillOldestSlot,
|
||||
dasFlags.BlobRetentionEpochFlag,
|
||||
flags.BatchVerifierLimit,
|
||||
flags.StateDiffExponents,
|
||||
flags.DisableEphemeralLogFile,
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.RPCHost,
|
||||
flags.RPCPort,
|
||||
flags.BatchVerifierLimit,
|
||||
flags.StateDiffExponents,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -214,13 +214,6 @@ func setGlobalParams() error {
|
||||
|
||||
func generateGenesis(ctx context.Context) (state.BeaconState, error) {
|
||||
f := &generateGenesisStateFlags
|
||||
if f.GenesisTime == 0 {
|
||||
f.GenesisTime = uint64(time.Now().Unix())
|
||||
log.Info("No genesis time specified, defaulting to now()")
|
||||
}
|
||||
log.Infof("Delaying genesis %v by %v seconds", f.GenesisTime, f.GenesisTimeDelay)
|
||||
f.GenesisTime += f.GenesisTimeDelay
|
||||
log.Infof("Genesis is now %v", f.GenesisTime)
|
||||
|
||||
v, err := version.FromString(f.ForkName)
|
||||
if err != nil {
|
||||
@@ -258,7 +251,28 @@ func generateGenesis(ctx context.Context) (state.BeaconState, error) {
|
||||
if err := json.Unmarshal(gbytes, gen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// set timestamps for genesis and shanghai fork
|
||||
// Use input file's timestamp (if `--genesis-time` is NOT explicitly provided)
|
||||
if f.GenesisTime == 0 {
|
||||
f.GenesisTime = gen.Timestamp
|
||||
log.Infof("Using genesis time from input file: %d", f.GenesisTime)
|
||||
}
|
||||
}
|
||||
|
||||
// If still unset (no `--genesis-time` and no input file), default to `now()`
|
||||
if f.GenesisTime == 0 {
|
||||
f.GenesisTime = uint64(time.Now().Unix())
|
||||
log.Info("No genesis time specified, defaulting to now()")
|
||||
}
|
||||
|
||||
// Apply delay (if any) and expose used genesis time
|
||||
if f.GenesisTimeDelay > 0 {
|
||||
log.Infof("Delaying genesis %d by %d seconds", f.GenesisTime, f.GenesisTimeDelay)
|
||||
f.GenesisTime += f.GenesisTimeDelay
|
||||
}
|
||||
log.Infof("Genesis time is %d", f.GenesisTime)
|
||||
|
||||
// Set the timestamps for genesis and forks
|
||||
if f.GethGenesisJsonIn != "" {
|
||||
gen.Timestamp = f.GenesisTime
|
||||
genesis := time.Unix(int64(f.GenesisTime), 0)
|
||||
gen.Config.ShanghaiTime = interop.GethShanghaiTime(genesis, params.BeaconConfig())
|
||||
@@ -301,7 +315,7 @@ func generateGenesis(ctx context.Context) (state.BeaconState, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.WriteFile(f.GethGenesisJsonOut, gbytes, 0600); err != nil {
|
||||
if err := os.WriteFile(f.GethGenesisJsonOut, gbytes, 0o600); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to write %s", f.GethGenesisJsonOut)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,75 @@ func Test_generateGenesis_BaseFeeValidation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func writeFile(path string, data []byte) error {
|
||||
return os.WriteFile(path, data, 0644)
|
||||
func Test_generateGenesis_TimestampHandling(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
inputTimestamp uint64 // timestamp in input genesis.json (0 = no input file)
|
||||
genesisTime uint64 // --genesis-time (0 = not set)
|
||||
genesisTimeDelay uint64 // --genesis-time-delay
|
||||
wantTimestamp uint64
|
||||
}{
|
||||
{
|
||||
name: "uses input file timestamp when no --genesis-time",
|
||||
inputTimestamp: 1700000000,
|
||||
wantTimestamp: 1700000000,
|
||||
},
|
||||
{
|
||||
name: "explicit --genesis-time overrides input file",
|
||||
inputTimestamp: 1700000000,
|
||||
genesisTime: 1600000000,
|
||||
wantTimestamp: 1600000000,
|
||||
},
|
||||
{
|
||||
name: "delay applied to input file timestamp",
|
||||
inputTimestamp: 1700000000,
|
||||
genesisTimeDelay: 100,
|
||||
wantTimestamp: 1700000100,
|
||||
},
|
||||
{
|
||||
name: "delay applied to explicit --genesis-time",
|
||||
inputTimestamp: 1700000000,
|
||||
genesisTime: 1600000000,
|
||||
genesisTimeDelay: 50,
|
||||
wantTimestamp: 1600000050,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
originalFlags := generateGenesisStateFlags
|
||||
defer func() {
|
||||
generateGenesisStateFlags = originalFlags
|
||||
}()
|
||||
|
||||
generateGenesisStateFlags.NumValidators = 2
|
||||
generateGenesisStateFlags.GenesisTime = tt.genesisTime
|
||||
generateGenesisStateFlags.GenesisTimeDelay = tt.genesisTimeDelay
|
||||
generateGenesisStateFlags.ForkName = version.String(version.Deneb)
|
||||
|
||||
if tt.inputTimestamp > 0 {
|
||||
genesis := &core.Genesis{
|
||||
Timestamp: tt.inputTimestamp,
|
||||
BaseFee: big.NewInt(1000000000),
|
||||
Difficulty: big.NewInt(0),
|
||||
GasLimit: 15000000,
|
||||
Alloc: types.GenesisAlloc{},
|
||||
Config: ¶ms.ChainConfig{ChainID: big.NewInt(32382)},
|
||||
}
|
||||
genesisJSON, err := json.Marshal(genesis)
|
||||
require.NoError(t, err)
|
||||
tmpFile := t.TempDir() + "/genesis.json"
|
||||
require.NoError(t, writeFile(tmpFile, genesisJSON))
|
||||
generateGenesisStateFlags.GethGenesisJsonIn = tmpFile
|
||||
}
|
||||
|
||||
st, err := generateGenesis(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(tt.wantTimestamp), st.GenesisTime().Unix())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func writeFile(path string, data []byte) error {
|
||||
return os.WriteFile(path, data, 0o644)
|
||||
}
|
||||
|
||||
@@ -280,7 +280,6 @@ var BeaconChainFlags = combinedFlags([]cli.Flag{
|
||||
DisableQUIC,
|
||||
EnableDiscoveryReboot,
|
||||
enableExperimentalAttestationPool,
|
||||
EnableStateDiff,
|
||||
forceHeadFlag,
|
||||
blacklistRoots,
|
||||
enableHashtree,
|
||||
|
||||
@@ -56,10 +56,12 @@ type BeaconChainConfig struct {
|
||||
EffectiveBalanceIncrement uint64 `yaml:"EFFECTIVE_BALANCE_INCREMENT" spec:"true"` // EffectiveBalanceIncrement is used for converting the high balance into the low balance for validators.
|
||||
|
||||
// Initial value constants.
|
||||
BLSWithdrawalPrefixByte byte `yaml:"BLS_WITHDRAWAL_PREFIX" spec:"true"` // BLSWithdrawalPrefixByte is used for BLS withdrawal and it's the first byte.
|
||||
ETH1AddressWithdrawalPrefixByte byte `yaml:"ETH1_ADDRESS_WITHDRAWAL_PREFIX" spec:"true"` // ETH1AddressWithdrawalPrefixByte is used for withdrawals and it's the first byte.
|
||||
CompoundingWithdrawalPrefixByte byte `yaml:"COMPOUNDING_WITHDRAWAL_PREFIX" spec:"true"` // CompoundingWithdrawalPrefixByteByte is used for compounding withdrawals and it's the first byte.
|
||||
ZeroHash [32]byte // ZeroHash is used to represent a zeroed out 32 byte array.
|
||||
BLSWithdrawalPrefixByte byte `yaml:"BLS_WITHDRAWAL_PREFIX" spec:"true"` // BLSWithdrawalPrefixByte is used for BLS withdrawal and it's the first byte.
|
||||
ETH1AddressWithdrawalPrefixByte byte `yaml:"ETH1_ADDRESS_WITHDRAWAL_PREFIX" spec:"true"` // ETH1AddressWithdrawalPrefixByte is used for withdrawals and it's the first byte.
|
||||
CompoundingWithdrawalPrefixByte byte `yaml:"COMPOUNDING_WITHDRAWAL_PREFIX" spec:"true"` // CompoundingWithdrawalPrefixByteByte is used for compounding withdrawals and it's the first byte.
|
||||
BuilderWithdrawalPrefixByte byte `yaml:"BUILDER_WITHDRAWAL_PREFIX" spec:"true"` // BuilderWithdrawalPrefixByte is used for builder withdrawals and it's the first byte.
|
||||
BuilderIndexSelfBuild primitives.BuilderIndex `yaml:"BUILDER_INDEX_SELF_BUILD" spec:"true"` // BuilderIndexSelfBuild indicates proposer self-built payloads.
|
||||
ZeroHash [32]byte // ZeroHash is used to represent a zeroed out 32 byte array.
|
||||
|
||||
// Time parameters constants.
|
||||
GenesisDelay uint64 `yaml:"GENESIS_DELAY" spec:"true"` // GenesisDelay is the minimum number of seconds to delay starting the Ethereum Beacon Chain genesis. Must be at least 1 second.
|
||||
@@ -139,6 +141,7 @@ type BeaconChainConfig struct {
|
||||
DomainApplicationMask [4]byte `yaml:"DOMAIN_APPLICATION_MASK" spec:"true"` // DomainApplicationMask defines the BLS signature domain for application mask.
|
||||
DomainApplicationBuilder [4]byte `yaml:"DOMAIN_APPLICATION_BUILDER" spec:"true"` // DomainApplicationBuilder defines the BLS signature domain for application builder.
|
||||
DomainBLSToExecutionChange [4]byte `yaml:"DOMAIN_BLS_TO_EXECUTION_CHANGE" spec:"true"` // DomainBLSToExecutionChange defines the BLS signature domain to change withdrawal addresses to ETH1 prefix
|
||||
DomainBeaconBuilder [4]byte `yaml:"DOMAIN_BEACON_BUILDER" spec:"true"` // DomainBeaconBuilder defines the BLS signature domain for beacon block builder.
|
||||
|
||||
// Prysm constants.
|
||||
GenesisValidatorsRoot [32]byte // GenesisValidatorsRoot is the root hash of the genesis validators.
|
||||
|
||||
@@ -94,6 +94,8 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
BLSWithdrawalPrefixByte: byte(0),
|
||||
ETH1AddressWithdrawalPrefixByte: byte(1),
|
||||
CompoundingWithdrawalPrefixByte: byte(2),
|
||||
BuilderWithdrawalPrefixByte: byte(3),
|
||||
BuilderIndexSelfBuild: primitives.BuilderIndex(math.MaxUint64),
|
||||
ZeroHash: [32]byte{},
|
||||
|
||||
// Time parameter constants.
|
||||
@@ -182,6 +184,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
DomainApplicationMask: bytesutil.Uint32ToBytes4(0x00000001),
|
||||
DomainApplicationBuilder: bytesutil.Uint32ToBytes4(0x00000001),
|
||||
DomainBLSToExecutionChange: bytesutil.Uint32ToBytes4(0x0A000000),
|
||||
DomainBeaconBuilder: bytesutil.Uint32ToBytes4(0x0B000000),
|
||||
|
||||
// Prysm constants.
|
||||
GenesisValidatorsRoot: [32]byte{75, 54, 61, 185, 78, 40, 97, 32, 215, 110, 185, 5, 52, 15, 221, 78, 84, 191, 233, 240, 107, 243, 63, 246, 207, 90, 210, 127, 81, 27, 254, 149},
|
||||
|
||||
@@ -14,11 +14,13 @@ go_library(
|
||||
"roblock.go",
|
||||
"rodatacolumn.go",
|
||||
"setters.go",
|
||||
"signed_execution_bid.go",
|
||||
"types.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/consensus-types/blocks",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
@@ -53,9 +55,11 @@ go_test(
|
||||
"roblock_test.go",
|
||||
"rodatacolumn_test.go",
|
||||
"setters_test.go",
|
||||
"signed_execution_bid_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types:go_default_library",
|
||||
|
||||
@@ -641,6 +641,8 @@ func BuildSignedBeaconBlockFromExecutionPayload(blk interfaces.ReadOnlySignedBea
|
||||
},
|
||||
Signature: sig[:],
|
||||
}
|
||||
case version.Gloas:
|
||||
return nil, errors.Wrap(errUnsupportedBeaconBlock, "gloas blocks are not supported in this function")
|
||||
default:
|
||||
return nil, errors.New("Block not of known type")
|
||||
}
|
||||
|
||||
142
consensus-types/blocks/signed_execution_bid.go
Normal file
142
consensus-types/blocks/signed_execution_bid.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"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/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// signedExecutionPayloadBid wraps the protobuf signed execution payload bid
|
||||
// and implements the ROSignedExecutionPayloadBid interface.
|
||||
type signedExecutionPayloadBid struct {
|
||||
bid *ethpb.SignedExecutionPayloadBid
|
||||
}
|
||||
|
||||
// executionPayloadBidGloas wraps the protobuf execution payload bid for Gloas fork
|
||||
// and implements the ROExecutionPayloadBidGloas interface.
|
||||
type executionPayloadBidGloas struct {
|
||||
payload *ethpb.ExecutionPayloadBid
|
||||
}
|
||||
|
||||
// IsNil checks if the signed execution payload bid is nil or invalid.
|
||||
func (s signedExecutionPayloadBid) IsNil() bool {
|
||||
if s.bid == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if _, err := WrappedROExecutionPayloadBid(s.bid.Message); err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return len(s.bid.Signature) != 96
|
||||
}
|
||||
|
||||
// IsNil checks if the execution payload bid is nil or has invalid fields.
|
||||
func (h executionPayloadBidGloas) IsNil() bool {
|
||||
if h.payload == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(h.payload.ParentBlockHash) != 32 ||
|
||||
len(h.payload.ParentBlockRoot) != 32 ||
|
||||
len(h.payload.BlockHash) != 32 ||
|
||||
len(h.payload.PrevRandao) != 32 ||
|
||||
len(h.payload.BlobKzgCommitmentsRoot) != 32 ||
|
||||
len(h.payload.FeeRecipient) != 20 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// WrappedROSignedExecutionPayloadBid creates a new read-only signed execution payload bid
|
||||
// wrapper from the given protobuf message.
|
||||
func WrappedROSignedExecutionPayloadBid(pb *ethpb.SignedExecutionPayloadBid) (interfaces.ROSignedExecutionPayloadBid, error) {
|
||||
wrapper := signedExecutionPayloadBid{bid: pb}
|
||||
if wrapper.IsNil() {
|
||||
return nil, consensus_types.ErrNilObjectWrapped
|
||||
}
|
||||
return wrapper, nil
|
||||
}
|
||||
|
||||
// WrappedROExecutionPayloadBid creates a new read-only execution payload bid
|
||||
// wrapper for the Gloas fork from the given protobuf message.
|
||||
func WrappedROExecutionPayloadBid(pb *ethpb.ExecutionPayloadBid) (interfaces.ROExecutionPayloadBid, error) {
|
||||
wrapper := executionPayloadBidGloas{payload: pb}
|
||||
if wrapper.IsNil() {
|
||||
return nil, consensus_types.ErrNilObjectWrapped
|
||||
}
|
||||
return wrapper, nil
|
||||
}
|
||||
|
||||
// Bid returns the execution payload bid as a read-only interface.
|
||||
func (s signedExecutionPayloadBid) Bid() (interfaces.ROExecutionPayloadBid, error) {
|
||||
return WrappedROExecutionPayloadBid(s.bid.Message)
|
||||
}
|
||||
|
||||
// SigningRoot computes the signing root for the execution payload bid with the given domain.
|
||||
func (s signedExecutionPayloadBid) SigningRoot(domain []byte) ([32]byte, error) {
|
||||
return signing.ComputeSigningRoot(s.bid.Message, domain)
|
||||
}
|
||||
|
||||
// Signature returns the BLS signature as a 96-byte array.
|
||||
func (s signedExecutionPayloadBid) Signature() [96]byte {
|
||||
return [96]byte(s.bid.Signature)
|
||||
}
|
||||
|
||||
// ParentBlockHash returns the hash of the parent execution block.
|
||||
func (h executionPayloadBidGloas) ParentBlockHash() [32]byte {
|
||||
return [32]byte(h.payload.ParentBlockHash)
|
||||
}
|
||||
|
||||
// ParentBlockRoot returns the beacon block root of the parent block.
|
||||
func (h executionPayloadBidGloas) ParentBlockRoot() [32]byte {
|
||||
return [32]byte(h.payload.ParentBlockRoot)
|
||||
}
|
||||
|
||||
// PrevRandao returns the previous randao value for the execution block.
|
||||
func (h executionPayloadBidGloas) PrevRandao() [32]byte {
|
||||
return [32]byte(h.payload.PrevRandao)
|
||||
}
|
||||
|
||||
// BlockHash returns the hash of the execution block.
|
||||
func (h executionPayloadBidGloas) BlockHash() [32]byte {
|
||||
return [32]byte(h.payload.BlockHash)
|
||||
}
|
||||
|
||||
// GasLimit returns the gas limit for the execution block.
|
||||
func (h executionPayloadBidGloas) GasLimit() uint64 {
|
||||
return h.payload.GasLimit
|
||||
}
|
||||
|
||||
// BuilderIndex returns the validator index of the builder who created this bid.
|
||||
func (h executionPayloadBidGloas) BuilderIndex() primitives.BuilderIndex {
|
||||
return h.payload.BuilderIndex
|
||||
}
|
||||
|
||||
// Slot returns the beacon chain slot for which this bid was created.
|
||||
func (h executionPayloadBidGloas) Slot() primitives.Slot {
|
||||
return h.payload.Slot
|
||||
}
|
||||
|
||||
// Value returns the payment value offered by the builder in Gwei.
|
||||
func (h executionPayloadBidGloas) Value() primitives.Gwei {
|
||||
return primitives.Gwei(h.payload.Value)
|
||||
}
|
||||
|
||||
// ExecutionPayment returns the execution payment offered by the builder.
|
||||
func (h executionPayloadBidGloas) ExecutionPayment() primitives.Gwei {
|
||||
return primitives.Gwei(h.payload.ExecutionPayment)
|
||||
}
|
||||
|
||||
// BlobKzgCommitmentsRoot returns the root of the KZG commitments for blobs.
|
||||
func (h executionPayloadBidGloas) BlobKzgCommitmentsRoot() [32]byte {
|
||||
return [32]byte(h.payload.BlobKzgCommitmentsRoot)
|
||||
}
|
||||
|
||||
// FeeRecipient returns the execution address that will receive the builder payment.
|
||||
func (h executionPayloadBidGloas) FeeRecipient() [20]byte {
|
||||
return [20]byte(h.payload.FeeRecipient)
|
||||
}
|
||||
127
consensus-types/blocks/signed_execution_bid_test.go
Normal file
127
consensus-types/blocks/signed_execution_bid_test.go
Normal file
@@ -0,0 +1,127 @@
|
||||
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"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
)
|
||||
|
||||
func validExecutionPayloadBid() *ethpb.ExecutionPayloadBid {
|
||||
return ðpb.ExecutionPayloadBid{
|
||||
ParentBlockHash: bytes.Repeat([]byte{0x01}, 32),
|
||||
ParentBlockRoot: bytes.Repeat([]byte{0x02}, 32),
|
||||
BlockHash: bytes.Repeat([]byte{0x03}, 32),
|
||||
PrevRandao: bytes.Repeat([]byte{0x04}, 32),
|
||||
GasLimit: 123,
|
||||
BuilderIndex: 5,
|
||||
Slot: 6,
|
||||
Value: 7,
|
||||
ExecutionPayment: 8,
|
||||
BlobKzgCommitmentsRoot: bytes.Repeat([]byte{0x05}, 32),
|
||||
FeeRecipient: bytes.Repeat([]byte{0x06}, 20),
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrappedROExecutionPayloadBid(t *testing.T) {
|
||||
t.Run("returns error on invalid lengths", func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
mutate func(*ethpb.ExecutionPayloadBid)
|
||||
}{
|
||||
{
|
||||
name: "parent block hash",
|
||||
mutate: func(b *ethpb.ExecutionPayloadBid) { b.ParentBlockHash = []byte{0x01} },
|
||||
},
|
||||
{
|
||||
name: "parent block root",
|
||||
mutate: func(b *ethpb.ExecutionPayloadBid) { b.ParentBlockRoot = []byte{0x02} },
|
||||
},
|
||||
{
|
||||
name: "block hash",
|
||||
mutate: func(b *ethpb.ExecutionPayloadBid) { b.BlockHash = []byte{0x03} },
|
||||
},
|
||||
{
|
||||
name: "prev randao",
|
||||
mutate: func(b *ethpb.ExecutionPayloadBid) { b.PrevRandao = []byte{0x04} },
|
||||
},
|
||||
{
|
||||
name: "blob kzg commitments root",
|
||||
mutate: func(b *ethpb.ExecutionPayloadBid) { b.BlobKzgCommitmentsRoot = []byte{0x05} },
|
||||
},
|
||||
{
|
||||
name: "fee recipient",
|
||||
mutate: func(b *ethpb.ExecutionPayloadBid) { b.FeeRecipient = []byte{0x06} },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
invalid := validExecutionPayloadBid()
|
||||
tc.mutate(invalid)
|
||||
|
||||
_, err := blocks.WrappedROExecutionPayloadBid(invalid)
|
||||
require.Equal(t, consensus_types.ErrNilObjectWrapped, err)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("wraps and exposes fields", func(t *testing.T) {
|
||||
bid := validExecutionPayloadBid()
|
||||
wrapped, err := blocks.WrappedROExecutionPayloadBid(bid)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, primitives.BuilderIndex(5), wrapped.BuilderIndex())
|
||||
require.Equal(t, primitives.Slot(6), wrapped.Slot())
|
||||
require.Equal(t, primitives.Gwei(7), wrapped.Value())
|
||||
require.Equal(t, primitives.Gwei(8), wrapped.ExecutionPayment())
|
||||
assert.DeepEqual(t, [32]byte(bytes.Repeat([]byte{0x01}, 32)), wrapped.ParentBlockHash())
|
||||
assert.DeepEqual(t, [32]byte(bytes.Repeat([]byte{0x02}, 32)), wrapped.ParentBlockRoot())
|
||||
assert.DeepEqual(t, [32]byte(bytes.Repeat([]byte{0x03}, 32)), wrapped.BlockHash())
|
||||
assert.DeepEqual(t, [32]byte(bytes.Repeat([]byte{0x04}, 32)), wrapped.PrevRandao())
|
||||
assert.DeepEqual(t, [32]byte(bytes.Repeat([]byte{0x05}, 32)), wrapped.BlobKzgCommitmentsRoot())
|
||||
assert.DeepEqual(t, [20]byte(bytes.Repeat([]byte{0x06}, 20)), wrapped.FeeRecipient())
|
||||
})
|
||||
}
|
||||
|
||||
func TestWrappedROSignedExecutionPayloadBid(t *testing.T) {
|
||||
t.Run("returns error for invalid signature length", func(t *testing.T) {
|
||||
signed := ðpb.SignedExecutionPayloadBid{
|
||||
Message: validExecutionPayloadBid(),
|
||||
Signature: bytes.Repeat([]byte{0xAA}, 95),
|
||||
}
|
||||
_, err := blocks.WrappedROSignedExecutionPayloadBid(signed)
|
||||
require.Equal(t, consensus_types.ErrNilObjectWrapped, err)
|
||||
})
|
||||
|
||||
t.Run("wraps and provides bid/signing data", func(t *testing.T) {
|
||||
sig := bytes.Repeat([]byte{0xAB}, 96)
|
||||
signed := ðpb.SignedExecutionPayloadBid{
|
||||
Message: validExecutionPayloadBid(),
|
||||
Signature: sig,
|
||||
}
|
||||
|
||||
wrapped, err := blocks.WrappedROSignedExecutionPayloadBid(signed)
|
||||
require.NoError(t, err)
|
||||
|
||||
bid, err := wrapped.Bid()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, primitives.Gwei(8), bid.ExecutionPayment())
|
||||
|
||||
gotSig := wrapped.Signature()
|
||||
assert.DeepEqual(t, [96]byte(sig), gotSig)
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
@@ -6,6 +6,7 @@ go_library(
|
||||
"beacon_block.go",
|
||||
"error.go",
|
||||
"light_client.go",
|
||||
"signed_execution_payload_bid.go",
|
||||
"utils.go",
|
||||
"validator.go",
|
||||
],
|
||||
|
||||
28
consensus-types/interfaces/signed_execution_payload_bid.go
Normal file
28
consensus-types/interfaces/signed_execution_payload_bid.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package interfaces
|
||||
|
||||
import (
|
||||
field_params "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
)
|
||||
|
||||
type ROSignedExecutionPayloadBid interface {
|
||||
Bid() (ROExecutionPayloadBid, error)
|
||||
Signature() [field_params.BLSSignatureLength]byte
|
||||
SigningRoot([]byte) ([32]byte, error)
|
||||
IsNil() bool
|
||||
}
|
||||
|
||||
type ROExecutionPayloadBid interface {
|
||||
ParentBlockHash() [32]byte
|
||||
ParentBlockRoot() [32]byte
|
||||
PrevRandao() [32]byte
|
||||
BlockHash() [32]byte
|
||||
GasLimit() uint64
|
||||
BuilderIndex() primitives.BuilderIndex
|
||||
Slot() primitives.Slot
|
||||
Value() primitives.Gwei
|
||||
ExecutionPayment() primitives.Gwei
|
||||
BlobKzgCommitmentsRoot() [32]byte
|
||||
FeeRecipient() [20]byte
|
||||
IsNil() bool
|
||||
}
|
||||
58
deps.bzl
58
deps.bzl
@@ -73,8 +73,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_allegro_bigcache",
|
||||
importpath = "github.com/allegro/bigcache",
|
||||
sum = "h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=",
|
||||
version = "v1.2.1",
|
||||
sum = "h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=",
|
||||
version = "v1.2.1-0.20190218064605-e24eb225f156",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_andreasbriese_bbloom",
|
||||
@@ -783,13 +783,13 @@ def prysm_deps():
|
||||
version = "v1.2.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_ethereum_c_kzg_4844",
|
||||
name = "com_github_ethereum_c_kzg_4844_v2",
|
||||
build_directives = [
|
||||
"gazelle:resolve go github.com/supranational/blst/bindings/go @com_github_supranational_blst//:go_default_library",
|
||||
],
|
||||
importpath = "github.com/ethereum/c-kzg-4844/v2",
|
||||
patch_args = ["-p1"],
|
||||
patches = ["//third_party:com_github_ethereum_c_kzg_4844.patch"],
|
||||
patches = ["//third_party:com_github_ethereum_c_kzg_4844_v2.patch"],
|
||||
sum = "h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=",
|
||||
version = "v2.1.5",
|
||||
)
|
||||
@@ -810,8 +810,8 @@ def prysm_deps():
|
||||
patches = [
|
||||
"//third_party:com_github_ethereum_go_ethereum_secp256k1.patch",
|
||||
],
|
||||
sum = "h1:qeM4TvbrWK0UC0tgkZ7NiRsmBGwsjqc64BHo20U59UQ=",
|
||||
version = "v1.16.7",
|
||||
sum = "h1:LLLfkZWijhR5m6yrAXbdlTeXoqontH+Ga2f9igY7law=",
|
||||
version = "v1.16.8",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_ethereum_go_verkle",
|
||||
@@ -939,18 +939,6 @@ def prysm_deps():
|
||||
sum = "h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=",
|
||||
version = "v0.0.0-20191108122812-4678299bea08",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_gdamore_encoding",
|
||||
importpath = "github.com/gdamore/encoding",
|
||||
sum = "h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw=",
|
||||
version = "v1.0.1",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_gdamore_tcell_v2",
|
||||
importpath = "github.com/gdamore/tcell/v2",
|
||||
sum = "h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=",
|
||||
version = "v2.7.4",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_getkin_kin_openapi",
|
||||
importpath = "github.com/getkin/kin-openapi",
|
||||
@@ -1559,12 +1547,6 @@ def prysm_deps():
|
||||
sum = "h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=",
|
||||
version = "v2.0.3",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_holiman_goevmlab",
|
||||
importpath = "github.com/holiman/goevmlab",
|
||||
sum = "h1:krEMViaomzuBfH/L1V4b8w2lVfsEpUbxH1ZJQpUaT6E=",
|
||||
version = "v0.0.0-20250515153315-ab84907ebdb2",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_holiman_uint256",
|
||||
importpath = "github.com/holiman/uint256",
|
||||
@@ -1897,12 +1879,6 @@ def prysm_deps():
|
||||
sum = "h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk=",
|
||||
version = "v0.0.5",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_korovkin_limiter",
|
||||
importpath = "github.com/korovkin/limiter",
|
||||
sum = "h1:7CfsXfFpCG1wrUpuyOzG8+vpL1ZqH2goz23wZ9pboGE=",
|
||||
version = "v0.0.0-20230307205149-3d4b2b34c99d",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_kr_fs",
|
||||
importpath = "github.com/kr/fs",
|
||||
@@ -2070,12 +2046,6 @@ def prysm_deps():
|
||||
sum = "h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=",
|
||||
version = "v2.0.3+incompatible",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_lucasb_eyer_go_colorful",
|
||||
importpath = "github.com/lucasb-eyer/go-colorful",
|
||||
sum = "h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=",
|
||||
version = "v1.2.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_lunixbochs_vtclean",
|
||||
importpath = "github.com/lunixbochs/vtclean",
|
||||
@@ -2148,12 +2118,6 @@ def prysm_deps():
|
||||
sum = "h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=",
|
||||
version = "v1.0.4",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_matttproud_golang_protobuf_extensions_v2",
|
||||
importpath = "github.com/matttproud/golang_protobuf_extensions/v2",
|
||||
sum = "h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=",
|
||||
version = "v2.0.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_mgutz_ansi",
|
||||
importpath = "github.com/mgutz/ansi",
|
||||
@@ -2445,8 +2409,8 @@ def prysm_deps():
|
||||
importpath = "github.com/OffchainLabs/hashtree",
|
||||
patch_args = ["-p1"],
|
||||
patches = ["//third_party:com_github_offchainlabs_hashtree.patch"],
|
||||
sum = "h1:R6DAjgAUwwfgji3jEI4WUxtZ3eJ+FbRHjW21UPMBJyo=",
|
||||
version = "v0.2.2",
|
||||
sum = "h1:nM8dBAQZzHLzzM14FaAHXnHTAXZIst69v5xWuS48y/c=",
|
||||
version = "v0.2.3",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_oklog_oklog",
|
||||
@@ -2947,12 +2911,6 @@ def prysm_deps():
|
||||
sum = "h1:dY6ETXrvDG7Sa4vE8ZQG4yqWg6UnOcbqTAahkV813vQ=",
|
||||
version = "v0.0.0-20190826022208-cac0b30c2563",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_rivo_tview",
|
||||
importpath = "github.com/rivo/tview",
|
||||
sum = "h1:HxvWMyQ3vKQBlYZq9wfFtjbUeA6UUYZoLJmmwWee43s=",
|
||||
version = "v0.0.0-20240519200218-0ac5f73025a8",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_rivo_uniseg",
|
||||
build_directives = [
|
||||
|
||||
2
go.mod
2
go.mod
@@ -15,7 +15,7 @@ require (
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/emicklei/dot v1.6.2
|
||||
github.com/ethereum/c-kzg-4844/v2 v2.1.5
|
||||
github.com/ethereum/go-ethereum v1.16.7
|
||||
github.com/ethereum/go-ethereum v1.16.8
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible
|
||||
|
||||
8
go.sum
8
go.sum
@@ -55,10 +55,10 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/OffchainLabs/go-bitfield v0.0.0-20251031151322-f427d04d8506 h1:d/SJkN8/9Ca+1YmuDiUJxAiV4w/a9S8NcsG7GMQSrVI=
|
||||
github.com/OffchainLabs/go-bitfield v0.0.0-20251031151322-f427d04d8506/go.mod h1:6TZI4FU6zT8x6ZfWa1J8YQ2NgW0wLV/W3fHRca8ISBo=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
|
||||
github.com/OffchainLabs/hashtree v0.2.3 h1:nM8dBAQZzHLzzM14FaAHXnHTAXZIst69v5xWuS48y/c=
|
||||
github.com/OffchainLabs/hashtree v0.2.3/go.mod h1:b07+cRZs+eAR8TR57CB9TQlt5Gnl/06Xs76xt/1wq0M=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
@@ -238,8 +238,8 @@ github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3
|
||||
github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs=
|
||||
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk=
|
||||
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8=
|
||||
github.com/ethereum/go-ethereum v1.16.7 h1:qeM4TvbrWK0UC0tgkZ7NiRsmBGwsjqc64BHo20U59UQ=
|
||||
github.com/ethereum/go-ethereum v1.16.7/go.mod h1:Fs6QebQbavneQTYcA39PEKv2+zIjX7rPUZ14DER46wk=
|
||||
github.com/ethereum/go-ethereum v1.16.8 h1:LLLfkZWijhR5m6yrAXbdlTeXoqontH+Ga2f9igY7law=
|
||||
github.com/ethereum/go-ethereum v1.16.8/go.mod h1:Fs6QebQbavneQTYcA39PEKv2+zIjX7rPUZ14DER46wk=
|
||||
github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8=
|
||||
github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
|
||||
@@ -1,22 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Continuous Integration script to check that BUILD.bazel files are as expected
|
||||
# when generated from gazelle.
|
||||
# Continuous Integration script to check that BUILD.bazel files and deps.bzl
|
||||
# are as expected when generated from gazelle.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
exit_code=0
|
||||
|
||||
# Duplicate redirect 5 to stdout so that it can be captured, but still printed
|
||||
# nicely.
|
||||
exec 5>&1
|
||||
|
||||
# Run gazelle while piping a copy of the output to stdout via 5.
|
||||
changes=$(bazel --batch --bazelrc=.buildkite-bazelrc run //:gazelle -- fix --mode=diff | tee >(cat - >&5))
|
||||
echo "Checking deps.bzl is in sync with go.mod..."
|
||||
bazel --batch --bazelrc=.buildkite-bazelrc run //:gazelle -- update-repos -from_file=go.mod -to_macro=deps.bzl%prysm_deps -prune=true
|
||||
|
||||
# If the captured stdout is not empty then Gazelle has diffs.
|
||||
if [ -z "$changes" ]
|
||||
then
|
||||
echo "OK: Gazelle does not need to be run"
|
||||
exit 0
|
||||
if git diff --exit-code deps.bzl; then
|
||||
echo "OK: deps.bzl is in sync with go.mod"
|
||||
else
|
||||
echo "FAIL: Gazelle needs to be run"
|
||||
echo "Please run bazel run //:gazelle -- fix"
|
||||
exit 1
|
||||
echo ""
|
||||
echo "FAIL: deps.bzl is out of sync with go.mod"
|
||||
exit_code=1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Checking BUILD.bazel files..."
|
||||
build_changes=$(bazel --batch --bazelrc=.buildkite-bazelrc run //:gazelle -- fix --mode=diff | tee >(cat - >&5)) || true
|
||||
|
||||
if [ -z "$build_changes" ]; then
|
||||
echo "OK: BUILD.bazel files are in sync"
|
||||
else
|
||||
echo "FAIL: BUILD.bazel files are out of sync"
|
||||
exit_code=1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [ $exit_code -eq 0 ]; then
|
||||
echo "All gazelle checks passed"
|
||||
else
|
||||
echo "Gazelle checks failed. Please run:"
|
||||
echo " bazel run //:gazelle -- update-repos -from_file=go.mod -to_macro=deps.bzl%prysm_deps -prune=true"
|
||||
echo " bazel run //:gazelle -- fix"
|
||||
fi
|
||||
|
||||
exit $exit_code
|
||||
|
||||
@@ -189,3 +189,28 @@ func copyBeaconBlockBodyGloas(body *BeaconBlockBodyGloas) *BeaconBlockBodyGloas
|
||||
|
||||
return copied
|
||||
}
|
||||
|
||||
// CopyBuilderPendingPayment creates a deep copy of a builder pending payment.
|
||||
func CopyBuilderPendingPayment(original *BuilderPendingPayment) *BuilderPendingPayment {
|
||||
if original == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &BuilderPendingPayment{
|
||||
Weight: original.Weight,
|
||||
Withdrawal: CopyBuilderPendingWithdrawal(original.Withdrawal),
|
||||
}
|
||||
}
|
||||
|
||||
// CopyBuilderPendingWithdrawal creates a deep copy of a builder pending withdrawal.
|
||||
func CopyBuilderPendingWithdrawal(original *BuilderPendingWithdrawal) *BuilderPendingWithdrawal {
|
||||
if original == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &BuilderPendingWithdrawal{
|
||||
FeeRecipient: bytesutil.SafeCopyBytes(original.FeeRecipient),
|
||||
Amount: original.Amount,
|
||||
BuilderIndex: original.BuilderIndex,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1246,3 +1246,89 @@ func genPayloadAttestations(num int) []*v1alpha1.PayloadAttestation {
|
||||
}
|
||||
return pas
|
||||
}
|
||||
|
||||
func TestCopyBuilderPendingWithdrawal(t *testing.T) {
|
||||
t.Run("nil returns nil", func(t *testing.T) {
|
||||
if got := v1alpha1.CopyBuilderPendingWithdrawal(nil); got != nil {
|
||||
t.Fatalf("CopyBuilderPendingWithdrawal(nil) = %v, want nil", got)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deep copy", func(t *testing.T) {
|
||||
original := &v1alpha1.BuilderPendingWithdrawal{
|
||||
FeeRecipient: []byte{0x01, 0x02},
|
||||
Amount: primitives.Gwei(10),
|
||||
BuilderIndex: primitives.BuilderIndex(3),
|
||||
}
|
||||
|
||||
copied := v1alpha1.CopyBuilderPendingWithdrawal(original)
|
||||
if copied == original {
|
||||
t.Fatalf("expected new pointer for withdrawal copy")
|
||||
}
|
||||
if !reflect.DeepEqual(copied, original) {
|
||||
t.Fatalf("CopyBuilderPendingWithdrawal() = %v, want %v", copied, original)
|
||||
}
|
||||
|
||||
original.FeeRecipient[0] = 0xFF
|
||||
original.Amount = primitives.Gwei(20)
|
||||
original.BuilderIndex = primitives.BuilderIndex(9)
|
||||
|
||||
if copied.FeeRecipient[0] == original.FeeRecipient[0] {
|
||||
t.Fatalf("fee recipient was not deep copied")
|
||||
}
|
||||
if copied.Amount != primitives.Gwei(10) {
|
||||
t.Fatalf("amount mutated on copy: %d", copied.Amount)
|
||||
}
|
||||
if copied.BuilderIndex != primitives.BuilderIndex(3) {
|
||||
t.Fatalf("builder index mutated on copy: %d", copied.BuilderIndex)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCopyBuilderPendingPayment(t *testing.T) {
|
||||
t.Run("nil returns nil", func(t *testing.T) {
|
||||
if got := v1alpha1.CopyBuilderPendingPayment(nil); got != nil {
|
||||
t.Fatalf("CopyBuilderPendingPayment(nil) = %v, want nil", got)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("deep copy", func(t *testing.T) {
|
||||
original := &v1alpha1.BuilderPendingPayment{
|
||||
Weight: primitives.Gwei(5),
|
||||
Withdrawal: &v1alpha1.BuilderPendingWithdrawal{
|
||||
FeeRecipient: []byte{0x0A, 0x0B},
|
||||
Amount: primitives.Gwei(50),
|
||||
BuilderIndex: primitives.BuilderIndex(7),
|
||||
},
|
||||
}
|
||||
|
||||
copied := v1alpha1.CopyBuilderPendingPayment(original)
|
||||
if copied == original {
|
||||
t.Fatalf("expected new pointer for payment copy")
|
||||
}
|
||||
if copied.Withdrawal == original.Withdrawal {
|
||||
t.Fatalf("expected nested withdrawal to be deep copied")
|
||||
}
|
||||
if !reflect.DeepEqual(copied, original) {
|
||||
t.Fatalf("CopyBuilderPendingPayment() = %v, want %v", copied, original)
|
||||
}
|
||||
|
||||
original.Weight = primitives.Gwei(10)
|
||||
original.Withdrawal.FeeRecipient[0] = 0xFF
|
||||
original.Withdrawal.Amount = primitives.Gwei(75)
|
||||
original.Withdrawal.BuilderIndex = primitives.BuilderIndex(9)
|
||||
|
||||
if copied.Weight != primitives.Gwei(5) {
|
||||
t.Fatalf("weight mutated on copy: %d", copied.Weight)
|
||||
}
|
||||
if copied.Withdrawal.FeeRecipient[0] == original.Withdrawal.FeeRecipient[0] {
|
||||
t.Fatalf("withdrawal fee recipient was not deep copied")
|
||||
}
|
||||
if copied.Withdrawal.Amount != primitives.Gwei(50) {
|
||||
t.Fatalf("withdrawal amount mutated on copy: %d", copied.Withdrawal.Amount)
|
||||
}
|
||||
if copied.Withdrawal.BuilderIndex != primitives.BuilderIndex(7) {
|
||||
t.Fatalf("withdrawal builder index mutated on copy: %d", copied.Withdrawal.BuilderIndex)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -200,6 +200,7 @@ go_test(
|
||||
"fulu__sanity__blocks_test.go",
|
||||
"fulu__sanity__slots_test.go",
|
||||
"fulu__ssz_static__ssz_static_test.go",
|
||||
"gloas__operations__execution_payload_header_test.go",
|
||||
"gloas__ssz_static__ssz_static_test.go",
|
||||
"phase0__epoch_processing__effective_balance_updates_test.go",
|
||||
"phase0__epoch_processing__epoch_processing_test.go",
|
||||
@@ -278,6 +279,7 @@ go_test(
|
||||
"//testing/spectest/shared/fulu/rewards:go_default_library",
|
||||
"//testing/spectest/shared/fulu/sanity:go_default_library",
|
||||
"//testing/spectest/shared/fulu/ssz_static:go_default_library",
|
||||
"//testing/spectest/shared/gloas/operations:go_default_library",
|
||||
"//testing/spectest/shared/gloas/ssz_static:go_default_library",
|
||||
"//testing/spectest/shared/phase0/epoch_processing:go_default_library",
|
||||
"//testing/spectest/shared/phase0/finality:go_default_library",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package mainnet
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations"
|
||||
)
|
||||
|
||||
func TestMainnet_Gloas_Operations_ExecutionPayloadBid(t *testing.T) {
|
||||
operations.RunExecutionPayloadBidTest(t, "mainnet")
|
||||
}
|
||||
@@ -206,6 +206,7 @@ go_test(
|
||||
"fulu__sanity__blocks_test.go",
|
||||
"fulu__sanity__slots_test.go",
|
||||
"fulu__ssz_static__ssz_static_test.go",
|
||||
"gloas__operations__execution_payload_bid_test.go",
|
||||
"gloas__ssz_static__ssz_static_test.go",
|
||||
"phase0__epoch_processing__effective_balance_updates_test.go",
|
||||
"phase0__epoch_processing__epoch_processing_test.go",
|
||||
@@ -288,6 +289,7 @@ go_test(
|
||||
"//testing/spectest/shared/fulu/rewards:go_default_library",
|
||||
"//testing/spectest/shared/fulu/sanity:go_default_library",
|
||||
"//testing/spectest/shared/fulu/ssz_static:go_default_library",
|
||||
"//testing/spectest/shared/gloas/operations:go_default_library",
|
||||
"//testing/spectest/shared/gloas/ssz_static:go_default_library",
|
||||
"//testing/spectest/shared/phase0/epoch_processing:go_default_library",
|
||||
"//testing/spectest/shared/phase0/finality:go_default_library",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package minimal
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations"
|
||||
)
|
||||
|
||||
func TestMinimal_Gloas_Operations_ExecutionPayloadBid(t *testing.T) {
|
||||
operations.RunExecutionPayloadBidTest(t, "minimal")
|
||||
}
|
||||
@@ -12,6 +12,7 @@ go_library(
|
||||
"deposit.go",
|
||||
"deposit_request.go",
|
||||
"execution_payload.go",
|
||||
"execution_payload_bid.go",
|
||||
"proposer_slashing.go",
|
||||
"slashing.go",
|
||||
"sync_aggregate.go",
|
||||
@@ -26,6 +27,7 @@ go_library(
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/electra:go_default_library",
|
||||
"//beacon-chain/core/gloas:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"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/consensus-types/interfaces"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/spectest/utils"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/util"
|
||||
"github.com/golang/snappy"
|
||||
)
|
||||
|
||||
func runExecutionPayloadBidTest(t *testing.T, config string, fork string, objName string, block blockWithSSZObject, sszToState SSZToState, operationFn BlockOperation) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, fork, "operations/"+objName+"/pyspec_tests")
|
||||
if len(testFolders) == 0 {
|
||||
t.Fatalf("No test folders found for %s/%s/%s", config, fork, "operations/"+objName+"/pyspec_tests")
|
||||
}
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
helpers.ClearCache()
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
blockFile, err := util.BazelFileBytes(folderPath, "block.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
blockSSZ, err := snappy.Decode(nil /* dst */, blockFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
blk, err := block(blockSSZ)
|
||||
require.NoError(t, err)
|
||||
RunBlockOperationTest(t, folderPath, blk, sszToState, operationFn)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func RunExecutionPayloadBidTest(t *testing.T, config string, fork string, block blockWithSSZObject, sszToState SSZToState) {
|
||||
runExecutionPayloadBidTest(t, config, fork, "execution_payload_bid", block, sszToState, func(ctx context.Context, s state.BeaconState, b interfaces.ReadOnlySignedBeaconBlock) (state.BeaconState, error) {
|
||||
err := gloas.ProcessExecutionPayloadBid(s, b.Block())
|
||||
return s, err
|
||||
})
|
||||
}
|
||||
21
testing/spectest/shared/gloas/operations/BUILD.bazel
Normal file
21
testing/spectest/shared/gloas/operations/BUILD.bazel
Normal file
@@ -0,0 +1,21 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"execution_payload_bid.go",
|
||||
"helpers.go",
|
||||
],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/testing/spectest/shared/gloas/operations",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native: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/spectest/shared/common/operations:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
||||
common "github.com/OffchainLabs/prysm/v7/testing/spectest/shared/common/operations"
|
||||
)
|
||||
|
||||
func blockWithSignedExecutionPayloadBid(blockSSZ []byte) (interfaces.SignedBeaconBlock, error) {
|
||||
var block ethpb.BeaconBlockGloas
|
||||
if err := block.UnmarshalSSZ(blockSSZ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockGloas{Block: &block})
|
||||
}
|
||||
|
||||
func RunExecutionPayloadBidTest(t *testing.T, config string) {
|
||||
common.RunExecutionPayloadBidTest(t, config, version.String(version.Gloas), blockWithSignedExecutionPayloadBid, sszToState)
|
||||
}
|
||||
15
testing/spectest/shared/gloas/operations/helpers.go
Normal file
15
testing/spectest/shared/gloas/operations/helpers.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
||||
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
func sszToState(b []byte) (state.BeaconState, error) {
|
||||
base := ðpb.BeaconStateGloas{}
|
||||
if err := base.UnmarshalSSZ(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return state_native.InitializeFromProtoGloas(base)
|
||||
}
|
||||
@@ -14,7 +14,7 @@ index 7e49df7..1d476f7 100644
|
||||
copts = [
|
||||
- "-Ibindings/go/src",
|
||||
- "-Ibindings/go/bindings/go/blst_headers",
|
||||
+ "-Iexternal/com_github_ethereum_c_kzg_4844/src",
|
||||
+ "-Iexternal/com_github_ethereum_c_kzg_4844_v2/src",
|
||||
+ "-Iexternal/com_github_supranational_blst/bindings/blst_headers",
|
||||
],
|
||||
importpath = "github.com/ethereum/c-kzg-4844/v2/bindings/go",
|
||||
Reference in New Issue
Block a user