mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-28 14:17:17 +00:00
748d513c62
* proper error checking and type assertions
319 lines
8.8 KiB
Go
319 lines
8.8 KiB
Go
package blockchain
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
|
"github.com/prysmaticlabs/go-ssz"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
|
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
|
|
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
|
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
|
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
"github.com/prysmaticlabs/prysm/shared/testutil"
|
|
messagediff "gopkg.in/d4l3k/messagediff.v1"
|
|
)
|
|
|
|
func TestFilterBoundaryCandidates_FilterCorrect(t *testing.T) {
|
|
ctx := context.Background()
|
|
db := testDB.SetupDB(t)
|
|
defer testDB.TeardownDB(t, db)
|
|
|
|
cfg := &Config{BeaconDB: db}
|
|
service, err := NewService(ctx, cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for i := uint64(0); i < 500; i++ {
|
|
if err := st.SetSlot(i); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root := [32]byte{}
|
|
copy(root[:], bytesutil.Bytes32(i))
|
|
service.initSyncState[root] = st.Copy()
|
|
if helpers.IsEpochStart(i) {
|
|
service.boundaryRoots = append(service.boundaryRoots, root)
|
|
}
|
|
}
|
|
lastIndex := len(service.boundaryRoots) - 1
|
|
for i := uint64(500); i < 2000; i++ {
|
|
if err := st.SetSlot(i); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root := [32]byte{}
|
|
copy(root[:], bytesutil.Bytes32(i))
|
|
service.initSyncState[root] = st.Copy()
|
|
}
|
|
// Set current state.
|
|
latestSlot := helpers.RoundUpToNearestEpoch(2000)
|
|
if err := st.SetSlot(latestSlot); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
lastRoot := [32]byte{}
|
|
copy(lastRoot[:], bytesutil.Bytes32(latestSlot))
|
|
|
|
service.initSyncState[lastRoot] = st.Copy()
|
|
service.finalizedCheckpt = ðpb.Checkpoint{
|
|
Epoch: 0,
|
|
Root: []byte{},
|
|
}
|
|
service.filterBoundaryCandidates(context.Background(), lastRoot, st)
|
|
if len(service.boundaryRoots[lastIndex+1:]) == 0 {
|
|
t.Fatal("Wanted non zero added boundary roots")
|
|
}
|
|
for _, rt := range service.boundaryRoots[lastIndex+1:] {
|
|
st, ok := service.initSyncState[rt]
|
|
if !ok {
|
|
t.Error("Root doen't exist in cache map")
|
|
continue
|
|
}
|
|
if !(helpers.IsEpochStart(st.Slot()) || helpers.IsEpochStart(st.Slot()-1) || helpers.IsEpochStart(st.Slot()+1)) {
|
|
t.Errorf("boundary roots not validly stored. They have slot %d", st.Slot())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFilterBoundaryCandidates_HandleSkippedSlots(t *testing.T) {
|
|
ctx := context.Background()
|
|
db := testDB.SetupDB(t)
|
|
defer testDB.TeardownDB(t, db)
|
|
|
|
cfg := &Config{BeaconDB: db}
|
|
service, err := NewService(ctx, cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for i := uint64(0); i < 500; i++ {
|
|
if err := st.SetSlot(i); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root := [32]byte{}
|
|
copy(root[:], bytesutil.Bytes32(i))
|
|
service.initSyncState[root] = st.Copy()
|
|
if helpers.IsEpochStart(i) {
|
|
service.boundaryRoots = append(service.boundaryRoots, root)
|
|
}
|
|
}
|
|
lastIndex := len(service.boundaryRoots) - 1
|
|
for i := uint64(500); i < 2000; i++ {
|
|
if err := st.SetSlot(i); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root := [32]byte{}
|
|
copy(root[:], bytesutil.Bytes32(i))
|
|
// save only for offsetted slots
|
|
if helpers.IsEpochStart(i + 10) {
|
|
service.initSyncState[root] = st.Copy()
|
|
}
|
|
}
|
|
// Set current state.
|
|
latestSlot := helpers.RoundUpToNearestEpoch(2000)
|
|
if err := st.SetSlot(latestSlot); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
lastRoot := [32]byte{}
|
|
copy(lastRoot[:], bytesutil.Bytes32(latestSlot))
|
|
|
|
service.initSyncState[lastRoot] = st.Copy()
|
|
service.finalizedCheckpt = ðpb.Checkpoint{
|
|
Epoch: 0,
|
|
Root: []byte{},
|
|
}
|
|
service.filterBoundaryCandidates(context.Background(), lastRoot, st)
|
|
if len(service.boundaryRoots[lastIndex+1:]) == 0 {
|
|
t.Fatal("Wanted non zero added boundary roots")
|
|
}
|
|
for _, rt := range service.boundaryRoots[lastIndex+1:] {
|
|
st, ok := service.initSyncState[rt]
|
|
if !ok {
|
|
t.Error("Root doen't exist in cache map")
|
|
continue
|
|
}
|
|
if st.Slot() >= 500 {
|
|
// Ignore head boundary root.
|
|
if st.Slot() == 2016 {
|
|
continue
|
|
}
|
|
if !helpers.IsEpochStart(st.Slot() + 10) {
|
|
t.Errorf("boundary roots not validly stored. They have slot %d "+
|
|
"instead of the offset from epoch start", st.Slot())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPruneOldStates_AlreadyFinalized(t *testing.T) {
|
|
ctx := context.Background()
|
|
db := testDB.SetupDB(t)
|
|
defer testDB.TeardownDB(t, db)
|
|
|
|
cfg := &Config{BeaconDB: db}
|
|
service, err := NewService(ctx, cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for i := uint64(100); i < 200; i++ {
|
|
if err := st.SetSlot(i); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root := [32]byte{}
|
|
copy(root[:], bytesutil.Bytes32(i))
|
|
service.initSyncState[root] = st.Copy()
|
|
service.boundaryRoots = append(service.boundaryRoots, root)
|
|
}
|
|
finalizedEpoch := uint64(5)
|
|
service.finalizedCheckpt = ðpb.Checkpoint{Epoch: finalizedEpoch}
|
|
service.pruneOldStates()
|
|
for _, rt := range service.boundaryRoots {
|
|
st, ok := service.initSyncState[rt]
|
|
if !ok {
|
|
t.Error("Root doen't exist in cache map")
|
|
continue
|
|
}
|
|
if st.Slot() < helpers.StartSlot(finalizedEpoch) {
|
|
t.Errorf("State with slot %d still exists and not pruned", st.Slot())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPruneNonBoundary_CanPrune(t *testing.T) {
|
|
ctx := context.Background()
|
|
db := testDB.SetupDB(t)
|
|
defer testDB.TeardownDB(t, db)
|
|
|
|
cfg := &Config{BeaconDB: db}
|
|
service, err := NewService(ctx, cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
st, err := stateTrie.InitializeFromProtoUnsafe(&pb.BeaconState{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
for i := uint64(0); i < 2000; i++ {
|
|
if err := st.SetSlot(i); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root := [32]byte{}
|
|
copy(root[:], bytesutil.Bytes32(i))
|
|
service.initSyncState[root] = st.Copy()
|
|
if helpers.IsEpochStart(i) {
|
|
service.boundaryRoots = append(service.boundaryRoots, root)
|
|
}
|
|
}
|
|
service.pruneNonBoundaryStates()
|
|
for _, rt := range service.boundaryRoots {
|
|
st, ok := service.initSyncState[rt]
|
|
if !ok {
|
|
t.Error("Root doesn't exist in cache map")
|
|
continue
|
|
}
|
|
if !helpers.IsEpochStart(st.Slot()) {
|
|
t.Errorf("Non boundary state with slot %d still exists and not pruned", st.Slot())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenerateState_CorrectlyGenerated(t *testing.T) {
|
|
db := testDB.SetupDB(t)
|
|
defer testDB.TeardownDB(t, db)
|
|
cfg := &Config{BeaconDB: db, StateGen: stategen.New(db, cache.NewStateSummaryCache())}
|
|
service, err := NewService(context.Background(), cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
beaconState, privs := testutil.DeterministicGenesisState(t, 32)
|
|
genesisBlock := blocks.NewGenesisBlock([]byte{})
|
|
bodyRoot, err := ssz.HashTreeRoot(genesisBlock.Block)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = beaconState.SetLatestBlockHeader(ðpb.BeaconBlockHeader{
|
|
Slot: genesisBlock.Block.Slot,
|
|
ParentRoot: genesisBlock.Block.ParentRoot,
|
|
StateRoot: params.BeaconConfig().ZeroHash[:],
|
|
BodyRoot: bodyRoot[:],
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := beaconState.SetSlashings(make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cp := beaconState.CurrentJustifiedCheckpoint()
|
|
mockRoot := [32]byte{}
|
|
copy(mockRoot[:], "hello-world")
|
|
cp.Root = mockRoot[:]
|
|
if err := beaconState.SetCurrentJustifiedCheckpoint(cp); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = db.SaveBlock(context.Background(), genesisBlock)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
genRoot, err := ssz.HashTreeRoot(genesisBlock)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = db.SaveState(context.Background(), beaconState, genRoot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
lastBlock := ðpb.SignedBeaconBlock{}
|
|
for i := uint64(1); i < 10; i++ {
|
|
block, err := testutil.GenerateFullBlock(beaconState, privs, testutil.DefaultBlockGenConfig(), i)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = db.SaveBlock(context.Background(), block)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
lastBlock = block
|
|
}
|
|
root, err := ssz.HashTreeRoot(lastBlock.Block)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
newState, err := service.generateState(context.Background(), genRoot, root)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !ssz.DeepEqual(newState.InnerStateUnsafe(), beaconState.InnerStateUnsafe()) {
|
|
diff, _ := messagediff.PrettyDiff(newState.InnerStateUnsafe(), beaconState.InnerStateUnsafe())
|
|
t.Errorf("Generated state is different from what is expected: %s", diff)
|
|
}
|
|
}
|