mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 22:07:59 -05:00
Compare commits
53 Commits
v3.1.2
...
capella-ba
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5854b91f79 | ||
|
|
60e6306107 | ||
|
|
42ccb7830a | ||
|
|
0bb03b9292 | ||
|
|
ed6fbf1480 | ||
|
|
477cec6021 | ||
|
|
de97f9aeb3 | ||
|
|
924500d111 | ||
|
|
2347d38fa0 | ||
|
|
a1c7fe62fb | ||
|
|
0677504ef1 | ||
|
|
ca2a7c4d9c | ||
|
|
0a203ffb0f | ||
|
|
e709d56607 | ||
|
|
28606629ad | ||
|
|
c817279464 | ||
|
|
009d6ed8ed | ||
|
|
5cec1282a9 | ||
|
|
340170fd29 | ||
|
|
7ed0cc139a | ||
|
|
c7621eb0fb | ||
|
|
e2fa06b41d | ||
|
|
2c822213eb | ||
|
|
c08bb39ffe | ||
|
|
5083d8ab34 | ||
|
|
7552a5dd07 | ||
|
|
c93d68f853 | ||
|
|
3e8aa4023d | ||
|
|
b443875e66 | ||
|
|
8ade8afb73 | ||
|
|
872021f10d | ||
|
|
bb09295072 | ||
|
|
e4b2b1ea7d | ||
|
|
ead329e610 | ||
|
|
a0c5669511 | ||
|
|
0fd5253915 | ||
|
|
86e855d499 | ||
|
|
001ae30a59 | ||
|
|
d1f0e5dd55 | ||
|
|
2142b13a41 | ||
|
|
ffac232d89 | ||
|
|
26b46301d2 | ||
|
|
fdf913aed9 | ||
|
|
9435d10652 | ||
|
|
8fa481cb93 | ||
|
|
26087d7b2d | ||
|
|
5a3a01090a | ||
|
|
55690de685 | ||
|
|
007c776d8a | ||
|
|
a15e0797e4 | ||
|
|
1572c530b5 | ||
|
|
652303522f | ||
|
|
39a7988e9e |
2
.bazelrc
2
.bazelrc
@@ -21,7 +21,6 @@ build --sandbox_default_allow_network=false
|
||||
|
||||
# Stamp binaries with git information
|
||||
build --workspace_status_command=./hack/workspace_status.sh
|
||||
build --stamp
|
||||
|
||||
# Prevent PATH changes from rebuilding when switching from IDE to command line.
|
||||
build --incompatible_strict_action_env
|
||||
@@ -38,7 +37,6 @@ build:minimal --@io_bazel_rules_go//go/config:tags=minimal
|
||||
|
||||
# Release flags
|
||||
build:release --compilation_mode=opt
|
||||
build:release --config=llvm
|
||||
|
||||
# LLVM compiler for building C/C++ dependencies.
|
||||
build:llvm --define compiler=llvm
|
||||
|
||||
@@ -304,31 +304,6 @@ func TestService_HeadGenesisValidatorsRoot(t *testing.T) {
|
||||
root = c.HeadGenesisValidatorsRoot()
|
||||
require.DeepEqual(t, root[:], s.GenesisValidatorsRoot())
|
||||
}
|
||||
func TestService_ChainHeads_ProtoArray(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
c := &Service{cfg: &config{ForkChoiceStore: doublylinkedtree.New()}}
|
||||
ojc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
ofc := ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}
|
||||
st, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, [32]byte{}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 103, [32]byte{'d'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
st, blkRoot, err = prepareForkchoiceState(ctx, 104, [32]byte{'e'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.cfg.ForkChoiceStore.InsertNode(ctx, st, blkRoot))
|
||||
|
||||
roots, slots := c.ChainHeads()
|
||||
require.DeepEqual(t, [][32]byte{{'c'}, {'d'}, {'e'}}, roots)
|
||||
require.DeepEqual(t, []types.Slot{102, 103, 104}, slots)
|
||||
}
|
||||
|
||||
//
|
||||
// A <- B <- C
|
||||
|
||||
@@ -14,7 +14,7 @@ var (
|
||||
// errNilFinalizedCheckpoint is returned when a nil finalized checkpt is returned from a state.
|
||||
errNilFinalizedCheckpoint = errors.New("nil finalized checkpoint returned from state")
|
||||
// errNilJustifiedCheckpoint is returned when a nil justified checkpt is returned from a state.
|
||||
errNilJustifiedCheckpoint = errors.New("nil finalized checkpoint returned from state")
|
||||
errNilJustifiedCheckpoint = errors.New("nil justified checkpoint returned from state")
|
||||
// errInvalidNilSummary is returned when a nil summary is returned from the DB.
|
||||
errInvalidNilSummary = errors.New("nil summary returned from the DB")
|
||||
// errWrongBlockCount is returned when the wrong number of blocks or block roots is used
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
)
|
||||
|
||||
var defaultLatestValidHash = bytesutil.PadTo([]byte{0xff}, 32)
|
||||
var errNoAttribute = errors.New("could not get payload attributes")
|
||||
|
||||
// notifyForkchoiceUpdateArg is the argument for the forkchoice update notification `notifyForkchoiceUpdate`.
|
||||
type notifyForkchoiceUpdateArg struct {
|
||||
@@ -32,6 +33,58 @@ type notifyForkchoiceUpdateArg struct {
|
||||
headBlock interfaces.BeaconBlock
|
||||
}
|
||||
|
||||
type callForkchoiceUpdatedReturn struct {
|
||||
hasAttr bool
|
||||
proposerId types.ValidatorIndex
|
||||
payloadID *enginev1.PayloadIDBytes
|
||||
lastValidHash []byte
|
||||
err error
|
||||
}
|
||||
|
||||
// callFforkchoiceUpdatedV1 wraps a call to the engine methods `engine_forkchoiceUpdatedV1`
|
||||
func (s *Service) callForkchoiceUpdatedV1(
|
||||
ctx context.Context,
|
||||
st state.BeaconState,
|
||||
nextSlot types.Slot,
|
||||
fcs *enginev1.ForkchoiceState) callForkchoiceUpdatedReturn {
|
||||
|
||||
hasAttr, attr, proposerId, err := s.getPayloadAttribute(ctx, st, nextSlot)
|
||||
if err != nil {
|
||||
return callForkchoiceUpdatedReturn{false, 0, nil, nil, errNoAttribute}
|
||||
}
|
||||
|
||||
payloadID, lastValidHash, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdated(ctx, fcs, attr)
|
||||
return callForkchoiceUpdatedReturn{
|
||||
hasAttr: hasAttr,
|
||||
proposerId: proposerId,
|
||||
payloadID: payloadID,
|
||||
lastValidHash: lastValidHash,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// callFforkchoiceUpdatedV2 wraps a call to the engine methods `engine_forkchoiceUpdatedV2`
|
||||
func (s *Service) callForkchoiceUpdatedV2(
|
||||
ctx context.Context,
|
||||
st state.BeaconState,
|
||||
nextSlot types.Slot,
|
||||
fcs *enginev1.ForkchoiceState) callForkchoiceUpdatedReturn {
|
||||
|
||||
hasAttr, attr, proposerId, err := s.getPayloadAttributeV2(ctx, st, nextSlot)
|
||||
if err != nil {
|
||||
return callForkchoiceUpdatedReturn{false, 0, nil, nil, errNoAttribute}
|
||||
}
|
||||
|
||||
payloadID, lastValidHash, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdatedV2(ctx, fcs, attr)
|
||||
return callForkchoiceUpdatedReturn{
|
||||
hasAttr: hasAttr,
|
||||
proposerId: proposerId,
|
||||
payloadID: payloadID,
|
||||
lastValidHash: lastValidHash,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// notifyForkchoiceUpdate signals execution engine the fork choice updates. Execution engine should:
|
||||
// 1. Re-organizes the execution payload chain and corresponding state to make head_block_hash the head.
|
||||
// 2. Applies finality to the execution state: it irreversibly persists the chain of all execution payloads and corresponding state, up to and including finalized_block_hash.
|
||||
@@ -67,15 +120,16 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
}
|
||||
|
||||
nextSlot := s.CurrentSlot() + 1 // Cache payload ID for next slot proposer.
|
||||
hasAttr, attr, proposerId, err := s.getPayloadAttribute(ctx, arg.headState, nextSlot)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not get head payload attribute")
|
||||
return nil, nil
|
||||
var fcuReturn callForkchoiceUpdatedReturn
|
||||
if slots.ToEpoch(nextSlot) >= params.BeaconConfig().CapellaForkEpoch {
|
||||
fcuReturn = s.callForkchoiceUpdatedV2(ctx, arg.headState, nextSlot, fcs)
|
||||
} else {
|
||||
fcuReturn = s.callForkchoiceUpdatedV1(ctx, arg.headState, nextSlot, fcs)
|
||||
}
|
||||
|
||||
payloadID, lastValidHash, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdated(ctx, fcs, attr)
|
||||
if err != nil {
|
||||
switch err {
|
||||
if fcuReturn.err != nil {
|
||||
switch fcuReturn.err {
|
||||
case errNoAttribute:
|
||||
return nil, errNoAttribute
|
||||
case execution.ErrAcceptedSyncingPayloadStatus:
|
||||
forkchoiceUpdatedOptimisticNodeCount.Inc()
|
||||
log.WithFields(logrus.Fields{
|
||||
@@ -83,14 +137,14 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
"headPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(headPayload.BlockHash())),
|
||||
"finalizedPayloadBlockHash": fmt.Sprintf("%#x", bytesutil.Trunc(finalizedHash[:])),
|
||||
}).Info("Called fork choice updated with optimistic block")
|
||||
return payloadID, nil
|
||||
return fcuReturn.payloadID, nil
|
||||
case execution.ErrInvalidPayloadStatus:
|
||||
forkchoiceUpdatedInvalidNodeCount.Inc()
|
||||
headRoot := arg.headRoot
|
||||
if len(lastValidHash) == 0 {
|
||||
lastValidHash = defaultLatestValidHash
|
||||
if len(fcuReturn.lastValidHash) == 0 {
|
||||
fcuReturn.lastValidHash = defaultLatestValidHash
|
||||
}
|
||||
invalidRoots, err := s.ForkChoicer().SetOptimisticToInvalid(ctx, headRoot, headBlk.ParentRoot(), bytesutil.ToBytes32(lastValidHash))
|
||||
invalidRoots, err := s.ForkChoicer().SetOptimisticToInvalid(ctx, headRoot, headBlk.ParentRoot(), bytesutil.ToBytes32(fcuReturn.lastValidHash))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not set head root to invalid")
|
||||
return nil, nil
|
||||
@@ -150,17 +204,23 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
|
||||
log.WithError(err).Error("Could not set head root to valid")
|
||||
return nil, nil
|
||||
}
|
||||
if hasAttr && payloadID != nil { // If the forkchoice update call has an attribute, update the proposer payload ID cache.
|
||||
// If the forkchoice update call has an attribute, update the proposer payload ID cache.
|
||||
if fcuReturn.hasAttr && fcuReturn.payloadID != nil {
|
||||
var pId [8]byte
|
||||
copy(pId[:], payloadID[:])
|
||||
s.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(nextSlot, proposerId, pId, arg.headRoot)
|
||||
} else if hasAttr && payloadID == nil {
|
||||
copy(pId[:], fcuReturn.payloadID[:])
|
||||
s.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(
|
||||
nextSlot,
|
||||
fcuReturn.proposerId,
|
||||
pId,
|
||||
arg.headRoot,
|
||||
)
|
||||
} else if fcuReturn.hasAttr && fcuReturn.payloadID == nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"blockHash": fmt.Sprintf("%#x", headPayload.BlockHash()),
|
||||
"slot": headBlk.Slot(),
|
||||
}).Error("Received nil payload ID on VALID engine response")
|
||||
}
|
||||
return payloadID, nil
|
||||
return fcuReturn.payloadID, nil
|
||||
}
|
||||
|
||||
// getPayloadHash returns the payload hash given the block root.
|
||||
@@ -180,7 +240,7 @@ func (s *Service) getPayloadHash(ctx context.Context, root []byte) ([32]byte, er
|
||||
return bytesutil.ToBytes32(payload.BlockHash()), nil
|
||||
}
|
||||
|
||||
// notifyForkchoiceUpdate signals execution engine on a new payload.
|
||||
// notifyNewPayload signals execution engine on a new payload.
|
||||
// It returns true if the EL has returned VALID for the block
|
||||
func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
|
||||
postStateHeader interfaces.ExecutionData, blk interfaces.SignedBeaconBlock) (bool, error) {
|
||||
@@ -302,6 +362,68 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
|
||||
return true, attr, proposerID, nil
|
||||
}
|
||||
|
||||
// getPayloadAttributesV2 returns the payload attributes for the given state and slot.
|
||||
// The attribute is required to initiate a payload build process in the context of an `engine_forkchoiceUpdatedV2` call.
|
||||
func (s *Service) getPayloadAttributeV2(
|
||||
ctx context.Context,
|
||||
st state.BeaconState,
|
||||
slot types.Slot) (bool, *enginev1.PayloadAttributesV2, types.ValidatorIndex, error) {
|
||||
// Root is `[32]byte{}` since we are retrieving proposer ID of a given slot.
|
||||
// During insertion at assignment the root was not known.
|
||||
proposerID, _, ok := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, [32]byte{} /* root */)
|
||||
if !ok { // There's no need to build attribute if there is no proposer for slot.
|
||||
return false, nil, 0, nil
|
||||
}
|
||||
|
||||
// Get previous randao.
|
||||
st = st.Copy()
|
||||
st, err := transition.ProcessSlotsIfPossible(ctx, st, slot)
|
||||
if err != nil {
|
||||
return false, nil, 0, err
|
||||
}
|
||||
prevRando, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
||||
if err != nil {
|
||||
return false, nil, 0, nil
|
||||
}
|
||||
|
||||
// Get fee recipient.
|
||||
feeRecipient := params.BeaconConfig().DefaultFeeRecipient
|
||||
recipient, err := s.cfg.BeaconDB.FeeRecipientByValidatorID(ctx, proposerID)
|
||||
switch {
|
||||
case errors.Is(err, kv.ErrNotFoundFeeRecipient):
|
||||
if feeRecipient.String() == params.BeaconConfig().EthBurnAddressHex {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"validatorIndex": proposerID,
|
||||
"burnAddress": params.BeaconConfig().EthBurnAddressHex,
|
||||
}).Warn("Fee recipient is currently using the burn address, " +
|
||||
"you will not be rewarded transaction fees on this setting. " +
|
||||
"Please set a different eth address as the fee recipient. " +
|
||||
"Please refer to our documentation for instructions")
|
||||
}
|
||||
case err != nil:
|
||||
return false, nil, 0, errors.Wrap(err, "could not get fee recipient in db")
|
||||
default:
|
||||
feeRecipient = recipient
|
||||
}
|
||||
|
||||
// Get timestamp.
|
||||
t, err := slots.ToTime(uint64(s.genesisTime.Unix()), slot)
|
||||
if err != nil {
|
||||
return false, nil, 0, err
|
||||
}
|
||||
withdrawals, err := st.ExpectedWithdrawals()
|
||||
if err != nil {
|
||||
return false, nil, 0, errors.Wrap(err, "could not get expected withdrawals")
|
||||
}
|
||||
attr := &enginev1.PayloadAttributesV2{
|
||||
Timestamp: uint64(t.Unix()),
|
||||
PrevRandao: prevRando,
|
||||
SuggestedFeeRecipient: feeRecipient.Bytes(),
|
||||
Withdrawals: withdrawals,
|
||||
}
|
||||
return true, attr, proposerID, nil
|
||||
}
|
||||
|
||||
// removeInvalidBlockAndState removes the invalid block and its corresponding state from the cache and DB.
|
||||
func (s *Service) removeInvalidBlockAndState(ctx context.Context, blkRoots [][32]byte) error {
|
||||
for _, root := range blkRoots {
|
||||
|
||||
@@ -117,12 +117,20 @@ func logPayload(block interfaces.BeaconBlock) error {
|
||||
return errors.New("gas limit should not be 0")
|
||||
}
|
||||
gasUtilized := float64(payload.GasUsed()) / float64(payload.GasLimit())
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
fields := logrus.Fields{
|
||||
"blockHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.BlockHash())),
|
||||
"parentHash": fmt.Sprintf("%#x", bytesutil.Trunc(payload.ParentHash())),
|
||||
"blockNumber": payload.BlockNumber,
|
||||
"gasUtilized": fmt.Sprintf("%.2f", gasUtilized),
|
||||
}).Debug("Synced new payload")
|
||||
}
|
||||
if block.Version() >= version.Capella {
|
||||
withdrawals, err := payload.Withdrawals()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get withdrawals")
|
||||
}
|
||||
fields["withdrawals"] = len(withdrawals)
|
||||
}
|
||||
|
||||
log.WithFields(fields).Debug("Synced new payload")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -328,7 +328,7 @@ func reportEpochMetrics(ctx context.Context, postState, headState state.BeaconSt
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case version.Altair, version.Bellatrix:
|
||||
case version.Altair, version.Bellatrix, version.Capella:
|
||||
v, b, err = altair.InitializePrecomputeValidators(ctx, headState)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -1989,216 +1989,6 @@ func TestStore_NoViableHead_Liveness(t *testing.T) {
|
||||
require.Equal(t, false, optimistic)
|
||||
}
|
||||
|
||||
// See the description in #10777 and #10782 for the full setup
|
||||
// We sync optimistically a chain of blocks. Block 12 is the first block in Epoch
|
||||
// 2 (and the merge block in this sequence). Block 18 justifies it and Block 19 returns
|
||||
// INVALID from NewPayload, with LVH block 12. No head is viable. We check
|
||||
// that the node is optimistic and that we can actually import a chain of blocks on top of
|
||||
// 12 and recover. Notice that it takes two epochs to fully recover, and we stay
|
||||
// optimistic for the whole time.
|
||||
func TestStore_NoViableHead_Liveness_Protoarray(t *testing.T) {
|
||||
params.SetupTestConfigCleanup(t)
|
||||
config := params.BeaconConfig()
|
||||
config.SlotsPerEpoch = 6
|
||||
config.AltairForkEpoch = 1
|
||||
config.BellatrixForkEpoch = 2
|
||||
params.OverrideBeaconConfig(config)
|
||||
|
||||
ctx := context.Background()
|
||||
beaconDB := testDB.SetupDB(t)
|
||||
|
||||
mockEngine := &mockExecution.EngineClient{ErrNewPayload: execution.ErrAcceptedSyncingPayloadStatus, ErrForkchoiceUpdated: execution.ErrAcceptedSyncingPayloadStatus}
|
||||
fc := doublylinkedtree.New()
|
||||
opts := []Option{
|
||||
WithDatabase(beaconDB),
|
||||
WithAttestationPool(attestations.NewPool()),
|
||||
WithStateGen(stategen.New(beaconDB, fc)),
|
||||
WithForkChoiceStore(fc),
|
||||
WithStateNotifier(&mock.MockStateNotifier{}),
|
||||
WithExecutionEngineCaller(mockEngine),
|
||||
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
|
||||
}
|
||||
service, err := NewService(ctx, opts...)
|
||||
require.NoError(t, err)
|
||||
|
||||
st, keys := util.DeterministicGenesisState(t, 64)
|
||||
stateRoot, err := st.HashTreeRoot(ctx)
|
||||
require.NoError(t, err, "Could not hash genesis state")
|
||||
|
||||
require.NoError(t, service.saveGenesisData(ctx, st))
|
||||
|
||||
genesis := blocks.NewGenesisBlock(stateRoot[:])
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(genesis)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb), "Could not save genesis block")
|
||||
|
||||
parentRoot, err := genesis.Block.HashTreeRoot()
|
||||
require.NoError(t, err, "Could not get signing root")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, st, parentRoot), "Could not save genesis state")
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
|
||||
|
||||
for i := 1; i < 6; i++ {
|
||||
driftGenesisTime(service, int64(i), 0)
|
||||
st, err := service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
b, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), types.Slot(i))
|
||||
require.NoError(t, err)
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.onBlock(ctx, wsb, root))
|
||||
}
|
||||
|
||||
for i := 6; i < 12; i++ {
|
||||
driftGenesisTime(service, int64(i), 0)
|
||||
st, err := service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
b, err := util.GenerateFullBlockAltair(st, keys, util.DefaultBlockGenConfig(), types.Slot(i))
|
||||
require.NoError(t, err)
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
err = service.onBlock(ctx, wsb, root)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// import the merge block
|
||||
driftGenesisTime(service, 12, 0)
|
||||
st, err = service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
b, err := util.GenerateFullBlockBellatrix(st, keys, util.DefaultBlockGenConfig(), 12)
|
||||
require.NoError(t, err)
|
||||
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
lastValidRoot, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
err = service.onBlock(ctx, wsb, lastValidRoot)
|
||||
require.NoError(t, err)
|
||||
// save the post state and the payload Hash of this block since it will
|
||||
// be the LVH
|
||||
validHeadState, err := service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
lvh := b.Block.Body.ExecutionPayload.BlockHash
|
||||
validjc := validHeadState.CurrentJustifiedCheckpoint()
|
||||
require.Equal(t, types.Epoch(0), validjc.Epoch)
|
||||
|
||||
// import blocks 13 through 18 to justify 12, these are invalid blocks
|
||||
invalidRoots := make([][32]byte, 19-13)
|
||||
for i := 13; i < 19; i++ {
|
||||
driftGenesisTime(service, int64(i), 0)
|
||||
st, err := service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
b, err := util.GenerateFullBlockBellatrix(st, keys, util.DefaultBlockGenConfig(), types.Slot(i))
|
||||
require.NoError(t, err)
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
invalidRoots[i-13], err = b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
err = service.onBlock(ctx, wsb, invalidRoots[i-13])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
// Check that we have justified the second epoch
|
||||
jc := service.ForkChoicer().JustifiedCheckpoint()
|
||||
require.Equal(t, types.Epoch(2), jc.Epoch)
|
||||
invalidHeadRoot := service.ForkChoicer().CachedHeadRoot()
|
||||
|
||||
// import block 19 to find out that the whole chain 13--18 was in fact
|
||||
// invalid
|
||||
mockEngine = &mockExecution.EngineClient{ErrNewPayload: execution.ErrInvalidPayloadStatus, NewPayloadResp: lvh}
|
||||
service.cfg.ExecutionEngineCaller = mockEngine
|
||||
driftGenesisTime(service, 19, 0)
|
||||
st, err = service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
b, err = util.GenerateFullBlockBellatrix(st, keys, util.DefaultBlockGenConfig(), 19)
|
||||
require.NoError(t, err)
|
||||
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
err = service.onBlock(ctx, wsb, root)
|
||||
require.ErrorContains(t, "received an INVALID payload from execution engine", err)
|
||||
|
||||
// Check that forkchoice's head and store's headroot are the previous head (since the invalid block did
|
||||
// not finish importing and it was never imported to forkchoice). Check
|
||||
// also that the node is optimistic
|
||||
require.Equal(t, invalidHeadRoot, service.ForkChoicer().CachedHeadRoot())
|
||||
headRoot, err := service.HeadRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, invalidHeadRoot, bytesutil.ToBytes32(headRoot))
|
||||
optimistic, err := service.IsOptimistic(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, optimistic)
|
||||
|
||||
// Check that the invalid blocks are not in database
|
||||
for i := 0; i < 19-13; i++ {
|
||||
require.Equal(t, false, service.cfg.BeaconDB.HasBlock(ctx, invalidRoots[i]))
|
||||
}
|
||||
|
||||
// Check that the node's justified checkpoint does not agree with the
|
||||
// last valid state's justified checkpoint
|
||||
sjc := service.CurrentJustifiedCheckpt()
|
||||
require.Equal(t, types.Epoch(2), sjc.Epoch)
|
||||
|
||||
// import another block based on the last valid head state
|
||||
mockEngine = &mockExecution.EngineClient{}
|
||||
service.cfg.ExecutionEngineCaller = mockEngine
|
||||
driftGenesisTime(service, 20, 0)
|
||||
b, err = util.GenerateFullBlockBellatrix(validHeadState, keys, &util.BlockGenConfig{}, 20)
|
||||
require.NoError(t, err)
|
||||
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
root, err = b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.onBlock(ctx, wsb, root))
|
||||
// Check that the head is still INVALID and the node is still optimistic
|
||||
require.Equal(t, invalidHeadRoot, service.ForkChoicer().CachedHeadRoot())
|
||||
optimistic, err = service.IsOptimistic(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, optimistic)
|
||||
st, err = service.cfg.StateGen.StateByRoot(ctx, root)
|
||||
require.NoError(t, err)
|
||||
// Import blocks 21--30 (Epoch 3 was not enough to justify 2)
|
||||
for i := 21; i < 30; i++ {
|
||||
driftGenesisTime(service, int64(i), 0)
|
||||
require.NoError(t, err)
|
||||
b, err := util.GenerateFullBlockBellatrix(st, keys, util.DefaultBlockGenConfig(), types.Slot(i))
|
||||
require.NoError(t, err)
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
root, err := b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
err = service.onBlock(ctx, wsb, root)
|
||||
require.NoError(t, err)
|
||||
st, err = service.cfg.StateGen.StateByRoot(ctx, root)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
// Head should still be INVALID and the node optimistic
|
||||
require.Equal(t, invalidHeadRoot, service.ForkChoicer().CachedHeadRoot())
|
||||
optimistic, err = service.IsOptimistic(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, optimistic)
|
||||
|
||||
// Import block 30, it should justify Epoch 4 and become HEAD, the node
|
||||
// recovers
|
||||
driftGenesisTime(service, 30, 0)
|
||||
b, err = util.GenerateFullBlockBellatrix(st, keys, util.DefaultBlockGenConfig(), 30)
|
||||
require.NoError(t, err)
|
||||
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
root, err = b.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
err = service.onBlock(ctx, wsb, root)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, root, service.ForkChoicer().CachedHeadRoot())
|
||||
sjc = service.CurrentJustifiedCheckpt()
|
||||
require.Equal(t, types.Epoch(4), sjc.Epoch)
|
||||
optimistic, err = service.IsOptimistic(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, optimistic)
|
||||
}
|
||||
|
||||
type newForkChoicer func() forkchoice.ForkChoicer
|
||||
|
||||
// See the description in #10777 and #10782 for the full setup
|
||||
|
||||
@@ -226,11 +226,11 @@ func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) {
|
||||
require.Equal(t, 2, fcs.NodeCount())
|
||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb))
|
||||
|
||||
// Generate attestatios for this block in Slot 1
|
||||
// Generate attestations for this block in Slot 1
|
||||
atts, err := util.GenerateAttestations(copied, pks, 1, 1, false)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, service.cfg.AttPool.SaveForkchoiceAttestations(atts))
|
||||
// Verify the target is in forchoice
|
||||
// Verify the target is in forkchoice
|
||||
require.Equal(t, true, fcs.HasNode(bytesutil.ToBytes32(atts[0].Data.BeaconBlockRoot)))
|
||||
|
||||
// Insert a new block to forkchoice
|
||||
|
||||
8
beacon-chain/cache/depositsnapshot/BUILD.bazel
vendored
Normal file
8
beacon-chain/cache/depositsnapshot/BUILD.bazel
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["merkle_tree.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/cache/depositsnapshot",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
19
beacon-chain/cache/depositsnapshot/merkle_tree.go
vendored
Normal file
19
beacon-chain/cache/depositsnapshot/merkle_tree.go
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package depositsnapshot
|
||||
|
||||
const (
|
||||
DepositContractDepth = 32 // Maximum tree depth as defined by EIP-4881.
|
||||
)
|
||||
|
||||
// MerkleTreeNode is the interface for a Merkle tree.
|
||||
type MerkleTreeNode interface {
|
||||
// GetRoot returns the root of the Merkle tree.
|
||||
GetRoot() [32]byte
|
||||
// IsFull returns whether there is space left for deposits.
|
||||
IsFull() bool
|
||||
// Finalize marks deposits of the Merkle tree as finalized.
|
||||
Finalize(deposits uint, depth uint) MerkleTreeNode
|
||||
// GetFinalized returns a list of hashes of all the finalized nodes and the number of deposits.
|
||||
GetFinalized(result [][32]byte) ([][32]byte, uint)
|
||||
// PushLeaf adds a new leaf node at the next available Zero node.
|
||||
PushLeaf(leaf [32]byte, deposits uint, depth uint) MerkleTreeNode
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func (c *SyncCommitteeHeadStateCache) Get(slot types.Slot) (state.BeaconState, e
|
||||
return nil, ErrIncorrectType
|
||||
}
|
||||
switch st.Version() {
|
||||
case version.Altair, version.Bellatrix:
|
||||
case version.Altair, version.Bellatrix, version.Capella:
|
||||
default:
|
||||
return nil, ErrIncorrectType
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ go_library(
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//network/forks:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/attestation:go_default_library",
|
||||
"//proto/prysm/v1alpha1/slashings:go_default_library",
|
||||
|
||||
@@ -33,6 +33,9 @@ func IsMergeTransitionComplete(st state.BeaconState) (bool, error) {
|
||||
if IsPreBellatrixVersion(st.Version()) {
|
||||
return false, nil
|
||||
}
|
||||
if st.Version() > version.Bellatrix {
|
||||
return true, nil
|
||||
}
|
||||
h, err := st.LatestExecutionPayloadHeader()
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -81,6 +84,9 @@ func IsExecutionEnabled(st state.BeaconState, body interfaces.BeaconBlockBody) (
|
||||
if IsPreBellatrixVersion(st.Version()) {
|
||||
return false, nil
|
||||
}
|
||||
if st.Version() > version.Bellatrix {
|
||||
return true, nil
|
||||
}
|
||||
header, err := st.LatestExecutionPayloadHeader()
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -127,6 +133,7 @@ func ValidatePayloadWhenMergeCompletes(st state.BeaconState, payload interfaces.
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(payload.ParentHash(), header.BlockHash()) {
|
||||
log.Errorf("parent Hash %#x, header Hash: %#x", bytesutil.Trunc(payload.ParentHash()), bytesutil.Trunc(header.BlockHash()))
|
||||
return ErrInvalidPayloadBlockHash
|
||||
}
|
||||
return nil
|
||||
@@ -192,21 +199,23 @@ func ValidatePayload(st state.BeaconState, payload interfaces.ExecutionData) err
|
||||
// transactions_root=hash_tree_root(payload.transactions),
|
||||
// )
|
||||
func ProcessPayload(st state.BeaconState, payload interfaces.ExecutionData) (state.BeaconState, error) {
|
||||
if st.Version() >= version.Capella {
|
||||
withdrawals, err := payload.Withdrawals()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get payload withdrawals")
|
||||
}
|
||||
st, err = ProcessWithdrawals(st, withdrawals)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process withdrawals")
|
||||
}
|
||||
}
|
||||
if err := ValidatePayloadWhenMergeCompletes(st, payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ValidatePayload(st, payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
header, err := blocks.PayloadToHeader(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wrappedHeader, err := blocks.WrappedExecutionPayloadHeader(header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := st.SetLatestExecutionPayloadHeader(wrappedHeader); err != nil {
|
||||
if err := st.SetLatestExecutionPayloadHeader(payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st, nil
|
||||
|
||||
@@ -3,11 +3,14 @@ package blocks
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/hash/htr"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
)
|
||||
@@ -76,3 +79,40 @@ func ProcessBLSToExecutionChange(st state.BeaconState, signed *ethpb.SignedBLSTo
|
||||
err = st.UpdateValidatorAtIndex(message.ValidatorIndex, val)
|
||||
return st, err
|
||||
}
|
||||
|
||||
func ProcessWithdrawals(st state.BeaconState, withdrawals []*enginev1.Withdrawal) (state.BeaconState, error) {
|
||||
expected, err := st.ExpectedWithdrawals()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get expected withdrawals")
|
||||
}
|
||||
if len(expected) != len(withdrawals) {
|
||||
return nil, errors.New("invalid number of withdrawals")
|
||||
}
|
||||
for i, withdrawal := range withdrawals {
|
||||
if withdrawal.WithdrawalIndex != expected[i].WithdrawalIndex {
|
||||
return nil, errors.New("invalid withdrawal index")
|
||||
}
|
||||
if withdrawal.ValidatorIndex != expected[i].ValidatorIndex {
|
||||
return nil, errors.New("invalid validator index")
|
||||
}
|
||||
if bytesutil.ToBytes20(withdrawal.ExecutionAddress) != bytesutil.ToBytes20(expected[i].ExecutionAddress) {
|
||||
return nil, errors.New("invalid execution address")
|
||||
}
|
||||
if withdrawal.Amount != expected[i].Amount {
|
||||
return nil, errors.New("invalid withdrawal amount")
|
||||
}
|
||||
err := helpers.DecreaseBalance(st, withdrawal.ValidatorIndex, withdrawal.Amount)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not decrease balance")
|
||||
}
|
||||
}
|
||||
if len(withdrawals) > 0 {
|
||||
if err := st.SetNextWithdrawalIndex(withdrawals[len(withdrawals)-1].WithdrawalIndex + 1); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set withdrawal index")
|
||||
}
|
||||
if err := st.SetLastWithdrawalValidatorIndex(withdrawals[len(withdrawals)-1].ValidatorIndex); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set latest withdrawal validator index")
|
||||
}
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
16
beacon-chain/core/capella/BUILD.bazel
Normal file
16
beacon-chain/core/capella/BUILD.bazel
Normal file
@@ -0,0 +1,16 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["upgrade.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/capella",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/core/time:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
],
|
||||
)
|
||||
96
beacon-chain/core/capella/upgrade.go
Normal file
96
beacon-chain/core/capella/upgrade.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package capella
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// UpgradeToCapella updates a generic state to return the version Capella state.
|
||||
func UpgradeToCapella(state state.BeaconState) (state.BeaconState, error) {
|
||||
epoch := time.CurrentEpoch(state)
|
||||
|
||||
currentSyncCommittee, err := state.CurrentSyncCommittee()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nextSyncCommittee, err := state.NextSyncCommittee()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prevEpochParticipation, err := state.PreviousEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
currentEpochParticipation, err := state.CurrentEpochParticipation()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inactivityScores, err := state.InactivityScores()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payloadHeader, err := state.LatestExecutionPayloadHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txRoot, err := payloadHeader.TransactionsRoot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := ðpb.BeaconStateCapella{
|
||||
GenesisTime: state.GenesisTime(),
|
||||
GenesisValidatorsRoot: state.GenesisValidatorsRoot(),
|
||||
Slot: state.Slot(),
|
||||
Fork: ðpb.Fork{
|
||||
PreviousVersion: state.Fork().CurrentVersion,
|
||||
CurrentVersion: params.BeaconConfig().CapellaForkVersion,
|
||||
Epoch: epoch,
|
||||
},
|
||||
LatestBlockHeader: state.LatestBlockHeader(),
|
||||
BlockRoots: state.BlockRoots(),
|
||||
StateRoots: state.StateRoots(),
|
||||
HistoricalRoots: state.HistoricalRoots(),
|
||||
Eth1Data: state.Eth1Data(),
|
||||
Eth1DataVotes: state.Eth1DataVotes(),
|
||||
Eth1DepositIndex: state.Eth1DepositIndex(),
|
||||
Validators: state.Validators(),
|
||||
Balances: state.Balances(),
|
||||
RandaoMixes: state.RandaoMixes(),
|
||||
Slashings: state.Slashings(),
|
||||
PreviousEpochParticipation: prevEpochParticipation,
|
||||
CurrentEpochParticipation: currentEpochParticipation,
|
||||
JustificationBits: state.JustificationBits(),
|
||||
PreviousJustifiedCheckpoint: state.PreviousJustifiedCheckpoint(),
|
||||
CurrentJustifiedCheckpoint: state.CurrentJustifiedCheckpoint(),
|
||||
FinalizedCheckpoint: state.FinalizedCheckpoint(),
|
||||
InactivityScores: inactivityScores,
|
||||
CurrentSyncCommittee: currentSyncCommittee,
|
||||
NextSyncCommittee: nextSyncCommittee,
|
||||
LatestExecutionPayloadHeader: &enginev1.ExecutionPayloadHeaderCapella{
|
||||
ParentHash: payloadHeader.ParentHash(),
|
||||
FeeRecipient: payloadHeader.FeeRecipient(),
|
||||
StateRoot: payloadHeader.StateRoot(),
|
||||
ReceiptsRoot: payloadHeader.ReceiptsRoot(),
|
||||
LogsBloom: payloadHeader.LogsBloom(),
|
||||
PrevRandao: payloadHeader.PrevRandao(),
|
||||
BlockNumber: payloadHeader.BlockNumber(),
|
||||
GasLimit: payloadHeader.GasLimit(),
|
||||
GasUsed: payloadHeader.GasUsed(),
|
||||
Timestamp: payloadHeader.Timestamp(),
|
||||
ExtraData: payloadHeader.ExtraData(),
|
||||
BaseFeePerGas: payloadHeader.BaseFeePerGas(),
|
||||
BlockHash: payloadHeader.BlockHash(),
|
||||
TransactionsRoot: txRoot,
|
||||
WithdrawalsRoot: make([]byte, 32),
|
||||
},
|
||||
NextWithdrawalIndex: 0,
|
||||
LastWithdrawalValidatorIndex: 0,
|
||||
}
|
||||
|
||||
return state_native.InitializeFromProtoUnsafeCapella(s)
|
||||
}
|
||||
@@ -70,6 +70,15 @@ func CanUpgradeToBellatrix(slot types.Slot) bool {
|
||||
return epochStart && bellatrixEpoch
|
||||
}
|
||||
|
||||
// CanUpgradeToCapella returns true if the input `slot` can upgrade to Capella.
|
||||
// Spec code:
|
||||
// If state.slot % SLOTS_PER_EPOCH == 0 and compute_epoch_at_slot(state.slot) == CAPELLA_FORK_EPOCH
|
||||
func CanUpgradeToCapella(slot types.Slot) bool {
|
||||
epochStart := slots.IsEpochStart(slot)
|
||||
capellaEpoch := slots.ToEpoch(slot) == params.BeaconConfig().CapellaForkEpoch
|
||||
return epochStart && capellaEpoch
|
||||
}
|
||||
|
||||
// CanProcessEpoch checks the eligibility to process epoch.
|
||||
// The epoch can be processed at the end of the last slot of every epoch.
|
||||
//
|
||||
|
||||
@@ -25,6 +25,7 @@ go_library(
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/capella:go_default_library",
|
||||
"//beacon-chain/core/epoch:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/execution:go_default_library",
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/altair"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/capella"
|
||||
e "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/epoch/precompute"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/execution"
|
||||
@@ -255,7 +256,7 @@ func ProcessSlots(ctx context.Context, state state.BeaconState, slot types.Slot)
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, errors.Wrap(err, "could not process epoch with optimizations")
|
||||
}
|
||||
case version.Altair, version.Bellatrix:
|
||||
case version.Altair, version.Bellatrix, version.Capella:
|
||||
state, err = altair.ProcessEpoch(ctx, state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
@@ -285,6 +286,14 @@ func ProcessSlots(ctx context.Context, state state.BeaconState, slot types.Slot)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if time.CanUpgradeToCapella(state.Slot()) {
|
||||
state, err = capella.UpgradeToCapella(state)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if highestSlot < state.Slot() {
|
||||
|
||||
@@ -243,7 +243,7 @@ func ProcessOperationsNoVerifyAttsSigs(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case version.Altair, version.Bellatrix:
|
||||
case version.Altair, version.Bellatrix, version.Capella:
|
||||
state, err = altairOperations(ctx, state, signedBeaconBlock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -30,10 +30,7 @@ go_library(
|
||||
"wss.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/kv",
|
||||
visibility = [
|
||||
"//beacon-chain:__subpackages__",
|
||||
"//tools:__subpackages__",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/db/filters:go_default_library",
|
||||
|
||||
@@ -789,6 +789,16 @@ func unmarshalBlock(_ context.Context, enc []byte) (interfaces.SignedBeaconBlock
|
||||
if err := rawBlock.UnmarshalSSZ(enc[len(bellatrixBlindKey):]); err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal blinded Bellatrix block")
|
||||
}
|
||||
case hasCapellaKey(enc):
|
||||
rawBlock = ðpb.SignedBeaconBlockCapella{}
|
||||
if err := rawBlock.UnmarshalSSZ(enc[len(capellaKey):]); err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal Capella block")
|
||||
}
|
||||
case hasCapellaBlindKey(enc):
|
||||
rawBlock = ðpb.SignedBlindedBeaconBlockCapella{}
|
||||
if err := rawBlock.UnmarshalSSZ(enc[len(capellaBlindKey):]); err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal blinded Capella block")
|
||||
}
|
||||
default:
|
||||
// Marshal block bytes to phase 0 beacon block.
|
||||
rawBlock = ðpb.SignedBeaconBlock{}
|
||||
@@ -828,6 +838,11 @@ func marshalBlock(_ context.Context, blk interfaces.SignedBeaconBlock) ([]byte,
|
||||
}
|
||||
}
|
||||
switch blockToSave.Version() {
|
||||
case version.Capella:
|
||||
if blockToSave.IsBlinded() {
|
||||
return snappy.Encode(nil, append(capellaBlindKey, encodedBlock...)), nil
|
||||
}
|
||||
return snappy.Encode(nil, append(capellaKey, encodedBlock...)), nil
|
||||
case version.Bellatrix:
|
||||
if blockToSave.IsBlinded() {
|
||||
return snappy.Encode(nil, append(bellatrixBlindKey, encodedBlock...)), nil
|
||||
|
||||
@@ -30,3 +30,10 @@ func hasCapellaKey(enc []byte) bool {
|
||||
}
|
||||
return bytes.Equal(enc[:len(capellaKey)], capellaKey)
|
||||
}
|
||||
|
||||
func hasCapellaBlindKey(enc []byte) bool {
|
||||
if len(capellaBlindKey) >= len(enc) {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(enc[:len(capellaBlindKey)], capellaBlindKey)
|
||||
}
|
||||
|
||||
@@ -98,6 +98,38 @@ func KVStoreDatafilePath(dirPath string) string {
|
||||
return path.Join(dirPath, DatabaseFileName)
|
||||
}
|
||||
|
||||
var Buckets = [][]byte{
|
||||
attestationsBucket,
|
||||
blocksBucket,
|
||||
stateBucket,
|
||||
proposerSlashingsBucket,
|
||||
attesterSlashingsBucket,
|
||||
voluntaryExitsBucket,
|
||||
chainMetadataBucket,
|
||||
checkpointBucket,
|
||||
powchainBucket,
|
||||
stateSummaryBucket,
|
||||
stateValidatorsBucket,
|
||||
// Indices buckets.
|
||||
attestationHeadBlockRootBucket,
|
||||
attestationSourceRootIndicesBucket,
|
||||
attestationSourceEpochIndicesBucket,
|
||||
attestationTargetRootIndicesBucket,
|
||||
attestationTargetEpochIndicesBucket,
|
||||
blockSlotIndicesBucket,
|
||||
stateSlotIndicesBucket,
|
||||
blockParentRootIndicesBucket,
|
||||
finalizedBlockRootsIndexBucket,
|
||||
blockRootValidatorHashesBucket,
|
||||
// State management service bucket.
|
||||
newStateServiceCompatibleBucket,
|
||||
// Migrations
|
||||
migrationsBucket,
|
||||
|
||||
feeRecipientBucket,
|
||||
registrationBucket,
|
||||
}
|
||||
|
||||
// NewKVStore initializes a new boltDB key-value store at the directory
|
||||
// path specified, creates the kv-buckets based on the schema, and stores
|
||||
// an open connection db object as a property of the Store struct.
|
||||
@@ -155,38 +187,7 @@ func NewKVStore(ctx context.Context, dirPath string) (*Store, error) {
|
||||
ctx: ctx,
|
||||
}
|
||||
if err := kv.db.Update(func(tx *bolt.Tx) error {
|
||||
return createBuckets(
|
||||
tx,
|
||||
attestationsBucket,
|
||||
blocksBucket,
|
||||
stateBucket,
|
||||
proposerSlashingsBucket,
|
||||
attesterSlashingsBucket,
|
||||
voluntaryExitsBucket,
|
||||
chainMetadataBucket,
|
||||
checkpointBucket,
|
||||
powchainBucket,
|
||||
stateSummaryBucket,
|
||||
stateValidatorsBucket,
|
||||
// Indices buckets.
|
||||
attestationHeadBlockRootBucket,
|
||||
attestationSourceRootIndicesBucket,
|
||||
attestationSourceEpochIndicesBucket,
|
||||
attestationTargetRootIndicesBucket,
|
||||
attestationTargetEpochIndicesBucket,
|
||||
blockSlotIndicesBucket,
|
||||
stateSlotIndicesBucket,
|
||||
blockParentRootIndicesBucket,
|
||||
finalizedBlockRootsIndexBucket,
|
||||
blockRootValidatorHashesBucket,
|
||||
// State management service bucket.
|
||||
newStateServiceCompatibleBucket,
|
||||
// Migrations
|
||||
migrationsBucket,
|
||||
|
||||
feeRecipientBucket,
|
||||
registrationBucket,
|
||||
)
|
||||
return createBuckets(tx, Buckets...)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ var (
|
||||
bellatrixKey = []byte("merge")
|
||||
bellatrixBlindKey = []byte("blind-bellatrix")
|
||||
capellaKey = []byte("capella")
|
||||
capellaBlindKey = []byte("blind-capella")
|
||||
|
||||
// block root included in the beacon state used by weak subjectivity initial sync
|
||||
originCheckpointBlockRootKey = []byte("origin-checkpoint-block-root")
|
||||
// block root tracking the progress of backfill, or pointing at genesis if backfill has not been initiated
|
||||
|
||||
@@ -26,10 +26,16 @@ import (
|
||||
const (
|
||||
// NewPayloadMethod v1 request string for JSON-RPC.
|
||||
NewPayloadMethod = "engine_newPayloadV1"
|
||||
// NewPayloadMethod v2 request string for JSON-RPC.
|
||||
NewPayloadMethodV2 = "engine_newPayloadV2"
|
||||
// ForkchoiceUpdatedMethod v1 request string for JSON-RPC.
|
||||
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
|
||||
// ForkchoiceUpdatedMethod v2 request string for JSON-RPC.
|
||||
ForkchoiceUpdatedMethodV2 = "engine_forkchoiceUpdatedV2"
|
||||
// GetPayloadMethod v1 request string for JSON-RPC.
|
||||
GetPayloadMethod = "engine_getPayloadV1"
|
||||
// GetPayloadMethod v2 request string for JSON-RPC.
|
||||
GetPayloadMethodV2 = "engine_getPayloadV2"
|
||||
// ExchangeTransitionConfigurationMethod v1 request string for JSON-RPC.
|
||||
ExchangeTransitionConfigurationMethod = "engine_exchangeTransitionConfigurationV1"
|
||||
// ExecutionBlockByHashMethod request string for JSON-RPC.
|
||||
@@ -66,7 +72,11 @@ type EngineCaller interface {
|
||||
ForkchoiceUpdated(
|
||||
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
|
||||
) (*pb.PayloadIDBytes, []byte, error)
|
||||
ForkchoiceUpdatedV2(
|
||||
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributesV2,
|
||||
) (*pb.PayloadIDBytes, []byte, error)
|
||||
GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error)
|
||||
GetPayloadV2(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayloadCapella, error)
|
||||
ExchangeTransitionConfiguration(
|
||||
ctx context.Context, cfg *pb.TransitionConfiguration,
|
||||
) error
|
||||
@@ -87,13 +97,21 @@ func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionDa
|
||||
ctx, cancel := context.WithDeadline(ctx, d)
|
||||
defer cancel()
|
||||
result := &pb.PayloadStatus{}
|
||||
payloadPb, ok := payload.Proto().(*pb.ExecutionPayload)
|
||||
payloadPb, ok := payload.Proto().(*pb.ExecutionPayloadCapella)
|
||||
if !ok {
|
||||
return nil, errors.New("execution data must be an execution payload")
|
||||
}
|
||||
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethod, payloadPb)
|
||||
if err != nil {
|
||||
return nil, handleRPCError(err)
|
||||
payloadPb, ok := payload.Proto().(*pb.ExecutionPayload)
|
||||
if !ok {
|
||||
return nil, errors.New("execution data must be a Bellatrix or Capella execution payload")
|
||||
}
|
||||
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethod, payloadPb)
|
||||
if err != nil {
|
||||
return nil, handleRPCError(err)
|
||||
}
|
||||
} else {
|
||||
err := s.rpcClient.CallContext(ctx, result, NewPayloadMethodV2, payloadPb)
|
||||
if err != nil {
|
||||
return nil, handleRPCError(err)
|
||||
}
|
||||
}
|
||||
|
||||
switch result.Status {
|
||||
@@ -146,6 +164,42 @@ func (s *Service) ForkchoiceUpdated(
|
||||
}
|
||||
}
|
||||
|
||||
// ForkchoiceUpdatedV2 calls the engine_forkchoiceUpdatedV2 method via JSON-RPC.
|
||||
func (s *Service) ForkchoiceUpdatedV2(
|
||||
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributesV2,
|
||||
) (*pb.PayloadIDBytes, []byte, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.ForkchoiceUpdatedV2")
|
||||
defer span.End()
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
forkchoiceUpdatedLatency.Observe(float64(time.Since(start).Milliseconds()))
|
||||
}()
|
||||
|
||||
d := time.Now().Add(time.Duration(params.BeaconConfig().ExecutionEngineTimeoutValue) * time.Second)
|
||||
ctx, cancel := context.WithDeadline(ctx, d)
|
||||
defer cancel()
|
||||
result := &ForkchoiceUpdatedResponse{}
|
||||
err := s.rpcClient.CallContext(ctx, result, ForkchoiceUpdatedMethodV2, state, attrs)
|
||||
if err != nil {
|
||||
return nil, nil, handleRPCError(err)
|
||||
}
|
||||
|
||||
if result.Status == nil {
|
||||
return nil, nil, ErrNilResponse
|
||||
}
|
||||
resp := result.Status
|
||||
switch resp.Status {
|
||||
case pb.PayloadStatus_SYNCING:
|
||||
return nil, nil, ErrAcceptedSyncingPayloadStatus
|
||||
case pb.PayloadStatus_INVALID:
|
||||
return nil, resp.LatestValidHash, ErrInvalidPayloadStatus
|
||||
case pb.PayloadStatus_VALID:
|
||||
return result.PayloadId, resp.LatestValidHash, nil
|
||||
default:
|
||||
return nil, nil, ErrUnknownPayloadStatus
|
||||
}
|
||||
}
|
||||
|
||||
// GetPayload calls the engine_getPayloadV1 method via JSON-RPC.
|
||||
func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetPayload")
|
||||
@@ -163,6 +217,23 @@ func (s *Service) GetPayload(ctx context.Context, payloadId [8]byte) (*pb.Execut
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// GetPayloadV2 calls the engine_getPayloadV2 method via JSON-RPC.
|
||||
func (s *Service) GetPayloadV2(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayloadCapella, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetPayloadV2")
|
||||
defer span.End()
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
getPayloadLatency.Observe(float64(time.Since(start).Milliseconds()))
|
||||
}()
|
||||
|
||||
d := time.Now().Add(defaultEngineTimeout)
|
||||
ctx, cancel := context.WithDeadline(ctx, d)
|
||||
defer cancel()
|
||||
result := &pb.ExecutionPayloadCapella{}
|
||||
err := s.rpcClient.CallContext(ctx, result, GetPayloadMethodV2, pb.PayloadIDBytes(payloadId))
|
||||
return result, handleRPCError(err)
|
||||
}
|
||||
|
||||
// ExchangeTransitionConfiguration calls the engine_exchangeTransitionConfigurationV1 method via JSON-RPC.
|
||||
func (s *Service) ExchangeTransitionConfiguration(
|
||||
ctx context.Context, cfg *pb.TransitionConfiguration,
|
||||
|
||||
@@ -3,6 +3,7 @@ package execution
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -14,7 +15,6 @@ import (
|
||||
contracts "github.com/prysmaticlabs/prysm/v3/contracts/deposit"
|
||||
"github.com/prysmaticlabs/prysm/v3/io/logs"
|
||||
"github.com/prysmaticlabs/prysm/v3/network"
|
||||
"github.com/prysmaticlabs/prysm/v3/network/authorization"
|
||||
)
|
||||
|
||||
func (s *Service) setupExecutionClientConnections(ctx context.Context, currEndpoint network.Endpoint) error {
|
||||
@@ -116,7 +116,15 @@ func (s *Service) newRPCClientWithAuth(ctx context.Context, endpoint network.End
|
||||
}
|
||||
switch u.Scheme {
|
||||
case "http", "https":
|
||||
client, err = gethRPC.DialHTTPWithClient(endpoint.Url, endpoint.HttpClient())
|
||||
httpAuth := gethRPC.WithHTTPAuth(func(h http.Header) error {
|
||||
header, err := endpoint.Auth.ToHeaderValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client.SetHeader("Authorization", header)
|
||||
return nil
|
||||
})
|
||||
client, err = gethRPC.DialOptions(ctx, endpoint.Url, httpAuth, gethRPC.WithHTTPClient(endpoint.HttpClient()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -128,13 +136,7 @@ func (s *Service) newRPCClientWithAuth(ctx context.Context, endpoint network.End
|
||||
default:
|
||||
return nil, fmt.Errorf("no known transport for URL scheme %q", u.Scheme)
|
||||
}
|
||||
if endpoint.Auth.Method != authorization.None {
|
||||
header, err := endpoint.Auth.ToHeaderValue()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.SetHeader("Authorization", header)
|
||||
}
|
||||
|
||||
for _, h := range s.cfg.headers {
|
||||
if h != "" {
|
||||
keyValue := strings.Split(h, "=")
|
||||
|
||||
@@ -275,7 +275,7 @@ func (f *ForkChoice) IsOptimistic(root [32]byte) (bool, error) {
|
||||
|
||||
// AncestorRoot returns the ancestor root of input block root at a given slot.
|
||||
func (f *ForkChoice) AncestorRoot(ctx context.Context, root [32]byte, slot types.Slot) ([32]byte, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "protoArray.AncestorRoot")
|
||||
ctx, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.AncestorRoot")
|
||||
defer span.End()
|
||||
|
||||
f.store.nodesLock.RLock()
|
||||
@@ -493,7 +493,7 @@ func (f *ForkChoice) UpdateFinalizedCheckpoint(fc *forkchoicetypes.Checkpoint) e
|
||||
|
||||
// CommonAncestor returns the common ancestor root and slot between the two block roots r1 and r2.
|
||||
func (f *ForkChoice) CommonAncestor(ctx context.Context, r1 [32]byte, r2 [32]byte) ([32]byte, types.Slot, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "doublelinkedtree.CommonAncestorRoot")
|
||||
ctx, span := trace.StartSpan(ctx, "doublyLinkedForkchoice.CommonAncestorRoot")
|
||||
defer span.End()
|
||||
|
||||
f.store.nodesLock.RLock()
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
@@ -74,7 +75,7 @@ func (s *Store) head(ctx context.Context) ([32]byte, error) {
|
||||
if s.justifiedCheckpoint.Epoch == params.BeaconConfig().GenesisEpoch {
|
||||
justifiedNode = s.treeRootNode
|
||||
} else {
|
||||
return [32]byte{}, errUnknownJustifiedRoot
|
||||
return [32]byte{}, errors.WithMessage(errUnknownJustifiedRoot, fmt.Sprintf("%#x", s.justifiedCheckpoint.Root))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +221,7 @@ func (s *Store) prune(ctx context.Context) error {
|
||||
|
||||
finalizedNode, ok := s.nodeByRoot[finalizedRoot]
|
||||
if !ok || finalizedNode == nil {
|
||||
return errUnknownFinalizedRoot
|
||||
return errors.WithMessage(errUnknownFinalizedRoot, fmt.Sprintf("%#x", finalizedRoot))
|
||||
}
|
||||
// return early if we haven't changed the finalized checkpoint
|
||||
if finalizedNode.parent == nil {
|
||||
|
||||
@@ -85,6 +85,7 @@ go_test(
|
||||
"//beacon-chain/monitor:go_default_library",
|
||||
"//cmd:go_default_library",
|
||||
"//cmd/beacon-chain/flags:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
|
||||
@@ -117,6 +117,9 @@ func New(cliCtx *cli.Context, opts ...Option) (*BeaconNode, error) {
|
||||
return nil, err
|
||||
}
|
||||
prereqs.WarnIfPlatformNotSupported(cliCtx.Context)
|
||||
if hasNetworkFlag(cliCtx) && cliCtx.IsSet(cmd.ChainConfigFileFlag.Name) {
|
||||
return nil, fmt.Errorf("%s cannot be passed concurrently with network flag", cmd.ChainConfigFileFlag.Name)
|
||||
}
|
||||
if err := features.ConfigureBeaconChain(cliCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -970,3 +973,14 @@ func (b *BeaconNode) registerBuilderService() error {
|
||||
}
|
||||
return b.services.RegisterService(svc)
|
||||
}
|
||||
|
||||
func hasNetworkFlag(cliCtx *cli.Context) bool {
|
||||
for _, flag := range features.NetworkFlags {
|
||||
for _, name := range flag.Names() {
|
||||
if cliCtx.IsSet(name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/monitor"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/beacon-chain/flags"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/features"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
@@ -171,3 +172,45 @@ func TestMonitor_RegisteredCorrectly(t *testing.T) {
|
||||
require.Equal(t, true, mService.TrackedValidators[2])
|
||||
require.Equal(t, false, mService.TrackedValidators[100])
|
||||
}
|
||||
|
||||
func Test_hasNetworkFlag(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
networkName string
|
||||
networkValue string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "Prater testnet",
|
||||
networkName: features.PraterTestnet.Name,
|
||||
networkValue: "prater",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "Mainnet",
|
||||
networkName: features.Mainnet.Name,
|
||||
networkValue: "mainnet",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "No network flag",
|
||||
networkName: "",
|
||||
networkValue: "",
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String(tt.networkName, tt.networkValue, tt.name)
|
||||
|
||||
cliCtx := cli.NewContext(&cli.App{}, set, nil)
|
||||
err := cliCtx.Set(tt.networkName, tt.networkValue)
|
||||
require.NoError(t, err)
|
||||
|
||||
if got := hasNetworkFlag(cliCtx); got != tt.want {
|
||||
t.Errorf("hasNetworkFlag() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ func (s *Service) forkWatcher() {
|
||||
case currSlot := <-slotTicker.C():
|
||||
currEpoch := slots.ToEpoch(currSlot)
|
||||
if currEpoch == params.BeaconConfig().AltairForkEpoch ||
|
||||
currEpoch == params.BeaconConfig().BellatrixForkEpoch {
|
||||
currEpoch == params.BeaconConfig().BellatrixForkEpoch ||
|
||||
currEpoch == params.BeaconConfig().CapellaForkEpoch {
|
||||
// If we are in the fork epoch, we update our enr with
|
||||
// the updated fork digest. These repeatedly does
|
||||
// this over the epoch, which might be slightly wasteful
|
||||
|
||||
@@ -26,6 +26,9 @@ var gossipTopicMappings = map[string]proto.Message{
|
||||
// versioned by epoch.
|
||||
func GossipTopicMappings(topic string, epoch types.Epoch) proto.Message {
|
||||
if topic == BlockSubnetTopicFormat {
|
||||
if epoch >= params.BeaconConfig().CapellaForkEpoch {
|
||||
return ðpb.SignedBeaconBlockCapella{}
|
||||
}
|
||||
if epoch >= params.BeaconConfig().BellatrixForkEpoch {
|
||||
return ðpb.SignedBeaconBlockBellatrix{}
|
||||
}
|
||||
@@ -59,4 +62,7 @@ func init() {
|
||||
// Specially handle Bellatrix objects.
|
||||
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBeaconBlockBellatrix{})] = BlockSubnetTopicFormat
|
||||
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBlindedBeaconBlockBellatrix{})] = BlockSubnetTopicFormat
|
||||
// Specially handle Capella objects
|
||||
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBeaconBlockCapella{})] = BlockSubnetTopicFormat
|
||||
GossipTypeMapping[reflect.TypeOf(ðpb.SignedBlindedBeaconBlockCapella{})] = BlockSubnetTopicFormat
|
||||
}
|
||||
|
||||
@@ -52,11 +52,17 @@ func (s *Service) CanSubscribe(topic string) bool {
|
||||
log.WithError(err).Error("Could not determine Bellatrix fork digest")
|
||||
return false
|
||||
}
|
||||
capellaForkDigest, err := forks.ForkDigestFromEpoch(params.BeaconConfig().CapellaForkEpoch, s.genesisValidatorsRoot)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not determine Capella fork digest")
|
||||
return false
|
||||
}
|
||||
|
||||
switch parts[2] {
|
||||
case fmt.Sprintf("%x", phase0ForkDigest):
|
||||
case fmt.Sprintf("%x", altairForkDigest):
|
||||
case fmt.Sprintf("%x", bellatrixForkDigest):
|
||||
case fmt.Sprintf("%x", capellaForkDigest):
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -269,8 +269,10 @@ func setInitialPublishBlockPostRequest(endpoint *apimiddleware.Endpoint,
|
||||
endpoint.PostRequest = &SignedBeaconBlockContainerJson{}
|
||||
} else if currentEpoch < params.BeaconConfig().BellatrixForkEpoch {
|
||||
endpoint.PostRequest = &SignedBeaconBlockAltairContainerJson{}
|
||||
} else {
|
||||
} else if currentEpoch < params.BeaconConfig().CapellaForkEpoch {
|
||||
endpoint.PostRequest = &SignedBeaconBlockBellatrixContainerJson{}
|
||||
} else {
|
||||
endpoint.PostRequest = &SignedBeaconBlockCapellaContainerJson{}
|
||||
}
|
||||
req.Body = io.NopCloser(bytes.NewBuffer(buf))
|
||||
return true, nil
|
||||
|
||||
@@ -336,6 +336,7 @@ type SignedBeaconBlockContainerV2Json struct {
|
||||
Phase0Block *BeaconBlockJson `json:"phase0_block"`
|
||||
AltairBlock *BeaconBlockAltairJson `json:"altair_block"`
|
||||
BellatrixBlock *BeaconBlockBellatrixJson `json:"bellatrix_block"`
|
||||
CapellaBlock *BeaconBlockCapellaJson `json:"capella_block"`
|
||||
Signature string `json:"signature" hex:"true"`
|
||||
}
|
||||
|
||||
@@ -343,6 +344,7 @@ type SignedBlindedBeaconBlockContainerJson struct {
|
||||
Phase0Block *BeaconBlockJson `json:"phase0_block"`
|
||||
AltairBlock *BeaconBlockAltairJson `json:"altair_block"`
|
||||
BellatrixBlock *BlindedBeaconBlockBellatrixJson `json:"bellatrix_block"`
|
||||
CapellaBlock *BlindedBeaconBlockCapellaJson `json:"capella_block"`
|
||||
Signature string `json:"signature" hex:"true"`
|
||||
}
|
||||
|
||||
@@ -350,12 +352,14 @@ type BeaconBlockContainerV2Json struct {
|
||||
Phase0Block *BeaconBlockJson `json:"phase0_block"`
|
||||
AltairBlock *BeaconBlockAltairJson `json:"altair_block"`
|
||||
BellatrixBlock *BeaconBlockBellatrixJson `json:"bellatrix_block"`
|
||||
CapellaBlock *BeaconBlockCapellaJson `json:"capella_block"`
|
||||
}
|
||||
|
||||
type BlindedBeaconBlockContainerJson struct {
|
||||
Phase0Block *BeaconBlockJson `json:"phase0_block"`
|
||||
AltairBlock *BeaconBlockAltairJson `json:"altair_block"`
|
||||
BellatrixBlock *BlindedBeaconBlockBellatrixJson `json:"bellatrix_block"`
|
||||
CapellaBlock *BlindedBeaconBlockCapellaJson `json:"capella_block"`
|
||||
}
|
||||
|
||||
type SignedBeaconBlockAltairContainerJson struct {
|
||||
@@ -368,11 +372,21 @@ type SignedBeaconBlockBellatrixContainerJson struct {
|
||||
Signature string `json:"signature" hex:"true"`
|
||||
}
|
||||
|
||||
type SignedBeaconBlockCapellaContainerJson struct {
|
||||
Message *BeaconBlockCapellaJson `json:"message"`
|
||||
Signature string `json:"signature" hex:"true"`
|
||||
}
|
||||
|
||||
type SignedBlindedBeaconBlockBellatrixContainerJson struct {
|
||||
Message *BlindedBeaconBlockBellatrixJson `json:"message"`
|
||||
Signature string `json:"signature" hex:"true"`
|
||||
}
|
||||
|
||||
type SignedBlindedBeaconBlockCapellaContainerJson struct {
|
||||
Message *BlindedBeaconBlockCapellaJson `json:"message"`
|
||||
Signature string `json:"signature" hex:"true"`
|
||||
}
|
||||
|
||||
type BeaconBlockAltairJson struct {
|
||||
Slot string `json:"slot"`
|
||||
ProposerIndex string `json:"proposer_index"`
|
||||
@@ -389,6 +403,14 @@ type BeaconBlockBellatrixJson struct {
|
||||
Body *BeaconBlockBodyBellatrixJson `json:"body"`
|
||||
}
|
||||
|
||||
type BeaconBlockCapellaJson struct {
|
||||
Slot string `json:"slot"`
|
||||
ProposerIndex string `json:"proposer_index"`
|
||||
ParentRoot string `json:"parent_root" hex:"true"`
|
||||
StateRoot string `json:"state_root" hex:"true"`
|
||||
Body *BeaconBlockBodyCapellaJson `json:"body"`
|
||||
}
|
||||
|
||||
type BlindedBeaconBlockBellatrixJson struct {
|
||||
Slot string `json:"slot"`
|
||||
ProposerIndex string `json:"proposer_index"`
|
||||
@@ -397,6 +419,14 @@ type BlindedBeaconBlockBellatrixJson struct {
|
||||
Body *BlindedBeaconBlockBodyBellatrixJson `json:"body"`
|
||||
}
|
||||
|
||||
type BlindedBeaconBlockCapellaJson struct {
|
||||
Slot string `json:"slot"`
|
||||
ProposerIndex string `json:"proposer_index"`
|
||||
ParentRoot string `json:"parent_root" hex:"true"`
|
||||
StateRoot string `json:"state_root" hex:"true"`
|
||||
Body *BlindedBeaconBlockBodyCapellaJson `json:"body"`
|
||||
}
|
||||
|
||||
type BeaconBlockBodyAltairJson struct {
|
||||
RandaoReveal string `json:"randao_reveal" hex:"true"`
|
||||
Eth1Data *Eth1DataJson `json:"eth1_data"`
|
||||
@@ -422,6 +452,20 @@ type BeaconBlockBodyBellatrixJson struct {
|
||||
ExecutionPayload *ExecutionPayloadJson `json:"execution_payload"`
|
||||
}
|
||||
|
||||
type BeaconBlockBodyCapellaJson struct {
|
||||
RandaoReveal string `json:"randao_reveal" hex:"true"`
|
||||
Eth1Data *Eth1DataJson `json:"eth1_data"`
|
||||
Graffiti string `json:"graffiti" hex:"true"`
|
||||
ProposerSlashings []*ProposerSlashingJson `json:"proposer_slashings"`
|
||||
AttesterSlashings []*AttesterSlashingJson `json:"attester_slashings"`
|
||||
Attestations []*AttestationJson `json:"attestations"`
|
||||
Deposits []*DepositJson `json:"deposits"`
|
||||
VoluntaryExits []*SignedVoluntaryExitJson `json:"voluntary_exits"`
|
||||
SyncAggregate *SyncAggregateJson `json:"sync_aggregate"`
|
||||
ExecutionPayload *ExecutionPayloadCapellaJson `json:"execution_payload"`
|
||||
BLSToExecutionChanges []*BLSToExecutionChangeJson `json:"bls_to_execution_changes"`
|
||||
}
|
||||
|
||||
type BlindedBeaconBlockBodyBellatrixJson struct {
|
||||
RandaoReveal string `json:"randao_reveal" hex:"true"`
|
||||
Eth1Data *Eth1DataJson `json:"eth1_data"`
|
||||
@@ -435,6 +479,20 @@ type BlindedBeaconBlockBodyBellatrixJson struct {
|
||||
ExecutionPayloadHeader *ExecutionPayloadHeaderJson `json:"execution_payload_header"`
|
||||
}
|
||||
|
||||
type BlindedBeaconBlockBodyCapellaJson struct {
|
||||
RandaoReveal string `json:"randao_reveal" hex:"true"`
|
||||
Eth1Data *Eth1DataJson `json:"eth1_data"`
|
||||
Graffiti string `json:"graffiti" hex:"true"`
|
||||
ProposerSlashings []*ProposerSlashingJson `json:"proposer_slashings"`
|
||||
AttesterSlashings []*AttesterSlashingJson `json:"attester_slashings"`
|
||||
Attestations []*AttestationJson `json:"attestations"`
|
||||
Deposits []*DepositJson `json:"deposits"`
|
||||
VoluntaryExits []*SignedVoluntaryExitJson `json:"voluntary_exits"`
|
||||
SyncAggregate *SyncAggregateJson `json:"sync_aggregate"`
|
||||
ExecutionPayloadHeader *ExecutionPayloadHeaderCapellaJson `json:"execution_payload_header"`
|
||||
BLSToExecutionChanges []*BLSToExecutionChangeJson `json:"bls_to_execution_changes"`
|
||||
}
|
||||
|
||||
type ExecutionPayloadJson struct {
|
||||
ParentHash string `json:"parent_hash" hex:"true"`
|
||||
FeeRecipient string `json:"fee_recipient" hex:"true"`
|
||||
@@ -452,6 +510,24 @@ type ExecutionPayloadJson struct {
|
||||
Transactions []string `json:"transactions" hex:"true"`
|
||||
}
|
||||
|
||||
type ExecutionPayloadCapellaJson struct {
|
||||
ParentHash string `json:"parent_hash" hex:"true"`
|
||||
FeeRecipient string `json:"fee_recipient" hex:"true"`
|
||||
StateRoot string `json:"state_root" hex:"true"`
|
||||
ReceiptsRoot string `json:"receipts_root" hex:"true"`
|
||||
LogsBloom string `json:"logs_bloom" hex:"true"`
|
||||
PrevRandao string `json:"prev_randao" hex:"true"`
|
||||
BlockNumber string `json:"block_number"`
|
||||
GasLimit string `json:"gas_limit"`
|
||||
GasUsed string `json:"gas_used"`
|
||||
TimeStamp string `json:"timestamp"`
|
||||
ExtraData string `json:"extra_data" hex:"true"`
|
||||
BaseFeePerGas string `json:"base_fee_per_gas" uint256:"true"`
|
||||
BlockHash string `json:"block_hash" hex:"true"`
|
||||
Transactions []string `json:"transactions" hex:"true"`
|
||||
Withdrawals []*WithdrawalJson `json:"withdrawals"`
|
||||
}
|
||||
|
||||
type ExecutionPayloadHeaderJson struct {
|
||||
ParentHash string `json:"parent_hash" hex:"true"`
|
||||
FeeRecipient string `json:"fee_recipient" hex:"true"`
|
||||
@@ -469,6 +545,24 @@ type ExecutionPayloadHeaderJson struct {
|
||||
TransactionsRoot string `json:"transactions_root" hex:"true"`
|
||||
}
|
||||
|
||||
type ExecutionPayloadHeaderCapellaJson struct {
|
||||
ParentHash string `json:"parent_hash" hex:"true"`
|
||||
FeeRecipient string `json:"fee_recipient" hex:"true"`
|
||||
StateRoot string `json:"state_root" hex:"true"`
|
||||
ReceiptsRoot string `json:"receipts_root" hex:"true"`
|
||||
LogsBloom string `json:"logs_bloom" hex:"true"`
|
||||
PrevRandao string `json:"prev_randao" hex:"true"`
|
||||
BlockNumber string `json:"block_number"`
|
||||
GasLimit string `json:"gas_limit"`
|
||||
GasUsed string `json:"gas_used"`
|
||||
TimeStamp string `json:"timestamp"`
|
||||
ExtraData string `json:"extra_data" hex:"true"`
|
||||
BaseFeePerGas string `json:"base_fee_per_gas" uint256:"true"`
|
||||
BlockHash string `json:"block_hash" hex:"true"`
|
||||
TransactionsRoot string `json:"transactions_root" hex:"true"`
|
||||
WithdrawalsRoot string `json:"withdrawals_root" hex:"true"`
|
||||
}
|
||||
|
||||
type SyncAggregateJson struct {
|
||||
SyncCommitteeBits string `json:"sync_committee_bits" hex:"true"`
|
||||
SyncCommitteeSignature string `json:"sync_committee_signature" hex:"true"`
|
||||
@@ -539,6 +633,17 @@ type AttestationDataJson struct {
|
||||
Target *CheckpointJson `json:"target"`
|
||||
}
|
||||
|
||||
type BLSToExecutionChangeJson struct {
|
||||
ValidatorIndex string `json:"validator_index"`
|
||||
FromBLSPubkey string `json:"from_bls_pubkey" hex:"true"`
|
||||
ToExecutionAddress string `jston:"to_execution_address" hex:"true"`
|
||||
}
|
||||
|
||||
type SigledBLSToExecutionChangeJson struct {
|
||||
BLSToExecutionChange *BLSToExecutionChangeJson `json:"message"`
|
||||
Signature string `json:"signature" hex:"true"`
|
||||
}
|
||||
|
||||
type DepositJson struct {
|
||||
Proof []string `json:"proof" hex:"true"`
|
||||
Data *Deposit_DataJson `json:"data"`
|
||||
@@ -593,6 +698,13 @@ type VersionJson struct {
|
||||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
type WithdrawalJson struct {
|
||||
WithdrawalIndex string `json:"index"`
|
||||
ValidatorIndex string `json:"validator_index"`
|
||||
ExecutionAddress string `json:"address" hex:"true"`
|
||||
Amount string `json:"amount"`
|
||||
}
|
||||
|
||||
type BeaconStateJson struct {
|
||||
GenesisTime string `json:"genesis_time"`
|
||||
GenesisValidatorsRoot string `json:"genesis_validators_root" hex:"true"`
|
||||
@@ -672,10 +784,41 @@ type BeaconStateBellatrixJson struct {
|
||||
LatestExecutionPayloadHeader *ExecutionPayloadHeaderJson `json:"latest_execution_payload_header"`
|
||||
}
|
||||
|
||||
type BeaconStateCapellaJson struct {
|
||||
GenesisTime string `json:"genesis_time"`
|
||||
GenesisValidatorsRoot string `json:"genesis_validators_root" hex:"true"`
|
||||
Slot string `json:"slot"`
|
||||
Fork *ForkJson `json:"fork"`
|
||||
LatestBlockHeader *BeaconBlockHeaderJson `json:"latest_block_header"`
|
||||
BlockRoots []string `json:"block_roots" hex:"true"`
|
||||
StateRoots []string `json:"state_roots" hex:"true"`
|
||||
HistoricalRoots []string `json:"historical_roots" hex:"true"`
|
||||
Eth1Data *Eth1DataJson `json:"eth1_data"`
|
||||
Eth1DataVotes []*Eth1DataJson `json:"eth1_data_votes"`
|
||||
Eth1DepositIndex string `json:"eth1_deposit_index"`
|
||||
Validators []*ValidatorJson `json:"validators"`
|
||||
Balances []string `json:"balances"`
|
||||
RandaoMixes []string `json:"randao_mixes" hex:"true"`
|
||||
Slashings []string `json:"slashings"`
|
||||
PreviousEpochParticipation EpochParticipation `json:"previous_epoch_participation"`
|
||||
CurrentEpochParticipation EpochParticipation `json:"current_epoch_participation"`
|
||||
JustificationBits string `json:"justification_bits" hex:"true"`
|
||||
PreviousJustifiedCheckpoint *CheckpointJson `json:"previous_justified_checkpoint"`
|
||||
CurrentJustifiedCheckpoint *CheckpointJson `json:"current_justified_checkpoint"`
|
||||
FinalizedCheckpoint *CheckpointJson `json:"finalized_checkpoint"`
|
||||
InactivityScores []string `json:"inactivity_scores"`
|
||||
CurrentSyncCommittee *SyncCommitteeJson `json:"current_sync_committee"`
|
||||
NextSyncCommittee *SyncCommitteeJson `json:"next_sync_committee"`
|
||||
LatestExecutionPayloadHeader *ExecutionPayloadHeaderCapellaJson `json:"latest_execution_payload_header"`
|
||||
NextWithdrawalIndex string `json:"next_withdrawal_index"`
|
||||
LastWithdrawalValidatorIndex string `json:"latest_withdrawal_validator_index"`
|
||||
}
|
||||
|
||||
type BeaconStateContainerV2Json struct {
|
||||
Phase0State *BeaconStateJson `json:"phase0_state"`
|
||||
AltairState *BeaconStateAltairJson `json:"altair_state"`
|
||||
BellatrixState *BeaconStateBellatrixJson `json:"bellatrix_state"`
|
||||
CapellaState *BeaconStateCapellaJson `json:"capella_state"`
|
||||
}
|
||||
|
||||
type ForkJson struct {
|
||||
|
||||
@@ -103,6 +103,7 @@ func TestGetSpec(t *testing.T) {
|
||||
config.TerminalBlockHashActivationEpoch = 72
|
||||
config.TerminalTotalDifficulty = "73"
|
||||
config.DefaultFeeRecipient = common.HexToAddress("DefaultFeeRecipient")
|
||||
config.MaxWithdrawalsPerPayload = 74
|
||||
|
||||
var dbp [4]byte
|
||||
copy(dbp[:], []byte{'0', '0', '0', '1'})
|
||||
@@ -135,7 +136,7 @@ func TestGetSpec(t *testing.T) {
|
||||
resp, err := server.GetSpec(context.Background(), &emptypb.Empty{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 102, len(resp.Data))
|
||||
assert.Equal(t, 103, len(resp.Data))
|
||||
for k, v := range resp.Data {
|
||||
switch k {
|
||||
case "CONFIG_NAME":
|
||||
@@ -355,6 +356,8 @@ func TestGetSpec(t *testing.T) {
|
||||
case "INTERVALS_PER_SLOT":
|
||||
assert.Equal(t, "3", v)
|
||||
case "SAFE_SLOTS_TO_IMPORT_OPTIMISTICALLY":
|
||||
case "MAX_WITHDRAWALS_PER_PAYLOAD":
|
||||
assert.Equal(t, "74", v)
|
||||
default:
|
||||
t.Errorf("Incorrect key: %s", k)
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ var eth1DataNotification bool
|
||||
const eth1dataTimeout = 2 * time.Second
|
||||
|
||||
// GetBeaconBlock is called by a proposer during its assigned slot to request a block to sign
|
||||
// by passing in the slot and the signed randao reveal of the slot. Returns phase0 beacon blocks
|
||||
// before the Altair fork epoch and Altair blocks post-fork epoch.
|
||||
// by passing in the slot and the signed randao reveal of the slot. Returns a full block
|
||||
// corresponding to the fork epoch
|
||||
func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ProposerServer.GetBeaconBlock")
|
||||
defer span.End()
|
||||
@@ -59,7 +59,6 @@ func (vs *Server) GetBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (
|
||||
if err := vs.optimisticStatus(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return vs.getBellatrixBeaconBlock(ctx, req)
|
||||
}
|
||||
|
||||
|
||||
@@ -15,26 +15,12 @@ import (
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
func (vs *Server) BuildAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ProposerServer.BuildAltairBeaconBlock")
|
||||
defer span.End()
|
||||
blkData, err := vs.buildPhase0BlockData(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not build block data: %v", err)
|
||||
}
|
||||
|
||||
func buildAltairBeaconBlockFromBlockData(blkData *blockData) *ethpb.BeaconBlockAltair {
|
||||
// Use zero hash as stub for state root to compute later.
|
||||
stateRoot := params.BeaconConfig().ZeroHash[:]
|
||||
|
||||
// No need for safe sub as req.Slot cannot be 0 if requesting Altair blocks. If 0, we will be throwing
|
||||
// an error in the first validity check of this endpoint.
|
||||
syncAggregate, err := vs.getSyncAggregate(ctx, req.Slot-1, bytesutil.ToBytes32(blkData.ParentRoot))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ðpb.BeaconBlockAltair{
|
||||
Slot: req.Slot,
|
||||
Slot: blkData.Slot,
|
||||
ParentRoot: blkData.ParentRoot,
|
||||
StateRoot: stateRoot,
|
||||
ProposerIndex: blkData.ProposerIdx,
|
||||
@@ -42,14 +28,24 @@ func (vs *Server) BuildAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRe
|
||||
Eth1Data: blkData.Eth1Data,
|
||||
Deposits: blkData.Deposits,
|
||||
Attestations: blkData.Attestations,
|
||||
RandaoReveal: req.RandaoReveal,
|
||||
RandaoReveal: blkData.RandaoReveal,
|
||||
ProposerSlashings: blkData.ProposerSlashings,
|
||||
AttesterSlashings: blkData.AttesterSlashings,
|
||||
VoluntaryExits: blkData.VoluntaryExits,
|
||||
Graffiti: blkData.Graffiti[:],
|
||||
SyncAggregate: syncAggregate,
|
||||
SyncAggregate: blkData.SyncAggregate,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (vs *Server) BuildAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ProposerServer.BuildAltairBeaconBlock")
|
||||
defer span.End()
|
||||
blkData, err := vs.buildPhase0BlockData(ctx, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not build block data: %v", err)
|
||||
}
|
||||
return buildAltairBeaconBlockFromBlockData(blkData), nil
|
||||
}
|
||||
|
||||
func (vs *Server) getAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition/interop"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db/kv"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
@@ -38,68 +39,124 @@ var builderGetPayloadMissCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
// block request. This value is known as `BUILDER_PROPOSAL_DELAY_TOLERANCE` in builder spec.
|
||||
const blockBuilderTimeout = 1 * time.Second
|
||||
|
||||
func (vs *Server) getBlockFromBuilder(ctx context.Context, altairBlk *ethpb.BeaconBlockAltair) (
|
||||
*ethpb.GenericBeaconBlock, error) {
|
||||
registered, err := vs.validatorRegistered(ctx, altairBlk.ProposerIndex)
|
||||
if registered && err == nil {
|
||||
builderReady, b, err := vs.GetAndBuildBlindBlock(ctx, altairBlk)
|
||||
if err != nil {
|
||||
// In the event of an error, the node should fall back to default execution engine for building block.
|
||||
builderGetPayloadMissCount.Inc()
|
||||
return nil, err
|
||||
} else if builderReady {
|
||||
return b, nil
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errors.New("validator is not registered")
|
||||
}
|
||||
|
||||
func (vs *Server) getBellatrixBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) {
|
||||
altairBlk, err := vs.BuildAltairBeaconBlock(ctx, req)
|
||||
blkData, err := vs.buildPhase0BlockData(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !req.SkipMevBoost {
|
||||
registered, err := vs.validatorRegistered(ctx, altairBlk.ProposerIndex)
|
||||
if registered && err == nil {
|
||||
builderReady, b, err := vs.GetAndBuildBlindBlock(ctx, altairBlk)
|
||||
if err != nil {
|
||||
// In the event of an error, the node should fall back to default execution engine for building block.
|
||||
log.WithError(err).Error("Failed to build a block from external builder, falling " +
|
||||
"back to local execution client")
|
||||
builderGetPayloadMissCount.Inc()
|
||||
} else if builderReady {
|
||||
return b, nil
|
||||
}
|
||||
} else if err != nil {
|
||||
log.WithError(err).WithFields(logrus.Fields{
|
||||
"slot": req.Slot,
|
||||
"validatorIndex": altairBlk.ProposerIndex,
|
||||
}).Error("Could not determine validator has registered. Defaulting to local execution client")
|
||||
// If the validator was not registered then we computed already an execution payload
|
||||
if !req.SkipMevBoost && blkData.ExecutionPayload == nil {
|
||||
altairBlk := buildAltairBeaconBlockFromBlockData(blkData)
|
||||
b, err := vs.getBlockFromBuilder(ctx, altairBlk)
|
||||
if err == nil {
|
||||
return b, nil
|
||||
}
|
||||
log.WithError(err).Error("falling back to local execution")
|
||||
|
||||
head, err := vs.HeadFetcher.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get head state %v", err)
|
||||
}
|
||||
|
||||
head, err = transition.ProcessSlotsUsingNextSlotCache(ctx, head, blkData.ParentRoot, req.Slot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not advance slots to calculate proposer index: %v", err)
|
||||
}
|
||||
|
||||
blkData.ExecutionPayload, err = vs.getExecutionPayload(ctx, req.Slot, blkData.ProposerIdx, bytesutil.ToBytes32(blkData.ParentRoot), head)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get execution payload")
|
||||
}
|
||||
}
|
||||
payload, err := vs.getExecutionPayload(ctx, req.Slot, altairBlk.ProposerIndex, bytesutil.ToBytes32(altairBlk.ParentRoot))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blk := ðpb.BeaconBlockBellatrix{
|
||||
Slot: altairBlk.Slot,
|
||||
ProposerIndex: altairBlk.ProposerIndex,
|
||||
ParentRoot: altairBlk.ParentRoot,
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
Body: ðpb.BeaconBlockBodyBellatrix{
|
||||
RandaoReveal: altairBlk.Body.RandaoReveal,
|
||||
Eth1Data: altairBlk.Body.Eth1Data,
|
||||
Graffiti: altairBlk.Body.Graffiti,
|
||||
ProposerSlashings: altairBlk.Body.ProposerSlashings,
|
||||
AttesterSlashings: altairBlk.Body.AttesterSlashings,
|
||||
Attestations: altairBlk.Body.Attestations,
|
||||
Deposits: altairBlk.Body.Deposits,
|
||||
VoluntaryExits: altairBlk.Body.VoluntaryExits,
|
||||
SyncAggregate: altairBlk.Body.SyncAggregate,
|
||||
ExecutionPayload: payload,
|
||||
},
|
||||
}
|
||||
// Compute state root with the newly constructed block.
|
||||
wsb, err := consensusblocks.NewSignedBeaconBlock(
|
||||
ðpb.SignedBeaconBlockBellatrix{Block: blk, Signature: make([]byte, 96)},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var wsb interfaces.SignedBeaconBlock
|
||||
if slots.ToEpoch(req.Slot) < params.BeaconConfig().CapellaForkEpoch {
|
||||
blk := ðpb.BeaconBlockBellatrix{
|
||||
Slot: blkData.Slot,
|
||||
ProposerIndex: blkData.ProposerIdx,
|
||||
ParentRoot: blkData.ParentRoot,
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
Body: ðpb.BeaconBlockBodyBellatrix{
|
||||
RandaoReveal: blkData.RandaoReveal,
|
||||
Eth1Data: blkData.Eth1Data,
|
||||
Graffiti: blkData.Graffiti[:],
|
||||
ProposerSlashings: blkData.ProposerSlashings,
|
||||
AttesterSlashings: blkData.AttesterSlashings,
|
||||
Attestations: blkData.Attestations,
|
||||
Deposits: blkData.Deposits,
|
||||
VoluntaryExits: blkData.VoluntaryExits,
|
||||
SyncAggregate: blkData.SyncAggregate,
|
||||
ExecutionPayload: blkData.ExecutionPayload,
|
||||
},
|
||||
}
|
||||
// Compute state root with the newly constructed block.
|
||||
wsb, err = consensusblocks.NewSignedBeaconBlock(
|
||||
ðpb.SignedBeaconBlockBellatrix{Block: blk, Signature: make([]byte, 96)},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
blk := ðpb.BeaconBlockCapella{
|
||||
Slot: blkData.Slot,
|
||||
ProposerIndex: blkData.ProposerIdx,
|
||||
ParentRoot: blkData.ParentRoot,
|
||||
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||
Body: ðpb.BeaconBlockBodyCapella{
|
||||
RandaoReveal: blkData.RandaoReveal,
|
||||
Eth1Data: blkData.Eth1Data,
|
||||
Graffiti: blkData.Graffiti[:],
|
||||
ProposerSlashings: blkData.ProposerSlashings,
|
||||
AttesterSlashings: blkData.AttesterSlashings,
|
||||
Attestations: blkData.Attestations,
|
||||
Deposits: blkData.Deposits,
|
||||
VoluntaryExits: blkData.VoluntaryExits,
|
||||
SyncAggregate: blkData.SyncAggregate,
|
||||
ExecutionPayload: blkData.ExecutionPayloadV2,
|
||||
BlsToExecutionChanges: blkData.BlsToExecutionChanges,
|
||||
},
|
||||
}
|
||||
// Compute state root with the newly constructed block.
|
||||
wsb, err = consensusblocks.NewSignedBeaconBlock(
|
||||
ðpb.SignedBeaconBlockCapella{Block: blk, Signature: make([]byte, 96)},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
stateRoot, err := vs.computeStateRoot(ctx, wsb)
|
||||
if err != nil {
|
||||
interop.WriteBlockToDisk(wsb, true /*failed*/)
|
||||
return nil, fmt.Errorf("could not compute state root: %v", err)
|
||||
}
|
||||
blk.StateRoot = stateRoot
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Bellatrix{Bellatrix: blk}}, nil
|
||||
wsb.Block().SetStateRoot(stateRoot)
|
||||
pb, err := wsb.Block().Proto()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal block")
|
||||
}
|
||||
if slots.ToEpoch(req.Slot) < params.BeaconConfig().CapellaForkEpoch {
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Bellatrix{Bellatrix: pb.(*ethpb.BeaconBlockBellatrix)}}, nil
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Capella{Capella: pb.(*ethpb.BeaconBlockCapella)}}, nil
|
||||
}
|
||||
|
||||
// This function retrieves the payload header given the slot number and the validator index.
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/transition"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db/kv"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
@@ -38,9 +38,14 @@ var (
|
||||
})
|
||||
)
|
||||
|
||||
// This returns the execution payload of a given slot. The function has full awareness of pre and post merge.
|
||||
// This returns the execution payload of a given slot.
|
||||
// The function has full awareness of pre and post merge.
|
||||
// The payload is computed given the respected time of merge.
|
||||
func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx types.ValidatorIndex, headRoot [32]byte) (*enginev1.ExecutionPayload, error) {
|
||||
func (vs *Server) getExecutionPayload(ctx context.Context,
|
||||
slot types.Slot,
|
||||
vIdx types.ValidatorIndex,
|
||||
headRoot [32]byte,
|
||||
st state.BeaconState) (*enginev1.ExecutionPayload, error) {
|
||||
proposerID, payloadId, ok := vs.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, headRoot)
|
||||
feeRecipient := params.BeaconConfig().DefaultFeeRecipient
|
||||
recipient, err := vs.BeaconDB.FeeRecipientByValidatorID(ctx, vIdx)
|
||||
@@ -70,7 +75,7 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
|
||||
payload, err := vs.ExecutionEngineCaller.GetPayload(ctx, pid)
|
||||
switch {
|
||||
case err == nil:
|
||||
warnIfFeeRecipientDiffers(payload, feeRecipient)
|
||||
warnIfFeeRecipientDiffers(payload.FeeRecipient, feeRecipient)
|
||||
return payload, nil
|
||||
case errors.Is(err, context.DeadlineExceeded):
|
||||
default:
|
||||
@@ -78,15 +83,6 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
|
||||
}
|
||||
}
|
||||
|
||||
st, err := vs.HeadFetcher.HeadState(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st, err = transition.ProcessSlotsIfPossible(ctx, st, slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var parentHash []byte
|
||||
var hasTerminalBlock bool
|
||||
mergeComplete, err := blocks.IsMergeTransitionComplete(st)
|
||||
@@ -165,18 +161,129 @@ func (vs *Server) getExecutionPayload(ctx context.Context, slot types.Slot, vIdx
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
warnIfFeeRecipientDiffers(payload, feeRecipient)
|
||||
warnIfFeeRecipientDiffers(payload.FeeRecipient, feeRecipient)
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// This returns the execution payload of a given slot after the Capella upgrade
|
||||
func (vs *Server) getExecutionPayloadV2(ctx context.Context,
|
||||
slot types.Slot,
|
||||
vIdx types.ValidatorIndex,
|
||||
headRoot [32]byte,
|
||||
st state.BeaconState) (*enginev1.ExecutionPayloadCapella, error) {
|
||||
proposerID, payloadId, ok := vs.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, headRoot)
|
||||
feeRecipient := params.BeaconConfig().DefaultFeeRecipient
|
||||
recipient, err := vs.BeaconDB.FeeRecipientByValidatorID(ctx, vIdx)
|
||||
switch err == nil {
|
||||
case true:
|
||||
feeRecipient = recipient
|
||||
case errors.As(err, kv.ErrNotFoundFeeRecipient):
|
||||
// If fee recipient is not found in DB and not set from beacon node CLI,
|
||||
// use the burn address.
|
||||
if feeRecipient.String() == params.BeaconConfig().EthBurnAddressHex {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"validatorIndex": vIdx,
|
||||
"burnAddress": params.BeaconConfig().EthBurnAddressHex,
|
||||
}).Warn("Fee recipient is currently using the burn address, " +
|
||||
"you will not be rewarded transaction fees on this setting. " +
|
||||
"Please set a different eth address as the fee recipient. " +
|
||||
"Please refer to our documentation for instructions")
|
||||
}
|
||||
default:
|
||||
return nil, errors.Wrap(err, "could not get fee recipient in db")
|
||||
}
|
||||
|
||||
if ok && proposerID == vIdx && payloadId != [8]byte{} { // Payload ID is cache hit. Return the cached payload ID.
|
||||
var pid [8]byte
|
||||
copy(pid[:], payloadId[:])
|
||||
payloadIDCacheHit.Inc()
|
||||
payload, err := vs.ExecutionEngineCaller.GetPayloadV2(ctx, pid)
|
||||
switch {
|
||||
case err == nil:
|
||||
warnIfFeeRecipientDiffers(payload.FeeRecipient, feeRecipient)
|
||||
return payload, nil
|
||||
case errors.Is(err, context.DeadlineExceeded):
|
||||
default:
|
||||
return nil, errors.Wrap(err, "could not get cached payload from execution client")
|
||||
}
|
||||
}
|
||||
payloadIDCacheMiss.Inc()
|
||||
|
||||
header, err := st.LatestExecutionPayloadHeader()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get latest execution payload header")
|
||||
}
|
||||
parentHash := header.BlockHash()
|
||||
|
||||
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
finalizedBlockHash := params.BeaconConfig().ZeroHash[:]
|
||||
finalizedRoot := bytesutil.ToBytes32(st.FinalizedCheckpoint().Root)
|
||||
if finalizedRoot != [32]byte{} { // finalized root could be zeros before the first finalized block.
|
||||
finalizedBlock, err := vs.BeaconDB.Block(ctx, bytesutil.ToBytes32(st.FinalizedCheckpoint().Root))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := consensusblocks.BeaconBlockIsNil(finalizedBlock); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch finalizedBlock.Version() {
|
||||
case version.Phase0, version.Altair: // Blocks before Bellatrix don't have execution payloads. Use zeros as the hash.
|
||||
default:
|
||||
finalizedPayload, err := finalizedBlock.Block().Body().Execution()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
finalizedBlockHash = finalizedPayload.BlockHash()
|
||||
}
|
||||
}
|
||||
|
||||
f := &enginev1.ForkchoiceState{
|
||||
HeadBlockHash: parentHash,
|
||||
SafeBlockHash: parentHash,
|
||||
FinalizedBlockHash: finalizedBlockHash,
|
||||
}
|
||||
|
||||
t, err := slots.ToTime(st.GenesisTime(), slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
withdrawals, err := st.ExpectedWithdrawals()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get expected withdrawals")
|
||||
}
|
||||
|
||||
p := &enginev1.PayloadAttributesV2{
|
||||
Timestamp: uint64(t.Unix()),
|
||||
PrevRandao: random,
|
||||
SuggestedFeeRecipient: feeRecipient.Bytes(),
|
||||
Withdrawals: withdrawals,
|
||||
}
|
||||
payloadID, _, err := vs.ExecutionEngineCaller.ForkchoiceUpdatedV2(ctx, f, p)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not prepare payload")
|
||||
}
|
||||
if payloadID == nil {
|
||||
return nil, fmt.Errorf("nil payload with block hash: %#x", parentHash)
|
||||
}
|
||||
payload, err := vs.ExecutionEngineCaller.GetPayloadV2(ctx, *payloadID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
warnIfFeeRecipientDiffers(payload.FeeRecipient, feeRecipient)
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// warnIfFeeRecipientDiffers logs a warning if the fee recipient in the included payload does not
|
||||
// match the requested one.
|
||||
func warnIfFeeRecipientDiffers(payload *enginev1.ExecutionPayload, feeRecipient common.Address) {
|
||||
func warnIfFeeRecipientDiffers(payloadRecipient []byte, feeRecipient common.Address) {
|
||||
// Warn if the fee recipient is not the value we expect.
|
||||
if payload != nil && !bytes.Equal(payload.FeeRecipient, feeRecipient[:]) {
|
||||
if !bytes.Equal(payloadRecipient, feeRecipient[:]) {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"wantedFeeRecipient": fmt.Sprintf("%#x", feeRecipient),
|
||||
"received": fmt.Sprintf("%#x", payload.FeeRecipient),
|
||||
"received": fmt.Sprintf("%#x", payloadRecipient),
|
||||
}).Warn("Fee recipient address from execution client is not what was expected. " +
|
||||
"It is possible someone has compromised your client to try and take your transaction fees")
|
||||
}
|
||||
|
||||
@@ -14,21 +14,29 @@ import (
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// blockData required to create a beacon block.
|
||||
type blockData struct {
|
||||
ParentRoot []byte
|
||||
Graffiti [32]byte
|
||||
ProposerIdx types.ValidatorIndex
|
||||
Eth1Data *ethpb.Eth1Data
|
||||
Deposits []*ethpb.Deposit
|
||||
Attestations []*ethpb.Attestation
|
||||
ProposerSlashings []*ethpb.ProposerSlashing
|
||||
AttesterSlashings []*ethpb.AttesterSlashing
|
||||
VoluntaryExits []*ethpb.SignedVoluntaryExit
|
||||
Slot types.Slot
|
||||
ParentRoot []byte
|
||||
Graffiti [32]byte
|
||||
ProposerIdx types.ValidatorIndex
|
||||
Eth1Data *ethpb.Eth1Data
|
||||
Deposits []*ethpb.Deposit
|
||||
Attestations []*ethpb.Attestation
|
||||
RandaoReveal []byte
|
||||
ProposerSlashings []*ethpb.ProposerSlashing
|
||||
AttesterSlashings []*ethpb.AttesterSlashing
|
||||
VoluntaryExits []*ethpb.SignedVoluntaryExit
|
||||
SyncAggregate *ethpb.SyncAggregate
|
||||
ExecutionPayload *enginev1.ExecutionPayload
|
||||
ExecutionPayloadV2 *enginev1.ExecutionPayloadCapella
|
||||
BlsToExecutionChanges []*ethpb.SignedBLSToExecutionChange
|
||||
}
|
||||
|
||||
func (vs *Server) getPhase0BeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlock, error) {
|
||||
@@ -43,7 +51,7 @@ func (vs *Server) getPhase0BeaconBlock(ctx context.Context, req *ethpb.BlockRequ
|
||||
stateRoot := params.BeaconConfig().ZeroHash[:]
|
||||
|
||||
blk := ðpb.BeaconBlock{
|
||||
Slot: req.Slot,
|
||||
Slot: blkData.Slot,
|
||||
ParentRoot: blkData.ParentRoot,
|
||||
StateRoot: stateRoot,
|
||||
ProposerIndex: blkData.ProposerIdx,
|
||||
@@ -51,7 +59,7 @@ func (vs *Server) getPhase0BeaconBlock(ctx context.Context, req *ethpb.BlockRequ
|
||||
Eth1Data: blkData.Eth1Data,
|
||||
Deposits: blkData.Deposits,
|
||||
Attestations: blkData.Attestations,
|
||||
RandaoReveal: req.RandaoReveal,
|
||||
RandaoReveal: blkData.RandaoReveal,
|
||||
ProposerSlashings: blkData.ProposerSlashings,
|
||||
AttesterSlashings: blkData.AttesterSlashings,
|
||||
VoluntaryExits: blkData.VoluntaryExits,
|
||||
@@ -156,15 +164,63 @@ func (vs *Server) buildPhase0BlockData(ctx context.Context, req *ethpb.BlockRequ
|
||||
validExits = append(validExits, exit)
|
||||
}
|
||||
|
||||
return &blockData{
|
||||
blk := &blockData{
|
||||
Slot: req.Slot,
|
||||
ParentRoot: parentRoot,
|
||||
Graffiti: graffiti,
|
||||
ProposerIdx: idx,
|
||||
Eth1Data: eth1Data,
|
||||
Deposits: deposits,
|
||||
Attestations: atts,
|
||||
RandaoReveal: req.RandaoReveal,
|
||||
ProposerSlashings: validProposerSlashings,
|
||||
AttesterSlashings: validAttSlashings,
|
||||
VoluntaryExits: validExits,
|
||||
}, nil
|
||||
}
|
||||
|
||||
if slots.ToEpoch(req.Slot) >= params.BeaconConfig().AltairForkEpoch {
|
||||
syncAggregate, err := vs.getSyncAggregate(ctx, req.Slot-1, bytesutil.ToBytes32(parentRoot))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not compute the sync aggregate")
|
||||
}
|
||||
|
||||
blk.SyncAggregate = syncAggregate
|
||||
}
|
||||
|
||||
if slots.ToEpoch(req.Slot) >= params.BeaconConfig().BellatrixForkEpoch {
|
||||
// We request the execution payload only if the validator is not registered
|
||||
// with a relayer
|
||||
registered, err := vs.validatorRegistered(ctx, idx)
|
||||
if !registered || err != nil {
|
||||
if slots.ToEpoch(req.Slot) >= params.BeaconConfig().CapellaForkEpoch {
|
||||
executionPayloadV2, err := vs.getExecutionPayloadV2(
|
||||
ctx,
|
||||
req.Slot,
|
||||
idx,
|
||||
bytesutil.ToBytes32(parentRoot),
|
||||
head,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get execution payload")
|
||||
}
|
||||
blk.ExecutionPayloadV2 = executionPayloadV2
|
||||
// TODO pack BlsToExecutionChanges Here
|
||||
blk.BlsToExecutionChanges = make([]*ethpb.SignedBLSToExecutionChange, 0)
|
||||
} else {
|
||||
executionPayload, err := vs.getExecutionPayload(
|
||||
ctx,
|
||||
req.Slot,
|
||||
idx,
|
||||
bytesutil.ToBytes32(parentRoot),
|
||||
head,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get execution payload")
|
||||
}
|
||||
blk.ExecutionPayload = executionPayload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blk, nil
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func (s *Service) processProposerSlashings(ctx context.Context, slashings []*eth
|
||||
// Log the slashing event and insert into the beacon node's operations pool.
|
||||
logProposerSlashing(sl)
|
||||
if err := s.serviceCfg.SlashingPoolInserter.InsertProposerSlashing(ctx, beaconState, sl); err != nil {
|
||||
log.WithError(err).Error("Could not insert attester slashing into operations pool")
|
||||
log.WithError(err).Error("Could not insert proposer slashing into operations pool")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -63,6 +63,8 @@ type ReadOnlyBeaconState interface {
|
||||
IsNil() bool
|
||||
Version() int
|
||||
LatestExecutionPayloadHeader() (interfaces.ExecutionData, error)
|
||||
LastWithdrawalValidatorIndex() (types.ValidatorIndex, error)
|
||||
ExpectedWithdrawals() ([]*enginev1.Withdrawal, error)
|
||||
}
|
||||
|
||||
// WriteOnlyBeaconState defines a struct which only has write access to beacon state methods.
|
||||
@@ -85,10 +87,8 @@ type WriteOnlyBeaconState interface {
|
||||
UpdateSlashingsAtIndex(idx, val uint64) error
|
||||
AppendHistoricalRoots(root [32]byte) error
|
||||
SetLatestExecutionPayloadHeader(payload interfaces.ExecutionData) error
|
||||
SetWithdrawalQueue(val []*enginev1.Withdrawal) error
|
||||
AppendWithdrawal(val *enginev1.Withdrawal) error
|
||||
SetNextWithdrawalIndex(i uint64) error
|
||||
SetNextPartialWithdrawalValidatorIndex(i types.ValidatorIndex) error
|
||||
SetLastWithdrawalValidatorIndex(i types.ValidatorIndex) error
|
||||
}
|
||||
|
||||
// ReadOnlyValidator defines a struct which only has read access to validator methods.
|
||||
|
||||
@@ -62,6 +62,7 @@ go_library(
|
||||
"//proto/engine/v1:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
@@ -90,10 +91,7 @@ go_test(
|
||||
"state_test.go",
|
||||
"state_trie_test.go",
|
||||
"types_test.go",
|
||||
] + select({
|
||||
"//config:mainnet": ["beacon_state_mainnet_test.go"],
|
||||
"//config:minimal": ["beacon_state_minimal_test.go"],
|
||||
}),
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/transition:go_default_library",
|
||||
|
||||
@@ -19,37 +19,36 @@ import (
|
||||
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
|
||||
type BeaconState struct {
|
||||
version int
|
||||
genesisTime uint64 `ssz-gen:"true"`
|
||||
genesisValidatorsRoot [32]byte `ssz-gen:"true" ssz-size:"32"`
|
||||
slot eth2types.Slot `ssz-gen:"true"`
|
||||
fork *ethpb.Fork `ssz-gen:"true"`
|
||||
latestBlockHeader *ethpb.BeaconBlockHeader `ssz-gen:"true"`
|
||||
blockRoots *customtypes.BlockRoots `ssz-gen:"true" ssz-size:"8192,32"`
|
||||
stateRoots *customtypes.StateRoots `ssz-gen:"true" ssz-size:"8192,32"`
|
||||
historicalRoots customtypes.HistoricalRoots `ssz-gen:"true" ssz-size:"?,32" ssz-max:"16777216"`
|
||||
eth1Data *ethpb.Eth1Data `ssz-gen:"true"`
|
||||
eth1DataVotes []*ethpb.Eth1Data `ssz-gen:"true" ssz-max:"2048"`
|
||||
eth1DepositIndex uint64 `ssz-gen:"true"`
|
||||
validators []*ethpb.Validator `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
balances []uint64 `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
randaoMixes *customtypes.RandaoMixes `ssz-gen:"true" ssz-size:"65536,32"`
|
||||
slashings []uint64 `ssz-gen:"true" ssz-size:"8192"`
|
||||
previousEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"4096"`
|
||||
currentEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"4096"`
|
||||
previousEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
currentEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
justificationBits bitfield.Bitvector4 `ssz-gen:"true" ssz-size:"1"`
|
||||
previousJustifiedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
currentJustifiedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
finalizedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
inactivityScores []uint64 `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
currentSyncCommittee *ethpb.SyncCommittee `ssz-gen:"true"`
|
||||
nextSyncCommittee *ethpb.SyncCommittee `ssz-gen:"true"`
|
||||
latestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader `ssz-gen:"true"`
|
||||
latestExecutionPayloadHeaderCapella *enginev1.ExecutionPayloadHeaderCapella `ssz-gen:"true"`
|
||||
withdrawalQueue []*enginev1.Withdrawal `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
nextWithdrawalIndex uint64 `ssz-gen:"true"`
|
||||
nextPartialWithdrawalValidatorIndex eth2types.ValidatorIndex `ssz-gen:"true"`
|
||||
genesisTime uint64
|
||||
genesisValidatorsRoot [32]byte
|
||||
slot eth2types.Slot
|
||||
fork *ethpb.Fork
|
||||
latestBlockHeader *ethpb.BeaconBlockHeader
|
||||
blockRoots *customtypes.BlockRoots
|
||||
stateRoots *customtypes.StateRoots
|
||||
historicalRoots customtypes.HistoricalRoots
|
||||
eth1Data *ethpb.Eth1Data
|
||||
eth1DataVotes []*ethpb.Eth1Data
|
||||
eth1DepositIndex uint64
|
||||
validators []*ethpb.Validator
|
||||
balances []uint64
|
||||
randaoMixes *customtypes.RandaoMixes
|
||||
slashings []uint64
|
||||
previousEpochAttestations []*ethpb.PendingAttestation
|
||||
currentEpochAttestations []*ethpb.PendingAttestation
|
||||
previousEpochParticipation []byte
|
||||
currentEpochParticipation []byte
|
||||
justificationBits bitfield.Bitvector4
|
||||
previousJustifiedCheckpoint *ethpb.Checkpoint
|
||||
currentJustifiedCheckpoint *ethpb.Checkpoint
|
||||
finalizedCheckpoint *ethpb.Checkpoint
|
||||
inactivityScores []uint64
|
||||
currentSyncCommittee *ethpb.SyncCommittee
|
||||
nextSyncCommittee *ethpb.SyncCommittee
|
||||
latestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader
|
||||
latestExecutionPayloadHeaderCapella *enginev1.ExecutionPayloadHeaderCapella
|
||||
nextWithdrawalIndex uint64
|
||||
lastWithdrawalValidatorIndex eth2types.ValidatorIndex
|
||||
|
||||
lock sync.RWMutex
|
||||
dirtyFields map[nativetypes.FieldIndex]bool
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
//go:build !minimal
|
||||
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
)
|
||||
|
||||
func TestMainnetSszValuesAgainstFieldParams(t *testing.T) {
|
||||
// Casting needed to avoid lock copy analyzer issue.
|
||||
bs := (interface{})(BeaconState{})
|
||||
bsType := reflect.TypeOf(bs)
|
||||
|
||||
f, ok := bsType.FieldByName("genesisValidatorsRoot")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v := f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("blockRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.BlockRootsLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("stateRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.StateRootsLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("historicalRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, "?,"+strconv.Itoa(fieldparams.RootLength), v)
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.HistoricalRootsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("eth1DataVotes")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.Eth1DataVotesLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("validators")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
|
||||
|
||||
f, ok = bsType.FieldByName("balances")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
|
||||
|
||||
f, ok = bsType.FieldByName("randaoMixes")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.RandaoMixesLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("slashings")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.SlashingsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("previousEpochAttestations")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.PreviousEpochAttestationsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("currentEpochAttestations")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.CurrentEpochAttestationsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("justificationBits")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, "1", v)
|
||||
|
||||
f, ok = bsType.FieldByName("inactivityScores")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
|
||||
}
|
||||
@@ -19,37 +19,36 @@ import (
|
||||
// getters and setters for its respective values and helpful functions such as HashTreeRoot().
|
||||
type BeaconState struct {
|
||||
version int
|
||||
genesisTime uint64 `ssz-gen:"true"`
|
||||
genesisValidatorsRoot [32]byte `ssz-gen:"true" ssz-size:"32"`
|
||||
slot eth2types.Slot `ssz-gen:"true"`
|
||||
fork *ethpb.Fork `ssz-gen:"true"`
|
||||
latestBlockHeader *ethpb.BeaconBlockHeader `ssz-gen:"true"`
|
||||
blockRoots *customtypes.BlockRoots `ssz-gen:"true" ssz-size:"64,32"`
|
||||
stateRoots *customtypes.StateRoots `ssz-gen:"true" ssz-size:"64,32"`
|
||||
historicalRoots customtypes.HistoricalRoots `ssz-gen:"true" ssz-size:"?,32" ssz-max:"16777216"`
|
||||
eth1Data *ethpb.Eth1Data `ssz-gen:"true"`
|
||||
eth1DataVotes []*ethpb.Eth1Data `ssz-gen:"true" ssz-max:"32"`
|
||||
eth1DepositIndex uint64 `ssz-gen:"true"`
|
||||
validators []*ethpb.Validator `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
balances []uint64 `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
randaoMixes *customtypes.RandaoMixes `ssz-gen:"true" ssz-size:"64,32"`
|
||||
slashings []uint64 `ssz-gen:"true" ssz-size:"64"`
|
||||
previousEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"1024"`
|
||||
currentEpochAttestations []*ethpb.PendingAttestation `ssz-gen:"true" ssz-max:"1024"`
|
||||
previousEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
currentEpochParticipation []byte `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
justificationBits bitfield.Bitvector4 `ssz-gen:"true" ssz-size:"1"`
|
||||
previousJustifiedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
currentJustifiedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
finalizedCheckpoint *ethpb.Checkpoint `ssz-gen:"true"`
|
||||
inactivityScores []uint64 `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
currentSyncCommittee *ethpb.SyncCommittee `ssz-gen:"true"`
|
||||
nextSyncCommittee *ethpb.SyncCommittee `ssz-gen:"true"`
|
||||
latestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader `ssz-gen:"true"`
|
||||
latestExecutionPayloadHeaderCapella *enginev1.ExecutionPayloadHeaderCapella `ssz-gen:"true"`
|
||||
withdrawalQueue []*enginev1.Withdrawal `ssz-gen:"true" ssz-max:"1099511627776"`
|
||||
nextWithdrawalIndex uint64 `ssz-gen:"true"`
|
||||
nextPartialWithdrawalValidatorIndex eth2types.ValidatorIndex `ssz-gen:"true"`
|
||||
genesisTime uint64
|
||||
genesisValidatorsRoot [32]byte
|
||||
slot eth2types.Slot
|
||||
fork *ethpb.Fork
|
||||
latestBlockHeader *ethpb.BeaconBlockHeader
|
||||
blockRoots *customtypes.BlockRoots
|
||||
stateRoots *customtypes.StateRoots
|
||||
historicalRoots customtypes.HistoricalRoots
|
||||
eth1Data *ethpb.Eth1Data
|
||||
eth1DataVotes []*ethpb.Eth1Data
|
||||
eth1DepositIndex uint64
|
||||
validators []*ethpb.Validator
|
||||
balances []uint64
|
||||
randaoMixes *customtypes.RandaoMixes
|
||||
slashings []uint64
|
||||
previousEpochAttestations []*ethpb.PendingAttestation
|
||||
currentEpochAttestations []*ethpb.PendingAttestation
|
||||
previousEpochParticipation []byte
|
||||
currentEpochParticipation []byte
|
||||
justificationBits bitfield.Bitvector4
|
||||
previousJustifiedCheckpoint *ethpb.Checkpoint
|
||||
currentJustifiedCheckpoint *ethpb.Checkpoint
|
||||
finalizedCheckpoint *ethpb.Checkpoint
|
||||
inactivityScores []uint64
|
||||
currentSyncCommittee *ethpb.SyncCommittee
|
||||
nextSyncCommittee *ethpb.SyncCommittee
|
||||
latestExecutionPayloadHeader *enginev1.ExecutionPayloadHeader
|
||||
latestExecutionPayloadHeaderCapella *enginev1.ExecutionPayloadHeaderCapella
|
||||
nextWithdrawalIndex uint64
|
||||
lastWithdrawalValidatorIndex eth2types.ValidatorIndex
|
||||
|
||||
lock sync.RWMutex
|
||||
dirtyFields map[nativetypes.FieldIndex]bool
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
//go:build minimal
|
||||
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
)
|
||||
|
||||
func TestMinimalSszValuesAgainstFieldParams(t *testing.T) {
|
||||
// Casting needed to avoid lock copy analyzer issue.
|
||||
bs := (interface{})(BeaconState{})
|
||||
bsType := reflect.TypeOf(bs)
|
||||
|
||||
f, ok := bsType.FieldByName("genesisValidatorsRoot")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v := f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("blockRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.BlockRootsLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("stateRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.StateRootsLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("historicalRoots")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, "?,"+strconv.Itoa(fieldparams.RootLength), v)
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.HistoricalRootsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("eth1DataVotes")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.Eth1DataVotesLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("validators")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
|
||||
|
||||
f, ok = bsType.FieldByName("balances")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
|
||||
|
||||
f, ok = bsType.FieldByName("randaoMixes")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.RandaoMixesLength)+","+strconv.Itoa(fieldparams.RootLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("slashings")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.SlashingsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("previousEpochAttestations")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.PreviousEpochAttestationsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("currentEpochAttestations")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.CurrentEpochAttestationsLength), v)
|
||||
|
||||
f, ok = bsType.FieldByName("justificationBits")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-size")
|
||||
assert.Equal(t, "1", v)
|
||||
|
||||
f, ok = bsType.FieldByName("inactivityScores")
|
||||
require.Equal(t, true, ok, "Required field not found")
|
||||
v = f.Tag.Get("ssz-max")
|
||||
assert.Equal(t, strconv.Itoa(fieldparams.ValidatorRegistryLimit), v)
|
||||
}
|
||||
@@ -14,10 +14,6 @@ func (b *BeaconState) LatestExecutionPayloadHeader() (interfaces.ExecutionData,
|
||||
return nil, errNotSupported("LatestExecutionPayloadHeader", b.version)
|
||||
}
|
||||
|
||||
if b.latestExecutionPayloadHeader == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
|
||||
@@ -99,34 +99,33 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
|
||||
}
|
||||
case version.Capella:
|
||||
return ðpb.BeaconStateCapella{
|
||||
GenesisTime: b.genesisTime,
|
||||
GenesisValidatorsRoot: gvrCopy[:],
|
||||
Slot: b.slot,
|
||||
Fork: b.fork,
|
||||
LatestBlockHeader: b.latestBlockHeader,
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1Data,
|
||||
Eth1DataVotes: b.eth1DataVotes,
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validators,
|
||||
Balances: b.balances,
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
Slashings: b.slashings,
|
||||
PreviousEpochParticipation: b.previousEpochParticipation,
|
||||
CurrentEpochParticipation: b.currentEpochParticipation,
|
||||
JustificationBits: b.justificationBits,
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
|
||||
FinalizedCheckpoint: b.finalizedCheckpoint,
|
||||
InactivityScores: b.inactivityScores,
|
||||
CurrentSyncCommittee: b.currentSyncCommittee,
|
||||
NextSyncCommittee: b.nextSyncCommittee,
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderCapella,
|
||||
WithdrawalQueue: b.withdrawalQueue,
|
||||
NextWithdrawalIndex: b.nextWithdrawalIndex,
|
||||
NextPartialWithdrawalValidatorIndex: b.nextPartialWithdrawalValidatorIndex,
|
||||
GenesisTime: b.genesisTime,
|
||||
GenesisValidatorsRoot: gvrCopy[:],
|
||||
Slot: b.slot,
|
||||
Fork: b.fork,
|
||||
LatestBlockHeader: b.latestBlockHeader,
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1Data,
|
||||
Eth1DataVotes: b.eth1DataVotes,
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validators,
|
||||
Balances: b.balances,
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
Slashings: b.slashings,
|
||||
PreviousEpochParticipation: b.previousEpochParticipation,
|
||||
CurrentEpochParticipation: b.currentEpochParticipation,
|
||||
JustificationBits: b.justificationBits,
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpoint,
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpoint,
|
||||
FinalizedCheckpoint: b.finalizedCheckpoint,
|
||||
InactivityScores: b.inactivityScores,
|
||||
CurrentSyncCommittee: b.currentSyncCommittee,
|
||||
NextSyncCommittee: b.nextSyncCommittee,
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderCapella,
|
||||
NextWithdrawalIndex: b.nextWithdrawalIndex,
|
||||
LastWithdrawalValidatorIndex: b.lastWithdrawalValidatorIndex,
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
@@ -226,34 +225,33 @@ func (b *BeaconState) ToProto() interface{} {
|
||||
}
|
||||
case version.Capella:
|
||||
return ðpb.BeaconStateCapella{
|
||||
GenesisTime: b.genesisTime,
|
||||
GenesisValidatorsRoot: gvrCopy[:],
|
||||
Slot: b.slot,
|
||||
Fork: b.forkVal(),
|
||||
LatestBlockHeader: b.latestBlockHeaderVal(),
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1DataVal(),
|
||||
Eth1DataVotes: b.eth1DataVotesVal(),
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validatorsVal(),
|
||||
Balances: b.balancesVal(),
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
Slashings: b.slashingsVal(),
|
||||
PreviousEpochParticipation: b.previousEpochParticipationVal(),
|
||||
CurrentEpochParticipation: b.currentEpochParticipationVal(),
|
||||
JustificationBits: b.justificationBitsVal(),
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
|
||||
FinalizedCheckpoint: b.finalizedCheckpointVal(),
|
||||
InactivityScores: b.inactivityScoresVal(),
|
||||
CurrentSyncCommittee: b.currentSyncCommitteeVal(),
|
||||
NextSyncCommittee: b.nextSyncCommitteeVal(),
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderCapellaVal(),
|
||||
WithdrawalQueue: b.withdrawalQueueVal(),
|
||||
NextWithdrawalIndex: b.nextWithdrawalIndex,
|
||||
NextPartialWithdrawalValidatorIndex: b.nextPartialWithdrawalValidatorIndex,
|
||||
GenesisTime: b.genesisTime,
|
||||
GenesisValidatorsRoot: gvrCopy[:],
|
||||
Slot: b.slot,
|
||||
Fork: b.forkVal(),
|
||||
LatestBlockHeader: b.latestBlockHeaderVal(),
|
||||
BlockRoots: b.blockRoots.Slice(),
|
||||
StateRoots: b.stateRoots.Slice(),
|
||||
HistoricalRoots: b.historicalRoots.Slice(),
|
||||
Eth1Data: b.eth1DataVal(),
|
||||
Eth1DataVotes: b.eth1DataVotesVal(),
|
||||
Eth1DepositIndex: b.eth1DepositIndex,
|
||||
Validators: b.validatorsVal(),
|
||||
Balances: b.balancesVal(),
|
||||
RandaoMixes: b.randaoMixes.Slice(),
|
||||
Slashings: b.slashingsVal(),
|
||||
PreviousEpochParticipation: b.previousEpochParticipationVal(),
|
||||
CurrentEpochParticipation: b.currentEpochParticipationVal(),
|
||||
JustificationBits: b.justificationBitsVal(),
|
||||
PreviousJustifiedCheckpoint: b.previousJustifiedCheckpointVal(),
|
||||
CurrentJustifiedCheckpoint: b.currentJustifiedCheckpointVal(),
|
||||
FinalizedCheckpoint: b.finalizedCheckpointVal(),
|
||||
InactivityScores: b.inactivityScoresVal(),
|
||||
CurrentSyncCommittee: b.currentSyncCommitteeVal(),
|
||||
NextSyncCommittee: b.nextSyncCommitteeVal(),
|
||||
LatestExecutionPayloadHeader: b.latestExecutionPayloadHeaderCapellaVal(),
|
||||
NextWithdrawalIndex: b.nextWithdrawalIndex,
|
||||
LastWithdrawalValidatorIndex: b.lastWithdrawalValidatorIndex,
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
|
||||
@@ -1,27 +1,15 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
)
|
||||
|
||||
// WithdrawalQueue returns the list of pending withdrawals.
|
||||
func (b *BeaconState) WithdrawalQueue() ([]*enginev1.Withdrawal, error) {
|
||||
if b.version < version.Capella {
|
||||
return nil, errNotSupported("WithdrawalQueue", b.version)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.withdrawalQueueVal(), nil
|
||||
}
|
||||
|
||||
func (b *BeaconState) withdrawalQueueVal() []*enginev1.Withdrawal {
|
||||
return ethpb.CopyWithdrawalSlice(b.withdrawalQueue)
|
||||
}
|
||||
const ETH1AddressOffset = 12
|
||||
|
||||
// NextWithdrawalIndex returns the index that will be assigned to the next withdrawal.
|
||||
func (b *BeaconState) NextWithdrawalIndex() (uint64, error) {
|
||||
@@ -37,13 +25,90 @@ func (b *BeaconState) NextWithdrawalIndex() (uint64, error) {
|
||||
|
||||
// NextPartialWithdrawalValidatorIndex returns the index of the validator which is
|
||||
// next in line for a partial withdrawal.
|
||||
func (b *BeaconState) NextPartialWithdrawalValidatorIndex() (types.ValidatorIndex, error) {
|
||||
func (b *BeaconState) LastWithdrawalValidatorIndex() (types.ValidatorIndex, error) {
|
||||
if b.version < version.Capella {
|
||||
return 0, errNotSupported("NextPartialWithdrawalValidatorIndex", b.version)
|
||||
return 0, errNotSupported("LastWithdrawalValidatorIndex", b.version)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
return b.nextPartialWithdrawalValidatorIndex, nil
|
||||
return b.lastWithdrawalValidatorIndex, nil
|
||||
}
|
||||
|
||||
// hasETH1WithdrawalCredential returns whether the validator has an ETH1
|
||||
// Withdrawal prefix. It assumes that the caller has a lock on the state
|
||||
func hasETH1WithdrawalCredential(val *ethpb.Validator) bool {
|
||||
if val == nil {
|
||||
return false
|
||||
}
|
||||
cred := val.WithdrawalCredentials
|
||||
return len(cred) > 0 && cred[0] == params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
}
|
||||
|
||||
// isFullyWithdrawableValidator returns whether the validator is able to perform a full
|
||||
// withdrawal. This differ from the spec helper in that the balance > 0 is not
|
||||
// checked. This function assumes that the caller holds a lock on the state
|
||||
func isFullyWithdrawableValidator(val *ethpb.Validator, epoch types.Epoch) bool {
|
||||
if val == nil {
|
||||
return false
|
||||
}
|
||||
return hasETH1WithdrawalCredential(val) && val.WithdrawableEpoch <= epoch
|
||||
}
|
||||
|
||||
// isPartiallyWithdrawable returns whether the validator is able to perform a
|
||||
// partial withdrawal. This function assumes that the caller has a lock on the state
|
||||
func isPartiallyWithdrawableValidator(val *ethpb.Validator, balance uint64) bool {
|
||||
if val == nil {
|
||||
return false
|
||||
}
|
||||
hasMaxBalance := val.EffectiveBalance == params.BeaconConfig().MaxEffectiveBalance
|
||||
hasExcessBalance := balance > params.BeaconConfig().MaxEffectiveBalance
|
||||
return hasETH1WithdrawalCredential(val) && hasExcessBalance && hasMaxBalance
|
||||
}
|
||||
|
||||
// ExpectedWithdrawals returns the withdrawals that a proposer will need to pack in the next block
|
||||
// applied to the current state. It is also used by validators to check that the execution payload carried
|
||||
// the right number of withdrawals
|
||||
func (b *BeaconState) ExpectedWithdrawals() ([]*enginev1.Withdrawal, error) {
|
||||
if b.version < version.Capella {
|
||||
return nil, errNotSupported("ExpectedWithdrawals", b.version)
|
||||
}
|
||||
|
||||
b.lock.RLock()
|
||||
defer b.lock.RUnlock()
|
||||
|
||||
withdrawals := make([]*enginev1.Withdrawal, 0, params.BeaconConfig().MaxWithdrawalsPerPayload)
|
||||
validatorIndex := b.lastWithdrawalValidatorIndex
|
||||
withdrawalIndex := b.nextWithdrawalIndex
|
||||
epoch := slots.ToEpoch(b.slot)
|
||||
for range b.validators {
|
||||
validatorIndex += 1
|
||||
if uint64(validatorIndex) == uint64(len(b.validators)) {
|
||||
validatorIndex = types.ValidatorIndex(0)
|
||||
}
|
||||
val := b.validators[validatorIndex]
|
||||
balance := b.balances[validatorIndex]
|
||||
if isFullyWithdrawableValidator(val, epoch) {
|
||||
withdrawals = append(withdrawals, &enginev1.Withdrawal{
|
||||
WithdrawalIndex: withdrawalIndex,
|
||||
ValidatorIndex: validatorIndex,
|
||||
ExecutionAddress: val.WithdrawalCredentials[ETH1AddressOffset:],
|
||||
Amount: balance,
|
||||
})
|
||||
withdrawalIndex++
|
||||
} else if isPartiallyWithdrawableValidator(val, balance) {
|
||||
withdrawals = append(withdrawals, &enginev1.Withdrawal{
|
||||
WithdrawalIndex: withdrawalIndex,
|
||||
ValidatorIndex: validatorIndex,
|
||||
ExecutionAddress: val.WithdrawalCredentials[ETH1AddressOffset:],
|
||||
Amount: balance - params.BeaconConfig().MaxEffectiveBalance,
|
||||
})
|
||||
withdrawalIndex++
|
||||
}
|
||||
if uint64(len(withdrawals)) == params.BeaconConfig().MaxWithdrawalsPerPayload {
|
||||
break
|
||||
}
|
||||
}
|
||||
return withdrawals, nil
|
||||
}
|
||||
|
||||
@@ -3,39 +3,15 @@ package state_native
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
)
|
||||
|
||||
func TestWithdrawalQueue(t *testing.T) {
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
ws := []*enginev1.Withdrawal{
|
||||
{
|
||||
WithdrawalIndex: 0,
|
||||
ExecutionAddress: []byte("address1"),
|
||||
Amount: 1,
|
||||
},
|
||||
{
|
||||
WithdrawalIndex: 1,
|
||||
ExecutionAddress: []byte("address2"),
|
||||
Amount: 2,
|
||||
},
|
||||
}
|
||||
s := BeaconState{version: version.Capella, withdrawalQueue: ws}
|
||||
q, err := s.WithdrawalQueue()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, ws, q)
|
||||
})
|
||||
t.Run("version before Capella not supported", func(t *testing.T) {
|
||||
s := BeaconState{version: version.Bellatrix}
|
||||
_, err := s.WithdrawalQueue()
|
||||
assert.ErrorContains(t, "WithdrawalQueue is not supported", err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNextWithdrawalIndex(t *testing.T) {
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
s := BeaconState{version: version.Capella, nextWithdrawalIndex: 123}
|
||||
@@ -50,16 +26,285 @@ func TestNextWithdrawalIndex(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestNextPartialWithdrawalValidatorIndex(t *testing.T) {
|
||||
func TestLastWithdrawalValidatorIndex(t *testing.T) {
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
s := BeaconState{version: version.Capella, nextPartialWithdrawalValidatorIndex: 123}
|
||||
i, err := s.NextPartialWithdrawalValidatorIndex()
|
||||
s := BeaconState{version: version.Capella, lastWithdrawalValidatorIndex: 123}
|
||||
i, err := s.LastWithdrawalValidatorIndex()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, types.ValidatorIndex(123), i)
|
||||
})
|
||||
t.Run("version before Capella not supported", func(t *testing.T) {
|
||||
s := BeaconState{version: version.Bellatrix}
|
||||
_, err := s.NextPartialWithdrawalValidatorIndex()
|
||||
assert.ErrorContains(t, "NextPartialWithdrawalValidatorIndex is not supported", err)
|
||||
_, err := s.LastWithdrawalValidatorIndex()
|
||||
assert.ErrorContains(t, "LastWithdrawalValidatorIndex is not supported", err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestHasETH1WithdrawalCredentials(t *testing.T) {
|
||||
creds := []byte{0xFA, 0xCC}
|
||||
v := ðpb.Validator{WithdrawalCredentials: creds}
|
||||
require.Equal(t, false, hasETH1WithdrawalCredential(v))
|
||||
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
|
||||
v = ðpb.Validator{WithdrawalCredentials: creds}
|
||||
require.Equal(t, true, hasETH1WithdrawalCredential(v))
|
||||
// No Withdrawal cred
|
||||
v = ðpb.Validator{}
|
||||
require.Equal(t, false, hasETH1WithdrawalCredential(v))
|
||||
}
|
||||
|
||||
func TestIsFullyWithdrawableValidator(t *testing.T) {
|
||||
// No ETH1 prefix
|
||||
creds := []byte{0xFA, 0xCC}
|
||||
v := ðpb.Validator{
|
||||
WithdrawalCredentials: creds,
|
||||
WithdrawableEpoch: 2,
|
||||
}
|
||||
require.Equal(t, false, isFullyWithdrawableValidator(v, 3))
|
||||
// Wrong withdrawable epoch
|
||||
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
|
||||
v = ðpb.Validator{
|
||||
WithdrawalCredentials: creds,
|
||||
WithdrawableEpoch: 2,
|
||||
}
|
||||
require.Equal(t, false, isFullyWithdrawableValidator(v, 1))
|
||||
// Fully withdrawable
|
||||
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
|
||||
v = ðpb.Validator{
|
||||
WithdrawalCredentials: creds,
|
||||
WithdrawableEpoch: 2,
|
||||
}
|
||||
require.Equal(t, true, isFullyWithdrawableValidator(v, 3))
|
||||
}
|
||||
|
||||
func TestIsPartiallyWithdrawableValidator(t *testing.T) {
|
||||
// No ETH1 prefix
|
||||
creds := []byte{0xFA, 0xCC}
|
||||
v, err := NewValidator(ðpb.Validator{
|
||||
WithdrawalCredentials: creds,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, v.IsPartiallyWithdrawable(params.BeaconConfig().MaxEffectiveBalance+1))
|
||||
// Not the right effective balance
|
||||
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
|
||||
v, err = NewValidator(ðpb.Validator{
|
||||
WithdrawalCredentials: creds,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance - 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, v.IsPartiallyWithdrawable(params.BeaconConfig().MaxEffectiveBalance+1))
|
||||
// Not enough balance
|
||||
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
|
||||
v, err = NewValidator(ðpb.Validator{
|
||||
WithdrawalCredentials: creds,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, v.IsPartiallyWithdrawable(params.BeaconConfig().MaxEffectiveBalance))
|
||||
// Partially Withdrawable
|
||||
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
|
||||
v, err = NewValidator(ðpb.Validator{
|
||||
WithdrawalCredentials: creds,
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, v.IsPartiallyWithdrawable(params.BeaconConfig().MaxEffectiveBalance+1))
|
||||
}
|
||||
|
||||
func TestExpectedWithdrawals(t *testing.T) {
|
||||
t.Run("no withdrawals", func(t *testing.T) {
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
validators: make([]*ethpb.Validator, 100),
|
||||
balances: make([]uint64, 100),
|
||||
}
|
||||
for i := range s.validators {
|
||||
s.balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||
val := ðpb.Validator{
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
WithdrawableEpoch: types.Epoch(1),
|
||||
}
|
||||
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
s.validators[i] = val
|
||||
}
|
||||
expected, err := s.ExpectedWithdrawals()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(expected))
|
||||
})
|
||||
t.Run("one fully withdrawable", func(t *testing.T) {
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
validators: make([]*ethpb.Validator, 100),
|
||||
balances: make([]uint64, 100),
|
||||
}
|
||||
for i := range s.validators {
|
||||
s.balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||
val := ðpb.Validator{
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
WithdrawableEpoch: types.Epoch(1),
|
||||
}
|
||||
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
s.validators[i] = val
|
||||
}
|
||||
s.validators[3].WithdrawableEpoch = types.Epoch(0)
|
||||
expected, err := s.ExpectedWithdrawals()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(expected))
|
||||
withdrawal := &enginev1.Withdrawal{
|
||||
WithdrawalIndex: 0,
|
||||
ValidatorIndex: 3,
|
||||
ExecutionAddress: s.validators[3].WithdrawalCredentials[12:],
|
||||
Amount: s.balances[3],
|
||||
}
|
||||
require.DeepEqual(t, withdrawal, expected[0])
|
||||
})
|
||||
t.Run("one partially withdrawable", func(t *testing.T) {
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
validators: make([]*ethpb.Validator, 100),
|
||||
balances: make([]uint64, 100),
|
||||
}
|
||||
for i := range s.validators {
|
||||
s.balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||
val := ðpb.Validator{
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
WithdrawableEpoch: types.Epoch(1),
|
||||
}
|
||||
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
s.validators[i] = val
|
||||
}
|
||||
s.balances[3] += params.BeaconConfig().MinDepositAmount
|
||||
expected, err := s.ExpectedWithdrawals()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(expected))
|
||||
withdrawal := &enginev1.Withdrawal{
|
||||
WithdrawalIndex: 0,
|
||||
ValidatorIndex: 3,
|
||||
ExecutionAddress: s.validators[3].WithdrawalCredentials[12:],
|
||||
Amount: params.BeaconConfig().MinDepositAmount,
|
||||
}
|
||||
require.DeepEqual(t, withdrawal, expected[0])
|
||||
})
|
||||
t.Run("one partially and one fully withdrawable", func(t *testing.T) {
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
validators: make([]*ethpb.Validator, 100),
|
||||
balances: make([]uint64, 100),
|
||||
}
|
||||
for i := range s.validators {
|
||||
s.balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||
val := ðpb.Validator{
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
WithdrawableEpoch: types.Epoch(1),
|
||||
}
|
||||
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
s.validators[i] = val
|
||||
}
|
||||
s.balances[3] += params.BeaconConfig().MinDepositAmount
|
||||
s.validators[7].WithdrawableEpoch = types.Epoch(0)
|
||||
expected, err := s.ExpectedWithdrawals()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(expected))
|
||||
|
||||
withdrawalFull := &enginev1.Withdrawal{
|
||||
WithdrawalIndex: 1,
|
||||
ValidatorIndex: 7,
|
||||
ExecutionAddress: s.validators[7].WithdrawalCredentials[12:],
|
||||
Amount: s.balances[7],
|
||||
}
|
||||
withdrawalPartial := &enginev1.Withdrawal{
|
||||
WithdrawalIndex: 0,
|
||||
ValidatorIndex: 3,
|
||||
ExecutionAddress: s.validators[3].WithdrawalCredentials[12:],
|
||||
Amount: params.BeaconConfig().MinDepositAmount,
|
||||
}
|
||||
require.DeepEqual(t, withdrawalPartial, expected[0])
|
||||
require.DeepEqual(t, withdrawalFull, expected[1])
|
||||
|
||||
})
|
||||
t.Run("all partially withdrawable", func(t *testing.T) {
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
validators: make([]*ethpb.Validator, 100),
|
||||
balances: make([]uint64, 100),
|
||||
}
|
||||
for i := range s.validators {
|
||||
s.balances[i] = params.BeaconConfig().MaxEffectiveBalance + 1
|
||||
val := ðpb.Validator{
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
WithdrawableEpoch: types.Epoch(1),
|
||||
}
|
||||
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
s.validators[i] = val
|
||||
}
|
||||
expected, err := s.ExpectedWithdrawals()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MaxWithdrawalsPerPayload, uint64(len(expected)))
|
||||
withdrawal := &enginev1.Withdrawal{
|
||||
WithdrawalIndex: 0,
|
||||
ValidatorIndex: 1,
|
||||
ExecutionAddress: s.validators[0].WithdrawalCredentials[12:],
|
||||
Amount: 1,
|
||||
}
|
||||
require.DeepEqual(t, withdrawal, expected[0])
|
||||
})
|
||||
t.Run("all fully withdrawable", func(t *testing.T) {
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
validators: make([]*ethpb.Validator, 100),
|
||||
balances: make([]uint64, 100),
|
||||
}
|
||||
for i := range s.validators {
|
||||
s.balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||
val := ðpb.Validator{
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
WithdrawableEpoch: types.Epoch(0),
|
||||
}
|
||||
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
s.validators[i] = val
|
||||
}
|
||||
expected, err := s.ExpectedWithdrawals()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MaxWithdrawalsPerPayload, uint64(len(expected)))
|
||||
withdrawal := &enginev1.Withdrawal{
|
||||
WithdrawalIndex: 0,
|
||||
ValidatorIndex: 1,
|
||||
ExecutionAddress: s.validators[0].WithdrawalCredentials[12:],
|
||||
Amount: params.BeaconConfig().MaxEffectiveBalance,
|
||||
}
|
||||
require.DeepEqual(t, withdrawal, expected[0])
|
||||
})
|
||||
t.Run("all fully and partially withdrawable", func(t *testing.T) {
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
validators: make([]*ethpb.Validator, 100),
|
||||
balances: make([]uint64, 100),
|
||||
}
|
||||
for i := range s.validators {
|
||||
s.balances[i] = params.BeaconConfig().MaxEffectiveBalance + 1
|
||||
val := ðpb.Validator{
|
||||
WithdrawalCredentials: make([]byte, 32),
|
||||
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||
WithdrawableEpoch: types.Epoch(0),
|
||||
}
|
||||
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
s.validators[i] = val
|
||||
}
|
||||
expected, err := s.ExpectedWithdrawals()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MaxWithdrawalsPerPayload, uint64(len(expected)))
|
||||
withdrawal := &enginev1.Withdrawal{
|
||||
WithdrawalIndex: 0,
|
||||
ValidatorIndex: 1,
|
||||
ExecutionAddress: s.validators[0].WithdrawalCredentials[12:],
|
||||
Amount: params.BeaconConfig().MaxEffectiveBalance + 1,
|
||||
}
|
||||
require.DeepEqual(t, withdrawal, expected[0])
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -246,13 +246,6 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
|
||||
}
|
||||
fieldRoots[nativetypes.LatestExecutionPayloadHeaderCapella.RealPosition()] = executionPayloadRoot[:]
|
||||
|
||||
// Withdrawal queue root.
|
||||
withdrawalQueueRoot, err := ssz.WithdrawalSliceRoot(hasher, state.withdrawalQueue, fieldparams.WithdrawalQueueLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldRoots[nativetypes.WithdrawalQueue.RealPosition()] = withdrawalQueueRoot[:]
|
||||
|
||||
// Next withdrawal index root.
|
||||
nextWithdrawalIndexRoot := make([]byte, 32)
|
||||
binary.LittleEndian.PutUint64(nextWithdrawalIndexRoot, state.nextWithdrawalIndex)
|
||||
@@ -260,8 +253,8 @@ func ComputeFieldRootsWithHasher(ctx context.Context, state *BeaconState) ([][]b
|
||||
|
||||
// Next partial withdrawal validator index root.
|
||||
nextPartialWithdrawalValidatorIndexRoot := make([]byte, 32)
|
||||
binary.LittleEndian.PutUint64(nextPartialWithdrawalValidatorIndexRoot, uint64(state.nextPartialWithdrawalValidatorIndex))
|
||||
fieldRoots[nativetypes.NextPartialWithdrawalValidatorIndex.RealPosition()] = nextPartialWithdrawalValidatorIndexRoot
|
||||
binary.LittleEndian.PutUint64(nextPartialWithdrawalValidatorIndexRoot, uint64(state.lastWithdrawalValidatorIndex))
|
||||
fieldRoots[nativetypes.LastWithdrawalValidatorIndex.RealPosition()] = nextPartialWithdrawalValidatorIndexRoot
|
||||
}
|
||||
|
||||
return fieldRoots, nil
|
||||
|
||||
@@ -256,9 +256,8 @@ func TestComputeFieldRootsWithHasher_Capella(t *testing.T) {
|
||||
wrappedHeader, err := blocks.WrappedExecutionPayloadHeaderCapella(executionPayloadHeaderCapella())
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, beaconState.SetLatestExecutionPayloadHeader(wrappedHeader))
|
||||
require.NoError(t, beaconState.SetWithdrawalQueue([]*enginev1.Withdrawal{withdrawal()}))
|
||||
require.NoError(t, beaconState.SetNextWithdrawalIndex(123))
|
||||
require.NoError(t, beaconState.SetNextPartialWithdrawalValidatorIndex(123))
|
||||
require.NoError(t, beaconState.SetLastWithdrawalValidatorIndex(123))
|
||||
|
||||
nativeState, ok := beaconState.(*statenative.BeaconState)
|
||||
require.Equal(t, true, ok)
|
||||
@@ -297,7 +296,6 @@ func TestComputeFieldRootsWithHasher_Capella(t *testing.T) {
|
||||
{0x3d, 0xf3, 0x66, 0xd4, 0x12, 0x40, 0x3f, 0x28, 0xeb, 0xe4, 0x19, 0x59, 0xae, 0xab, 0x4d, 0xf3, 0x98, 0x88, 0x7f, 0x1e, 0x58, 0xa, 0x5d, 0xd4, 0xeb, 0xe5, 0x5d, 0x3d, 0x11, 0x70, 0x24, 0x76},
|
||||
{0xd6, 0x4c, 0xb1, 0xac, 0x61, 0x7, 0x26, 0xbb, 0xd3, 0x27, 0x2a, 0xcd, 0xdd, 0x55, 0xf, 0x2b, 0x6a, 0xe8, 0x1, 0x31, 0x48, 0x66, 0x2f, 0x98, 0x7b, 0x6d, 0x27, 0x69, 0xd9, 0x40, 0xcc, 0x37},
|
||||
{0x39, 0x29, 0x16, 0xe8, 0x5a, 0xd2, 0xb, 0xbb, 0x1f, 0xef, 0x6a, 0xe0, 0x2d, 0xa6, 0x6a, 0x46, 0x81, 0xba, 0xcf, 0x86, 0xfc, 0x16, 0x22, 0x2a, 0x9b, 0x72, 0x96, 0x71, 0x2b, 0xc7, 0x5b, 0x9d},
|
||||
{0xf4, 0x45, 0x82, 0x69, 0xdb, 0xbf, 0x2e, 0x9, 0x52, 0xc0, 0xf9, 0xe8, 0x59, 0x17, 0xe0, 0xaf, 0x31, 0x80, 0x79, 0xf3, 0x1d, 0x9d, 0xce, 0xaa, 0xd8, 0x22, 0xc7, 0xeb, 0xf5, 0xd3, 0x85, 0x7e},
|
||||
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package state_native
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
nativetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native/types"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
_ "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
@@ -19,6 +20,22 @@ func (b *BeaconState) SetLatestExecutionPayloadHeader(val interfaces.ExecutionDa
|
||||
}
|
||||
|
||||
switch header := val.Proto().(type) {
|
||||
case *enginev1.ExecutionPayload:
|
||||
latest, err := consensusblocks.PayloadToHeader(val)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert payload to header")
|
||||
}
|
||||
b.latestExecutionPayloadHeader = latest
|
||||
b.markFieldAsDirty(nativetypes.LatestExecutionPayloadHeader)
|
||||
return nil
|
||||
case *enginev1.ExecutionPayloadCapella:
|
||||
latest, err := consensusblocks.PayloadToHeaderCapella(val)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not convert payload to header")
|
||||
}
|
||||
b.latestExecutionPayloadHeaderCapella = latest
|
||||
b.markFieldAsDirty(nativetypes.LatestExecutionPayloadHeaderCapella)
|
||||
return nil
|
||||
case *enginev1.ExecutionPayloadHeader:
|
||||
b.latestExecutionPayloadHeader = header
|
||||
b.markFieldAsDirty(nativetypes.LatestExecutionPayloadHeader)
|
||||
|
||||
@@ -1,63 +1,10 @@
|
||||
package state_native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
nativetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stateutil"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
)
|
||||
|
||||
// SetWithdrawalQueue for the beacon state. Updates the entire list
|
||||
// to a new value by overwriting the previous one.
|
||||
func (b *BeaconState) SetWithdrawalQueue(val []*enginev1.Withdrawal) error {
|
||||
if b.version < version.Capella {
|
||||
return errNotSupported("SetWithdrawalQueue", b.version)
|
||||
}
|
||||
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.withdrawalQueue = val
|
||||
b.sharedFieldReferences[nativetypes.WithdrawalQueue].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.WithdrawalQueue] = stateutil.NewRef(1)
|
||||
b.markFieldAsDirty(nativetypes.WithdrawalQueue)
|
||||
b.rebuildTrie[nativetypes.WithdrawalQueue] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendWithdrawal adds a new withdrawal to the end of withdrawal queue.
|
||||
func (b *BeaconState) AppendWithdrawal(val *enginev1.Withdrawal) error {
|
||||
if b.version < version.Capella {
|
||||
return errNotSupported("AppendWithdrawal", b.version)
|
||||
}
|
||||
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
q := b.withdrawalQueue
|
||||
max := uint64(fieldparams.ValidatorRegistryLimit)
|
||||
if uint64(len(q)) == max {
|
||||
return fmt.Errorf("withdrawal queue has max length %d", max)
|
||||
}
|
||||
|
||||
if b.sharedFieldReferences[nativetypes.WithdrawalQueue].Refs() > 1 {
|
||||
// Copy elements in underlying array by reference.
|
||||
q = make([]*enginev1.Withdrawal, len(b.withdrawalQueue))
|
||||
copy(q, b.withdrawalQueue)
|
||||
b.sharedFieldReferences[nativetypes.WithdrawalQueue].MinusRef()
|
||||
b.sharedFieldReferences[nativetypes.WithdrawalQueue] = stateutil.NewRef(1)
|
||||
}
|
||||
|
||||
b.withdrawalQueue = append(q, val)
|
||||
b.markFieldAsDirty(nativetypes.WithdrawalQueue)
|
||||
b.addDirtyIndices(nativetypes.WithdrawalQueue, []uint64{uint64(len(b.withdrawalQueue) - 1)})
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetNextWithdrawalIndex sets the index that will be assigned to the next withdrawal.
|
||||
func (b *BeaconState) SetNextWithdrawalIndex(i uint64) error {
|
||||
if b.version < version.Capella {
|
||||
@@ -71,9 +18,9 @@ func (b *BeaconState) SetNextWithdrawalIndex(i uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetNextPartialWithdrawalValidatorIndex sets the index of the validator which is
|
||||
// SetLastWithdrawalValidatorIndex sets the index of the validator which is
|
||||
// next in line for a partial withdrawal.
|
||||
func (b *BeaconState) SetNextPartialWithdrawalValidatorIndex(i types.ValidatorIndex) error {
|
||||
func (b *BeaconState) SetLastWithdrawalValidatorIndex(i types.ValidatorIndex) error {
|
||||
if b.version < version.Capella {
|
||||
return errNotSupported("SetNextPartialWithdrawalValidatorIndex", b.version)
|
||||
}
|
||||
@@ -81,6 +28,6 @@ func (b *BeaconState) SetNextPartialWithdrawalValidatorIndex(i types.ValidatorIn
|
||||
b.lock.Lock()
|
||||
defer b.lock.Unlock()
|
||||
|
||||
b.nextPartialWithdrawalValidatorIndex = i
|
||||
b.lastWithdrawalValidatorIndex = i
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,99 +3,24 @@ package state_native
|
||||
import (
|
||||
"testing"
|
||||
|
||||
nativetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native/types"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stateutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
)
|
||||
|
||||
func TestSetWithdrawalQueue(t *testing.T) {
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
oldQ := []*enginev1.Withdrawal{
|
||||
{
|
||||
WithdrawalIndex: 0,
|
||||
ExecutionAddress: []byte("address1"),
|
||||
Amount: 1,
|
||||
ValidatorIndex: 2,
|
||||
},
|
||||
{
|
||||
WithdrawalIndex: 1,
|
||||
ExecutionAddress: []byte("address2"),
|
||||
Amount: 2,
|
||||
ValidatorIndex: 3,
|
||||
},
|
||||
}
|
||||
newQ := []*enginev1.Withdrawal{
|
||||
{
|
||||
WithdrawalIndex: 2,
|
||||
ExecutionAddress: []byte("address3"),
|
||||
Amount: 3,
|
||||
ValidatorIndex: 4,
|
||||
},
|
||||
{
|
||||
WithdrawalIndex: 3,
|
||||
ExecutionAddress: []byte("address4"),
|
||||
Amount: 4,
|
||||
ValidatorIndex: 5,
|
||||
},
|
||||
}
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
withdrawalQueue: oldQ,
|
||||
sharedFieldReferences: map[nativetypes.FieldIndex]*stateutil.Reference{nativetypes.WithdrawalQueue: stateutil.NewRef(1)},
|
||||
dirtyFields: map[nativetypes.FieldIndex]bool{},
|
||||
rebuildTrie: map[nativetypes.FieldIndex]bool{},
|
||||
}
|
||||
err := s.SetWithdrawalQueue(newQ)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, newQ, s.withdrawalQueue)
|
||||
})
|
||||
t.Run("version before Capella not supported", func(t *testing.T) {
|
||||
s := BeaconState{version: version.Bellatrix}
|
||||
err := s.SetWithdrawalQueue([]*enginev1.Withdrawal{})
|
||||
assert.ErrorContains(t, "SetWithdrawalQueue is not supported", err)
|
||||
})
|
||||
func TestSetNextWithdrawalIndex(t *testing.T) {
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
nextWithdrawalIndex: 3,
|
||||
}
|
||||
require.NoError(t, s.SetNextWithdrawalIndex(5))
|
||||
require.Equal(t, uint64(5), s.nextWithdrawalIndex)
|
||||
}
|
||||
|
||||
func TestAppendWithdrawal(t *testing.T) {
|
||||
t.Run("ok", func(t *testing.T) {
|
||||
oldWithdrawal1 := &enginev1.Withdrawal{
|
||||
WithdrawalIndex: 0,
|
||||
ExecutionAddress: []byte("address1"),
|
||||
Amount: 1,
|
||||
ValidatorIndex: 2,
|
||||
}
|
||||
oldWithdrawal2 := &enginev1.Withdrawal{
|
||||
WithdrawalIndex: 1,
|
||||
ExecutionAddress: []byte("address2"),
|
||||
Amount: 2,
|
||||
ValidatorIndex: 3,
|
||||
}
|
||||
q := []*enginev1.Withdrawal{oldWithdrawal1, oldWithdrawal2}
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
withdrawalQueue: q,
|
||||
sharedFieldReferences: map[nativetypes.FieldIndex]*stateutil.Reference{nativetypes.WithdrawalQueue: stateutil.NewRef(1)},
|
||||
dirtyFields: map[nativetypes.FieldIndex]bool{},
|
||||
dirtyIndices: map[nativetypes.FieldIndex][]uint64{},
|
||||
rebuildTrie: map[nativetypes.FieldIndex]bool{},
|
||||
}
|
||||
newWithdrawal := &enginev1.Withdrawal{
|
||||
WithdrawalIndex: 2,
|
||||
ExecutionAddress: []byte("address3"),
|
||||
Amount: 3,
|
||||
ValidatorIndex: 4,
|
||||
}
|
||||
err := s.AppendWithdrawal(newWithdrawal)
|
||||
require.NoError(t, err)
|
||||
expectedQ := []*enginev1.Withdrawal{oldWithdrawal1, oldWithdrawal2, newWithdrawal}
|
||||
assert.DeepEqual(t, expectedQ, s.withdrawalQueue)
|
||||
})
|
||||
t.Run("version before Capella not supported", func(t *testing.T) {
|
||||
s := BeaconState{version: version.Bellatrix}
|
||||
err := s.AppendWithdrawal(&enginev1.Withdrawal{})
|
||||
assert.ErrorContains(t, "AppendWithdrawal is not supported", err)
|
||||
})
|
||||
func TestSetLastWithdrawalValidatorIndex(t *testing.T) {
|
||||
s := BeaconState{
|
||||
version: version.Capella,
|
||||
lastWithdrawalValidatorIndex: 3,
|
||||
}
|
||||
require.NoError(t, s.SetLastWithdrawalValidatorIndex(5))
|
||||
require.Equal(t, types.ValidatorIndex(5), s.lastWithdrawalValidatorIndex)
|
||||
}
|
||||
|
||||
@@ -80,9 +80,8 @@ var bellatrixFields = append(altairFields, nativetypes.LatestExecutionPayloadHea
|
||||
var capellaFields = append(
|
||||
altairFields,
|
||||
nativetypes.LatestExecutionPayloadHeaderCapella,
|
||||
nativetypes.WithdrawalQueue,
|
||||
nativetypes.NextWithdrawalIndex,
|
||||
nativetypes.NextPartialWithdrawalValidatorIndex,
|
||||
nativetypes.LastWithdrawalValidatorIndex,
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -432,9 +431,8 @@ func InitializeFromProtoUnsafeCapella(st *ethpb.BeaconStateCapella) (state.Beaco
|
||||
currentSyncCommittee: st.CurrentSyncCommittee,
|
||||
nextSyncCommittee: st.NextSyncCommittee,
|
||||
latestExecutionPayloadHeaderCapella: st.LatestExecutionPayloadHeader,
|
||||
withdrawalQueue: st.WithdrawalQueue,
|
||||
nextWithdrawalIndex: st.NextWithdrawalIndex,
|
||||
nextPartialWithdrawalValidatorIndex: st.NextPartialWithdrawalValidatorIndex,
|
||||
lastWithdrawalValidatorIndex: st.LastWithdrawalValidatorIndex,
|
||||
|
||||
dirtyFields: make(map[nativetypes.FieldIndex]bool, fieldCount),
|
||||
dirtyIndices: make(map[nativetypes.FieldIndex][]uint64, fieldCount),
|
||||
@@ -468,7 +466,6 @@ func InitializeFromProtoUnsafeCapella(st *ethpb.BeaconStateCapella) (state.Beaco
|
||||
b.sharedFieldReferences[nativetypes.CurrentEpochParticipationBits] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.InactivityScores] = stateutil.NewRef(1)
|
||||
b.sharedFieldReferences[nativetypes.LatestExecutionPayloadHeaderCapella] = stateutil.NewRef(1) // New in Capella.
|
||||
b.sharedFieldReferences[nativetypes.WithdrawalQueue] = stateutil.NewRef(1) // New in Capella.
|
||||
|
||||
state.StateCount.Inc()
|
||||
// Finalizer runs when dst is being destroyed in garbage collection.
|
||||
@@ -497,11 +494,11 @@ func (b *BeaconState) Copy() state.BeaconState {
|
||||
version: b.version,
|
||||
|
||||
// Primitive nativetypes, safe to copy.
|
||||
genesisTime: b.genesisTime,
|
||||
slot: b.slot,
|
||||
eth1DepositIndex: b.eth1DepositIndex,
|
||||
nextWithdrawalIndex: b.nextWithdrawalIndex,
|
||||
nextPartialWithdrawalValidatorIndex: b.nextPartialWithdrawalValidatorIndex,
|
||||
genesisTime: b.genesisTime,
|
||||
slot: b.slot,
|
||||
eth1DepositIndex: b.eth1DepositIndex,
|
||||
nextWithdrawalIndex: b.nextWithdrawalIndex,
|
||||
lastWithdrawalValidatorIndex: b.lastWithdrawalValidatorIndex,
|
||||
|
||||
// Large arrays, infrequently changed, constant size.
|
||||
blockRoots: b.blockRoots,
|
||||
@@ -519,7 +516,6 @@ func (b *BeaconState) Copy() state.BeaconState {
|
||||
previousEpochParticipation: b.previousEpochParticipation,
|
||||
currentEpochParticipation: b.currentEpochParticipation,
|
||||
inactivityScores: b.inactivityScores,
|
||||
withdrawalQueue: b.withdrawalQueue,
|
||||
|
||||
// Everything else, too small to be concerned about, constant size.
|
||||
genesisValidatorsRoot: b.genesisValidatorsRoot,
|
||||
@@ -833,12 +829,10 @@ func (b *BeaconState) rootSelector(ctx context.Context, field nativetypes.FieldI
|
||||
return b.latestExecutionPayloadHeader.HashTreeRoot()
|
||||
case nativetypes.LatestExecutionPayloadHeaderCapella:
|
||||
return b.latestExecutionPayloadHeaderCapella.HashTreeRoot()
|
||||
case nativetypes.WithdrawalQueue:
|
||||
return ssz.WithdrawalSliceRoot(hasher, b.withdrawalQueue, fieldparams.WithdrawalQueueLimit)
|
||||
case nativetypes.NextWithdrawalIndex:
|
||||
return ssz.Uint64Root(b.nextWithdrawalIndex), nil
|
||||
case nativetypes.NextPartialWithdrawalValidatorIndex:
|
||||
return ssz.Uint64Root(uint64(b.nextPartialWithdrawalValidatorIndex)), nil
|
||||
case nativetypes.LastWithdrawalValidatorIndex:
|
||||
return ssz.Uint64Root(uint64(b.lastWithdrawalValidatorIndex)), nil
|
||||
}
|
||||
return [32]byte{}, errors.New("invalid field index provided")
|
||||
}
|
||||
|
||||
@@ -67,12 +67,10 @@ func (f FieldIndex) String(_ int) string {
|
||||
return "latestExecutionPayloadHeader"
|
||||
case LatestExecutionPayloadHeaderCapella:
|
||||
return "LatestExecutionPayloadHeaderCapella"
|
||||
case WithdrawalQueue:
|
||||
return "WithdrawalQueue"
|
||||
case NextWithdrawalIndex:
|
||||
return "NextWithdrawalIndex"
|
||||
case NextPartialWithdrawalValidatorIndex:
|
||||
return "NextPartialWithdrawalValidatorIndex"
|
||||
case LastWithdrawalValidatorIndex:
|
||||
return "LastWithdrawalValidatorIndex"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
@@ -132,12 +130,10 @@ func (f FieldIndex) RealPosition() int {
|
||||
return 23
|
||||
case LatestExecutionPayloadHeader, LatestExecutionPayloadHeaderCapella:
|
||||
return 24
|
||||
case WithdrawalQueue:
|
||||
return 25
|
||||
case NextWithdrawalIndex:
|
||||
return 25
|
||||
case LastWithdrawalValidatorIndex:
|
||||
return 26
|
||||
case NextPartialWithdrawalValidatorIndex:
|
||||
return 27
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
@@ -193,7 +189,6 @@ const (
|
||||
NextSyncCommittee
|
||||
LatestExecutionPayloadHeader
|
||||
LatestExecutionPayloadHeaderCapella
|
||||
WithdrawalQueue
|
||||
NextWithdrawalIndex
|
||||
NextPartialWithdrawalValidatorIndex
|
||||
LastWithdrawalValidatorIndex
|
||||
)
|
||||
|
||||
@@ -80,8 +80,8 @@ func (_ *State) replayBlocks(
|
||||
// The Blocks are returned in slot-descending order.
|
||||
func (s *State) loadBlocks(ctx context.Context, startSlot, endSlot types.Slot, endBlockRoot [32]byte) ([]interfaces.SignedBeaconBlock, error) {
|
||||
// Nothing to load for invalid range.
|
||||
if endSlot < startSlot {
|
||||
return nil, fmt.Errorf("start slot %d >= end slot %d", startSlot, endSlot)
|
||||
if startSlot > endSlot {
|
||||
return nil, fmt.Errorf("start slot %d > end slot %d", startSlot, endSlot)
|
||||
}
|
||||
filter := filters.NewFilter().SetStartSlot(startSlot).SetEndSlot(endSlot)
|
||||
blocks, blockRoots, err := s.beaconDB.Blocks(ctx, filter)
|
||||
|
||||
@@ -86,7 +86,7 @@ var (
|
||||
prometheus.HistogramOpts{
|
||||
Name: "block_arrival_latency_milliseconds",
|
||||
Help: "Captures blocks propagation time. Blocks arrival in milliseconds distribution",
|
||||
Buckets: []float64{100, 250, 500, 750, 1000, 1500, 2000, 4000, 8000, 12000},
|
||||
Buckets: []float64{100, 250, 500, 750, 1000, 1500, 2000, 4000, 8000, 12000, 16000, 20000, 24000},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@ func (s *Service) sendRecentBeaconBlocksRequest(ctx context.Context, blockRoots
|
||||
return err
|
||||
}
|
||||
s.pendingQueueLock.Lock()
|
||||
defer s.pendingQueueLock.Unlock()
|
||||
if err := s.insertBlockToPendingQueue(blk.Block().Slot(), blk, blkRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
s.pendingQueueLock.Unlock()
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
|
||||
@@ -12,6 +12,7 @@ go_library(
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//cmd/prysmctl/checkpointsync:go_default_library",
|
||||
"//cmd/prysmctl/db:go_default_library",
|
||||
"//cmd/prysmctl/deprecated:go_default_library",
|
||||
"//cmd/prysmctl/p2p:go_default_library",
|
||||
"//cmd/prysmctl/signing:go_default_library",
|
||||
|
||||
21
cmd/prysmctl/db/BUILD.bazel
Normal file
21
cmd/prysmctl/db/BUILD.bazel
Normal file
@@ -0,0 +1,21 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"buckets.go",
|
||||
"cmd.go",
|
||||
"query.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/db",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/db/kv:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
"@io_etcd_go_bbolt//:go_default_library",
|
||||
],
|
||||
)
|
||||
32
cmd/prysmctl/db/buckets.go
Normal file
32
cmd/prysmctl/db/buckets.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db/kv"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var bucketsFlags = struct {
|
||||
Path string
|
||||
}{}
|
||||
|
||||
var bucketsCmd = &cli.Command{
|
||||
Name: "buckets",
|
||||
Usage: "list db buckets",
|
||||
Action: bucketsAction,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "path",
|
||||
Usage: "path to directory containing beaconchain.db",
|
||||
Destination: &bucketsFlags.Path,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func bucketsAction(_ *cli.Context) error {
|
||||
for _, b := range kv.Buckets {
|
||||
fmt.Printf("%s\n", string(b))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
14
cmd/prysmctl/db/cmd.go
Normal file
14
cmd/prysmctl/db/cmd.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package db
|
||||
|
||||
import "github.com/urfave/cli/v2"
|
||||
|
||||
var Commands = []*cli.Command{
|
||||
{
|
||||
Name: "db",
|
||||
Usage: "commands to work with the prysm beacon db",
|
||||
Subcommands: []*cli.Command{
|
||||
queryCmd,
|
||||
bucketsCmd,
|
||||
},
|
||||
},
|
||||
}
|
||||
97
cmd/prysmctl/db/query.go
Normal file
97
cmd/prysmctl/db/query.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
var queryFlags = struct {
|
||||
Path string
|
||||
Bucket string
|
||||
KeysOnly bool
|
||||
Prefix string
|
||||
}{}
|
||||
|
||||
var queryCmd = &cli.Command{
|
||||
Name: "query",
|
||||
Usage: "database query tool",
|
||||
Action: queryAction,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "bucket",
|
||||
Usage: "boltdb bucket to search",
|
||||
Destination: &queryFlags.Bucket,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "path",
|
||||
Usage: "path to directory containing beaconchain.db",
|
||||
Destination: &queryFlags.Path,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "prefix",
|
||||
Usage: "prefix of db record key to match against (eg 0xa1 would match 0xa10, 0xa1f etc)",
|
||||
Destination: &queryFlags.Prefix,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "print-keys",
|
||||
Usage: "only display keys, not values",
|
||||
Destination: &queryFlags.KeysOnly,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func queryAction(_ *cli.Context) error {
|
||||
flags := queryFlags
|
||||
db, err := getDB(flags.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if flags.Prefix != "" {
|
||||
return prefixScan(db, flags.Bucket, flags.Prefix, flags.KeysOnly)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func prefixScan(db *bolt.DB, bucket, prefix string, keysOnly bool) error {
|
||||
if !keysOnly {
|
||||
return errors.New("prefix scan with value display not implemented")
|
||||
}
|
||||
pb, err := hexutil.Decode(prefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("scanning for prefix=%#x", pb)
|
||||
return db.View(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte(bucket))
|
||||
c := b.Cursor()
|
||||
for k, _ := c.Seek(pb); k != nil && bytes.HasPrefix(k, pb); k, _ = c.Next() {
|
||||
fmt.Printf("%#x\n", k)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func getDB(path string) (*bolt.DB, error) {
|
||||
bdb, err := bolt.Open(
|
||||
path,
|
||||
params.BeaconIoConfig().ReadWritePermissions,
|
||||
&bolt.Options{
|
||||
Timeout: 1 * time.Second,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, bolt.ErrTimeout) {
|
||||
return nil, errors.New("cannot obtain database lock, database may be in use by another process")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return bdb, nil
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/checkpointsync"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/db"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/deprecated"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/p2p"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/signing"
|
||||
@@ -31,6 +32,7 @@ func init() {
|
||||
prysmctlCommands = append(prysmctlCommands, deprecated.Commands...)
|
||||
|
||||
prysmctlCommands = append(prysmctlCommands, checkpointsync.Commands...)
|
||||
prysmctlCommands = append(prysmctlCommands, db.Commands...)
|
||||
prysmctlCommands = append(prysmctlCommands, p2p.Commands...)
|
||||
prysmctlCommands = append(prysmctlCommands, testnet.Commands...)
|
||||
prysmctlCommands = append(prysmctlCommands, weaksubjectivity.Commands...)
|
||||
|
||||
@@ -36,6 +36,7 @@ var Commands = []*cli.Command{
|
||||
flags.GrpcRetriesFlag,
|
||||
flags.GrpcRetryDelayFlag,
|
||||
flags.ExitAllFlag,
|
||||
flags.ForceExitFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.RopstenTestnet,
|
||||
|
||||
@@ -169,6 +169,7 @@ var Commands = &cli.Command{
|
||||
flags.GrpcRetriesFlag,
|
||||
flags.GrpcRetryDelayFlag,
|
||||
flags.ExitAllFlag,
|
||||
flags.ForceExitFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.RopstenTestnet,
|
||||
|
||||
@@ -67,7 +67,7 @@ func TestBackupAccounts_Noninteractive_Derived(t *testing.T) {
|
||||
// Create 2 accounts
|
||||
derivedKM, ok := km.(*derived.Keymanager)
|
||||
require.Equal(t, true, ok)
|
||||
err = derivedKM.RecoverAccountsFromMnemonic(cliCtx.Context, constant.TestMnemonic, "", 2)
|
||||
err = derivedKM.RecoverAccountsFromMnemonic(cliCtx.Context, constant.TestMnemonic, "", "", 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Obtain the public keys of the accounts we created
|
||||
|
||||
@@ -92,7 +92,7 @@ func AccountsExit(c *cli.Context, r io.Reader) error {
|
||||
return errors.New("wallet is empty, no accounts to delete")
|
||||
}
|
||||
// Filter keys either from CLI flag or from interactive session.
|
||||
rawPubKey, formattedPubKeys, err := accounts.FilterExitAccountsFromUserInput(c, r, validatingPublicKeys)
|
||||
rawPubKey, formattedPubKeys, err := accounts.FilterExitAccountsFromUserInput(c, r, validatingPublicKeys, c.Bool(flags.ForceExitFlag.Name))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not filter public keys for deletion")
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func TestExitAccountsCli_OK(t *testing.T) {
|
||||
var stdin bytes.Buffer
|
||||
stdin.Write([]byte(accounts.ExitPassphrase))
|
||||
rawPubKeys, formattedPubKeys, err := accounts.FilterExitAccountsFromUserInput(
|
||||
cliCtx, &stdin, validatingPublicKeys,
|
||||
cliCtx, &stdin, validatingPublicKeys, false,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, rawPubKeys)
|
||||
@@ -190,7 +190,7 @@ func TestExitAccountsCli_OK_AllPublicKeys(t *testing.T) {
|
||||
var stdin bytes.Buffer
|
||||
stdin.Write([]byte(accounts.ExitPassphrase))
|
||||
rawPubKeys, formattedPubKeys, err := accounts.FilterExitAccountsFromUserInput(
|
||||
cliCtx, &stdin, validatingPublicKeys,
|
||||
cliCtx, &stdin, validatingPublicKeys, false,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, rawPubKeys)
|
||||
@@ -216,3 +216,92 @@ func TestExitAccountsCli_OK_AllPublicKeys(t *testing.T) {
|
||||
sort.Strings(formattedExitedKeys)
|
||||
require.DeepEqual(t, wantedFormatted, formattedExitedKeys)
|
||||
}
|
||||
|
||||
func TestExitAccountsCli_OK_ForceExit(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
mockValidatorClient := mock2.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
mockNodeClient := mock2.NewMockNodeClient(ctrl)
|
||||
|
||||
mockValidatorClient.EXPECT().
|
||||
ValidatorIndex(gomock.Any(), gomock.Any()).
|
||||
Return(ðpb.ValidatorIndexResponse{Index: 1}, nil)
|
||||
|
||||
// Any time in the past will suffice
|
||||
genesisTime := ×tamppb.Timestamp{
|
||||
Seconds: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC).Unix(),
|
||||
}
|
||||
|
||||
mockNodeClient.EXPECT().
|
||||
GetGenesis(gomock.Any(), gomock.Any()).
|
||||
Return(ðpb.Genesis{GenesisTime: genesisTime}, nil)
|
||||
|
||||
mockValidatorClient.EXPECT().
|
||||
DomainData(gomock.Any(), gomock.Any()).
|
||||
Return(ðpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil)
|
||||
|
||||
mockValidatorClient.EXPECT().
|
||||
ProposeExit(gomock.Any(), gomock.AssignableToTypeOf(ðpb.SignedVoluntaryExit{})).
|
||||
Return(ðpb.ProposeExitResponse{}, nil)
|
||||
|
||||
walletDir, _, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
// Write a directory where we will import keys from.
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
// Create keystore file in the keys directory we can then import from in our wallet.
|
||||
keystore, _ := createKeystore(t, keysDir)
|
||||
time.Sleep(time.Second)
|
||||
|
||||
// We initialize a wallet with a local keymanager.
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
// Wallet configuration flags.
|
||||
walletDir: walletDir,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
// Flag required for ImportAccounts to work.
|
||||
keysDir: keysDir,
|
||||
// Flag required for ExitAccounts to work.
|
||||
voluntaryExitPublicKeys: keystore.Pubkey,
|
||||
})
|
||||
opts := []accounts.Option{
|
||||
accounts.WithWalletDir(walletDir),
|
||||
accounts.WithKeymanagerType(keymanager.Local),
|
||||
accounts.WithWalletPassword(password),
|
||||
}
|
||||
acc, err := accounts.NewCLIManager(opts...)
|
||||
require.NoError(t, err)
|
||||
_, err = acc.WalletCreate(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
_, km, err := walletWithKeymanager(cliCtx)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, km)
|
||||
|
||||
validatingPublicKeys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, validatingPublicKeys)
|
||||
|
||||
rawPubKeys, formattedPubKeys, err := accounts.FilterExitAccountsFromUserInput(
|
||||
cliCtx, &bytes.Buffer{}, validatingPublicKeys, true,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, rawPubKeys)
|
||||
require.NotNil(t, formattedPubKeys)
|
||||
|
||||
cfg := accounts.PerformExitCfg{
|
||||
ValidatorClient: mockValidatorClient,
|
||||
NodeClient: mockNodeClient,
|
||||
Keymanager: km,
|
||||
RawPubKeys: rawPubKeys,
|
||||
FormattedPubKeys: formattedPubKeys,
|
||||
}
|
||||
rawExitedKeys, formattedExitedKeys, err := accounts.PerformVoluntaryExit(cliCtx.Context, cfg)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(rawExitedKeys))
|
||||
assert.DeepEqual(t, rawPubKeys[0], rawExitedKeys[0])
|
||||
require.Equal(t, 1, len(formattedExitedKeys))
|
||||
assert.Equal(t, "0x"+keystore.Pubkey[:12], formattedExitedKeys[0])
|
||||
}
|
||||
|
||||
@@ -162,6 +162,11 @@ var (
|
||||
Name: "mnemonic-file",
|
||||
Usage: "File to retrieve mnemonic for non-interactively passing a mnemonic phrase into wallet recover.",
|
||||
}
|
||||
// MnemonicLanguageFlag is used to specify the language of the mnemonic.
|
||||
MnemonicLanguageFlag = &cli.StringFlag{
|
||||
Name: "mnemonic-language",
|
||||
Usage: "Allows specifying mnemonic language. Supported languages are: english|chinese_traditional|chinese_simplified|czech|french|japanese|korean|italian|spanish",
|
||||
}
|
||||
// ShowDepositDataFlag for accounts.
|
||||
ShowDepositDataFlag = &cli.BoolFlag{
|
||||
Name: "show-deposit-data",
|
||||
@@ -214,6 +219,11 @@ var (
|
||||
Name: "exit-all",
|
||||
Usage: "Exit all validators. This will still require the staker to confirm a userprompt for the action",
|
||||
}
|
||||
// ForceExitFlag to exit without displaying the confirmation prompt.
|
||||
ForceExitFlag = &cli.BoolFlag{
|
||||
Name: "force-exit",
|
||||
Usage: "Exit without displaying the confirmation prompt",
|
||||
}
|
||||
// BackupPasswordFile for encrypting accounts a user wishes to back up.
|
||||
BackupPasswordFile = &cli.StringFlag{
|
||||
Name: "backup-password-file",
|
||||
|
||||
@@ -77,6 +77,7 @@ func ConstructCLIManagerOpts(cliCtx *cli.Context, keymanagerKind keymanager.Kind
|
||||
cliOpts = append(cliOpts, accounts.WithWalletPassword(walletPassword))
|
||||
cliOpts = append(cliOpts, accounts.WithKeymanagerType(keymanagerKind))
|
||||
cliOpts = append(cliOpts, accounts.WithSkipMnemonicConfirm(cliCtx.Bool(flags.SkipDepositConfirmationFlag.Name)))
|
||||
cliOpts = append(cliOpts, accounts.WithMnemonicLanguage(cliCtx.String(flags.MnemonicLanguageFlag.Name)))
|
||||
|
||||
skipMnemonic25thWord := cliCtx.IsSet(flags.SkipMnemonic25thWordCheckFlag.Name)
|
||||
has25thWordFile := cliCtx.IsSet(flags.Mnemonic25thWordFileFlag.Name)
|
||||
|
||||
@@ -179,3 +179,11 @@ var BeaconChainFlags = append(deprecatedBeaconFlags, append(deprecatedFlags, []c
|
||||
var E2EBeaconChainFlags = []string{
|
||||
"--dev",
|
||||
}
|
||||
|
||||
// NetworkFlags contains a list of network flags.
|
||||
var NetworkFlags = []cli.Flag{
|
||||
Mainnet,
|
||||
PraterTestnet,
|
||||
RopstenTestnet,
|
||||
SepoliaTestnet,
|
||||
}
|
||||
|
||||
@@ -94,11 +94,12 @@ type BeaconChainConfig struct {
|
||||
ProportionalSlashingMultiplier uint64 `yaml:"PROPORTIONAL_SLASHING_MULTIPLIER" spec:"true"` // ProportionalSlashingMultiplier is used as a multiplier on slashed penalties.
|
||||
|
||||
// Max operations per block constants.
|
||||
MaxProposerSlashings uint64 `yaml:"MAX_PROPOSER_SLASHINGS" spec:"true"` // MaxProposerSlashings defines the maximum number of slashings of proposers possible in a block.
|
||||
MaxAttesterSlashings uint64 `yaml:"MAX_ATTESTER_SLASHINGS" spec:"true"` // MaxAttesterSlashings defines the maximum number of casper FFG slashings possible in a block.
|
||||
MaxAttestations uint64 `yaml:"MAX_ATTESTATIONS" spec:"true"` // MaxAttestations defines the maximum allowed attestations in a beacon block.
|
||||
MaxDeposits uint64 `yaml:"MAX_DEPOSITS" spec:"true"` // MaxDeposits defines the maximum number of validator deposits in a block.
|
||||
MaxVoluntaryExits uint64 `yaml:"MAX_VOLUNTARY_EXITS" spec:"true"` // MaxVoluntaryExits defines the maximum number of validator exits in a block.
|
||||
MaxProposerSlashings uint64 `yaml:"MAX_PROPOSER_SLASHINGS" spec:"true"` // MaxProposerSlashings defines the maximum number of slashings of proposers possible in a block.
|
||||
MaxAttesterSlashings uint64 `yaml:"MAX_ATTESTER_SLASHINGS" spec:"true"` // MaxAttesterSlashings defines the maximum number of casper FFG slashings possible in a block.
|
||||
MaxAttestations uint64 `yaml:"MAX_ATTESTATIONS" spec:"true"` // MaxAttestations defines the maximum allowed attestations in a beacon block.
|
||||
MaxDeposits uint64 `yaml:"MAX_DEPOSITS" spec:"true"` // MaxDeposits defines the maximum number of validator deposits in a block.
|
||||
MaxVoluntaryExits uint64 `yaml:"MAX_VOLUNTARY_EXITS" spec:"true"` // MaxVoluntaryExits defines the maximum number of validator exits in a block.
|
||||
MaxWithdrawalsPerPayload uint64 `yaml:"MAX_WITHDRAWALS_PER_PAYLOAD" spec:"true"` // MaxWithdrawalsPerPayload defines the maximum number of withdrawals in a block.
|
||||
|
||||
// BLS domain values.
|
||||
DomainBeaconProposer [4]byte `yaml:"DOMAIN_BEACON_PROPOSER" spec:"true"` // DomainBeaconProposer defines the BLS signature domain for beacon proposal verification.
|
||||
@@ -224,6 +225,8 @@ func configForkSchedule(b *BeaconChainConfig) map[[fieldparams.VersionLength]byt
|
||||
fvs[bytesutil.ToBytes4(b.AltairForkVersion)] = b.AltairForkEpoch
|
||||
// Set Bellatrix fork data.
|
||||
fvs[bytesutil.ToBytes4(b.BellatrixForkVersion)] = b.BellatrixForkEpoch
|
||||
// Set Capella fork data.
|
||||
fvs[bytesutil.ToBytes4(b.CapellaForkVersion)] = b.CapellaForkEpoch
|
||||
return fvs
|
||||
}
|
||||
|
||||
@@ -235,5 +238,7 @@ func configForkNames(b *BeaconChainConfig) map[[fieldparams.VersionLength]byte]s
|
||||
fvn[bytesutil.ToBytes4(b.AltairForkVersion)] = "altair"
|
||||
// Set Bellatrix fork data.
|
||||
fvn[bytesutil.ToBytes4(b.BellatrixForkVersion)] = "bellatrix"
|
||||
// Set Capella fork data.
|
||||
fvn[bytesutil.ToBytes4(b.CapellaForkVersion)] = "capella"
|
||||
return fvn
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ func InteropConfig() *BeaconChainConfig {
|
||||
c.GenesisForkVersion = []byte{0, 0, 0, 235}
|
||||
c.AltairForkVersion = []byte{1, 0, 0, 235}
|
||||
c.BellatrixForkVersion = []byte{2, 0, 0, 235}
|
||||
c.ShardingForkVersion = []byte{3, 0, 0, 235}
|
||||
c.CapellaForkVersion = []byte{3, 0, 0, 235}
|
||||
c.ShardingForkVersion = []byte{4, 0, 0, 235}
|
||||
|
||||
c.InitializeForkSchedule()
|
||||
return c
|
||||
|
||||
@@ -149,11 +149,12 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
ProportionalSlashingMultiplier: 1,
|
||||
|
||||
// Max operations per block constants.
|
||||
MaxProposerSlashings: 16,
|
||||
MaxAttesterSlashings: 2,
|
||||
MaxAttestations: 128,
|
||||
MaxDeposits: 16,
|
||||
MaxVoluntaryExits: 16,
|
||||
MaxProposerSlashings: 16,
|
||||
MaxAttesterSlashings: 2,
|
||||
MaxAttestations: 128,
|
||||
MaxDeposits: 16,
|
||||
MaxVoluntaryExits: 16,
|
||||
MaxWithdrawalsPerPayload: 16,
|
||||
|
||||
// BLS domain values.
|
||||
DomainBeaconProposer: bytesutil.Uint32ToBytes4(0x00000000),
|
||||
@@ -188,7 +189,7 @@ var mainnetBeaconConfig = &BeaconChainConfig{
|
||||
BeaconStateFieldCount: 21,
|
||||
BeaconStateAltairFieldCount: 24,
|
||||
BeaconStateBellatrixFieldCount: 25,
|
||||
BeaconStateCapellaFieldCount: 28,
|
||||
BeaconStateCapellaFieldCount: 27,
|
||||
|
||||
// Slasher related values.
|
||||
WeakSubjectivityPeriod: 54000,
|
||||
|
||||
@@ -67,6 +67,7 @@ func MinimalSpecConfig() *BeaconChainConfig {
|
||||
minimalConfig.MaxAttestations = 128
|
||||
minimalConfig.MaxDeposits = 16
|
||||
minimalConfig.MaxVoluntaryExits = 16
|
||||
minimalConfig.MaxWithdrawalsPerPayload = 4
|
||||
|
||||
// Signature domains
|
||||
minimalConfig.DomainBeaconProposer = bytesutil.ToBytes4(bytesutil.Bytes4(0))
|
||||
|
||||
@@ -100,6 +100,7 @@ func compareConfigs(t *testing.T, expected, actual *params.BeaconChainConfig) {
|
||||
require.DeepEqual(t, expected.MaxAttestations, actual.MaxAttestations)
|
||||
require.DeepEqual(t, expected.MaxDeposits, actual.MaxDeposits)
|
||||
require.DeepEqual(t, expected.MaxVoluntaryExits, actual.MaxVoluntaryExits)
|
||||
require.DeepEqual(t, expected.MaxWithdrawalsPerPayload, actual.MaxWithdrawalsPerPayload)
|
||||
require.DeepEqual(t, expected.DomainBeaconProposer, actual.DomainBeaconProposer)
|
||||
require.DeepEqual(t, expected.DomainRandao, actual.DomainRandao)
|
||||
require.DeepEqual(t, expected.DomainBeaconAttester, actual.DomainBeaconAttester)
|
||||
|
||||
@@ -3,6 +3,7 @@ package params
|
||||
const (
|
||||
altairE2EForkEpoch = 6
|
||||
bellatrixE2EForkEpoch = 8
|
||||
capellaE2EForkEpoch = 10
|
||||
)
|
||||
|
||||
// E2ETestConfig retrieves the configurations made specifically for E2E testing.
|
||||
@@ -33,6 +34,7 @@ func E2ETestConfig() *BeaconChainConfig {
|
||||
// Fork Parameters.
|
||||
e2eConfig.AltairForkEpoch = altairE2EForkEpoch
|
||||
e2eConfig.BellatrixForkEpoch = bellatrixE2EForkEpoch
|
||||
e2eConfig.CapellaForkEpoch = capellaE2EForkEpoch
|
||||
|
||||
// Terminal Total Difficulty.
|
||||
e2eConfig.TerminalTotalDifficulty = "616"
|
||||
@@ -42,7 +44,8 @@ func E2ETestConfig() *BeaconChainConfig {
|
||||
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 253}
|
||||
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 253}
|
||||
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 253}
|
||||
e2eConfig.ShardingForkVersion = []byte{3, 0, 0, 253}
|
||||
e2eConfig.CapellaForkVersion = []byte{3, 0, 0, 253}
|
||||
e2eConfig.ShardingForkVersion = []byte{4, 0, 0, 253}
|
||||
|
||||
e2eConfig.InitializeForkSchedule()
|
||||
return e2eConfig
|
||||
@@ -70,6 +73,7 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
|
||||
// Altair Fork Parameters.
|
||||
e2eConfig.AltairForkEpoch = altairE2EForkEpoch
|
||||
e2eConfig.BellatrixForkEpoch = bellatrixE2EForkEpoch
|
||||
e2eConfig.CapellaForkEpoch = capellaE2EForkEpoch
|
||||
|
||||
// Terminal Total Difficulty.
|
||||
e2eConfig.TerminalTotalDifficulty = "616"
|
||||
@@ -79,7 +83,8 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
|
||||
e2eConfig.GenesisForkVersion = []byte{0, 0, 0, 254}
|
||||
e2eConfig.AltairForkVersion = []byte{1, 0, 0, 254}
|
||||
e2eConfig.BellatrixForkVersion = []byte{2, 0, 0, 254}
|
||||
e2eConfig.ShardingForkVersion = []byte{3, 0, 0, 254}
|
||||
e2eConfig.CapellaForkVersion = []byte{3, 0, 0, 254}
|
||||
e2eConfig.ShardingForkVersion = []byte{4, 0, 0, 254}
|
||||
|
||||
e2eConfig.InitializeForkSchedule()
|
||||
return e2eConfig
|
||||
|
||||
@@ -32,6 +32,7 @@ func RopstenConfig() *BeaconChainConfig {
|
||||
cfg.AltairForkVersion = []byte{0x80, 0x00, 0x00, 0x70}
|
||||
cfg.BellatrixForkEpoch = 750
|
||||
cfg.BellatrixForkVersion = []byte{0x80, 0x00, 0x00, 0x71}
|
||||
cfg.CapellaForkVersion = []byte{0x80, 0x00, 0x00, 0x72}
|
||||
cfg.TerminalTotalDifficulty = "50000000000000000"
|
||||
cfg.DepositContractAddress = "0x6f22fFbC56eFF051aECF839396DD1eD9aD6BBA9D"
|
||||
cfg.InitializeForkSchedule()
|
||||
|
||||
@@ -140,11 +140,21 @@ func (e executionPayload) Transactions() ([][]byte, error) {
|
||||
return e.p.Transactions, nil
|
||||
}
|
||||
|
||||
// TransactionsRoot --
|
||||
func (e executionPayload) TransactionsRoot() ([]byte, error) {
|
||||
return nil, ErrUnsupportedGetter
|
||||
}
|
||||
|
||||
// Withdrawals --
|
||||
func (e executionPayload) Withdrawals() ([]*enginev1.Withdrawal, error) {
|
||||
return nil, ErrUnsupportedGetter
|
||||
}
|
||||
|
||||
// WithdrawalsRoot --
|
||||
func (e executionPayload) WithdrawalsRoot() ([]byte, error) {
|
||||
return nil, ErrUnsupportedGetter
|
||||
}
|
||||
|
||||
// executionPayloadHeader is a convenience wrapper around a blinded beacon block body's execution header data structure
|
||||
// This wrapper allows us to conform to a common interface so that beacon
|
||||
// blocks for future forks can also be applied across Prysm without issues.
|
||||
@@ -271,11 +281,21 @@ func (executionPayloadHeader) Transactions() ([][]byte, error) {
|
||||
return nil, ErrUnsupportedGetter
|
||||
}
|
||||
|
||||
// TransactionsRoot --
|
||||
func (e executionPayloadHeader) TransactionsRoot() ([]byte, error) {
|
||||
return e.p.TransactionsRoot, nil
|
||||
}
|
||||
|
||||
// Withdrawals --
|
||||
func (e executionPayloadHeader) Withdrawals() ([]*enginev1.Withdrawal, error) {
|
||||
return nil, ErrUnsupportedGetter
|
||||
}
|
||||
|
||||
// WithdrawalsRoot --
|
||||
func (e executionPayloadHeader) WithdrawalsRoot() ([]byte, error) {
|
||||
return nil, ErrUnsupportedGetter
|
||||
}
|
||||
|
||||
// PayloadToHeader converts `payload` into execution payload header format.
|
||||
func PayloadToHeader(payload interfaces.ExecutionData) (*enginev1.ExecutionPayloadHeader, error) {
|
||||
txs, err := payload.Transactions()
|
||||
@@ -430,11 +450,21 @@ func (e executionPayloadCapella) Transactions() ([][]byte, error) {
|
||||
return e.p.Transactions, nil
|
||||
}
|
||||
|
||||
// TransactionsRoot --
|
||||
func (e executionPayloadCapella) TransactionsRoot() ([]byte, error) {
|
||||
return nil, ErrUnsupportedGetter
|
||||
}
|
||||
|
||||
// Withdrawals --
|
||||
func (e executionPayloadCapella) Withdrawals() ([]*enginev1.Withdrawal, error) {
|
||||
return e.p.Withdrawals, nil
|
||||
}
|
||||
|
||||
// WithdrawalsRoot --
|
||||
func (e executionPayloadCapella) WithdrawalsRoot() ([]byte, error) {
|
||||
return nil, ErrUnsupportedGetter
|
||||
}
|
||||
|
||||
// executionPayloadHeaderCapella is a convenience wrapper around a blinded beacon block body's execution header data structure
|
||||
// This wrapper allows us to conform to a common interface so that beacon
|
||||
// blocks for future forks can also be applied across Prysm without issues.
|
||||
@@ -561,11 +591,21 @@ func (executionPayloadHeaderCapella) Transactions() ([][]byte, error) {
|
||||
return nil, ErrUnsupportedGetter
|
||||
}
|
||||
|
||||
// TransactionsRoot --
|
||||
func (e executionPayloadHeaderCapella) TransactionsRoot() ([]byte, error) {
|
||||
return e.p.TransactionsRoot, nil
|
||||
}
|
||||
|
||||
// Withdrawals --
|
||||
func (e executionPayloadHeaderCapella) Withdrawals() ([]*enginev1.Withdrawal, error) {
|
||||
return nil, ErrUnsupportedGetter
|
||||
}
|
||||
|
||||
// WitdrawalsRoot --
|
||||
func (e executionPayloadHeaderCapella) WithdrawalsRoot() ([]byte, error) {
|
||||
return e.p.WithdrawalsRoot, nil
|
||||
}
|
||||
|
||||
// PayloadToHeaderCapella converts `payload` into execution payload header format.
|
||||
func PayloadToHeaderCapella(payload interfaces.ExecutionData) (*enginev1.ExecutionPayloadHeaderCapella, error) {
|
||||
txs, err := payload.Transactions()
|
||||
|
||||
@@ -81,6 +81,113 @@ func TestWrapExecutionPayloadHeader_SSZ(t *testing.T) {
|
||||
assert.NoError(t, wsb.UnmarshalSSZ(encoded))
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayloadCapella(t *testing.T) {
|
||||
data := &enginev1.ExecutionPayloadCapella{
|
||||
ParentHash: []byte("parenthash"),
|
||||
FeeRecipient: []byte("feerecipient"),
|
||||
StateRoot: []byte("stateroot"),
|
||||
ReceiptsRoot: []byte("receiptsroot"),
|
||||
LogsBloom: []byte("logsbloom"),
|
||||
PrevRandao: []byte("prevrandao"),
|
||||
BlockNumber: 11,
|
||||
GasLimit: 22,
|
||||
GasUsed: 33,
|
||||
Timestamp: 44,
|
||||
ExtraData: []byte("extradata"),
|
||||
BaseFeePerGas: []byte("basefeepergas"),
|
||||
BlockHash: []byte("blockhash"),
|
||||
Transactions: [][]byte{[]byte("transaction")},
|
||||
Withdrawals: []*enginev1.Withdrawal{{
|
||||
WithdrawalIndex: 55,
|
||||
ValidatorIndex: 66,
|
||||
ExecutionAddress: []byte("executionaddress"),
|
||||
Amount: 77,
|
||||
}},
|
||||
}
|
||||
payload, err := blocks.WrappedExecutionPayloadCapella(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.DeepEqual(t, data, payload.Proto())
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayloadHeaderCapella(t *testing.T) {
|
||||
data := &enginev1.ExecutionPayloadHeaderCapella{
|
||||
ParentHash: []byte("parenthash"),
|
||||
FeeRecipient: []byte("feerecipient"),
|
||||
StateRoot: []byte("stateroot"),
|
||||
ReceiptsRoot: []byte("receiptsroot"),
|
||||
LogsBloom: []byte("logsbloom"),
|
||||
PrevRandao: []byte("prevrandao"),
|
||||
BlockNumber: 11,
|
||||
GasLimit: 22,
|
||||
GasUsed: 33,
|
||||
Timestamp: 44,
|
||||
ExtraData: []byte("extradata"),
|
||||
BaseFeePerGas: []byte("basefeepergas"),
|
||||
BlockHash: []byte("blockhash"),
|
||||
TransactionsRoot: []byte("transactionsroot"),
|
||||
WithdrawalsRoot: []byte("withdrawalsroot"),
|
||||
}
|
||||
payload, err := blocks.WrappedExecutionPayloadHeaderCapella(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.DeepEqual(t, data, payload.Proto())
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayloadCapella_IsNil(t *testing.T) {
|
||||
_, err := blocks.WrappedExecutionPayloadCapella(nil)
|
||||
require.Equal(t, blocks.ErrNilObjectWrapped, err)
|
||||
|
||||
data := &enginev1.ExecutionPayloadCapella{GasUsed: 54}
|
||||
payload, err := blocks.WrappedExecutionPayloadCapella(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, false, payload.IsNil())
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayloadHeaderCapella_IsNil(t *testing.T) {
|
||||
_, err := blocks.WrappedExecutionPayloadHeaderCapella(nil)
|
||||
require.Equal(t, blocks.ErrNilObjectWrapped, err)
|
||||
|
||||
data := &enginev1.ExecutionPayloadHeaderCapella{GasUsed: 54}
|
||||
payload, err := blocks.WrappedExecutionPayloadHeaderCapella(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, false, payload.IsNil())
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayloadCapella_SSZ(t *testing.T) {
|
||||
payload := createWrappedPayloadCapella(t)
|
||||
rt, err := payload.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, rt)
|
||||
|
||||
var b []byte
|
||||
b, err = payload.MarshalSSZTo(b)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, 0, len(b))
|
||||
encoded, err := payload.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, 0, payload.SizeSSZ())
|
||||
assert.NoError(t, payload.UnmarshalSSZ(encoded))
|
||||
}
|
||||
|
||||
func TestWrapExecutionPayloadHeaderCapella_SSZ(t *testing.T) {
|
||||
payload := createWrappedPayloadHeaderCapella(t)
|
||||
rt, err := payload.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, rt)
|
||||
|
||||
var b []byte
|
||||
b, err = payload.MarshalSSZTo(b)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, 0, len(b))
|
||||
encoded, err := payload.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, 0, payload.SizeSSZ())
|
||||
assert.NoError(t, payload.UnmarshalSSZ(encoded))
|
||||
}
|
||||
|
||||
func createWrappedPayload(t testing.TB) interfaces.ExecutionData {
|
||||
wsb, err := blocks.WrappedExecutionPayload(&enginev1.ExecutionPayload{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
@@ -122,3 +229,47 @@ func createWrappedPayloadHeader(t testing.TB) interfaces.ExecutionData {
|
||||
require.NoError(t, err)
|
||||
return wsb
|
||||
}
|
||||
|
||||
func createWrappedPayloadCapella(t testing.TB) interfaces.ExecutionData {
|
||||
payload, err := blocks.WrappedExecutionPayloadCapella(&enginev1.ExecutionPayloadCapella{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
||||
PrevRandao: make([]byte, fieldparams.RootLength),
|
||||
BlockNumber: 0,
|
||||
GasLimit: 0,
|
||||
GasUsed: 0,
|
||||
Timestamp: 0,
|
||||
ExtraData: make([]byte, 0),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
Transactions: make([][]byte, 0),
|
||||
Withdrawals: make([]*enginev1.Withdrawal, 0),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return payload
|
||||
}
|
||||
|
||||
func createWrappedPayloadHeaderCapella(t testing.TB) interfaces.ExecutionData {
|
||||
payload, err := blocks.WrappedExecutionPayloadHeaderCapella(&enginev1.ExecutionPayloadHeaderCapella{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
||||
StateRoot: make([]byte, fieldparams.RootLength),
|
||||
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
||||
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
||||
PrevRandao: make([]byte, fieldparams.RootLength),
|
||||
BlockNumber: 0,
|
||||
GasLimit: 0,
|
||||
GasUsed: 0,
|
||||
Timestamp: 0,
|
||||
ExtraData: make([]byte, 0),
|
||||
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
||||
BlockHash: make([]byte, fieldparams.RootLength),
|
||||
TransactionsRoot: make([]byte, fieldparams.RootLength),
|
||||
WithdrawalsRoot: make([]byte, fieldparams.RootLength),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return payload
|
||||
}
|
||||
|
||||
@@ -47,6 +47,14 @@ func NewSignedBeaconBlock(i interface{}) (interfaces.SignedBeaconBlock, error) {
|
||||
return initBlindedSignedBlockFromProtoBellatrix(b.BlindedBellatrix)
|
||||
case *eth.SignedBlindedBeaconBlockBellatrix:
|
||||
return initBlindedSignedBlockFromProtoBellatrix(b)
|
||||
case *eth.GenericSignedBeaconBlock_Capella:
|
||||
return initSignedBlockFromProtoCapella(b.Capella)
|
||||
case *eth.SignedBeaconBlockCapella:
|
||||
return initSignedBlockFromProtoCapella(b)
|
||||
case *eth.GenericSignedBeaconBlock_BlindedCapella:
|
||||
return initBlindedSignedBlockFromProtoCapella(b.BlindedCapella)
|
||||
case *eth.SignedBlindedBeaconBlockCapella:
|
||||
return initBlindedSignedBlockFromProtoCapella(b)
|
||||
default:
|
||||
return nil, errors.Wrapf(ErrUnsupportedSignedBeaconBlock, "unable to create block from type %T", i)
|
||||
}
|
||||
@@ -73,6 +81,14 @@ func NewBeaconBlock(i interface{}) (interfaces.BeaconBlock, error) {
|
||||
return initBlindedBlockFromProtoBellatrix(b.BlindedBellatrix)
|
||||
case *eth.BlindedBeaconBlockBellatrix:
|
||||
return initBlindedBlockFromProtoBellatrix(b)
|
||||
case *eth.GenericBeaconBlock_Capella:
|
||||
return initBlockFromProtoCapella(b.Capella)
|
||||
case *eth.BeaconBlockCapella:
|
||||
return initBlockFromProtoCapella(b)
|
||||
case *eth.GenericBeaconBlock_BlindedCapella:
|
||||
return initBlindedBlockFromProtoCapella(b.BlindedCapella)
|
||||
case *eth.BlindedBeaconBlockCapella:
|
||||
return initBlindedBlockFromProtoCapella(b)
|
||||
default:
|
||||
return nil, errors.Wrapf(errUnsupportedBeaconBlock, "unable to create block from type %T", i)
|
||||
}
|
||||
@@ -91,6 +107,10 @@ func NewBeaconBlockBody(i interface{}) (interfaces.BeaconBlockBody, error) {
|
||||
return initBlockBodyFromProtoBellatrix(b)
|
||||
case *eth.BlindedBeaconBlockBodyBellatrix:
|
||||
return initBlindedBlockBodyFromProtoBellatrix(b)
|
||||
case *eth.BeaconBlockBodyCapella:
|
||||
return initBlockBodyFromProtoCapella(b)
|
||||
case *eth.BlindedBeaconBlockBodyCapella:
|
||||
return initBlindedBlockBodyFromProtoCapella(b)
|
||||
default:
|
||||
return nil, errors.Wrapf(errUnsupportedBeaconBlockBody, "unable to create block body from type %T", i)
|
||||
}
|
||||
@@ -131,6 +151,19 @@ func BuildSignedBeaconBlock(blk interfaces.BeaconBlock, signature []byte) (inter
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
return NewSignedBeaconBlock(ð.SignedBeaconBlockBellatrix{Block: pb, Signature: signature})
|
||||
case version.Capella:
|
||||
if blk.IsBlinded() {
|
||||
pb, ok := pb.(*eth.BlindedBeaconBlockCapella)
|
||||
if !ok {
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
return NewSignedBeaconBlock(ð.SignedBlindedBeaconBlockCapella{Block: pb, Signature: signature})
|
||||
}
|
||||
pb, ok := pb.(*eth.BeaconBlockCapella)
|
||||
if !ok {
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
return NewSignedBeaconBlock(ð.SignedBeaconBlockCapella{Block: pb, Signature: signature})
|
||||
default:
|
||||
return nil, errUnsupportedBeaconBlock
|
||||
}
|
||||
@@ -139,7 +172,7 @@ func BuildSignedBeaconBlock(blk interfaces.BeaconBlock, signature []byte) (inter
|
||||
// BuildSignedBeaconBlockFromExecutionPayload takes a signed, blinded beacon block and converts into
|
||||
// a full, signed beacon block by specifying an execution payload.
|
||||
func BuildSignedBeaconBlockFromExecutionPayload(
|
||||
blk interfaces.SignedBeaconBlock, payload *enginev1.ExecutionPayload,
|
||||
blk interfaces.SignedBeaconBlock, payload interface{},
|
||||
) (interfaces.SignedBeaconBlock, error) {
|
||||
if err := BeaconBlockIsNil(blk); err != nil {
|
||||
return nil, err
|
||||
@@ -153,16 +186,26 @@ func BuildSignedBeaconBlockFromExecutionPayload(
|
||||
return nil, errors.Wrap(err, "could not get execution payload header")
|
||||
default:
|
||||
}
|
||||
wrappedPayload, err := WrappedExecutionPayload(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
var wrappedPayload interfaces.ExecutionData
|
||||
var wrapErr error
|
||||
switch p := payload.(type) {
|
||||
case *enginev1.ExecutionPayload:
|
||||
wrappedPayload, wrapErr = WrappedExecutionPayload(p)
|
||||
case *enginev1.ExecutionPayloadCapella:
|
||||
wrappedPayload, wrapErr = WrappedExecutionPayloadCapella(p)
|
||||
default:
|
||||
return nil, fmt.Errorf("%T is not a type of execution payload", p)
|
||||
}
|
||||
if wrapErr != nil {
|
||||
return nil, wrapErr
|
||||
}
|
||||
empty, err := IsEmptyExecutionData(wrappedPayload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !empty {
|
||||
payloadRoot, err := payload.HashTreeRoot()
|
||||
payloadRoot, err := wrappedPayload.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not hash tree root execution payload")
|
||||
}
|
||||
@@ -187,26 +230,61 @@ func BuildSignedBeaconBlockFromExecutionPayload(
|
||||
randaoReveal := b.Body().RandaoReveal()
|
||||
graffiti := b.Body().Graffiti()
|
||||
sig := blk.Signature()
|
||||
bellatrixFullBlock := ð.SignedBeaconBlockBellatrix{
|
||||
Block: ð.BeaconBlockBellatrix{
|
||||
Slot: b.Slot(),
|
||||
ProposerIndex: b.ProposerIndex(),
|
||||
ParentRoot: parentRoot[:],
|
||||
StateRoot: stateRoot[:],
|
||||
Body: ð.BeaconBlockBodyBellatrix{
|
||||
RandaoReveal: randaoReveal[:],
|
||||
Eth1Data: b.Body().Eth1Data(),
|
||||
Graffiti: graffiti[:],
|
||||
ProposerSlashings: b.Body().ProposerSlashings(),
|
||||
AttesterSlashings: b.Body().AttesterSlashings(),
|
||||
Attestations: b.Body().Attestations(),
|
||||
Deposits: b.Body().Deposits(),
|
||||
VoluntaryExits: b.Body().VoluntaryExits(),
|
||||
SyncAggregate: syncAgg,
|
||||
ExecutionPayload: payload,
|
||||
|
||||
var fullBlock interface{}
|
||||
switch p := payload.(type) {
|
||||
case *enginev1.ExecutionPayload:
|
||||
fullBlock = ð.SignedBeaconBlockBellatrix{
|
||||
Block: ð.BeaconBlockBellatrix{
|
||||
Slot: b.Slot(),
|
||||
ProposerIndex: b.ProposerIndex(),
|
||||
ParentRoot: parentRoot[:],
|
||||
StateRoot: stateRoot[:],
|
||||
Body: ð.BeaconBlockBodyBellatrix{
|
||||
RandaoReveal: randaoReveal[:],
|
||||
Eth1Data: b.Body().Eth1Data(),
|
||||
Graffiti: graffiti[:],
|
||||
ProposerSlashings: b.Body().ProposerSlashings(),
|
||||
AttesterSlashings: b.Body().AttesterSlashings(),
|
||||
Attestations: b.Body().Attestations(),
|
||||
Deposits: b.Body().Deposits(),
|
||||
VoluntaryExits: b.Body().VoluntaryExits(),
|
||||
SyncAggregate: syncAgg,
|
||||
ExecutionPayload: p,
|
||||
},
|
||||
},
|
||||
},
|
||||
Signature: sig[:],
|
||||
Signature: sig[:],
|
||||
}
|
||||
case *enginev1.ExecutionPayloadCapella:
|
||||
blsToExecutionChanges, err := b.Body().BLSToExecutionChanges()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fullBlock = ð.SignedBeaconBlockCapella{
|
||||
Block: ð.BeaconBlockCapella{
|
||||
Slot: b.Slot(),
|
||||
ProposerIndex: b.ProposerIndex(),
|
||||
ParentRoot: parentRoot[:],
|
||||
StateRoot: stateRoot[:],
|
||||
Body: ð.BeaconBlockBodyCapella{
|
||||
RandaoReveal: randaoReveal[:],
|
||||
Eth1Data: b.Body().Eth1Data(),
|
||||
Graffiti: graffiti[:],
|
||||
ProposerSlashings: b.Body().ProposerSlashings(),
|
||||
AttesterSlashings: b.Body().AttesterSlashings(),
|
||||
Attestations: b.Body().Attestations(),
|
||||
Deposits: b.Body().Deposits(),
|
||||
VoluntaryExits: b.Body().VoluntaryExits(),
|
||||
SyncAggregate: syncAgg,
|
||||
ExecutionPayload: p,
|
||||
BlsToExecutionChanges: blsToExecutionChanges,
|
||||
},
|
||||
},
|
||||
Signature: sig[:],
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("%T is not a type of execution payload", p)
|
||||
}
|
||||
return NewSignedBeaconBlock(bellatrixFullBlock)
|
||||
|
||||
return NewSignedBeaconBlock(fullBlock)
|
||||
}
|
||||
|
||||
@@ -85,6 +85,42 @@ func Test_NewSignedBeaconBlock(t *testing.T) {
|
||||
assert.Equal(t, version.Bellatrix, b.Version())
|
||||
assert.Equal(t, true, b.IsBlinded())
|
||||
})
|
||||
t.Run("GenericSignedBeaconBlock_Capella", func(t *testing.T) {
|
||||
pb := ð.GenericSignedBeaconBlock_Capella{
|
||||
Capella: ð.SignedBeaconBlockCapella{
|
||||
Block: ð.BeaconBlockCapella{
|
||||
Body: ð.BeaconBlockBodyCapella{}}}}
|
||||
b, err := NewSignedBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, version.Capella, b.Version())
|
||||
})
|
||||
t.Run("SignedBeaconBlockCapella", func(t *testing.T) {
|
||||
pb := ð.SignedBeaconBlockCapella{
|
||||
Block: ð.BeaconBlockCapella{
|
||||
Body: ð.BeaconBlockBodyCapella{}}}
|
||||
b, err := NewSignedBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, version.Capella, b.Version())
|
||||
})
|
||||
t.Run("GenericSignedBeaconBlock_BlindedCapella", func(t *testing.T) {
|
||||
pb := ð.GenericSignedBeaconBlock_BlindedCapella{
|
||||
BlindedCapella: ð.SignedBlindedBeaconBlockCapella{
|
||||
Block: ð.BlindedBeaconBlockCapella{
|
||||
Body: ð.BlindedBeaconBlockBodyCapella{}}}}
|
||||
b, err := NewSignedBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, version.Capella, b.Version())
|
||||
assert.Equal(t, true, b.IsBlinded())
|
||||
})
|
||||
t.Run("SignedBlindedBeaconBlockCapella", func(t *testing.T) {
|
||||
pb := ð.SignedBlindedBeaconBlockCapella{
|
||||
Block: ð.BlindedBeaconBlockCapella{
|
||||
Body: ð.BlindedBeaconBlockBodyCapella{}}}
|
||||
b, err := NewSignedBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, version.Capella, b.Version())
|
||||
assert.Equal(t, true, b.IsBlinded())
|
||||
})
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
_, err := NewSignedBeaconBlock(nil)
|
||||
assert.ErrorContains(t, "received nil object", err)
|
||||
@@ -146,6 +182,32 @@ func Test_NewBeaconBlock(t *testing.T) {
|
||||
assert.Equal(t, version.Bellatrix, b.Version())
|
||||
assert.Equal(t, true, b.IsBlinded())
|
||||
})
|
||||
t.Run("GenericBeaconBlock_Capella", func(t *testing.T) {
|
||||
pb := ð.GenericBeaconBlock_Capella{Capella: ð.BeaconBlockCapella{Body: ð.BeaconBlockBodyCapella{}}}
|
||||
b, err := NewBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, version.Capella, b.Version())
|
||||
})
|
||||
t.Run("BeaconBlockCapella", func(t *testing.T) {
|
||||
pb := ð.BeaconBlockCapella{Body: ð.BeaconBlockBodyCapella{}}
|
||||
b, err := NewBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, version.Capella, b.Version())
|
||||
})
|
||||
t.Run("GenericBeaconBlock_BlindedCapella", func(t *testing.T) {
|
||||
pb := ð.GenericBeaconBlock_BlindedCapella{BlindedCapella: ð.BlindedBeaconBlockCapella{Body: ð.BlindedBeaconBlockBodyCapella{}}}
|
||||
b, err := NewBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, version.Capella, b.Version())
|
||||
assert.Equal(t, true, b.IsBlinded())
|
||||
})
|
||||
t.Run("BlindedBeaconBlockCapella", func(t *testing.T) {
|
||||
pb := ð.BlindedBeaconBlockCapella{Body: ð.BlindedBeaconBlockBodyCapella{}}
|
||||
b, err := NewBeaconBlock(pb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, version.Capella, b.Version())
|
||||
assert.Equal(t, true, b.IsBlinded())
|
||||
})
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
_, err := NewBeaconBlock(nil)
|
||||
assert.ErrorContains(t, "received nil object", err)
|
||||
@@ -190,6 +252,23 @@ func Test_NewBeaconBlockBody(t *testing.T) {
|
||||
assert.Equal(t, version.Bellatrix, b.version)
|
||||
assert.Equal(t, true, b.isBlinded)
|
||||
})
|
||||
t.Run("BeaconBlockBodyCapella", func(t *testing.T) {
|
||||
pb := ð.BeaconBlockBodyCapella{}
|
||||
i, err := NewBeaconBlockBody(pb)
|
||||
require.NoError(t, err)
|
||||
b, ok := i.(*BeaconBlockBody)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, version.Capella, b.version)
|
||||
})
|
||||
t.Run("BlindedBeaconBlockBodyCapella", func(t *testing.T) {
|
||||
pb := ð.BlindedBeaconBlockBodyCapella{}
|
||||
i, err := NewBeaconBlockBody(pb)
|
||||
require.NoError(t, err)
|
||||
b, ok := i.(*BeaconBlockBody)
|
||||
require.Equal(t, true, ok)
|
||||
assert.Equal(t, version.Capella, b.version)
|
||||
assert.Equal(t, true, b.isBlinded)
|
||||
})
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
_, err := NewBeaconBlockBody(nil)
|
||||
assert.ErrorContains(t, "received nil object", err)
|
||||
@@ -231,6 +310,21 @@ func Test_BuildSignedBeaconBlock(t *testing.T) {
|
||||
assert.Equal(t, version.Bellatrix, sb.Version())
|
||||
assert.Equal(t, true, sb.IsBlinded())
|
||||
})
|
||||
t.Run("Capella", func(t *testing.T) {
|
||||
b := &BeaconBlock{version: version.Capella, body: &BeaconBlockBody{version: version.Capella}}
|
||||
sb, err := BuildSignedBeaconBlock(b, sig[:])
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, sig, sb.Signature())
|
||||
assert.Equal(t, version.Capella, sb.Version())
|
||||
})
|
||||
t.Run("CapellaBlind", func(t *testing.T) {
|
||||
b := &BeaconBlock{version: version.Capella, body: &BeaconBlockBody{version: version.Capella, isBlinded: true}}
|
||||
sb, err := BuildSignedBeaconBlock(b, sig[:])
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, sig, sb.Signature())
|
||||
assert.Equal(t, version.Capella, sb.Version())
|
||||
assert.Equal(t, true, sb.IsBlinded())
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuildSignedBeaconBlockFromExecutionPayload(t *testing.T) {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ssz "github.com/prysmaticlabs/fastssz"
|
||||
field_params "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
@@ -60,6 +63,13 @@ func (b *SignedBeaconBlock) Copy() (interfaces.SignedBeaconBlock, error) {
|
||||
}
|
||||
cp := eth.CopySignedBeaconBlockBellatrix(pb.(*eth.SignedBeaconBlockBellatrix))
|
||||
return initSignedBlockFromProtoBellatrix(cp)
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
cp := eth.CopySignedBlindedBeaconBlockCapella(pb.(*eth.SignedBlindedBeaconBlockCapella))
|
||||
return initBlindedSignedBlockFromProtoCapella(cp)
|
||||
}
|
||||
cp := eth.CopySignedBeaconBlockCapella(pb.(*eth.SignedBeaconBlockCapella))
|
||||
return initSignedBlockFromProtoCapella(cp)
|
||||
default:
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
@@ -89,6 +99,15 @@ func (b *SignedBeaconBlock) PbGenericBlock() (*eth.GenericSignedBeaconBlock, err
|
||||
return ð.GenericSignedBeaconBlock{
|
||||
Block: ð.GenericSignedBeaconBlock_Bellatrix{Bellatrix: pb.(*eth.SignedBeaconBlockBellatrix)},
|
||||
}, nil
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
return ð.GenericSignedBeaconBlock{
|
||||
Block: ð.GenericSignedBeaconBlock_BlindedCapella{BlindedCapella: pb.(*eth.SignedBlindedBeaconBlockCapella)},
|
||||
}, nil
|
||||
}
|
||||
return ð.GenericSignedBeaconBlock{
|
||||
Block: ð.GenericSignedBeaconBlock_Capella{Capella: pb.(*eth.SignedBeaconBlockCapella)},
|
||||
}, nil
|
||||
default:
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
@@ -143,9 +162,33 @@ func (b *SignedBeaconBlock) PbBlindedBellatrixBlock() (*eth.SignedBlindedBeaconB
|
||||
return pb.(*eth.SignedBlindedBeaconBlockBellatrix), nil
|
||||
}
|
||||
|
||||
// PbCapellaBlock returns the underlying protobuf object.
|
||||
func (b *SignedBeaconBlock) PbCapellaBlock() (*eth.SignedBeaconBlockCapella, error) {
|
||||
if b.version != version.Capella || b.IsBlinded() {
|
||||
return nil, errNotSupported("PbCapellaBlock", b.version)
|
||||
}
|
||||
pb, err := b.Proto()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pb.(*eth.SignedBeaconBlockCapella), nil
|
||||
}
|
||||
|
||||
// PbBlindedCapellaBlock returns the underlying protobuf object.
|
||||
func (b *SignedBeaconBlock) PbBlindedCapellaBlock() (*eth.SignedBlindedBeaconBlockCapella, error) {
|
||||
if b.version != version.Capella || !b.IsBlinded() {
|
||||
return nil, errNotSupported("PbBlindedCapellaBlock", b.version)
|
||||
}
|
||||
pb, err := b.Proto()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pb.(*eth.SignedBlindedBeaconBlockCapella), nil
|
||||
}
|
||||
|
||||
// ToBlinded converts a non-blinded block to its blinded equivalent.
|
||||
func (b *SignedBeaconBlock) ToBlinded() (interfaces.SignedBeaconBlock, error) {
|
||||
if b.version != version.Bellatrix {
|
||||
if b.version < version.Bellatrix {
|
||||
return nil, ErrUnsupportedVersion
|
||||
}
|
||||
if b.IsBlinded() {
|
||||
@@ -158,32 +201,66 @@ func (b *SignedBeaconBlock) ToBlinded() (interfaces.SignedBeaconBlock, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
header, err := PayloadToHeader(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return initBlindedSignedBlockFromProtoBellatrix(
|
||||
ð.SignedBlindedBeaconBlockBellatrix{
|
||||
Block: ð.BlindedBeaconBlockBellatrix{
|
||||
Slot: b.block.slot,
|
||||
ProposerIndex: b.block.proposerIndex,
|
||||
ParentRoot: b.block.parentRoot[:],
|
||||
StateRoot: b.block.stateRoot[:],
|
||||
Body: ð.BlindedBeaconBlockBodyBellatrix{
|
||||
RandaoReveal: b.block.body.randaoReveal[:],
|
||||
Eth1Data: b.block.body.eth1Data,
|
||||
Graffiti: b.block.body.graffiti[:],
|
||||
ProposerSlashings: b.block.body.proposerSlashings,
|
||||
AttesterSlashings: b.block.body.attesterSlashings,
|
||||
Attestations: b.block.body.attestations,
|
||||
Deposits: b.block.body.deposits,
|
||||
VoluntaryExits: b.block.body.voluntaryExits,
|
||||
SyncAggregate: b.block.body.syncAggregate,
|
||||
ExecutionPayloadHeader: header,
|
||||
|
||||
switch p := payload.Proto().(type) {
|
||||
case *enginev1.ExecutionPayload:
|
||||
header, err := PayloadToHeader(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return initBlindedSignedBlockFromProtoBellatrix(
|
||||
ð.SignedBlindedBeaconBlockBellatrix{
|
||||
Block: ð.BlindedBeaconBlockBellatrix{
|
||||
Slot: b.block.slot,
|
||||
ProposerIndex: b.block.proposerIndex,
|
||||
ParentRoot: b.block.parentRoot[:],
|
||||
StateRoot: b.block.stateRoot[:],
|
||||
Body: ð.BlindedBeaconBlockBodyBellatrix{
|
||||
RandaoReveal: b.block.body.randaoReveal[:],
|
||||
Eth1Data: b.block.body.eth1Data,
|
||||
Graffiti: b.block.body.graffiti[:],
|
||||
ProposerSlashings: b.block.body.proposerSlashings,
|
||||
AttesterSlashings: b.block.body.attesterSlashings,
|
||||
Attestations: b.block.body.attestations,
|
||||
Deposits: b.block.body.deposits,
|
||||
VoluntaryExits: b.block.body.voluntaryExits,
|
||||
SyncAggregate: b.block.body.syncAggregate,
|
||||
ExecutionPayloadHeader: header,
|
||||
},
|
||||
},
|
||||
},
|
||||
Signature: b.signature[:],
|
||||
})
|
||||
Signature: b.signature[:],
|
||||
})
|
||||
case *enginev1.ExecutionPayloadCapella:
|
||||
header, err := PayloadToHeaderCapella(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return initBlindedSignedBlockFromProtoCapella(
|
||||
ð.SignedBlindedBeaconBlockCapella{
|
||||
Block: ð.BlindedBeaconBlockCapella{
|
||||
Slot: b.block.slot,
|
||||
ProposerIndex: b.block.proposerIndex,
|
||||
ParentRoot: b.block.parentRoot[:],
|
||||
StateRoot: b.block.stateRoot[:],
|
||||
Body: ð.BlindedBeaconBlockBodyCapella{
|
||||
RandaoReveal: b.block.body.randaoReveal[:],
|
||||
Eth1Data: b.block.body.eth1Data,
|
||||
Graffiti: b.block.body.graffiti[:],
|
||||
ProposerSlashings: b.block.body.proposerSlashings,
|
||||
AttesterSlashings: b.block.body.attesterSlashings,
|
||||
Attestations: b.block.body.attestations,
|
||||
Deposits: b.block.body.deposits,
|
||||
VoluntaryExits: b.block.body.voluntaryExits,
|
||||
SyncAggregate: b.block.body.syncAggregate,
|
||||
ExecutionPayloadHeader: header,
|
||||
BlsToExecutionChanges: b.block.body.blsToExecutionChanges,
|
||||
},
|
||||
},
|
||||
Signature: b.signature[:],
|
||||
})
|
||||
default:
|
||||
return nil, fmt.Errorf("%T is not an execution payload header", p)
|
||||
}
|
||||
}
|
||||
|
||||
// Version of the underlying protobuf object.
|
||||
@@ -233,6 +310,11 @@ func (b *SignedBeaconBlock) MarshalSSZ() ([]byte, error) {
|
||||
return pb.(*eth.SignedBlindedBeaconBlockBellatrix).MarshalSSZ()
|
||||
}
|
||||
return pb.(*eth.SignedBeaconBlockBellatrix).MarshalSSZ()
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
return pb.(*eth.SignedBlindedBeaconBlockCapella).MarshalSSZ()
|
||||
}
|
||||
return pb.(*eth.SignedBeaconBlockCapella).MarshalSSZ()
|
||||
default:
|
||||
return []byte{}, errIncorrectBlockVersion
|
||||
}
|
||||
@@ -255,6 +337,11 @@ func (b *SignedBeaconBlock) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
return pb.(*eth.SignedBlindedBeaconBlockBellatrix).MarshalSSZTo(dst)
|
||||
}
|
||||
return pb.(*eth.SignedBeaconBlockBellatrix).MarshalSSZTo(dst)
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
return pb.(*eth.SignedBlindedBeaconBlockCapella).MarshalSSZTo(dst)
|
||||
}
|
||||
return pb.(*eth.SignedBeaconBlockCapella).MarshalSSZTo(dst)
|
||||
default:
|
||||
return []byte{}, errIncorrectBlockVersion
|
||||
}
|
||||
@@ -281,6 +368,11 @@ func (b *SignedBeaconBlock) SizeSSZ() int {
|
||||
return pb.(*eth.SignedBlindedBeaconBlockBellatrix).SizeSSZ()
|
||||
}
|
||||
return pb.(*eth.SignedBeaconBlockBellatrix).SizeSSZ()
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
return pb.(*eth.SignedBlindedBeaconBlockCapella).SizeSSZ()
|
||||
}
|
||||
return pb.(*eth.SignedBeaconBlockCapella).SizeSSZ()
|
||||
default:
|
||||
panic(incorrectBlockVersion)
|
||||
}
|
||||
@@ -332,6 +424,28 @@ func (b *SignedBeaconBlock) UnmarshalSSZ(buf []byte) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
pb := ð.SignedBlindedBeaconBlockCapella{}
|
||||
if err := pb.UnmarshalSSZ(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
var err error
|
||||
newBlock, err = initBlindedSignedBlockFromProtoCapella(pb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
pb := ð.SignedBeaconBlockCapella{}
|
||||
if err := pb.UnmarshalSSZ(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
var err error
|
||||
newBlock, err = initSignedBlockFromProtoCapella(pb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errIncorrectBlockVersion
|
||||
}
|
||||
@@ -359,6 +473,13 @@ func (b *BeaconBlock) StateRoot() [field_params.RootLength]byte {
|
||||
return b.stateRoot
|
||||
}
|
||||
|
||||
// SetStateRoot sets the state root of the underlying beacon block
|
||||
// This function is not thread safe, it is only used during block
|
||||
// proposal to set the state root of a new block
|
||||
func (b *BeaconBlock) SetStateRoot(root []byte) {
|
||||
copy(b.stateRoot[:], root)
|
||||
}
|
||||
|
||||
// Body returns the underlying block body.
|
||||
func (b *BeaconBlock) Body() interfaces.BeaconBlockBody {
|
||||
return b.body
|
||||
@@ -395,6 +516,11 @@ func (b *BeaconBlock) HashTreeRoot() ([field_params.RootLength]byte, error) {
|
||||
return pb.(*eth.BlindedBeaconBlockBellatrix).HashTreeRoot()
|
||||
}
|
||||
return pb.(*eth.BeaconBlockBellatrix).HashTreeRoot()
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
return pb.(*eth.BlindedBeaconBlockCapella).HashTreeRoot()
|
||||
}
|
||||
return pb.(*eth.BeaconBlockCapella).HashTreeRoot()
|
||||
default:
|
||||
return [field_params.RootLength]byte{}, errIncorrectBlockVersion
|
||||
}
|
||||
@@ -416,6 +542,11 @@ func (b *BeaconBlock) HashTreeRootWith(h *ssz.Hasher) error {
|
||||
return pb.(*eth.BlindedBeaconBlockBellatrix).HashTreeRootWith(h)
|
||||
}
|
||||
return pb.(*eth.BeaconBlockBellatrix).HashTreeRootWith(h)
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
return pb.(*eth.BlindedBeaconBlockCapella).HashTreeRootWith(h)
|
||||
}
|
||||
return pb.(*eth.BeaconBlockCapella).HashTreeRootWith(h)
|
||||
default:
|
||||
return errIncorrectBlockVersion
|
||||
}
|
||||
@@ -438,6 +569,11 @@ func (b *BeaconBlock) MarshalSSZ() ([]byte, error) {
|
||||
return pb.(*eth.BlindedBeaconBlockBellatrix).MarshalSSZ()
|
||||
}
|
||||
return pb.(*eth.BeaconBlockBellatrix).MarshalSSZ()
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
return pb.(*eth.BlindedBeaconBlockCapella).MarshalSSZ()
|
||||
}
|
||||
return pb.(*eth.BeaconBlockCapella).MarshalSSZ()
|
||||
default:
|
||||
return []byte{}, errIncorrectBlockVersion
|
||||
}
|
||||
@@ -460,6 +596,11 @@ func (b *BeaconBlock) MarshalSSZTo(dst []byte) ([]byte, error) {
|
||||
return pb.(*eth.BlindedBeaconBlockBellatrix).MarshalSSZTo(dst)
|
||||
}
|
||||
return pb.(*eth.BeaconBlockBellatrix).MarshalSSZTo(dst)
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
return pb.(*eth.BlindedBeaconBlockCapella).MarshalSSZTo(dst)
|
||||
}
|
||||
return pb.(*eth.BeaconBlockCapella).MarshalSSZTo(dst)
|
||||
default:
|
||||
return []byte{}, errIncorrectBlockVersion
|
||||
}
|
||||
@@ -486,6 +627,11 @@ func (b *BeaconBlock) SizeSSZ() int {
|
||||
return pb.(*eth.BlindedBeaconBlockBellatrix).SizeSSZ()
|
||||
}
|
||||
return pb.(*eth.BeaconBlockBellatrix).SizeSSZ()
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
return pb.(*eth.BlindedBeaconBlockCapella).SizeSSZ()
|
||||
}
|
||||
return pb.(*eth.BeaconBlockCapella).SizeSSZ()
|
||||
default:
|
||||
panic(incorrectBodyVersion)
|
||||
}
|
||||
@@ -537,6 +683,28 @@ func (b *BeaconBlock) UnmarshalSSZ(buf []byte) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
pb := ð.BlindedBeaconBlockCapella{}
|
||||
if err := pb.UnmarshalSSZ(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
var err error
|
||||
newBlock, err = initBlindedBlockFromProtoCapella(pb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
pb := ð.BeaconBlockCapella{}
|
||||
if err := pb.UnmarshalSSZ(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
var err error
|
||||
newBlock, err = initBlockFromProtoCapella(pb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errIncorrectBlockVersion
|
||||
}
|
||||
@@ -560,6 +728,11 @@ func (b *BeaconBlock) AsSignRequestObject() (validatorpb.SignRequestObject, erro
|
||||
return &validatorpb.SignRequest_BlindedBlockBellatrix{BlindedBlockBellatrix: pb.(*eth.BlindedBeaconBlockBellatrix)}, nil
|
||||
}
|
||||
return &validatorpb.SignRequest_BlockBellatrix{BlockBellatrix: pb.(*eth.BeaconBlockBellatrix)}, nil
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
return &validatorpb.SignRequest_BlindedBlockCapella{BlindedBlockCapella: pb.(*eth.BlindedBeaconBlockCapella)}, nil
|
||||
}
|
||||
return &validatorpb.SignRequest_BlockCapella{BlockCapella: pb.(*eth.BeaconBlockCapella)}, nil
|
||||
default:
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
@@ -625,14 +798,58 @@ func (b *BeaconBlockBody) Execution() (interfaces.ExecutionData, error) {
|
||||
return nil, errNotSupported("Execution", b.version)
|
||||
case version.Bellatrix:
|
||||
if b.isBlinded {
|
||||
return WrappedExecutionPayloadHeader(b.executionPayloadHeader)
|
||||
var ph *enginev1.ExecutionPayloadHeader
|
||||
var ok bool
|
||||
if b.executionPayloadHeader != nil {
|
||||
ph, ok = b.executionPayloadHeader.Proto().(*enginev1.ExecutionPayloadHeader)
|
||||
if !ok {
|
||||
return nil, errPayloadHeaderWrongType
|
||||
}
|
||||
}
|
||||
return WrappedExecutionPayloadHeader(ph)
|
||||
}
|
||||
return WrappedExecutionPayload(b.executionPayload)
|
||||
var p *enginev1.ExecutionPayload
|
||||
var ok bool
|
||||
if b.executionPayload != nil {
|
||||
p, ok = b.executionPayload.Proto().(*enginev1.ExecutionPayload)
|
||||
if !ok {
|
||||
return nil, errPayloadWrongType
|
||||
}
|
||||
}
|
||||
return WrappedExecutionPayload(p)
|
||||
case version.Capella:
|
||||
if b.isBlinded {
|
||||
var ph *enginev1.ExecutionPayloadHeaderCapella
|
||||
var ok bool
|
||||
if b.executionPayloadHeader != nil {
|
||||
ph, ok = b.executionPayloadHeader.Proto().(*enginev1.ExecutionPayloadHeaderCapella)
|
||||
if !ok {
|
||||
return nil, errPayloadHeaderWrongType
|
||||
}
|
||||
return WrappedExecutionPayloadHeaderCapella(ph)
|
||||
}
|
||||
}
|
||||
var p *enginev1.ExecutionPayloadCapella
|
||||
var ok bool
|
||||
if b.executionPayload != nil {
|
||||
p, ok = b.executionPayload.Proto().(*enginev1.ExecutionPayloadCapella)
|
||||
if !ok {
|
||||
return nil, errPayloadWrongType
|
||||
}
|
||||
}
|
||||
return WrappedExecutionPayloadCapella(p)
|
||||
default:
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BeaconBlockBody) BLSToExecutionChanges() ([]*eth.SignedBLSToExecutionChange, error) {
|
||||
if b.version < version.Capella {
|
||||
return nil, errNotSupported("BLSToExecutionChanges", b.version)
|
||||
}
|
||||
return b.blsToExecutionChanges, nil
|
||||
}
|
||||
|
||||
// HashTreeRoot returns the ssz root of the block body.
|
||||
func (b *BeaconBlockBody) HashTreeRoot() ([field_params.RootLength]byte, error) {
|
||||
pb, err := b.Proto()
|
||||
@@ -649,6 +866,11 @@ func (b *BeaconBlockBody) HashTreeRoot() ([field_params.RootLength]byte, error)
|
||||
return pb.(*eth.BlindedBeaconBlockBodyBellatrix).HashTreeRoot()
|
||||
}
|
||||
return pb.(*eth.BeaconBlockBodyBellatrix).HashTreeRoot()
|
||||
case version.Capella:
|
||||
if b.isBlinded {
|
||||
return pb.(*eth.BlindedBeaconBlockBodyCapella).HashTreeRoot()
|
||||
}
|
||||
return pb.(*eth.BeaconBlockBodyCapella).HashTreeRoot()
|
||||
default:
|
||||
return [field_params.RootLength]byte{}, errIncorrectBodyVersion
|
||||
}
|
||||
|
||||
@@ -309,6 +309,14 @@ func Test_BeaconBlockBody_SyncAggregate(t *testing.T) {
|
||||
assert.Equal(t, result, sa)
|
||||
}
|
||||
|
||||
func Test_BeaconBlockBody_BLSToExecutionChanges(t *testing.T) {
|
||||
changes := []*eth.SignedBLSToExecutionChange{{}}
|
||||
bb := &BeaconBlockBody{version: version.Capella, blsToExecutionChanges: changes}
|
||||
result, err := bb.BLSToExecutionChanges()
|
||||
require.NoError(t, err)
|
||||
assert.DeepSSZEqual(t, result, changes)
|
||||
}
|
||||
|
||||
func Test_BeaconBlockBody_HashTreeRoot(t *testing.T) {
|
||||
pb := hydrateBeaconBlockBody()
|
||||
expectedHTR, err := pb.HashTreeRoot()
|
||||
|
||||
@@ -3,6 +3,7 @@ package blocks
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -73,6 +74,33 @@ func (b *SignedBeaconBlock) Proto() (proto.Message, error) {
|
||||
Block: block,
|
||||
Signature: b.signature[:],
|
||||
}, nil
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
var block *eth.BlindedBeaconBlockCapella
|
||||
if blockMessage != nil {
|
||||
var ok bool
|
||||
block, ok = blockMessage.(*eth.BlindedBeaconBlockCapella)
|
||||
if !ok {
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
}
|
||||
return ð.SignedBlindedBeaconBlockCapella{
|
||||
Block: block,
|
||||
Signature: b.signature[:],
|
||||
}, nil
|
||||
}
|
||||
var block *eth.BeaconBlockCapella
|
||||
if blockMessage != nil {
|
||||
var ok bool
|
||||
block, ok = blockMessage.(*eth.BeaconBlockCapella)
|
||||
if !ok {
|
||||
return nil, errIncorrectBlockVersion
|
||||
}
|
||||
}
|
||||
return ð.SignedBeaconBlockCapella{
|
||||
Block: block,
|
||||
Signature: b.signature[:],
|
||||
}, nil
|
||||
default:
|
||||
return nil, errors.New("unsupported signed beacon block version")
|
||||
}
|
||||
@@ -155,6 +183,39 @@ func (b *BeaconBlock) Proto() (proto.Message, error) {
|
||||
StateRoot: b.stateRoot[:],
|
||||
Body: body,
|
||||
}, nil
|
||||
case version.Capella:
|
||||
if b.IsBlinded() {
|
||||
var body *eth.BlindedBeaconBlockBodyCapella
|
||||
if bodyMessage != nil {
|
||||
var ok bool
|
||||
body, ok = bodyMessage.(*eth.BlindedBeaconBlockBodyCapella)
|
||||
if !ok {
|
||||
return nil, errIncorrectBodyVersion
|
||||
}
|
||||
}
|
||||
return ð.BlindedBeaconBlockCapella{
|
||||
Slot: b.slot,
|
||||
ProposerIndex: b.proposerIndex,
|
||||
ParentRoot: b.parentRoot[:],
|
||||
StateRoot: b.stateRoot[:],
|
||||
Body: body,
|
||||
}, nil
|
||||
}
|
||||
var body *eth.BeaconBlockBodyCapella
|
||||
if bodyMessage != nil {
|
||||
var ok bool
|
||||
body, ok = bodyMessage.(*eth.BeaconBlockBodyCapella)
|
||||
if !ok {
|
||||
return nil, errIncorrectBodyVersion
|
||||
}
|
||||
}
|
||||
return ð.BeaconBlockCapella{
|
||||
Slot: b.slot,
|
||||
ProposerIndex: b.proposerIndex,
|
||||
ParentRoot: b.parentRoot[:],
|
||||
StateRoot: b.stateRoot[:],
|
||||
Body: body,
|
||||
}, nil
|
||||
default:
|
||||
return nil, errors.New("unsupported beacon block version")
|
||||
}
|
||||
@@ -192,6 +253,14 @@ func (b *BeaconBlockBody) Proto() (proto.Message, error) {
|
||||
}, nil
|
||||
case version.Bellatrix:
|
||||
if b.isBlinded {
|
||||
var ph *enginev1.ExecutionPayloadHeader
|
||||
var ok bool
|
||||
if b.executionPayloadHeader != nil {
|
||||
ph, ok = b.executionPayloadHeader.Proto().(*enginev1.ExecutionPayloadHeader)
|
||||
if !ok {
|
||||
return nil, errPayloadHeaderWrongType
|
||||
}
|
||||
}
|
||||
return ð.BlindedBeaconBlockBodyBellatrix{
|
||||
RandaoReveal: b.randaoReveal[:],
|
||||
Eth1Data: b.eth1Data,
|
||||
@@ -202,9 +271,17 @@ func (b *BeaconBlockBody) Proto() (proto.Message, error) {
|
||||
Deposits: b.deposits,
|
||||
VoluntaryExits: b.voluntaryExits,
|
||||
SyncAggregate: b.syncAggregate,
|
||||
ExecutionPayloadHeader: b.executionPayloadHeader,
|
||||
ExecutionPayloadHeader: ph,
|
||||
}, nil
|
||||
}
|
||||
var p *enginev1.ExecutionPayload
|
||||
var ok bool
|
||||
if b.executionPayload != nil {
|
||||
p, ok = b.executionPayload.Proto().(*enginev1.ExecutionPayload)
|
||||
if !ok {
|
||||
return nil, errPayloadWrongType
|
||||
}
|
||||
}
|
||||
return ð.BeaconBlockBodyBellatrix{
|
||||
RandaoReveal: b.randaoReveal[:],
|
||||
Eth1Data: b.eth1Data,
|
||||
@@ -215,7 +292,52 @@ func (b *BeaconBlockBody) Proto() (proto.Message, error) {
|
||||
Deposits: b.deposits,
|
||||
VoluntaryExits: b.voluntaryExits,
|
||||
SyncAggregate: b.syncAggregate,
|
||||
ExecutionPayload: b.executionPayload,
|
||||
ExecutionPayload: p,
|
||||
}, nil
|
||||
case version.Capella:
|
||||
if b.isBlinded {
|
||||
var ph *enginev1.ExecutionPayloadHeaderCapella
|
||||
var ok bool
|
||||
if b.executionPayloadHeader != nil {
|
||||
ph, ok = b.executionPayloadHeader.Proto().(*enginev1.ExecutionPayloadHeaderCapella)
|
||||
if !ok {
|
||||
return nil, errPayloadHeaderWrongType
|
||||
}
|
||||
}
|
||||
return ð.BlindedBeaconBlockBodyCapella{
|
||||
RandaoReveal: b.randaoReveal[:],
|
||||
Eth1Data: b.eth1Data,
|
||||
Graffiti: b.graffiti[:],
|
||||
ProposerSlashings: b.proposerSlashings,
|
||||
AttesterSlashings: b.attesterSlashings,
|
||||
Attestations: b.attestations,
|
||||
Deposits: b.deposits,
|
||||
VoluntaryExits: b.voluntaryExits,
|
||||
SyncAggregate: b.syncAggregate,
|
||||
ExecutionPayloadHeader: ph,
|
||||
BlsToExecutionChanges: b.blsToExecutionChanges,
|
||||
}, nil
|
||||
}
|
||||
var p *enginev1.ExecutionPayloadCapella
|
||||
var ok bool
|
||||
if b.executionPayload != nil {
|
||||
p, ok = b.executionPayload.Proto().(*enginev1.ExecutionPayloadCapella)
|
||||
if !ok {
|
||||
return nil, errPayloadWrongType
|
||||
}
|
||||
}
|
||||
return ð.BeaconBlockBodyCapella{
|
||||
RandaoReveal: b.randaoReveal[:],
|
||||
Eth1Data: b.eth1Data,
|
||||
Graffiti: b.graffiti[:],
|
||||
ProposerSlashings: b.proposerSlashings,
|
||||
AttesterSlashings: b.attesterSlashings,
|
||||
Attestations: b.attestations,
|
||||
Deposits: b.deposits,
|
||||
VoluntaryExits: b.voluntaryExits,
|
||||
SyncAggregate: b.syncAggregate,
|
||||
ExecutionPayload: p,
|
||||
BlsToExecutionChanges: b.blsToExecutionChanges,
|
||||
}, nil
|
||||
default:
|
||||
return nil, errors.New("unsupported beacon block body version")
|
||||
@@ -273,6 +395,23 @@ func initSignedBlockFromProtoBellatrix(pb *eth.SignedBeaconBlockBellatrix) (*Sig
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func initSignedBlockFromProtoCapella(pb *eth.SignedBeaconBlockCapella) (*SignedBeaconBlock, error) {
|
||||
if pb == nil {
|
||||
return nil, errNilBlock
|
||||
}
|
||||
|
||||
block, err := initBlockFromProtoCapella(pb.Block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := &SignedBeaconBlock{
|
||||
version: version.Capella,
|
||||
block: block,
|
||||
signature: bytesutil.ToBytes96(pb.Signature),
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func initBlindedSignedBlockFromProtoBellatrix(pb *eth.SignedBlindedBeaconBlockBellatrix) (*SignedBeaconBlock, error) {
|
||||
if pb == nil {
|
||||
return nil, errNilBlock
|
||||
@@ -290,6 +429,23 @@ func initBlindedSignedBlockFromProtoBellatrix(pb *eth.SignedBlindedBeaconBlockBe
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func initBlindedSignedBlockFromProtoCapella(pb *eth.SignedBlindedBeaconBlockCapella) (*SignedBeaconBlock, error) {
|
||||
if pb == nil {
|
||||
return nil, errNilBlock
|
||||
}
|
||||
|
||||
block, err := initBlindedBlockFromProtoCapella(pb.Block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := &SignedBeaconBlock{
|
||||
version: version.Capella,
|
||||
block: block,
|
||||
signature: bytesutil.ToBytes96(pb.Signature),
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func initBlockFromProtoPhase0(pb *eth.BeaconBlock) (*BeaconBlock, error) {
|
||||
if pb == nil {
|
||||
return nil, errNilBlock
|
||||
@@ -370,6 +526,46 @@ func initBlindedBlockFromProtoBellatrix(pb *eth.BlindedBeaconBlockBellatrix) (*B
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func initBlockFromProtoCapella(pb *eth.BeaconBlockCapella) (*BeaconBlock, error) {
|
||||
if pb == nil {
|
||||
return nil, errNilBlock
|
||||
}
|
||||
|
||||
body, err := initBlockBodyFromProtoCapella(pb.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := &BeaconBlock{
|
||||
version: version.Capella,
|
||||
slot: pb.Slot,
|
||||
proposerIndex: pb.ProposerIndex,
|
||||
parentRoot: bytesutil.ToBytes32(pb.ParentRoot),
|
||||
stateRoot: bytesutil.ToBytes32(pb.StateRoot),
|
||||
body: body,
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func initBlindedBlockFromProtoCapella(pb *eth.BlindedBeaconBlockCapella) (*BeaconBlock, error) {
|
||||
if pb == nil {
|
||||
return nil, errNilBlock
|
||||
}
|
||||
|
||||
body, err := initBlindedBlockBodyFromProtoCapella(pb.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := &BeaconBlock{
|
||||
version: version.Capella,
|
||||
slot: pb.Slot,
|
||||
proposerIndex: pb.ProposerIndex,
|
||||
parentRoot: bytesutil.ToBytes32(pb.ParentRoot),
|
||||
stateRoot: bytesutil.ToBytes32(pb.StateRoot),
|
||||
body: body,
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func initBlockBodyFromProtoPhase0(pb *eth.BeaconBlockBody) (*BeaconBlockBody, error) {
|
||||
if pb == nil {
|
||||
return nil, errNilBlockBody
|
||||
@@ -416,6 +612,11 @@ func initBlockBodyFromProtoBellatrix(pb *eth.BeaconBlockBodyBellatrix) (*BeaconB
|
||||
return nil, errNilBlockBody
|
||||
}
|
||||
|
||||
p, err := WrappedExecutionPayload(pb.ExecutionPayload)
|
||||
// We allow the payload to be nil
|
||||
if err != nil && err != ErrNilObjectWrapped {
|
||||
return nil, err
|
||||
}
|
||||
b := &BeaconBlockBody{
|
||||
version: version.Bellatrix,
|
||||
isBlinded: false,
|
||||
@@ -428,7 +629,7 @@ func initBlockBodyFromProtoBellatrix(pb *eth.BeaconBlockBodyBellatrix) (*BeaconB
|
||||
deposits: pb.Deposits,
|
||||
voluntaryExits: pb.VoluntaryExits,
|
||||
syncAggregate: pb.SyncAggregate,
|
||||
executionPayload: pb.ExecutionPayload,
|
||||
executionPayload: p,
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
@@ -438,6 +639,11 @@ func initBlindedBlockBodyFromProtoBellatrix(pb *eth.BlindedBeaconBlockBodyBellat
|
||||
return nil, errNilBlockBody
|
||||
}
|
||||
|
||||
ph, err := WrappedExecutionPayloadHeader(pb.ExecutionPayloadHeader)
|
||||
// We allow the payload to be nil
|
||||
if err != nil && err != ErrNilObjectWrapped {
|
||||
return nil, err
|
||||
}
|
||||
b := &BeaconBlockBody{
|
||||
version: version.Bellatrix,
|
||||
isBlinded: true,
|
||||
@@ -450,7 +656,63 @@ func initBlindedBlockBodyFromProtoBellatrix(pb *eth.BlindedBeaconBlockBodyBellat
|
||||
deposits: pb.Deposits,
|
||||
voluntaryExits: pb.VoluntaryExits,
|
||||
syncAggregate: pb.SyncAggregate,
|
||||
executionPayloadHeader: pb.ExecutionPayloadHeader,
|
||||
executionPayloadHeader: ph,
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func initBlockBodyFromProtoCapella(pb *eth.BeaconBlockBodyCapella) (*BeaconBlockBody, error) {
|
||||
if pb == nil {
|
||||
return nil, errNilBlockBody
|
||||
}
|
||||
|
||||
p, err := WrappedExecutionPayloadCapella(pb.ExecutionPayload)
|
||||
// We allow the payload to be nil
|
||||
if err != nil && err != ErrNilObjectWrapped {
|
||||
return nil, err
|
||||
}
|
||||
b := &BeaconBlockBody{
|
||||
version: version.Capella,
|
||||
isBlinded: false,
|
||||
randaoReveal: bytesutil.ToBytes96(pb.RandaoReveal),
|
||||
eth1Data: pb.Eth1Data,
|
||||
graffiti: bytesutil.ToBytes32(pb.Graffiti),
|
||||
proposerSlashings: pb.ProposerSlashings,
|
||||
attesterSlashings: pb.AttesterSlashings,
|
||||
attestations: pb.Attestations,
|
||||
deposits: pb.Deposits,
|
||||
voluntaryExits: pb.VoluntaryExits,
|
||||
syncAggregate: pb.SyncAggregate,
|
||||
executionPayload: p,
|
||||
blsToExecutionChanges: pb.BlsToExecutionChanges,
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func initBlindedBlockBodyFromProtoCapella(pb *eth.BlindedBeaconBlockBodyCapella) (*BeaconBlockBody, error) {
|
||||
if pb == nil {
|
||||
return nil, errNilBlockBody
|
||||
}
|
||||
|
||||
ph, err := WrappedExecutionPayloadHeaderCapella(pb.ExecutionPayloadHeader)
|
||||
// We allow the payload to be nil
|
||||
if err != nil && err != ErrNilObjectWrapped {
|
||||
return nil, err
|
||||
}
|
||||
b := &BeaconBlockBody{
|
||||
version: version.Capella,
|
||||
isBlinded: true,
|
||||
randaoReveal: bytesutil.ToBytes96(pb.RandaoReveal),
|
||||
eth1Data: pb.Eth1Data,
|
||||
graffiti: bytesutil.ToBytes32(pb.Graffiti),
|
||||
proposerSlashings: pb.ProposerSlashings,
|
||||
attesterSlashings: pb.AttesterSlashings,
|
||||
attestations: pb.Attestations,
|
||||
deposits: pb.Deposits,
|
||||
voluntaryExits: pb.VoluntaryExits,
|
||||
syncAggregate: pb.SyncAggregate,
|
||||
executionPayloadHeader: ph,
|
||||
blsToExecutionChanges: pb.BlsToExecutionChanges,
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
@@ -12,16 +12,19 @@ import (
|
||||
)
|
||||
|
||||
type fields struct {
|
||||
root [32]byte
|
||||
sig [96]byte
|
||||
deposits []*eth.Deposit
|
||||
atts []*eth.Attestation
|
||||
proposerSlashings []*eth.ProposerSlashing
|
||||
attesterSlashings []*eth.AttesterSlashing
|
||||
voluntaryExits []*eth.SignedVoluntaryExit
|
||||
syncAggregate *eth.SyncAggregate
|
||||
execPayload *enginev1.ExecutionPayload
|
||||
execPayloadHeader *enginev1.ExecutionPayloadHeader
|
||||
root [32]byte
|
||||
sig [96]byte
|
||||
deposits []*eth.Deposit
|
||||
atts []*eth.Attestation
|
||||
proposerSlashings []*eth.ProposerSlashing
|
||||
attesterSlashings []*eth.AttesterSlashing
|
||||
voluntaryExits []*eth.SignedVoluntaryExit
|
||||
syncAggregate *eth.SyncAggregate
|
||||
execPayload *enginev1.ExecutionPayload
|
||||
execPayloadHeader *enginev1.ExecutionPayloadHeader
|
||||
execPayloadCapella *enginev1.ExecutionPayloadCapella
|
||||
execPayloadHeaderCapella *enginev1.ExecutionPayloadHeaderCapella
|
||||
blsToExecutionChanges []*eth.SignedBLSToExecutionChange
|
||||
}
|
||||
|
||||
func Test_SignedBeaconBlock_Proto(t *testing.T) {
|
||||
@@ -114,7 +117,7 @@ func Test_SignedBeaconBlock_Proto(t *testing.T) {
|
||||
proposerIndex: 128,
|
||||
parentRoot: f.root,
|
||||
stateRoot: f.root,
|
||||
body: bodyBellatrix(),
|
||||
body: bodyBellatrix(t),
|
||||
},
|
||||
signature: f.sig,
|
||||
}
|
||||
@@ -148,7 +151,7 @@ func Test_SignedBeaconBlock_Proto(t *testing.T) {
|
||||
proposerIndex: 128,
|
||||
parentRoot: f.root,
|
||||
stateRoot: f.root,
|
||||
body: bodyBlindedBellatrix(),
|
||||
body: bodyBlindedBellatrix(t),
|
||||
},
|
||||
signature: f.sig,
|
||||
}
|
||||
@@ -163,6 +166,74 @@ func Test_SignedBeaconBlock_Proto(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
})
|
||||
t.Run("Capella", func(t *testing.T) {
|
||||
expectedBlock := ð.SignedBeaconBlockCapella{
|
||||
Block: ð.BeaconBlockCapella{
|
||||
Slot: 128,
|
||||
ProposerIndex: 128,
|
||||
ParentRoot: f.root[:],
|
||||
StateRoot: f.root[:],
|
||||
Body: bodyPbCapella(),
|
||||
},
|
||||
Signature: f.sig[:],
|
||||
}
|
||||
block := &SignedBeaconBlock{
|
||||
version: version.Capella,
|
||||
block: &BeaconBlock{
|
||||
version: version.Capella,
|
||||
slot: 128,
|
||||
proposerIndex: 128,
|
||||
parentRoot: f.root,
|
||||
stateRoot: f.root,
|
||||
body: bodyCapella(t),
|
||||
},
|
||||
signature: f.sig,
|
||||
}
|
||||
|
||||
result, err := block.Proto()
|
||||
require.NoError(t, err)
|
||||
resultBlock, ok := result.(*eth.SignedBeaconBlockCapella)
|
||||
require.Equal(t, true, ok)
|
||||
resultHTR, err := resultBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
})
|
||||
t.Run("CapellaBlind", func(t *testing.T) {
|
||||
expectedBlock := ð.SignedBlindedBeaconBlockCapella{
|
||||
Block: ð.BlindedBeaconBlockCapella{
|
||||
Slot: 128,
|
||||
ProposerIndex: 128,
|
||||
ParentRoot: f.root[:],
|
||||
StateRoot: f.root[:],
|
||||
Body: bodyPbBlindedCapella(),
|
||||
},
|
||||
Signature: f.sig[:],
|
||||
}
|
||||
block := &SignedBeaconBlock{
|
||||
version: version.Capella,
|
||||
block: &BeaconBlock{
|
||||
version: version.Capella,
|
||||
slot: 128,
|
||||
proposerIndex: 128,
|
||||
parentRoot: f.root,
|
||||
stateRoot: f.root,
|
||||
body: bodyBlindedCapella(t),
|
||||
},
|
||||
signature: f.sig,
|
||||
}
|
||||
|
||||
result, err := block.Proto()
|
||||
require.NoError(t, err)
|
||||
resultBlock, ok := result.(*eth.SignedBlindedBeaconBlockCapella)
|
||||
require.Equal(t, true, ok)
|
||||
resultHTR, err := resultBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_BeaconBlock_Proto(t *testing.T) {
|
||||
@@ -236,7 +307,7 @@ func Test_BeaconBlock_Proto(t *testing.T) {
|
||||
proposerIndex: 128,
|
||||
parentRoot: f.root,
|
||||
stateRoot: f.root,
|
||||
body: bodyBellatrix(),
|
||||
body: bodyBellatrix(t),
|
||||
}
|
||||
|
||||
result, err := block.Proto()
|
||||
@@ -263,7 +334,7 @@ func Test_BeaconBlock_Proto(t *testing.T) {
|
||||
proposerIndex: 128,
|
||||
parentRoot: f.root,
|
||||
stateRoot: f.root,
|
||||
body: bodyBlindedBellatrix(),
|
||||
body: bodyBlindedBellatrix(t),
|
||||
}
|
||||
|
||||
result, err := block.Proto()
|
||||
@@ -276,6 +347,60 @@ func Test_BeaconBlock_Proto(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
})
|
||||
t.Run("Capella", func(t *testing.T) {
|
||||
expectedBlock := ð.BeaconBlockCapella{
|
||||
Slot: 128,
|
||||
ProposerIndex: 128,
|
||||
ParentRoot: f.root[:],
|
||||
StateRoot: f.root[:],
|
||||
Body: bodyPbCapella(),
|
||||
}
|
||||
block := &BeaconBlock{
|
||||
version: version.Capella,
|
||||
slot: 128,
|
||||
proposerIndex: 128,
|
||||
parentRoot: f.root,
|
||||
stateRoot: f.root,
|
||||
body: bodyCapella(t),
|
||||
}
|
||||
|
||||
result, err := block.Proto()
|
||||
require.NoError(t, err)
|
||||
resultBlock, ok := result.(*eth.BeaconBlockCapella)
|
||||
require.Equal(t, true, ok)
|
||||
resultHTR, err := resultBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
})
|
||||
t.Run("CapellaBlind", func(t *testing.T) {
|
||||
expectedBlock := ð.BlindedBeaconBlockCapella{
|
||||
Slot: 128,
|
||||
ProposerIndex: 128,
|
||||
ParentRoot: f.root[:],
|
||||
StateRoot: f.root[:],
|
||||
Body: bodyPbBlindedCapella(),
|
||||
}
|
||||
block := &BeaconBlock{
|
||||
version: version.Capella,
|
||||
slot: 128,
|
||||
proposerIndex: 128,
|
||||
parentRoot: f.root,
|
||||
stateRoot: f.root,
|
||||
body: bodyBlindedCapella(t),
|
||||
}
|
||||
|
||||
result, err := block.Proto()
|
||||
require.NoError(t, err)
|
||||
resultBlock, ok := result.(*eth.BlindedBeaconBlockCapella)
|
||||
require.Equal(t, true, ok)
|
||||
resultHTR, err := resultBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_BeaconBlockBody_Proto(t *testing.T) {
|
||||
@@ -308,7 +433,7 @@ func Test_BeaconBlockBody_Proto(t *testing.T) {
|
||||
})
|
||||
t.Run("Bellatrix", func(t *testing.T) {
|
||||
expectedBody := bodyPbBellatrix()
|
||||
body := bodyBellatrix()
|
||||
body := bodyBellatrix(t)
|
||||
result, err := body.Proto()
|
||||
require.NoError(t, err)
|
||||
resultBlock, ok := result.(*eth.BeaconBlockBodyBellatrix)
|
||||
@@ -321,7 +446,7 @@ func Test_BeaconBlockBody_Proto(t *testing.T) {
|
||||
})
|
||||
t.Run("BellatrixBlind", func(t *testing.T) {
|
||||
expectedBody := bodyPbBlindedBellatrix()
|
||||
body := bodyBlindedBellatrix()
|
||||
body := bodyBlindedBellatrix(t)
|
||||
result, err := body.Proto()
|
||||
require.NoError(t, err)
|
||||
resultBlock, ok := result.(*eth.BlindedBeaconBlockBodyBellatrix)
|
||||
@@ -332,6 +457,56 @@ func Test_BeaconBlockBody_Proto(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
})
|
||||
t.Run("Capella", func(t *testing.T) {
|
||||
expectedBody := bodyPbCapella()
|
||||
body := bodyCapella(t)
|
||||
result, err := body.Proto()
|
||||
require.NoError(t, err)
|
||||
resultBlock, ok := result.(*eth.BeaconBlockBodyCapella)
|
||||
require.Equal(t, true, ok)
|
||||
resultHTR, err := resultBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBody.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
})
|
||||
t.Run("CapellaBlind", func(t *testing.T) {
|
||||
expectedBody := bodyPbBlindedCapella()
|
||||
body := bodyBlindedCapella(t)
|
||||
result, err := body.Proto()
|
||||
require.NoError(t, err)
|
||||
resultBlock, ok := result.(*eth.BlindedBeaconBlockBodyCapella)
|
||||
require.Equal(t, true, ok)
|
||||
resultHTR, err := resultBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBody.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
})
|
||||
t.Run("Bellatrix - wrong payload type", func(t *testing.T) {
|
||||
body := bodyBellatrix(t)
|
||||
body.executionPayload = &executionPayloadHeader{}
|
||||
_, err := body.Proto()
|
||||
require.ErrorIs(t, err, errPayloadWrongType)
|
||||
})
|
||||
t.Run("BellatrixBlind - wrong payload type", func(t *testing.T) {
|
||||
body := bodyBlindedBellatrix(t)
|
||||
body.executionPayloadHeader = &executionPayload{}
|
||||
_, err := body.Proto()
|
||||
require.ErrorIs(t, err, errPayloadHeaderWrongType)
|
||||
})
|
||||
t.Run("Capella - wrong payload type", func(t *testing.T) {
|
||||
body := bodyCapella(t)
|
||||
body.executionPayload = &executionPayloadHeaderCapella{}
|
||||
_, err := body.Proto()
|
||||
require.ErrorIs(t, err, errPayloadWrongType)
|
||||
})
|
||||
t.Run("CapellaBlind - wrong payload type", func(t *testing.T) {
|
||||
body := bodyBlindedCapella(t)
|
||||
body.executionPayloadHeader = &executionPayloadCapella{}
|
||||
_, err := body.Proto()
|
||||
require.ErrorIs(t, err, errPayloadHeaderWrongType)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_initSignedBlockFromProtoPhase0(t *testing.T) {
|
||||
@@ -422,6 +597,50 @@ func Test_initBlindedSignedBlockFromProtoBellatrix(t *testing.T) {
|
||||
assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature[:])
|
||||
}
|
||||
|
||||
func Test_initSignedBlockFromProtoCapella(t *testing.T) {
|
||||
f := getFields()
|
||||
expectedBlock := ð.SignedBeaconBlockCapella{
|
||||
Block: ð.BeaconBlockCapella{
|
||||
Slot: 128,
|
||||
ProposerIndex: 128,
|
||||
ParentRoot: f.root[:],
|
||||
StateRoot: f.root[:],
|
||||
Body: bodyPbCapella(),
|
||||
},
|
||||
Signature: f.sig[:],
|
||||
}
|
||||
resultBlock, err := initSignedBlockFromProtoCapella(expectedBlock)
|
||||
require.NoError(t, err)
|
||||
resultHTR, err := resultBlock.block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature[:])
|
||||
}
|
||||
|
||||
func Test_initBlindedSignedBlockFromProtoCapella(t *testing.T) {
|
||||
f := getFields()
|
||||
expectedBlock := ð.SignedBlindedBeaconBlockCapella{
|
||||
Block: ð.BlindedBeaconBlockCapella{
|
||||
Slot: 128,
|
||||
ProposerIndex: 128,
|
||||
ParentRoot: f.root[:],
|
||||
StateRoot: f.root[:],
|
||||
Body: bodyPbBlindedCapella(),
|
||||
},
|
||||
Signature: f.sig[:],
|
||||
}
|
||||
resultBlock, err := initBlindedSignedBlockFromProtoCapella(expectedBlock)
|
||||
require.NoError(t, err)
|
||||
resultHTR, err := resultBlock.block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
assert.DeepEqual(t, expectedBlock.Signature, resultBlock.signature[:])
|
||||
}
|
||||
|
||||
func Test_initBlockFromProtoPhase0(t *testing.T) {
|
||||
f := getFields()
|
||||
expectedBlock := ð.BeaconBlock{
|
||||
@@ -494,6 +713,42 @@ func Test_initBlockFromProtoBlindedBellatrix(t *testing.T) {
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
}
|
||||
|
||||
func Test_initBlockFromProtoCapella(t *testing.T) {
|
||||
f := getFields()
|
||||
expectedBlock := ð.BeaconBlockCapella{
|
||||
Slot: 128,
|
||||
ProposerIndex: 128,
|
||||
ParentRoot: f.root[:],
|
||||
StateRoot: f.root[:],
|
||||
Body: bodyPbCapella(),
|
||||
}
|
||||
resultBlock, err := initBlockFromProtoCapella(expectedBlock)
|
||||
require.NoError(t, err)
|
||||
resultHTR, err := resultBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
}
|
||||
|
||||
func Test_initBlockFromProtoBlindedCapella(t *testing.T) {
|
||||
f := getFields()
|
||||
expectedBlock := ð.BlindedBeaconBlockCapella{
|
||||
Slot: 128,
|
||||
ProposerIndex: 128,
|
||||
ParentRoot: f.root[:],
|
||||
StateRoot: f.root[:],
|
||||
Body: bodyPbBlindedCapella(),
|
||||
}
|
||||
resultBlock, err := initBlindedBlockFromProtoCapella(expectedBlock)
|
||||
require.NoError(t, err)
|
||||
resultHTR, err := resultBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBlock.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
}
|
||||
|
||||
func Test_initBlockBodyFromProtoPhase0(t *testing.T) {
|
||||
expectedBody := bodyPbPhase0()
|
||||
resultBody, err := initBlockBodyFromProtoPhase0(expectedBody)
|
||||
@@ -538,6 +793,28 @@ func Test_initBlockBodyFromProtoBlindedBellatrix(t *testing.T) {
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
}
|
||||
|
||||
func Test_initBlockBodyFromProtoCapella(t *testing.T) {
|
||||
expectedBody := bodyPbCapella()
|
||||
resultBody, err := initBlockBodyFromProtoCapella(expectedBody)
|
||||
require.NoError(t, err)
|
||||
resultHTR, err := resultBody.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBody.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
}
|
||||
|
||||
func Test_initBlockBodyFromProtoBlindedCapella(t *testing.T) {
|
||||
expectedBody := bodyPbBlindedCapella()
|
||||
resultBody, err := initBlindedBlockBodyFromProtoCapella(expectedBody)
|
||||
require.NoError(t, err)
|
||||
resultHTR, err := resultBody.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
expectedHTR, err := expectedBody.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, expectedHTR, resultHTR)
|
||||
}
|
||||
|
||||
func bodyPbPhase0() *eth.BeaconBlockBody {
|
||||
f := getFields()
|
||||
return ð.BeaconBlockBody{
|
||||
@@ -615,6 +892,48 @@ func bodyPbBlindedBellatrix() *eth.BlindedBeaconBlockBodyBellatrix {
|
||||
}
|
||||
}
|
||||
|
||||
func bodyPbCapella() *eth.BeaconBlockBodyCapella {
|
||||
f := getFields()
|
||||
return ð.BeaconBlockBodyCapella{
|
||||
RandaoReveal: f.sig[:],
|
||||
Eth1Data: ð.Eth1Data{
|
||||
DepositRoot: f.root[:],
|
||||
DepositCount: 128,
|
||||
BlockHash: f.root[:],
|
||||
},
|
||||
Graffiti: f.root[:],
|
||||
ProposerSlashings: f.proposerSlashings,
|
||||
AttesterSlashings: f.attesterSlashings,
|
||||
Attestations: f.atts,
|
||||
Deposits: f.deposits,
|
||||
VoluntaryExits: f.voluntaryExits,
|
||||
SyncAggregate: f.syncAggregate,
|
||||
ExecutionPayload: f.execPayloadCapella,
|
||||
BlsToExecutionChanges: f.blsToExecutionChanges,
|
||||
}
|
||||
}
|
||||
|
||||
func bodyPbBlindedCapella() *eth.BlindedBeaconBlockBodyCapella {
|
||||
f := getFields()
|
||||
return ð.BlindedBeaconBlockBodyCapella{
|
||||
RandaoReveal: f.sig[:],
|
||||
Eth1Data: ð.Eth1Data{
|
||||
DepositRoot: f.root[:],
|
||||
DepositCount: 128,
|
||||
BlockHash: f.root[:],
|
||||
},
|
||||
Graffiti: f.root[:],
|
||||
ProposerSlashings: f.proposerSlashings,
|
||||
AttesterSlashings: f.attesterSlashings,
|
||||
Attestations: f.atts,
|
||||
Deposits: f.deposits,
|
||||
VoluntaryExits: f.voluntaryExits,
|
||||
SyncAggregate: f.syncAggregate,
|
||||
ExecutionPayloadHeader: f.execPayloadHeaderCapella,
|
||||
BlsToExecutionChanges: f.blsToExecutionChanges,
|
||||
}
|
||||
}
|
||||
|
||||
func bodyPhase0() *BeaconBlockBody {
|
||||
f := getFields()
|
||||
return &BeaconBlockBody{
|
||||
@@ -654,8 +973,10 @@ func bodyAltair() *BeaconBlockBody {
|
||||
}
|
||||
}
|
||||
|
||||
func bodyBellatrix() *BeaconBlockBody {
|
||||
func bodyBellatrix(t *testing.T) *BeaconBlockBody {
|
||||
f := getFields()
|
||||
p, err := WrappedExecutionPayload(f.execPayload)
|
||||
require.NoError(t, err)
|
||||
return &BeaconBlockBody{
|
||||
version: version.Bellatrix,
|
||||
randaoReveal: f.sig,
|
||||
@@ -671,12 +992,14 @@ func bodyBellatrix() *BeaconBlockBody {
|
||||
deposits: f.deposits,
|
||||
voluntaryExits: f.voluntaryExits,
|
||||
syncAggregate: f.syncAggregate,
|
||||
executionPayload: f.execPayload,
|
||||
executionPayload: p,
|
||||
}
|
||||
}
|
||||
|
||||
func bodyBlindedBellatrix() *BeaconBlockBody {
|
||||
func bodyBlindedBellatrix(t *testing.T) *BeaconBlockBody {
|
||||
f := getFields()
|
||||
ph, err := WrappedExecutionPayloadHeader(f.execPayloadHeader)
|
||||
require.NoError(t, err)
|
||||
return &BeaconBlockBody{
|
||||
version: version.Bellatrix,
|
||||
isBlinded: true,
|
||||
@@ -693,7 +1016,56 @@ func bodyBlindedBellatrix() *BeaconBlockBody {
|
||||
deposits: f.deposits,
|
||||
voluntaryExits: f.voluntaryExits,
|
||||
syncAggregate: f.syncAggregate,
|
||||
executionPayloadHeader: f.execPayloadHeader,
|
||||
executionPayloadHeader: ph,
|
||||
}
|
||||
}
|
||||
|
||||
func bodyCapella(t *testing.T) *BeaconBlockBody {
|
||||
f := getFields()
|
||||
p, err := WrappedExecutionPayloadCapella(f.execPayloadCapella)
|
||||
require.NoError(t, err)
|
||||
return &BeaconBlockBody{
|
||||
version: version.Capella,
|
||||
randaoReveal: f.sig,
|
||||
eth1Data: ð.Eth1Data{
|
||||
DepositRoot: f.root[:],
|
||||
DepositCount: 128,
|
||||
BlockHash: f.root[:],
|
||||
},
|
||||
graffiti: f.root,
|
||||
proposerSlashings: f.proposerSlashings,
|
||||
attesterSlashings: f.attesterSlashings,
|
||||
attestations: f.atts,
|
||||
deposits: f.deposits,
|
||||
voluntaryExits: f.voluntaryExits,
|
||||
syncAggregate: f.syncAggregate,
|
||||
executionPayload: p,
|
||||
blsToExecutionChanges: f.blsToExecutionChanges,
|
||||
}
|
||||
}
|
||||
|
||||
func bodyBlindedCapella(t *testing.T) *BeaconBlockBody {
|
||||
f := getFields()
|
||||
ph, err := WrappedExecutionPayloadHeaderCapella(f.execPayloadHeaderCapella)
|
||||
require.NoError(t, err)
|
||||
return &BeaconBlockBody{
|
||||
version: version.Capella,
|
||||
isBlinded: true,
|
||||
randaoReveal: f.sig,
|
||||
eth1Data: ð.Eth1Data{
|
||||
DepositRoot: f.root[:],
|
||||
DepositCount: 128,
|
||||
BlockHash: f.root[:],
|
||||
},
|
||||
graffiti: f.root,
|
||||
proposerSlashings: f.proposerSlashings,
|
||||
attesterSlashings: f.attesterSlashings,
|
||||
attestations: f.atts,
|
||||
deposits: f.deposits,
|
||||
voluntaryExits: f.voluntaryExits,
|
||||
syncAggregate: f.syncAggregate,
|
||||
executionPayloadHeader: ph,
|
||||
blsToExecutionChanges: f.blsToExecutionChanges,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,17 +1222,72 @@ func getFields() fields {
|
||||
BlockHash: root[:],
|
||||
TransactionsRoot: root[:],
|
||||
}
|
||||
execPayloadCapella := &enginev1.ExecutionPayloadCapella{
|
||||
ParentHash: root[:],
|
||||
FeeRecipient: b20,
|
||||
StateRoot: root[:],
|
||||
ReceiptsRoot: root[:],
|
||||
LogsBloom: b256,
|
||||
PrevRandao: root[:],
|
||||
BlockNumber: 128,
|
||||
GasLimit: 128,
|
||||
GasUsed: 128,
|
||||
Timestamp: 128,
|
||||
ExtraData: root[:],
|
||||
BaseFeePerGas: root[:],
|
||||
BlockHash: root[:],
|
||||
Transactions: [][]byte{
|
||||
[]byte("transaction1"),
|
||||
[]byte("transaction2"),
|
||||
[]byte("transaction8"),
|
||||
},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
{
|
||||
WithdrawalIndex: 128,
|
||||
ExecutionAddress: b20,
|
||||
Amount: 128,
|
||||
},
|
||||
},
|
||||
}
|
||||
execPayloadHeaderCapella := &enginev1.ExecutionPayloadHeaderCapella{
|
||||
ParentHash: root[:],
|
||||
FeeRecipient: b20,
|
||||
StateRoot: root[:],
|
||||
ReceiptsRoot: root[:],
|
||||
LogsBloom: b256,
|
||||
PrevRandao: root[:],
|
||||
BlockNumber: 128,
|
||||
GasLimit: 128,
|
||||
GasUsed: 128,
|
||||
Timestamp: 128,
|
||||
ExtraData: root[:],
|
||||
BaseFeePerGas: root[:],
|
||||
BlockHash: root[:],
|
||||
TransactionsRoot: root[:],
|
||||
WithdrawalsRoot: root[:],
|
||||
}
|
||||
blsToExecutionChanges := []*eth.SignedBLSToExecutionChange{{
|
||||
Message: ð.BLSToExecutionChange{
|
||||
ValidatorIndex: 128,
|
||||
FromBlsPubkey: b48,
|
||||
ToExecutionAddress: b20,
|
||||
},
|
||||
Signature: sig[:],
|
||||
}}
|
||||
|
||||
return fields{
|
||||
root: root,
|
||||
sig: sig,
|
||||
deposits: deposits,
|
||||
atts: atts,
|
||||
proposerSlashings: []*eth.ProposerSlashing{proposerSlashing},
|
||||
attesterSlashings: []*eth.AttesterSlashing{attesterSlashing},
|
||||
voluntaryExits: []*eth.SignedVoluntaryExit{voluntaryExit},
|
||||
syncAggregate: syncAggregate,
|
||||
execPayload: execPayload,
|
||||
execPayloadHeader: execPayloadHeader,
|
||||
root: root,
|
||||
sig: sig,
|
||||
deposits: deposits,
|
||||
atts: atts,
|
||||
proposerSlashings: []*eth.ProposerSlashing{proposerSlashing},
|
||||
attesterSlashings: []*eth.AttesterSlashing{attesterSlashing},
|
||||
voluntaryExits: []*eth.SignedVoluntaryExit{voluntaryExit},
|
||||
syncAggregate: syncAggregate,
|
||||
execPayload: execPayload,
|
||||
execPayloadHeader: execPayloadHeader,
|
||||
execPayloadCapella: execPayloadCapella,
|
||||
execPayloadHeaderCapella: execPayloadHeaderCapella,
|
||||
blsToExecutionChanges: blsToExecutionChanges,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@ func NewSignedBeaconBlockFromGeneric(gb *eth.GenericSignedBeaconBlock) (interfac
|
||||
return blocks.NewSignedBeaconBlock(bb.Bellatrix)
|
||||
case *eth.GenericSignedBeaconBlock_BlindedBellatrix:
|
||||
return blocks.NewSignedBeaconBlock(bb.BlindedBellatrix)
|
||||
case *eth.GenericSignedBeaconBlock_Capella:
|
||||
return blocks.NewSignedBeaconBlock(bb.Capella)
|
||||
case *eth.GenericSignedBeaconBlock_BlindedCapella:
|
||||
return blocks.NewSignedBeaconBlock(bb.BlindedCapella)
|
||||
default:
|
||||
return nil, errors.Wrapf(blocks.ErrUnsupportedSignedBeaconBlock, "unable to create block from type %T", gb)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ type blockMutator struct {
|
||||
Phase0 func(beaconBlock *eth.SignedBeaconBlock)
|
||||
Altair func(beaconBlock *eth.SignedBeaconBlockAltair)
|
||||
Bellatrix func(beaconBlock *eth.SignedBeaconBlockBellatrix)
|
||||
Capella func(beaconBlock *eth.SignedBeaconBlockCapella)
|
||||
}
|
||||
|
||||
func (m blockMutator) apply(b interfaces.SignedBeaconBlock) (interfaces.SignedBeaconBlock, error) {
|
||||
@@ -37,6 +38,13 @@ func (m blockMutator) apply(b interfaces.SignedBeaconBlock) (interfaces.SignedBe
|
||||
}
|
||||
m.Bellatrix(bb)
|
||||
return blocks.NewSignedBeaconBlock(bb)
|
||||
case version.Capella:
|
||||
bb, err := b.PbCapellaBlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.Capella(bb)
|
||||
return blocks.NewSignedBeaconBlock(bb)
|
||||
default:
|
||||
return nil, blocks.ErrUnsupportedSignedBeaconBlock
|
||||
}
|
||||
@@ -48,6 +56,7 @@ func SetBlockStateRoot(b interfaces.SignedBeaconBlock, sr [32]byte) (interfaces.
|
||||
Phase0: func(bb *eth.SignedBeaconBlock) { bb.Block.StateRoot = sr[:] },
|
||||
Altair: func(bb *eth.SignedBeaconBlockAltair) { bb.Block.StateRoot = sr[:] },
|
||||
Bellatrix: func(bb *eth.SignedBeaconBlockBellatrix) { bb.Block.StateRoot = sr[:] },
|
||||
Capella: func(bb *eth.SignedBeaconBlockCapella) { bb.Block.StateRoot = sr[:] },
|
||||
}.apply(b)
|
||||
}
|
||||
|
||||
@@ -57,6 +66,7 @@ func SetBlockParentRoot(b interfaces.SignedBeaconBlock, pr [32]byte) (interfaces
|
||||
Phase0: func(bb *eth.SignedBeaconBlock) { bb.Block.ParentRoot = pr[:] },
|
||||
Altair: func(bb *eth.SignedBeaconBlockAltair) { bb.Block.ParentRoot = pr[:] },
|
||||
Bellatrix: func(bb *eth.SignedBeaconBlockBellatrix) { bb.Block.ParentRoot = pr[:] },
|
||||
Capella: func(bb *eth.SignedBeaconBlockCapella) { bb.Block.ParentRoot = pr[:] },
|
||||
}.apply(b)
|
||||
}
|
||||
|
||||
@@ -66,6 +76,7 @@ func SetBlockSlot(b interfaces.SignedBeaconBlock, s types.Slot) (interfaces.Sign
|
||||
Phase0: func(bb *eth.SignedBeaconBlock) { bb.Block.Slot = s },
|
||||
Altair: func(bb *eth.SignedBeaconBlockAltair) { bb.Block.Slot = s },
|
||||
Bellatrix: func(bb *eth.SignedBeaconBlockBellatrix) { bb.Block.Slot = s },
|
||||
Capella: func(bb *eth.SignedBeaconBlockCapella) { bb.Block.Slot = s },
|
||||
}.apply(b)
|
||||
}
|
||||
|
||||
@@ -75,5 +86,6 @@ func SetProposerIndex(b interfaces.SignedBeaconBlock, idx types.ValidatorIndex)
|
||||
Phase0: func(bb *eth.SignedBeaconBlock) { bb.Block.ProposerIndex = idx },
|
||||
Altair: func(bb *eth.SignedBeaconBlockAltair) { bb.Block.ProposerIndex = idx },
|
||||
Bellatrix: func(bb *eth.SignedBeaconBlockBellatrix) { bb.Block.ProposerIndex = idx },
|
||||
Capella: func(bb *eth.SignedBeaconBlockCapella) { bb.Block.ProposerIndex = idx },
|
||||
}.apply(b)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
field_params "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
engine "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
)
|
||||
@@ -18,6 +17,11 @@ var (
|
||||
_ = interfaces.BeaconBlockBody(&BeaconBlockBody{})
|
||||
)
|
||||
|
||||
var (
|
||||
errPayloadWrongType = errors.New("execution payload has wrong type")
|
||||
errPayloadHeaderWrongType = errors.New("execution payload header has wrong type")
|
||||
)
|
||||
|
||||
const (
|
||||
incorrectBlockVersion = "incorrect beacon block version"
|
||||
incorrectBodyVersion = "incorrect beacon block body version"
|
||||
@@ -49,8 +53,9 @@ type BeaconBlockBody struct {
|
||||
deposits []*eth.Deposit
|
||||
voluntaryExits []*eth.SignedVoluntaryExit
|
||||
syncAggregate *eth.SyncAggregate
|
||||
executionPayload *engine.ExecutionPayload
|
||||
executionPayloadHeader *engine.ExecutionPayloadHeader
|
||||
executionPayload interfaces.ExecutionData
|
||||
executionPayloadHeader interfaces.ExecutionData
|
||||
blsToExecutionChanges []*eth.SignedBLSToExecutionChange
|
||||
}
|
||||
|
||||
// BeaconBlock is the main beacon block structure. It can represent any block type.
|
||||
|
||||
@@ -24,6 +24,8 @@ type SignedBeaconBlock interface {
|
||||
ToBlinded() (SignedBeaconBlock, error)
|
||||
PbBellatrixBlock() (*ethpb.SignedBeaconBlockBellatrix, error)
|
||||
PbBlindedBellatrixBlock() (*ethpb.SignedBlindedBeaconBlockBellatrix, error)
|
||||
PbCapellaBlock() (*ethpb.SignedBeaconBlockCapella, error)
|
||||
PbBlindedCapellaBlock() (*ethpb.SignedBlindedBeaconBlockCapella, error)
|
||||
ssz.Marshaler
|
||||
ssz.Unmarshaler
|
||||
Version() int
|
||||
@@ -38,6 +40,7 @@ type BeaconBlock interface {
|
||||
ProposerIndex() types.ValidatorIndex
|
||||
ParentRoot() [field_params.RootLength]byte
|
||||
StateRoot() [field_params.RootLength]byte
|
||||
SetStateRoot([]byte)
|
||||
Body() BeaconBlockBody
|
||||
IsNil() bool
|
||||
IsBlinded() bool
|
||||
@@ -66,6 +69,7 @@ type BeaconBlockBody interface {
|
||||
HashTreeRoot() ([field_params.RootLength]byte, error)
|
||||
Proto() (proto.Message, error)
|
||||
Execution() (ExecutionData, error)
|
||||
BLSToExecutionChanges() ([]*ethpb.SignedBLSToExecutionChange, error)
|
||||
}
|
||||
|
||||
// ExecutionData represents execution layer information that is contained
|
||||
@@ -90,5 +94,7 @@ type ExecutionData interface {
|
||||
BaseFeePerGas() []byte
|
||||
BlockHash() []byte
|
||||
Transactions() ([][]byte, error)
|
||||
TransactionsRoot() ([]byte, error)
|
||||
Withdrawals() ([]*enginev1.Withdrawal, error)
|
||||
WithdrawalsRoot() ([]byte, error)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,14 @@ func (SignedBeaconBlock) PbBlindedBellatrixBlock() (*eth.SignedBlindedBeaconBloc
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (SignedBeaconBlock) PbCapellaBlock() (*eth.SignedBeaconBlockCapella, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (SignedBeaconBlock) PbBlindedCapellaBlock() (*eth.SignedBlindedBeaconBlockCapella, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (SignedBeaconBlock) MarshalSSZTo(_ []byte) ([]byte, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
@@ -211,6 +219,10 @@ func (BeaconBlockBody) Execution() (interfaces.ExecutionData, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (BeaconBlockBody) BLSToExecutionChanges() ([]*eth.SignedBLSToExecutionChange, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
var _ interfaces.SignedBeaconBlock = &SignedBeaconBlock{}
|
||||
var _ interfaces.BeaconBlock = &BeaconBlock{}
|
||||
var _ interfaces.BeaconBlockBody = &BeaconBlockBody{}
|
||||
|
||||
@@ -152,8 +152,8 @@ func (pq *PriorityQueue) PopByKey(key string) (*Item, error) {
|
||||
// RetrieveByKey searches the queue for an item with the given key and returns it
|
||||
// from the queue if found. Returns nil if not found.
|
||||
func (pq *PriorityQueue) RetrieveByKey(key string) *Item {
|
||||
pq.lock.Lock()
|
||||
defer pq.lock.Unlock()
|
||||
pq.lock.RLock()
|
||||
defer pq.lock.RUnlock()
|
||||
|
||||
item, ok := pq.dataMap[key]
|
||||
if !ok {
|
||||
|
||||
60
deps.bzl
60
deps.bzl
@@ -183,7 +183,6 @@ def prysm_deps():
|
||||
sum = "h1:BS+UYpbsElC82gB+2E2jiCBg36i8HlubTB/dO/moQ9c=",
|
||||
version = "v1.2.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_aws_aws_sdk_go_v2_config",
|
||||
importpath = "github.com/aws/aws-sdk-go-v2/config",
|
||||
@@ -232,7 +231,6 @@ def prysm_deps():
|
||||
sum = "h1:D6CSsM3gdxaGaqXnPgOBCeL6Mophqzu7KJOu7zW78sU=",
|
||||
version = "v1.1.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_azure_azure_sdk_for_go_sdk_azcore",
|
||||
importpath = "github.com/Azure/azure-sdk-for-go/sdk/azcore",
|
||||
@@ -482,13 +480,13 @@ def prysm_deps():
|
||||
sum = "h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=",
|
||||
version = "v0.3.4",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_cloudflare_cloudflare_go",
|
||||
importpath = "github.com/cloudflare/cloudflare-go",
|
||||
sum = "h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA=",
|
||||
version = "v0.14.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_cncf_udpa_go",
|
||||
importpath = "github.com/cncf/udpa/go",
|
||||
@@ -514,7 +512,6 @@ def prysm_deps():
|
||||
sum = "h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=",
|
||||
version = "v0.0.0-20161010025455-3a0bb77429bd",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_consensys_bavard",
|
||||
importpath = "github.com/consensys/bavard",
|
||||
@@ -581,6 +578,12 @@ def prysm_deps():
|
||||
sum = "h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=",
|
||||
version = "v2.0.2",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_crate_crypto_go_ipa",
|
||||
importpath = "github.com/crate-crypto/go-ipa",
|
||||
sum = "h1:6IrxszG5G+O7zhtkWxq6+unVvnrm1fqV2Pe+T95DUzw=",
|
||||
version = "v0.0.0-20220523130400-f11357ae11c7",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_creack_pty",
|
||||
@@ -703,13 +706,13 @@ def prysm_deps():
|
||||
sum = "h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=",
|
||||
version = "v1.2.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_docker_docker",
|
||||
importpath = "github.com/docker/docker",
|
||||
sum = "h1:HlFGsy+9/xrgMmhmN+NGhCc5SHGJ7I+kHosRR1xc/aI=",
|
||||
version = "v1.6.2",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_docker_go_units",
|
||||
importpath = "github.com/docker/go-units",
|
||||
@@ -823,8 +826,9 @@ def prysm_deps():
|
||||
patches = [
|
||||
"//third_party:com_github_ethereum_go_ethereum_secp256k1.patch",
|
||||
],
|
||||
sum = "h1:5dFrKJDnYf8L6/5o42abCE6a9yJm9cs4EJVRyYMr55s=",
|
||||
version = "v1.10.25",
|
||||
replace = "github.com/nisdas/go-ethereum",
|
||||
sum = "h1:vFw9+/935WbQRNWpyprJ3zFzzpC/Z3ruq6Gbgoio3rs=",
|
||||
version = "v1.9.13-0.20221106065001-55500c94417c",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
@@ -937,6 +941,13 @@ def prysm_deps():
|
||||
sum = "h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=",
|
||||
version = "v0.0.0-20191108122812-4678299bea08",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_gballet_go_verkle",
|
||||
importpath = "github.com/gballet/go-verkle",
|
||||
sum = "h1:AB7YjNrzlVHsYz06zCULVV2zYCEft82P86dSmtwxKL0=",
|
||||
version = "v0.0.0-20220902153445-097bd83b7732",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_gdamore_encoding",
|
||||
importpath = "github.com/gdamore/encoding",
|
||||
@@ -1545,6 +1556,12 @@ def prysm_deps():
|
||||
sum = "h1:wCMygKUQhmcQAjlk2Gquzq6dLmyMv2kF+llRspoRgrk=",
|
||||
version = "v0.0.0-20210917013441-d37c07cfda4e",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_holiman_big",
|
||||
importpath = "github.com/holiman/big",
|
||||
sum = "h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw=",
|
||||
version = "v0.0.0-20221017200358-a027dc42d04e",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_holiman_bloomfilter_v2",
|
||||
@@ -1763,13 +1780,13 @@ def prysm_deps():
|
||||
sum = "h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=",
|
||||
version = "v1.0.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_jedisct1_go_minisign",
|
||||
importpath = "github.com/jedisct1/go-minisign",
|
||||
sum = "h1:UvSe12bq+Uj2hWd8aOlwPmoZ+CITRFrdit+sDGfAg8U=",
|
||||
version = "v0.0.0-20190909160543-45766022959e",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_jellevandenhooff_dkim",
|
||||
importpath = "github.com/jellevandenhooff/dkim",
|
||||
@@ -1789,13 +1806,13 @@ def prysm_deps():
|
||||
sum = "h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=",
|
||||
version = "v0.4.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_jmespath_go_jmespath_internal_testify",
|
||||
importpath = "github.com/jmespath/go-jmespath/internal/testify",
|
||||
sum = "h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=",
|
||||
version = "v1.5.1",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_jonboulle_clockwork",
|
||||
importpath = "github.com/jonboulle/clockwork",
|
||||
@@ -2003,13 +2020,13 @@ def prysm_deps():
|
||||
sum = "h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=",
|
||||
version = "v0.3.0",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_leanovate_gopter",
|
||||
importpath = "github.com/leanovate/gopter",
|
||||
sum = "h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=",
|
||||
version = "v0.2.9",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_leodido_go_urn",
|
||||
importpath = "github.com/leodido/go-urn",
|
||||
@@ -2968,11 +2985,11 @@ def prysm_deps():
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_rivo_uniseg",
|
||||
importpath = "github.com/rivo/uniseg",
|
||||
build_directives = [
|
||||
"gazelle:exclude gen_breaktest.go",
|
||||
"gazelle:exclude gen_properties.go",
|
||||
],
|
||||
importpath = "github.com/rivo/uniseg",
|
||||
sum = "h1:3Z3Eu6FGHZWSfNKJTOUiPatWwfc7DzJRU04jFUqJODw=",
|
||||
version = "v0.3.4",
|
||||
)
|
||||
@@ -3478,8 +3495,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "com_github_urfave_cli_v2",
|
||||
importpath = "github.com/urfave/cli/v2",
|
||||
sum = "h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y=",
|
||||
version = "v2.10.2",
|
||||
sum = "h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q=",
|
||||
version = "v2.17.2-0.20221006022127-8f469abc00aa",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_uudashr_gocognit",
|
||||
@@ -3850,12 +3867,7 @@ def prysm_deps():
|
||||
sum = "h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=",
|
||||
version = "v2.0.0-20160621034901-c1b8fa8bdcce",
|
||||
)
|
||||
go_repository(
|
||||
name = "in_gopkg_olebedev_go_duktape_v3",
|
||||
importpath = "gopkg.in/olebedev/go-duktape.v3",
|
||||
sum = "h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=",
|
||||
version = "v3.0.0-20200619000410-60c24ae608a6",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "in_gopkg_redis_v4",
|
||||
importpath = "gopkg.in/redis.v4",
|
||||
@@ -4163,8 +4175,8 @@ def prysm_deps():
|
||||
go_repository(
|
||||
name = "org_golang_x_sys",
|
||||
importpath = "golang.org/x/sys",
|
||||
sum = "h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=",
|
||||
version = "v0.0.0-20220829200755-d48e67d00261",
|
||||
sum = "h1:OK7RB6t2WQX54srQQYSXMW8dF5C6/8+oA/s5QBmmto4=",
|
||||
version = "v0.0.0-20221013171732-95e765b1cc43",
|
||||
)
|
||||
go_repository(
|
||||
name = "org_golang_x_term",
|
||||
@@ -4259,12 +4271,6 @@ def prysm_deps():
|
||||
sum = "h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=",
|
||||
version = "v1.22.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "tools_gotest",
|
||||
importpath = "gotest.tools",
|
||||
sum = "h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=",
|
||||
version = "v2.2.0+incompatible",
|
||||
)
|
||||
|
||||
# Note: go_repository is already wrapped with maybe!
|
||||
maybe(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user