Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix beacon-chain/sync Test Race #390

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis-bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ build --verbose_failures
build --sandbox_debug
build --test_output=errors
build --flaky_test_attempts=5
build --features=race
39 changes: 22 additions & 17 deletions beacon-chain/sync/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -785,22 +785,26 @@ func TestSavingBlocksInSync(t *testing.T) {
t.Fatalf("unable to get hash of crystallized state: %v", err)
}

block := &pb.BeaconBlock{
MainChainRef: []byte{1, 2, 3},
ParentHash: generichash,
SlotNumber: uint64(20),
CrystallizedStateHash: crystallizedStateHash[:],
}
getBlockResponseMsg := func(slotNumber uint64) p2p.Message {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is neat!

block := &pb.BeaconBlock{
MainChainRef: []byte{1, 2, 3},
ParentHash: generichash,
SlotNumber: slotNumber,
CrystallizedStateHash: crystallizedStateHash[:],
}

blockResponse := &pb.BeaconBlockResponse{
Block: block,
}
blockResponse := &pb.BeaconBlockResponse{
Block: block,
}

msg1 := p2p.Message{
Peer: p2p.Peer{},
Data: blockResponse,
return p2p.Message{
Peer: p2p.Peer{},
Data: blockResponse,
}
}

msg1 := getBlockResponseMsg(0)

msg2 := p2p.Message{
Peer: p2p.Peer{},
Data: incorrectStateResponse,
Expand All @@ -818,24 +822,25 @@ func TestSavingBlocksInSync(t *testing.T) {
ss.crystallizedStateBuf <- msg2

if crystallizedStateHash != ss.initialCrystallizedStateHash {
t.Fatalf("Crystallized state hash not updated: %x", blockResponse.Block.CrystallizedStateHash)
br := msg1.Data.(*pb.BeaconBlockResponse)
t.Fatalf("Crystallized state hash not updated: %x", br.Block.CrystallizedStateHash)
}

blockResponse.Block.SlotNumber = 30
msg1.Data = blockResponse
msg1 = getBlockResponseMsg(30)
ss.blockBuf <- msg1

if stateResponse.CrystallizedState.GetLastFinalizedEpoch() != ss.currentSlotNumber {
t.Fatalf("slotnumber saved when it was not supposed too: %v", stateResponse.CrystallizedState.GetLastFinalizedEpoch())
}

blockResponse.Block.SlotNumber = 100
msg1 = getBlockResponseMsg(100)
ss.blockBuf <- msg1

ss.cancel()
<-exitRoutine

if blockResponse.Block.GetSlotNumber() != ss.currentSlotNumber {
br := msg1.Data.(*pb.BeaconBlockResponse)
if br.Block.GetSlotNumber() != ss.currentSlotNumber {
t.Fatalf("slotnumber not updated despite receiving a valid block: %v", ss.currentSlotNumber)
}

Expand Down
1 change: 1 addition & 0 deletions client/contracts/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ go_test(
name = "go_default_test",
srcs = ["sharding_manager_test.go"],
embed = [":go_default_library"],
race = "off",
deps = [
"//client/params:go_default_library",
"@com_github_ethereum_go_ethereum//accounts/abi/bind:go_default_library",
Expand Down
23 changes: 23 additions & 0 deletions client/syncer/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,29 @@ go_test(
"@com_github_ethereum_go_ethereum//core:go_default_library",
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
"@com_github_ethereum_go_ethereum//crypto:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
],
)

# by default gazelle tries to add all the test files to the first
# go_test; we need to exclude the tests that we want to configure
# in a particular way
# gazelle:exclude service_norace_test.go

go_test(
name = "go_norace_test",
srcs = ["service_norace_test.go"],
embed = [":go_default_library"],
race = "off", # TODO(#377): fix issues with race detection testing.
deps = [
"//client/mainchain:go_default_library",
"//client/params:go_default_library",
"//client/types:go_default_library",
"//proto/sharding/p2p/v1:go_default_library",
"//shared/database:go_default_library",
"//shared/p2p:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
],
Expand Down
98 changes: 98 additions & 0 deletions client/syncer/service_norace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package syncer

import (
"fmt"
"io/ioutil"
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
gethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/prysmaticlabs/prysm/client/mainchain"
"github.com/prysmaticlabs/prysm/client/params"
"github.com/prysmaticlabs/prysm/client/types"
pb "github.com/prysmaticlabs/prysm/proto/sharding/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/database"
"github.com/prysmaticlabs/prysm/shared/p2p"
"github.com/sirupsen/logrus"
logTest "github.com/sirupsen/logrus/hooks/test"
)

func init() {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(ioutil.Discard)
}

// This test checks the proper functioning of the handleCollationBodyRequests goroutine
// by listening to the responseSent channel which occurs after successful
// construction and sending of a response via p2p.
func TestHandleCollationBodyRequests(t *testing.T) {
hook := logTest.NewGlobal()

config := &database.DBConfig{Name: "", DataDir: "", InMemory: true}
shardChainDB, err := database.NewDB(config)
if err != nil {
t.Fatalf("unable to setup db: %v", err)
}
server, err := p2p.NewServer()
if err != nil {
t.Fatalf("Unable to setup p2p server: %v", err)
}

body := []byte{1, 2, 3, 4, 5}
shardID := big.NewInt(0)
chunkRoot := gethTypes.DeriveSha(types.Chunks(body))
period := big.NewInt(0)
proposerAddress := common.BytesToAddress([]byte{})

header := types.NewCollationHeader(shardID, &chunkRoot, period, &proposerAddress, [32]byte{})
// Stores the collation into the inmemory kv store shardChainDB.
collation := types.NewCollation(header, body, nil)

shard := types.NewShard(shardID, shardChainDB.DB())

if err := shard.SaveCollation(collation); err != nil {
t.Fatalf("Could not store collation in shardChainDB: %v", err)
}

syncer, err := NewSyncer(params.DefaultConfig(), &mainchain.SMCClient{}, server, shardChainDB, 0)
if err != nil {
t.Fatalf("Unable to setup syncer service: %v", err)
}
syncer.Start()
syncer.collationBodyBuf = make(chan p2p.Message)

doneChan := make(chan struct{})
exitRoutine := make(chan bool)

go func() {
syncer.run(doneChan)
<-exitRoutine
}()

msg := p2p.Message{
Peer: p2p.Peer{},
Data: &pb.CollationBodyRequest{
ChunkRoot: chunkRoot.Bytes(),
ShardId: shardID.Uint64(),
Period: period.Uint64(),
ProposerAddress: proposerAddress.Bytes(),
},
}
syncer.collationBodyBuf <- msg
doneChan <- struct{}{}
exitRoutine <- true

logMsg := hook.Entries[1].Message
want := fmt.Sprintf("Received p2p request of type: %T", &pb.CollationBodyRequest{})
if logMsg != want {
t.Errorf("incorrect log, expected %s, got %s", want, logMsg)
}

logMsg = hook.Entries[4].Message
want = fmt.Sprintf("Responding to p2p collation request")
if logMsg != want {
t.Errorf("incorrect log, expected %s, got %s", want, logMsg)
}
hook.Reset()
}
87 changes: 0 additions & 87 deletions client/syncer/service_test.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,18 @@
package syncer

import (
"fmt"
"io/ioutil"
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
gethTypes "github.com/ethereum/go-ethereum/core/types"
"github.com/prysmaticlabs/prysm/client/mainchain"
"github.com/prysmaticlabs/prysm/client/params"
"github.com/prysmaticlabs/prysm/client/types"
pb "github.com/prysmaticlabs/prysm/proto/sharding/p2p/v1"
"github.com/prysmaticlabs/prysm/shared"
"github.com/prysmaticlabs/prysm/shared/database"
"github.com/prysmaticlabs/prysm/shared/p2p"
"github.com/sirupsen/logrus"
logTest "github.com/sirupsen/logrus/hooks/test"
)

var _ = shared.Service(&Syncer{})

func init() {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(ioutil.Discard)
}

func TestStop(t *testing.T) {
hook := logTest.NewGlobal()

Expand Down Expand Up @@ -63,77 +50,3 @@ func TestStop(t *testing.T) {
}
hook.Reset()
}

// This test checks the proper functioning of the handleCollationBodyRequests goroutine
// by listening to the responseSent channel which occurs after successful
// construction and sending of a response via p2p.
func TestHandleCollationBodyRequests(t *testing.T) {
hook := logTest.NewGlobal()

config := &database.DBConfig{Name: "", DataDir: "", InMemory: true}
shardChainDB, err := database.NewDB(config)
if err != nil {
t.Fatalf("unable to setup db: %v", err)
}
server, err := p2p.NewServer()
if err != nil {
t.Fatalf("Unable to setup p2p server: %v", err)
}

body := []byte{1, 2, 3, 4, 5}
shardID := big.NewInt(0)
chunkRoot := gethTypes.DeriveSha(types.Chunks(body))
period := big.NewInt(0)
proposerAddress := common.BytesToAddress([]byte{})

header := types.NewCollationHeader(shardID, &chunkRoot, period, &proposerAddress, [32]byte{})
// Stores the collation into the inmemory kv store shardChainDB.
collation := types.NewCollation(header, body, nil)

shard := types.NewShard(shardID, shardChainDB.DB())

if err := shard.SaveCollation(collation); err != nil {
t.Fatalf("Could not store collation in shardChainDB: %v", err)
}

syncer, err := NewSyncer(params.DefaultConfig(), &mainchain.SMCClient{}, server, shardChainDB, 0)
if err != nil {
t.Fatalf("Unable to setup syncer service: %v", err)
}
syncer.Start()
syncer.collationBodyBuf = make(chan p2p.Message)

doneChan := make(chan struct{})
exitRoutine := make(chan bool)

go func() {
syncer.run(doneChan)
<-exitRoutine
}()

msg := p2p.Message{
Peer: p2p.Peer{},
Data: &pb.CollationBodyRequest{
ChunkRoot: chunkRoot.Bytes(),
ShardId: shardID.Uint64(),
Period: period.Uint64(),
ProposerAddress: proposerAddress.Bytes(),
},
}
syncer.collationBodyBuf <- msg
doneChan <- struct{}{}
exitRoutine <- true

logMsg := hook.Entries[1].Message
want := fmt.Sprintf("Received p2p request of type: %T", &pb.CollationBodyRequest{})
if logMsg != want {
t.Errorf("incorrect log, expected %s, got %s", want, logMsg)
}

logMsg = hook.Entries[4].Message
want = fmt.Sprintf("Responding to p2p collation request")
if logMsg != want {
t.Errorf("incorrect log, expected %s, got %s", want, logMsg)
}
hook.Reset()
}
24 changes: 15 additions & 9 deletions shared/p2p/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"discovery_test.go",
"feed_example_test.go",
"feed_test.go",
"options_test.go",
Expand All @@ -47,22 +46,29 @@ go_test(
"@com_github_ethereum_go_ethereum//event:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
"@com_github_libp2p_go_floodsub//:go_default_library",
"@com_github_libp2p_go_libp2p//p2p/discovery:go_default_library",
"@com_github_libp2p_go_libp2p//p2p/host/basic:go_default_library",
"@com_github_libp2p_go_libp2p_peer//:go_default_library",
"@com_github_libp2p_go_libp2p_swarm//testing:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
],
)

# by default gazelle tries to add all the test files to the first
# go_test; we want to treat feed_concurrent_test.go differently
# gazelle:exclude feed_concurrent_test.go
# go_test; we need to exclude the tests that we want to configure
# in a particular way
# gazelle:exclude discovery_norace_test.go
# gazelle:exclude service_norace_test.go

go_test(
name = "go_feed_concurrent_write_test",
srcs = ["feed_concurrent_test.go"],
name = "go_norace_test",
srcs = [
"discovery_norace_test.go",
"service_norace_test.go",
],
embed = [":go_default_library"],
race = "on",
race = "off", # TODO(#377): fix issues with race detection testing.
deps = [
"@com_github_libp2p_go_libp2p//p2p/host/basic:go_default_library",
"@com_github_libp2p_go_libp2p_swarm//testing:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
],
)
Loading