aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml52
-rw-r--r--GNUmakefile24
-rw-r--r--Gopkg.lock12
-rw-r--r--core/configuration-chain_test.go96
-rw-r--r--core/consensus_test.go72
-rw-r--r--integration_test/consensus_test.go31
6 files changed, 230 insertions, 57 deletions
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..faf9a24
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,52 @@
+language: go
+go_import_path: github.com/dexon-foundation/dexon-consensus
+os: linux
+dist: trusty
+sudo: required
+go: 1.11.x
+addons:
+ apt:
+ packages:
+ - openssl
+ - libssl-dev
+ - libgmp-dev
+script:
+- set -e
+- bin/install_tools.sh
+- dep ensure -v
+- make dep
+- |
+ if [ "${TRAVIS_BRANCH}" == "master" ]; then
+ make test
+ else
+ make test-short
+ fi
+- make
+git:
+ depth: 3
+cache:
+ directories:
+ - vendor
+before_cache:
+- rm -rf vendor/github.com/dexon-foundation/bls
+- rm -rf vendor/github.com/dexon-foundation/mcl
+env:
+- ONLY_INTEGRATION_TEST=true NO_TEST_RACE=true
+- ONLY_INTEGRATION_TEST=true
+- NO_INTEGRATION_TEST=true
+matrix:
+ allow_failures:
+ - env: ONLY_INTEGRATION_TEST=true
+ fast_finish: true
+ include:
+ - name: Lint
+ script:
+ - set -e
+ - bin/install_tools.sh
+ - dep ensure -v
+ - make dep
+ - make lint
+ - make vet
+notifications:
+ slack:
+ secure: Asyh9eDoT6/zn6bnpDQ0CabPk6YwP2N5ACmyltT9ozeJLCoOGAsWmmVyUpHJkF/yA6Zd59ilGfC4hFMy+Wk+DZvbQL27QTsgcLf+sHzbD2CunCuJzDkO8b6JSKgZ60BH5XCLSxtf7p/0lYn+MnXCg+Ly/CFN5fwacp6gybZ+UqlH+xjvW8VSZnka2YHzRIB3P5+013scPvjr9WIJ/wxviUZetFM+AOL3Uf2t7hXEGTceYEN8bIchElazJoYpzzN0nZwHJ7/IjdbSWNnXfuJUlEEqrUHeY+shLIGZvGES9zqPIOHPFJQyh3oyknYY08wsZJpU7InS/wbOs43Pte78vhoYQbxIi5Pg4bPGAWJgTePllFV99rk7ELBoDPrEp/auSxlEu1rhq9yFsef0HePrp2KuAQHz5twnnaF3kAR6IUoa/DgWNqgw71QqdWFihEeeQGn/sYUocdp2Jc1ZVIUrafICjCPJFf5pSoAyBVnx0lA4MhyEEVdwtoOR2XXn6G4+58/IF3VfH2gqS8OlE10uA71wQb3np74RBNA4mfke3mjPKwKNXJug/txPBFxsGGq9kOVwYVm4QUwkJ5hbHciGFv29Pzvo1fhJSE5/YluaHhzLHeb8vVTBTPMwzApQBL2ZCdKPZ9bppzJiR+zR+JacE/jrHnQfpMJYoykvcGQrN/s=
diff --git a/GNUmakefile b/GNUmakefile
index 51c6b34..b7af3f5 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -44,6 +44,21 @@ else
endif
endef
+GO_TEST_TIMEOUT := 20m
+
+TEST_TARGET := go list ./... | grep -v 'vendor'
+ifeq ($(NO_INTEGRATION_TEST), true)
+ GO_TEST_TIMEOUT := 10m
+ TEST_TARGET := $(TEST_TARGET) | grep -v 'integration_test'
+else ifeq ($(ONLY_INTEGRATION_TEST), true)
+ TEST_TARGET := $(TEST_TARGET) | grep 'integration_test'
+endif
+
+GO_TEST_FLAG := -v -timeout $(GO_TEST_TIMEOUT)
+ifneq ($(NO_TEST_RACE), true)
+ GO_TEST_FLAG := $(GO_TEST_FLAG) -race
+endif
+
COMPONENTS = \
dexcon-simulation \
dexcon-simulation-peer-server \
@@ -83,17 +98,18 @@ lint:
vet:
@go vet `go list ./... | grep -v 'vendor'`
+
test-short:
- @for pkg in `go list ./... | grep -v 'vendor'`; do \
- if ! go test -race -short -v $$pkg; then \
+ @for pkg in `$(TEST_TARGET)`; do \
+ if ! go test -short $(GO_TEST_FLAG) $$pkg; then \
echo 'Some test failed, abort'; \
exit 1; \
fi; \
done
test:
- @for pkg in `go list ./... | grep -v 'vendor'`; do \
- if ! go test -timeout 15m -race -v $$pkg; then \
+ @for pkg in `$(TEST_TARGET)`; do \
+ if ! go test $(GO_TEST_FLAG) $$pkg; then \
echo 'Some test failed, abort'; \
exit 1; \
fi; \
diff --git a/Gopkg.lock b/Gopkg.lock
index 46dab79..2293203 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -27,7 +27,7 @@
[[projects]]
branch = "dev"
- digest = "1:2b010a52e574bc0f815d5fdf403a8b36384665ac0923c94a28b99f8537fbf9fe"
+ digest = "1:de44df5d2d82983648c5f861dd7b7f54133e14b1c4dc412c58347e3872ab2181"
name = "github.com/dexon-foundation/dexon"
packages = [
"common",
@@ -36,12 +36,21 @@
"crypto",
"crypto/secp256k1",
"crypto/sha3",
+ "log",
"rlp",
]
pruneopts = "UT"
revision = "abe4e80a8b6cf9dee93652ea36cdc56065a39a0f"
[[projects]]
+ digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d"
+ name = "github.com/go-stack/stack"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a"
+ version = "v1.8.0"
+
+[[projects]]
branch = "master"
digest = "1:4a0c6bb4805508a6287675fac876be2ac1182539ca8a32468d8128882e9d5009"
name = "github.com/golang/snappy"
@@ -115,6 +124,7 @@
input-imports = [
"github.com/dexon-foundation/bls/ffi/go/bls",
"github.com/dexon-foundation/dexon/crypto",
+ "github.com/dexon-foundation/dexon/log",
"github.com/dexon-foundation/dexon/rlp",
"github.com/naoina/toml",
"github.com/stretchr/testify/suite",
diff --git a/core/configuration-chain_test.go b/core/configuration-chain_test.go
index 3a7f729..2e75b7f 100644
--- a/core/configuration-chain_test.go
+++ b/core/configuration-chain_test.go
@@ -19,6 +19,7 @@ package core
import (
"encoding/json"
+ "errors"
"sync"
"testing"
"time"
@@ -61,16 +62,24 @@ func newTestCCReceiver(
func (r *testCCReceiver) ProposeDKGComplaint(complaint *typesDKG.Complaint) {
prvKey, exist := r.s.prvKeys[complaint.ProposerID]
- r.s.Require().True(exist)
+ if !exist {
+ panic(errors.New("should exist"))
+ }
var err error
complaint.Signature, err = prvKey.Sign(hashDKGComplaint(complaint))
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
for _, gov := range r.govs {
// Use Marshal/Unmarshal to do deep copy.
data, err := json.Marshal(complaint)
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
complaintCopy := &typesDKG.Complaint{}
- r.s.Require().NoError(json.Unmarshal(data, complaintCopy))
+ if err := json.Unmarshal(data, complaintCopy); err != nil {
+ panic(err)
+ }
gov.AddDKGComplaint(complaintCopy.Round, complaintCopy)
}
}
@@ -78,16 +87,24 @@ func (r *testCCReceiver) ProposeDKGComplaint(complaint *typesDKG.Complaint) {
func (r *testCCReceiver) ProposeDKGMasterPublicKey(
mpk *typesDKG.MasterPublicKey) {
prvKey, exist := r.s.prvKeys[mpk.ProposerID]
- r.s.Require().True(exist)
+ if !exist {
+ panic(errors.New("should exist"))
+ }
var err error
mpk.Signature, err = prvKey.Sign(hashDKGMasterPublicKey(mpk))
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
for _, gov := range r.govs {
// Use Marshal/Unmarshal to do deep copy.
data, err := json.Marshal(mpk)
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
mpkCopy := typesDKG.NewMasterPublicKey()
- r.s.Require().NoError(json.Unmarshal(data, mpkCopy))
+ if err := json.Unmarshal(data, mpkCopy); err != nil {
+ panic(err)
+ }
gov.AddDKGMasterPublicKey(mpkCopy.Round, mpkCopy)
}
}
@@ -96,14 +113,22 @@ func (r *testCCReceiver) ProposeDKGPrivateShare(
prv *typesDKG.PrivateShare) {
go func() {
prvKey, exist := r.s.prvKeys[prv.ProposerID]
- r.s.Require().True(exist)
+ if !exist {
+ panic(errors.New("should exist"))
+ }
var err error
prv.Signature, err = prvKey.Sign(hashDKGPrivateShare(prv))
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
receiver, exist := r.nodes[prv.ReceiverID]
- r.s.Require().True(exist)
+ if !exist {
+ panic(errors.New("should exist"))
+ }
err = receiver.processPrivateShare(prv)
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
}()
}
@@ -111,34 +136,52 @@ func (r *testCCReceiver) ProposeDKGAntiNackComplaint(
prv *typesDKG.PrivateShare) {
go func() {
prvKey, exist := r.s.prvKeys[prv.ProposerID]
- r.s.Require().True(exist)
+ if !exist {
+ panic(errors.New("should exist"))
+ }
var err error
prv.Signature, err = prvKey.Sign(hashDKGPrivateShare(prv))
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
for _, cc := range r.nodes {
// Use Marshal/Unmarshal to do deep copy.
data, err := json.Marshal(prv)
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
prvCopy := &typesDKG.PrivateShare{}
- r.s.Require().NoError(json.Unmarshal(data, prvCopy))
+ if err := json.Unmarshal(data, prvCopy); err != nil {
+ panic(err)
+ }
err = cc.processPrivateShare(prvCopy)
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
}
}()
}
func (r *testCCReceiver) ProposeDKGFinalize(final *typesDKG.Finalize) {
prvKey, exist := r.s.prvKeys[final.ProposerID]
- r.s.Require().True(exist)
+ if !exist {
+ panic(errors.New("should exist"))
+ }
var err error
final.Signature, err = prvKey.Sign(hashDKGFinalize(final))
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
for _, gov := range r.govs {
// Use Marshal/Unmarshal to do deep copy.
data, err := json.Marshal(final)
- r.s.Require().NoError(err)
+ if err != nil {
+ panic(err)
+ }
finalCopy := &typesDKG.Finalize{}
- r.s.Require().NoError(json.Unmarshal(data, finalCopy))
+ if err := json.Unmarshal(data, finalCopy); err != nil {
+ panic(err)
+ }
gov.AddDKGFinalize(finalCopy.Round, finalCopy)
}
}
@@ -174,7 +217,7 @@ func (s *ConfigurationChainTestSuite) runDKG(
for _, nID := range s.nIDs {
gov, err := test.NewGovernance(test.NewState(
- pks, 50*time.Millisecond, &common.NullLogger{}, true), ConfigRoundShift)
+ pks, 100*time.Millisecond, &common.NullLogger{}, true), ConfigRoundShift)
s.Require().NoError(err)
cache := utils.NewNodeSetCache(gov)
cfgChains[nID] = newConfigurationChain(
@@ -214,6 +257,9 @@ func (s *ConfigurationChainTestSuite) preparePartialSignature(
psigs []*typesDKG.PartialSignature) {
psigs = make([]*typesDKG.PartialSignature, 0, len(cfgChains))
for nID, cc := range cfgChains {
+ if _, exist := cc.gpk[round]; !exist {
+ continue
+ }
if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist {
continue
}
@@ -245,6 +291,9 @@ func (s *ConfigurationChainTestSuite) TestConfigurationChain() {
errs := make(chan error, n)
tsigChan := make(chan crypto.Signature, n)
for nID, cc := range cfgChains {
+ if _, exist := cc.gpk[round]; !exist {
+ continue
+ }
if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist {
continue
}
@@ -260,6 +309,9 @@ func (s *ConfigurationChainTestSuite) TestConfigurationChain() {
}
}
for nID, cc := range cfgChains {
+ if _, exist := cc.gpk[round]; !exist {
+ s.FailNow("Should be qualifyied")
+ }
if _, exist := cc.gpk[round].qualifyNodeIDs[nID]; !exist {
s.FailNow("Should be qualifyied")
}
diff --git a/core/consensus_test.go b/core/consensus_test.go
index 9234512..65f4e36 100644
--- a/core/consensus_test.go
+++ b/core/consensus_test.go
@@ -18,17 +18,19 @@
package core
import (
+ "encoding/json"
"sort"
"testing"
"time"
+ "github.com/stretchr/testify/suite"
+
"github.com/dexon-foundation/dexon-consensus/common"
"github.com/dexon-foundation/dexon-consensus/core/blockdb"
"github.com/dexon-foundation/dexon-consensus/core/crypto"
"github.com/dexon-foundation/dexon-consensus/core/test"
"github.com/dexon-foundation/dexon-consensus/core/types"
typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg"
- "github.com/stretchr/testify/suite"
)
// network implements core.Network.
@@ -101,37 +103,33 @@ func (nc *networkConnection) broadcast(from types.NodeID, msg interface{}) {
}
func (nc *networkConnection) send(to types.NodeID, msg interface{}) {
- con, exist := nc.cons[to]
+ ch, exist := nc.cons[to]
if !exist {
return
}
- go func() {
- var err error
- // Testify package does not support concurrent call.
- // Use panic() to detact error.
- switch val := msg.(type) {
- case *types.Block:
- err = con.preProcessBlock(val)
- case *types.Vote:
- err = con.ProcessVote(val)
- case *types.AgreementResult:
- err = con.ProcessAgreementResult(val)
- case *types.BlockRandomnessResult:
- err = con.ProcessBlockRandomnessResult(val)
- case *typesDKG.PrivateShare:
- err = con.cfgModule.processPrivateShare(val)
- case *typesDKG.PartialSignature:
- err = con.cfgModule.processPartialSignature(val)
- }
+ msgCopy := msg
+ // Clone msg if necessary.
+ switch val := msg.(type) {
+ case *types.Block:
+ msgCopy = val.Clone()
+ case *typesDKG.PrivateShare:
+ // Use Marshal/Unmarshal to do deep copy.
+ data, err := json.Marshal(val)
if err != nil {
panic(err)
}
- }()
+ valCopy := &typesDKG.PrivateShare{}
+ if err := json.Unmarshal(data, valCopy); err != nil {
+ panic(err)
+ }
+ msgCopy = valCopy
+ }
+ ch <- msgCopy
}
type networkConnection struct {
s *ConsensusTestSuite
- cons map[types.NodeID]*Consensus
+ cons map[types.NodeID]chan interface{}
}
func (nc *networkConnection) newNetwork(nID types.NodeID) *network {
@@ -142,7 +140,33 @@ func (nc *networkConnection) newNetwork(nID types.NodeID) *network {
}
func (nc *networkConnection) setCon(nID types.NodeID, con *Consensus) {
- nc.cons[nID] = con
+ ch := make(chan interface{}, 1000)
+ go func() {
+ for {
+ msg := <-ch
+ var err error
+ // Testify package does not support concurrent call.
+ // Use panic() to detact error.
+ switch val := msg.(type) {
+ case *types.Block:
+ err = con.preProcessBlock(val)
+ case *types.Vote:
+ err = con.ProcessVote(val)
+ case *types.AgreementResult:
+ err = con.ProcessAgreementResult(val)
+ case *types.BlockRandomnessResult:
+ err = con.ProcessBlockRandomnessResult(val)
+ case *typesDKG.PrivateShare:
+ err = con.cfgModule.processPrivateShare(val)
+ case *typesDKG.PartialSignature:
+ err = con.cfgModule.processPartialSignature(val)
+ }
+ if err != nil {
+ panic(err)
+ }
+ }
+ }()
+ nc.cons[nID] = ch
}
type ConsensusTestSuite struct {
@@ -153,7 +177,7 @@ type ConsensusTestSuite struct {
func (s *ConsensusTestSuite) newNetworkConnection() *networkConnection {
return &networkConnection{
s: s,
- cons: make(map[types.NodeID]*Consensus),
+ cons: make(map[types.NodeID]chan interface{}),
}
}
diff --git a/integration_test/consensus_test.go b/integration_test/consensus_test.go
index d66ff72..16cfa8f 100644
--- a/integration_test/consensus_test.go
+++ b/integration_test/consensus_test.go
@@ -19,6 +19,7 @@ package integration
import (
"context"
+ "fmt"
"sync"
"testing"
"time"
@@ -208,10 +209,10 @@ func (s *ConsensusTestSuite) TestSimple() {
Loop:
for {
<-time.After(5 * time.Second)
- s.T().Log("check latest position delivered by each node")
+ fmt.Println("check latest position delivered by each node")
for _, n := range nodes {
latestPos := n.app.GetLatestDeliveredPosition()
- s.T().Log("latestPos", n.ID, &latestPos)
+ fmt.Println("latestPos", n.ID, &latestPos)
if latestPos.Round < untilRound {
continue Loop
}
@@ -283,10 +284,10 @@ func (s *ConsensusTestSuite) TestNumChainsChange() {
Loop:
for {
<-time.After(5 * time.Second)
- s.T().Log("check latest position delivered by each node")
+ fmt.Println("check latest position delivered by each node")
for _, n := range nodes {
latestPos := n.app.GetLatestDeliveredPosition()
- s.T().Log("latestPos", n.ID, &latestPos)
+ fmt.Println("latestPos", n.ID, &latestPos)
if latestPos.Round < untilRound {
continue Loop
}
@@ -320,7 +321,7 @@ func (s *ConsensusTestSuite) TestSync() {
core.ConfigRoundShift)
req.NoError(err)
req.NoError(seedGov.State().RequestChange(
- test.StateChangeRoundInterval, 30*time.Second))
+ test.StateChangeRoundInterval, 50*time.Second))
// A short round interval.
nodes := s.setupNodes(dMoment, prvKeys, seedGov)
// Choose the first node as "syncNode" that its consensus' Run() is called
@@ -348,6 +349,24 @@ func (s *ConsensusTestSuite) TestSync() {
}
}
}()
+ // Print status every 5 seconds so CI won't fail.
+ monitorCtx, monitorCancel := context.WithCancel(
+ context.Background())
+ defer monitorCancel()
+ go func() {
+ for {
+ select {
+ case <-time.After(5 * time.Second):
+ for _, n := range nodes {
+ pos := n.app.GetLatestDeliveredPosition()
+ fmt.Println("latestPos", n.ID, &pos)
+ break
+ }
+ case <-monitorCtx.Done():
+ return
+ }
+ }
+ }()
ReachAlive:
for {
// If all nodes excepts syncNode have reached aliveRound, call syncNode's
@@ -425,7 +444,7 @@ ReachAlive:
// Stop a node, we should still be able to proceed.
stoppedNode.con.Stop()
stoppedNode.con = nil
- s.T().Log("one node stopped")
+ fmt.Println("one node stopped")
// Initiate a dummy routine to consume the receive channel.
go func() {
for {