Compare commits

..

5 Commits

Author SHA1 Message Date
terence
995d53706c Changelog 2026-01-23 21:50:59 -08:00
terence
db54dc0e22 Clean up after merge confilcts for better review 2026-01-23 21:44:44 -08:00
terence
e2005cf8cf Resolve merge conflicts 2026-01-23 21:26:08 -08:00
terence
c617611b2f Review feedback 1 2026-01-23 21:04:43 -08:00
terence tsao
1a8c753f57 Implement process attestation 2026-01-16 08:36:04 +08:00
127 changed files with 1726 additions and 1536 deletions

View File

@@ -20,6 +20,7 @@ go_library(
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/epoch:go_default_library",
"//beacon-chain/core/epoch/precompute:go_default_library",
"//beacon-chain/core/gloas:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/signing:go_default_library",
"//beacon-chain/core/time:go_default_library",

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/time"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
@@ -16,6 +17,7 @@ import (
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1/attestation"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/pkg/errors"
)
@@ -75,7 +77,12 @@ func ProcessAttestationNoVerifySignature(
return nil, err
}
return SetParticipationAndRewardProposer(ctx, beaconState, att.GetData().Target.Epoch, indices, participatedFlags, totalBalance)
beaconState, err = gloas.UpdatePendingPaymentWeight(beaconState, att, indices, participatedFlags)
if err != nil {
return nil, errors.Wrap(err, "failed to update pending payment weight")
}
return SetParticipationAndRewardProposer(ctx, beaconState, att.GetData().Target.Epoch, indices, participatedFlags, totalBalance, att)
}
// SetParticipationAndRewardProposer retrieves and sets the epoch participation bits in state. Based on the epoch participation, it rewards
@@ -105,7 +112,9 @@ func SetParticipationAndRewardProposer(
beaconState state.BeaconState,
targetEpoch primitives.Epoch,
indices []uint64,
participatedFlags map[uint8]bool, totalBalance uint64) (state.BeaconState, error) {
participatedFlags map[uint8]bool,
totalBalance uint64,
att ethpb.Att) (state.BeaconState, error) {
var proposerRewardNumerator uint64
currentEpoch := time.CurrentEpoch(beaconState)
var stateErr error
@@ -299,6 +308,40 @@ func AttestationParticipationFlagIndices(beaconState state.ReadOnlyBeaconState,
participatedFlags[targetFlagIndex] = true
}
matchedSrcTgtHead := matchedHead && matchedSrcTgt
// Spec v1.7.0-alpha pseudocode:
//
// # [New in Gloas:EIP7732]
// if is_attestation_same_slot(state, data):
// assert data.index == 0
// payload_matches = True
// else:
// slot_index = data.slot % SLOTS_PER_HISTORICAL_ROOT
// payload_index = state.execution_payload_availability[slot_index]
// payload_matches = data.index == payload_index
//
// # [Modified in Gloas:EIP7732]
// is_matching_head = is_matching_target and head_root_matches and payload_matches
var matchingPayload bool
if beaconState.Version() >= version.Gloas {
sameSlot, err := gloas.SameSlotAttestation(beaconState, [32]byte(data.BeaconBlockRoot), data.Slot)
if err != nil {
return nil, errors.Wrap(err, "failed to get same slot attestation status")
}
if sameSlot {
if data.CommitteeIndex != 0 {
return nil, fmt.Errorf("committee index %d for same slot attestation must be 0", data.CommitteeIndex)
}
matchingPayload = true
} else {
executionPayloadAvail, err := beaconState.ExecutionPayloadAvailability(data.Slot)
if err != nil {
return nil, errors.Wrap(err, "failed to get execution payload availability status")
}
matchingPayload = executionPayloadAvail == uint64(data.CommitteeIndex)
}
matchedSrcTgtHead = matchedSrcTgtHead && matchingPayload
}
if matchedSrcTgtHead && delay == cfg.MinAttestationInclusionDelay {
participatedFlags[headFlagIndex] = true
}

View File

@@ -1,7 +1,9 @@
package altair_test
import (
"bytes"
"fmt"
"reflect"
"testing"
"github.com/OffchainLabs/go-bitfield"
@@ -556,7 +558,7 @@ func TestSetParticipationAndRewardProposer(t *testing.T) {
b, err := helpers.TotalActiveBalance(beaconState)
require.NoError(t, err)
st, err := altair.SetParticipationAndRewardProposer(t.Context(), beaconState, test.epoch, test.indices, test.participatedFlags, b)
st, err := altair.SetParticipationAndRewardProposer(t.Context(), beaconState, test.epoch, test.indices, test.participatedFlags, b, &ethpb.Attestation{})
require.NoError(t, err)
i, err := helpers.BeaconProposerIndex(t.Context(), st)
@@ -775,11 +777,67 @@ func TestAttestationParticipationFlagIndices(t *testing.T) {
headFlagIndex: true,
},
},
{
name: "gloas same-slot committee index non-zero errors",
inputState: func() state.BeaconState {
stateSlot := primitives.Slot(5)
slot := primitives.Slot(3)
targetRoot := bytes.Repeat([]byte{0xAA}, 32)
headRoot := bytes.Repeat([]byte{0xBB}, 32)
prevRoot := bytes.Repeat([]byte{0xCC}, 32)
return buildGloasStateForFlags(t, stateSlot, slot, targetRoot, headRoot, prevRoot, 0, 0)
}(),
inputData: &ethpb.AttestationData{
Slot: 3,
CommitteeIndex: 1, // invalid for same-slot
BeaconBlockRoot: bytes.Repeat([]byte{0xBB}, 32),
Source: &ethpb.Checkpoint{Root: bytes.Repeat([]byte{0xDD}, 32)},
Target: &ethpb.Checkpoint{
Epoch: 0,
Root: bytes.Repeat([]byte{0xAA}, 32),
},
},
inputDelay: 1,
participationIndices: nil,
},
{
name: "gloas payload availability matches committee index",
inputState: func() state.BeaconState {
stateSlot := primitives.Slot(5)
slot := primitives.Slot(3)
targetRoot := bytes.Repeat([]byte{0xAA}, 32)
headRoot := bytes.Repeat([]byte{0xBB}, 32)
// Same prev root to make SameSlotAttestation false and use payload availability.
return buildGloasStateForFlags(t, stateSlot, slot, targetRoot, headRoot, headRoot, 1, slot)
}(),
inputData: &ethpb.AttestationData{
Slot: 3,
CommitteeIndex: 1,
BeaconBlockRoot: bytes.Repeat([]byte{0xBB}, 32),
Source: &ethpb.Checkpoint{Root: bytes.Repeat([]byte{0xDD}, 32)},
Target: &ethpb.Checkpoint{
Epoch: 0,
Root: bytes.Repeat([]byte{0xAA}, 32),
},
},
inputDelay: 1,
participationIndices: map[uint8]bool{
sourceFlagIndex: true,
targetFlagIndex: true,
headFlagIndex: true,
},
},
}
for _, test := range tests {
flagIndices, err := altair.AttestationParticipationFlagIndices(test.inputState, test.inputData, test.inputDelay)
if test.participationIndices == nil {
require.ErrorContains(t, "committee index", err)
continue
}
require.NoError(t, err)
require.DeepEqual(t, test.participationIndices, flagIndices)
if !reflect.DeepEqual(test.participationIndices, flagIndices) {
t.Fatalf("unexpected participation indices: got %v want %v", flagIndices, test.participationIndices)
}
}
}
@@ -858,3 +916,61 @@ func TestMatchingStatus(t *testing.T) {
require.Equal(t, test.matchedHead, head)
}
}
func buildGloasStateForFlags(t *testing.T, stateSlot, slot primitives.Slot, targetRoot, headRoot, prevRoot []byte, availabilityBit uint8, availabilitySlot primitives.Slot) state.BeaconState {
t.Helper()
cfg := params.BeaconConfig()
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
blockRoots[0] = targetRoot
blockRoots[slot%cfg.SlotsPerHistoricalRoot] = headRoot
blockRoots[(slot-1)%cfg.SlotsPerHistoricalRoot] = prevRoot
stateRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
for i := range stateRoots {
stateRoots[i] = make([]byte, fieldparams.RootLength)
}
randaoMixes := make([][]byte, cfg.EpochsPerHistoricalVector)
for i := range randaoMixes {
randaoMixes[i] = make([]byte, fieldparams.RootLength)
}
execPayloadAvailability := make([]byte, cfg.SlotsPerHistoricalRoot/8)
idx := availabilitySlot % cfg.SlotsPerHistoricalRoot
byteIndex := idx / 8
bitIndex := idx % 8
if availabilityBit == 1 {
execPayloadAvailability[byteIndex] |= 1 << bitIndex
}
checkpointRoot := bytes.Repeat([]byte{0xDD}, fieldparams.RootLength)
justified := &ethpb.Checkpoint{Root: checkpointRoot}
stProto := &ethpb.BeaconStateGloas{
Slot: stateSlot,
GenesisValidatorsRoot: bytes.Repeat([]byte{0x11}, fieldparams.RootLength),
BlockRoots: blockRoots,
StateRoots: stateRoots,
RandaoMixes: randaoMixes,
ExecutionPayloadAvailability: execPayloadAvailability,
CurrentJustifiedCheckpoint: justified,
PreviousJustifiedCheckpoint: justified,
Validators: []*ethpb.Validator{
{
EffectiveBalance: cfg.MinActivationBalance,
WithdrawalCredentials: append([]byte{cfg.ETH1AddressWithdrawalPrefixByte}, bytes.Repeat([]byte{0x01}, 31)...),
},
},
Balances: []uint64{cfg.MinActivationBalance},
BuilderPendingPayments: make([]*ethpb.BuilderPendingPayment, cfg.SlotsPerEpoch*2),
Fork: &ethpb.Fork{
CurrentVersion: bytes.Repeat([]byte{0x01}, 4),
PreviousVersion: bytes.Repeat([]byte{0x01}, 4),
Epoch: 0,
},
}
beaconState, err := state_native.InitializeFromProtoGloas(stProto)
require.NoError(t, err)
return beaconState
}

View File

@@ -111,7 +111,16 @@ func VerifyAttestationNoVerifySignature(
var indexedAtt ethpb.IndexedAtt
if att.Version() >= version.Electra {
if att.GetData().CommitteeIndex != 0 {
// Spec v1.7.0-alpha pseudocode:
//
// # [Modified in Gloas:EIP7732]
// assert data.index < 2
//
if beaconState.Version() >= version.Gloas {
if att.GetData().CommitteeIndex >= 2 {
return fmt.Errorf("incorrect committee index %d", att.GetData().CommitteeIndex)
}
} else if att.GetData().CommitteeIndex != 0 {
return errors.New("committee index must be 0 post-Electra")
}

View File

@@ -1,6 +1,7 @@
package blocks_test
import (
"bytes"
"context"
"testing"
@@ -314,6 +315,75 @@ func TestVerifyAttestationNoVerifySignature_Electra(t *testing.T) {
})
}
func TestVerifyAttestationNoVerifySignature_GloasCommitteeIndexLimit(t *testing.T) {
cfg := params.BeaconConfig()
stateSlot := cfg.MinAttestationInclusionDelay + 1
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
for i := range blockRoots {
blockRoots[i] = make([]byte, fieldparams.RootLength)
}
stateRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
for i := range stateRoots {
stateRoots[i] = make([]byte, fieldparams.RootLength)
}
randaoMixes := make([][]byte, cfg.EpochsPerHistoricalVector)
for i := range randaoMixes {
randaoMixes[i] = make([]byte, fieldparams.RootLength)
}
checkpointRoot := bytes.Repeat([]byte{0xAA}, fieldparams.RootLength)
justified := &ethpb.Checkpoint{Epoch: 0, Root: checkpointRoot}
gloasStateProto := &ethpb.BeaconStateGloas{
Slot: stateSlot,
GenesisValidatorsRoot: bytes.Repeat([]byte{0x11}, fieldparams.RootLength),
BlockRoots: blockRoots,
StateRoots: stateRoots,
RandaoMixes: randaoMixes,
ExecutionPayloadAvailability: make([]byte, cfg.SlotsPerHistoricalRoot/8),
CurrentJustifiedCheckpoint: justified,
PreviousJustifiedCheckpoint: justified,
Validators: []*ethpb.Validator{
{
EffectiveBalance: cfg.MinActivationBalance,
WithdrawalCredentials: append([]byte{cfg.ETH1AddressWithdrawalPrefixByte}, bytes.Repeat([]byte{0x01}, 31)...),
},
},
Balances: []uint64{cfg.MinActivationBalance},
BuilderPendingPayments: make([]*ethpb.BuilderPendingPayment, cfg.SlotsPerEpoch*2),
Fork: &ethpb.Fork{
CurrentVersion: bytes.Repeat([]byte{0x01}, 4),
PreviousVersion: bytes.Repeat([]byte{0x01}, 4),
Epoch: 0,
},
}
beaconState, err := state_native.InitializeFromProtoGloas(gloasStateProto)
require.NoError(t, err)
committeeBits := bitfield.NewBitvector64()
committeeBits.SetBitAt(0, true)
aggBits := bitfield.NewBitlist(1)
aggBits.SetBitAt(0, true)
att := &ethpb.AttestationElectra{
Data: &ethpb.AttestationData{
Slot: 0,
CommitteeIndex: 2, // invalid for Gloas (must be <2)
BeaconBlockRoot: blockRoots[0],
Source: justified,
Target: justified,
},
AggregationBits: aggBits,
CommitteeBits: committeeBits,
Signature: bytes.Repeat([]byte{0x00}, fieldparams.BLSSignatureLength),
}
err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
assert.ErrorContains(t, "incorrect committee index 2", err)
}
func TestConvertToIndexed_OK(t *testing.T) {
helpers.ClearCache()
validators := make([]*ethpb.Validator, 2*params.BeaconConfig().SlotsPerEpoch)
@@ -583,6 +653,7 @@ func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) {
}
func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing.T) {
helpers.ClearCache()
ctx := t.Context()
numOfValidators := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(4))
validators := make([]*ethpb.Validator, numOfValidators)
@@ -590,17 +661,25 @@ func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing
require.NoError(t, err)
for i := range validators {
validators[i] = &ethpb.Validator{
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: keys[i].PublicKey().Marshal(),
WithdrawalCredentials: make([]byte, 32),
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: keys[i].PublicKey().Marshal(),
WithdrawalCredentials: make([]byte, 32),
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
ActivationEligibilityEpoch: 0,
ActivationEpoch: 0,
}
}
balances := make([]uint64, numOfValidators)
for i := range balances {
balances[i] = uint64(params.BeaconConfig().MaxEffectiveBalance)
}
t.Run("pre-Electra", func(t *testing.T) {
st, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, st.SetSlot(5))
require.NoError(t, st.SetValidators(validators))
require.NoError(t, st.SetBalances(balances))
comm1, err := helpers.BeaconCommitteeFromState(t.Context(), st, 1 /*slot*/, 0 /*committeeIndex*/)
require.NoError(t, err)
@@ -650,6 +729,7 @@ func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing
require.NoError(t, err)
require.NoError(t, st.SetSlot(5))
require.NoError(t, st.SetValidators(validators))
require.NoError(t, st.SetBalances(balances))
comm1, err := helpers.BeaconCommitteeFromState(t.Context(), st, 1 /*slot*/, 0 /*committeeIndex*/)
require.NoError(t, err)

View File

@@ -14,6 +14,7 @@ go_library(
"transition.go",
"upgrade.go",
"validator.go",
"withdrawals.go",
],
importpath = "github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra",
visibility = ["//visibility:public"],
@@ -41,6 +42,8 @@ go_library(
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_ethereum_go_ethereum//common/math:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],
@@ -60,11 +63,13 @@ go_test(
"transition_test.go",
"upgrade_test.go",
"validator_test.go",
"withdrawals_test.go",
],
data = glob(["testdata/**"]),
embed = [":go_default_library"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/signing:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
@@ -77,12 +82,16 @@ go_test(
"//encoding/bytesutil:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/fuzz:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_google_gofuzz//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
],
)

View File

@@ -3,14 +3,19 @@ package electra
import (
"bytes"
"context"
"fmt"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/ethereum/go-ethereum/common/math"
"github.com/pkg/errors"
)
@@ -90,6 +95,217 @@ func ProcessPendingConsolidations(ctx context.Context, st state.BeaconState) err
return nil
}
// ProcessConsolidationRequests implements the spec definition below. This method makes mutating
// calls to the beacon state.
//
// def process_consolidation_request(
// state: BeaconState,
// consolidation_request: ConsolidationRequest
// ) -> None:
// if is_valid_switch_to_compounding_request(state, consolidation_request):
// validator_pubkeys = [v.pubkey for v in state.validators]
// request_source_pubkey = consolidation_request.source_pubkey
// source_index = ValidatorIndex(validator_pubkeys.index(request_source_pubkey))
// switch_to_compounding_validator(state, source_index)
// return
//
// # Verify that source != target, so a consolidation cannot be used as an exit.
// if consolidation_request.source_pubkey == consolidation_request.target_pubkey:
// return
// # If the pending consolidations queue is full, consolidation requests are ignored
// if len(state.pending_consolidations) == PENDING_CONSOLIDATIONS_LIMIT:
// return
// # If there is too little available consolidation churn limit, consolidation requests are ignored
// if get_consolidation_churn_limit(state) <= MIN_ACTIVATION_BALANCE:
// return
//
// validator_pubkeys = [v.pubkey for v in state.validators]
// # Verify pubkeys exists
// request_source_pubkey = consolidation_request.source_pubkey
// request_target_pubkey = consolidation_request.target_pubkey
// if request_source_pubkey not in validator_pubkeys:
// return
// if request_target_pubkey not in validator_pubkeys:
// return
// source_index = ValidatorIndex(validator_pubkeys.index(request_source_pubkey))
// target_index = ValidatorIndex(validator_pubkeys.index(request_target_pubkey))
// source_validator = state.validators[source_index]
// target_validator = state.validators[target_index]
//
// # Verify source withdrawal credentials
// has_correct_credential = has_execution_withdrawal_credential(source_validator)
// is_correct_source_address = (
// source_validator.withdrawal_credentials[12:] == consolidation_request.source_address
// )
// if not (has_correct_credential and is_correct_source_address):
// return
//
// # Verify that target has compounding withdrawal credentials
// if not has_compounding_withdrawal_credential(target_validator):
// return
//
// # Verify the source and the target are active
// current_epoch = get_current_epoch(state)
// if not is_active_validator(source_validator, current_epoch):
// return
// if not is_active_validator(target_validator, current_epoch):
// return
// # Verify exits for source and target have not been initiated
// if source_validator.exit_epoch != FAR_FUTURE_EPOCH:
// return
// if target_validator.exit_epoch != FAR_FUTURE_EPOCH:
// return
//
// # Verify the source has been active long enough
// if current_epoch < source_validator.activation_epoch + SHARD_COMMITTEE_PERIOD:
// return
//
// # Verify the source has no pending withdrawals in the queue
// if get_pending_balance_to_withdraw(state, source_index) > 0:
// return
// # Initiate source validator exit and append pending consolidation
// source_validator.exit_epoch = compute_consolidation_epoch_and_update_churn(
// state, source_validator.effective_balance
// )
// source_validator.withdrawable_epoch = Epoch(
// source_validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
// )
// state.pending_consolidations.append(PendingConsolidation(
// source_index=source_index,
// target_index=target_index
// ))
func ProcessConsolidationRequests(ctx context.Context, st state.BeaconState, reqs []*enginev1.ConsolidationRequest) error {
if len(reqs) == 0 || st == nil {
return nil
}
curEpoch := slots.ToEpoch(st.Slot())
ffe := params.BeaconConfig().FarFutureEpoch
minValWithdrawDelay := params.BeaconConfig().MinValidatorWithdrawabilityDelay
pcLimit := params.BeaconConfig().PendingConsolidationsLimit
for _, cr := range reqs {
if cr == nil {
return errors.New("nil consolidation request")
}
if ctx.Err() != nil {
return fmt.Errorf("cannot process consolidation requests: %w", ctx.Err())
}
if IsValidSwitchToCompoundingRequest(st, cr) {
srcIdx, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(cr.SourcePubkey))
if !ok {
log.Error("Failed to find source validator index")
continue
}
if err := SwitchToCompoundingValidator(st, srcIdx); err != nil {
log.WithError(err).Error("Failed to switch to compounding validator")
}
continue
}
sourcePubkey := bytesutil.ToBytes48(cr.SourcePubkey)
targetPubkey := bytesutil.ToBytes48(cr.TargetPubkey)
if sourcePubkey == targetPubkey {
continue
}
if npc, err := st.NumPendingConsolidations(); err != nil {
return fmt.Errorf("failed to fetch number of pending consolidations: %w", err) // This should never happen.
} else if npc >= pcLimit {
continue
}
activeBal, err := helpers.TotalActiveBalance(st)
if err != nil {
return err
}
churnLimit := helpers.ConsolidationChurnLimit(primitives.Gwei(activeBal))
if churnLimit <= primitives.Gwei(params.BeaconConfig().MinActivationBalance) {
continue
}
srcIdx, ok := st.ValidatorIndexByPubkey(sourcePubkey)
if !ok {
continue
}
tgtIdx, ok := st.ValidatorIndexByPubkey(targetPubkey)
if !ok {
continue
}
srcV, err := st.ValidatorAtIndex(srcIdx)
if err != nil {
return fmt.Errorf("failed to fetch source validator: %w", err) // This should never happen.
}
roSrcV, err := state_native.NewValidator(srcV)
if err != nil {
return err
}
tgtV, err := st.ValidatorAtIndexReadOnly(tgtIdx)
if err != nil {
return fmt.Errorf("failed to fetch target validator: %w", err) // This should never happen.
}
// Verify source withdrawal credentials
if !roSrcV.HasExecutionWithdrawalCredentials() {
continue
}
// Confirm source_validator.withdrawal_credentials[12:] == consolidation_request.source_address
if len(srcV.WithdrawalCredentials) != 32 || len(cr.SourceAddress) != 20 || !bytes.HasSuffix(srcV.WithdrawalCredentials, cr.SourceAddress) {
continue
}
// Target validator must have their withdrawal credentials set appropriately.
if !tgtV.HasCompoundingWithdrawalCredentials() {
continue
}
// Both validators must be active.
if !helpers.IsActiveValidator(srcV, curEpoch) || !helpers.IsActiveValidatorUsingTrie(tgtV, curEpoch) {
continue
}
// Neither validator is exiting.
if srcV.ExitEpoch != ffe || tgtV.ExitEpoch() != ffe {
continue
}
e, overflow := math.SafeAdd(uint64(srcV.ActivationEpoch), uint64(params.BeaconConfig().ShardCommitteePeriod))
if overflow {
log.Error("Overflow when adding activation epoch and shard committee period")
continue
}
if uint64(curEpoch) < e {
continue
}
hasBal, err := st.HasPendingBalanceToWithdraw(srcIdx)
if err != nil {
log.WithError(err).Error("Failed to fetch pending balance to withdraw")
continue
}
if hasBal {
continue
}
// Initiate the exit of the source validator.
exitEpoch, err := ComputeConsolidationEpochAndUpdateChurn(ctx, st, primitives.Gwei(srcV.EffectiveBalance))
if err != nil {
log.WithError(err).Error("Failed to compute consolidation epoch")
continue
}
srcV.ExitEpoch = exitEpoch
srcV.WithdrawableEpoch = exitEpoch + minValWithdrawDelay
if err := st.UpdateValidatorAtIndex(srcIdx, srcV); err != nil {
return fmt.Errorf("failed to update validator: %w", err) // This should never happen.
}
if err := st.AppendPendingConsolidation(&eth.PendingConsolidation{SourceIndex: srcIdx, TargetIndex: tgtIdx}); err != nil {
return fmt.Errorf("failed to append pending consolidation: %w", err) // This should never happen.
}
}
return nil
}
// IsValidSwitchToCompoundingRequest returns true if the given consolidation request is valid for switching to compounding.
//
// Spec code:

View File

@@ -8,6 +8,8 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
@@ -201,6 +203,275 @@ func TestProcessPendingConsolidations(t *testing.T) {
}
}
func TestProcessConsolidationRequests(t *testing.T) {
tests := []struct {
name string
state state.BeaconState
reqs []*enginev1.ConsolidationRequest
validate func(*testing.T, state.BeaconState)
wantErr bool
}{
{
name: "nil request",
state: func() state.BeaconState {
st := &eth.BeaconStateElectra{}
s, err := state_native.InitializeFromProtoElectra(st)
require.NoError(t, err)
return s
}(),
reqs: []*enginev1.ConsolidationRequest{nil},
validate: func(t *testing.T, st state.BeaconState) {
require.DeepEqual(t, st, st)
},
wantErr: true,
},
{
name: "one valid request",
state: func() state.BeaconState {
st := &eth.BeaconStateElectra{
Slot: params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().ShardCommitteePeriod)),
Validators: createValidatorsWithTotalActiveBalance(32000000000000000), // 32M ETH
}
// Validator scenario setup. See comments in reqs section.
st.Validators[3].WithdrawalCredentials = bytesutil.Bytes32(0)
st.Validators[8].WithdrawalCredentials = bytesutil.Bytes32(1)
st.Validators[9].ActivationEpoch = params.BeaconConfig().FarFutureEpoch
st.Validators[12].ActivationEpoch = params.BeaconConfig().FarFutureEpoch
st.Validators[13].ExitEpoch = 10
st.Validators[16].ExitEpoch = 10
st.PendingPartialWithdrawals = []*eth.PendingPartialWithdrawal{
{
Index: 17,
Amount: 100,
},
}
s, err := state_native.InitializeFromProtoElectra(st)
require.NoError(t, err)
return s
}(),
reqs: []*enginev1.ConsolidationRequest{
// Source doesn't have withdrawal credentials.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(1)),
SourcePubkey: []byte("val_3"),
TargetPubkey: []byte("val_4"),
},
// Source withdrawal credentials don't match the consolidation address.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(0)), // Should be 5
SourcePubkey: []byte("val_5"),
TargetPubkey: []byte("val_6"),
},
// Target does not have their withdrawal credentials set appropriately. (Using eth1 address prefix)
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(7)),
SourcePubkey: []byte("val_7"),
TargetPubkey: []byte("val_8"),
},
// Source is inactive.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(9)),
SourcePubkey: []byte("val_9"),
TargetPubkey: []byte("val_10"),
},
// Target is inactive.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(11)),
SourcePubkey: []byte("val_11"),
TargetPubkey: []byte("val_12"),
},
// Source is exiting.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(13)),
SourcePubkey: []byte("val_13"),
TargetPubkey: []byte("val_14"),
},
// Target is exiting.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(15)),
SourcePubkey: []byte("val_15"),
TargetPubkey: []byte("val_16"),
},
// Source doesn't exist
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(0)),
SourcePubkey: []byte("INVALID"),
TargetPubkey: []byte("val_0"),
},
// Target doesn't exist
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(0)),
SourcePubkey: []byte("val_0"),
TargetPubkey: []byte("INVALID"),
},
// Source == target
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(0)),
SourcePubkey: []byte("val_0"),
TargetPubkey: []byte("val_0"),
},
// Has pending partial withdrawal
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(0)),
SourcePubkey: []byte("val_17"),
TargetPubkey: []byte("val_1"),
},
// Valid consolidation request. This should be last to ensure invalid requests do
// not end the processing early.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(1)),
SourcePubkey: []byte("val_1"),
TargetPubkey: []byte("val_2"),
},
},
validate: func(t *testing.T, st state.BeaconState) {
// Verify a pending consolidation is created.
numPC, err := st.NumPendingConsolidations()
require.NoError(t, err)
require.Equal(t, uint64(1), numPC)
pcs, err := st.PendingConsolidations()
require.NoError(t, err)
require.Equal(t, primitives.ValidatorIndex(1), pcs[0].SourceIndex)
require.Equal(t, primitives.ValidatorIndex(2), pcs[0].TargetIndex)
// Verify the source validator is exiting.
src, err := st.ValidatorAtIndex(1)
require.NoError(t, err)
require.NotEqual(t, params.BeaconConfig().FarFutureEpoch, src.ExitEpoch, "source validator exit epoch not updated")
require.Equal(t, params.BeaconConfig().MinValidatorWithdrawabilityDelay, src.WithdrawableEpoch-src.ExitEpoch, "source validator withdrawable epoch not set correctly")
},
},
{
name: "pending consolidations limit reached",
state: func() state.BeaconState {
st := &eth.BeaconStateElectra{
Validators: createValidatorsWithTotalActiveBalance(32000000000000000), // 32M ETH
PendingConsolidations: make([]*eth.PendingConsolidation, params.BeaconConfig().PendingConsolidationsLimit),
}
s, err := state_native.InitializeFromProtoElectra(st)
require.NoError(t, err)
return s
}(),
reqs: []*enginev1.ConsolidationRequest{
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(1)),
SourcePubkey: []byte("val_1"),
TargetPubkey: []byte("val_2"),
},
},
validate: func(t *testing.T, st state.BeaconState) {
// Verify no pending consolidation is created.
numPC, err := st.NumPendingConsolidations()
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().PendingConsolidationsLimit, numPC)
// Verify the source validator is not exiting.
src, err := st.ValidatorAtIndex(1)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().FarFutureEpoch, src.ExitEpoch, "source validator exit epoch should not be updated")
require.Equal(t, params.BeaconConfig().FarFutureEpoch, src.WithdrawableEpoch, "source validator withdrawable epoch should not be updated")
},
},
{
name: "pending consolidations limit reached during processing",
state: func() state.BeaconState {
st := &eth.BeaconStateElectra{
Slot: params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().ShardCommitteePeriod)),
Validators: createValidatorsWithTotalActiveBalance(32000000000000000), // 32M ETH
PendingConsolidations: make([]*eth.PendingConsolidation, params.BeaconConfig().PendingConsolidationsLimit-1),
}
s, err := state_native.InitializeFromProtoElectra(st)
require.NoError(t, err)
return s
}(),
reqs: []*enginev1.ConsolidationRequest{
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(1)),
SourcePubkey: []byte("val_1"),
TargetPubkey: []byte("val_2"),
},
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(3)),
SourcePubkey: []byte("val_3"),
TargetPubkey: []byte("val_4"),
},
},
validate: func(t *testing.T, st state.BeaconState) {
// Verify a pending consolidation is created.
numPC, err := st.NumPendingConsolidations()
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().PendingConsolidationsLimit, numPC)
// The first consolidation was appended.
pcs, err := st.PendingConsolidations()
require.NoError(t, err)
require.Equal(t, primitives.ValidatorIndex(1), pcs[params.BeaconConfig().PendingConsolidationsLimit-1].SourceIndex)
require.Equal(t, primitives.ValidatorIndex(2), pcs[params.BeaconConfig().PendingConsolidationsLimit-1].TargetIndex)
// Verify the second source validator is not exiting.
src, err := st.ValidatorAtIndex(3)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().FarFutureEpoch, src.ExitEpoch, "source validator exit epoch should not be updated")
require.Equal(t, params.BeaconConfig().FarFutureEpoch, src.WithdrawableEpoch, "source validator withdrawable epoch should not be updated")
},
},
{
name: "pending consolidations limit reached and compounded consolidation after",
state: func() state.BeaconState {
st := &eth.BeaconStateElectra{
Slot: params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().ShardCommitteePeriod)),
Validators: createValidatorsWithTotalActiveBalance(32000000000000000), // 32M ETH
PendingConsolidations: make([]*eth.PendingConsolidation, params.BeaconConfig().PendingConsolidationsLimit),
}
// To allow compounding consolidation requests.
st.Validators[3].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
s, err := state_native.InitializeFromProtoElectra(st)
require.NoError(t, err)
return s
}(),
reqs: []*enginev1.ConsolidationRequest{
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(1)),
SourcePubkey: []byte("val_1"),
TargetPubkey: []byte("val_2"),
},
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(3)),
SourcePubkey: []byte("val_3"),
TargetPubkey: []byte("val_3"),
},
},
validate: func(t *testing.T, st state.BeaconState) {
// Verify a pending consolidation is created.
numPC, err := st.NumPendingConsolidations()
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().PendingConsolidationsLimit, numPC)
// Verify that the last consolidation was included
src, err := st.ValidatorAtIndex(3)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().CompoundingWithdrawalPrefixByte, src.WithdrawalCredentials[0], "source validator was not compounded")
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := electra.ProcessConsolidationRequests(context.TODO(), tt.state, tt.reqs)
if (err != nil) != tt.wantErr {
t.Errorf("ProcessWithdrawalRequests() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
require.NoError(t, err)
}
if tt.validate != nil {
tt.validate(t, tt.state)
}
})
}
}
func TestIsValidSwitchToCompoundingRequest(t *testing.T) {
st, _ := util.DeterministicGenesisStateElectra(t, 1)
t.Run("nil source pubkey", func(t *testing.T) {

View File

@@ -12,6 +12,7 @@ import (
"github.com/OffchainLabs/prysm/v7/contracts/deposit"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/OffchainLabs/prysm/v7/time/slots"
@@ -535,3 +536,62 @@ func GetValidatorFromDeposit(pubKey []byte, withdrawalCredentials []byte, amount
validator.EffectiveBalance = min(amount-(amount%params.BeaconConfig().EffectiveBalanceIncrement), maxEffectiveBalance)
return validator, nil
}
// ProcessDepositRequests is a function as part of electra to process execution layer deposits
func ProcessDepositRequests(ctx context.Context, beaconState state.BeaconState, requests []*enginev1.DepositRequest) (state.BeaconState, error) {
_, span := trace.StartSpan(ctx, "electra.ProcessDepositRequests")
defer span.End()
if len(requests) == 0 {
return beaconState, nil
}
var err error
for _, receipt := range requests {
beaconState, err = processDepositRequest(beaconState, receipt)
if err != nil {
return nil, errors.Wrap(err, "could not apply deposit request")
}
}
return beaconState, nil
}
// processDepositRequest processes the specific deposit request
// def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None:
//
// # Set deposit request start index
// if state.deposit_requests_start_index == UNSET_DEPOSIT_REQUESTS_START_INDEX:
// state.deposit_requests_start_index = deposit_request.index
//
// # Create pending deposit
// state.pending_deposits.append(PendingDeposit(
// pubkey=deposit_request.pubkey,
// withdrawal_credentials=deposit_request.withdrawal_credentials,
// amount=deposit_request.amount,
// signature=deposit_request.signature,
// slot=state.slot,
// ))
func processDepositRequest(beaconState state.BeaconState, request *enginev1.DepositRequest) (state.BeaconState, error) {
requestsStartIndex, err := beaconState.DepositRequestsStartIndex()
if err != nil {
return nil, errors.Wrap(err, "could not get deposit requests start index")
}
if request == nil {
return nil, errors.New("nil deposit request")
}
if requestsStartIndex == params.BeaconConfig().UnsetDepositRequestsStartIndex {
if err := beaconState.SetDepositRequestsStartIndex(request.Index); err != nil {
return nil, errors.Wrap(err, "could not set deposit requests start index")
}
}
if err := beaconState.AppendPendingDeposit(&ethpb.PendingDeposit{
PublicKey: bytesutil.SafeCopyBytes(request.Pubkey),
WithdrawalCredentials: bytesutil.SafeCopyBytes(request.WithdrawalCredentials),
Amount: request.Amount,
Signature: bytesutil.SafeCopyBytes(request.Signature),
Slot: beaconState.Slot(),
}); err != nil {
return nil, errors.Wrap(err, "could not append deposit request")
}
return beaconState, nil
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra"
"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"
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
stateTesting "github.com/OffchainLabs/prysm/v7/beacon-chain/state/testing"
@@ -14,6 +15,7 @@ import (
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/crypto/bls"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/testing/util"
@@ -359,6 +361,60 @@ func TestBatchProcessNewPendingDeposits(t *testing.T) {
})
}
func TestProcessDepositRequests(t *testing.T) {
st, _ := util.DeterministicGenesisStateElectra(t, 1)
sk, err := bls.RandKey()
require.NoError(t, err)
require.NoError(t, st.SetDepositRequestsStartIndex(1))
t.Run("empty requests continues", func(t *testing.T) {
newSt, err := electra.ProcessDepositRequests(t.Context(), st, []*enginev1.DepositRequest{})
require.NoError(t, err)
require.DeepEqual(t, newSt, st)
})
t.Run("nil request errors", func(t *testing.T) {
_, err = electra.ProcessDepositRequests(t.Context(), st, []*enginev1.DepositRequest{nil})
require.ErrorContains(t, "nil deposit request", err)
})
vals := st.Validators()
vals[0].PublicKey = sk.PublicKey().Marshal()
vals[0].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
require.NoError(t, st.SetValidators(vals))
bals := st.Balances()
bals[0] = params.BeaconConfig().MinActivationBalance + 2000
require.NoError(t, st.SetBalances(bals))
require.NoError(t, st.SetPendingDeposits(make([]*eth.PendingDeposit, 0))) // reset pbd as the determinitstic state populates this already
withdrawalCred := make([]byte, 32)
withdrawalCred[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
depositMessage := &eth.DepositMessage{
PublicKey: sk.PublicKey().Marshal(),
Amount: 1000,
WithdrawalCredentials: withdrawalCred,
}
domain, err := signing.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
require.NoError(t, err)
sr, err := signing.ComputeSigningRoot(depositMessage, domain)
require.NoError(t, err)
sig := sk.Sign(sr[:])
requests := []*enginev1.DepositRequest{
{
Pubkey: depositMessage.PublicKey,
Index: 0,
WithdrawalCredentials: depositMessage.WithdrawalCredentials,
Amount: depositMessage.Amount,
Signature: sig.Marshal(),
},
}
st, err = electra.ProcessDepositRequests(t.Context(), st, requests)
require.NoError(t, err)
pbd, err := st.PendingDeposits()
require.NoError(t, err)
require.Equal(t, 1, len(pbd))
require.Equal(t, uint64(1000), pbd[0].Amount)
}
func TestProcessDeposit_Electra_Simple(t *testing.T) {
deps, _, err := util.DeterministicDepositsAndKeysSameValidator(3)
require.NoError(t, err)

View File

@@ -1,4 +1,4 @@
package requests
package electra
import (
"bytes"
@@ -88,7 +88,7 @@ import (
// withdrawable_epoch=withdrawable_epoch,
// ))
func ProcessWithdrawalRequests(ctx context.Context, st state.BeaconState, wrs []*enginev1.WithdrawalRequest) (state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "requests.ProcessWithdrawalRequests")
ctx, span := trace.StartSpan(ctx, "electra.ProcessWithdrawalRequests")
defer span.End()
currentEpoch := slots.ToEpoch(st.Slot())
if len(wrs) == 0 {

View File

@@ -1,9 +1,9 @@
package requests_test
package electra_test
import (
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/requests"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
@@ -289,7 +289,7 @@ func TestProcessWithdrawRequests(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := requests.ProcessWithdrawalRequests(t.Context(), tt.args.st, tt.args.wrs)
got, err := electra.ProcessWithdrawalRequests(t.Context(), tt.args.st, tt.args.wrs)
if (err != nil) != tt.wantErr {
t.Errorf("ProcessWithdrawalRequests() error = %v, wantErr %v", err, tt.wantErr)
return

View File

@@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"attestation.go",
"bid.go",
"pending_payment.go",
"proposer_slashing.go",
@@ -21,6 +22,7 @@ go_library(
"//crypto/bls:go_default_library",
"//crypto/bls/common:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
@@ -29,6 +31,7 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"attestation_test.go",
"bid_test.go",
"pending_payment_test.go",
"proposer_slashing_test.go",

View File

@@ -0,0 +1,153 @@
package gloas
import (
"bytes"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/pkg/errors"
)
// SameSlotAttestation checks if the attestation is for the same slot as the block root in the state.
// Spec v1.7.0-alpha pseudocode:
//
// is_attestation_same_slot(state, data):
// if data.slot == 0:
// return True
//
// blockroot = data.beacon_block_root
// slot_blockroot = get_block_root_at_slot(state, data.slot)
// prev_blockroot = get_block_root_at_slot(state, Slot(data.slot - 1))
//
// return blockroot == slot_blockroot and blockroot != prev_blockroot
func SameSlotAttestation(state state.ReadOnlyBeaconState, blockRoot [32]byte, slot primitives.Slot) (bool, error) {
if slot == 0 {
return true, nil
}
blockRootAtSlot, err := helpers.BlockRootAtSlot(state, slot)
if err != nil {
return false, errors.Wrapf(err, "block root at slot %d", slot)
}
matchingBlockRoot := bytes.Equal(blockRoot[:], blockRootAtSlot)
blockRootAtPrevSlot, err := helpers.BlockRootAtSlot(state, slot-1)
if err != nil {
return false, errors.Wrapf(err, "block root at slot %d", slot-1)
}
matchingPrevBlockRoot := bytes.Equal(blockRoot[:], blockRootAtPrevSlot)
return matchingBlockRoot && !matchingPrevBlockRoot, nil
}
// UpdatePendingPaymentWeight updates the builder pending payment weight based on attestation participation.
// Spec v1.7.0-alpha pseudocode:
//
// if data.target.epoch == get_current_epoch(state):
// current_epoch_target = True
// epoch_participation = state.current_epoch_participation
// payment = state.builder_pending_payments[SLOTS_PER_EPOCH + data.slot % SLOTS_PER_EPOCH]
// else:
// current_epoch_target = False
// epoch_participation = state.previous_epoch_participation
// payment = state.builder_pending_payments[data.slot % SLOTS_PER_EPOCH]
//
// proposer_reward_numerator = 0
// for index in get_attesting_indices(state, attestation):
// will_set_new_flag = False
// for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
// if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index):
// epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
// proposer_reward_numerator += get_base_reward(state, index) * weight
// # [New in Gloas:EIP7732]
// will_set_new_flag = True
// if (
// will_set_new_flag
// and is_attestation_same_slot(state, data)
// and payment.withdrawal.amount > 0
// ):
// payment.weight += state.validators[index].effective_balance
// if current_epoch_target:
// state.builder_pending_payments[SLOTS_PER_EPOCH + data.slot % SLOTS_PER_EPOCH] = payment
// else:
// state.builder_pending_payments[data.slot % SLOTS_PER_EPOCH] = payment
func UpdatePendingPaymentWeight(beaconState state.BeaconState, att ethpb.Att, indices []uint64, participatedFlags map[uint8]bool) (state.BeaconState, error) {
if beaconState.Version() < version.Gloas {
return beaconState, nil
}
data := att.GetData()
epoch := slots.ToEpoch(beaconState.Slot())
isSameSlot, err := SameSlotAttestation(beaconState, [32]byte(data.BeaconBlockRoot), data.Slot)
if err != nil {
return nil, errors.Wrap(err, "check same-slot attestation")
}
if !isSameSlot {
return beaconState, nil
}
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
var (
paymentSlot primitives.Slot
payment *ethpb.BuilderPendingPayment
epochParticipation []byte
)
if data.Target.Epoch == epoch {
paymentSlot = slotsPerEpoch + (data.Slot % slotsPerEpoch)
payment, err = beaconState.BuilderPendingPayment(uint64(paymentSlot))
if err != nil {
return nil, errors.Wrapf(err, "get builder pending payment at slot %d", paymentSlot)
}
epochParticipation, err = beaconState.CurrentEpochParticipation()
if err != nil {
return nil, errors.Wrap(err, "get current epoch participation")
}
} else {
paymentSlot = data.Slot % slotsPerEpoch
payment, err = beaconState.BuilderPendingPayment(uint64(paymentSlot))
if err != nil {
return nil, errors.Wrapf(err, "get builder pending payment at slot %d", paymentSlot)
}
epochParticipation, err = beaconState.PreviousEpochParticipation()
if err != nil {
return nil, errors.Wrap(err, "get previous epoch participation")
}
}
if payment.Withdrawal.Amount == 0 {
return beaconState, nil
}
cfg := params.BeaconConfig()
flagIndices := []uint8{cfg.TimelySourceFlagIndex, cfg.TimelyTargetFlagIndex, cfg.TimelyHeadFlagIndex}
for _, idx := range indices {
if idx >= uint64(len(epochParticipation)) {
return nil, errors.Errorf("index %d exceeds participation length %d", idx, len(epochParticipation))
}
participation := epochParticipation[idx]
for _, f := range flagIndices {
if !participatedFlags[f] {
continue
}
if participation&(1<<f) == 0 {
validator, err := beaconState.ValidatorAtIndex(primitives.ValidatorIndex(idx))
if err != nil {
return nil, errors.Wrapf(err, "validator at index %d", idx)
}
payment.Weight += primitives.Gwei(validator.EffectiveBalance)
break
}
}
}
if err := beaconState.SetBuilderPendingPayment(paymentSlot, payment); err != nil {
return nil, errors.Wrapf(err, "set builder pending payment at slot %d", paymentSlot)
}
return beaconState, nil
}

View File

@@ -0,0 +1,286 @@
package gloas
import (
"bytes"
"testing"
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/time/slots"
)
func buildStateWithBlockRoots(t *testing.T, stateSlot primitives.Slot, roots map[primitives.Slot][]byte) *state_native.BeaconState {
t.Helper()
cfg := params.BeaconConfig()
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
for slot, root := range roots {
blockRoots[slot%cfg.SlotsPerHistoricalRoot] = root
}
stateRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
for i := range stateRoots {
stateRoots[i] = bytes.Repeat([]byte{0x11}, 32)
}
randaoMixes := make([][]byte, cfg.EpochsPerHistoricalVector)
for i := range randaoMixes {
randaoMixes[i] = bytes.Repeat([]byte{0x22}, 32)
}
execPayloadAvailability := make([]byte, cfg.SlotsPerHistoricalRoot/8)
stProto := &ethpb.BeaconStateGloas{
Slot: stateSlot,
GenesisValidatorsRoot: bytes.Repeat([]byte{0x33}, 32),
Fork: &ethpb.Fork{
CurrentVersion: bytes.Repeat([]byte{0x44}, 4),
PreviousVersion: bytes.Repeat([]byte{0x44}, 4),
Epoch: 0,
},
BlockRoots: blockRoots,
StateRoots: stateRoots,
RandaoMixes: randaoMixes,
ExecutionPayloadAvailability: execPayloadAvailability,
Validators: []*ethpb.Validator{},
Balances: []uint64{},
BuilderPendingPayments: make([]*ethpb.BuilderPendingPayment, cfg.SlotsPerEpoch*2),
BuilderPendingWithdrawals: []*ethpb.BuilderPendingWithdrawal{},
}
state, err := state_native.InitializeFromProtoGloas(stProto)
require.NoError(t, err)
return state.(*state_native.BeaconState)
}
func TestSameSlotAttestation(t *testing.T) {
rootA := bytes.Repeat([]byte{0xAA}, 32)
rootB := bytes.Repeat([]byte{0xBB}, 32)
rootC := bytes.Repeat([]byte{0xCC}, 32)
tests := []struct {
name string
stateSlot primitives.Slot
slot primitives.Slot
blockRoot []byte
roots map[primitives.Slot][]byte
want bool
}{
{
name: "slot zero always true",
stateSlot: 1,
slot: 0,
blockRoot: rootA,
roots: map[primitives.Slot][]byte{},
want: true,
},
{
name: "matching current different previous",
stateSlot: 6,
slot: 4,
blockRoot: rootA,
roots: map[primitives.Slot][]byte{
4: rootA,
3: rootB,
},
want: true,
},
{
name: "matching current same previous",
stateSlot: 6,
slot: 4,
blockRoot: rootA,
roots: map[primitives.Slot][]byte{
4: rootA,
3: rootA,
},
want: false,
},
{
name: "non matching current",
stateSlot: 6,
slot: 4,
blockRoot: rootC,
roots: map[primitives.Slot][]byte{
4: rootA,
3: rootB,
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
state := buildStateWithBlockRoots(t, tt.stateSlot, tt.roots)
var rootArr [32]byte
copy(rootArr[:], tt.blockRoot)
got, err := SameSlotAttestation(state, rootArr, tt.slot)
require.NoError(t, err)
require.Equal(t, tt.want, got)
})
}
}
func buildStateForPaymentTest(t *testing.T, stateSlot primitives.Slot, paymentIdx int, amount primitives.Gwei, weight primitives.Gwei, roots map[primitives.Slot][]byte) *state_native.BeaconState {
t.Helper()
cfg := params.BeaconConfig()
blockRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
for slot, root := range roots {
blockRoots[slot%cfg.SlotsPerHistoricalRoot] = root
}
stateRoots := make([][]byte, cfg.SlotsPerHistoricalRoot)
for i := range stateRoots {
stateRoots[i] = bytes.Repeat([]byte{0x44}, 32)
}
randaoMixes := make([][]byte, cfg.EpochsPerHistoricalVector)
for i := range randaoMixes {
randaoMixes[i] = bytes.Repeat([]byte{0x55}, 32)
}
validator := &ethpb.Validator{
PublicKey: bytes.Repeat([]byte{0x01}, 48),
WithdrawalCredentials: append([]byte{cfg.ETH1AddressWithdrawalPrefixByte}, bytes.Repeat([]byte{0x02}, 31)...),
EffectiveBalance: cfg.MinActivationBalance,
}
payments := make([]*ethpb.BuilderPendingPayment, cfg.SlotsPerEpoch*2)
for i := range payments {
payments[i] = &ethpb.BuilderPendingPayment{
Withdrawal: &ethpb.BuilderPendingWithdrawal{
FeeRecipient: make([]byte, 20),
},
}
}
payments[paymentIdx] = &ethpb.BuilderPendingPayment{
Weight: weight,
Withdrawal: &ethpb.BuilderPendingWithdrawal{
FeeRecipient: make([]byte, 20),
Amount: amount,
},
}
execPayloadAvailability := make([]byte, cfg.SlotsPerHistoricalRoot/8)
stProto := &ethpb.BeaconStateGloas{
Slot: stateSlot,
GenesisValidatorsRoot: bytes.Repeat([]byte{0x33}, 32),
BlockRoots: blockRoots,
StateRoots: stateRoots,
RandaoMixes: randaoMixes,
ExecutionPayloadAvailability: execPayloadAvailability,
Validators: []*ethpb.Validator{validator},
Balances: []uint64{cfg.MinActivationBalance},
CurrentEpochParticipation: []byte{0},
PreviousEpochParticipation: []byte{0},
BuilderPendingPayments: payments,
Fork: &ethpb.Fork{
CurrentVersion: bytes.Repeat([]byte{0x66}, 4),
PreviousVersion: bytes.Repeat([]byte{0x66}, 4),
Epoch: 0,
},
}
state, err := state_native.InitializeFromProtoGloas(stProto)
require.NoError(t, err)
return state.(*state_native.BeaconState)
}
func TestUpdatePendingPaymentWeight(t *testing.T) {
cfg := params.BeaconConfig()
slotsPerEpoch := cfg.SlotsPerEpoch
slot := primitives.Slot(4)
stateSlot := slot + 1
currentEpoch := slots.ToEpoch(stateSlot)
rootA := bytes.Repeat([]byte{0xAA}, 32)
rootB := bytes.Repeat([]byte{0xBB}, 32)
tests := []struct {
name string
targetEpoch primitives.Epoch
blockRoot []byte
initialAmount primitives.Gwei
initialWeight primitives.Gwei
wantWeight primitives.Gwei
}{
{
name: "same slot current epoch adds weight",
targetEpoch: currentEpoch,
blockRoot: rootA,
initialAmount: 10,
initialWeight: 0,
wantWeight: primitives.Gwei(cfg.MinActivationBalance),
},
{
name: "same slot zero amount no weight change",
targetEpoch: currentEpoch,
blockRoot: rootA,
initialAmount: 0,
initialWeight: 5,
wantWeight: 5,
},
{
name: "non matching block root no change",
targetEpoch: currentEpoch,
blockRoot: rootB,
initialAmount: 10,
initialWeight: 7,
wantWeight: 7,
},
{
name: "previous epoch target uses earlier slot",
targetEpoch: currentEpoch - 1,
blockRoot: rootA,
initialAmount: 20,
initialWeight: 0,
wantWeight: primitives.Gwei(cfg.MinActivationBalance),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var paymentIdx int
if tt.targetEpoch == currentEpoch {
paymentIdx = int(slotsPerEpoch + (slot % slotsPerEpoch))
} else {
paymentIdx = int(slot % slotsPerEpoch)
}
state := buildStateForPaymentTest(t, stateSlot, paymentIdx, tt.initialAmount, tt.initialWeight, map[primitives.Slot][]byte{
slot: tt.blockRoot,
slot - 1: rootB,
})
att := &ethpb.Attestation{
Data: &ethpb.AttestationData{
Slot: slot,
CommitteeIndex: 0,
BeaconBlockRoot: tt.blockRoot,
Source: &ethpb.Checkpoint{},
Target: &ethpb.Checkpoint{
Epoch: tt.targetEpoch,
},
},
}
participatedFlags := map[uint8]bool{
cfg.TimelySourceFlagIndex: true,
cfg.TimelyTargetFlagIndex: true,
cfg.TimelyHeadFlagIndex: true,
}
indices := []uint64{0}
gotState, err := UpdatePendingPaymentWeight(state, att, indices, participatedFlags)
require.NoError(t, err)
payment, err := gotState.BuilderPendingPayment(uint64(paymentIdx))
require.NoError(t, err)
require.Equal(t, tt.wantWeight, payment.Weight)
})
}
}

View File

@@ -1,60 +0,0 @@
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"consolidations.go",
"deposits.go",
"log.go",
"withdrawals.go",
],
importpath = "github.com/OffchainLabs/prysm/v7/beacon-chain/core/requests",
visibility = ["//visibility:public"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/validators:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/bls/common:go_default_library",
"//encoding/bytesutil:go_default_library",
"//math:go_default_library",
"//monitoring/tracing/trace:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/version:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_ethereum_go_ethereum//common/math:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"consolidations_test.go",
"deposits_test.go",
"withdrawals_test.go",
],
deps = [
":go_default_library",
"//beacon-chain/core/signing:go_default_library",
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
],
)

View File

@@ -1,365 +0,0 @@
package requests
import (
"bytes"
"context"
"fmt"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/crypto/bls/common"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
prysmMath "github.com/OffchainLabs/prysm/v7/math"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/ethereum/go-ethereum/common/math"
"github.com/pkg/errors"
)
// ProcessConsolidationRequests implements the spec definition below. This method makes mutating
// calls to the beacon state.
//
// def process_consolidation_request(
// state: BeaconState,
// consolidation_request: ConsolidationRequest
// ) -> None:
// if is_valid_switch_to_compounding_request(state, consolidation_request):
// validator_pubkeys = [v.pubkey for v in state.validators]
// request_source_pubkey = consolidation_request.source_pubkey
// source_index = ValidatorIndex(validator_pubkeys.index(request_source_pubkey))
// switch_to_compounding_validator(state, source_index)
// return
//
// # Verify that source != target, so a consolidation cannot be used as an exit.
// if consolidation_request.source_pubkey == consolidation_request.target_pubkey:
// return
// # If the pending consolidations queue is full, consolidation requests are ignored
// if len(state.pending_consolidations) == PENDING_CONSOLIDATIONS_LIMIT:
// return
// # If there is too little available consolidation churn limit, consolidation requests are ignored
// if get_consolidation_churn_limit(state) <= MIN_ACTIVATION_BALANCE:
// return
//
// validator_pubkeys = [v.pubkey for v in state.validators]
// # Verify pubkeys exists
// request_source_pubkey = consolidation_request.source_pubkey
// request_target_pubkey = consolidation_request.target_pubkey
// if request_source_pubkey not in validator_pubkeys:
// return
// if request_target_pubkey not in validator_pubkeys:
// return
// source_index = ValidatorIndex(validator_pubkeys.index(request_source_pubkey))
// target_index = ValidatorIndex(validator_pubkeys.index(request_target_pubkey))
// source_validator = state.validators[source_index]
// target_validator = state.validators[target_index]
//
// # Verify source withdrawal credentials
// has_correct_credential = has_execution_withdrawal_credential(source_validator)
// is_correct_source_address = (
// source_validator.withdrawal_credentials[12:] == consolidation_request.source_address
// )
// if not (has_correct_credential and is_correct_source_address):
// return
//
// # Verify that target has compounding withdrawal credentials
// if not has_compounding_withdrawal_credential(target_validator):
// return
//
// # Verify the source and the target are active
// current_epoch = get_current_epoch(state)
// if not is_active_validator(source_validator, current_epoch):
// return
// if not is_active_validator(target_validator, current_epoch):
// return
// # Verify exits for source and target have not been initiated
// if source_validator.exit_epoch != FAR_FUTURE_EPOCH:
// return
// if target_validator.exit_epoch != FAR_FUTURE_EPOCH:
// return
//
// # Verify the source has been active long enough
// if current_epoch < source_validator.activation_epoch + SHARD_COMMITTEE_PERIOD:
// return
//
// # Verify the source has no pending withdrawals in the queue
// if get_pending_balance_to_withdraw(state, source_index) > 0:
// return
// # Initiate source validator exit and append pending consolidation
// source_validator.exit_epoch = compute_consolidation_epoch_and_update_churn(
// state, source_validator.effective_balance
// )
// source_validator.withdrawable_epoch = Epoch(
// source_validator.exit_epoch + MIN_VALIDATOR_WITHDRAWABILITY_DELAY
// )
// state.pending_consolidations.append(PendingConsolidation(
// source_index=source_index,
// target_index=target_index
// ))
func ProcessConsolidationRequests(ctx context.Context, st state.BeaconState, reqs []*enginev1.ConsolidationRequest) error {
ctx, span := trace.StartSpan(ctx, "requests.ProcessConsolidationRequests")
defer span.End()
if len(reqs) == 0 || st == nil {
return nil
}
curEpoch := slots.ToEpoch(st.Slot())
ffe := params.BeaconConfig().FarFutureEpoch
minValWithdrawDelay := params.BeaconConfig().MinValidatorWithdrawabilityDelay
pcLimit := params.BeaconConfig().PendingConsolidationsLimit
for _, cr := range reqs {
if cr == nil {
return errors.New("nil consolidation request")
}
if ctx.Err() != nil {
return fmt.Errorf("cannot process consolidation requests: %w", ctx.Err())
}
if isValidSwitchToCompoundingRequest(st, cr) {
srcIdx, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(cr.SourcePubkey))
if !ok {
log.Error("Failed to find source validator index")
continue
}
if err := switchToCompoundingValidator(st, srcIdx); err != nil {
log.WithError(err).Error("Failed to switch to compounding validator")
}
continue
}
sourcePubkey := bytesutil.ToBytes48(cr.SourcePubkey)
targetPubkey := bytesutil.ToBytes48(cr.TargetPubkey)
if sourcePubkey == targetPubkey {
continue
}
if npc, err := st.NumPendingConsolidations(); err != nil {
return fmt.Errorf("failed to fetch number of pending consolidations: %w", err) // This should never happen.
} else if npc >= pcLimit {
continue
}
activeBal, err := helpers.TotalActiveBalance(st)
if err != nil {
return err
}
churnLimit := helpers.ConsolidationChurnLimit(primitives.Gwei(activeBal))
if churnLimit <= primitives.Gwei(params.BeaconConfig().MinActivationBalance) {
continue
}
srcIdx, ok := st.ValidatorIndexByPubkey(sourcePubkey)
if !ok {
continue
}
tgtIdx, ok := st.ValidatorIndexByPubkey(targetPubkey)
if !ok {
continue
}
srcV, err := st.ValidatorAtIndex(srcIdx)
if err != nil {
return fmt.Errorf("failed to fetch source validator: %w", err) // This should never happen.
}
roSrcV, err := state_native.NewValidator(srcV)
if err != nil {
return err
}
tgtV, err := st.ValidatorAtIndexReadOnly(tgtIdx)
if err != nil {
return fmt.Errorf("failed to fetch target validator: %w", err) // This should never happen.
}
// Verify source withdrawal credentials.
if !roSrcV.HasExecutionWithdrawalCredentials() {
continue
}
// Confirm source_validator.withdrawal_credentials[12:] == consolidation_request.source_address.
if len(srcV.WithdrawalCredentials) != 32 || len(cr.SourceAddress) != 20 || !bytes.HasSuffix(srcV.WithdrawalCredentials, cr.SourceAddress) {
continue
}
// Target validator must have their withdrawal credentials set appropriately.
if !tgtV.HasCompoundingWithdrawalCredentials() {
continue
}
// Both validators must be active.
if !helpers.IsActiveValidator(srcV, curEpoch) || !helpers.IsActiveValidatorUsingTrie(tgtV, curEpoch) {
continue
}
// Neither validator is exiting.
if srcV.ExitEpoch != ffe || tgtV.ExitEpoch() != ffe {
continue
}
e, overflow := math.SafeAdd(uint64(srcV.ActivationEpoch), uint64(params.BeaconConfig().ShardCommitteePeriod))
if overflow {
log.Error("Overflow when adding activation epoch and shard committee period")
continue
}
if uint64(curEpoch) < e {
continue
}
hasBal, err := st.HasPendingBalanceToWithdraw(srcIdx)
if err != nil {
log.WithError(err).Error("Failed to fetch pending balance to withdraw")
continue
}
if hasBal {
continue
}
exitEpoch, err := computeConsolidationEpochAndUpdateChurn(st, primitives.Gwei(srcV.EffectiveBalance))
if err != nil {
log.WithError(err).Error("Failed to compute consolidation epoch")
continue
}
srcV.ExitEpoch = exitEpoch
srcV.WithdrawableEpoch = exitEpoch + minValWithdrawDelay
if err := st.UpdateValidatorAtIndex(srcIdx, srcV); err != nil {
return fmt.Errorf("failed to update validator: %w", err) // This should never happen.
}
if err := st.AppendPendingConsolidation(&eth.PendingConsolidation{SourceIndex: srcIdx, TargetIndex: tgtIdx}); err != nil {
return fmt.Errorf("failed to append pending consolidation: %w", err) // This should never happen.
}
}
return nil
}
func isValidSwitchToCompoundingRequest(st state.BeaconState, req *enginev1.ConsolidationRequest) bool {
if req.SourcePubkey == nil || req.TargetPubkey == nil {
return false
}
if !bytes.Equal(req.SourcePubkey, req.TargetPubkey) {
return false
}
srcIdx, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(req.SourcePubkey))
if !ok {
return false
}
srcV, err := st.ValidatorAtIndexReadOnly(srcIdx)
if err != nil {
return false
}
sourceAddress := req.SourceAddress
withdrawalCreds := srcV.GetWithdrawalCredentials()
if len(withdrawalCreds) != 32 || len(sourceAddress) != 20 || !bytes.HasSuffix(withdrawalCreds, sourceAddress) {
return false
}
if !srcV.HasETH1WithdrawalCredentials() {
return false
}
curEpoch := slots.ToEpoch(st.Slot())
if !helpers.IsActiveValidatorUsingTrie(srcV, curEpoch) {
return false
}
if srcV.ExitEpoch() != params.BeaconConfig().FarFutureEpoch {
return false
}
return true
}
func switchToCompoundingValidator(st state.BeaconState, idx primitives.ValidatorIndex) error {
v, err := st.ValidatorAtIndex(idx)
if err != nil {
return err
}
if len(v.WithdrawalCredentials) == 0 {
return errors.New("validator has no withdrawal credentials")
}
v.WithdrawalCredentials[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
if err := st.UpdateValidatorAtIndex(idx, v); err != nil {
return err
}
return queueExcessActiveBalance(st, idx)
}
func queueExcessActiveBalance(st state.BeaconState, idx primitives.ValidatorIndex) error {
bal, err := st.BalanceAtIndex(idx)
if err != nil {
return err
}
if bal > params.BeaconConfig().MinActivationBalance {
if err := st.UpdateBalancesAtIndex(idx, params.BeaconConfig().MinActivationBalance); err != nil {
return err
}
excessBalance := bal - params.BeaconConfig().MinActivationBalance
val, err := st.ValidatorAtIndexReadOnly(idx)
if err != nil {
return err
}
pk := val.PublicKey()
return st.AppendPendingDeposit(&eth.PendingDeposit{
PublicKey: pk[:],
WithdrawalCredentials: val.GetWithdrawalCredentials(),
Amount: excessBalance,
Signature: common.InfiniteSignature[:],
Slot: params.BeaconConfig().GenesisSlot,
})
}
return nil
}
func computeConsolidationEpochAndUpdateChurn(st state.BeaconState, consolidationBalance primitives.Gwei) (primitives.Epoch, error) {
earliestEpoch, err := st.EarliestConsolidationEpoch()
if err != nil {
return 0, err
}
earliestConsolidationEpoch := max(earliestEpoch, helpers.ActivationExitEpoch(slots.ToEpoch(st.Slot())))
activeBal, err := helpers.TotalActiveBalance(st)
if err != nil {
return 0, err
}
perEpochConsolidationChurn := helpers.ConsolidationChurnLimit(primitives.Gwei(activeBal))
var consolidationBalanceToConsume primitives.Gwei
if earliestEpoch < earliestConsolidationEpoch {
consolidationBalanceToConsume = perEpochConsolidationChurn
} else {
consolidationBalanceToConsume, err = st.ConsolidationBalanceToConsume()
if err != nil {
return 0, err
}
}
if consolidationBalance > consolidationBalanceToConsume {
balanceToProcess := consolidationBalance - consolidationBalanceToConsume
additionalEpochs, err := prysmMath.Div64(uint64(balanceToProcess-1), uint64(perEpochConsolidationChurn))
if err != nil {
return 0, err
}
additionalEpochs++
earliestConsolidationEpoch += primitives.Epoch(additionalEpochs)
consolidationBalanceToConsume += primitives.Gwei(additionalEpochs) * perEpochConsolidationChurn
}
if err := st.SetConsolidationBalanceToConsume(consolidationBalanceToConsume - consolidationBalance); err != nil {
return 0, err
}
if err := st.SetEarliestConsolidationEpoch(earliestConsolidationEpoch); err != nil {
return 0, err
}
return earliestConsolidationEpoch, nil
}

View File

@@ -1,316 +0,0 @@
package requests_test
import (
"context"
"fmt"
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/requests"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
)
func createValidatorsWithTotalActiveBalance(totalBal primitives.Gwei) []*eth.Validator {
num := totalBal / primitives.Gwei(params.BeaconConfig().MinActivationBalance)
vals := make([]*eth.Validator, num)
for i := range vals {
wd := make([]byte, 32)
wd[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
wd[31] = byte(i)
vals[i] = &eth.Validator{
ActivationEpoch: primitives.Epoch(0),
EffectiveBalance: params.BeaconConfig().MinActivationBalance,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: fmt.Appendf(nil, "val_%d", i),
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
WithdrawalCredentials: wd,
}
}
if totalBal%primitives.Gwei(params.BeaconConfig().MinActivationBalance) != 0 {
vals = append(vals, &eth.Validator{
ActivationEpoch: primitives.Epoch(0),
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: uint64(totalBal) % params.BeaconConfig().MinActivationBalance,
})
}
return vals
}
func TestProcessConsolidationRequests(t *testing.T) {
tests := []struct {
name string
state state.BeaconState
reqs []*enginev1.ConsolidationRequest
validate func(*testing.T, state.BeaconState)
wantErr bool
}{
{
name: "nil request",
state: func() state.BeaconState {
st := &eth.BeaconStateElectra{}
s, err := state_native.InitializeFromProtoElectra(st)
require.NoError(t, err)
return s
}(),
reqs: []*enginev1.ConsolidationRequest{nil},
validate: func(t *testing.T, st state.BeaconState) {
require.DeepEqual(t, st, st)
},
wantErr: true,
},
{
name: "one valid request",
state: func() state.BeaconState {
st := &eth.BeaconStateElectra{
Slot: params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().ShardCommitteePeriod)),
Validators: createValidatorsWithTotalActiveBalance(32000000000000000), // 32M ETH
}
// Validator scenario setup. See comments in reqs section.
st.Validators[3].WithdrawalCredentials = bytesutil.Bytes32(0)
st.Validators[8].WithdrawalCredentials = bytesutil.Bytes32(1)
st.Validators[9].ActivationEpoch = params.BeaconConfig().FarFutureEpoch
st.Validators[12].ActivationEpoch = params.BeaconConfig().FarFutureEpoch
st.Validators[13].ExitEpoch = 10
st.Validators[16].ExitEpoch = 10
st.PendingPartialWithdrawals = []*eth.PendingPartialWithdrawal{
{
Index: 17,
Amount: 100,
},
}
s, err := state_native.InitializeFromProtoElectra(st)
require.NoError(t, err)
return s
}(),
reqs: []*enginev1.ConsolidationRequest{
// Source doesn't have withdrawal credentials.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(1)),
SourcePubkey: []byte("val_3"),
TargetPubkey: []byte("val_4"),
},
// Source withdrawal credentials don't match the consolidation address.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(0)), // Should be 5
SourcePubkey: []byte("val_5"),
TargetPubkey: []byte("val_6"),
},
// Target does not have their withdrawal credentials set appropriately. (Using eth1 address prefix)
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(7)),
SourcePubkey: []byte("val_7"),
TargetPubkey: []byte("val_8"),
},
// Source is inactive.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(9)),
SourcePubkey: []byte("val_9"),
TargetPubkey: []byte("val_10"),
},
// Target is inactive.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(11)),
SourcePubkey: []byte("val_11"),
TargetPubkey: []byte("val_12"),
},
// Source is exiting.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(13)),
SourcePubkey: []byte("val_13"),
TargetPubkey: []byte("val_14"),
},
// Target is exiting.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(15)),
SourcePubkey: []byte("val_15"),
TargetPubkey: []byte("val_16"),
},
// Source doesn't exist
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(0)),
SourcePubkey: []byte("INVALID"),
TargetPubkey: []byte("val_0"),
},
// Target doesn't exist
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(0)),
SourcePubkey: []byte("val_0"),
TargetPubkey: []byte("INVALID"),
},
// Source == target
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(0)),
SourcePubkey: []byte("val_0"),
TargetPubkey: []byte("val_0"),
},
// Has pending partial withdrawal
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(0)),
SourcePubkey: []byte("val_17"),
TargetPubkey: []byte("val_1"),
},
// Valid consolidation request. This should be last to ensure invalid requests do
// not end the processing early.
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(1)),
SourcePubkey: []byte("val_1"),
TargetPubkey: []byte("val_2"),
},
},
validate: func(t *testing.T, st state.BeaconState) {
// Verify a pending consolidation is created.
numPC, err := st.NumPendingConsolidations()
require.NoError(t, err)
require.Equal(t, uint64(1), numPC)
pcs, err := st.PendingConsolidations()
require.NoError(t, err)
require.Equal(t, primitives.ValidatorIndex(1), pcs[0].SourceIndex)
require.Equal(t, primitives.ValidatorIndex(2), pcs[0].TargetIndex)
// Verify the source validator is exiting.
src, err := st.ValidatorAtIndex(1)
require.NoError(t, err)
require.NotEqual(t, params.BeaconConfig().FarFutureEpoch, src.ExitEpoch, "source validator exit epoch not updated")
require.Equal(t, params.BeaconConfig().MinValidatorWithdrawabilityDelay, src.WithdrawableEpoch-src.ExitEpoch, "source validator withdrawable epoch not set correctly")
},
wantErr: false,
},
{
name: "pending consolidations limit reached",
state: func() state.BeaconState {
st := &eth.BeaconStateElectra{
Validators: createValidatorsWithTotalActiveBalance(32000000000000000), // 32M ETH
PendingConsolidations: make([]*eth.PendingConsolidation, params.BeaconConfig().PendingConsolidationsLimit),
}
s, err := state_native.InitializeFromProtoElectra(st)
require.NoError(t, err)
return s
}(),
reqs: []*enginev1.ConsolidationRequest{
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(1)),
SourcePubkey: []byte("val_1"),
TargetPubkey: []byte("val_2"),
},
},
validate: func(t *testing.T, st state.BeaconState) {
// Verify no pending consolidation is created.
numPC, err := st.NumPendingConsolidations()
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().PendingConsolidationsLimit, numPC)
// Verify the source validator is not exiting.
src, err := st.ValidatorAtIndex(1)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().FarFutureEpoch, src.ExitEpoch, "source validator exit epoch should not be updated")
require.Equal(t, params.BeaconConfig().FarFutureEpoch, src.WithdrawableEpoch, "source validator withdrawable epoch should not be updated")
},
wantErr: false,
},
{
name: "pending consolidations limit reached during processing",
state: func() state.BeaconState {
st := &eth.BeaconStateElectra{
Slot: params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().ShardCommitteePeriod)),
Validators: createValidatorsWithTotalActiveBalance(32000000000000000), // 32M ETH
PendingConsolidations: make([]*eth.PendingConsolidation, params.BeaconConfig().PendingConsolidationsLimit-1),
}
s, err := state_native.InitializeFromProtoElectra(st)
require.NoError(t, err)
return s
}(),
reqs: []*enginev1.ConsolidationRequest{
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(1)),
SourcePubkey: []byte("val_1"),
TargetPubkey: []byte("val_2"),
},
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(3)),
SourcePubkey: []byte("val_3"),
TargetPubkey: []byte("val_4"),
},
},
validate: func(t *testing.T, st state.BeaconState) {
// Verify a pending consolidation is created.
numPC, err := st.NumPendingConsolidations()
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().PendingConsolidationsLimit, numPC)
// The first consolidation was appended.
pcs, err := st.PendingConsolidations()
require.NoError(t, err)
require.Equal(t, primitives.ValidatorIndex(1), pcs[params.BeaconConfig().PendingConsolidationsLimit-1].SourceIndex)
require.Equal(t, primitives.ValidatorIndex(2), pcs[params.BeaconConfig().PendingConsolidationsLimit-1].TargetIndex)
// Verify the second source validator is not exiting.
src, err := st.ValidatorAtIndex(3)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().FarFutureEpoch, src.ExitEpoch, "source validator exit epoch should not be updated")
require.Equal(t, params.BeaconConfig().FarFutureEpoch, src.WithdrawableEpoch, "source validator withdrawable epoch should not be updated")
},
wantErr: false,
},
{
name: "pending consolidations limit reached and compounded consolidation after",
state: func() state.BeaconState {
st := &eth.BeaconStateElectra{
Slot: params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().ShardCommitteePeriod)),
Validators: createValidatorsWithTotalActiveBalance(32000000000000000), // 32M ETH
PendingConsolidations: make([]*eth.PendingConsolidation, params.BeaconConfig().PendingConsolidationsLimit),
}
// To allow compounding consolidation requests.
st.Validators[3].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
s, err := state_native.InitializeFromProtoElectra(st)
require.NoError(t, err)
return s
}(),
reqs: []*enginev1.ConsolidationRequest{
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(1)),
SourcePubkey: []byte("val_1"),
TargetPubkey: []byte("val_2"),
},
{
SourceAddress: append(bytesutil.PadTo(nil, 19), byte(3)),
SourcePubkey: []byte("val_3"),
TargetPubkey: []byte("val_3"),
},
},
validate: func(t *testing.T, st state.BeaconState) {
// Verify a pending consolidation is created.
numPC, err := st.NumPendingConsolidations()
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().PendingConsolidationsLimit, numPC)
// Verify that the last consolidation was included
src, err := st.ValidatorAtIndex(3)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().CompoundingWithdrawalPrefixByte, src.WithdrawalCredentials[0], "source validator was not compounded")
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := requests.ProcessConsolidationRequests(context.TODO(), tt.state, tt.reqs)
if (err != nil) != tt.wantErr {
t.Errorf("ProcessWithdrawalRequests() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
require.NoError(t, err)
}
if tt.validate != nil {
tt.validate(t, tt.state)
}
})
}
}

View File

@@ -1,73 +0,0 @@
package requests
import (
"context"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/pkg/errors"
)
// ProcessDepositRequests processes execution layer deposits requests.
func ProcessDepositRequests(ctx context.Context, beaconState state.BeaconState, reqs []*enginev1.DepositRequest) (state.BeaconState, error) {
_, span := trace.StartSpan(ctx, "requests.ProcessDepositRequests")
defer span.End()
if len(reqs) == 0 {
return beaconState, nil
}
var err error
for _, req := range reqs {
beaconState, err = processDepositRequest(beaconState, req)
if err != nil {
return nil, errors.Wrap(err, "could not apply deposit request")
}
}
return beaconState, nil
}
// processDepositRequest processes the specific deposit request
//
// def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None:
//
// # Set deposit request start index
// if state.deposit_requests_start_index == UNSET_DEPOSIT_REQUESTS_START_INDEX:
// state.deposit_requests_start_index = deposit_request.index
//
// # Create pending deposit
// state.pending_deposits.append(PendingDeposit(
// pubkey=deposit_request.pubkey,
// withdrawal_credentials=deposit_request.withdrawal_credentials,
// amount=deposit_request.amount,
// signature=deposit_request.signature,
// slot=state.slot,
// ))
func processDepositRequest(beaconState state.BeaconState, req *enginev1.DepositRequest) (state.BeaconState, error) {
requestsStartIndex, err := beaconState.DepositRequestsStartIndex()
if err != nil {
return nil, errors.Wrap(err, "could not get deposit requests start index")
}
if req == nil {
return nil, errors.New("nil deposit request")
}
if requestsStartIndex == params.BeaconConfig().UnsetDepositRequestsStartIndex {
if err := beaconState.SetDepositRequestsStartIndex(req.Index); err != nil {
return nil, errors.Wrap(err, "could not set deposit requests start index")
}
}
if err := beaconState.AppendPendingDeposit(&ethpb.PendingDeposit{
PublicKey: bytesutil.SafeCopyBytes(req.Pubkey),
WithdrawalCredentials: bytesutil.SafeCopyBytes(req.WithdrawalCredentials),
Amount: req.Amount,
Signature: bytesutil.SafeCopyBytes(req.Signature),
Slot: beaconState.Slot(),
}); err != nil {
return nil, errors.Wrap(err, "could not append deposit request")
}
return beaconState, nil
}

View File

@@ -1,70 +0,0 @@
package requests_test
import (
"testing"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/requests"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/crypto/bls"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/testing/require"
"github.com/OffchainLabs/prysm/v7/testing/util"
)
func TestProcessDepositRequests(t *testing.T) {
st, _ := util.DeterministicGenesisStateElectra(t, 1)
sk, err := bls.RandKey()
require.NoError(t, err)
require.NoError(t, st.SetDepositRequestsStartIndex(1))
t.Run("empty requests continues", func(t *testing.T) {
newSt, err := requests.ProcessDepositRequests(t.Context(), st, []*enginev1.DepositRequest{})
require.NoError(t, err)
require.DeepEqual(t, newSt, st)
})
t.Run("nil request errors", func(t *testing.T) {
_, err = requests.ProcessDepositRequests(t.Context(), st, []*enginev1.DepositRequest{nil})
require.ErrorContains(t, "nil deposit request", err)
})
vals := st.Validators()
vals[0].PublicKey = sk.PublicKey().Marshal()
vals[0].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
require.NoError(t, st.SetValidators(vals))
bals := st.Balances()
bals[0] = params.BeaconConfig().MinActivationBalance + 2000
require.NoError(t, st.SetBalances(bals))
require.NoError(t, st.SetPendingDeposits(make([]*eth.PendingDeposit, 0))) // reset pbd as the deterministic state populates this already
withdrawalCred := make([]byte, 32)
withdrawalCred[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
depositMessage := &eth.DepositMessage{
PublicKey: sk.PublicKey().Marshal(),
Amount: 1000,
WithdrawalCredentials: withdrawalCred,
}
domain, err := signing.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
require.NoError(t, err)
sr, err := signing.ComputeSigningRoot(depositMessage, domain)
require.NoError(t, err)
sig := sk.Sign(sr[:])
reqs := []*enginev1.DepositRequest{
{
Pubkey: depositMessage.PublicKey,
Index: 0,
WithdrawalCredentials: depositMessage.WithdrawalCredentials,
Amount: depositMessage.Amount,
Signature: sig.Marshal(),
},
}
st, err = requests.ProcessDepositRequests(t.Context(), st, reqs)
require.NoError(t, err)
pbd, err := st.PendingDeposits()
require.NoError(t, err)
require.Equal(t, 1, len(pbd))
require.Equal(t, uint64(1000), pbd[0].Amount)
require.DeepEqual(t, bytesutil.SafeCopyBytes(reqs[0].Pubkey), pbd[0].PublicKey)
}

View File

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

View File

@@ -27,7 +27,6 @@ go_library(
"//beacon-chain/core/execution:go_default_library",
"//beacon-chain/core/fulu:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/requests:go_default_library",
"//beacon-chain/core/time:go_default_library",
"//beacon-chain/core/transition/interop:go_default_library",
"//beacon-chain/core/validators:go_default_library",

View File

@@ -6,7 +6,6 @@ import (
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/blocks"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
coreRequests "github.com/OffchainLabs/prysm/v7/beacon-chain/core/requests"
v "github.com/OffchainLabs/prysm/v7/beacon-chain/core/validators"
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
@@ -98,7 +97,7 @@ func electraOperations(ctx context.Context, st state.BeaconState, block interfac
return nil, electra.NewExecReqError("nil deposit request")
}
}
st, err = coreRequests.ProcessDepositRequests(ctx, st, requests.Deposits)
st, err = electra.ProcessDepositRequests(ctx, st, requests.Deposits)
if err != nil {
return nil, electra.NewExecReqError(errors.Wrap(err, "could not process deposit requests").Error())
}
@@ -108,7 +107,7 @@ func electraOperations(ctx context.Context, st state.BeaconState, block interfac
return nil, electra.NewExecReqError("nil withdrawal request")
}
}
st, err = coreRequests.ProcessWithdrawalRequests(ctx, st, requests.Withdrawals)
st, err = electra.ProcessWithdrawalRequests(ctx, st, requests.Withdrawals)
if err != nil {
return nil, electra.NewExecReqError(errors.Wrap(err, "could not process withdrawal requests").Error())
}
@@ -117,7 +116,7 @@ func electraOperations(ctx context.Context, st state.BeaconState, block interfac
return nil, electra.NewExecReqError("nil consolidation request")
}
}
if err := coreRequests.ProcessConsolidationRequests(ctx, st, requests.Consolidations); err != nil {
if err := electra.ProcessConsolidationRequests(ctx, st, requests.Consolidations); err != nil {
return nil, electra.NewExecReqError(errors.Wrap(err, "could not process consolidation requests").Error())
}
return st, nil

View File

@@ -64,6 +64,7 @@ go_library(
"//monitoring/tracing:go_default_library",
"//runtime:go_default_library",
"//runtime/prereqs:go_default_library",
"//runtime/version:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",

View File

@@ -66,6 +66,7 @@ import (
"github.com/OffchainLabs/prysm/v7/monitoring/prometheus"
"github.com/OffchainLabs/prysm/v7/runtime"
"github.com/OffchainLabs/prysm/v7/runtime/prereqs"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -468,6 +469,10 @@ func (b *BeaconNode) OperationFeed() event.SubscriberSender {
func (b *BeaconNode) Start() {
b.lock.Lock()
log.WithFields(logrus.Fields{
"version": version.Version(),
}).Info("Starting beacon node")
b.services.StartAll()
stop := b.stop

View File

@@ -68,6 +68,7 @@ func TestNodeClose_OK(t *testing.T) {
}
func TestNodeStart_Ok(t *testing.T) {
hook := logTest.NewGlobal()
app := cli.App{}
tmp := fmt.Sprintf("%s/datadirtest2", t.TempDir())
set := flag.NewFlagSet("test", 0)
@@ -96,9 +97,11 @@ func TestNodeStart_Ok(t *testing.T) {
}()
time.Sleep(3 * time.Second)
node.Close()
require.LogsContain(t, hook, "Starting beacon node")
}
func TestNodeStart_SyncChecker(t *testing.T) {
hook := logTest.NewGlobal()
app := cli.App{}
tmp := fmt.Sprintf("%s/datadirtest2", t.TempDir())
set := flag.NewFlagSet("test", 0)
@@ -124,6 +127,7 @@ func TestNodeStart_SyncChecker(t *testing.T) {
time.Sleep(3 * time.Second)
assert.NotNil(t, node.syncChecker.Svc)
node.Close()
require.LogsContain(t, hook, "Starting beacon node")
}
// TestClearDB tests clearing the database

View File

@@ -8,6 +8,7 @@ import (
"io"
"net/http"
"strconv"
"strings"
"time"
"github.com/OffchainLabs/prysm/v7/api"
@@ -25,6 +26,7 @@ import (
"github.com/OffchainLabs/prysm/v7/consensus-types/blocks"
"github.com/OffchainLabs/prysm/v7/consensus-types/interfaces"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v7/network/httputil"
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
@@ -1042,27 +1044,112 @@ func (s *Server) GetBlockRoot(w http.ResponseWriter, r *http.Request) {
ctx, span := trace.StartSpan(r.Context(), "beacon.GetBlockRoot")
defer span.End()
var err error
var root []byte
blockID := r.PathValue("block_id")
if blockID == "" {
httputil.HandleError(w, "block_id is required in URL params", http.StatusBadRequest)
return
}
root, err := s.Blocker.BlockRoot(ctx, []byte(blockID))
if !shared.WriteBlockRootFetchError(w, err) {
return
switch blockID {
case "head":
root, err = s.ChainInfoFetcher.HeadRoot(ctx)
if err != nil {
httputil.HandleError(w, "Could not retrieve head root: "+err.Error(), http.StatusInternalServerError)
return
}
if root == nil {
httputil.HandleError(w, "No head root was found", http.StatusNotFound)
return
}
case "finalized":
finalized := s.ChainInfoFetcher.FinalizedCheckpt()
root = finalized.Root
case "genesis":
blk, err := s.BeaconDB.GenesisBlock(ctx)
if err != nil {
httputil.HandleError(w, "Could not retrieve genesis block: "+err.Error(), http.StatusInternalServerError)
return
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
httputil.HandleError(w, "Could not find genesis block: "+err.Error(), http.StatusNotFound)
return
}
blkRoot, err := blk.Block().HashTreeRoot()
if err != nil {
httputil.HandleError(w, "Could not hash genesis block: "+err.Error(), http.StatusInternalServerError)
return
}
root = blkRoot[:]
default:
isHex := strings.HasPrefix(blockID, "0x")
if isHex {
blockIDBytes, err := hexutil.Decode(blockID)
if err != nil {
httputil.HandleError(w, "Could not decode block ID into bytes: "+err.Error(), http.StatusBadRequest)
return
}
if len(blockIDBytes) != fieldparams.RootLength {
httputil.HandleError(w, fmt.Sprintf("Block ID has length %d instead of %d", len(blockIDBytes), fieldparams.RootLength), http.StatusBadRequest)
return
}
blockID32 := bytesutil.ToBytes32(blockIDBytes)
blk, err := s.BeaconDB.Block(ctx, blockID32)
if err != nil {
httputil.HandleError(w, fmt.Sprintf("Could not retrieve block for block root %#x: %v", blockID, err), http.StatusInternalServerError)
return
}
if err := blocks.BeaconBlockIsNil(blk); err != nil {
httputil.HandleError(w, "Could not find block: "+err.Error(), http.StatusNotFound)
return
}
root = blockIDBytes
} else {
slot, err := strconv.ParseUint(blockID, 10, 64)
if err != nil {
httputil.HandleError(w, "Could not parse block ID: "+err.Error(), http.StatusBadRequest)
return
}
hasRoots, roots, err := s.BeaconDB.BlockRootsBySlot(ctx, primitives.Slot(slot))
if err != nil {
httputil.HandleError(w, fmt.Sprintf("Could not retrieve blocks for slot %d: %v", slot, err), http.StatusInternalServerError)
return
}
if !hasRoots {
httputil.HandleError(w, "Could not find any blocks with given slot", http.StatusNotFound)
return
}
root = roots[0][:]
if len(roots) == 1 {
break
}
for _, blockRoot := range roots {
canonical, err := s.ChainInfoFetcher.IsCanonical(ctx, blockRoot)
if err != nil {
httputil.HandleError(w, "Could not determine if block root is canonical: "+err.Error(), http.StatusInternalServerError)
return
}
if canonical {
root = blockRoot[:]
break
}
}
}
}
isOptimistic, err := s.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
b32Root := bytesutil.ToBytes32(root)
isOptimistic, err := s.OptimisticModeFetcher.IsOptimisticForRoot(ctx, b32Root)
if err != nil {
httputil.HandleError(w, "Could not check if block is optimistic: "+err.Error(), http.StatusInternalServerError)
return
}
response := &structs.BlockRootResponse{
Data: &structs.BlockRoot{
Root: hexutil.Encode(root[:]),
Root: hexutil.Encode(root),
},
ExecutionOptimistic: isOptimistic,
Finalized: s.FinalizationFetcher.IsFinalized(ctx, root),
Finalized: s.FinalizationFetcher.IsFinalized(ctx, b32Root),
}
httputil.WriteJson(w, response)
}

View File

@@ -2509,10 +2509,6 @@ func TestServer_GetBlockRoot(t *testing.T) {
HeadFetcher: mockChainFetcher,
OptimisticModeFetcher: mockChainFetcher,
FinalizationFetcher: mockChainFetcher,
Blocker: &lookup.BeaconDbBlocker{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainFetcher,
},
}
root, err := genBlk.Block.HashTreeRoot()
@@ -2528,7 +2524,7 @@ func TestServer_GetBlockRoot(t *testing.T) {
{
name: "bad formatting",
blockID: map[string]string{"block_id": "3bad0"},
wantErr: "Invalid block ID",
wantErr: "Could not parse block ID",
wantCode: http.StatusBadRequest,
},
{
@@ -2576,7 +2572,7 @@ func TestServer_GetBlockRoot(t *testing.T) {
{
name: "non-existent root",
blockID: map[string]string{"block_id": hexutil.Encode(bytesutil.PadTo([]byte("hi there"), 32))},
wantErr: "Block not found",
wantErr: "Could not find block",
wantCode: http.StatusNotFound,
},
{
@@ -2589,7 +2585,7 @@ func TestServer_GetBlockRoot(t *testing.T) {
{
name: "no block",
blockID: map[string]string{"block_id": "105"},
wantErr: "Block not found",
wantErr: "Could not find any blocks with given slot",
wantCode: http.StatusNotFound,
},
}
@@ -2637,10 +2633,6 @@ func TestServer_GetBlockRoot(t *testing.T) {
HeadFetcher: mockChainFetcher,
OptimisticModeFetcher: mockChainFetcher,
FinalizationFetcher: mockChainFetcher,
Blocker: &lookup.BeaconDbBlocker{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainFetcher,
},
}
request := httptest.NewRequest(http.MethodGet, url, nil)
@@ -2676,10 +2668,6 @@ func TestServer_GetBlockRoot(t *testing.T) {
HeadFetcher: mockChainFetcher,
OptimisticModeFetcher: mockChainFetcher,
FinalizationFetcher: mockChainFetcher,
Blocker: &lookup.BeaconDbBlocker{
BeaconDB: beaconDB,
ChainInfoFetcher: mockChainFetcher,
},
}
t.Run("true", func(t *testing.T) {
request := httptest.NewRequest(http.MethodGet, url, nil)

View File

@@ -26,30 +26,21 @@ func WriteStateFetchError(w http.ResponseWriter, err error) {
httputil.HandleError(w, "Could not get state: "+err.Error(), http.StatusInternalServerError)
}
// writeBlockIdError handles common block ID lookup errors.
// Returns true if an error was handled and written to the response, false if no error.
func writeBlockIdError(w http.ResponseWriter, err error, fallbackMsg string) bool {
if err == nil {
return false
}
// WriteBlockFetchError writes an appropriate error based on the supplied argument.
// The argument error should be a result of fetching block.
func WriteBlockFetchError(w http.ResponseWriter, blk interfaces.ReadOnlySignedBeaconBlock, err error) bool {
var blockNotFoundErr *lookup.BlockNotFoundError
if errors.As(err, &blockNotFoundErr) {
httputil.HandleError(w, "Block not found: "+blockNotFoundErr.Error(), http.StatusNotFound)
return true
return false
}
var invalidBlockIdErr *lookup.BlockIdParseError
if errors.As(err, &invalidBlockIdErr) {
httputil.HandleError(w, "Invalid block ID: "+invalidBlockIdErr.Error(), http.StatusBadRequest)
return true
return false
}
httputil.HandleError(w, fallbackMsg+": "+err.Error(), http.StatusInternalServerError)
return true
}
// WriteBlockFetchError writes an appropriate error based on the supplied argument.
// The argument error should be a result of fetching block.
func WriteBlockFetchError(w http.ResponseWriter, blk interfaces.ReadOnlySignedBeaconBlock, err error) bool {
if writeBlockIdError(w, err, "Could not get block from block ID") {
if err != nil {
httputil.HandleError(w, "Could not get block from block ID: "+err.Error(), http.StatusInternalServerError)
return false
}
if err = blocks.BeaconBlockIsNil(blk); err != nil {
@@ -58,10 +49,3 @@ func WriteBlockFetchError(w http.ResponseWriter, blk interfaces.ReadOnlySignedBe
}
return true
}
// WriteBlockRootFetchError writes an appropriate error based on the supplied argument.
// The argument error should be a result of fetching block root.
// Returns true if no error occurred, false otherwise.
func WriteBlockRootFetchError(w http.ResponseWriter, err error) bool {
return !writeBlockIdError(w, err, "Could not get block root from block ID")
}

View File

@@ -105,59 +105,3 @@ func TestWriteBlockFetchError(t *testing.T) {
})
}
}
// TestWriteBlockRootFetchError tests the WriteBlockRootFetchError function
// to ensure that the correct error message and code are written to the response
// and that the function returns the correct boolean value.
func TestWriteBlockRootFetchError(t *testing.T) {
cases := []struct {
name string
err error
expectedMessage string
expectedCode int
expectedReturn bool
}{
{
name: "Nil error should return true",
err: nil,
expectedReturn: true,
},
{
name: "BlockNotFoundError should return 404",
err: lookup.NewBlockNotFoundError("block not found at slot 123"),
expectedMessage: "Block not found",
expectedCode: http.StatusNotFound,
expectedReturn: false,
},
{
name: "BlockIdParseError should return 400",
err: &lookup.BlockIdParseError{},
expectedMessage: "Invalid block ID",
expectedCode: http.StatusBadRequest,
expectedReturn: false,
},
{
name: "Generic error should return 500",
err: errors.New("database connection failed"),
expectedMessage: "Could not get block root from block ID",
expectedCode: http.StatusInternalServerError,
expectedReturn: false,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
writer := httptest.NewRecorder()
result := WriteBlockRootFetchError(writer, c.err)
assert.Equal(t, c.expectedReturn, result, "incorrect return value")
if !c.expectedReturn {
assert.Equal(t, c.expectedCode, writer.Code, "incorrect status code")
assert.StringContains(t, c.expectedMessage, writer.Body.String(), "incorrect error message")
e := &httputil.DefaultJsonError{}
assert.NoError(t, json.Unmarshal(writer.Body.Bytes(), e), "failed to unmarshal response")
}
})
}
}

View File

@@ -60,7 +60,6 @@ func (e BlockIdParseError) Error() string {
// Blocker is responsible for retrieving blocks.
type Blocker interface {
Block(ctx context.Context, id []byte) (interfaces.ReadOnlySignedBeaconBlock, error)
BlockRoot(ctx context.Context, id []byte) ([fieldparams.RootLength]byte, error)
BlobSidecars(ctx context.Context, id string, opts ...options.BlobsOption) ([]*blocks.VerifiedROBlob, *core.RpcError)
Blobs(ctx context.Context, id string, opts ...options.BlobsOption) ([][]byte, *core.RpcError)
DataColumns(ctx context.Context, id string, indices []int) ([]blocks.VerifiedRODataColumn, *core.RpcError)
@@ -226,18 +225,6 @@ func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.Read
return blk, nil
}
// BlockRoot returns the block root for a given identifier. The identifier can be one of:
// - "head" (canonical head in node's view)
// - "genesis"
// - "finalized"
// - "justified"
// - <slot>
// - <hex encoded block root with '0x' prefix>
func (p *BeaconDbBlocker) BlockRoot(ctx context.Context, id []byte) ([fieldparams.RootLength]byte, error) {
root, _, err := p.resolveBlockID(ctx, string(id))
return root, err
}
// blobsContext holds common information needed for blob retrieval
type blobsContext struct {
root [fieldparams.RootLength]byte

View File

@@ -168,111 +168,6 @@ func TestGetBlock(t *testing.T) {
}
}
func TestBlockRoot(t *testing.T) {
beaconDB := testDB.SetupDB(t)
ctx := t.Context()
genBlk, blkContainers := testutil.FillDBWithBlocks(ctx, t, beaconDB)
canonicalRoots := make(map[[32]byte]bool)
for _, bContr := range blkContainers {
canonicalRoots[bytesutil.ToBytes32(bContr.BlockRoot)] = true
}
headBlock := blkContainers[len(blkContainers)-1]
wsb, err := blocks.NewSignedBeaconBlock(headBlock.Block.(*ethpb.BeaconBlockContainer_Phase0Block).Phase0Block)
require.NoError(t, err)
fetcher := &BeaconDbBlocker{
BeaconDB: beaconDB,
ChainInfoFetcher: &mockChain.ChainService{
DB: beaconDB,
Block: wsb,
Root: headBlock.BlockRoot,
FinalizedCheckPoint: &ethpb.Checkpoint{Root: blkContainers[64].BlockRoot},
CurrentJustifiedCheckPoint: &ethpb.Checkpoint{Root: blkContainers[32].BlockRoot},
CanonicalRoots: canonicalRoots,
},
}
genesisRoot, err := genBlk.Block.HashTreeRoot()
require.NoError(t, err)
tests := []struct {
name string
blockID []byte
want [32]byte
wantErr bool
}{
{
name: "slot",
blockID: []byte("30"),
want: bytesutil.ToBytes32(blkContainers[30].BlockRoot),
},
{
name: "bad formatting",
blockID: []byte("3bad0"),
wantErr: true,
},
{
name: "head",
blockID: []byte("head"),
want: bytesutil.ToBytes32(headBlock.BlockRoot),
},
{
name: "finalized",
blockID: []byte("finalized"),
want: bytesutil.ToBytes32(blkContainers[64].BlockRoot),
},
{
name: "justified",
blockID: []byte("justified"),
want: bytesutil.ToBytes32(blkContainers[32].BlockRoot),
},
{
name: "genesis",
blockID: []byte("genesis"),
want: genesisRoot,
},
{
name: "genesis root",
blockID: genesisRoot[:],
want: genesisRoot,
},
{
name: "root",
blockID: blkContainers[20].BlockRoot,
want: bytesutil.ToBytes32(blkContainers[20].BlockRoot),
},
{
name: "hex root",
blockID: []byte(hexutil.Encode(blkContainers[20].BlockRoot)),
want: bytesutil.ToBytes32(blkContainers[20].BlockRoot),
},
{
name: "non-existent root",
blockID: bytesutil.PadTo([]byte("hi there"), 32),
wantErr: true,
},
{
name: "no block at slot",
blockID: []byte("105"),
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := fetcher.BlockRoot(ctx, tt.blockID)
if tt.wantErr {
assert.NotEqual(t, err, nil, "no error has been returned")
return
}
require.NoError(t, err)
assert.DeepEqual(t, tt.want, result)
})
}
}
func TestBlobsErrorHandling(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.BeaconConfig().Copy()

View File

@@ -15,7 +15,6 @@ import (
// MockBlocker is a fake implementation of lookup.Blocker.
type MockBlocker struct {
BlockToReturn interfaces.ReadOnlySignedBeaconBlock
RootToReturn [32]byte
ErrorToReturn error
SlotBlockMap map[primitives.Slot]interfaces.ReadOnlySignedBeaconBlock
RootBlockMap map[[32]byte]interfaces.ReadOnlySignedBeaconBlock
@@ -40,14 +39,6 @@ func (m *MockBlocker) Block(_ context.Context, b []byte) (interfaces.ReadOnlySig
return m.SlotBlockMap[primitives.Slot(slotNumber)], nil
}
// BlockRoot --
func (m *MockBlocker) BlockRoot(_ context.Context, _ []byte) ([32]byte, error) {
if m.ErrorToReturn != nil {
return [32]byte{}, m.ErrorToReturn
}
return m.RootToReturn, nil
}
// BlobSidecars --
func (*MockBlocker) BlobSidecars(_ context.Context, _ string, _ ...options.BlobsOption) ([]*blocks.VerifiedROBlob, *core.RpcError) {
return nil, &core.RpcError{}

View File

@@ -20,5 +20,7 @@ type readOnlyGloasFields interface {
IsActiveBuilder(primitives.BuilderIndex) (bool, error)
CanBuilderCoverBid(primitives.BuilderIndex, primitives.Gwei) (bool, error)
LatestBlockHash() ([32]byte, error)
BuilderPendingPayment(index uint64) (*ethpb.BuilderPendingPayment, error)
BuilderPendingPayments() ([]*ethpb.BuilderPendingPayment, error)
ExecutionPayloadAvailability(slot primitives.Slot) (uint64, error)
}

View File

@@ -147,3 +147,36 @@ func (b *BeaconState) BuilderPendingPayments() ([]*ethpb.BuilderPendingPayment,
return b.builderPendingPaymentsVal(), nil
}
// BuilderPendingPayment returns the builder pending payment for the given index.
func (b *BeaconState) BuilderPendingPayment(index uint64) (*ethpb.BuilderPendingPayment, error) {
if b.version < version.Gloas {
return nil, errNotSupported("BuilderPendingPayment", b.version)
}
b.lock.RLock()
defer b.lock.RUnlock()
if index >= uint64(len(b.builderPendingPayments)) {
return nil, fmt.Errorf("builder pending payment index %d out of range (len=%d)", index, len(b.builderPendingPayments))
}
return ethpb.CopyBuilderPendingPayment(b.builderPendingPayments[index]), nil
}
// ExecutionPayloadAvailability returns the execution payload availability bit for the given slot.
func (b *BeaconState) ExecutionPayloadAvailability(slot primitives.Slot) (uint64, error) {
if b.version < version.Gloas {
return 0, errNotSupported("ExecutionPayloadAvailability", b.version)
}
b.lock.RLock()
defer b.lock.RUnlock()
slotIndex := slot % params.BeaconConfig().SlotsPerHistoricalRoot
byteIndex := slotIndex / 8
bitIndex := slotIndex % 8
bit := (b.executionPayloadAvailability[byteIndex] >> bitIndex) & 1
return uint64(bit), nil
}

View File

@@ -166,3 +166,77 @@ func TestBuilderPendingPayments_UnsupportedVersion(t *testing.T) {
_, err = st.BuilderPendingPayments()
require.ErrorContains(t, "BuilderPendingPayments", err)
}
func TestBuilderPendingPayment_ReturnsCopy(t *testing.T) {
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
payments := make([]*ethpb.BuilderPendingPayment, 2*slotsPerEpoch)
target := uint64(slotsPerEpoch + 1)
payments[target] = &ethpb.BuilderPendingPayment{Weight: 10}
st, err := state_native.InitializeFromProtoUnsafeGloas(&ethpb.BeaconStateGloas{
BuilderPendingPayments: payments,
})
require.NoError(t, err)
payment, err := st.BuilderPendingPayment(target)
require.NoError(t, err)
// mutate returned copy
payment.Weight = 99
original, err := st.BuilderPendingPayment(target)
require.NoError(t, err)
require.Equal(t, uint64(10), uint64(original.Weight))
}
func TestBuilderPendingPayment_UnsupportedVersion(t *testing.T) {
stIface, err := state_native.InitializeFromProtoElectra(&ethpb.BeaconStateElectra{})
require.NoError(t, err)
st := stIface.(*state_native.BeaconState)
_, err = st.BuilderPendingPayment(0)
require.ErrorContains(t, "BuilderPendingPayment", err)
}
func TestBuilderPendingPayment_OutOfRange(t *testing.T) {
stIface, err := state_native.InitializeFromProtoUnsafeGloas(&ethpb.BeaconStateGloas{
BuilderPendingPayments: []*ethpb.BuilderPendingPayment{},
})
require.NoError(t, err)
_, err = stIface.BuilderPendingPayment(0)
require.ErrorContains(t, "out of range", err)
}
func TestExecutionPayloadAvailability(t *testing.T) {
t.Run("unsupported version", func(t *testing.T) {
stIface, err := state_native.InitializeFromProtoElectra(&ethpb.BeaconStateElectra{})
require.NoError(t, err)
st := stIface.(*state_native.BeaconState)
_, err = st.ExecutionPayloadAvailability(0)
require.ErrorContains(t, "ExecutionPayloadAvailability", err)
})
t.Run("reads expected bit", func(t *testing.T) {
// Ensure the backing slice is large enough.
availability := make([]byte, params.BeaconConfig().SlotsPerHistoricalRoot/8)
// Pick a slot and set its corresponding bit.
slot := primitives.Slot(9) // byteIndex=1, bitIndex=1
availability[1] = 0b00000010
stIface, err := state_native.InitializeFromProtoUnsafeGloas(&ethpb.BeaconStateGloas{
ExecutionPayloadAvailability: availability,
})
require.NoError(t, err)
bit, err := stIface.ExecutionPayloadAvailability(slot)
require.NoError(t, err)
require.Equal(t, uint64(1), bit)
otherBit, err := stIface.ExecutionPayloadAvailability(8)
require.NoError(t, err)
require.Equal(t, uint64(0), otherBit)
})
}

View File

@@ -113,100 +113,77 @@ func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, uint64, err
defer b.lock.RUnlock()
withdrawals := make([]*enginev1.Withdrawal, 0, params.BeaconConfig().MaxWithdrawalsPerPayload)
withdrawalIndex := b.nextWithdrawalIndex
withdrawalIndex, processedPartialWithdrawalsCount, err := b.appendPendingPartialWithdrawals(withdrawalIndex, &withdrawals)
if err != nil {
return nil, 0, err
}
err = b.appendValidatorsSweepWithdrawals(withdrawalIndex, &withdrawals)
if err != nil {
return nil, 0, err
}
return withdrawals, processedPartialWithdrawalsCount, nil
}
func (b *BeaconState) appendPendingPartialWithdrawals(withdrawalIndex uint64, withdrawals *[]*enginev1.Withdrawal) (uint64, uint64, error) {
if b.version < version.Electra {
return withdrawalIndex, 0, nil
}
ws := *withdrawals
epoch := slots.ToEpoch(b.slot)
var processedPartialWithdrawalsCount uint64
for _, w := range b.pendingPartialWithdrawals {
if w.WithdrawableEpoch > epoch || len(ws) >= int(params.BeaconConfig().MaxPendingPartialsPerWithdrawalsSweep) {
break
}
v, err := b.validatorAtIndexReadOnly(w.Index)
if err != nil {
return withdrawalIndex, 0, fmt.Errorf("failed to determine withdrawals at index %d: %w", w.Index, err)
}
vBal, err := b.balanceAtIndex(w.Index)
if err != nil {
return withdrawalIndex, 0, fmt.Errorf("could not retrieve balance at index %d: %w", w.Index, err)
}
hasSufficientEffectiveBalance := v.EffectiveBalance() >= params.BeaconConfig().MinActivationBalance
var totalWithdrawn uint64
for _, wi := range ws {
if wi.ValidatorIndex == w.Index {
totalWithdrawn += wi.Amount
}
}
balance, err := mathutil.Sub64(vBal, totalWithdrawn)
if err != nil {
return withdrawalIndex, 0, errors.Wrapf(err, "failed to subtract balance %d with total withdrawn %d", vBal, totalWithdrawn)
}
hasExcessBalance := balance > params.BeaconConfig().MinActivationBalance
if v.ExitEpoch() == params.BeaconConfig().FarFutureEpoch && hasSufficientEffectiveBalance && hasExcessBalance {
amount := min(balance-params.BeaconConfig().MinActivationBalance, w.Amount)
ws = append(ws, &enginev1.Withdrawal{
Index: withdrawalIndex,
ValidatorIndex: w.Index,
Address: v.GetWithdrawalCredentials()[12:],
Amount: amount,
})
withdrawalIndex++
}
processedPartialWithdrawalsCount++
}
*withdrawals = ws
return withdrawalIndex, processedPartialWithdrawalsCount, nil
}
func (b *BeaconState) appendValidatorsSweepWithdrawals(withdrawalIndex uint64, withdrawals *[]*enginev1.Withdrawal) error {
ws := *withdrawals
validatorIndex := b.nextWithdrawalValidatorIndex
validatorsLen := b.validatorsLen()
withdrawalIndex := b.nextWithdrawalIndex
epoch := slots.ToEpoch(b.slot)
// Electra partial withdrawals functionality.
var processedPartialWithdrawalsCount uint64
if b.version >= version.Electra {
for _, w := range b.pendingPartialWithdrawals {
if w.WithdrawableEpoch > epoch || len(withdrawals) >= int(params.BeaconConfig().MaxPendingPartialsPerWithdrawalsSweep) {
break
}
v, err := b.validatorAtIndexReadOnly(w.Index)
if err != nil {
return nil, 0, fmt.Errorf("failed to determine withdrawals at index %d: %w", w.Index, err)
}
vBal, err := b.balanceAtIndex(w.Index)
if err != nil {
return nil, 0, fmt.Errorf("could not retrieve balance at index %d: %w", w.Index, err)
}
hasSufficientEffectiveBalance := v.EffectiveBalance() >= params.BeaconConfig().MinActivationBalance
var totalWithdrawn uint64
for _, wi := range withdrawals {
if wi.ValidatorIndex == w.Index {
totalWithdrawn += wi.Amount
}
}
balance, err := mathutil.Sub64(vBal, totalWithdrawn)
if err != nil {
return nil, 0, errors.Wrapf(err, "failed to subtract balance %d with total withdrawn %d", vBal, totalWithdrawn)
}
hasExcessBalance := balance > params.BeaconConfig().MinActivationBalance
if v.ExitEpoch() == params.BeaconConfig().FarFutureEpoch && hasSufficientEffectiveBalance && hasExcessBalance {
amount := min(balance-params.BeaconConfig().MinActivationBalance, w.Amount)
withdrawals = append(withdrawals, &enginev1.Withdrawal{
Index: withdrawalIndex,
ValidatorIndex: w.Index,
Address: v.GetWithdrawalCredentials()[12:],
Amount: amount,
})
withdrawalIndex++
}
processedPartialWithdrawalsCount++
}
}
validatorsLen := b.validatorsLen()
bound := min(uint64(validatorsLen), params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep)
for range bound {
val, err := b.validatorAtIndexReadOnly(validatorIndex)
if err != nil {
return errors.Wrapf(err, "could not retrieve validator at index %d", validatorIndex)
return nil, 0, errors.Wrapf(err, "could not retrieve validator at index %d", validatorIndex)
}
balance, err := b.balanceAtIndex(validatorIndex)
if err != nil {
return errors.Wrapf(err, "could not retrieve balance at index %d", validatorIndex)
return nil, 0, errors.Wrapf(err, "could not retrieve balance at index %d", validatorIndex)
}
if b.version >= version.Electra {
var partiallyWithdrawnBalance uint64
for _, w := range ws {
for _, w := range withdrawals {
if w.ValidatorIndex == validatorIndex {
partiallyWithdrawnBalance += w.Amount
}
}
balance, err = mathutil.Sub64(balance, partiallyWithdrawnBalance)
if err != nil {
return errors.Wrapf(err, "could not subtract balance %d with partial withdrawn balance %d", balance, partiallyWithdrawnBalance)
return nil, 0, errors.Wrapf(err, "could not subtract balance %d with partial withdrawn balance %d", balance, partiallyWithdrawnBalance)
}
}
if helpers.IsFullyWithdrawableValidator(val, balance, epoch, b.version) {
ws = append(ws, &enginev1.Withdrawal{
withdrawals = append(withdrawals, &enginev1.Withdrawal{
Index: withdrawalIndex,
ValidatorIndex: validatorIndex,
Address: bytesutil.SafeCopyBytes(val.GetWithdrawalCredentials()[ETH1AddressOffset:]),
@@ -214,7 +191,7 @@ func (b *BeaconState) appendValidatorsSweepWithdrawals(withdrawalIndex uint64, w
})
withdrawalIndex++
} else if helpers.IsPartiallyWithdrawableValidator(val, balance, epoch, b.version) {
ws = append(ws, &enginev1.Withdrawal{
withdrawals = append(withdrawals, &enginev1.Withdrawal{
Index: withdrawalIndex,
ValidatorIndex: validatorIndex,
Address: bytesutil.SafeCopyBytes(val.GetWithdrawalCredentials()[ETH1AddressOffset:]),
@@ -222,7 +199,7 @@ func (b *BeaconState) appendValidatorsSweepWithdrawals(withdrawalIndex uint64, w
})
withdrawalIndex++
}
if uint64(len(ws)) == params.BeaconConfig().MaxWithdrawalsPerPayload {
if uint64(len(withdrawals)) == params.BeaconConfig().MaxWithdrawalsPerPayload {
break
}
validatorIndex += 1
@@ -231,8 +208,7 @@ func (b *BeaconState) appendValidatorsSweepWithdrawals(withdrawalIndex uint64, w
}
}
*withdrawals = ws
return nil
return withdrawals, processedPartialWithdrawalsCount, nil
}
func (b *BeaconState) PendingPartialWithdrawals() ([]*ethpb.PendingPartialWithdrawal, error) {

View File

@@ -1,3 +0,0 @@
### Ignored
- add `cmd` and all it's subcategories to the log.go generation process.

View File

@@ -1,3 +0,0 @@
### Added
- Added a version log at startup to display the version of the build.

View File

@@ -1,3 +0,0 @@
### Fixed
- Fixed a bug in `hack/check-logs.sh` where untracked files were ignored.

View File

@@ -1,3 +0,0 @@
### Ignored
- optimizing /eth/v1/beacon/blocks/{block_id}/root endpoint by reusing blocker lookup instead of duplicated logic.

View File

@@ -1,2 +0,0 @@
### Fixed
- Fix hashtree release builds.

View File

@@ -0,0 +1,3 @@
### Added
- Added process attestation for gloas

View File

@@ -1,2 +0,0 @@
### Ignored
- Move withdrawal/consolidation request processing into `beacon-chain/core/requests` to avoid fork/package dependency cycles.

View File

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

View File

@@ -1,2 +0,0 @@
### Ignored
- Refactor expected withdrawals into reusable helpers for future forks.

View File

@@ -9,7 +9,6 @@ go_library(
"defaults.go",
"flags.go",
"helpers.go",
"log.go",
"password_reader.go",
"wrap_flags.go",
],

View File

@@ -2,10 +2,7 @@ load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"db.go",
"log.go",
],
srcs = ["db.go"],
importpath = "github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/db",
visibility = ["//visibility:public"],
deps = [

View File

@@ -4,9 +4,12 @@ import (
beacondb "github.com/OffchainLabs/prysm/v7/beacon-chain/db"
"github.com/OffchainLabs/prysm/v7/cmd"
"github.com/OffchainLabs/prysm/v7/runtime/tos"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
var log = logrus.WithField("prefix", "db")
// Commands for interacting with a beacon chain database.
var Commands = &cli.Command{
Name: "db",

View File

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

View File

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

View File

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

View File

@@ -2,10 +2,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"jwt.go",
"log.go",
],
srcs = ["jwt.go"],
importpath = "github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/jwt",
visibility = ["//visibility:public"],
deps = [

View File

@@ -6,6 +6,7 @@ import (
"github.com/OffchainLabs/prysm/v7/api"
"github.com/OffchainLabs/prysm/v7/cmd"
"github.com/OffchainLabs/prysm/v7/io/file"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
@@ -22,7 +23,7 @@ var Commands = &cli.Command{
}),
Action: func(cliCtx *cli.Context) error {
if err := generateAuthSecretInFile(cliCtx); err != nil {
log.WithError(err).Fatal("Could not generate jwt")
logrus.WithError(err).Fatal("Could not generate jwt")
}
return nil
},
@@ -56,6 +57,6 @@ func generateAuthSecretInFile(c *cli.Context) error {
if err := file.WriteFile(fileName, []byte(secret)); err != nil {
return err
}
log.Infof("Successfully wrote JSON-RPC authentication secret to file %s", fileName)
logrus.Infof("Successfully wrote JSON-RPC authentication secret to file %s", fileName)
return nil
}

View File

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

View File

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

View File

@@ -243,11 +243,6 @@ func before(ctx *cli.Context) error {
}
}
// Log Prysm version on startup. After initializing log-file and ephemeral log-file.
log.WithFields(logrus.Fields{
"version": version.Version(),
}).Info("Prysm Beacon Chain started")
if err := cmd.ExpandSingleEndpointIfFile(ctx, flags.ExecutionEngineEndpoint); err != nil {
return errors.Wrap(err, "failed to expand single endpoint")
}

View File

@@ -2,10 +2,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"log.go",
"options.go",
],
srcs = ["options.go"],
importpath = "github.com/OffchainLabs/prysm/v7/cmd/beacon-chain/storage",
visibility = ["//visibility:public"],
deps = [

View File

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

View File

@@ -15,6 +15,7 @@ import (
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

View File

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

View File

@@ -14,6 +14,8 @@ import (
"github.com/urfave/cli/v2"
)
var log = logrus.WithField("prefix", "node")
// ConfirmAction uses the passed in actionText as the confirmation text displayed in the terminal.
// The user must enter Y or N to indicate whether they confirm the action detailed in the warning text.
// Returns a boolean representing the user's answer.

View File

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

View File

@@ -4,10 +4,7 @@ load("//tools:prysm_image.bzl", "prysm_image_upload")
go_library(
name = "go_default_library",
srcs = [
"log.go",
"main.go",
],
srcs = ["main.go"],
importpath = "github.com/OffchainLabs/prysm/v7/cmd/prysmctl",
visibility = ["//visibility:private"],
deps = [

View File

@@ -5,7 +5,6 @@ go_library(
srcs = [
"cmd.go",
"download.go",
"log.go",
],
importpath = "github.com/OffchainLabs/prysm/v7/cmd/prysmctl/checkpointsync",
visibility = ["//visibility:public"],

View File

@@ -8,6 +8,7 @@ import (
"github.com/OffchainLabs/prysm/v7/api/client"
"github.com/OffchainLabs/prysm/v7/api/client/beacon"
"github.com/OffchainLabs/prysm/v7/beacon-chain/sync/checkpoint"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

View File

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

View File

@@ -5,7 +5,6 @@ go_library(
srcs = [
"buckets.go",
"cmd.go",
"log.go",
"query.go",
"span.go",
],

View File

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

View File

@@ -8,6 +8,7 @@ import (
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
bolt "go.etcd.io/bbolt"
)

View File

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

View File

@@ -9,6 +9,7 @@ import (
"github.com/OffchainLabs/prysm/v7/cmd/prysmctl/testnet"
"github.com/OffchainLabs/prysm/v7/cmd/prysmctl/validator"
"github.com/OffchainLabs/prysm/v7/cmd/prysmctl/weaksubjectivity"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

View File

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

View File

@@ -4,7 +4,6 @@ go_library(
name = "go_default_library",
srcs = [
"generate_genesis.go",
"log.go",
"testnet.go",
],
importpath = "github.com/OffchainLabs/prysm/v7/cmd/prysmctl/testnet",

View File

@@ -43,6 +43,7 @@ var (
GethGenesisJsonIn string
GethGenesisJsonOut string
}{}
log = logrus.WithField("prefix", "genesis")
outputSSZFlag = &cli.StringFlag{
Name: "output-ssz",
Destination: &generateGenesisStateFlags.OutputSSZ,

View File

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

View File

@@ -5,7 +5,6 @@ go_library(
srcs = [
"cmd.go",
"error.go",
"log.go",
"proposer_settings.go",
"withdraw.go",
],

View File

@@ -10,6 +10,7 @@ import (
"github.com/OffchainLabs/prysm/v7/config/features"
"github.com/OffchainLabs/prysm/v7/runtime/tos"
"github.com/logrusorgru/aurora"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

View File

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

View File

@@ -16,6 +16,7 @@ import (
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
validatorpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1/validator-client"
"github.com/ethereum/go-ethereum/common"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

View File

@@ -18,7 +18,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/logrusorgru/aurora"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
@@ -143,7 +143,7 @@ func checkIfWithdrawsAreInPool(ctx context.Context, client *beacon.Client, reque
}
if len(requestMap) != 0 {
for key, address := range requestMap {
log.WithFields(logrus.Fields{
log.WithFields(log.Fields{
"validatorIndex": key,
"executionAddress:": address,
}).Warn("Set withdrawal address message not found in the node's operations pool.")

View File

@@ -5,7 +5,6 @@ go_library(
srcs = [
"checkpoint.go",
"cmd.go",
"log.go",
],
importpath = "github.com/OffchainLabs/prysm/v7/cmd/prysmctl/weaksubjectivity",
visibility = ["//visibility:public"],

View File

@@ -8,6 +8,7 @@ import (
"github.com/OffchainLabs/prysm/v7/api/client"
"github.com/OffchainLabs/prysm/v7/api/client/beacon"
"github.com/OffchainLabs/prysm/v7/beacon-chain/sync/checkpoint"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

View File

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

View File

@@ -5,7 +5,6 @@ load("//tools:prysm_image.bzl", "prysm_image_upload")
go_library(
name = "go_default_library",
srcs = [
"log.go",
"main.go",
"usage.go",
],

View File

@@ -9,7 +9,6 @@ go_library(
"exit.go",
"import.go",
"list.go",
"log.go",
"wallet_utils.go",
],
importpath = "github.com/OffchainLabs/prysm/v7/cmd/validator/accounts",

View File

@@ -7,9 +7,12 @@ import (
"github.com/OffchainLabs/prysm/v7/cmd/validator/flags"
"github.com/OffchainLabs/prysm/v7/config/features"
"github.com/OffchainLabs/prysm/v7/runtime/tos"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
var log = logrus.WithField("prefix", "accounts")
// Commands for managing Prysm validator accounts.
var Commands = &cli.Command{
Name: "accounts",

View File

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

View File

@@ -2,10 +2,7 @@ load("@prysm//tools/go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"db.go",
"log.go",
],
srcs = ["db.go"],
importpath = "github.com/OffchainLabs/prysm/v7/cmd/validator/db",
visibility = ["//visibility:public"],
deps = [

View File

@@ -4,9 +4,12 @@ import (
"github.com/OffchainLabs/prysm/v7/cmd"
"github.com/OffchainLabs/prysm/v7/runtime/tos"
validatordb "github.com/OffchainLabs/prysm/v7/validator/db"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
var log = logrus.WithField("prefix", "db")
var (
// SourceDataDirFlag defines a path on disk where source Prysm databases are stored. Used for conversion.
SourceDataDirFlag = &cli.StringFlag{

View File

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

View File

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

View File

@@ -34,6 +34,8 @@ import (
"github.com/urfave/cli/v2"
)
var log = logrus.WithField("prefix", "main")
func startNode(ctx *cli.Context) error {
// Verify if ToS is accepted.
if err := tos.VerifyTosAcceptedOrPrompt(ctx); err != nil {
@@ -219,11 +221,6 @@ func main() {
}
}
// Log Prysm version on startup. After initializing log-file and ephemeral log-file.
log.WithFields(logrus.Fields{
"version": version.Version(),
}).Info("Prysm Validator started")
// Fix data dir for Windows users.
outdatedDataDir := filepath.Join(file.HomeDir(), "AppData", "Roaming", "Eth2Validators")
currentDataDir := flags.DefaultValidatorDir()

View File

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

View File

@@ -4,7 +4,6 @@ go_library(
name = "go_default_library",
srcs = [
"create.go",
"log.go",
"recover.go",
"wallet.go",
],

View File

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

View File

@@ -5,9 +5,12 @@ import (
"github.com/OffchainLabs/prysm/v7/cmd/validator/flags"
"github.com/OffchainLabs/prysm/v7/config/features"
"github.com/OffchainLabs/prysm/v7/runtime/tos"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
var log = logrus.WithField("prefix", "wallet")
// Commands for wallets for Prysm validators.
var Commands = &cli.Command{
Name: "wallet",

View File

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

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More