package blockchain import ( "context" "encoding/binary" "reflect" "testing" "github.com/prysmaticlabs/go-ssz" b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/core/state" v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators" testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" "github.com/prysmaticlabs/prysm/beacon-chain/internal" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/testutil" logTest "github.com/sirupsen/logrus/hooks/test" ) func TestReceiveBlock_ProcessCorrectly(t *testing.T) { hook := logTest.NewGlobal() db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) ctx := context.Background() chainService := setupBeaconChain(t, db) deposits, privKeys := testutil.SetupInitialDeposits(t, 100) beaconState, err := state.GenesisBeaconState(deposits, 0, ðpb.Eth1Data{}) if err != nil { t.Fatal(err) } beaconState.Eth1DepositIndex = 100 stateRoot, err := ssz.HashTreeRoot(beaconState) if err != nil { t.Fatal(err) } genesis := b.NewGenesisBlock(stateRoot[:]) bodyRoot, err := ssz.HashTreeRoot(genesis.Body) if err != nil { t.Fatal(err) } if err := chainService.forkChoiceStore.GenesisStore(ctx, beaconState); err != nil { t.Fatal(err) } beaconState.LatestBlockHeader = ðpb.BeaconBlockHeader{ Slot: genesis.Slot, ParentRoot: genesis.ParentRoot, BodyRoot: bodyRoot[:], StateRoot: genesis.StateRoot, } if err := chainService.beaconDB.SaveBlock(ctx, genesis); err != nil { t.Fatalf("Could not save block to db: %v", err) } parentRoot, err := ssz.SigningRoot(genesis) if err != nil { t.Fatal(err) } if err := db.SaveState(ctx, beaconState, parentRoot); err != nil { t.Fatal(err) } slot := beaconState.Slot + 1 epoch := helpers.SlotToEpoch(slot) beaconState.Slot++ randaoReveal, err := testutil.CreateRandaoReveal(beaconState, epoch, privKeys) if err != nil { t.Fatal(err) } beaconState.Slot-- block := ðpb.BeaconBlock{ Slot: slot, ParentRoot: parentRoot[:], Body: ðpb.BeaconBlockBody{ Eth1Data: ðpb.Eth1Data{ DepositCount: uint64(len(deposits)), DepositRoot: []byte("a"), BlockHash: []byte("b"), }, RandaoReveal: randaoReveal[:], Attestations: nil, }, } stateRootCandidate, err := state.ExecuteStateTransitionNoVerify(context.Background(), beaconState, block) if err != nil { t.Fatal(err) } stateRoot, err = ssz.HashTreeRoot(stateRootCandidate) if err != nil { t.Fatal(err) } block.StateRoot = stateRoot[:] block, err = testutil.SignBlock(beaconState, block, privKeys) if err != nil { t.Error(err) } if err := chainService.beaconDB.SaveBlock(ctx, block); err != nil { t.Fatal(err) } if err := chainService.ReceiveBlock(context.Background(), block); err != nil { t.Errorf("Block failed processing: %v", err) } testutil.AssertLogsContain(t, hook, "Finished state transition and updated fork choice store for block") testutil.AssertLogsContain(t, hook, "Finished applying fork choice for block") } func TestReceiveBlockNoPubsubForkchoice_ProcessCorrectly(t *testing.T) { hook := logTest.NewGlobal() db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) ctx := context.Background() chainService := setupBeaconChain(t, db) deposits, privKeys := testutil.SetupInitialDeposits(t, 100) beaconState, err := state.GenesisBeaconState(deposits, 0, ðpb.Eth1Data{}) if err != nil { t.Fatal(err) } beaconState.Eth1DepositIndex = 100 stateRoot, err := ssz.HashTreeRoot(beaconState) if err != nil { t.Fatal(err) } genesis := b.NewGenesisBlock(stateRoot[:]) bodyRoot, err := ssz.HashTreeRoot(genesis.Body) if err != nil { t.Fatal(err) } if err := chainService.forkChoiceStore.GenesisStore(ctx, beaconState); err != nil { t.Fatal(err) } beaconState.LatestBlockHeader = ðpb.BeaconBlockHeader{ Slot: genesis.Slot, ParentRoot: genesis.ParentRoot, BodyRoot: bodyRoot[:], StateRoot: genesis.StateRoot, } if err := chainService.beaconDB.SaveBlock(ctx, genesis); err != nil { t.Fatalf("Could not save block to db: %v", err) } parentRoot, err := ssz.SigningRoot(genesis) if err != nil { t.Fatal(err) } if err := db.SaveState(ctx, beaconState, parentRoot); err != nil { t.Fatal(err) } slot := beaconState.Slot + 1 epoch := helpers.SlotToEpoch(slot) beaconState.Slot++ randaoReveal, err := testutil.CreateRandaoReveal(beaconState, epoch, privKeys) if err != nil { t.Fatal(err) } beaconState.Slot-- block := ðpb.BeaconBlock{ Slot: slot, ParentRoot: parentRoot[:], Body: ðpb.BeaconBlockBody{ Eth1Data: ðpb.Eth1Data{ DepositCount: uint64(len(deposits)), DepositRoot: []byte("a"), BlockHash: []byte("b"), }, RandaoReveal: randaoReveal[:], Attestations: nil, }, } stateRootCandidate, err := state.ExecuteStateTransitionNoVerify(context.Background(), beaconState, block) if err != nil { t.Fatal(err) } stateRoot, err = ssz.HashTreeRoot(stateRootCandidate) if err != nil { t.Fatal(err) } block.StateRoot = stateRoot[:] block, err = testutil.SignBlock(beaconState, block, privKeys) if err != nil { t.Error(err) } if err := chainService.beaconDB.SaveBlock(ctx, block); err != nil { t.Fatal(err) } if err := chainService.ReceiveBlockNoPubsubForkchoice(context.Background(), block); err != nil { t.Errorf("Block failed processing: %v", err) } testutil.AssertLogsContain(t, hook, "Finished state transition and updated fork choice store for block") testutil.AssertLogsDoNotContain(t, hook, "Finished fork choice") } func TestSaveValidatorIdx_SaveRetrieveWorks(t *testing.T) { db := internal.SetupDBDeprecated(t) defer internal.TeardownDBDeprecated(t, db) ctx := context.Background() epoch := uint64(1) v.InsertActivatedIndices(epoch+1, []uint64{0, 1, 2}) var validators []*ethpb.Validator for i := 0; i < 3; i++ { pubKeyBuf := make([]byte, params.BeaconConfig().BLSPubkeyLength) binary.PutUvarint(pubKeyBuf, uint64(i)) validators = append(validators, ðpb.Validator{ PublicKey: pubKeyBuf, }) } state := &pb.BeaconState{ Validators: validators, Slot: epoch * params.BeaconConfig().SlotsPerEpoch, } chainService := setupBeaconChain(t, db) if err := chainService.saveValidatorIdx(ctx, state); err != nil { t.Fatalf("Could not save validator idx: %v", err) } wantedIdx := uint64(2) idx, _, err := chainService.beaconDB.ValidatorIndex(ctx, bytesutil.ToBytes48(validators[wantedIdx].PublicKey)) if err != nil { t.Fatalf("Could not get validator index: %v", err) } if wantedIdx != idx { t.Errorf("Wanted: %d, got: %d", wantedIdx, idx) } if v.ActivatedValFromEpoch(epoch) != nil { t.Errorf("Activated validators mapping for epoch %d still there", epoch) } } func TestSaveValidatorIdx_IdxNotInState(t *testing.T) { db := internal.SetupDBDeprecated(t) defer internal.TeardownDBDeprecated(t, db) epoch := uint64(100) ctx := context.Background() // Tried to insert 5 active indices to DB with only 3 validators in state v.InsertActivatedIndices(epoch+1, []uint64{0, 1, 2, 3, 4}) var validators []*ethpb.Validator for i := 0; i < 3; i++ { pubKeyBuf := make([]byte, params.BeaconConfig().BLSPubkeyLength) binary.PutUvarint(pubKeyBuf, uint64(i)) validators = append(validators, ðpb.Validator{ PublicKey: pubKeyBuf, }) } state := &pb.BeaconState{ Validators: validators, Slot: epoch * params.BeaconConfig().SlotsPerEpoch, } chainService := setupBeaconChain(t, db) if err := chainService.saveValidatorIdx(ctx, state); err != nil { t.Fatalf("Could not save validator idx: %v", err) } wantedIdx := uint64(2) idx, _, err := chainService.beaconDB.ValidatorIndex(ctx, bytesutil.ToBytes48(validators[wantedIdx].PublicKey)) if err != nil { t.Fatalf("Could not get validator index: %v", err) } if wantedIdx != idx { t.Errorf("Wanted: %d, got: %d", wantedIdx, idx) } if v.ActivatedValFromEpoch(epoch) != nil { t.Errorf("Activated validators mapping for epoch %d still there", epoch) } // Verify the skipped validators are included in the next epoch if !reflect.DeepEqual(v.ActivatedValFromEpoch(epoch+2), []uint64{3, 4}) { t.Error("Did not get wanted validator from activation queue") } }