mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 21:08:10 -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.
|
||||
committee, err := helpers.BeaconCommitteeFromState(ctx, baseState, a.GetData().Slot, a.GetData().CommitteeIndex)
|
||||
committees, err := helpers.AttestationCommittees(ctx, baseState, a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexedAtt, err := attestation.ConvertToIndexed(ctx, a, committee)
|
||||
indexedAtt, err := attestation.ConvertToIndexed(ctx, a, committees...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@ import (
|
||||
"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"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"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) {
|
||||
service, tr := minimalTestService(t)
|
||||
ctx := tr.ctx
|
||||
eval := func(ctx context.Context, service *Service, genesisState state.BeaconState, pks []bls.SecretKey) {
|
||||
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)
|
||||
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].Data.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))
|
||||
t.Run("pre-Electra", func(t *testing.T) {
|
||||
service, tr := minimalTestService(t)
|
||||
ctx := tr.ctx
|
||||
genesisState, pks := util.DeterministicGenesisState(t, 64)
|
||||
eval(ctx, service, genesisState, pks)
|
||||
})
|
||||
t.Run("post-Electra", func(t *testing.T) {
|
||||
service, tr := minimalTestService(t)
|
||||
ctx := tr.ctx
|
||||
genesisState, pks := util.DeterministicGenesisStateElectra(t, 64)
|
||||
eval(ctx, service, genesisState, pks)
|
||||
})
|
||||
}
|
||||
|
||||
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 {
|
||||
// Feed in block's attestations to fork choice store.
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
indices, err := attestation.AttestingIndices(a, committee)
|
||||
indices, err := attestation.AttestingIndices(a, committees...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1963,68 +1963,130 @@ func TestNoViableHead_Reboot(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOnBlock_HandleBlockAttestations(t *testing.T) {
|
||||
service, tr := minimalTestService(t)
|
||||
ctx := tr.ctx
|
||||
t.Run("pre-Electra", func(t *testing.T) {
|
||||
service, tr := minimalTestService(t)
|
||||
ctx := tr.ctx
|
||||
|
||||
st, keys := util.DeterministicGenesisState(t, 64)
|
||||
stateRoot, err := st.HashTreeRoot(ctx)
|
||||
require.NoError(t, err, "Could not hash genesis state")
|
||||
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))
|
||||
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")
|
||||
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")
|
||||
|
||||
st, err = service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
b, err := util.GenerateFullBlock(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.GenerateFullBlock(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.GenerateFullBlock(st, keys, util.DefaultBlockGenConfig(), 2)
|
||||
require.NoError(t, err)
|
||||
wsb, err = consensusblocks.NewSignedBeaconBlock(b)
|
||||
require.NoError(t, err)
|
||||
st, err = service.HeadState(ctx)
|
||||
require.NoError(t, err)
|
||||
b, err = util.GenerateFullBlock(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.GenerateFullBlock(st3, keys, util.DefaultBlockGenConfig(), 3)
|
||||
require.NoError(t, err)
|
||||
wsb3, err := consensusblocks.NewSignedBeaconBlock(b3)
|
||||
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.GenerateFullBlock(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()))
|
||||
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.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()))
|
||||
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()))
|
||||
})
|
||||
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) {
|
||||
|
||||
@@ -73,7 +73,7 @@ func TestProcessAttestations_Ok(t *testing.T) {
|
||||
require.NoError(t, service.saveGenesisData(ctx, genesisState))
|
||||
atts, err := util.GenerateAttestations(genesisState, pks, 1, 0, false)
|
||||
require.NoError(t, err)
|
||||
tRoot := bytesutil.ToBytes32(atts[0].Data.Target.Root)
|
||||
tRoot := bytesutil.ToBytes32(atts[0].GetData().Target.Root)
|
||||
copied := genesisState.Copy()
|
||||
copied, err = transition.ProcessSlots(ctx, copied, 1)
|
||||
require.NoError(t, err)
|
||||
@@ -131,8 +131,8 @@ func TestService_ProcessAttestationsAndUpdateHead(t *testing.T) {
|
||||
}
|
||||
require.NoError(t, service.cfg.AttPool.SaveForkchoiceAttestations(attsToSave))
|
||||
// Verify the target is in forkchoice
|
||||
require.Equal(t, true, fcs.HasNode(bytesutil.ToBytes32(atts[0].Data.BeaconBlockRoot)))
|
||||
require.Equal(t, tRoot, 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].GetData().BeaconBlockRoot))
|
||||
require.Equal(t, true, fcs.HasNode(service.originBlockRoot))
|
||||
|
||||
// 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.
|
||||
ctx := context.TODO()
|
||||
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 {
|
||||
log.WithError(err).Error("Could not get attestation committee")
|
||||
log.WithError(err).Error("Could not get attestation committees")
|
||||
return
|
||||
}
|
||||
indexedAtt, err := attestation.ConvertToIndexed(ctx, att, committee)
|
||||
indexedAtt, err := attestation.ConvertToIndexed(ctx, att, committees...)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not convert to indexed attestation")
|
||||
return
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filesystem"
|
||||
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"
|
||||
doublylinkedtree "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/doubly-linked-tree"
|
||||
"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()),
|
||||
WithBlobStorage(filesystem.NewEphemeralBlobStorage(t)),
|
||||
WithSyncChecker(mock.MockChecker{}),
|
||||
WithExecutionEngineCaller(&mockExecution.EngineClient{}),
|
||||
}
|
||||
// append the variadic opts so they override the defaults by being processed afterwards
|
||||
opts = append(defOpts, opts...)
|
||||
|
||||
@@ -66,11 +66,11 @@ func ProcessAttestationNoVerifySignature(
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
indices, err := attestation.AttestingIndices(att, committee)
|
||||
indices, err := attestation.AttestingIndices(att, committees...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -195,47 +195,95 @@ func TestProcessAttestations_InvalidAggregationBitsLength(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.SetBitAt(0, true)
|
||||
var mockRoot [32]byte
|
||||
copy(mockRoot[:], "hello-world")
|
||||
att := util.HydrateAttestation(ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||
},
|
||||
AggregationBits: aggBits,
|
||||
aggBits := bitfield.NewBitlist(3)
|
||||
aggBits.SetBitAt(0, true)
|
||||
var mockRoot [32]byte
|
||||
copy(mockRoot[:], "hello-world")
|
||||
att := util.HydrateAttestation(ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||
Target: ðpb.Checkpoint{Root: mockRoot[:]},
|
||||
},
|
||||
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()
|
||||
cfc.Root = mockRoot[:]
|
||||
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc))
|
||||
aggBits := bitfield.NewBitlist(3)
|
||||
aggBits.SetBitAt(0, true)
|
||||
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)
|
||||
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])
|
||||
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)
|
||||
sig, err := bls.SignatureFromBytes(sb)
|
||||
attestingIndices, err := attestation.AttestingIndices(att, committee)
|
||||
require.NoError(t, err)
|
||||
sigs[i] = sig
|
||||
}
|
||||
att.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
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}
|
||||
block := util.NewBeaconBlockElectra()
|
||||
block.Block.Body.Attestations = []*ethpb.AttestationElectra{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)
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
func TestProcessAttestationNoVerify_SourceTargetHead(t *testing.T) {
|
||||
|
||||
@@ -154,7 +154,7 @@ func TranslateParticipation(ctx context.Context, state state.BeaconState, atts [
|
||||
if err != nil {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -200,23 +200,6 @@ func ProcessAttestationNoVerifySignature(
|
||||
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.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
|
||||
@@ -578,53 +578,109 @@ func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing
|
||||
}
|
||||
}
|
||||
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(5))
|
||||
require.NoError(t, st.SetValidators(validators))
|
||||
t.Run("pre-Electra", func(t *testing.T) {
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(5))
|
||||
require.NoError(t, st.SetValidators(validators))
|
||||
|
||||
comm1, err := helpers.BeaconCommitteeFromState(context.Background(), st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||
require.NoError(t, err)
|
||||
att1 := util.HydrateAttestation(ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: 1,
|
||||
},
|
||||
comm1, err := helpers.BeaconCommitteeFromState(context.Background(), st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||
require.NoError(t, err)
|
||||
att1 := util.HydrateAttestation(ðpb.Attestation{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
||||
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)
|
||||
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())
|
||||
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()
|
||||
t.Run("post-Electra", func(t *testing.T) {
|
||||
st, err := util.NewBeaconStateElectra()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(5))
|
||||
require.NoError(t, st.SetValidators(validators))
|
||||
|
||||
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,
|
||||
},
|
||||
comm1, err := helpers.BeaconCommitteeFromState(context.Background(), st, 1 /*slot*/, 0 /*committeeIndex*/)
|
||||
require.NoError(t, err)
|
||||
commBits1 := primitives.NewAttestationCommitteeBits()
|
||||
commBits1.SetBitAt(0, true)
|
||||
att1 := util.HydrateAttestationElectra(ðpb.AttestationElectra{
|
||||
AggregationBits: bitfield.NewBitlist(uint64(len(comm1))),
|
||||
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) {
|
||||
|
||||
@@ -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) {
|
||||
fuzzer := fuzz.NewWithSeed(0)
|
||||
state := ðpb.BeaconState{}
|
||||
|
||||
@@ -163,7 +163,42 @@ func NewGenesisBlockForState(ctx context.Context, st state.BeaconState) (interfa
|
||||
SyncCommitteeBits: make([]byte, fieldparams.SyncCommitteeLength/8),
|
||||
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),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: make([]byte, 32),
|
||||
|
||||
@@ -192,11 +192,11 @@ func createAttestationSignatureBatch(
|
||||
descs := make([]string, len(atts))
|
||||
for i, a := range atts {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
ia, err := attestation.ConvertToIndexed(ctx, a, c)
|
||||
ia, err := attestation.ConvertToIndexed(ctx, a, committees...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -470,7 +470,7 @@ func UnslashedAttestingIndices(ctx context.Context, state state.ReadOnlyBeaconSt
|
||||
seen := make(map[uint64]bool)
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ go_library(
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//math:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"//time:go_default_library",
|
||||
"//time/slots: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/math"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
"github.com/prysmaticlabs/prysm/v5/time/slots"
|
||||
)
|
||||
|
||||
@@ -58,6 +59,29 @@ func SlotCommitteeCount(activeValidatorCount uint64) uint64 {
|
||||
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
|
||||
// is a spec implementation where state is used as an argument. In case of state retrieval
|
||||
// becomes expensive, consider using BeaconCommittee below.
|
||||
|
||||
@@ -715,3 +715,37 @@ func TestCommitteeIndices(t *testing.T) {
|
||||
indices := helpers.CommitteeIndices(bitfield)
|
||||
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 {
|
||||
var slashings []*ethpb.AttesterSlashing
|
||||
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)
|
||||
slashings = append(slashings, slashing)
|
||||
slashings = append(slashings, generatedSlashing.(*ethpb.AttesterSlashing))
|
||||
}
|
||||
var allSig1 []bls.Signature
|
||||
var allSig2 []bls.Signature
|
||||
@@ -78,12 +78,14 @@ func TestPool_InsertAttesterSlashing(t *testing.T) {
|
||||
pendingSlashings := make([]*PendingAttesterSlashing, 20)
|
||||
slashings := make([]*ethpb.AttesterSlashing, 20)
|
||||
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)
|
||||
pendingSlashings[i] = &PendingAttesterSlashing{
|
||||
attesterSlashing: sl,
|
||||
attesterSlashing: generatedSl,
|
||||
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
|
||||
}
|
||||
require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch))
|
||||
@@ -303,12 +305,16 @@ func TestPool_InsertAttesterSlashing_SigFailsVerify_ClearPool(t *testing.T) {
|
||||
pendingSlashings := make([]*PendingAttesterSlashing, 2)
|
||||
slashings := make([]*ethpb.AttesterSlashing, 2)
|
||||
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)
|
||||
pendingSlashings[i] = &PendingAttesterSlashing{
|
||||
attesterSlashing: sl,
|
||||
attesterSlashing: generatedSl,
|
||||
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
|
||||
}
|
||||
// We mess up the signature of the second slashing.
|
||||
|
||||
@@ -66,13 +66,13 @@ func TestServer_SubmitAttesterSlashing(t *testing.T) {
|
||||
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)
|
||||
|
||||
// We want the intersection of the slashing attesting indices
|
||||
// to be slashed, so we expect validators 2 and 3 to be in the response
|
||||
// slashed indices.
|
||||
_, err = bs.SubmitAttesterSlashing(ctx, slashing)
|
||||
_, err = bs.SubmitAttesterSlashing(ctx, generatedSlashing.(*ethpb.AttesterSlashing))
|
||||
require.NoError(t, err)
|
||||
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,
|
||||
}
|
||||
|
||||
slashing, err := util.GenerateAttesterSlashingForValidator(st, privs[2], primitives.ValidatorIndex(2))
|
||||
generatedSlashing, err := util.GenerateAttesterSlashingForValidator(st, privs[2], primitives.ValidatorIndex(2))
|
||||
require.NoError(t, err)
|
||||
|
||||
// We want the intersection of the slashing attesting indices
|
||||
@@ -153,17 +153,17 @@ func TestServer_SubmitAttesterSlashing_DontBroadcast(t *testing.T) {
|
||||
wanted := ðpb.SubmitSlashingResponse{
|
||||
SlashedIndices: []primitives.ValidatorIndex{2},
|
||||
}
|
||||
res, err := bs.SubmitAttesterSlashing(ctx, slashing)
|
||||
res, err := bs.SubmitAttesterSlashing(ctx, generatedSlashing.(*ethpb.AttesterSlashing))
|
||||
require.NoError(t, err)
|
||||
if !proto.Equal(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")
|
||||
|
||||
slashing, err = util.GenerateAttesterSlashingForValidator(st, privs[5], primitives.ValidatorIndex(5))
|
||||
generatedSlashing, err = util.GenerateAttesterSlashingForValidator(st, privs[5], primitives.ValidatorIndex(5))
|
||||
require.NoError(t, err)
|
||||
// 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.
|
||||
_, 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")
|
||||
}
|
||||
|
||||
@@ -753,10 +753,12 @@ func injectSlashings(t *testing.T, st state.BeaconState, keys []bls.SecretKey, s
|
||||
|
||||
attSlashings := make([]*ethpb.AttesterSlashing, params.BeaconConfig().MaxAttesterSlashings)
|
||||
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)
|
||||
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
|
||||
err = server.SlashingsPool.InsertAttesterSlashing(context.Background(), st, attesterSlashing)
|
||||
err = server.SlashingsPool.InsertAttesterSlashing(context.Background(), st, generatedAttesterSlashing.(*ethpb.AttesterSlashing))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
return proposerSlashings, attSlashings
|
||||
|
||||
@@ -170,7 +170,7 @@ func TestSubscribe_ReceivesAttesterSlashing(t *testing.T) {
|
||||
1, /* validator index */
|
||||
)
|
||||
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)
|
||||
p2pService.ReceivePubSub(topic, attesterSlashing)
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"committee_bits_mainnet.go",
|
||||
"committee_bits_minimal.go", # keep
|
||||
"committee_index.go",
|
||||
"domain.go",
|
||||
"epoch.go",
|
||||
@@ -20,6 +22,7 @@ go_library(
|
||||
deps = [
|
||||
"//math: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",
|
||||
"deposits.go",
|
||||
"electra.go",
|
||||
"electra_block.go",
|
||||
"electra_state.go",
|
||||
"helpers.go",
|
||||
"merge.go",
|
||||
|
||||
@@ -345,19 +345,35 @@ func GenerateFullBlockAltair(
|
||||
numToGen = conf.NumAttesterSlashings
|
||||
var aSlashings []*ethpb.AttesterSlashing
|
||||
if numToGen > 0 {
|
||||
aSlashings, err = generateAttesterSlashings(bState, privs, numToGen)
|
||||
generated, err := generateAttesterSlashings(bState, privs, numToGen)
|
||||
if err != nil {
|
||||
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
|
||||
var atts []*ethpb.Attestation
|
||||
if numToGen > 0 {
|
||||
atts, err = GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||
generatedAtts, err := GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
@@ -2,7 +2,6 @@ package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
@@ -48,10 +47,8 @@ func NewAttestation() *ethpb.Attestation {
|
||||
// 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.
|
||||
func GenerateAttestations(
|
||||
bState state.BeaconState, privs []bls.SecretKey, numToGen uint64, slot primitives.Slot, randomRoot bool,
|
||||
) ([]*ethpb.Attestation, error) {
|
||||
var attestations []*ethpb.Attestation
|
||||
func GenerateAttestations(bState state.BeaconState, privs []bls.SecretKey, numToGen uint64, slot primitives.Slot, randomRoot bool) ([]ethpb.Att, error) { // nolint:gocognit
|
||||
var attestations []ethpb.Att
|
||||
generateHeadState := false
|
||||
bState = bState.Copy()
|
||||
if slot > bState.Slot() {
|
||||
@@ -108,8 +105,28 @@ func GenerateAttestations(
|
||||
return nil, err
|
||||
}
|
||||
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:
|
||||
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)
|
||||
@@ -180,9 +197,14 @@ func GenerateAttestations(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ci := c
|
||||
if bState.Version() >= version.Electra {
|
||||
// committee index must be 0 post-Electra
|
||||
ci = 0
|
||||
}
|
||||
attData := ðpb.AttestationData{
|
||||
Slot: slot,
|
||||
CommitteeIndex: c,
|
||||
CommitteeIndex: ci,
|
||||
BeaconBlockRoot: headRoot,
|
||||
Source: bState.CurrentJustifiedCheckpoint(),
|
||||
Target: ðpb.Checkpoint{
|
||||
@@ -211,10 +233,22 @@ func GenerateAttestations(
|
||||
continue
|
||||
}
|
||||
|
||||
att := ðpb.Attestation{
|
||||
Data: attData,
|
||||
AggregationBits: aggregationBits,
|
||||
Signature: bls.AggregateSignatures(sigs).Marshal(),
|
||||
var att ethpb.Att
|
||||
if bState.Version() >= version.Electra {
|
||||
cb := primitives.NewAttestationCommitteeBits()
|
||||
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)
|
||||
}
|
||||
@@ -238,6 +272,25 @@ func HydrateAttestation(a *ethpb.Attestation) *ethpb.Attestation {
|
||||
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
|
||||
// to comply with fssz marshalling and unmarshalling rules.
|
||||
func HydrateV1Attestation(a *attv1.Attestation) *attv1.Attestation {
|
||||
|
||||
@@ -56,19 +56,35 @@ func GenerateFullBlockBellatrix(
|
||||
numToGen = conf.NumAttesterSlashings
|
||||
var aSlashings []*ethpb.AttesterSlashing
|
||||
if numToGen > 0 {
|
||||
aSlashings, err = generateAttesterSlashings(bState, privs, numToGen)
|
||||
generated, err := generateAttesterSlashings(bState, privs, numToGen)
|
||||
if err != nil {
|
||||
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
|
||||
var atts []*ethpb.Attestation
|
||||
if numToGen > 0 {
|
||||
atts, err = GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||
generatedAtts, err := GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
v1 "github.com/prysmaticlabs/prysm/v5/proto/eth/v1"
|
||||
v2 "github.com/prysmaticlabs/prysm/v5/proto/eth/v2"
|
||||
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/require"
|
||||
)
|
||||
@@ -109,19 +110,35 @@ func GenerateFullBlock(
|
||||
numToGen = conf.NumAttesterSlashings
|
||||
var aSlashings []*ethpb.AttesterSlashing
|
||||
if numToGen > 0 {
|
||||
aSlashings, err = generateAttesterSlashings(bState, privs, numToGen)
|
||||
generated, err := generateAttesterSlashings(bState, privs, numToGen)
|
||||
if err != nil {
|
||||
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
|
||||
var atts []*ethpb.Attestation
|
||||
if numToGen > 0 {
|
||||
atts, err = GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||
generatedAtts, err := GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||
if err != nil {
|
||||
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
|
||||
@@ -265,9 +282,59 @@ func GenerateAttesterSlashingForValidator(
|
||||
bState state.BeaconState,
|
||||
priv bls.SecretKey,
|
||||
idx primitives.ValidatorIndex,
|
||||
) (*ethpb.AttesterSlashing, error) {
|
||||
) (ethpb.AttSlashing, error) {
|
||||
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{
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: bState.Slot(),
|
||||
@@ -321,8 +388,8 @@ func generateAttesterSlashings(
|
||||
bState state.BeaconState,
|
||||
privs []bls.SecretKey,
|
||||
numSlashings uint64,
|
||||
) ([]*ethpb.AttesterSlashing, error) {
|
||||
attesterSlashings := make([]*ethpb.AttesterSlashing, numSlashings)
|
||||
) ([]ethpb.AttSlashing, error) {
|
||||
attesterSlashings := make([]ethpb.AttSlashing, numSlashings)
|
||||
randGen := rand.NewDeterministicGenerator()
|
||||
for i := uint64(0); i < numSlashings; i++ {
|
||||
committeeIndex := randGen.Uint64() % helpers.SlotCommitteeCount(uint64(bState.NumValidators()))
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
// GenerateFullBlockCapella generates a fully valid Capella 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 GenerateFullBlockCapella(
|
||||
bState state.BeaconState,
|
||||
privs []bls.SecretKey,
|
||||
@@ -55,19 +54,35 @@ func GenerateFullBlockCapella(
|
||||
numToGen = conf.NumAttesterSlashings
|
||||
var aSlashings []*ethpb.AttesterSlashing
|
||||
if numToGen > 0 {
|
||||
aSlashings, err = generateAttesterSlashings(bState, privs, numToGen)
|
||||
generated, err := generateAttesterSlashings(bState, privs, numToGen)
|
||||
if err != nil {
|
||||
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
|
||||
var atts []*ethpb.Attestation
|
||||
if numToGen > 0 {
|
||||
atts, err = GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||
generatedAtts, err := GenerateAttestations(bState, privs, numToGen, slot, false)
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
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 (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -54,8 +55,12 @@ func BlockSignature(
|
||||
wsb, err = blocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: b})
|
||||
case *ethpb.BeaconBlockCapella:
|
||||
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:
|
||||
return nil, errors.New("unsupported block type")
|
||||
return nil, fmt.Errorf("unsupported block type %T", b)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not wrap block")
|
||||
@@ -74,6 +79,10 @@ func BlockSignature(
|
||||
b.StateRoot = s[:]
|
||||
case *ethpb.BeaconBlockCapella:
|
||||
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
|
||||
@@ -88,6 +97,10 @@ func BlockSignature(
|
||||
blockSlot = b.Slot
|
||||
case *ethpb.BeaconBlockCapella:
|
||||
blockSlot = b.Slot
|
||||
case *ethpb.BeaconBlockDeneb:
|
||||
blockSlot = b.Slot
|
||||
case *ethpb.BeaconBlockElectra:
|
||||
blockSlot = b.Slot
|
||||
}
|
||||
|
||||
// process slots to get the right fork
|
||||
@@ -111,6 +124,10 @@ func BlockSignature(
|
||||
blockRoot, err = signing.ComputeSigningRoot(b, domain)
|
||||
case *ethpb.BeaconBlockCapella:
|
||||
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 {
|
||||
return nil, err
|
||||
|
||||
@@ -122,10 +122,18 @@ func generateMarshalledFullStateAndBlock() error {
|
||||
|
||||
var atts []*ethpb.Attestation
|
||||
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 {
|
||||
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...)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user