aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml12
-rw-r--r--Gopkg.lock85
-rw-r--r--Gopkg.toml4
-rw-r--r--core/agreement-mgr.go47
-rw-r--r--core/agreement.go13
-rw-r--r--core/utils/vote-filter.go6
-rw-r--r--core/utils/vote-filter_test.go12
-rw-r--r--integration_test/consensus_test.go5
8 files changed, 117 insertions, 67 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 08ff726..c8d1c53 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -20,7 +20,7 @@ commands:
command: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
make test
- elif [ "${CIRCLE_BRANCH}" == "single-chain" ]; then
+ elif [ "${CIRCLE_BRANCH}" == "dexon-classic" ]; then
make test
else
make test-short
@@ -98,6 +98,14 @@ jobs:
steps:
- init_workspace
- run_test
+ - run:
+ name: Saving Logs
+ when: on_fail
+ command: |
+ mkdir -p /tmp/logs
+ cd integration_test && tar -czf /tmp/logs/integration_test.tar.gz log.*
+ - store_artifacts:
+ path: /tmp/logs
build:
executor: go1_11
@@ -130,7 +138,7 @@ workflows:
branches:
only:
- master
- - single-chain
+ - dexon-classic
test_and_build:
jobs:
diff --git a/Gopkg.lock b/Gopkg.lock
index faecb2f..602b10b 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -3,11 +3,11 @@
[[projects]]
branch = "master"
- digest = "1:c0decf632843204d2b8781de7b26e7038584e2dcccc7e2f401e88ae85b1df2b7"
+ digest = "1:093bf93a65962e8191e3e8cd8fc6c363f83d43caca9739c906531ba7210a9904"
name = "github.com/btcsuite/btcd"
packages = ["btcec"]
pruneopts = "UT"
- revision = "2a560b2036bee5e3679ec2133eb6520b2f195213"
+ revision = "9bfb2ca0346b57e246cc96fa31074df521175240"
[[projects]]
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
@@ -19,15 +19,15 @@
[[projects]]
branch = "dev"
- digest = "1:c331891ab345659ad4e3e6af2c0b2ba262dd2c83867b2928f4c89455a429cb79"
+ digest = "1:989ca7617ed87c5fa460e9f63414d797fd0d2dd07cdda0b6d6d3e7450e002b1f"
name = "github.com/dexon-foundation/bls"
packages = ["ffi/go/bls"]
pruneopts = "UT"
- revision = "1208495d2fd3e5a69edaf7f429607e7ef431a5dd"
+ revision = "b0a83abe7389df7f4c45adc3b52d957f3996322d"
[[projects]]
branch = "dev"
- digest = "1:de44df5d2d82983648c5f861dd7b7f54133e14b1c4dc412c58347e3872ab2181"
+ digest = "1:8fc72b5a0372267ae68d203aef3e1108eb7274050c7ded516ea1af71a8a09b77"
name = "github.com/dexon-foundation/dexon"
packages = [
"common",
@@ -35,12 +35,11 @@
"common/math",
"crypto",
"crypto/secp256k1",
- "crypto/sha3",
"log",
"rlp",
]
pruneopts = "UT"
- revision = "abe4e80a8b6cf9dee93652ea36cdc56065a39a0f"
+ revision = "f1ed7d074fe1d574a84c308c6ad878dc2d153654"
[[projects]]
digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d"
@@ -51,12 +50,23 @@
version = "v1.8.0"
[[projects]]
- branch = "master"
- digest = "1:4a0c6bb4805508a6287675fac876be2ac1182539ca8a32468d8128882e9d5009"
+ digest = "1:e4f5819333ac698d294fe04dbf640f84719658d5c7ce195b10060cc37292ce79"
name = "github.com/golang/snappy"
packages = ["."]
pruneopts = "UT"
- revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a"
+ revision = "2a8bb927dd31d8daada140a5d09578521ce5c36a"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:d15ee511aa0f56baacc1eb4c6b922fa1c03b38413b6be18166b996d82a0156ea"
+ name = "github.com/hashicorp/golang-lru"
+ packages = [
+ ".",
+ "simplelru",
+ ]
+ pruneopts = "UT"
+ revision = "7087cb70de9f7a8bc0a10c375cb0d2280a8edf9c"
+ version = "v0.5.1"
[[projects]]
digest = "1:b56c589214f01a5601e0821387db484617392d0042f26234bf2da853a2f498a1"
@@ -86,7 +96,7 @@
version = "v1.0.0"
[[projects]]
- digest = "1:5110e3d4f130772fd39e6ce8208ad1955b242ccfcc8ad9d158857250579c82f4"
+ digest = "1:8ff03ccc603abb0d7cce94d34b613f5f6251a9e1931eba1a3f9888a9029b055c"
name = "github.com/stretchr/testify"
packages = [
"assert",
@@ -94,12 +104,12 @@
"suite",
]
pruneopts = "UT"
- revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
- version = "v1.2.2"
+ revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053"
+ version = "v1.3.0"
[[projects]]
branch = "master"
- digest = "1:f2ffd421680b0a3f7887501b3c6974bcf19217ecd301d0e2c9b681940ec363d5"
+ digest = "1:3f0c28875fb78456bc1815a9c13cb5962a4f0c462b37ec72e90c2f2cc407b54f"
name = "github.com/syndtr/goleveldb"
packages = [
"leveldb",
@@ -116,44 +126,39 @@
"leveldb/util",
]
pruneopts = "UT"
- revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd"
+ revision = "c3a204f8e96543bb0cc090385c001078f184fc46"
+
+[[projects]]
+ branch = "master"
+ digest = "1:d193d0292355f8fada46cf77967d64df52ce6e0a757f81a3a1b2626ac77d649d"
+ name = "golang.org/x/crypto"
+ packages = ["sha3"]
+ pruneopts = "UT"
+ revision = "38d8ce5564a5b71b2e3a00553993f1b9a7ae852f"
+
+[[projects]]
+ branch = "master"
+ digest = "1:13917c3d8b9b6c14a941d66af59444b7ce53a859a8b86e24891a713186f42c65"
+ name = "golang.org/x/sys"
+ packages = [
+ "cpu",
+ "unix",
+ ]
+ pruneopts = "UT"
+ revision = "0ad05ae3009d6413d3363aa09b350b2ec37daf09"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
- "github.com/btcsuite/btcd/btcec",
- "github.com/davecgh/go-spew/spew",
"github.com/dexon-foundation/bls/ffi/go/bls",
- "github.com/dexon-foundation/dexon/common",
- "github.com/dexon-foundation/dexon/common/hexutil",
- "github.com/dexon-foundation/dexon/common/math",
"github.com/dexon-foundation/dexon/crypto",
- "github.com/dexon-foundation/dexon/crypto/secp256k1",
- "github.com/dexon-foundation/dexon/crypto/sha3",
"github.com/dexon-foundation/dexon/log",
"github.com/dexon-foundation/dexon/rlp",
- "github.com/go-stack/stack",
- "github.com/golang/snappy",
- "github.com/naoina/go-stringutil",
+ "github.com/hashicorp/golang-lru",
"github.com/naoina/toml",
- "github.com/naoina/toml/ast",
- "github.com/pmezard/go-difflib/difflib",
- "github.com/stretchr/testify/assert",
- "github.com/stretchr/testify/require",
"github.com/stretchr/testify/suite",
"github.com/syndtr/goleveldb/leveldb",
- "github.com/syndtr/goleveldb/leveldb/cache",
- "github.com/syndtr/goleveldb/leveldb/comparer",
- "github.com/syndtr/goleveldb/leveldb/errors",
- "github.com/syndtr/goleveldb/leveldb/filter",
- "github.com/syndtr/goleveldb/leveldb/iterator",
- "github.com/syndtr/goleveldb/leveldb/journal",
- "github.com/syndtr/goleveldb/leveldb/memdb",
- "github.com/syndtr/goleveldb/leveldb/opt",
- "github.com/syndtr/goleveldb/leveldb/storage",
- "github.com/syndtr/goleveldb/leveldb/table",
- "github.com/syndtr/goleveldb/leveldb/util",
]
solver-name = "gps-cdcl"
solver-version = 1
diff --git a/Gopkg.toml b/Gopkg.toml
index 799a63f..0ad7fbb 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -45,6 +45,10 @@
branch = "master"
name = "github.com/syndtr/goleveldb"
+[[constraint]]
+ name = "github.com/hashicorp/golang-lru"
+ version = "0.5.1"
+
[prune]
go-tests = true
unused-packages = true
diff --git a/core/agreement-mgr.go b/core/agreement-mgr.go
index ac28955..4597fe9 100644
--- a/core/agreement-mgr.go
+++ b/core/agreement-mgr.go
@@ -24,6 +24,8 @@ import (
"sync"
"time"
+ lru "github.com/hashicorp/golang-lru"
+
"github.com/dexon-foundation/dexon-consensus/common"
"github.com/dexon-foundation/dexon-consensus/core/types"
typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg"
@@ -41,6 +43,7 @@ var (
)
const maxResultCache = 100
+const settingLimit = 3
// genValidLeader generate a validLeader function for agreement modules.
func genValidLeader(
@@ -130,12 +133,15 @@ type agreementMgr struct {
recv *consensusBAReceiver
processedBAResult map[types.Position]struct{}
voteFilter *utils.VoteFilter
+ settingCache *lru.Cache
+ curRoundSetting *baRoundSetting
waitGroup sync.WaitGroup
isRunning bool
lock sync.RWMutex
}
func newAgreementMgr(con *Consensus) (mgr *agreementMgr, err error) {
+ settingCache, _ := lru.New(settingLimit)
mgr = &agreementMgr{
con: con,
ID: con.ID,
@@ -149,6 +155,7 @@ func newAgreementMgr(con *Consensus) (mgr *agreementMgr, err error) {
ctx: con.ctx,
processedBAResult: make(map[types.Position]struct{}, maxResultCache),
voteFilter: utils.NewVoteFilter(),
+ settingCache: settingCache,
}
mgr.recv = &consensusBAReceiver{
consensus: con,
@@ -165,21 +172,18 @@ func (mgr *agreementMgr) prepare() {
newLeaderSelector(genValidLeader(mgr), mgr.logger),
mgr.signer,
mgr.logger)
- nodes, err := mgr.cache.GetNodeSet(round)
- if err != nil {
+ setting := mgr.generateSetting(round)
+ if setting == nil {
+ mgr.logger.Warn("Unable to prepare init setting", "round", round)
return
}
- agr.notarySet = nodes.GetSubSet(
- int(mgr.config(round).notarySetSize),
- types.NewNotarySetTarget(mgr.config(round).crs))
+ mgr.curRoundSetting = setting
+ agr.notarySet = mgr.curRoundSetting.dkgSet
// Hacky way to make agreement module self contained.
mgr.recv.agreementModule = agr
mgr.baModule = agr
if round >= DKGDelayRound {
- setting := mgr.generateSetting(round)
- if setting == nil {
- mgr.logger.Warn("Unable to prepare init setting", "round", round)
- } else if _, exist := setting.dkgSet[mgr.ID]; exist {
+ if _, exist := setting.dkgSet[mgr.ID]; exist {
mgr.logger.Debug("Preparing signer and npks.", "round", round)
npk, signer, err := mgr.con.cfgModule.getDKGInfo(round, false)
if err != nil {
@@ -268,9 +272,25 @@ func (mgr *agreementMgr) notifyRoundEvents(evts []utils.RoundEventParam) error {
}
func (mgr *agreementMgr) processVote(v *types.Vote) (err error) {
+ if !mgr.recv.isNotary {
+ return nil
+ }
if mgr.voteFilter.Filter(v) {
return nil
}
+ if v.Position.Round == mgr.curRoundSetting.round {
+ if _, exist := mgr.curRoundSetting.dkgSet[v.ProposerID]; !exist {
+ return ErrNotInNotarySet
+ }
+ } else if v.Position.Round == mgr.curRoundSetting.round+1 {
+ setting := mgr.generateSetting(v.Position.Round)
+ if setting == nil {
+ return ErrConfigurationNotReady
+ }
+ if _, exist := setting.dkgSet[v.ProposerID]; !exist {
+ return ErrNotInNotarySet
+ }
+ }
if err = mgr.baModule.processVote(v); err == nil {
mgr.baModule.updateFilter(mgr.voteFilter)
mgr.voteFilter.AddVote(v)
@@ -339,6 +359,7 @@ func (mgr *agreementMgr) processAgreementResult(
result.Position.Round)
return ErrConfigurationNotReady
}
+ mgr.curRoundSetting = setting
leader, err := mgr.calcLeader(setting.dkgSet, setting.crs, result.Position)
if err != nil {
return err
@@ -374,6 +395,9 @@ func (mgr *agreementMgr) stop() {
}
func (mgr *agreementMgr) generateSetting(round uint64) *baRoundSetting {
+ if setting, exist := mgr.settingCache.Get(round); exist {
+ return setting.(*baRoundSetting)
+ }
curConfig := mgr.config(round)
if curConfig == nil {
return nil
@@ -399,13 +423,15 @@ func (mgr *agreementMgr) generateSetting(round uint64) *baRoundSetting {
return nil
}
}
- return &baRoundSetting{
+ setting := &baRoundSetting{
crs: curConfig.crs,
dkgSet: dkgSet,
round: round,
threshold: utils.GetBAThreshold(&types.Config{
NotarySetSize: curConfig.notarySetSize}),
}
+ mgr.settingCache.Add(round, setting)
+ return setting
}
func (mgr *agreementMgr) runBA(initRound uint64) {
@@ -465,6 +491,7 @@ Loop:
}
mgr.recv.isNotary = checkRound()
mgr.voteFilter = utils.NewVoteFilter()
+ mgr.voteFilter.Position.Round = currentRound
mgr.recv.emptyBlockHashMap = &sync.Map{}
if currentRound >= DKGDelayRound && mgr.recv.isNotary {
var err error
diff --git a/core/agreement.go b/core/agreement.go
index a6fb074..cb46771 100644
--- a/core/agreement.go
+++ b/core/agreement.go
@@ -361,9 +361,6 @@ func (a *agreement) sanityCheck(vote *types.Vote) error {
if vote.Type >= types.MaxVoteType {
return ErrInvalidVote
}
- if _, exist := a.notarySet[vote.ProposerID]; !exist {
- return ErrNotInNotarySet
- }
ok, err := utils.VerifyVoteSignature(vote)
if err != nil {
return err
@@ -371,6 +368,10 @@ func (a *agreement) sanityCheck(vote *types.Vote) error {
if !ok {
return ErrIncorrectVoteSignature
}
+ if vote.Position.Round != a.agreementID().Round {
+ // TODO(jimmy): maybe we can verify partial signature at agreement-mgr.
+ return nil
+ }
if !a.data.recv.VerifyPartialSignature(vote) {
return ErrIncorrectVotePartialSignature
}
@@ -412,7 +413,7 @@ func (a *agreement) updateFilter(filter *utils.VoteFilter) {
filter.Confirm = a.hasOutput
filter.LockIter = a.data.lockIter
filter.Period = a.data.period
- filter.Height = a.agreementID().Height
+ filter.Position.Height = a.agreementID().Height
}
// processVote is the entry point for processing Vote.
@@ -426,8 +427,8 @@ func (a *agreement) processVote(vote *types.Vote) error {
// Agreement module has stopped.
if isStop(aID) {
- // Hacky way to not drop first votes for genesis height.
- if vote.Position.Height == types.GenesisHeight {
+ // Hacky way to not drop first votes when round just begins.
+ if vote.Position.Round == aID.Round {
a.pendingVote = append(a.pendingVote, pendingVote{
vote: vote,
receivedTime: time.Now().UTC(),
diff --git a/core/utils/vote-filter.go b/core/utils/vote-filter.go
index 2fc18bb..446d88a 100644
--- a/core/utils/vote-filter.go
+++ b/core/utils/vote-filter.go
@@ -25,7 +25,7 @@ import (
// To maximize performance, this structure is not thread-safe and will never be.
type VoteFilter struct {
Voted map[types.VoteHeader]struct{}
- Height uint64
+ Position types.Position
LockIter uint64
Period uint64
Confirm bool
@@ -43,9 +43,9 @@ func (vf *VoteFilter) Filter(vote *types.Vote) bool {
if vote.Type == types.VoteInit {
return true
}
- if vote.Position.Height < vf.Height {
+ if vote.Position.Older(vf.Position) {
return true
- } else if vote.Position.Height > vf.Height {
+ } else if vote.Position.Newer(vf.Position) {
// It's impossible to check the vote of other height.
return false
}
diff --git a/core/utils/vote-filter_test.go b/core/utils/vote-filter_test.go
index 443efff..4e7a7b9 100644
--- a/core/utils/vote-filter_test.go
+++ b/core/utils/vote-filter_test.go
@@ -32,22 +32,22 @@ type VoteFilterTestSuite struct {
func (s *VoteFilterTestSuite) TestFilterVotePass() {
filter := NewVoteFilter()
- filter.Height = uint64(6)
+ filter.Position.Height = uint64(6)
filter.Period = uint64(3)
filter.LockIter = uint64(3)
// Pass with higher Height.
vote := types.NewVote(types.VotePreCom, common.NewRandomHash(), uint64(1))
- vote.Position.Height = filter.Height + 1
+ vote.Position.Height = filter.Position.Height + 1
s.Require().False(filter.Filter(vote))
// Pass with VotePreCom.
vote = types.NewVote(types.VotePreCom, common.NewRandomHash(),
filter.LockIter)
- vote.Position.Height = filter.Height
+ vote.Position.Height = filter.Position.Height
s.Require().False(filter.Filter(vote))
// Pass with VoteCom.
vote = types.NewVote(types.VoteCom, common.NewRandomHash(),
filter.Period)
- vote.Position.Height = filter.Height
+ vote.Position.Height = filter.Position.Height
s.Require().False(filter.Filter(vote))
vote.Period--
s.Require().False(filter.Filter(vote))
@@ -81,9 +81,9 @@ func (s *VoteFilterTestSuite) TestFilterConfirm() {
}
func (s *VoteFilterTestSuite) TestFilterLowerHeight() {
filter := NewVoteFilter()
- filter.Height = uint64(10)
+ filter.Position.Height = uint64(10)
vote := types.NewVote(types.VoteCom, common.NewRandomHash(), uint64(1))
- vote.Position.Height = filter.Height - 1
+ vote.Position.Height = filter.Position.Height - 1
s.True(filter.Filter(vote))
}
diff --git a/integration_test/consensus_test.go b/integration_test/consensus_test.go
index 05d7c44..bf2970a 100644
--- a/integration_test/consensus_test.go
+++ b/integration_test/consensus_test.go
@@ -252,6 +252,11 @@ func (s *ConsensusTestSuite) syncBlocksWithSomeNode(
}
func (s *ConsensusTestSuite) TestSimple() {
+ if testing.Short() {
+ // All other tests will cover this basic case. To speed up CI process,
+ // ignore this test in short mode.
+ return
+ }
// The simplest test case:
// - Node set is equals to DKG set and notary set for each chain in each
// round.