mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-06 22:23:56 -05:00
* Ran gopls modernize to fix everything go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./... * Override rules_go provided dependency for golang.org/x/tools to v0.38.0. To update this, checked out rules_go, then ran `bazel run //go/tools/releaser -- upgrade-dep -mirror=false org_golang_x_tools` and copied the patches. * Fix buildtag violations and ignore buildtag violations in external * Introduce modernize analyzer package. * Add modernize "any" analyzer. * Fix violations of any analyzer * Add modernize "appendclipped" analyzer. * Fix violations of appendclipped * Add modernize "bloop" analyzer. * Add modernize "fmtappendf" analyzer. * Add modernize "forvar" analyzer. * Add modernize "mapsloop" analyzer. * Add modernize "minmax" analyzer. * Fix violations of minmax analyzer * Add modernize "omitzero" analyzer. * Add modernize "rangeint" analyzer. * Fix violations of rangeint. * Add modernize "reflecttypefor" analyzer. * Fix violations of reflecttypefor analyzer. * Add modernize "slicescontains" analyzer. * Add modernize "slicessort" analyzer. * Add modernize "slicesdelete" analyzer. This is disabled by default for now. See https://go.dev/issue/73686. * Add modernize "stringscutprefix" analyzer. * Add modernize "stringsbuilder" analyzer. * Fix violations of stringsbuilder analyzer. * Add modernize "stringsseq" analyzer. * Add modernize "testingcontext" analyzer. * Add modernize "waitgroup" analyzer. * Changelog fragment * gofmt * gazelle * Add modernize "newexpr" analyzer. * Disable newexpr until go1.26 * Add more details in WORKSPACE on how to update the override * @nalepae feedback on min() * gofmt * Fix violations of forvar
362 lines
13 KiB
Go
362 lines
13 KiB
Go
package altair_test
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
|
|
"github.com/OffchainLabs/go-bitfield"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/altair"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/time"
|
|
p2pType "github.com/OffchainLabs/prysm/v7/beacon-chain/p2p/types"
|
|
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
|
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
|
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
|
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
|
"github.com/OffchainLabs/prysm/v7/testing/require"
|
|
"github.com/OffchainLabs/prysm/v7/testing/util"
|
|
"github.com/OffchainLabs/prysm/v7/time/slots"
|
|
)
|
|
|
|
func TestProcessSyncCommittee_PerfectParticipation(t *testing.T) {
|
|
beaconState, privKeys := util.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
|
require.NoError(t, beaconState.SetSlot(1))
|
|
committee, err := altair.NextSyncCommittee(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
|
|
|
syncBits := bitfield.NewBitvector512()
|
|
for i := range syncBits {
|
|
syncBits[i] = 0xff
|
|
}
|
|
indices, err := altair.NextSyncCommitteeIndices(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
ps := slots.PrevSlot(beaconState.Slot())
|
|
pbr, err := helpers.BlockRootAtSlot(beaconState, ps)
|
|
require.NoError(t, err)
|
|
sigs := make([]bls.Signature, len(indices))
|
|
for i, indice := range indices {
|
|
b := p2pType.SSZBytes(pbr)
|
|
sb, err := signing.ComputeDomainAndSign(beaconState, time.CurrentEpoch(beaconState), &b, params.BeaconConfig().DomainSyncCommittee, privKeys[indice])
|
|
require.NoError(t, err)
|
|
sig, err := bls.SignatureFromBytes(sb)
|
|
require.NoError(t, err)
|
|
sigs[i] = sig
|
|
}
|
|
aggregatedSig := bls.AggregateSignatures(sigs).Marshal()
|
|
syncAggregate := ðpb.SyncAggregate{
|
|
SyncCommitteeBits: syncBits,
|
|
SyncCommitteeSignature: aggregatedSig,
|
|
}
|
|
|
|
// Verify that ProcessSyncAggregateNoVerifySig and ProcessSyncAggregate have the same outcome.
|
|
beaconStateNoVerifySig := beaconState.Copy()
|
|
beaconStateNoVerifySig, rewardNoVerifySig, err := altair.ProcessSyncAggregateNoVerifySig(t.Context(), beaconStateNoVerifySig, syncAggregate)
|
|
require.NoError(t, err)
|
|
sszNoVerifySig, err := beaconStateNoVerifySig.MarshalSSZ()
|
|
require.NoError(t, err)
|
|
var reward uint64
|
|
beaconState, reward, err = altair.ProcessSyncAggregate(t.Context(), beaconState, syncAggregate)
|
|
require.NoError(t, err)
|
|
ssz, err := beaconState.MarshalSSZ()
|
|
require.NoError(t, err)
|
|
assert.DeepEqual(t, sszNoVerifySig, ssz, "States resulting from ProcessSyncAggregateNoVerifySig and ProcessSyncAggregate are not equal")
|
|
assert.Equal(t, rewardNoVerifySig, reward, "Rewards resulting from ProcessSyncAggregateNoVerifySig and ProcessSyncAggregate are not equal")
|
|
assert.Equal(t, uint64(72192), reward)
|
|
|
|
// Use a non-sync committee index to compare profitability.
|
|
syncCommittee := make(map[primitives.ValidatorIndex]bool)
|
|
for _, index := range indices {
|
|
syncCommittee[index] = true
|
|
}
|
|
nonSyncIndex := primitives.ValidatorIndex(params.BeaconConfig().MaxValidatorsPerCommittee + 1)
|
|
for i := primitives.ValidatorIndex(0); uint64(i) < params.BeaconConfig().MaxValidatorsPerCommittee; i++ {
|
|
if !syncCommittee[i] {
|
|
nonSyncIndex = i
|
|
break
|
|
}
|
|
}
|
|
|
|
// Sync committee should be more profitable than non sync committee
|
|
balances := beaconState.Balances()
|
|
require.Equal(t, true, balances[indices[0]] > balances[nonSyncIndex])
|
|
|
|
// Proposer should be more profitable than rest of the sync committee
|
|
proposerIndex, err := helpers.BeaconProposerIndex(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
require.Equal(t, true, balances[proposerIndex] > balances[indices[0]])
|
|
|
|
// Sync committee should have the same profits, except you are a proposer
|
|
for i := 1; i < len(indices); i++ {
|
|
if proposerIndex == indices[i-1] || proposerIndex == indices[i] {
|
|
continue
|
|
}
|
|
require.Equal(t, balances[indices[i-1]], balances[indices[i]])
|
|
}
|
|
|
|
// Increased balance validator count should equal to sync committee count
|
|
increased := uint64(0)
|
|
for _, balance := range balances {
|
|
if balance > params.BeaconConfig().MaxEffectiveBalance {
|
|
increased++
|
|
}
|
|
}
|
|
require.Equal(t, params.BeaconConfig().SyncCommitteeSize, increased)
|
|
}
|
|
|
|
func TestProcessSyncCommittee_MixParticipation_BadSignature(t *testing.T) {
|
|
beaconState, privKeys := util.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
|
require.NoError(t, beaconState.SetSlot(1))
|
|
committee, err := altair.NextSyncCommittee(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
|
|
|
syncBits := bitfield.NewBitvector512()
|
|
for i := range syncBits {
|
|
syncBits[i] = 0xAA
|
|
}
|
|
indices, err := altair.NextSyncCommitteeIndices(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
ps := slots.PrevSlot(beaconState.Slot())
|
|
pbr, err := helpers.BlockRootAtSlot(beaconState, ps)
|
|
require.NoError(t, err)
|
|
sigs := make([]bls.Signature, len(indices))
|
|
for i, indice := range indices {
|
|
b := p2pType.SSZBytes(pbr)
|
|
sb, err := signing.ComputeDomainAndSign(beaconState, time.CurrentEpoch(beaconState), &b, params.BeaconConfig().DomainSyncCommittee, privKeys[indice])
|
|
require.NoError(t, err)
|
|
sig, err := bls.SignatureFromBytes(sb)
|
|
require.NoError(t, err)
|
|
sigs[i] = sig
|
|
}
|
|
aggregatedSig := bls.AggregateSignatures(sigs).Marshal()
|
|
syncAggregate := ðpb.SyncAggregate{
|
|
SyncCommitteeBits: syncBits,
|
|
SyncCommitteeSignature: aggregatedSig,
|
|
}
|
|
|
|
_, _, err = altair.ProcessSyncAggregate(t.Context(), beaconState, syncAggregate)
|
|
require.ErrorContains(t, "invalid sync committee signature", err)
|
|
}
|
|
|
|
func TestProcessSyncCommittee_MixParticipation_GoodSignature(t *testing.T) {
|
|
beaconState, privKeys := util.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
|
require.NoError(t, beaconState.SetSlot(1))
|
|
committee, err := altair.NextSyncCommittee(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
|
|
|
syncBits := bitfield.NewBitvector512()
|
|
for i := range syncBits {
|
|
syncBits[i] = 0xAA
|
|
}
|
|
indices, err := altair.NextSyncCommitteeIndices(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
ps := slots.PrevSlot(beaconState.Slot())
|
|
pbr, err := helpers.BlockRootAtSlot(beaconState, ps)
|
|
require.NoError(t, err)
|
|
sigs := make([]bls.Signature, 0, len(indices))
|
|
for i, indice := range indices {
|
|
if syncBits.BitAt(uint64(i)) {
|
|
b := p2pType.SSZBytes(pbr)
|
|
sb, err := signing.ComputeDomainAndSign(beaconState, time.CurrentEpoch(beaconState), &b, params.BeaconConfig().DomainSyncCommittee, privKeys[indice])
|
|
require.NoError(t, err)
|
|
sig, err := bls.SignatureFromBytes(sb)
|
|
require.NoError(t, err)
|
|
sigs = append(sigs, sig)
|
|
}
|
|
}
|
|
aggregatedSig := bls.AggregateSignatures(sigs).Marshal()
|
|
syncAggregate := ðpb.SyncAggregate{
|
|
SyncCommitteeBits: syncBits,
|
|
SyncCommitteeSignature: aggregatedSig,
|
|
}
|
|
|
|
_, _, err = altair.ProcessSyncAggregate(t.Context(), beaconState, syncAggregate)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// This is a regression test #11696
|
|
func TestProcessSyncCommittee_DontPrecompute(t *testing.T) {
|
|
beaconState, _ := util.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
|
require.NoError(t, beaconState.SetSlot(1))
|
|
committee, err := altair.NextSyncCommittee(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
committeeKeys := committee.Pubkeys
|
|
committeeKeys[1] = committeeKeys[0]
|
|
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
|
idx, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(committeeKeys[0]))
|
|
require.Equal(t, true, ok)
|
|
|
|
syncBits := bitfield.NewBitvector512()
|
|
for i := range syncBits {
|
|
syncBits[i] = 0xFF
|
|
}
|
|
syncBits.SetBitAt(0, false)
|
|
syncAggregate := ðpb.SyncAggregate{
|
|
SyncCommitteeBits: syncBits,
|
|
}
|
|
require.NoError(t, beaconState.UpdateBalancesAtIndex(idx, 0))
|
|
st, votedKeys, _, err := altair.ProcessSyncAggregateEported(t.Context(), beaconState, syncAggregate)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 511, len(votedKeys))
|
|
require.DeepEqual(t, committeeKeys[0], votedKeys[0].Marshal())
|
|
balances := st.Balances()
|
|
require.Equal(t, uint64(988), balances[idx])
|
|
}
|
|
|
|
func TestProcessSyncCommittee_processSyncAggregate(t *testing.T) {
|
|
beaconState, _ := util.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
|
require.NoError(t, beaconState.SetSlot(1))
|
|
committee, err := altair.NextSyncCommittee(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
|
|
|
syncBits := bitfield.NewBitvector512()
|
|
for i := range syncBits {
|
|
syncBits[i] = 0xAA
|
|
}
|
|
syncAggregate := ðpb.SyncAggregate{
|
|
SyncCommitteeBits: syncBits,
|
|
}
|
|
|
|
st, votedKeys, _, err := altair.ProcessSyncAggregateEported(t.Context(), beaconState, syncAggregate)
|
|
require.NoError(t, err)
|
|
votedMap := make(map[[fieldparams.BLSPubkeyLength]byte]bool)
|
|
for _, key := range votedKeys {
|
|
votedMap[bytesutil.ToBytes48(key.Marshal())] = true
|
|
}
|
|
require.Equal(t, int(syncBits.Len()/2), len(votedKeys))
|
|
|
|
currentSyncCommittee, err := st.CurrentSyncCommittee()
|
|
require.NoError(t, err)
|
|
committeeKeys := currentSyncCommittee.Pubkeys
|
|
balances := st.Balances()
|
|
|
|
proposerIndex, err := helpers.BeaconProposerIndex(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
|
|
for i := range syncBits {
|
|
if syncBits.BitAt(uint64(i)) {
|
|
pk := bytesutil.ToBytes48(committeeKeys[i])
|
|
require.DeepEqual(t, true, votedMap[pk])
|
|
idx, ok := st.ValidatorIndexByPubkey(pk)
|
|
require.Equal(t, true, ok)
|
|
require.Equal(t, uint64(32000000988), balances[idx])
|
|
} else {
|
|
pk := bytesutil.ToBytes48(committeeKeys[i])
|
|
require.DeepEqual(t, false, votedMap[pk])
|
|
idx, ok := st.ValidatorIndexByPubkey(pk)
|
|
require.Equal(t, true, ok)
|
|
if idx != proposerIndex {
|
|
require.Equal(t, uint64(31999999012), balances[idx])
|
|
}
|
|
}
|
|
}
|
|
require.Equal(t, uint64(32000035108), balances[proposerIndex])
|
|
}
|
|
|
|
func Test_VerifySyncCommitteeSig(t *testing.T) {
|
|
beaconState, privKeys := util.DeterministicGenesisStateAltair(t, params.BeaconConfig().MaxValidatorsPerCommittee)
|
|
require.NoError(t, beaconState.SetSlot(1))
|
|
committee, err := altair.NextSyncCommittee(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
|
|
|
|
syncBits := bitfield.NewBitvector512()
|
|
for i := range syncBits {
|
|
syncBits[i] = 0xff
|
|
}
|
|
indices, err := altair.NextSyncCommitteeIndices(t.Context(), beaconState)
|
|
require.NoError(t, err)
|
|
ps := slots.PrevSlot(beaconState.Slot())
|
|
pbr, err := helpers.BlockRootAtSlot(beaconState, ps)
|
|
require.NoError(t, err)
|
|
sigs := make([]bls.Signature, len(indices))
|
|
pks := make([]bls.PublicKey, len(indices))
|
|
for i, indice := range indices {
|
|
b := p2pType.SSZBytes(pbr)
|
|
sb, err := signing.ComputeDomainAndSign(beaconState, time.CurrentEpoch(beaconState), &b, params.BeaconConfig().DomainSyncCommittee, privKeys[indice])
|
|
require.NoError(t, err)
|
|
sig, err := bls.SignatureFromBytes(sb)
|
|
require.NoError(t, err)
|
|
sigs[i] = sig
|
|
pks[i] = privKeys[indice].PublicKey()
|
|
}
|
|
aggregatedSig := bls.AggregateSignatures(sigs).Marshal()
|
|
|
|
blsKey, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
require.ErrorContains(t, "invalid sync committee signature", altair.VerifySyncCommitteeSig(beaconState, pks, blsKey.Sign([]byte{'m', 'e', 'o', 'w'}).Marshal()))
|
|
|
|
require.NoError(t, altair.VerifySyncCommitteeSig(beaconState, pks, aggregatedSig))
|
|
}
|
|
|
|
func Test_SyncRewards(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
activeBalance uint64
|
|
wantProposerReward uint64
|
|
wantParticipantReward uint64
|
|
errString string
|
|
}{
|
|
{
|
|
name: "active balance is 0",
|
|
activeBalance: 0,
|
|
wantProposerReward: 0,
|
|
wantParticipantReward: 0,
|
|
errString: "active balance can't be 0",
|
|
},
|
|
{
|
|
name: "active balance is 1",
|
|
activeBalance: 1,
|
|
wantProposerReward: 0,
|
|
wantParticipantReward: 0,
|
|
errString: "",
|
|
},
|
|
{
|
|
name: "active balance is 1eth",
|
|
activeBalance: params.BeaconConfig().EffectiveBalanceIncrement,
|
|
wantProposerReward: 0,
|
|
wantParticipantReward: 3,
|
|
errString: "",
|
|
},
|
|
{
|
|
name: "active balance is 32eth",
|
|
activeBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
wantProposerReward: 3,
|
|
wantParticipantReward: 21,
|
|
errString: "",
|
|
},
|
|
{
|
|
name: "active balance is 32eth * 1m validators",
|
|
activeBalance: params.BeaconConfig().MaxEffectiveBalance * 1e9,
|
|
wantProposerReward: 62780,
|
|
wantParticipantReward: 439463,
|
|
errString: "",
|
|
},
|
|
{
|
|
name: "active balance is max uint64",
|
|
activeBalance: math.MaxUint64,
|
|
wantProposerReward: 70368,
|
|
wantParticipantReward: 492581,
|
|
errString: "",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
proposerReward, participantReward, err := altair.SyncRewards(tt.activeBalance)
|
|
if (err != nil) && (tt.errString != "") {
|
|
require.ErrorContains(t, tt.errString, err)
|
|
return
|
|
}
|
|
require.Equal(t, tt.wantProposerReward, proposerReward)
|
|
require.Equal(t, tt.wantParticipantReward, participantReward)
|
|
})
|
|
}
|
|
}
|