mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-14 14:08:19 +00:00
490 lines
14 KiB
Go
490 lines
14 KiB
Go
package blocks_test
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
|
"github.com/prysmaticlabs/go-ssz"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
|
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
|
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
|
"github.com/prysmaticlabs/prysm/shared/bls"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
"github.com/prysmaticlabs/prysm/shared/testutil"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func init() {
|
|
logrus.SetOutput(ioutil.Discard) // Ignore "validator activated" logs
|
|
}
|
|
|
|
func TestProcessBlockHeader_ImproperBlockSlot(t *testing.T) {
|
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
|
for i := 0; i < len(validators); i++ {
|
|
validators[i] = ðpb.Validator{
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
Slashed: true,
|
|
}
|
|
}
|
|
|
|
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
|
Validators: validators,
|
|
Slot: 10,
|
|
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 10}, // Must be less than block.Slot
|
|
Fork: &pb.Fork{
|
|
PreviousVersion: []byte{0, 0, 0, 0},
|
|
CurrentVersion: []byte{0, 0, 0, 0},
|
|
},
|
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
latestBlockSignedRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
currentEpoch := helpers.CurrentEpoch(state)
|
|
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
|
if err != nil {
|
|
t.Fatalf("Failed to get domain form state: %v", err)
|
|
}
|
|
priv := bls.RandKey()
|
|
pID, err := helpers.BeaconProposerIndex(state)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
block := ðpb.SignedBeaconBlock{
|
|
Block: ðpb.BeaconBlock{
|
|
ProposerIndex: pID,
|
|
Slot: 10,
|
|
Body: ðpb.BeaconBlockBody{
|
|
RandaoReveal: []byte{'A', 'B', 'C'},
|
|
},
|
|
ParentRoot: latestBlockSignedRoot[:],
|
|
},
|
|
}
|
|
signingRoot, err := helpers.ComputeSigningRoot(block.Block, dt)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get signing root of block: %v", err)
|
|
}
|
|
blockSig := priv.Sign(signingRoot[:])
|
|
block.Signature = blockSig.Marshal()[:]
|
|
|
|
proposerIdx, err := helpers.BeaconProposerIndex(state)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
validators[proposerIdx].Slashed = false
|
|
validators[proposerIdx].PublicKey = priv.PublicKey().Marshal()
|
|
err = state.UpdateValidatorAtIndex(proposerIdx, validators[proposerIdx])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = blocks.ProcessBlockHeader(state, block)
|
|
if err == nil || err.Error() != "block.Slot 10 must be greater than state.LatestBlockHeader.Slot 10" {
|
|
t.Fatalf("did not get expected error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestProcessBlockHeader_WrongProposerSig(t *testing.T) {
|
|
testutil.ResetCache()
|
|
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
|
|
if err := beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{Slot: 9}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := beaconState.SetSlot(10); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
lbhdr, err := stateutil.BlockHeaderRoot(beaconState.LatestBlockHeader())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
proposerIdx, err := helpers.BeaconProposerIndex(beaconState)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
block := ðpb.SignedBeaconBlock{
|
|
Block: ðpb.BeaconBlock{
|
|
ProposerIndex: proposerIdx,
|
|
Slot: 10,
|
|
Body: ðpb.BeaconBlockBody{
|
|
RandaoReveal: []byte{'A', 'B', 'C'},
|
|
},
|
|
ParentRoot: lbhdr[:],
|
|
},
|
|
}
|
|
dt, err := helpers.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconProposer, beaconState.GenesisValidatorRoot())
|
|
if err != nil {
|
|
t.Fatalf("Failed to get domain form state: %v", err)
|
|
}
|
|
signingRoot, err := helpers.ComputeSigningRoot(block.Block, dt)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get signing root of block: %v", err)
|
|
}
|
|
blockSig := privKeys[proposerIdx+1].Sign(signingRoot[:])
|
|
block.Signature = blockSig.Marshal()[:]
|
|
|
|
_, err = blocks.ProcessBlockHeader(beaconState, block)
|
|
want := "signature did not verify"
|
|
if err == nil || !strings.Contains(err.Error(), want) {
|
|
t.Errorf("Expected %v, received %v", want, err)
|
|
}
|
|
}
|
|
|
|
func TestProcessBlockHeader_DifferentSlots(t *testing.T) {
|
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
|
for i := 0; i < len(validators); i++ {
|
|
validators[i] = ðpb.Validator{
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
Slashed: true,
|
|
}
|
|
}
|
|
|
|
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
|
Validators: validators,
|
|
Slot: 10,
|
|
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
|
Fork: &pb.Fork{
|
|
PreviousVersion: []byte{0, 0, 0, 0},
|
|
CurrentVersion: []byte{0, 0, 0, 0},
|
|
},
|
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
lbhsr, err := ssz.HashTreeRoot(state.LatestBlockHeader())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
currentEpoch := helpers.CurrentEpoch(state)
|
|
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
|
if err != nil {
|
|
t.Fatalf("Failed to get domain form state: %v", err)
|
|
}
|
|
priv := bls.RandKey()
|
|
root, err := helpers.ComputeSigningRoot([]byte("hello"), dt)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
blockSig := priv.Sign(root[:])
|
|
validators[5896].PublicKey = priv.PublicKey().Marshal()
|
|
block := ðpb.SignedBeaconBlock{
|
|
Block: ðpb.BeaconBlock{
|
|
Slot: 1,
|
|
Body: ðpb.BeaconBlockBody{
|
|
RandaoReveal: []byte{'A', 'B', 'C'},
|
|
},
|
|
ParentRoot: lbhsr[:],
|
|
},
|
|
Signature: blockSig.Marshal(),
|
|
}
|
|
|
|
_, err = blocks.ProcessBlockHeader(state, block)
|
|
want := "is different than block slot"
|
|
if err == nil || !strings.Contains(err.Error(), want) {
|
|
t.Errorf("Expected %v, received %v", want, err)
|
|
}
|
|
}
|
|
|
|
func TestProcessBlockHeader_PreviousBlockRootNotSignedRoot(t *testing.T) {
|
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
|
for i := 0; i < len(validators); i++ {
|
|
validators[i] = ðpb.Validator{
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
Slashed: true,
|
|
}
|
|
}
|
|
|
|
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
|
Validators: validators,
|
|
Slot: 10,
|
|
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
|
Fork: &pb.Fork{
|
|
PreviousVersion: []byte{0, 0, 0, 0},
|
|
CurrentVersion: []byte{0, 0, 0, 0},
|
|
},
|
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
currentEpoch := helpers.CurrentEpoch(state)
|
|
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
|
if err != nil {
|
|
t.Fatalf("Failed to get domain form state: %v", err)
|
|
}
|
|
priv := bls.RandKey()
|
|
root, err := helpers.ComputeSigningRoot([]byte("hello"), dt)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
blockSig := priv.Sign(root[:])
|
|
validators[5896].PublicKey = priv.PublicKey().Marshal()
|
|
pID, err := helpers.BeaconProposerIndex(state)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
block := ðpb.SignedBeaconBlock{
|
|
Block: ðpb.BeaconBlock{
|
|
ProposerIndex: pID,
|
|
Slot: 10,
|
|
Body: ðpb.BeaconBlockBody{
|
|
RandaoReveal: []byte{'A', 'B', 'C'},
|
|
},
|
|
ParentRoot: []byte{'A'},
|
|
},
|
|
Signature: blockSig.Marshal(),
|
|
}
|
|
|
|
_, err = blocks.ProcessBlockHeader(state, block)
|
|
want := "does not match"
|
|
if err == nil || !strings.Contains(err.Error(), want) {
|
|
t.Errorf("Expected %v, received %v", want, err)
|
|
}
|
|
}
|
|
|
|
func TestProcessBlockHeader_SlashedProposer(t *testing.T) {
|
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
|
for i := 0; i < len(validators); i++ {
|
|
validators[i] = ðpb.Validator{
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
Slashed: true,
|
|
}
|
|
}
|
|
|
|
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
|
Validators: validators,
|
|
Slot: 10,
|
|
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
|
Fork: &pb.Fork{
|
|
PreviousVersion: []byte{0, 0, 0, 0},
|
|
CurrentVersion: []byte{0, 0, 0, 0},
|
|
},
|
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
parentRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
currentEpoch := helpers.CurrentEpoch(state)
|
|
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
|
if err != nil {
|
|
t.Fatalf("Failed to get domain form state: %v", err)
|
|
}
|
|
priv := bls.RandKey()
|
|
root, err := helpers.ComputeSigningRoot([]byte("hello"), dt)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
blockSig := priv.Sign(root[:])
|
|
|
|
validators[12683].PublicKey = priv.PublicKey().Marshal()
|
|
pID, err := helpers.BeaconProposerIndex(state)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
block := ðpb.SignedBeaconBlock{
|
|
Block: ðpb.BeaconBlock{
|
|
ProposerIndex: pID,
|
|
Slot: 10,
|
|
Body: ðpb.BeaconBlockBody{
|
|
RandaoReveal: []byte{'A', 'B', 'C'},
|
|
},
|
|
ParentRoot: parentRoot[:],
|
|
},
|
|
Signature: blockSig.Marshal(),
|
|
}
|
|
|
|
_, err = blocks.ProcessBlockHeader(state, block)
|
|
want := "was previously slashed"
|
|
if err == nil || !strings.Contains(err.Error(), want) {
|
|
t.Errorf("Expected %v, received %v", want, err)
|
|
}
|
|
}
|
|
|
|
func TestProcessBlockHeader_OK(t *testing.T) {
|
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
|
for i := 0; i < len(validators); i++ {
|
|
validators[i] = ðpb.Validator{
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
Slashed: true,
|
|
}
|
|
}
|
|
|
|
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
|
Validators: validators,
|
|
Slot: 10,
|
|
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
|
Fork: &pb.Fork{
|
|
PreviousVersion: []byte{0, 0, 0, 0},
|
|
CurrentVersion: []byte{0, 0, 0, 0},
|
|
},
|
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
latestBlockSignedRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
currentEpoch := helpers.CurrentEpoch(state)
|
|
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
|
if err != nil {
|
|
t.Fatalf("Failed to get domain form state: %v", err)
|
|
}
|
|
priv := bls.RandKey()
|
|
pID, err := helpers.BeaconProposerIndex(state)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
block := ðpb.SignedBeaconBlock{
|
|
Block: ðpb.BeaconBlock{
|
|
ProposerIndex: pID,
|
|
Slot: 10,
|
|
Body: ðpb.BeaconBlockBody{
|
|
RandaoReveal: []byte{'A', 'B', 'C'},
|
|
},
|
|
ParentRoot: latestBlockSignedRoot[:],
|
|
},
|
|
}
|
|
signingRoot, err := helpers.ComputeSigningRoot(block.Block, dt)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get signing root of block: %v", err)
|
|
}
|
|
blockSig := priv.Sign(signingRoot[:])
|
|
block.Signature = blockSig.Marshal()[:]
|
|
bodyRoot, err := stateutil.BlockBodyRoot(block.Block.Body)
|
|
if err != nil {
|
|
t.Fatalf("Failed to hash block bytes got: %v", err)
|
|
}
|
|
|
|
proposerIdx, err := helpers.BeaconProposerIndex(state)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
validators[proposerIdx].Slashed = false
|
|
validators[proposerIdx].PublicKey = priv.PublicKey().Marshal()
|
|
err = state.UpdateValidatorAtIndex(proposerIdx, validators[proposerIdx])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
newState, err := blocks.ProcessBlockHeader(state, block)
|
|
if err != nil {
|
|
t.Fatalf("Failed to process block header got: %v", err)
|
|
}
|
|
var zeroHash [32]byte
|
|
nsh := newState.LatestBlockHeader()
|
|
expected := ðpb.BeaconBlockHeader{
|
|
ProposerIndex: pID,
|
|
Slot: block.Block.Slot,
|
|
ParentRoot: latestBlockSignedRoot[:],
|
|
BodyRoot: bodyRoot[:],
|
|
StateRoot: zeroHash[:],
|
|
}
|
|
if !proto.Equal(nsh, expected) {
|
|
t.Errorf("Expected %v, received %v", expected, nsh)
|
|
}
|
|
}
|
|
|
|
func TestBlockSignatureSet_OK(t *testing.T) {
|
|
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
|
for i := 0; i < len(validators); i++ {
|
|
validators[i] = ðpb.Validator{
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
Slashed: true,
|
|
}
|
|
}
|
|
|
|
state, err := stateTrie.InitializeFromProto(&pb.BeaconState{
|
|
Validators: validators,
|
|
Slot: 10,
|
|
LatestBlockHeader: ðpb.BeaconBlockHeader{Slot: 9},
|
|
Fork: &pb.Fork{
|
|
PreviousVersion: []byte{0, 0, 0, 0},
|
|
CurrentVersion: []byte{0, 0, 0, 0},
|
|
},
|
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
latestBlockSignedRoot, err := stateutil.BlockHeaderRoot(state.LatestBlockHeader())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
currentEpoch := helpers.CurrentEpoch(state)
|
|
dt, err := helpers.Domain(state.Fork(), currentEpoch, params.BeaconConfig().DomainBeaconProposer, state.GenesisValidatorRoot())
|
|
if err != nil {
|
|
t.Fatalf("Failed to get domain form state: %v", err)
|
|
}
|
|
priv := bls.RandKey()
|
|
pID, err := helpers.BeaconProposerIndex(state)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
block := ðpb.SignedBeaconBlock{
|
|
Block: ðpb.BeaconBlock{
|
|
ProposerIndex: pID,
|
|
Slot: 10,
|
|
Body: ðpb.BeaconBlockBody{
|
|
RandaoReveal: []byte{'A', 'B', 'C'},
|
|
},
|
|
ParentRoot: latestBlockSignedRoot[:],
|
|
},
|
|
}
|
|
signingRoot, err := helpers.ComputeSigningRoot(block.Block, dt)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get signing root of block: %v", err)
|
|
}
|
|
blockSig := priv.Sign(signingRoot[:])
|
|
block.Signature = blockSig.Marshal()[:]
|
|
|
|
proposerIdx, err := helpers.BeaconProposerIndex(state)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
validators[proposerIdx].Slashed = false
|
|
validators[proposerIdx].PublicKey = priv.PublicKey().Marshal()
|
|
err = state.UpdateValidatorAtIndex(proposerIdx, validators[proposerIdx])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
set, err := blocks.BlockSignatureSet(state, block)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
verified, err := set.Verify()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !verified {
|
|
t.Error("Block signature set returned a set which was unable to be verified")
|
|
}
|
|
}
|