mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 21:38:05 -05:00
Eip 7549 core (#14037)
* interfaces move * build fix * remove annoying warning * more build fixes * review * core code * tests part 1 * tests part 2 * TranslateParticipation doesn't need Electra * remove unused function * pending atts don't need Electra * tests part 3 * build fixes * review * remove newline * review * fix test
This commit is contained in:
@@ -80,11 +80,11 @@ func (s *Service) OnAttestation(ctx context.Context, a ethpb.Att, disparity time
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use the target state to verify attesting indices are valid.
|
// Use the target state to verify attesting indices are valid.
|
||||||
committee, err := helpers.BeaconCommitteeFromState(ctx, baseState, a.GetData().Slot, a.GetData().CommitteeIndex)
|
committees, err := helpers.AttestationCommittees(ctx, baseState, a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
indexedAtt, err := attestation.ConvertToIndexed(ctx, a, committee)
|
indexedAtt, err := attestation.ConvertToIndexed(ctx, a, committees...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||||
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
|
||||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||||
@@ -125,25 +127,36 @@ func TestStore_OnAttestation_ErrorConditions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestStore_OnAttestation_Ok_DoublyLinkedTree(t *testing.T) {
|
func TestStore_OnAttestation_Ok_DoublyLinkedTree(t *testing.T) {
|
||||||
service, tr := minimalTestService(t)
|
eval := func(ctx context.Context, service *Service, genesisState state.BeaconState, pks []bls.SecretKey) {
|
||||||
ctx := tr.ctx
|
service.SetGenesisTime(time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0))
|
||||||
|
require.NoError(t, service.saveGenesisData(ctx, genesisState))
|
||||||
|
att, err := util.GenerateAttestations(genesisState, pks, 1, 0, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
tRoot := bytesutil.ToBytes32(att[0].GetData().Target.Root)
|
||||||
|
copied := genesisState.Copy()
|
||||||
|
copied, err = transition.ProcessSlots(ctx, copied, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, copied, tRoot))
|
||||||
|
ojc := ðpb.Checkpoint{Epoch: 0, Root: tRoot[:]}
|
||||||
|
ofc := ðpb.Checkpoint{Epoch: 0, Root: tRoot[:]}
|
||||||
|
state, blkRoot, err := prepareForkchoiceState(ctx, 0, tRoot, tRoot, params.BeaconConfig().ZeroHash, ojc, ofc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
|
||||||
|
require.NoError(t, service.OnAttestation(ctx, att[0], 0))
|
||||||
|
}
|
||||||
|
|
||||||
genesisState, pks := util.DeterministicGenesisState(t, 64)
|
t.Run("pre-Electra", func(t *testing.T) {
|
||||||
service.SetGenesisTime(time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0))
|
service, tr := minimalTestService(t)
|
||||||
require.NoError(t, service.saveGenesisData(ctx, genesisState))
|
ctx := tr.ctx
|
||||||
att, err := util.GenerateAttestations(genesisState, pks, 1, 0, false)
|
genesisState, pks := util.DeterministicGenesisState(t, 64)
|
||||||
require.NoError(t, err)
|
eval(ctx, service, genesisState, pks)
|
||||||
tRoot := bytesutil.ToBytes32(att[0].Data.Target.Root)
|
})
|
||||||
copied := genesisState.Copy()
|
t.Run("post-Electra", func(t *testing.T) {
|
||||||
copied, err = transition.ProcessSlots(ctx, copied, 1)
|
service, tr := minimalTestService(t)
|
||||||
require.NoError(t, err)
|
ctx := tr.ctx
|
||||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, copied, tRoot))
|
genesisState, pks := util.DeterministicGenesisStateElectra(t, 64)
|
||||||
ojc := ðpb.Checkpoint{Epoch: 0, Root: tRoot[:]}
|
eval(ctx, service, genesisState, pks)
|
||||||
ofc := ðpb.Checkpoint{Epoch: 0, Root: tRoot[:]}
|
})
|
||||||
state, blkRoot, err := prepareForkchoiceState(ctx, 0, tRoot, tRoot, params.BeaconConfig().ZeroHash, ojc, ofc)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NoError(t, service.cfg.ForkChoiceStore.InsertNode(ctx, state, blkRoot))
|
|
||||||
require.NoError(t, service.OnAttestation(ctx, att[0], 0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestService_GetRecentPreState(t *testing.T) {
|
func TestService_GetRecentPreState(t *testing.T) {
|
||||||
|
|||||||
@@ -366,11 +366,11 @@ func (s *Service) handleEpochBoundary(ctx context.Context, slot primitives.Slot,
|
|||||||
func (s *Service) handleBlockAttestations(ctx context.Context, blk interfaces.ReadOnlyBeaconBlock, st state.BeaconState) error {
|
func (s *Service) handleBlockAttestations(ctx context.Context, blk interfaces.ReadOnlyBeaconBlock, st state.BeaconState) error {
|
||||||
// Feed in block's attestations to fork choice store.
|
// Feed in block's attestations to fork choice store.
|
||||||
for _, a := range blk.Body().Attestations() {
|
for _, a := range blk.Body().Attestations() {
|
||||||
committee, err := helpers.BeaconCommitteeFromState(ctx, st, a.GetData().Slot, a.GetData().CommitteeIndex)
|
committees, err := helpers.AttestationCommittees(ctx, st, a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
indices, err := attestation.AttestingIndices(a, committee)
|
indices, err := attestation.AttestingIndices(a, committees...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1963,68 +1963,130 @@ func TestNoViableHead_Reboot(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOnBlock_HandleBlockAttestations(t *testing.T) {
|
func TestOnBlock_HandleBlockAttestations(t *testing.T) {
|
||||||
service, tr := minimalTestService(t)
|
t.Run("pre-Electra", func(t *testing.T) {
|
||||||
ctx := tr.ctx
|
service, tr := minimalTestService(t)
|
||||||
|
ctx := tr.ctx
|
||||||
|
|
||||||
st, keys := util.DeterministicGenesisState(t, 64)
|
st, keys := util.DeterministicGenesisState(t, 64)
|
||||||
stateRoot, err := st.HashTreeRoot(ctx)
|
stateRoot, err := st.HashTreeRoot(ctx)
|
||||||
require.NoError(t, err, "Could not hash genesis state")
|
require.NoError(t, err, "Could not hash genesis state")
|
||||||
|
|
||||||
require.NoError(t, service.saveGenesisData(ctx, st))
|
require.NoError(t, service.saveGenesisData(ctx, st))
|
||||||
|
|
||||||
genesis := blocks.NewGenesisBlock(stateRoot[:])
|
genesis := blocks.NewGenesisBlock(stateRoot[:])
|
||||||
wsb, err := consensusblocks.NewSignedBeaconBlock(genesis)
|
wsb, err := consensusblocks.NewSignedBeaconBlock(genesis)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb), "Could not save genesis block")
|
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb), "Could not save genesis block")
|
||||||
parentRoot, err := genesis.Block.HashTreeRoot()
|
parentRoot, err := genesis.Block.HashTreeRoot()
|
||||||
require.NoError(t, err, "Could not get signing root")
|
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.SaveState(ctx, st, parentRoot), "Could not save genesis state")
|
||||||
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
|
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
|
||||||
|
|
||||||
st, err = service.HeadState(ctx)
|
st, err = service.HeadState(ctx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
b, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 1)
|
b, err := util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
root, err := b.Block.HashTreeRoot()
|
root, err := b.Block.HashTreeRoot()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
preState, err := service.getBlockPreState(ctx, wsb.Block())
|
preState, err := service.getBlockPreState(ctx, wsb.Block())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
postState, err := service.validateStateTransition(ctx, preState, wsb)
|
postState, err := service.validateStateTransition(ctx, preState, wsb)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, service.savePostStateInfo(ctx, root, wsb, postState))
|
require.NoError(t, service.savePostStateInfo(ctx, root, wsb, postState))
|
||||||
require.NoError(t, service.postBlockProcess(&postBlockProcessConfig{ctx, wsb, root, [32]byte{}, postState, false}))
|
require.NoError(t, service.postBlockProcess(&postBlockProcessConfig{ctx, wsb, root, [32]byte{}, postState, false}))
|
||||||
|
|
||||||
st, err = service.HeadState(ctx)
|
st, err = service.HeadState(ctx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
b, err = util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 2)
|
b, err = util.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// prepare another block that is not inserted
|
// prepare another block that is not inserted
|
||||||
st3, err := transition.ExecuteStateTransition(ctx, st, wsb)
|
st3, err := transition.ExecuteStateTransition(ctx, st, wsb)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
b3, err := util.GenerateFullBlock(st3, keys, util.DefaultBlockGenConfig(), 3)
|
b3, err := util.GenerateFullBlock(st3, keys, util.DefaultBlockGenConfig(), 3)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
wsb3, err := consensusblocks.NewSignedBeaconBlock(b3)
|
wsb3, err := consensusblocks.NewSignedBeaconBlock(b3)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, 1, len(wsb.Block().Body().Attestations()))
|
require.Equal(t, 1, len(wsb.Block().Body().Attestations()))
|
||||||
a := wsb.Block().Body().Attestations()[0]
|
a := wsb.Block().Body().Attestations()[0]
|
||||||
r := bytesutil.ToBytes32(a.GetData().BeaconBlockRoot)
|
r := bytesutil.ToBytes32(a.GetData().BeaconBlockRoot)
|
||||||
require.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(r))
|
require.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(r))
|
||||||
|
|
||||||
require.Equal(t, 1, len(wsb.Block().Body().Attestations()))
|
require.Equal(t, 1, len(wsb.Block().Body().Attestations()))
|
||||||
a3 := wsb3.Block().Body().Attestations()[0]
|
a3 := wsb3.Block().Body().Attestations()[0]
|
||||||
r3 := bytesutil.ToBytes32(a3.GetData().BeaconBlockRoot)
|
r3 := bytesutil.ToBytes32(a3.GetData().BeaconBlockRoot)
|
||||||
require.Equal(t, false, service.cfg.ForkChoiceStore.HasNode(r3))
|
require.Equal(t, false, service.cfg.ForkChoiceStore.HasNode(r3))
|
||||||
|
|
||||||
require.NoError(t, service.handleBlockAttestations(ctx, wsb.Block(), st)) // fine to use the same committee as st
|
require.NoError(t, service.handleBlockAttestations(ctx, wsb.Block(), st)) // fine to use the same committee as st
|
||||||
require.Equal(t, 0, service.cfg.AttPool.ForkchoiceAttestationCount())
|
require.Equal(t, 0, service.cfg.AttPool.ForkchoiceAttestationCount())
|
||||||
require.NoError(t, service.handleBlockAttestations(ctx, wsb3.Block(), st3)) // fine to use the same committee as st
|
require.NoError(t, service.handleBlockAttestations(ctx, wsb3.Block(), st3)) // fine to use the same committee as st
|
||||||
require.Equal(t, 1, len(service.cfg.AttPool.BlockAttestations()))
|
require.Equal(t, 1, len(service.cfg.AttPool.BlockAttestations()))
|
||||||
|
})
|
||||||
|
t.Run("post-Electra", func(t *testing.T) {
|
||||||
|
service, tr := minimalTestService(t)
|
||||||
|
ctx := tr.ctx
|
||||||
|
|
||||||
|
st, keys := util.DeterministicGenesisStateElectra(t, 64)
|
||||||
|
require.NoError(t, service.saveGenesisData(ctx, st))
|
||||||
|
|
||||||
|
genesis, err := blocks.NewGenesisBlockForState(ctx, st)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, genesis), "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")
|
||||||
|
|
||||||
|
st, err = service.HeadState(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
b, err := util.GenerateFullBlockElectra(st, keys, util.DefaultBlockGenConfig(), 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
wsb, err := consensusblocks.NewSignedBeaconBlock(b)
|
||||||
|
require.NoError(t, err)
|
||||||
|
root, err := b.Block.HashTreeRoot()
|
||||||
|
require.NoError(t, err)
|
||||||
|
preState, err := service.getBlockPreState(ctx, wsb.Block())
|
||||||
|
require.NoError(t, err)
|
||||||
|
postState, err := service.validateStateTransition(ctx, preState, wsb)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, service.savePostStateInfo(ctx, root, wsb, postState))
|
||||||
|
require.NoError(t, service.postBlockProcess(&postBlockProcessConfig{ctx, wsb, root, [32]byte{}, postState, false}))
|
||||||
|
|
||||||
|
st, err = service.HeadState(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
b, err = util.GenerateFullBlockElectra(st, keys, util.DefaultBlockGenConfig(), 2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// prepare another block that is not inserted
|
||||||
|
st3, err := transition.ExecuteStateTransition(ctx, st, wsb)
|
||||||
|
require.NoError(t, err)
|
||||||
|
b3, err := util.GenerateFullBlockElectra(st3, keys, util.DefaultBlockGenConfig(), 3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
wsb3, err := consensusblocks.NewSignedBeaconBlock(b3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, 1, len(wsb.Block().Body().Attestations()))
|
||||||
|
a := wsb.Block().Body().Attestations()[0]
|
||||||
|
r := bytesutil.ToBytes32(a.GetData().BeaconBlockRoot)
|
||||||
|
require.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(r))
|
||||||
|
|
||||||
|
require.Equal(t, 1, len(wsb.Block().Body().Attestations()))
|
||||||
|
a3 := wsb3.Block().Body().Attestations()[0]
|
||||||
|
r3 := bytesutil.ToBytes32(a3.GetData().BeaconBlockRoot)
|
||||||
|
require.Equal(t, false, service.cfg.ForkChoiceStore.HasNode(r3))
|
||||||
|
|
||||||
|
require.NoError(t, service.handleBlockAttestations(ctx, wsb.Block(), st)) // fine to use the same committee as st
|
||||||
|
require.Equal(t, 0, service.cfg.AttPool.ForkchoiceAttestationCount())
|
||||||
|
require.NoError(t, service.handleBlockAttestations(ctx, wsb3.Block(), st3)) // fine to use the same committee as st
|
||||||
|
require.Equal(t, 1, len(service.cfg.AttPool.BlockAttestations()))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFillMissingBlockPayloadId_DiffSlotExitEarly(t *testing.T) {
|
func TestFillMissingBlockPayloadId_DiffSlotExitEarly(t *testing.T) {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func TestProcessAttestations_Ok(t *testing.T) {
|
|||||||
require.NoError(t, service.saveGenesisData(ctx, genesisState))
|
require.NoError(t, service.saveGenesisData(ctx, genesisState))
|
||||||
atts, err := util.GenerateAttestations(genesisState, pks, 1, 0, false)
|
atts, err := util.GenerateAttestations(genesisState, pks, 1, 0, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
tRoot := bytesutil.ToBytes32(atts[0].Data.Target.Root)
|
tRoot := bytesutil.ToBytes32(atts[0].GetData().Target.Root)
|
||||||
copied := genesisState.Copy()
|
copied := genesisState.Copy()
|
||||||
copied, err = transition.ProcessSlots(ctx, copied, 1)
|
copied, err = transition.ProcessSlots(ctx, copied, 1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -131,8 +131,8 @@ func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) {
|
|||||||
}
|
}
|
||||||
require.NoError(t, service.cfg.AttPool.SaveForkchoiceAttestations(attsToSave))
|
require.NoError(t, service.cfg.AttPool.SaveForkchoiceAttestations(attsToSave))
|
||||||
// Verify the target is in forkchoice
|
// Verify the target is in forkchoice
|
||||||
require.Equal(t, true, fcs.HasNode(bytesutil.ToBytes32(atts[0].Data.BeaconBlockRoot)))
|
require.Equal(t, true, fcs.HasNode(bytesutil.ToBytes32(atts[0].GetData().BeaconBlockRoot)))
|
||||||
require.Equal(t, tRoot, bytesutil.ToBytes32(atts[0].Data.BeaconBlockRoot))
|
require.Equal(t, tRoot, bytesutil.ToBytes32(atts[0].GetData().BeaconBlockRoot))
|
||||||
require.Equal(t, true, fcs.HasNode(service.originBlockRoot))
|
require.Equal(t, true, fcs.HasNode(service.originBlockRoot))
|
||||||
|
|
||||||
// Insert a new block to forkchoice
|
// Insert a new block to forkchoice
|
||||||
|
|||||||
@@ -479,12 +479,12 @@ func (s *Service) sendBlockAttestationsToSlasher(signed interfaces.ReadOnlySigne
|
|||||||
// is done in the background to avoid adding more load to this critical code path.
|
// is done in the background to avoid adding more load to this critical code path.
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
for _, att := range signed.Block().Body().Attestations() {
|
for _, att := range signed.Block().Body().Attestations() {
|
||||||
committee, err := helpers.BeaconCommitteeFromState(ctx, preState, att.GetData().Slot, att.GetData().CommitteeIndex)
|
committees, err := helpers.AttestationCommittees(ctx, preState, att)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("Could not get attestation committee")
|
log.WithError(err).Error("Could not get attestation committees")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
indexedAtt, err := attestation.ConvertToIndexed(ctx, att, committee)
|
indexedAtt, err := attestation.ConvertToIndexed(ctx, att, committees...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).Error("Could not convert to indexed attestation")
|
log.WithError(err).Error("Could not convert to indexed attestation")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db"
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db"
|
||||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filesystem"
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filesystem"
|
||||||
testDB "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
testDB "github.com/prysmaticlabs/prysm/v5/beacon-chain/db/testing"
|
||||||
|
mockExecution "github.com/prysmaticlabs/prysm/v5/beacon-chain/execution/testing"
|
||||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice"
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice"
|
||||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
|
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
|
||||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/operations/attestations"
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/operations/attestations"
|
||||||
@@ -120,6 +121,7 @@ func minimalTestService(t *testing.T, opts ...Option) (*Service, *testServiceReq
|
|||||||
WithTrackedValidatorsCache(cache.NewTrackedValidatorsCache()),
|
WithTrackedValidatorsCache(cache.NewTrackedValidatorsCache()),
|
||||||
WithBlobStorage(filesystem.NewEphemeralBlobStorage(t)),
|
WithBlobStorage(filesystem.NewEphemeralBlobStorage(t)),
|
||||||
WithSyncChecker(mock.MockChecker{}),
|
WithSyncChecker(mock.MockChecker{}),
|
||||||
|
WithExecutionEngineCaller(&mockExecution.EngineClient{}),
|
||||||
}
|
}
|
||||||
// append the variadic opts so they override the defaults by being processed afterwards
|
// append the variadic opts so they override the defaults by being processed afterwards
|
||||||
opts = append(defOpts, opts...)
|
opts = append(defOpts, opts...)
|
||||||
|
|||||||
@@ -66,11 +66,11 @@ func ProcessAttestationNoVerifySignature(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
committee, err := helpers.BeaconCommitteeFromState(ctx, beaconState, att.GetData().Slot, att.GetData().CommitteeIndex)
|
committees, err := helpers.AttestationCommittees(ctx, beaconState, att)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
indices, err := attestation.AttestingIndices(att, committee)
|
indices, err := attestation.AttestingIndices(att, committees...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,47 +195,95 @@ func TestProcessAttestations_InvalidAggregationBitsLength(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessAttestations_OK(t *testing.T) {
|
func TestProcessAttestations_OK(t *testing.T) {
|
||||||
beaconState, privKeys := util.DeterministicGenesisStateAltair(t, 100)
|
t.Run("pre-Electra", func(t *testing.T) {
|
||||||
|
beaconState, privKeys := util.DeterministicGenesisStateAltair(t, 100)
|
||||||
|
|
||||||
aggBits := bitfield.NewBitlist(3)
|
aggBits := bitfield.NewBitlist(3)
|
||||||
aggBits.SetBitAt(0, true)
|
aggBits.SetBitAt(0, true)
|
||||||
var mockRoot [32]byte
|
var mockRoot [32]byte
|
||||||
copy(mockRoot[:], "hello-world")
|
copy(mockRoot[:], "hello-world")
|
||||||
att := util.HydrateAttestation(ðpb.Attestation{
|
att := util.HydrateAttestation(ðpb.Attestation{
|
||||||
Data: ðpb.AttestationData{
|
Data: ðpb.AttestationData{
|
||||||
Source: ðpb.Checkpoint{Root: mockRoot[:]},
|
Source: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||||
Target: ðpb.Checkpoint{Root: mockRoot[:]},
|
Target: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||||
},
|
},
|
||||||
AggregationBits: aggBits,
|
AggregationBits: aggBits,
|
||||||
|
})
|
||||||
|
|
||||||
|
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||||
|
cfc.Root = mockRoot[:]
|
||||||
|
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||||
|
|
||||||
|
committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att.Data.Slot, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
attestingIndices, err := attestation.AttestingIndices(att, committee)
|
||||||
|
require.NoError(t, err)
|
||||||
|
sigs := make([]bls.Signature, len(attestingIndices))
|
||||||
|
for i, indice := range attestingIndices {
|
||||||
|
sb, err := signing.ComputeDomainAndSign(beaconState, 0, att.Data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice])
|
||||||
|
require.NoError(t, err)
|
||||||
|
sig, err := bls.SignatureFromBytes(sb)
|
||||||
|
require.NoError(t, err)
|
||||||
|
sigs[i] = sig
|
||||||
|
}
|
||||||
|
att.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||||
|
|
||||||
|
block := util.NewBeaconBlockAltair()
|
||||||
|
block.Block.Body.Attestations = []*ethpb.Attestation{att}
|
||||||
|
|
||||||
|
err = beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||||
|
require.NoError(t, err)
|
||||||
|
wsb, err := blocks.NewSignedBeaconBlock(block)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb.Block())
|
||||||
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
t.Run("post-Electra", func(t *testing.T) {
|
||||||
|
beaconState, privKeys := util.DeterministicGenesisStateElectra(t, 100)
|
||||||
|
|
||||||
cfc := beaconState.CurrentJustifiedCheckpoint()
|
aggBits := bitfield.NewBitlist(3)
|
||||||
cfc.Root = mockRoot[:]
|
aggBits.SetBitAt(0, true)
|
||||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
committeeBits := primitives.NewAttestationCommitteeBits()
|
||||||
|
committeeBits.SetBitAt(0, true)
|
||||||
|
var mockRoot [32]byte
|
||||||
|
copy(mockRoot[:], "hello-world")
|
||||||
|
att := util.HydrateAttestationElectra(ðpb.AttestationElectra{
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Source: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||||
|
Target: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||||
|
},
|
||||||
|
AggregationBits: aggBits,
|
||||||
|
CommitteeBits: committeeBits,
|
||||||
|
})
|
||||||
|
|
||||||
committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att.Data.Slot, att.Data.CommitteeIndex)
|
cfc := beaconState.CurrentJustifiedCheckpoint()
|
||||||
require.NoError(t, err)
|
cfc.Root = mockRoot[:]
|
||||||
attestingIndices, err := attestation.AttestingIndices(att, committee)
|
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||||
require.NoError(t, err)
|
|
||||||
sigs := make([]bls.Signature, len(attestingIndices))
|
committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att.Data.Slot, 0)
|
||||||
for i, indice := range attestingIndices {
|
|
||||||
sb, err := signing.ComputeDomainAndSign(beaconState, 0, att.Data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice])
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sig, err := bls.SignatureFromBytes(sb)
|
attestingIndices, err := attestation.AttestingIndices(att, committee)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sigs[i] = sig
|
sigs := make([]bls.Signature, len(attestingIndices))
|
||||||
}
|
for i, indice := range attestingIndices {
|
||||||
att.Signature = bls.AggregateSignatures(sigs).Marshal()
|
sb, err := signing.ComputeDomainAndSign(beaconState, 0, att.Data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice])
|
||||||
|
require.NoError(t, err)
|
||||||
|
sig, err := bls.SignatureFromBytes(sb)
|
||||||
|
require.NoError(t, err)
|
||||||
|
sigs[i] = sig
|
||||||
|
}
|
||||||
|
att.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||||
|
|
||||||
block := util.NewBeaconBlockAltair()
|
block := util.NewBeaconBlockElectra()
|
||||||
block.Block.Body.Attestations = []*ethpb.Attestation{att}
|
block.Block.Body.Attestations = []*ethpb.AttestationElectra{att}
|
||||||
|
|
||||||
err = beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
err = beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
wsb, err := blocks.NewSignedBeaconBlock(block)
|
wsb, err := blocks.NewSignedBeaconBlock(block)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb.Block())
|
_, err = altair.ProcessAttestationsNoVerifySignature(context.Background(), beaconState, wsb.Block())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessAttestationNoVerify_SourceTargetHead(t *testing.T) {
|
func TestProcessAttestationNoVerify_SourceTargetHead(t *testing.T) {
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ func TranslateParticipation(ctx context.Context, state state.BeaconState, atts [
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
committee, err := helpers.BeaconCommitteeFromState(ctx, state, att.Data.Slot, att.Data.CommitteeIndex)
|
committee, err := helpers.BeaconCommitteeFromState(ctx, state, att.GetData().Slot, att.GetData().CommitteeIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,23 +200,6 @@ func ProcessAttestationNoVerifySignature(
|
|||||||
return beaconState, nil
|
return beaconState, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyAttestationSignature converts and attestation into an indexed attestation and verifies
|
|
||||||
// the signature in that attestation.
|
|
||||||
func VerifyAttestationSignature(ctx context.Context, beaconState state.ReadOnlyBeaconState, att ethpb.Att) error {
|
|
||||||
if err := helpers.ValidateNilAttestation(att); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
committee, err := helpers.BeaconCommitteeFromState(ctx, beaconState, att.GetData().Slot, att.GetData().CommitteeIndex)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
indexedAtt, err := attestation.ConvertToIndexed(ctx, att, committee)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return VerifyIndexedAttestation(ctx, beaconState, indexedAtt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyIndexedAttestation determines the validity of an indexed attestation.
|
// VerifyIndexedAttestation determines the validity of an indexed attestation.
|
||||||
//
|
//
|
||||||
// Spec pseudocode definition:
|
// Spec pseudocode definition:
|
||||||
|
|||||||
@@ -578,53 +578,109 @@ func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
st, err := util.NewBeaconState()
|
t.Run("pre-Electra", func(t *testing.T) {
|
||||||
require.NoError(t, err)
|
st, err := util.NewBeaconState()
|
||||||
require.NoError(t, st.SetSlot(5))
|
require.NoError(t, err)
|
||||||
require.NoError(t, st.SetValidators(validators))
|
require.NoError(t, st.SetSlot(5))
|
||||||
|
require.NoError(t, st.SetValidators(validators))
|
||||||
|
|
||||||
comm1, err := helpers.BeaconCommitteeFromState(context.Background(), st, 1 /*slot*/, 0 /*committeeIndex*/)
|
comm1, err := helpers.BeaconCommitteeFromState(context.Background(), st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
att1 := util.HydrateAttestation(ðpb.Attestation{
|
att1 := util.HydrateAttestation(ðpb.Attestation{
|
||||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
||||||
Data: ðpb.AttestationData{
|
Data: ðpb.AttestationData{
|
||||||
Slot: 1,
|
Slot: 1,
|
||||||
},
|
},
|
||||||
|
})
|
||||||
|
domain, err := signing.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorsRoot())
|
||||||
|
require.NoError(t, err)
|
||||||
|
root, err := signing.ComputeSigningRoot(att1.Data, domain)
|
||||||
|
require.NoError(t, err)
|
||||||
|
var sigs []bls.Signature
|
||||||
|
for i, u := range comm1 {
|
||||||
|
att1.AggregationBits.SetBitAt(uint64(i), true)
|
||||||
|
sigs = append(sigs, keys[u].Sign(root[:]))
|
||||||
|
}
|
||||||
|
att1.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||||
|
|
||||||
|
comm2, err := helpers.BeaconCommitteeFromState(context.Background(), st, 1 /*slot*/, 1 /*committeeIndex*/)
|
||||||
|
require.NoError(t, err)
|
||||||
|
att2 := util.HydrateAttestation(ðpb.Attestation{
|
||||||
|
AggregationBits: bitfield.NewBitlist(uint64(len(comm2))),
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: 1,
|
||||||
|
CommitteeIndex: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
root, err = signing.ComputeSigningRoot(att2.Data, domain)
|
||||||
|
require.NoError(t, err)
|
||||||
|
sigs = nil
|
||||||
|
for i, u := range comm2 {
|
||||||
|
att2.AggregationBits.SetBitAt(uint64(i), true)
|
||||||
|
sigs = append(sigs, keys[u].Sign(root[:]))
|
||||||
|
}
|
||||||
|
att2.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||||
|
|
||||||
|
set, err := blocks.AttestationSignatureBatch(ctx, st, []ethpb.Att{att1, att2})
|
||||||
|
require.NoError(t, err)
|
||||||
|
verified, err := set.Verify()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, true, verified, "Multiple signatures were unable to be verified.")
|
||||||
})
|
})
|
||||||
domain, err := signing.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorsRoot())
|
t.Run("post-Electra", func(t *testing.T) {
|
||||||
require.NoError(t, err)
|
st, err := util.NewBeaconStateElectra()
|
||||||
root, err := signing.ComputeSigningRoot(att1.Data, domain)
|
require.NoError(t, err)
|
||||||
require.NoError(t, err)
|
require.NoError(t, st.SetSlot(5))
|
||||||
var sigs []bls.Signature
|
require.NoError(t, st.SetValidators(validators))
|
||||||
for i, u := range comm1 {
|
|
||||||
att1.AggregationBits.SetBitAt(uint64(i), true)
|
|
||||||
sigs = append(sigs, keys[u].Sign(root[:]))
|
|
||||||
}
|
|
||||||
att1.Signature = bls.AggregateSignatures(sigs).Marshal()
|
|
||||||
|
|
||||||
comm2, err := helpers.BeaconCommitteeFromState(context.Background(), st, 1 /*slot*/, 1 /*committeeIndex*/)
|
comm1, err := helpers.BeaconCommitteeFromState(context.Background(), st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
att2 := util.HydrateAttestation(ðpb.Attestation{
|
commBits1 := primitives.NewAttestationCommitteeBits()
|
||||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm2))),
|
commBits1.SetBitAt(0, true)
|
||||||
Data: ðpb.AttestationData{
|
att1 := util.HydrateAttestationElectra(ðpb.AttestationElectra{
|
||||||
Slot: 1,
|
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
||||||
CommitteeIndex: 1,
|
CommitteeBits: commBits1,
|
||||||
},
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
domain, err := signing.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorsRoot())
|
||||||
|
require.NoError(t, err)
|
||||||
|
root, err := signing.ComputeSigningRoot(att1.Data, domain)
|
||||||
|
require.NoError(t, err)
|
||||||
|
var sigs []bls.Signature
|
||||||
|
for i, u := range comm1 {
|
||||||
|
att1.AggregationBits.SetBitAt(uint64(i), true)
|
||||||
|
sigs = append(sigs, keys[u].Sign(root[:]))
|
||||||
|
}
|
||||||
|
att1.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||||
|
|
||||||
|
comm2, err := helpers.BeaconCommitteeFromState(context.Background(), st, 1 /*slot*/, 1 /*committeeIndex*/)
|
||||||
|
require.NoError(t, err)
|
||||||
|
commBits2 := primitives.NewAttestationCommitteeBits()
|
||||||
|
commBits2.SetBitAt(1, true)
|
||||||
|
att2 := util.HydrateAttestationElectra(ðpb.AttestationElectra{
|
||||||
|
AggregationBits: bitfield.NewBitlist(uint64(len(comm2))),
|
||||||
|
CommitteeBits: commBits2,
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
root, err = signing.ComputeSigningRoot(att2.Data, domain)
|
||||||
|
require.NoError(t, err)
|
||||||
|
sigs = nil
|
||||||
|
for i, u := range comm2 {
|
||||||
|
att2.AggregationBits.SetBitAt(uint64(i), true)
|
||||||
|
sigs = append(sigs, keys[u].Sign(root[:]))
|
||||||
|
}
|
||||||
|
att2.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||||
|
|
||||||
|
set, err := blocks.AttestationSignatureBatch(ctx, st, []ethpb.Att{att1, att2})
|
||||||
|
require.NoError(t, err)
|
||||||
|
verified, err := set.Verify()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, true, verified, "Multiple signatures were unable to be verified.")
|
||||||
})
|
})
|
||||||
root, err = signing.ComputeSigningRoot(att2.Data, domain)
|
|
||||||
require.NoError(t, err)
|
|
||||||
sigs = nil
|
|
||||||
for i, u := range comm2 {
|
|
||||||
att2.AggregationBits.SetBitAt(uint64(i), true)
|
|
||||||
sigs = append(sigs, keys[u].Sign(root[:]))
|
|
||||||
}
|
|
||||||
att2.Signature = bls.AggregateSignatures(sigs).Marshal()
|
|
||||||
|
|
||||||
set, err := blocks.AttestationSignatureBatch(ctx, st, []ethpb.Att{att1, att2})
|
|
||||||
require.NoError(t, err)
|
|
||||||
verified, err := set.Verify()
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, true, verified, "Multiple signatures were unable to be verified.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRetrieveAttestationSignatureSet_AcrossFork(t *testing.T) {
|
func TestRetrieveAttestationSignatureSet_AcrossFork(t *testing.T) {
|
||||||
|
|||||||
@@ -297,21 +297,6 @@ func TestFuzzVerifyIndexedAttestationn_10000(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFuzzVerifyAttestation_10000(t *testing.T) {
|
|
||||||
fuzzer := fuzz.NewWithSeed(0)
|
|
||||||
state := ðpb.BeaconState{}
|
|
||||||
attestation := ðpb.Attestation{}
|
|
||||||
ctx := context.Background()
|
|
||||||
for i := 0; i < 10000; i++ {
|
|
||||||
fuzzer.Fuzz(state)
|
|
||||||
fuzzer.Fuzz(attestation)
|
|
||||||
s, err := state_native.InitializeFromProtoUnsafePhase0(state)
|
|
||||||
require.NoError(t, err)
|
|
||||||
err = VerifyAttestationSignature(ctx, s, attestation)
|
|
||||||
_ = err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFuzzProcessDeposits_10000(t *testing.T) {
|
func TestFuzzProcessDeposits_10000(t *testing.T) {
|
||||||
fuzzer := fuzz.NewWithSeed(0)
|
fuzzer := fuzz.NewWithSeed(0)
|
||||||
state := ðpb.BeaconState{}
|
state := ðpb.BeaconState{}
|
||||||
|
|||||||
@@ -163,7 +163,42 @@ func NewGenesisBlockForState(ctx context.Context, st state.BeaconState) (interfa
|
|||||||
SyncCommitteeBits: make([]byte, fieldparams.SyncCommitteeLength/8),
|
SyncCommitteeBits: make([]byte, fieldparams.SyncCommitteeLength/8),
|
||||||
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
||||||
},
|
},
|
||||||
ExecutionPayload: &enginev1.ExecutionPayloadDeneb{ // Deneb difference.
|
ExecutionPayload: &enginev1.ExecutionPayloadDeneb{
|
||||||
|
ParentHash: make([]byte, 32),
|
||||||
|
FeeRecipient: make([]byte, 20),
|
||||||
|
StateRoot: make([]byte, 32),
|
||||||
|
ReceiptsRoot: make([]byte, 32),
|
||||||
|
LogsBloom: make([]byte, 256),
|
||||||
|
PrevRandao: make([]byte, 32),
|
||||||
|
ExtraData: make([]byte, 0),
|
||||||
|
BaseFeePerGas: make([]byte, 32),
|
||||||
|
BlockHash: make([]byte, 32),
|
||||||
|
Transactions: make([][]byte, 0),
|
||||||
|
Withdrawals: make([]*enginev1.Withdrawal, 0),
|
||||||
|
},
|
||||||
|
BlsToExecutionChanges: make([]*ethpb.SignedBLSToExecutionChange, 0),
|
||||||
|
BlobKzgCommitments: make([][]byte, 0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Signature: params.BeaconConfig().EmptySignature[:],
|
||||||
|
})
|
||||||
|
case *ethpb.BeaconStateElectra:
|
||||||
|
return blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockElectra{
|
||||||
|
Block: ðpb.BeaconBlockElectra{
|
||||||
|
ParentRoot: params.BeaconConfig().ZeroHash[:],
|
||||||
|
StateRoot: root[:],
|
||||||
|
Body: ðpb.BeaconBlockBodyElectra{
|
||||||
|
RandaoReveal: make([]byte, 96),
|
||||||
|
Eth1Data: ðpb.Eth1Data{
|
||||||
|
DepositRoot: make([]byte, 32),
|
||||||
|
BlockHash: make([]byte, 32),
|
||||||
|
},
|
||||||
|
Graffiti: make([]byte, 32),
|
||||||
|
SyncAggregate: ðpb.SyncAggregate{
|
||||||
|
SyncCommitteeBits: make([]byte, fieldparams.SyncCommitteeLength/8),
|
||||||
|
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
||||||
|
},
|
||||||
|
ExecutionPayload: &enginev1.ExecutionPayloadElectra{
|
||||||
ParentHash: make([]byte, 32),
|
ParentHash: make([]byte, 32),
|
||||||
FeeRecipient: make([]byte, 20),
|
FeeRecipient: make([]byte, 20),
|
||||||
StateRoot: make([]byte, 32),
|
StateRoot: make([]byte, 32),
|
||||||
|
|||||||
@@ -192,11 +192,11 @@ func createAttestationSignatureBatch(
|
|||||||
descs := make([]string, len(atts))
|
descs := make([]string, len(atts))
|
||||||
for i, a := range atts {
|
for i, a := range atts {
|
||||||
sigs[i] = a.GetSignature()
|
sigs[i] = a.GetSignature()
|
||||||
c, err := helpers.BeaconCommitteeFromState(ctx, beaconState, a.GetData().Slot, a.GetData().CommitteeIndex)
|
committees, err := helpers.AttestationCommittees(ctx, beaconState, a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ia, err := attestation.ConvertToIndexed(ctx, a, c)
|
ia, err := attestation.ConvertToIndexed(ctx, a, committees...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -470,7 +470,7 @@ func UnslashedAttestingIndices(ctx context.Context, state state.ReadOnlyBeaconSt
|
|||||||
seen := make(map[uint64]bool)
|
seen := make(map[uint64]bool)
|
||||||
|
|
||||||
for _, att := range atts {
|
for _, att := range atts {
|
||||||
committee, err := helpers.BeaconCommitteeFromState(ctx, state, att.Data.Slot, att.Data.CommitteeIndex)
|
committee, err := helpers.BeaconCommitteeFromState(ctx, state, att.GetData().Slot, att.GetData().CommitteeIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ go_library(
|
|||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//math:go_default_library",
|
"//math:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
"//runtime/version:go_default_library",
|
||||||
"//time:go_default_library",
|
"//time:go_default_library",
|
||||||
"//time/slots:go_default_library",
|
"//time/slots:go_default_library",
|
||||||
"@com_github_pkg_errors//:go_default_library",
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||||
"github.com/prysmaticlabs/prysm/v5/math"
|
"github.com/prysmaticlabs/prysm/v5/math"
|
||||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -58,6 +59,29 @@ func SlotCommitteeCount(activeValidatorCount uint64) uint64 {
|
|||||||
return committeesPerSlot
|
return committeesPerSlot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AttestationCommittees returns beacon state committees that reflect attestation's committee indices.
|
||||||
|
func AttestationCommittees(ctx context.Context, st state.ReadOnlyBeaconState, att ethpb.Att) ([][]primitives.ValidatorIndex, error) {
|
||||||
|
var committees [][]primitives.ValidatorIndex
|
||||||
|
if att.Version() >= version.Electra {
|
||||||
|
committeeIndices := att.CommitteeBitsVal().BitIndices()
|
||||||
|
committees = make([][]primitives.ValidatorIndex, len(committeeIndices))
|
||||||
|
for i, ci := range committeeIndices {
|
||||||
|
committee, err := BeaconCommitteeFromState(ctx, st, att.GetData().Slot, primitives.CommitteeIndex(ci))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
committees[i] = committee
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
committee, err := BeaconCommitteeFromState(ctx, st, att.GetData().Slot, att.GetData().CommitteeIndex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
committees = [][]primitives.ValidatorIndex{committee}
|
||||||
|
}
|
||||||
|
return committees, nil
|
||||||
|
}
|
||||||
|
|
||||||
// BeaconCommitteeFromState returns the crosslink committee of a given slot and committee index. This
|
// BeaconCommitteeFromState returns the crosslink committee of a given slot and committee index. This
|
||||||
// is a spec implementation where state is used as an argument. In case of state retrieval
|
// is a spec implementation where state is used as an argument. In case of state retrieval
|
||||||
// becomes expensive, consider using BeaconCommittee below.
|
// becomes expensive, consider using BeaconCommittee below.
|
||||||
|
|||||||
@@ -715,3 +715,37 @@ func TestCommitteeIndices(t *testing.T) {
|
|||||||
indices := helpers.CommitteeIndices(bitfield)
|
indices := helpers.CommitteeIndices(bitfield)
|
||||||
assert.DeepEqual(t, []primitives.CommitteeIndex{0, 1, 3}, indices)
|
assert.DeepEqual(t, []primitives.CommitteeIndex{0, 1, 3}, indices)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAttestationCommittees(t *testing.T) {
|
||||||
|
validators := make([]*ethpb.Validator, params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().TargetCommitteeSize))
|
||||||
|
for i := 0; i < len(validators); i++ {
|
||||||
|
validators[i] = ðpb.Validator{
|
||||||
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{
|
||||||
|
Validators: validators,
|
||||||
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("pre-Electra", func(t *testing.T) {
|
||||||
|
att := ðpb.Attestation{Data: ðpb.AttestationData{CommitteeIndex: 0}}
|
||||||
|
committees, err := helpers.AttestationCommittees(context.Background(), state, att)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(committees))
|
||||||
|
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[0])))
|
||||||
|
})
|
||||||
|
t.Run("post-Electra", func(t *testing.T) {
|
||||||
|
bits := primitives.NewAttestationCommitteeBits()
|
||||||
|
bits.SetBitAt(0, true)
|
||||||
|
bits.SetBitAt(1, true)
|
||||||
|
att := ðpb.AttestationElectra{CommitteeBits: bits, Data: ðpb.AttestationData{}}
|
||||||
|
committees, err := helpers.AttestationCommittees(context.Background(), state, att)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 2, len(committees))
|
||||||
|
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[0])))
|
||||||
|
assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(committees[1])))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import (
|
|||||||
func validAttesterSlashingForValIdx(t *testing.T, beaconState state.BeaconState, privs []bls.SecretKey, valIdx ...uint64) *ethpb.AttesterSlashing {
|
func validAttesterSlashingForValIdx(t *testing.T, beaconState state.BeaconState, privs []bls.SecretKey, valIdx ...uint64) *ethpb.AttesterSlashing {
|
||||||
var slashings []*ethpb.AttesterSlashing
|
var slashings []*ethpb.AttesterSlashing
|
||||||
for _, idx := range valIdx {
|
for _, idx := range valIdx {
|
||||||
slashing, err := util.GenerateAttesterSlashingForValidator(beaconState, privs[idx], primitives.ValidatorIndex(idx))
|
generatedSlashing, err := util.GenerateAttesterSlashingForValidator(beaconState, privs[idx], primitives.ValidatorIndex(idx))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
slashings = append(slashings, slashing)
|
slashings = append(slashings, generatedSlashing.(*ethpb.AttesterSlashing))
|
||||||
}
|
}
|
||||||
var allSig1 []bls.Signature
|
var allSig1 []bls.Signature
|
||||||
var allSig2 []bls.Signature
|
var allSig2 []bls.Signature
|
||||||
@@ -78,12 +78,14 @@ func TestPool_InsertAttesterSlashing(t *testing.T) {
|
|||||||
pendingSlashings := make([]*PendingAttesterSlashing, 20)
|
pendingSlashings := make([]*PendingAttesterSlashing, 20)
|
||||||
slashings := make([]*ethpb.AttesterSlashing, 20)
|
slashings := make([]*ethpb.AttesterSlashing, 20)
|
||||||
for i := 0; i < len(pendingSlashings); i++ {
|
for i := 0; i < len(pendingSlashings); i++ {
|
||||||
sl, err := util.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], primitives.ValidatorIndex(i))
|
generatedSl, err := util.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], primitives.ValidatorIndex(i))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pendingSlashings[i] = &PendingAttesterSlashing{
|
pendingSlashings[i] = &PendingAttesterSlashing{
|
||||||
attesterSlashing: sl,
|
attesterSlashing: generatedSl,
|
||||||
validatorToSlash: primitives.ValidatorIndex(i),
|
validatorToSlash: primitives.ValidatorIndex(i),
|
||||||
}
|
}
|
||||||
|
sl, ok := generatedSl.(*ethpb.AttesterSlashing)
|
||||||
|
require.Equal(t, true, ok, "Attester slashing has the wrong type (expected %T, got %T)", ðpb.AttesterSlashing{}, generatedSl)
|
||||||
slashings[i] = sl
|
slashings[i] = sl
|
||||||
}
|
}
|
||||||
require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||||
@@ -303,12 +305,16 @@ func TestPool_InsertAttesterSlashing_SigFailsVerify_ClearPool(t *testing.T) {
|
|||||||
pendingSlashings := make([]*PendingAttesterSlashing, 2)
|
pendingSlashings := make([]*PendingAttesterSlashing, 2)
|
||||||
slashings := make([]*ethpb.AttesterSlashing, 2)
|
slashings := make([]*ethpb.AttesterSlashing, 2)
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
sl, err := util.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], primitives.ValidatorIndex(i))
|
generatedSl, err := util.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], primitives.ValidatorIndex(i))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pendingSlashings[i] = &PendingAttesterSlashing{
|
pendingSlashings[i] = &PendingAttesterSlashing{
|
||||||
attesterSlashing: sl,
|
attesterSlashing: generatedSl,
|
||||||
validatorToSlash: primitives.ValidatorIndex(i),
|
validatorToSlash: primitives.ValidatorIndex(i),
|
||||||
}
|
}
|
||||||
|
sl, ok := generatedSl.(*ethpb.AttesterSlashing)
|
||||||
|
if !ok {
|
||||||
|
require.Equal(t, true, ok, "Attester slashing has the wrong type (expected %T, got %T)", ðpb.AttesterSlashing{}, generatedSl)
|
||||||
|
}
|
||||||
slashings[i] = sl
|
slashings[i] = sl
|
||||||
}
|
}
|
||||||
// We mess up the signature of the second slashing.
|
// We mess up the signature of the second slashing.
|
||||||
|
|||||||
@@ -66,13 +66,13 @@ func TestServer_SubmitAttesterSlashing(t *testing.T) {
|
|||||||
Broadcaster: mb,
|
Broadcaster: mb,
|
||||||
}
|
}
|
||||||
|
|
||||||
slashing, err := util.GenerateAttesterSlashingForValidator(st, privs[2], primitives.ValidatorIndex(2))
|
generatedSlashing, err := util.GenerateAttesterSlashingForValidator(st, privs[2], primitives.ValidatorIndex(2))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We want the intersection of the slashing attesting indices
|
// We want the intersection of the slashing attesting indices
|
||||||
// to be slashed, so we expect validators 2 and 3 to be in the response
|
// to be slashed, so we expect validators 2 and 3 to be in the response
|
||||||
// slashed indices.
|
// slashed indices.
|
||||||
_, err = bs.SubmitAttesterSlashing(ctx, slashing)
|
_, err = bs.SubmitAttesterSlashing(ctx, generatedSlashing.(*ethpb.AttesterSlashing))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, true, mb.BroadcastCalled.Load(), "Expected broadcast to be called when flag is set")
|
assert.Equal(t, true, mb.BroadcastCalled.Load(), "Expected broadcast to be called when flag is set")
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ func TestServer_SubmitAttesterSlashing_DontBroadcast(t *testing.T) {
|
|||||||
Broadcaster: mb,
|
Broadcaster: mb,
|
||||||
}
|
}
|
||||||
|
|
||||||
slashing, err := util.GenerateAttesterSlashingForValidator(st, privs[2], primitives.ValidatorIndex(2))
|
generatedSlashing, err := util.GenerateAttesterSlashingForValidator(st, privs[2], primitives.ValidatorIndex(2))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// We want the intersection of the slashing attesting indices
|
// We want the intersection of the slashing attesting indices
|
||||||
@@ -153,17 +153,17 @@ func TestServer_SubmitAttesterSlashing_DontBroadcast(t *testing.T) {
|
|||||||
wanted := ðpb.SubmitSlashingResponse{
|
wanted := ðpb.SubmitSlashingResponse{
|
||||||
SlashedIndices: []primitives.ValidatorIndex{2},
|
SlashedIndices: []primitives.ValidatorIndex{2},
|
||||||
}
|
}
|
||||||
res, err := bs.SubmitAttesterSlashing(ctx, slashing)
|
res, err := bs.SubmitAttesterSlashing(ctx, generatedSlashing.(*ethpb.AttesterSlashing))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
if !proto.Equal(wanted, res) {
|
if !proto.Equal(wanted, res) {
|
||||||
t.Errorf("Wanted %v, received %v", wanted, res)
|
t.Errorf("Wanted %v, received %v", wanted, res)
|
||||||
}
|
}
|
||||||
assert.Equal(t, false, mb.BroadcastCalled.Load(), "Expected broadcast not to be called by default")
|
assert.Equal(t, false, mb.BroadcastCalled.Load(), "Expected broadcast not to be called by default")
|
||||||
|
|
||||||
slashing, err = util.GenerateAttesterSlashingForValidator(st, privs[5], primitives.ValidatorIndex(5))
|
generatedSlashing, err = util.GenerateAttesterSlashingForValidator(st, privs[5], primitives.ValidatorIndex(5))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// If any of the attesting indices in the slashing object have already
|
// If any of the attesting indices in the slashing object have already
|
||||||
// been slashed, we should fail to insert properly into the attester slashing pool.
|
// been slashed, we should fail to insert properly into the attester slashing pool.
|
||||||
_, err = bs.SubmitAttesterSlashing(ctx, slashing)
|
_, err = bs.SubmitAttesterSlashing(ctx, generatedSlashing.(*ethpb.AttesterSlashing))
|
||||||
assert.NotNil(t, err, "Expected including a attester slashing for an already slashed validator to fail")
|
assert.NotNil(t, err, "Expected including a attester slashing for an already slashed validator to fail")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -753,10 +753,12 @@ func injectSlashings(t *testing.T, st state.BeaconState, keys []bls.SecretKey, s
|
|||||||
|
|
||||||
attSlashings := make([]*ethpb.AttesterSlashing, params.BeaconConfig().MaxAttesterSlashings)
|
attSlashings := make([]*ethpb.AttesterSlashing, params.BeaconConfig().MaxAttesterSlashings)
|
||||||
for i := uint64(0); i < params.BeaconConfig().MaxAttesterSlashings; i++ {
|
for i := uint64(0); i < params.BeaconConfig().MaxAttesterSlashings; i++ {
|
||||||
attesterSlashing, err := util.GenerateAttesterSlashingForValidator(st, keys[i+params.BeaconConfig().MaxProposerSlashings], primitives.ValidatorIndex(i+params.BeaconConfig().MaxProposerSlashings) /* validator index */)
|
generatedAttesterSlashing, err := util.GenerateAttesterSlashingForValidator(st, keys[i+params.BeaconConfig().MaxProposerSlashings], primitives.ValidatorIndex(i+params.BeaconConfig().MaxProposerSlashings) /* validator index */)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
attesterSlashing, ok := generatedAttesterSlashing.(*ethpb.AttesterSlashing)
|
||||||
|
require.Equal(t, true, ok, "Attester slashing has the wrong type (expected %T, got %T)", ðpb.AttesterSlashing{}, generatedAttesterSlashing)
|
||||||
attSlashings[i] = attesterSlashing
|
attSlashings[i] = attesterSlashing
|
||||||
err = server.SlashingsPool.InsertAttesterSlashing(context.Background(), st, attesterSlashing)
|
err = server.SlashingsPool.InsertAttesterSlashing(context.Background(), st, generatedAttesterSlashing.(*ethpb.AttesterSlashing))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
return proposerSlashings, attSlashings
|
return proposerSlashings, attSlashings
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ func TestSubscribe_ReceivesAttesterSlashing(t *testing.T) {
|
|||||||
1, /* validator index */
|
1, /* validator index */
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "Error generating attester slashing")
|
require.NoError(t, err, "Error generating attester slashing")
|
||||||
err = r.cfg.beaconDB.SaveState(ctx, beaconState, bytesutil.ToBytes32(attesterSlashing.Attestation_1.Data.BeaconBlockRoot))
|
err = r.cfg.beaconDB.SaveState(ctx, beaconState, bytesutil.ToBytes32(attesterSlashing.FirstAttestation().GetData().BeaconBlockRoot))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
p2pService.ReceivePubSub(topic, attesterSlashing)
|
p2pService.ReceivePubSub(topic, attesterSlashing)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"committee_bits_mainnet.go",
|
||||||
|
"committee_bits_minimal.go", # keep
|
||||||
"committee_index.go",
|
"committee_index.go",
|
||||||
"domain.go",
|
"domain.go",
|
||||||
"epoch.go",
|
"epoch.go",
|
||||||
@@ -20,6 +22,7 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//math:go_default_library",
|
"//math:go_default_library",
|
||||||
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
"@com_github_prysmaticlabs_fastssz//:go_default_library",
|
||||||
|
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
9
consensus-types/primitives/committee_bits_mainnet.go
Normal file
9
consensus-types/primitives/committee_bits_mainnet.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build !minimal
|
||||||
|
|
||||||
|
package primitives
|
||||||
|
|
||||||
|
import "github.com/prysmaticlabs/go-bitfield"
|
||||||
|
|
||||||
|
func NewAttestationCommitteeBits() bitfield.Bitvector64 {
|
||||||
|
return bitfield.NewBitvector64()
|
||||||
|
}
|
||||||
9
consensus-types/primitives/committee_bits_minimal.go
Normal file
9
consensus-types/primitives/committee_bits_minimal.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build minimal
|
||||||
|
|
||||||
|
package primitives
|
||||||
|
|
||||||
|
import "github.com/prysmaticlabs/go-bitfield"
|
||||||
|
|
||||||
|
func NewAttestationCommitteeBits() bitfield.Bitvector4 {
|
||||||
|
return bitfield.NewBitvector4()
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ go_library(
|
|||||||
"deneb_state.go",
|
"deneb_state.go",
|
||||||
"deposits.go",
|
"deposits.go",
|
||||||
"electra.go",
|
"electra.go",
|
||||||
|
"electra_block.go",
|
||||||
"electra_state.go",
|
"electra_state.go",
|
||||||
"helpers.go",
|
"helpers.go",
|
||||||
"merge.go",
|
"merge.go",
|
||||||
|
|||||||
@@ -345,19 +345,35 @@ func GenerateFullBlockAltair(
|
|||||||
numToGen = conf.NumAttesterSlashings
|
numToGen = conf.NumAttesterSlashings
|
||||||
var aSlashings []*ethpb.AttesterSlashing
|
var aSlashings []*ethpb.AttesterSlashing
|
||||||
if numToGen > 0 {
|
if numToGen > 0 {
|
||||||
aSlashings, err = generateAttesterSlashings(bState, privs, numToGen)
|
generated, err := generateAttesterSlashings(bState, privs, numToGen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
|
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
|
||||||
}
|
}
|
||||||
|
aSlashings = make([]*ethpb.AttesterSlashing, len(generated))
|
||||||
|
var ok bool
|
||||||
|
for i, s := range generated {
|
||||||
|
aSlashings[i], ok = s.(*ethpb.AttesterSlashing)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("attester slashing has wrong type (expected %T, got %T)", ðpb.AttesterSlashing{}, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
numToGen = conf.NumAttestations
|
numToGen = conf.NumAttestations
|
||||||
var atts []*ethpb.Attestation
|
var atts []*ethpb.Attestation
|
||||||
if numToGen > 0 {
|
if numToGen > 0 {
|
||||||
atts, err = GenerateAttestations(bState, privs, numToGen, slot, false)
|
generatedAtts, err := GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
|
return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
|
||||||
}
|
}
|
||||||
|
atts = make([]*ethpb.Attestation, len(generatedAtts))
|
||||||
|
var ok bool
|
||||||
|
for i, a := range generatedAtts {
|
||||||
|
atts[i], ok = a.(*ethpb.Attestation)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("attestation has the wrong type (expected %T, got %T)", ðpb.Attestation{}, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
numToGen = conf.NumDeposits
|
numToGen = conf.NumDeposits
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package util
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
@@ -48,10 +47,8 @@ func NewAttestation() *ethpb.Attestation {
|
|||||||
// for the same data with their aggregation bits split uniformly.
|
// for the same data with their aggregation bits split uniformly.
|
||||||
//
|
//
|
||||||
// If you request 4 attestations, but there are 8 committees, you will get 4 fully aggregated attestations.
|
// If you request 4 attestations, but there are 8 committees, you will get 4 fully aggregated attestations.
|
||||||
func GenerateAttestations(
|
func GenerateAttestations(bState state.BeaconState, privs []bls.SecretKey, numToGen uint64, slot primitives.Slot, randomRoot bool) ([]ethpb.Att, error) { // nolint:gocognit
|
||||||
bState state.BeaconState, privs []bls.SecretKey, numToGen uint64, slot primitives.Slot, randomRoot bool,
|
var attestations []ethpb.Att
|
||||||
) ([]*ethpb.Attestation, error) {
|
|
||||||
var attestations []*ethpb.Attestation
|
|
||||||
generateHeadState := false
|
generateHeadState := false
|
||||||
bState = bState.Copy()
|
bState = bState.Copy()
|
||||||
if slot > bState.Slot() {
|
if slot > bState.Slot() {
|
||||||
@@ -108,8 +105,28 @@ func GenerateAttestations(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
headState = genState
|
headState = genState
|
||||||
|
case version.Deneb:
|
||||||
|
pbState, err := state_native.ProtobufBeaconStateDeneb(bState.ToProto())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
genState, err := state_native.InitializeFromProtoUnsafeDeneb(pbState)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
headState = genState
|
||||||
|
case version.Electra:
|
||||||
|
pbState, err := state_native.ProtobufBeaconStateElectra(bState.ToProto())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
genState, err := state_native.InitializeFromProtoUnsafeElectra(pbState)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
headState = genState
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("state type isn't supported")
|
return nil, fmt.Errorf("state version %s isn't supported", version.String(bState.Version()))
|
||||||
}
|
}
|
||||||
|
|
||||||
headState, err = transition.ProcessSlots(context.Background(), headState, slot+1)
|
headState, err = transition.ProcessSlots(context.Background(), headState, slot+1)
|
||||||
@@ -180,9 +197,14 @@ func GenerateAttestations(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci := c
|
||||||
|
if bState.Version() >= version.Electra {
|
||||||
|
// committee index must be 0 post-Electra
|
||||||
|
ci = 0
|
||||||
|
}
|
||||||
attData := ðpb.AttestationData{
|
attData := ðpb.AttestationData{
|
||||||
Slot: slot,
|
Slot: slot,
|
||||||
CommitteeIndex: c,
|
CommitteeIndex: ci,
|
||||||
BeaconBlockRoot: headRoot,
|
BeaconBlockRoot: headRoot,
|
||||||
Source: bState.CurrentJustifiedCheckpoint(),
|
Source: bState.CurrentJustifiedCheckpoint(),
|
||||||
Target: ðpb.Checkpoint{
|
Target: ðpb.Checkpoint{
|
||||||
@@ -211,10 +233,22 @@ func GenerateAttestations(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
att := ðpb.Attestation{
|
var att ethpb.Att
|
||||||
Data: attData,
|
if bState.Version() >= version.Electra {
|
||||||
AggregationBits: aggregationBits,
|
cb := primitives.NewAttestationCommitteeBits()
|
||||||
Signature: bls.AggregateSignatures(sigs).Marshal(),
|
cb.SetBitAt(uint64(c), true)
|
||||||
|
att = ðpb.AttestationElectra{
|
||||||
|
Data: attData,
|
||||||
|
CommitteeBits: cb,
|
||||||
|
AggregationBits: aggregationBits,
|
||||||
|
Signature: bls.AggregateSignatures(sigs).Marshal(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
att = ðpb.Attestation{
|
||||||
|
Data: attData,
|
||||||
|
AggregationBits: aggregationBits,
|
||||||
|
Signature: bls.AggregateSignatures(sigs).Marshal(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
attestations = append(attestations, att)
|
attestations = append(attestations, att)
|
||||||
}
|
}
|
||||||
@@ -238,6 +272,25 @@ func HydrateAttestation(a *ethpb.Attestation) *ethpb.Attestation {
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HydrateAttestationElectra hydrates an attestation object with correct field length sizes
|
||||||
|
// to comply with fssz marshalling and unmarshalling rules.
|
||||||
|
func HydrateAttestationElectra(a *ethpb.AttestationElectra) *ethpb.AttestationElectra {
|
||||||
|
if a.Signature == nil {
|
||||||
|
a.Signature = make([]byte, 96)
|
||||||
|
}
|
||||||
|
if a.AggregationBits == nil {
|
||||||
|
a.AggregationBits = make([]byte, 1)
|
||||||
|
}
|
||||||
|
if a.CommitteeBits == nil {
|
||||||
|
a.CommitteeBits = primitives.NewAttestationCommitteeBits()
|
||||||
|
}
|
||||||
|
if a.Data == nil {
|
||||||
|
a.Data = ðpb.AttestationData{}
|
||||||
|
}
|
||||||
|
a.Data = HydrateAttestationData(a.Data)
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
// HydrateV1Attestation hydrates a v1 attestation object with correct field length sizes
|
// HydrateV1Attestation hydrates a v1 attestation object with correct field length sizes
|
||||||
// to comply with fssz marshalling and unmarshalling rules.
|
// to comply with fssz marshalling and unmarshalling rules.
|
||||||
func HydrateV1Attestation(a *attv1.Attestation) *attv1.Attestation {
|
func HydrateV1Attestation(a *attv1.Attestation) *attv1.Attestation {
|
||||||
|
|||||||
@@ -56,19 +56,35 @@ func GenerateFullBlockBellatrix(
|
|||||||
numToGen = conf.NumAttesterSlashings
|
numToGen = conf.NumAttesterSlashings
|
||||||
var aSlashings []*ethpb.AttesterSlashing
|
var aSlashings []*ethpb.AttesterSlashing
|
||||||
if numToGen > 0 {
|
if numToGen > 0 {
|
||||||
aSlashings, err = generateAttesterSlashings(bState, privs, numToGen)
|
generated, err := generateAttesterSlashings(bState, privs, numToGen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
|
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
|
||||||
}
|
}
|
||||||
|
aSlashings = make([]*ethpb.AttesterSlashing, len(generated))
|
||||||
|
var ok bool
|
||||||
|
for i, s := range generated {
|
||||||
|
aSlashings[i], ok = s.(*ethpb.AttesterSlashing)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("attester slashing has wrong type (expected %T, got %T)", ðpb.AttesterSlashing{}, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
numToGen = conf.NumAttestations
|
numToGen = conf.NumAttestations
|
||||||
var atts []*ethpb.Attestation
|
var atts []*ethpb.Attestation
|
||||||
if numToGen > 0 {
|
if numToGen > 0 {
|
||||||
atts, err = GenerateAttestations(bState, privs, numToGen, slot, false)
|
generatedAtts, err := GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
|
return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
|
||||||
}
|
}
|
||||||
|
atts = make([]*ethpb.Attestation, len(generatedAtts))
|
||||||
|
var ok bool
|
||||||
|
for i, a := range generatedAtts {
|
||||||
|
atts[i], ok = a.(*ethpb.Attestation)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("attestation has the wrong type (expected %T, got %T)", ðpb.Attestation{}, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
numToGen = conf.NumDeposits
|
numToGen = conf.NumDeposits
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
v1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
|
v1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
|
||||||
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
|
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
|
||||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||||
"github.com/prysmaticlabs/prysm/v5/testing/assertions"
|
"github.com/prysmaticlabs/prysm/v5/testing/assertions"
|
||||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||||
)
|
)
|
||||||
@@ -109,19 +110,35 @@ func GenerateFullBlock(
|
|||||||
numToGen = conf.NumAttesterSlashings
|
numToGen = conf.NumAttesterSlashings
|
||||||
var aSlashings []*ethpb.AttesterSlashing
|
var aSlashings []*ethpb.AttesterSlashing
|
||||||
if numToGen > 0 {
|
if numToGen > 0 {
|
||||||
aSlashings, err = generateAttesterSlashings(bState, privs, numToGen)
|
generated, err := generateAttesterSlashings(bState, privs, numToGen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
|
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
|
||||||
}
|
}
|
||||||
|
aSlashings = make([]*ethpb.AttesterSlashing, len(generated))
|
||||||
|
var ok bool
|
||||||
|
for i, s := range generated {
|
||||||
|
aSlashings[i], ok = s.(*ethpb.AttesterSlashing)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("attester slashing has the wrong type (expected %T, got %T)", ðpb.AttesterSlashing{}, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
numToGen = conf.NumAttestations
|
numToGen = conf.NumAttestations
|
||||||
var atts []*ethpb.Attestation
|
var atts []*ethpb.Attestation
|
||||||
if numToGen > 0 {
|
if numToGen > 0 {
|
||||||
atts, err = GenerateAttestations(bState, privs, numToGen, slot, false)
|
generatedAtts, err := GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
|
return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
|
||||||
}
|
}
|
||||||
|
atts = make([]*ethpb.Attestation, len(generatedAtts))
|
||||||
|
var ok bool
|
||||||
|
for i, a := range generatedAtts {
|
||||||
|
atts[i], ok = a.(*ethpb.Attestation)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("attestation has the wrong type (expected %T, got %T)", ðpb.Attestation{}, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
numToGen = conf.NumDeposits
|
numToGen = conf.NumDeposits
|
||||||
@@ -265,9 +282,59 @@ func GenerateAttesterSlashingForValidator(
|
|||||||
bState state.BeaconState,
|
bState state.BeaconState,
|
||||||
priv bls.SecretKey,
|
priv bls.SecretKey,
|
||||||
idx primitives.ValidatorIndex,
|
idx primitives.ValidatorIndex,
|
||||||
) (*ethpb.AttesterSlashing, error) {
|
) (ethpb.AttSlashing, error) {
|
||||||
currentEpoch := time.CurrentEpoch(bState)
|
currentEpoch := time.CurrentEpoch(bState)
|
||||||
|
|
||||||
|
if bState.Version() >= version.Electra {
|
||||||
|
att1 := ðpb.IndexedAttestationElectra{
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: bState.Slot(),
|
||||||
|
CommitteeIndex: 0,
|
||||||
|
BeaconBlockRoot: make([]byte, fieldparams.RootLength),
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: currentEpoch,
|
||||||
|
Root: params.BeaconConfig().ZeroHash[:],
|
||||||
|
},
|
||||||
|
Source: ðpb.Checkpoint{
|
||||||
|
Epoch: currentEpoch + 1,
|
||||||
|
Root: params.BeaconConfig().ZeroHash[:],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
AttestingIndices: []uint64{uint64(idx)},
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
att1.Signature, err = signing.ComputeDomainAndSign(bState, currentEpoch, att1.Data, params.BeaconConfig().DomainBeaconAttester, priv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
att2 := ðpb.IndexedAttestationElectra{
|
||||||
|
Data: ðpb.AttestationData{
|
||||||
|
Slot: bState.Slot(),
|
||||||
|
CommitteeIndex: 0,
|
||||||
|
BeaconBlockRoot: make([]byte, fieldparams.RootLength),
|
||||||
|
Target: ðpb.Checkpoint{
|
||||||
|
Epoch: currentEpoch,
|
||||||
|
Root: params.BeaconConfig().ZeroHash[:],
|
||||||
|
},
|
||||||
|
Source: ðpb.Checkpoint{
|
||||||
|
Epoch: currentEpoch,
|
||||||
|
Root: params.BeaconConfig().ZeroHash[:],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
AttestingIndices: []uint64{uint64(idx)},
|
||||||
|
}
|
||||||
|
att2.Signature, err = signing.ComputeDomainAndSign(bState, currentEpoch, att2.Data, params.BeaconConfig().DomainBeaconAttester, priv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ðpb.AttesterSlashingElectra{
|
||||||
|
Attestation_1: att1,
|
||||||
|
Attestation_2: att2,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
att1 := ðpb.IndexedAttestation{
|
att1 := ðpb.IndexedAttestation{
|
||||||
Data: ðpb.AttestationData{
|
Data: ðpb.AttestationData{
|
||||||
Slot: bState.Slot(),
|
Slot: bState.Slot(),
|
||||||
@@ -321,8 +388,8 @@ func generateAttesterSlashings(
|
|||||||
bState state.BeaconState,
|
bState state.BeaconState,
|
||||||
privs []bls.SecretKey,
|
privs []bls.SecretKey,
|
||||||
numSlashings uint64,
|
numSlashings uint64,
|
||||||
) ([]*ethpb.AttesterSlashing, error) {
|
) ([]ethpb.AttSlashing, error) {
|
||||||
attesterSlashings := make([]*ethpb.AttesterSlashing, numSlashings)
|
attesterSlashings := make([]ethpb.AttSlashing, numSlashings)
|
||||||
randGen := rand.NewDeterministicGenerator()
|
randGen := rand.NewDeterministicGenerator()
|
||||||
for i := uint64(0); i < numSlashings; i++ {
|
for i := uint64(0); i < numSlashings; i++ {
|
||||||
committeeIndex := randGen.Uint64() % helpers.SlotCommitteeCount(uint64(bState.NumValidators()))
|
committeeIndex := randGen.Uint64() % helpers.SlotCommitteeCount(uint64(bState.NumValidators()))
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import (
|
|||||||
// GenerateFullBlockCapella generates a fully valid Capella block with the requested parameters.
|
// GenerateFullBlockCapella generates a fully valid Capella block with the requested parameters.
|
||||||
// Use BlockGenConfig to declare the conditions you would like the block generated under.
|
// Use BlockGenConfig to declare the conditions you would like the block generated under.
|
||||||
// This function modifies the passed state as follows:
|
// This function modifies the passed state as follows:
|
||||||
|
|
||||||
func GenerateFullBlockCapella(
|
func GenerateFullBlockCapella(
|
||||||
bState state.BeaconState,
|
bState state.BeaconState,
|
||||||
privs []bls.SecretKey,
|
privs []bls.SecretKey,
|
||||||
@@ -55,19 +54,35 @@ func GenerateFullBlockCapella(
|
|||||||
numToGen = conf.NumAttesterSlashings
|
numToGen = conf.NumAttesterSlashings
|
||||||
var aSlashings []*ethpb.AttesterSlashing
|
var aSlashings []*ethpb.AttesterSlashing
|
||||||
if numToGen > 0 {
|
if numToGen > 0 {
|
||||||
aSlashings, err = generateAttesterSlashings(bState, privs, numToGen)
|
generated, err := generateAttesterSlashings(bState, privs, numToGen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
|
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
|
||||||
}
|
}
|
||||||
|
aSlashings = make([]*ethpb.AttesterSlashing, len(generated))
|
||||||
|
var ok bool
|
||||||
|
for i, s := range generated {
|
||||||
|
aSlashings[i], ok = s.(*ethpb.AttesterSlashing)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("attester slashing has the wrong type (expected %T, got %T)", ðpb.AttesterSlashing{}, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
numToGen = conf.NumAttestations
|
numToGen = conf.NumAttestations
|
||||||
var atts []*ethpb.Attestation
|
var atts []*ethpb.Attestation
|
||||||
if numToGen > 0 {
|
if numToGen > 0 {
|
||||||
atts, err = GenerateAttestations(bState, privs, numToGen, slot, false)
|
generatedAtts, err := GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
|
return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
|
||||||
}
|
}
|
||||||
|
atts = make([]*ethpb.Attestation, len(generatedAtts))
|
||||||
|
var ok bool
|
||||||
|
for i, a := range generatedAtts {
|
||||||
|
atts[i], ok = a.(*ethpb.Attestation)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("attestation has the wrong type (expected %T, got %T)", ðpb.Attestation{}, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
numToGen = conf.NumDeposits
|
numToGen = conf.NumDeposits
|
||||||
|
|||||||
223
testing/util/electra_block.go
Normal file
223
testing/util/electra_block.go
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/prysmaticlabs/go-bitfield"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/transition"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||||
|
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||||
|
v1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
|
||||||
|
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||||
|
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenerateFullBlockElectra generates a fully valid Electra block with the requested parameters.
|
||||||
|
// Use BlockGenConfig to declare the conditions you would like the block generated under.
|
||||||
|
// This function modifies the passed state as follows:
|
||||||
|
func GenerateFullBlockElectra(
|
||||||
|
bState state.BeaconState,
|
||||||
|
privs []bls.SecretKey,
|
||||||
|
conf *BlockGenConfig,
|
||||||
|
slot primitives.Slot,
|
||||||
|
) (*ethpb.SignedBeaconBlockElectra, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
currentSlot := bState.Slot()
|
||||||
|
if currentSlot > slot {
|
||||||
|
return nil, fmt.Errorf("current slot in state is larger than given slot. %d > %d", currentSlot, slot)
|
||||||
|
}
|
||||||
|
bState = bState.Copy()
|
||||||
|
|
||||||
|
if conf == nil {
|
||||||
|
conf = &BlockGenConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var pSlashings []*ethpb.ProposerSlashing
|
||||||
|
numToGen := conf.NumProposerSlashings
|
||||||
|
if numToGen > 0 {
|
||||||
|
pSlashings, err = generateProposerSlashings(bState, privs, numToGen)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed generating %d proposer slashings:", numToGen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numToGen = conf.NumAttesterSlashings
|
||||||
|
var aSlashings []*ethpb.AttesterSlashingElectra
|
||||||
|
if numToGen > 0 {
|
||||||
|
generated, err := generateAttesterSlashings(bState, privs, numToGen)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
|
||||||
|
}
|
||||||
|
aSlashings = make([]*ethpb.AttesterSlashingElectra, len(generated))
|
||||||
|
var ok bool
|
||||||
|
for i, s := range generated {
|
||||||
|
aSlashings[i], ok = s.(*ethpb.AttesterSlashingElectra)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("attester slashing has the wrong type (expected %T, got %T)", ðpb.AttesterSlashingElectra{}, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numToGen = conf.NumAttestations
|
||||||
|
var atts []*ethpb.AttestationElectra
|
||||||
|
if numToGen > 0 {
|
||||||
|
generatedAtts, err := GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed generating %d attestations:", numToGen)
|
||||||
|
}
|
||||||
|
atts = make([]*ethpb.AttestationElectra, len(generatedAtts))
|
||||||
|
var ok bool
|
||||||
|
for i, a := range generatedAtts {
|
||||||
|
atts[i], ok = a.(*ethpb.AttestationElectra)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("attestation has the wrong type (expected %T, got %T)", ðpb.AttestationElectra{}, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numToGen = conf.NumDeposits
|
||||||
|
var newDeposits []*ethpb.Deposit
|
||||||
|
eth1Data := bState.Eth1Data()
|
||||||
|
if numToGen > 0 {
|
||||||
|
newDeposits, eth1Data, err = generateDepositsAndEth1Data(bState, numToGen)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed generating %d deposits:", numToGen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numToGen = conf.NumVoluntaryExits
|
||||||
|
var exits []*ethpb.SignedVoluntaryExit
|
||||||
|
if numToGen > 0 {
|
||||||
|
exits, err = generateVoluntaryExits(bState, privs, numToGen)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed generating %d attester slashings:", numToGen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numToGen = conf.NumTransactions
|
||||||
|
newTransactions := make([][]byte, numToGen)
|
||||||
|
for i := uint64(0); i < numToGen; i++ {
|
||||||
|
newTransactions[i] = bytesutil.Uint64ToBytesLittleEndian(i)
|
||||||
|
}
|
||||||
|
newWithdrawals := make([]*v1.Withdrawal, 0)
|
||||||
|
|
||||||
|
random, err := helpers.RandaoMix(bState, time.CurrentEpoch(bState))
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not process randao mix")
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp, err := slots.ToTime(bState.GenesisTime(), slot)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not get current timestamp")
|
||||||
|
}
|
||||||
|
|
||||||
|
stCopy := bState.Copy()
|
||||||
|
stCopy, err = transition.ProcessSlots(context.Background(), stCopy, slot)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
parentExecution, err := stCopy.LatestExecutionPayloadHeader()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
blockHash := indexToHash(uint64(slot))
|
||||||
|
newExecutionPayloadCapella := &v1.ExecutionPayloadElectra{
|
||||||
|
ParentHash: parentExecution.BlockHash(),
|
||||||
|
FeeRecipient: make([]byte, 20),
|
||||||
|
StateRoot: params.BeaconConfig().ZeroHash[:],
|
||||||
|
ReceiptsRoot: params.BeaconConfig().ZeroHash[:],
|
||||||
|
LogsBloom: make([]byte, 256),
|
||||||
|
PrevRandao: random,
|
||||||
|
BlockNumber: uint64(slot),
|
||||||
|
ExtraData: params.BeaconConfig().ZeroHash[:],
|
||||||
|
BaseFeePerGas: params.BeaconConfig().ZeroHash[:],
|
||||||
|
BlockHash: blockHash[:],
|
||||||
|
Timestamp: uint64(timestamp.Unix()),
|
||||||
|
Transactions: newTransactions,
|
||||||
|
Withdrawals: newWithdrawals,
|
||||||
|
}
|
||||||
|
var syncCommitteeBits []byte
|
||||||
|
currSize := new(ethpb.SyncAggregate).SyncCommitteeBits.Len()
|
||||||
|
switch currSize {
|
||||||
|
case 512:
|
||||||
|
syncCommitteeBits = bitfield.NewBitvector512()
|
||||||
|
case 32:
|
||||||
|
syncCommitteeBits = bitfield.NewBitvector32()
|
||||||
|
default:
|
||||||
|
return nil, errors.New("invalid bit vector size")
|
||||||
|
}
|
||||||
|
newSyncAggregate := ðpb.SyncAggregate{
|
||||||
|
SyncCommitteeBits: syncCommitteeBits,
|
||||||
|
SyncCommitteeSignature: append([]byte{0xC0}, make([]byte, 95)...),
|
||||||
|
}
|
||||||
|
|
||||||
|
newHeader := bState.LatestBlockHeader()
|
||||||
|
prevStateRoot, err := bState.HashTreeRoot(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not hash state")
|
||||||
|
}
|
||||||
|
newHeader.StateRoot = prevStateRoot[:]
|
||||||
|
parentRoot, err := newHeader.HashTreeRoot()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not hash the new header")
|
||||||
|
}
|
||||||
|
|
||||||
|
if slot == currentSlot {
|
||||||
|
slot = currentSlot + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
reveal, err := RandaoReveal(stCopy, time.CurrentEpoch(stCopy), privs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not compute randao reveal")
|
||||||
|
}
|
||||||
|
|
||||||
|
idx, err := helpers.BeaconProposerIndex(ctx, stCopy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not compute beacon proposer index")
|
||||||
|
}
|
||||||
|
|
||||||
|
changes := make([]*ethpb.SignedBLSToExecutionChange, conf.NumBLSChanges)
|
||||||
|
for i := uint64(0); i < conf.NumBLSChanges; i++ {
|
||||||
|
changes[i], err = GenerateBLSToExecutionChange(bState, privs[i+1], primitives.ValidatorIndex(i))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
block := ðpb.BeaconBlockElectra{
|
||||||
|
Slot: slot,
|
||||||
|
ParentRoot: parentRoot[:],
|
||||||
|
ProposerIndex: idx,
|
||||||
|
Body: ðpb.BeaconBlockBodyElectra{
|
||||||
|
Eth1Data: eth1Data,
|
||||||
|
RandaoReveal: reveal,
|
||||||
|
ProposerSlashings: pSlashings,
|
||||||
|
AttesterSlashings: aSlashings,
|
||||||
|
Attestations: atts,
|
||||||
|
VoluntaryExits: exits,
|
||||||
|
Deposits: newDeposits,
|
||||||
|
Graffiti: make([]byte, fieldparams.RootLength),
|
||||||
|
SyncAggregate: newSyncAggregate,
|
||||||
|
ExecutionPayload: newExecutionPayloadCapella,
|
||||||
|
BlsToExecutionChanges: changes,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// The fork can change after processing the state
|
||||||
|
signature, err := BlockSignature(bState, block, privs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not compute block signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ðpb.SignedBeaconBlockElectra{Block: block, Signature: signature.Marshal()}, nil
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package util
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -54,8 +55,12 @@ func BlockSignature(
|
|||||||
wsb, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: b})
|
wsb, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: b})
|
||||||
case *ethpb.BeaconBlockCapella:
|
case *ethpb.BeaconBlockCapella:
|
||||||
wsb, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockCapella{Block: b})
|
wsb, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockCapella{Block: b})
|
||||||
|
case *ethpb.BeaconBlockDeneb:
|
||||||
|
wsb, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockDeneb{Block: b})
|
||||||
|
case *ethpb.BeaconBlockElectra:
|
||||||
|
wsb, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockElectra{Block: b})
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("unsupported block type")
|
return nil, fmt.Errorf("unsupported block type %T", b)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "could not wrap block")
|
return nil, errors.Wrap(err, "could not wrap block")
|
||||||
@@ -74,6 +79,10 @@ func BlockSignature(
|
|||||||
b.StateRoot = s[:]
|
b.StateRoot = s[:]
|
||||||
case *ethpb.BeaconBlockCapella:
|
case *ethpb.BeaconBlockCapella:
|
||||||
b.StateRoot = s[:]
|
b.StateRoot = s[:]
|
||||||
|
case *ethpb.BeaconBlockDeneb:
|
||||||
|
b.StateRoot = s[:]
|
||||||
|
case *ethpb.BeaconBlockElectra:
|
||||||
|
b.StateRoot = s[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporarily increasing the beacon state slot here since BeaconProposerIndex is a
|
// Temporarily increasing the beacon state slot here since BeaconProposerIndex is a
|
||||||
@@ -88,6 +97,10 @@ func BlockSignature(
|
|||||||
blockSlot = b.Slot
|
blockSlot = b.Slot
|
||||||
case *ethpb.BeaconBlockCapella:
|
case *ethpb.BeaconBlockCapella:
|
||||||
blockSlot = b.Slot
|
blockSlot = b.Slot
|
||||||
|
case *ethpb.BeaconBlockDeneb:
|
||||||
|
blockSlot = b.Slot
|
||||||
|
case *ethpb.BeaconBlockElectra:
|
||||||
|
blockSlot = b.Slot
|
||||||
}
|
}
|
||||||
|
|
||||||
// process slots to get the right fork
|
// process slots to get the right fork
|
||||||
@@ -111,6 +124,10 @@ func BlockSignature(
|
|||||||
blockRoot, err = signing.ComputeSigningRoot(b, domain)
|
blockRoot, err = signing.ComputeSigningRoot(b, domain)
|
||||||
case *ethpb.BeaconBlockCapella:
|
case *ethpb.BeaconBlockCapella:
|
||||||
blockRoot, err = signing.ComputeSigningRoot(b, domain)
|
blockRoot, err = signing.ComputeSigningRoot(b, domain)
|
||||||
|
case *ethpb.BeaconBlockDeneb:
|
||||||
|
blockRoot, err = signing.ComputeSigningRoot(b, domain)
|
||||||
|
case *ethpb.BeaconBlockElectra:
|
||||||
|
blockRoot, err = signing.ComputeSigningRoot(b, domain)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -122,10 +122,18 @@ func generateMarshalledFullStateAndBlock() error {
|
|||||||
|
|
||||||
var atts []*ethpb.Attestation
|
var atts []*ethpb.Attestation
|
||||||
for i := slotOffset + 1; i < slotsPerEpoch+slotOffset; i++ {
|
for i := slotOffset + 1; i < slotsPerEpoch+slotOffset; i++ {
|
||||||
attsForSlot, err := util.GenerateAttestations(beaconState, privs, attConfig.NumAttestations, i, false)
|
generatedAttsForSlot, err := util.GenerateAttestations(beaconState, privs, attConfig.NumAttestations, i, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
attsForSlot := make([]*ethpb.Attestation, len(generatedAttsForSlot))
|
||||||
|
for j, att := range generatedAttsForSlot {
|
||||||
|
a, ok := att.(*ethpb.Attestation)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("attestation is not of type *ethpb.Attestation")
|
||||||
|
}
|
||||||
|
attsForSlot[j] = a
|
||||||
|
}
|
||||||
atts = append(atts, attsForSlot...)
|
atts = append(atts, attsForSlot...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user