github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/helpers/committee_test.go (about)

     1  package helpers
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strconv"
     7  	"testing"
     8  
     9  	types "github.com/prysmaticlabs/eth2-types"
    10  	"github.com/prysmaticlabs/go-bitfield"
    11  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    12  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    13  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    14  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    15  	"github.com/prysmaticlabs/prysm/shared/hashutil"
    16  	"github.com/prysmaticlabs/prysm/shared/params"
    17  	"github.com/prysmaticlabs/prysm/shared/sliceutil"
    18  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    19  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    20  )
    21  
    22  func TestComputeCommittee_WithoutCache(t *testing.T) {
    23  	// Create 10 committees
    24  	committeeCount := uint64(10)
    25  	validatorCount := committeeCount * params.BeaconConfig().TargetCommitteeSize
    26  	validators := make([]*ethpb.Validator, validatorCount)
    27  
    28  	for i := 0; i < len(validators); i++ {
    29  		k := make([]byte, 48)
    30  		copy(k, strconv.Itoa(i))
    31  		validators[i] = &ethpb.Validator{
    32  			PublicKey:             k,
    33  			WithdrawalCredentials: make([]byte, 32),
    34  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
    35  		}
    36  	}
    37  
    38  	state, err := v1.InitializeFromProto(&pb.BeaconState{
    39  		Validators:  validators,
    40  		Slot:        200,
    41  		BlockRoots:  make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
    42  		StateRoots:  make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
    43  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
    44  	})
    45  	require.NoError(t, err)
    46  
    47  	epoch := CurrentEpoch(state)
    48  	indices, err := ActiveValidatorIndices(state, epoch)
    49  	require.NoError(t, err)
    50  	seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
    51  	require.NoError(t, err)
    52  	committees, err := ComputeCommittee(indices, seed, 0, 1 /* Total committee*/)
    53  	assert.NoError(t, err, "Could not compute committee")
    54  
    55  	// Test shuffled indices are correct for index 5 committee
    56  	index := uint64(5)
    57  	committee5, err := ComputeCommittee(indices, seed, index, committeeCount)
    58  	assert.NoError(t, err, "Could not compute committee")
    59  	start := sliceutil.SplitOffset(validatorCount, committeeCount, index)
    60  	end := sliceutil.SplitOffset(validatorCount, committeeCount, index+1)
    61  	assert.DeepEqual(t, committee5, committees[start:end], "Committee has different shuffled indices")
    62  
    63  	// Test shuffled indices are correct for index 9 committee
    64  	index = uint64(9)
    65  	committee9, err := ComputeCommittee(indices, seed, index, committeeCount)
    66  	assert.NoError(t, err, "Could not compute committee")
    67  	start = sliceutil.SplitOffset(validatorCount, committeeCount, index)
    68  	end = sliceutil.SplitOffset(validatorCount, committeeCount, index+1)
    69  	assert.DeepEqual(t, committee9, committees[start:end], "Committee has different shuffled indices")
    70  }
    71  
    72  func TestComputeCommittee_RegressionTest(t *testing.T) {
    73  	indices := []types.ValidatorIndex{1, 3, 8, 16, 18, 19, 20, 23, 30, 35, 43, 46, 47, 54, 56, 58, 69, 70, 71, 83, 84, 85, 91, 96, 100, 103, 105, 106, 112, 121, 127, 128, 129, 140, 142, 144, 146, 147, 149, 152, 153, 154, 157, 160, 173, 175, 180, 182, 188, 189, 191, 194, 201, 204, 217, 221, 226, 228, 230, 231, 239, 241, 249, 250, 255}
    74  	seed := [32]byte{68, 110, 161, 250, 98, 230, 161, 172, 227, 226, 99, 11, 138, 124, 201, 134, 38, 197, 0, 120, 6, 165, 122, 34, 19, 216, 43, 226, 210, 114, 165, 183}
    75  	index := uint64(215)
    76  	count := uint64(32)
    77  	_, err := ComputeCommittee(indices, seed, index, count)
    78  	require.ErrorContains(t, "index out of range", err)
    79  }
    80  
    81  func TestVerifyBitfieldLength_OK(t *testing.T) {
    82  	bf := bitfield.Bitlist{0xFF, 0x01}
    83  	committeeSize := uint64(8)
    84  	assert.NoError(t, VerifyBitfieldLength(bf, committeeSize), "Bitfield is not validated when it was supposed to be")
    85  
    86  	bf = bitfield.Bitlist{0xFF, 0x07}
    87  	committeeSize = 10
    88  	assert.NoError(t, VerifyBitfieldLength(bf, committeeSize), "Bitfield is not validated when it was supposed to be")
    89  }
    90  
    91  func TestCommitteeAssignments_CannotRetrieveFutureEpoch(t *testing.T) {
    92  	ClearCache()
    93  	epoch := types.Epoch(1)
    94  	state, err := v1.InitializeFromProto(&pb.BeaconState{
    95  		Slot: 0, // Epoch 0.
    96  	})
    97  	require.NoError(t, err)
    98  	_, _, err = CommitteeAssignments(state, epoch+1)
    99  	assert.ErrorContains(t, "can't be greater than next epoch", err)
   100  }
   101  
   102  func TestCommitteeAssignments_NoProposerForSlot0(t *testing.T) {
   103  	validators := make([]*ethpb.Validator, 4*params.BeaconConfig().SlotsPerEpoch)
   104  	for i := 0; i < len(validators); i++ {
   105  		var activationEpoch types.Epoch
   106  		if i >= len(validators)/2 {
   107  			activationEpoch = 3
   108  		}
   109  		validators[i] = &ethpb.Validator{
   110  			ActivationEpoch: activationEpoch,
   111  			ExitEpoch:       params.BeaconConfig().FarFutureEpoch,
   112  		}
   113  	}
   114  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   115  		Validators:  validators,
   116  		Slot:        2 * params.BeaconConfig().SlotsPerEpoch, // epoch 2
   117  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   118  	})
   119  	require.NoError(t, err)
   120  	ClearCache()
   121  	_, proposerIndexToSlots, err := CommitteeAssignments(state, 0)
   122  	require.NoError(t, err, "Failed to determine CommitteeAssignments")
   123  	for _, slots := range proposerIndexToSlots {
   124  		for _, s := range slots {
   125  			assert.NotEqual(t, uint64(0), s, "No proposer should be assigned to slot 0")
   126  		}
   127  	}
   128  }
   129  
   130  func TestCommitteeAssignments_CanRetrieve(t *testing.T) {
   131  	// Initialize test with 256 validators, each slot and each index gets 4 validators.
   132  	validators := make([]*ethpb.Validator, 4*params.BeaconConfig().SlotsPerEpoch)
   133  	for i := 0; i < len(validators); i++ {
   134  		// First 2 epochs only half validators are activated.
   135  		var activationEpoch types.Epoch
   136  		if i >= len(validators)/2 {
   137  			activationEpoch = 3
   138  		}
   139  		validators[i] = &ethpb.Validator{
   140  			ActivationEpoch: activationEpoch,
   141  			ExitEpoch:       params.BeaconConfig().FarFutureEpoch,
   142  		}
   143  	}
   144  
   145  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   146  		Validators:  validators,
   147  		Slot:        2 * params.BeaconConfig().SlotsPerEpoch, // epoch 2
   148  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   149  	})
   150  	require.NoError(t, err)
   151  
   152  	tests := []struct {
   153  		index          types.ValidatorIndex
   154  		slot           types.Slot
   155  		committee      []types.ValidatorIndex
   156  		committeeIndex types.CommitteeIndex
   157  		isProposer     bool
   158  		proposerSlot   types.Slot
   159  	}{
   160  		{
   161  			index:          0,
   162  			slot:           78,
   163  			committee:      []types.ValidatorIndex{0, 38},
   164  			committeeIndex: 0,
   165  			isProposer:     false,
   166  		},
   167  		{
   168  			index:          1,
   169  			slot:           71,
   170  			committee:      []types.ValidatorIndex{1, 4},
   171  			committeeIndex: 0,
   172  			isProposer:     true,
   173  			proposerSlot:   79,
   174  		},
   175  		{
   176  			index:          11,
   177  			slot:           90,
   178  			committee:      []types.ValidatorIndex{31, 11},
   179  			committeeIndex: 0,
   180  			isProposer:     false,
   181  		}, {
   182  			index:          2,
   183  			slot:           127, // 3rd epoch has more active validators
   184  			committee:      []types.ValidatorIndex{89, 2, 81, 5},
   185  			committeeIndex: 0,
   186  			isProposer:     false,
   187  		},
   188  	}
   189  
   190  	for i, tt := range tests {
   191  		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
   192  			ClearCache()
   193  			validatorIndexToCommittee, proposerIndexToSlots, err := CommitteeAssignments(state, SlotToEpoch(tt.slot))
   194  			require.NoError(t, err, "Failed to determine CommitteeAssignments")
   195  			cac := validatorIndexToCommittee[tt.index]
   196  			assert.Equal(t, tt.committeeIndex, cac.CommitteeIndex, "Unexpected committeeIndex for validator index %d", tt.index)
   197  			assert.Equal(t, tt.slot, cac.AttesterSlot, "Unexpected slot for validator index %d", tt.index)
   198  			if len(proposerIndexToSlots[tt.index]) > 0 && proposerIndexToSlots[tt.index][0] != tt.proposerSlot {
   199  				t.Errorf("wanted proposer slot %d, got proposer slot %d for validator index %d",
   200  					tt.proposerSlot, proposerIndexToSlots[tt.index][0], tt.index)
   201  			}
   202  			assert.DeepEqual(t, tt.committee, cac.Committee, "Unexpected committee for validator index %d", tt.index)
   203  		})
   204  	}
   205  }
   206  
   207  func TestCommitteeAssignments_CannotRetrieveFuture(t *testing.T) {
   208  	// Initialize test with 256 validators, each slot and each index gets 4 validators.
   209  	validators := make([]*ethpb.Validator, 4*params.BeaconConfig().SlotsPerEpoch)
   210  	for i := 0; i < len(validators); i++ {
   211  		// First 2 epochs only half validators are activated.
   212  		var activationEpoch types.Epoch
   213  		if i >= len(validators)/2 {
   214  			activationEpoch = 3
   215  		}
   216  		validators[i] = &ethpb.Validator{
   217  			ActivationEpoch: activationEpoch,
   218  			ExitEpoch:       params.BeaconConfig().FarFutureEpoch,
   219  		}
   220  	}
   221  
   222  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   223  		Validators:  validators,
   224  		Slot:        2 * params.BeaconConfig().SlotsPerEpoch, // epoch 2
   225  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   226  	})
   227  	require.NoError(t, err)
   228  	_, proposerIndxs, err := CommitteeAssignments(state, CurrentEpoch(state))
   229  	require.NoError(t, err)
   230  	require.NotEqual(t, 0, len(proposerIndxs), "wanted non-zero proposer index set")
   231  
   232  	_, proposerIndxs, err = CommitteeAssignments(state, CurrentEpoch(state)+1)
   233  	require.NoError(t, err)
   234  	require.Equal(t, 0, len(proposerIndxs), "wanted empty proposer index set")
   235  }
   236  
   237  func TestCommitteeAssignments_EverySlotHasMin1Proposer(t *testing.T) {
   238  	// Initialize test with 256 validators, each slot and each index gets 4 validators.
   239  	validators := make([]*ethpb.Validator, 4*params.BeaconConfig().SlotsPerEpoch)
   240  	for i := 0; i < len(validators); i++ {
   241  		validators[i] = &ethpb.Validator{
   242  			ActivationEpoch: 0,
   243  			ExitEpoch:       params.BeaconConfig().FarFutureEpoch,
   244  		}
   245  	}
   246  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   247  		Validators:  validators,
   248  		Slot:        2 * params.BeaconConfig().SlotsPerEpoch, // epoch 2
   249  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   250  	})
   251  	require.NoError(t, err)
   252  	ClearCache()
   253  	epoch := types.Epoch(1)
   254  	_, proposerIndexToSlots, err := CommitteeAssignments(state, epoch)
   255  	require.NoError(t, err, "Failed to determine CommitteeAssignments")
   256  
   257  	slotsWithProposers := make(map[types.Slot]bool)
   258  	for _, proposerSlots := range proposerIndexToSlots {
   259  		for _, slot := range proposerSlots {
   260  			slotsWithProposers[slot] = true
   261  		}
   262  	}
   263  	assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch), uint64(len(slotsWithProposers)), "Unexpected slots")
   264  	startSlot, err := StartSlot(epoch)
   265  	require.NoError(t, err)
   266  	endSlot, err := StartSlot(epoch + 1)
   267  	require.NoError(t, err)
   268  	for i := startSlot; i < endSlot; i++ {
   269  		hasProposer := slotsWithProposers[i]
   270  		assert.Equal(t, true, hasProposer, "Expected every slot in epoch 1 to have a proposer, slot %d did not", i)
   271  	}
   272  }
   273  
   274  func TestVerifyAttestationBitfieldLengths_OK(t *testing.T) {
   275  	validators := make([]*ethpb.Validator, 2*params.BeaconConfig().SlotsPerEpoch)
   276  	activeRoots := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector)
   277  	for i := 0; i < len(validators); i++ {
   278  		validators[i] = &ethpb.Validator{
   279  			ExitEpoch: params.BeaconConfig().FarFutureEpoch,
   280  		}
   281  	}
   282  
   283  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   284  		Validators:  validators,
   285  		RandaoMixes: activeRoots,
   286  	})
   287  	require.NoError(t, err)
   288  
   289  	tests := []struct {
   290  		attestation         *ethpb.Attestation
   291  		stateSlot           types.Slot
   292  		verificationFailure bool
   293  	}{
   294  		{
   295  			attestation: &ethpb.Attestation{
   296  				AggregationBits: bitfield.Bitlist{0x05},
   297  				Data: &ethpb.AttestationData{
   298  					CommitteeIndex: 5,
   299  					Target:         &ethpb.Checkpoint{Root: make([]byte, 32)},
   300  				},
   301  			},
   302  			stateSlot: 5,
   303  		},
   304  		{
   305  
   306  			attestation: &ethpb.Attestation{
   307  				AggregationBits: bitfield.Bitlist{0x06},
   308  				Data: &ethpb.AttestationData{
   309  					CommitteeIndex: 10,
   310  					Target:         &ethpb.Checkpoint{Root: make([]byte, 32)},
   311  				},
   312  			},
   313  			stateSlot: 10,
   314  		},
   315  		{
   316  			attestation: &ethpb.Attestation{
   317  				AggregationBits: bitfield.Bitlist{0x06},
   318  				Data: &ethpb.AttestationData{
   319  					CommitteeIndex: 20,
   320  					Target:         &ethpb.Checkpoint{Root: make([]byte, 32)},
   321  				},
   322  			},
   323  			stateSlot: 20,
   324  		},
   325  		{
   326  			attestation: &ethpb.Attestation{
   327  				AggregationBits: bitfield.Bitlist{0x06},
   328  				Data: &ethpb.AttestationData{
   329  					CommitteeIndex: 20,
   330  					Target:         &ethpb.Checkpoint{Root: make([]byte, 32)},
   331  				},
   332  			},
   333  			stateSlot: 20,
   334  		},
   335  		{
   336  			attestation: &ethpb.Attestation{
   337  				AggregationBits: bitfield.Bitlist{0xFF, 0xC0, 0x01},
   338  				Data: &ethpb.AttestationData{
   339  					CommitteeIndex: 5,
   340  					Target:         &ethpb.Checkpoint{Root: make([]byte, 32)},
   341  				},
   342  			},
   343  			stateSlot:           5,
   344  			verificationFailure: true,
   345  		},
   346  		{
   347  			attestation: &ethpb.Attestation{
   348  				AggregationBits: bitfield.Bitlist{0xFF, 0x01},
   349  				Data: &ethpb.AttestationData{
   350  					CommitteeIndex: 20,
   351  					Target:         &ethpb.Checkpoint{Root: make([]byte, 32)},
   352  				},
   353  			},
   354  			stateSlot:           20,
   355  			verificationFailure: true,
   356  		},
   357  	}
   358  
   359  	for i, tt := range tests {
   360  		ClearCache()
   361  		require.NoError(t, state.SetSlot(tt.stateSlot))
   362  		err := VerifyAttestationBitfieldLengths(state, tt.attestation)
   363  		if tt.verificationFailure {
   364  			assert.NotNil(t, err, "Verification succeeded when it was supposed to fail")
   365  		} else {
   366  			assert.NoError(t, err, "%d Failed to verify bitfield: %v", i, err)
   367  		}
   368  	}
   369  }
   370  
   371  func TestShuffledIndices_ShuffleRightLength(t *testing.T) {
   372  	valiatorCount := 1000
   373  	validators := make([]*ethpb.Validator, valiatorCount)
   374  	indices := make([]uint64, valiatorCount)
   375  	for i := 0; i < valiatorCount; i++ {
   376  		validators[i] = &ethpb.Validator{
   377  			ExitEpoch: params.BeaconConfig().FarFutureEpoch,
   378  		}
   379  		indices[i] = uint64(i)
   380  	}
   381  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   382  		Validators:  validators,
   383  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   384  	})
   385  	require.NoError(t, err)
   386  	// Test for current epoch
   387  	shuffledIndices, err := ShuffledIndices(state, 0)
   388  	require.NoError(t, err)
   389  	assert.Equal(t, valiatorCount, len(shuffledIndices), "Incorrect shuffled indices count")
   390  	if reflect.DeepEqual(indices, shuffledIndices) {
   391  		t.Error("Shuffling did not happen")
   392  	}
   393  
   394  	// Test for next epoch
   395  	shuffledIndices, err = ShuffledIndices(state, 1)
   396  	require.NoError(t, err)
   397  	assert.Equal(t, valiatorCount, len(shuffledIndices), "Incorrect shuffled indices count")
   398  	if reflect.DeepEqual(indices, shuffledIndices) {
   399  		t.Error("Shuffling did not happen")
   400  	}
   401  }
   402  
   403  func TestUpdateCommitteeCache_CanUpdate(t *testing.T) {
   404  	ClearCache()
   405  	validatorCount := params.BeaconConfig().MinGenesisActiveValidatorCount
   406  	validators := make([]*ethpb.Validator, validatorCount)
   407  	indices := make([]types.ValidatorIndex, validatorCount)
   408  	for i := types.ValidatorIndex(0); uint64(i) < validatorCount; i++ {
   409  		validators[i] = &ethpb.Validator{
   410  			ExitEpoch: params.BeaconConfig().FarFutureEpoch,
   411  		}
   412  		indices[i] = i
   413  	}
   414  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   415  		Validators:  validators,
   416  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   417  	})
   418  	require.NoError(t, err)
   419  	require.NoError(t, UpdateCommitteeCache(state, CurrentEpoch(state)))
   420  
   421  	epoch := types.Epoch(1)
   422  	idx := types.CommitteeIndex(1)
   423  	seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
   424  	require.NoError(t, err)
   425  
   426  	indices, err = committeeCache.Committee(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch)), seed, idx)
   427  	require.NoError(t, err)
   428  	assert.Equal(t, params.BeaconConfig().TargetCommitteeSize, uint64(len(indices)), "Did not save correct indices lengths")
   429  }
   430  
   431  func BenchmarkComputeCommittee300000_WithPreCache(b *testing.B) {
   432  	validators := make([]*ethpb.Validator, 300000)
   433  	for i := 0; i < len(validators); i++ {
   434  		validators[i] = &ethpb.Validator{
   435  			ExitEpoch: params.BeaconConfig().FarFutureEpoch,
   436  		}
   437  	}
   438  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   439  		Validators:  validators,
   440  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   441  	})
   442  	require.NoError(b, err)
   443  
   444  	epoch := CurrentEpoch(state)
   445  	indices, err := ActiveValidatorIndices(state, epoch)
   446  	require.NoError(b, err)
   447  	seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
   448  	require.NoError(b, err)
   449  
   450  	index := uint64(3)
   451  	_, err = ComputeCommittee(indices, seed, index, params.BeaconConfig().MaxCommitteesPerSlot)
   452  	if err != nil {
   453  		panic(err)
   454  	}
   455  
   456  	b.ResetTimer()
   457  	for n := 0; n < b.N; n++ {
   458  		_, err := ComputeCommittee(indices, seed, index, params.BeaconConfig().MaxCommitteesPerSlot)
   459  		if err != nil {
   460  			panic(err)
   461  		}
   462  	}
   463  }
   464  
   465  func BenchmarkComputeCommittee3000000_WithPreCache(b *testing.B) {
   466  	validators := make([]*ethpb.Validator, 3000000)
   467  	for i := 0; i < len(validators); i++ {
   468  		validators[i] = &ethpb.Validator{
   469  			ExitEpoch: params.BeaconConfig().FarFutureEpoch,
   470  		}
   471  	}
   472  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   473  		Validators:  validators,
   474  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   475  	})
   476  	require.NoError(b, err)
   477  
   478  	epoch := CurrentEpoch(state)
   479  	indices, err := ActiveValidatorIndices(state, epoch)
   480  	require.NoError(b, err)
   481  	seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
   482  	require.NoError(b, err)
   483  
   484  	index := uint64(3)
   485  	_, err = ComputeCommittee(indices, seed, index, params.BeaconConfig().MaxCommitteesPerSlot)
   486  	if err != nil {
   487  		panic(err)
   488  	}
   489  
   490  	b.ResetTimer()
   491  	for n := 0; n < b.N; n++ {
   492  		_, err := ComputeCommittee(indices, seed, index, params.BeaconConfig().MaxCommitteesPerSlot)
   493  		if err != nil {
   494  			panic(err)
   495  		}
   496  	}
   497  }
   498  
   499  func BenchmarkComputeCommittee128000_WithOutPreCache(b *testing.B) {
   500  	validators := make([]*ethpb.Validator, 128000)
   501  	for i := 0; i < len(validators); i++ {
   502  		validators[i] = &ethpb.Validator{
   503  			ExitEpoch: params.BeaconConfig().FarFutureEpoch,
   504  		}
   505  	}
   506  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   507  		Validators:  validators,
   508  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   509  	})
   510  	require.NoError(b, err)
   511  
   512  	epoch := CurrentEpoch(state)
   513  	indices, err := ActiveValidatorIndices(state, epoch)
   514  	require.NoError(b, err)
   515  	seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
   516  	require.NoError(b, err)
   517  
   518  	i := uint64(0)
   519  	index := uint64(0)
   520  	b.ResetTimer()
   521  	for n := 0; n < b.N; n++ {
   522  		i++
   523  		_, err := ComputeCommittee(indices, seed, index, params.BeaconConfig().MaxCommitteesPerSlot)
   524  		if err != nil {
   525  			panic(err)
   526  		}
   527  		if i < params.BeaconConfig().TargetCommitteeSize {
   528  			index = (index + 1) % params.BeaconConfig().MaxCommitteesPerSlot
   529  			i = 0
   530  		}
   531  	}
   532  }
   533  
   534  func BenchmarkComputeCommittee1000000_WithOutCache(b *testing.B) {
   535  	validators := make([]*ethpb.Validator, 1000000)
   536  	for i := 0; i < len(validators); i++ {
   537  		validators[i] = &ethpb.Validator{
   538  			ExitEpoch: params.BeaconConfig().FarFutureEpoch,
   539  		}
   540  	}
   541  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   542  		Validators:  validators,
   543  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   544  	})
   545  	require.NoError(b, err)
   546  
   547  	epoch := CurrentEpoch(state)
   548  	indices, err := ActiveValidatorIndices(state, epoch)
   549  	require.NoError(b, err)
   550  	seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
   551  	require.NoError(b, err)
   552  
   553  	i := uint64(0)
   554  	index := uint64(0)
   555  	b.ResetTimer()
   556  	for n := 0; n < b.N; n++ {
   557  		i++
   558  		_, err := ComputeCommittee(indices, seed, index, params.BeaconConfig().MaxCommitteesPerSlot)
   559  		if err != nil {
   560  			panic(err)
   561  		}
   562  		if i < params.BeaconConfig().TargetCommitteeSize {
   563  			index = (index + 1) % params.BeaconConfig().MaxCommitteesPerSlot
   564  			i = 0
   565  		}
   566  	}
   567  }
   568  
   569  func BenchmarkComputeCommittee4000000_WithOutCache(b *testing.B) {
   570  	validators := make([]*ethpb.Validator, 4000000)
   571  	for i := 0; i < len(validators); i++ {
   572  		validators[i] = &ethpb.Validator{
   573  			ExitEpoch: params.BeaconConfig().FarFutureEpoch,
   574  		}
   575  	}
   576  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   577  		Validators:  validators,
   578  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   579  	})
   580  	require.NoError(b, err)
   581  
   582  	epoch := CurrentEpoch(state)
   583  	indices, err := ActiveValidatorIndices(state, epoch)
   584  	require.NoError(b, err)
   585  	seed, err := Seed(state, epoch, params.BeaconConfig().DomainBeaconAttester)
   586  	require.NoError(b, err)
   587  
   588  	i := uint64(0)
   589  	index := uint64(0)
   590  	b.ResetTimer()
   591  	for n := 0; n < b.N; n++ {
   592  		i++
   593  		_, err := ComputeCommittee(indices, seed, index, params.BeaconConfig().MaxCommitteesPerSlot)
   594  		if err != nil {
   595  			panic(err)
   596  		}
   597  		if i < params.BeaconConfig().TargetCommitteeSize {
   598  			index = (index + 1) % params.BeaconConfig().MaxCommitteesPerSlot
   599  			i = 0
   600  		}
   601  	}
   602  }
   603  
   604  func TestBeaconCommitteeFromState_UpdateCacheForPreviousEpoch(t *testing.T) {
   605  	committeeSize := uint64(16)
   606  	validators := make([]*ethpb.Validator, params.BeaconConfig().SlotsPerEpoch.Mul(committeeSize))
   607  	for i := 0; i < len(validators); i++ {
   608  		validators[i] = &ethpb.Validator{
   609  			ExitEpoch: params.BeaconConfig().FarFutureEpoch,
   610  		}
   611  	}
   612  
   613  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   614  		Slot:        params.BeaconConfig().SlotsPerEpoch,
   615  		Validators:  validators,
   616  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   617  	})
   618  	require.NoError(t, err)
   619  	_, err = BeaconCommitteeFromState(state, 1 /* previous epoch */, 0)
   620  	require.NoError(t, err)
   621  
   622  	// Verify previous epoch is cached
   623  	seed, err := Seed(state, 0, params.BeaconConfig().DomainBeaconAttester)
   624  	require.NoError(t, err)
   625  	activeIndices, err := committeeCache.ActiveIndices(seed)
   626  	require.NoError(t, err)
   627  	assert.NotNil(t, activeIndices, "Did not cache active indices")
   628  }
   629  
   630  func TestPrecomputeProposerIndices_Ok(t *testing.T) {
   631  	validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
   632  	for i := 0; i < len(validators); i++ {
   633  		validators[i] = &ethpb.Validator{
   634  			ExitEpoch: params.BeaconConfig().FarFutureEpoch,
   635  		}
   636  	}
   637  
   638  	state, err := v1.InitializeFromProto(&pb.BeaconState{
   639  		Validators:  validators,
   640  		RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
   641  	})
   642  	require.NoError(t, err)
   643  
   644  	indices, err := ActiveValidatorIndices(state, 0)
   645  	require.NoError(t, err)
   646  
   647  	proposerIndices, err := precomputeProposerIndices(state, indices)
   648  	require.NoError(t, err)
   649  
   650  	var wantedProposerIndices []types.ValidatorIndex
   651  	seed, err := Seed(state, 0, params.BeaconConfig().DomainBeaconProposer)
   652  	require.NoError(t, err)
   653  	for i := uint64(0); i < uint64(params.BeaconConfig().SlotsPerEpoch); i++ {
   654  		seedWithSlot := append(seed[:], bytesutil.Bytes8(i)...)
   655  		seedWithSlotHash := hashutil.Hash(seedWithSlot)
   656  		index, err := ComputeProposerIndex(state, indices, seedWithSlotHash)
   657  		require.NoError(t, err)
   658  		wantedProposerIndices = append(wantedProposerIndices, index)
   659  	}
   660  	assert.DeepEqual(t, wantedProposerIndices, proposerIndices, "Did not precompute proposer indices correctly")
   661  }