package blockchain import ( "bytes" "context" "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" testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" "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) } genesisBlkRoot, err := ssz.SigningRoot(genesis) if err != nil { t.Fatal(err) } cp := ðpb.Checkpoint{Root: genesisBlkRoot[:]} if err := chainService.forkChoiceStore.GenesisStore(ctx, cp, cp); 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 applying state transition") } func TestReceiveReceiveBlockNoPubsub_CanSaveHeadInfo(t *testing.T) { hook := logTest.NewGlobal() db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) ctx := context.Background() chainService := setupBeaconChain(t, db) headBlk := ðpb.BeaconBlock{Slot: 100} if err := db.SaveBlock(ctx, headBlk); err != nil { t.Fatal(err) } r, err := ssz.SigningRoot(headBlk) if err != nil { t.Fatal(err) } chainService.forkChoiceStore = &store{headRoot: r[:]} if err := chainService.ReceiveBlockNoPubsub(ctx, ðpb.BeaconBlock{ Slot: 1, Body: ðpb.BeaconBlockBody{}}); err != nil { t.Fatal(err) } if !bytes.Equal(r[:], chainService.HeadRoot()) { t.Error("Incorrect head root saved") } if !reflect.DeepEqual(headBlk, chainService.HeadBlock()) { t.Error("Incorrect head block saved") } testutil.AssertLogsContain(t, hook, "Saved new head info") } func TestReceiveReceiveBlockNoPubsub_SameHead(t *testing.T) { hook := logTest.NewGlobal() db := testDB.SetupDB(t) defer testDB.TeardownDB(t, db) ctx := context.Background() chainService := setupBeaconChain(t, db) headBlk := ðpb.BeaconBlock{} if err := db.SaveBlock(ctx, headBlk); err != nil { t.Fatal(err) } newBlk := ðpb.BeaconBlock{ Slot: 1, Body: ðpb.BeaconBlockBody{}} newRoot, _ := ssz.SigningRoot(newBlk) if err := db.SaveBlock(ctx, newBlk); err != nil { t.Fatal(err) } chainService.forkChoiceStore = &store{headRoot: newRoot[:]} chainService.canonicalRoots[0] = newRoot[:] if err := chainService.ReceiveBlockNoPubsub(ctx, newBlk); err != nil { t.Fatal(err) } testutil.AssertLogsDoNotContain(t, hook, "Saved new head info") } 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, ðpb.Checkpoint{}, ðpb.Checkpoint{}); 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 applying state transition") testutil.AssertLogsDoNotContain(t, hook, "Finished fork choice") }