prysm-pulse/beacon-chain/core/state/transition_test.go
2019-02-14 01:17:54 +00:00

596 lines
18 KiB
Go

package state
import (
"fmt"
"strings"
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
)
func TestProcessBlock_IncorrectSlot(t *testing.T) {
beaconState := &pb.BeaconState{
Slot: 5,
}
block := &pb.BeaconBlock{
Slot: 4,
}
want := fmt.Sprintf(
"block.slot != state.slot, block.slot = %d, state.slot = %d",
4,
5,
)
if _, err := ProcessBlock(beaconState, block, false); !strings.Contains(err.Error(), want) {
t.Errorf("Expected %s, received %v", want, err)
}
}
func TestProcessBlock_IncorrectProposerSlashing(t *testing.T) {
registry := validators.InitialValidatorRegistry()
slashings := make([]*pb.ProposerSlashing, params.BeaconConfig().MaxProposerSlashings+1)
latestMixes := make([][]byte, params.BeaconConfig().LatestRandaoMixesLength)
beaconState := &pb.BeaconState{
LatestRandaoMixesHash32S: latestMixes,
ValidatorRegistry: registry,
Slot: 5,
}
block := &pb.BeaconBlock{
Slot: 5,
RandaoRevealHash32: []byte{},
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
Body: &pb.BeaconBlockBody{
ProposerSlashings: slashings,
},
}
want := "could not verify block proposer slashing"
if _, err := ProcessBlock(beaconState, block, false); !strings.Contains(err.Error(), want) {
t.Errorf("Expected %s, received %v", want, err)
}
}
func TestProcessBlock_IncorrectAttesterSlashing(t *testing.T) {
registry := validators.InitialValidatorRegistry()
slashings := []*pb.ProposerSlashing{
{
ProposerIndex: 1,
ProposalData_1: &pb.ProposalSignedData{
Slot: 1,
Shard: 1,
BlockRootHash32: []byte{0, 1, 0},
},
ProposalData_2: &pb.ProposalSignedData{
Slot: 1,
Shard: 1,
BlockRootHash32: []byte{0, 1, 0},
},
},
}
attesterSlashings := make([]*pb.AttesterSlashing, params.BeaconConfig().MaxAttesterSlashings+1)
latestMixes := make([][]byte, params.BeaconConfig().LatestRandaoMixesLength)
beaconState := &pb.BeaconState{
LatestRandaoMixesHash32S: latestMixes,
Slot: 5,
ValidatorRegistry: registry,
}
block := &pb.BeaconBlock{
Slot: 5,
RandaoRevealHash32: []byte{},
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
Body: &pb.BeaconBlockBody{
ProposerSlashings: slashings,
AttesterSlashings: attesterSlashings,
},
}
want := "could not verify block attester slashing"
if _, err := ProcessBlock(beaconState, block, false); !strings.Contains(err.Error(), want) {
t.Errorf("Expected %s, received %v", want, err)
}
}
func TestProcessBlock_IncorrectProcessBlockAttestations(t *testing.T) {
validators := make([]*pb.Validator, 1000)
for i := uint64(0); i < 1000; i++ {
pubkey := hashutil.Hash([]byte{byte(i)})
validators[i] = &pb.Validator{
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
Pubkey: pubkey[:],
PenalizedEpoch: 10,
}
}
proposerSlashings := []*pb.ProposerSlashing{
{
ProposerIndex: 1,
ProposalData_1: &pb.ProposalSignedData{
Slot: 1,
Shard: 1,
BlockRootHash32: []byte{0, 1, 0},
},
ProposalData_2: &pb.ProposalSignedData{
Slot: 1,
Shard: 1,
BlockRootHash32: []byte{0, 1, 0},
},
},
}
att1 := &pb.AttestationData{
Slot: 5,
JustifiedEpoch: 5,
}
att2 := &pb.AttestationData{
Slot: 5,
JustifiedEpoch: 4,
}
attesterSlashings := []*pb.AttesterSlashing{
{
SlashableAttestation_1: &pb.SlashableAttestation{
Data: att1,
ValidatorIndices: []uint64{1, 2, 3, 4, 5, 6, 7, 8},
CustodyBitfield: []byte{0xFF},
},
SlashableAttestation_2: &pb.SlashableAttestation{
Data: att2,
ValidatorIndices: []uint64{1, 2, 3, 4, 5, 6, 7, 8},
CustodyBitfield: []byte{0xFF},
},
},
}
blockAttestations := make([]*pb.Attestation, params.BeaconConfig().MaxAttestations+1)
latestMixes := make([][]byte, params.BeaconConfig().LatestRandaoMixesLength)
beaconState := &pb.BeaconState{
LatestRandaoMixesHash32S: latestMixes,
Slot: 5,
ValidatorRegistry: validators,
ValidatorBalances: make([]uint64, len(validators)),
LatestPenalizedBalances: make([]uint64, params.BeaconConfig().LatestPenalizedExitLength),
}
block := &pb.BeaconBlock{
Slot: 5,
RandaoRevealHash32: []byte{},
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
Body: &pb.BeaconBlockBody{
ProposerSlashings: proposerSlashings,
AttesterSlashings: attesterSlashings,
Attestations: blockAttestations,
},
}
want := "could not process block attestations"
if _, err := ProcessBlock(beaconState, block, false); !strings.Contains(err.Error(), want) {
t.Errorf("Expected %s, received %v", want, err)
}
}
func TestProcessBlock_IncorrectProcessExits(t *testing.T) {
validators := make([]*pb.Validator, 1000)
for i := uint64(0); i < 1000; i++ {
pubkey := hashutil.Hash([]byte{byte(i)})
validators[i] = &pb.Validator{
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
Pubkey: pubkey[:],
PenalizedEpoch: 10,
}
}
proposerSlashings := []*pb.ProposerSlashing{
{
ProposerIndex: 1,
ProposalData_1: &pb.ProposalSignedData{
Slot: 1,
Shard: 1,
BlockRootHash32: []byte{0, 1, 0},
},
ProposalData_2: &pb.ProposalSignedData{
Slot: 1,
Shard: 1,
BlockRootHash32: []byte{0, 1, 0},
},
},
}
att1 := &pb.AttestationData{
Slot: 5,
JustifiedEpoch: 5,
}
att2 := &pb.AttestationData{
Slot: 5,
JustifiedEpoch: 4,
}
attesterSlashings := []*pb.AttesterSlashing{
{
SlashableAttestation_1: &pb.SlashableAttestation{
Data: att1,
ValidatorIndices: []uint64{1, 2, 3, 4, 5, 6, 7, 8},
CustodyBitfield: []byte{0xFF},
},
SlashableAttestation_2: &pb.SlashableAttestation{
Data: att2,
ValidatorIndices: []uint64{1, 2, 3, 4, 5, 6, 7, 8},
CustodyBitfield: []byte{0xFF},
},
},
}
var blockRoots [][]byte
for i := uint64(0); i < 2*params.BeaconConfig().EpochLength; i++ {
blockRoots = append(blockRoots, []byte{byte(i)})
}
stateLatestCrosslinks := []*pb.Crosslink{
{
ShardBlockRootHash32: []byte{1},
},
}
blockAtt := &pb.Attestation{
Data: &pb.AttestationData{
Shard: 0,
Slot: 20,
JustifiedBlockRootHash32: blockRoots[0],
LatestCrosslink: &pb.Crosslink{ShardBlockRootHash32: []byte{1}},
ShardBlockRootHash32: []byte{},
},
AggregationBitfield: []byte{1},
CustodyBitfield: []byte{1},
}
attestations := []*pb.Attestation{blockAtt}
latestMixes := make([][]byte, params.BeaconConfig().LatestRandaoMixesLength)
beaconState := &pb.BeaconState{
LatestRandaoMixesHash32S: latestMixes,
ValidatorRegistry: validators,
Slot: 64,
PreviousJustifiedEpoch: 0,
LatestBlockRootHash32S: blockRoots,
LatestCrosslinks: stateLatestCrosslinks,
ValidatorBalances: make([]uint64, len(validators)),
LatestPenalizedBalances: make([]uint64, params.BeaconConfig().LatestPenalizedExitLength),
}
exits := make([]*pb.Exit, params.BeaconConfig().MaxExits+1)
block := &pb.BeaconBlock{
Slot: 64,
RandaoRevealHash32: []byte{},
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
Body: &pb.BeaconBlockBody{
ProposerSlashings: proposerSlashings,
AttesterSlashings: attesterSlashings,
Attestations: attestations,
Exits: exits,
},
}
want := "could not process validator exits"
if _, err := ProcessBlock(beaconState, block, false); !strings.Contains(err.Error(), want) {
t.Errorf("Expected %s, received %v", want, err)
}
}
func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
validators := make([]*pb.Validator, 1000)
for i := uint64(0); i < 1000; i++ {
pubkey := hashutil.Hash([]byte{byte(i)})
validators[i] = &pb.Validator{
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
Pubkey: pubkey[:],
PenalizedEpoch: 10,
}
}
proposerSlashings := []*pb.ProposerSlashing{
{
ProposerIndex: 1,
ProposalData_1: &pb.ProposalSignedData{
Slot: 1,
Shard: 1,
BlockRootHash32: []byte{0, 1, 0},
},
ProposalData_2: &pb.ProposalSignedData{
Slot: 1,
Shard: 1,
BlockRootHash32: []byte{0, 1, 0},
},
},
}
att1 := &pb.AttestationData{
Slot: 5,
JustifiedEpoch: 5,
}
att2 := &pb.AttestationData{
Slot: 5,
JustifiedEpoch: 4,
}
attesterSlashings := []*pb.AttesterSlashing{
{
SlashableAttestation_1: &pb.SlashableAttestation{
Data: att1,
ValidatorIndices: []uint64{1, 2, 3, 4, 5, 6, 7, 8},
CustodyBitfield: []byte{0xFF},
},
SlashableAttestation_2: &pb.SlashableAttestation{
Data: att2,
ValidatorIndices: []uint64{1, 2, 3, 4, 5, 6, 7, 8},
CustodyBitfield: []byte{0xFF},
},
},
}
var blockRoots [][]byte
for i := uint64(0); i < 2*params.BeaconConfig().EpochLength; i++ {
blockRoots = append(blockRoots, []byte{byte(i)})
}
stateLatestCrosslinks := []*pb.Crosslink{
{
ShardBlockRootHash32: []byte{1},
},
}
blockAtt := &pb.Attestation{
Data: &pb.AttestationData{
Shard: 0,
Slot: 20,
JustifiedBlockRootHash32: blockRoots[0],
LatestCrosslink: &pb.Crosslink{ShardBlockRootHash32: []byte{1}},
ShardBlockRootHash32: []byte{},
},
AggregationBitfield: []byte{1},
CustodyBitfield: []byte{1},
}
attestations := []*pb.Attestation{blockAtt}
latestMixes := make([][]byte, params.BeaconConfig().LatestRandaoMixesLength)
beaconState := &pb.BeaconState{
LatestRandaoMixesHash32S: latestMixes,
ValidatorRegistry: validators,
Slot: 64,
PreviousJustifiedEpoch: 0,
LatestBlockRootHash32S: blockRoots,
LatestCrosslinks: stateLatestCrosslinks,
ValidatorBalances: make([]uint64, len(validators)),
LatestPenalizedBalances: make([]uint64, params.BeaconConfig().LatestPenalizedExitLength),
}
exits := []*pb.Exit{
{
ValidatorIndex: 10,
Epoch: 0,
},
}
block := &pb.BeaconBlock{
Slot: 64,
RandaoRevealHash32: []byte{},
Eth1Data: &pb.Eth1Data{
DepositRootHash32: []byte{2},
BlockHash32: []byte{3},
},
Body: &pb.BeaconBlockBody{
ProposerSlashings: proposerSlashings,
AttesterSlashings: attesterSlashings,
Attestations: attestations,
Exits: exits,
},
}
if _, err := ProcessBlock(beaconState, block, false); err != nil {
t.Errorf("Expected block to pass processing conditions: %v", err)
}
}
func TestProcessEpoch_PassesProcessingConditions(t *testing.T) {
var validatorRegistry []*pb.Validator
for i := uint64(0); i < 10; i++ {
validatorRegistry = append(validatorRegistry,
&pb.Validator{
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
})
}
validatorBalances := make([]uint64, len(validatorRegistry))
for i := 0; i < len(validatorBalances); i++ {
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
}
var attestations []*pb.PendingAttestation
for i := uint64(0); i < params.BeaconConfig().EpochLength*2; i++ {
attestations = append(attestations, &pb.PendingAttestation{
Data: &pb.AttestationData{
Slot: i + params.BeaconConfig().EpochLength,
Shard: 1,
JustifiedEpoch: 1,
JustifiedBlockRootHash32: []byte{0},
},
InclusionSlot: i + params.BeaconConfig().EpochLength + 1,
})
}
var blockRoots [][]byte
for i := uint64(0); i < 2*params.BeaconConfig().EpochLength; i++ {
blockRoots = append(blockRoots, []byte{byte(i)})
}
var randaoHashes [][]byte
for i := uint64(0); i < params.BeaconConfig().EpochLength; i++ {
randaoHashes = append(randaoHashes, []byte{byte(i)})
}
crosslinkRecord := []*pb.Crosslink{{}, {}}
state := &pb.BeaconState{
Slot: params.BeaconConfig().EpochLength,
LatestAttestations: attestations,
ValidatorBalances: validatorBalances,
ValidatorRegistry: validatorRegistry,
LatestBlockRootHash32S: blockRoots,
LatestCrosslinks: crosslinkRecord,
LatestRandaoMixesHash32S: randaoHashes,
LatestIndexRootHash32S: make([][]byte,
params.BeaconConfig().LatestIndexRootsLength),
LatestPenalizedBalances: make([]uint64,
params.BeaconConfig().LatestPenalizedExitLength),
}
_, err := ProcessEpoch(state)
if err != nil {
t.Errorf("Expected epoch transition to pass processing conditions: %v", err)
}
}
func TestProcessEpoch_InactiveConditions(t *testing.T) {
defaultBalance := params.BeaconConfig().MaxDepositAmount
validatorRegistry := []*pb.Validator{
{ExitEpoch: params.BeaconConfig().FarFutureEpoch}, {ExitEpoch: params.BeaconConfig().FarFutureEpoch},
{ExitEpoch: params.BeaconConfig().FarFutureEpoch}, {ExitEpoch: params.BeaconConfig().FarFutureEpoch},
{ExitEpoch: params.BeaconConfig().FarFutureEpoch}, {ExitEpoch: params.BeaconConfig().FarFutureEpoch},
{ExitEpoch: params.BeaconConfig().FarFutureEpoch}, {ExitEpoch: params.BeaconConfig().FarFutureEpoch}}
validatorBalances := []uint64{
defaultBalance, defaultBalance, defaultBalance, defaultBalance,
defaultBalance, defaultBalance, defaultBalance, defaultBalance,
}
var attestations []*pb.PendingAttestation
for i := uint64(0); i < params.BeaconConfig().EpochLength*2; i++ {
attestations = append(attestations, &pb.PendingAttestation{
Data: &pb.AttestationData{
Slot: i + params.BeaconConfig().EpochLength,
Shard: 1,
JustifiedEpoch: 1,
JustifiedBlockRootHash32: []byte{0},
},
AggregationBitfield: []byte{},
InclusionSlot: i + params.BeaconConfig().EpochLength + 1,
})
}
var blockRoots [][]byte
for i := uint64(0); i < 2*params.BeaconConfig().EpochLength; i++ {
blockRoots = append(blockRoots, []byte{byte(i)})
}
var randaoHashes [][]byte
for i := uint64(0); i < 5*params.BeaconConfig().EpochLength; i++ {
randaoHashes = append(randaoHashes, []byte{byte(i)})
}
crosslinkRecord := []*pb.Crosslink{{}, {}}
state := &pb.BeaconState{
Slot: params.BeaconConfig().EpochLength,
LatestAttestations: attestations,
ValidatorBalances: validatorBalances,
ValidatorRegistry: validatorRegistry,
LatestBlockRootHash32S: blockRoots,
LatestCrosslinks: crosslinkRecord,
LatestRandaoMixesHash32S: randaoHashes,
LatestIndexRootHash32S: make([][]byte,
params.BeaconConfig().LatestIndexRootsLength),
LatestPenalizedBalances: make([]uint64,
params.BeaconConfig().LatestPenalizedExitLength),
}
_, err := ProcessEpoch(state)
if err != nil {
t.Errorf("Expected epoch transition to pass processing conditions: %v", err)
}
}
func TestProcessEpoch_CantGetBoundaryAttestation(t *testing.T) {
state := &pb.BeaconState{
Slot: 5,
LatestAttestations: []*pb.PendingAttestation{
{Data: &pb.AttestationData{Slot: 4}},
}}
want := fmt.Sprintf(
"could not get current boundary attestations: slot %d is not within expected range of %d to %d",
0, state.Slot, state.Slot-1,
)
if _, err := ProcessEpoch(state); !strings.Contains(err.Error(), want) {
t.Errorf("Expected: %s, received: %v", want, err)
}
}
func TestProcessEpoch_CantGetCurrentValidatorIndices(t *testing.T) {
latestBlockRoots := make([][]byte, params.BeaconConfig().LatestBlockRootsLength)
for i := 0; i < len(latestBlockRoots); i++ {
latestBlockRoots[i] = params.BeaconConfig().ZeroHash[:]
}
var attestations []*pb.PendingAttestation
for i := uint64(0); i < params.BeaconConfig().EpochLength*2; i++ {
attestations = append(attestations, &pb.PendingAttestation{
Data: &pb.AttestationData{
Slot: 1,
Shard: 1,
JustifiedBlockRootHash32: make([]byte, 32),
},
AggregationBitfield: []byte{0xff},
})
}
state := &pb.BeaconState{
Slot: params.BeaconConfig().EpochLength,
LatestAttestations: attestations,
LatestBlockRootHash32S: latestBlockRoots,
}
wanted := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 0, 1)
if _, err := ProcessEpoch(state); !strings.Contains(err.Error(), wanted) {
t.Errorf("Expected: %s, received: %v", wanted, err)
}
}
func TestProcessEpoch_CantProcessCurrentBoundaryAttestations(t *testing.T) {
state := &pb.BeaconState{
Slot: 100,
LatestAttestations: []*pb.PendingAttestation{
{Data: &pb.AttestationData{}},
}}
want := fmt.Sprintf(
"could not get prev boundary attestations: slot %d is not within expected range of %d to %d",
0, state.Slot, state.Slot-1,
)
if _, err := ProcessEpoch(state); !strings.Contains(err.Error(), want) {
t.Errorf("Expected: %s, received: %v", want, err)
}
}
func TestProcessEpoch_CantProcessEjections(t *testing.T) {
validatorRegistries := validators.InitialValidatorRegistry()
validatorBalances := make([]uint64, len(validatorRegistries))
for i := 0; i < len(validatorBalances); i++ {
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
}
var randaoHashes [][]byte
for i := uint64(0); i < 4*params.BeaconConfig().EpochLength; i++ {
randaoHashes = append(randaoHashes, []byte{byte(i)})
}
var participationBitfield []byte
for i := 0; i < 16; i++ {
participationBitfield = append(participationBitfield, byte(0xff))
}
ExitEpoch := 4*params.BeaconConfig().EpochLength + 1
validatorRegistries[0].ExitEpoch = ExitEpoch
validatorBalances[0] = params.BeaconConfig().EjectionBalance - 1
state := &pb.BeaconState{
Slot: params.BeaconConfig().EpochLength,
ValidatorBalances: validatorBalances,
LatestBlockRootHash32S: make([][]byte, params.BeaconConfig().LatestBlockRootsLength),
ValidatorRegistry: validatorRegistries,
LatestRandaoMixesHash32S: randaoHashes,
LatestCrosslinks: []*pb.Crosslink{{}},
LatestAttestations: []*pb.PendingAttestation{
{Data: &pb.AttestationData{}, AggregationBitfield: participationBitfield},
}}
want := fmt.Sprintf("could not process inclusion distance: 0")
if _, err := ProcessEpoch(state); !strings.Contains(err.Error(), want) {
t.Errorf("Expected: %s, received: %v", want, err)
}
}