aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com
diff options
context:
space:
mode:
authorJimmy Hu <jimmy.hu@dexon.org>2019-03-13 18:19:53 +0800
committerWei-Ning Huang <w@byzantine-lab.io>2019-06-12 17:27:22 +0800
commit43457d6a008524f9dd353fce7b12e16cd4d0e157 (patch)
tree12782a2db49a1ee4e1fa97db64901251eeed36af /vendor/github.com
parenta0684dc255fb2d3db22ea4c03957d9b7b27a0a36 (diff)
downloadgo-tangerine-43457d6a008524f9dd353fce7b12e16cd4d0e157.tar
go-tangerine-43457d6a008524f9dd353fce7b12e16cd4d0e157.tar.gz
go-tangerine-43457d6a008524f9dd353fce7b12e16cd4d0e157.tar.bz2
go-tangerine-43457d6a008524f9dd353fce7b12e16cd4d0e157.tar.lz
go-tangerine-43457d6a008524f9dd353fce7b12e16cd4d0e157.tar.xz
go-tangerine-43457d6a008524f9dd353fce7b12e16cd4d0e157.tar.zst
go-tangerine-43457d6a008524f9dd353fce7b12e16cd4d0e157.zip
vendor: sync to latest core (#253)
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go10
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go32
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go73
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go14
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/dkg.go27
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/db/interfaces.go8
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/db/level-db.go45
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/db/memory.go55
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go30
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/round-based-config.go51
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-based-config.go112
-rw-r--r--vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go302
12 files changed, 648 insertions, 111 deletions
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go
index 88cc432ff..7b5effba8 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go
@@ -65,7 +65,7 @@ func genValidLeader(
}
type agreementMgrConfig struct {
- roundBasedConfig
+ utils.RoundBasedConfig
notarySetSize uint32
lambdaBA time.Duration
@@ -77,14 +77,14 @@ func (c *agreementMgrConfig) from(
c.notarySetSize = config.NotarySetSize
c.lambdaBA = config.LambdaBA
c.crs = crs
- c.setupRoundBasedFields(round, config)
+ c.SetupRoundBasedFields(round, config)
}
func newAgreementMgrConfig(prev agreementMgrConfig, config *types.Config,
crs common.Hash) (c agreementMgrConfig) {
c = agreementMgrConfig{}
- c.from(prev.roundID+1, config, crs)
- c.setRoundBeginHeight(prev.roundEndHeight)
+ c.from(prev.RoundID()+1, config, crs)
+ c.AppendTo(prev.RoundBasedConfig)
return
}
@@ -356,7 +356,7 @@ Loop:
setting.recv.isNotary = checkRound()
// Run BA for this round.
setting.recv.roundValue.Store(currentRound)
- setting.recv.changeNotaryHeight = curConfig.roundEndHeight
+ setting.recv.changeNotaryHeight = curConfig.RoundEndHeight()
setting.recv.restartNotary <- types.Position{
Round: setting.recv.round(),
Height: math.MaxUint64,
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go
index b6c8b1da5..19a580b4f 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go
@@ -103,21 +103,21 @@ func (pb pendingBlockRecords) searchByPosition(p types.Position) (
}
type blockChainConfig struct {
- roundBasedConfig
+ utils.RoundBasedConfig
minBlockInterval time.Duration
}
func (c *blockChainConfig) fromConfig(round uint64, config *types.Config) {
c.minBlockInterval = config.MinBlockInterval
- c.setupRoundBasedFields(round, config)
+ c.SetupRoundBasedFields(round, config)
}
func newBlockChainConfig(prev blockChainConfig, config *types.Config) (
c blockChainConfig) {
c = blockChainConfig{}
- c.fromConfig(prev.roundID+1, config)
- c.setRoundBeginHeight(prev.roundEndHeight)
+ c.fromConfig(prev.RoundID()+1, config)
+ c.AppendTo(prev.RoundBasedConfig)
return
}
@@ -145,14 +145,14 @@ func newBlockChain(nID types.NodeID, dMoment time.Time, initBlock *types.Block,
initConfig blockChainConfig, app Application, vGetter tsigVerifierGetter,
signer *utils.Signer, logger common.Logger) *blockChain {
if initBlock != nil {
- if initConfig.roundID != initBlock.Position.Round {
+ if initConfig.RoundID() != initBlock.Position.Round {
panic(fmt.Errorf("incompatible config/block %s %d",
- initBlock, initConfig.roundID))
+ initBlock, initConfig.RoundID()))
}
} else {
- if initConfig.roundID != 0 {
+ if initConfig.RoundID() != 0 {
panic(fmt.Errorf("genesis config should from round 0 %d",
- initConfig.roundID))
+ initConfig.RoundID()))
}
}
return &blockChain{
@@ -235,7 +235,7 @@ func (bc *blockChain) sanityCheck(b *types.Block) error {
return ErrInvalidBlockHeight
}
tipConfig := bc.tipConfig()
- if tipConfig.isLastBlock(bc.lastConfirmed) {
+ if tipConfig.IsLastBlock(bc.lastConfirmed) {
if b.Position.Round != bc.lastConfirmed.Position.Round+1 {
return ErrRoundNotSwitch
}
@@ -359,7 +359,7 @@ func (bc *blockChain) tipRound() uint64 {
return 0
}
offset, tipConfig := uint64(0), bc.tipConfig()
- if tipConfig.isLastBlock(bc.lastConfirmed) {
+ if tipConfig.IsLastBlock(bc.lastConfirmed) {
offset++
}
return bc.lastConfirmed.Position.Round + offset
@@ -499,12 +499,12 @@ func (bc *blockChain) checkIfBlocksConfirmed() {
}
func (bc *blockChain) purgeConfig() {
- for bc.configs[0].roundID < bc.lastConfirmed.Position.Round {
+ for bc.configs[0].RoundID() < bc.lastConfirmed.Position.Round {
bc.configs = bc.configs[1:]
}
- if bc.configs[0].roundID != bc.lastConfirmed.Position.Round {
+ if bc.configs[0].RoundID() != bc.lastConfirmed.Position.Round {
panic(fmt.Errorf("mismatched tip config: %d %d",
- bc.configs[0].roundID, bc.lastConfirmed.Position.Round))
+ bc.configs[0].RoundID(), bc.lastConfirmed.Position.Round))
}
}
@@ -556,7 +556,7 @@ func (bc *blockChain) prepareBlock(position types.Position,
b, err = nil, ErrNotFollowTipPosition
return
}
- if tipConfig.isLastBlock(tip) {
+ if tipConfig.IsLastBlock(tip) {
if tip.Position.Round+1 != position.Round {
b, err = nil, ErrRoundNotSwitch
return
@@ -610,9 +610,9 @@ func (bc *blockChain) tipConfig() blockChainConfig {
if bc.lastConfirmed == nil {
panic(fmt.Errorf("attempting to access config without tip"))
}
- if bc.lastConfirmed.Position.Round != bc.configs[0].roundID {
+ if bc.lastConfirmed.Position.Round != bc.configs[0].RoundID() {
panic(fmt.Errorf("inconsist config and tip: %d %d",
- bc.lastConfirmed.Position.Round, bc.configs[0].roundID))
+ bc.lastConfirmed.Position.Round, bc.configs[0].RoundID()))
}
return bc.configs[0]
}
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go
index 9e8df6bd1..9214cd97d 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go
@@ -106,6 +106,12 @@ func (cc *configurationChain) registerDKG(round uint64, threshold int) {
cc.recv,
round,
threshold)
+ err = cc.db.PutOrUpdateDKGMasterPrivateShares(round, *cc.dkg.prvShares)
+ if err != nil {
+ cc.logger.Error("Error put or update DKG master private shares", "error",
+ err)
+ return
+ }
go func() {
ticker := newTicker(cc.gov, round, TickerDKG)
defer ticker.Stop()
@@ -287,33 +293,58 @@ func (cc *configurationChain) getDKGInfo(
}
func (cc *configurationChain) recoverDKGInfo(round uint64) error {
- cc.dkgResult.Lock()
- defer cc.dkgResult.Unlock()
- _, signerExists := cc.dkgSigner[round]
- _, npksExists := cc.npks[round]
+ var npksExists, signerExists bool
+ func() {
+ cc.dkgResult.Lock()
+ defer cc.dkgResult.Unlock()
+ _, signerExists = cc.dkgSigner[round]
+ _, npksExists = cc.npks[round]
+ }()
if signerExists && npksExists {
return nil
}
if !cc.gov.IsDKGFinal(round) {
return ErrDKGNotReady
}
- // Restore group public key.
- npks, err := typesDKG.NewNodePublicKeys(round,
- cc.gov.DKGMasterPublicKeys(round),
- cc.gov.DKGComplaints(round),
- utils.GetDKGThreshold(
- utils.GetConfigWithPanic(cc.gov, round, cc.logger)))
- if err != nil {
- return err
- }
- // Check if we have private shares in DB.
- prvKey, err := cc.db.GetDKGPrivateKey(round)
- if err != nil {
- return err
- }
- cc.npks[round] = npks
- cc.dkgSigner[round] = &dkgShareSecret{
- privateKey: &prvKey,
+
+ if !npksExists {
+ threshold := utils.GetDKGThreshold(
+ utils.GetConfigWithPanic(cc.gov, round, cc.logger))
+ // Restore group public key.
+ cc.logger.Debug("Calling Governance.DKGMasterPublicKeys for recoverDKGInfo",
+ "round", round)
+ cc.logger.Debug("Calling Governance.DKGComplaints for recoverDKGInfo",
+ "round", round)
+ npks, err := typesDKG.NewNodePublicKeys(round,
+ cc.gov.DKGMasterPublicKeys(round),
+ cc.gov.DKGComplaints(round),
+ threshold)
+ if err != nil {
+ cc.logger.Warn("Failed to create DKGGroupPublicKey",
+ "round", round, "error", err)
+ return err
+ }
+ func() {
+ cc.dkgResult.Lock()
+ defer cc.dkgResult.Unlock()
+ cc.npks[round] = npks
+ }()
+ }
+ if !signerExists {
+ // Check if we have private shares in DB.
+ prvKey, err := cc.db.GetDKGPrivateKey(round)
+ if err != nil {
+ cc.logger.Warn("Failed to create DKGPrivateKey",
+ "round", round, "error", err)
+ return err
+ }
+ func() {
+ cc.dkgResult.Lock()
+ defer cc.dkgResult.Unlock()
+ cc.dkgSigner[round] = &dkgShareSecret{
+ privateKey: &prvKey,
+ }
+ }()
}
return nil
}
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go
index ccb332684..4201cbcc2 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go
@@ -538,6 +538,11 @@ func newConsensusForRound(
logger: logger,
}
cfgModule := newConfigurationChain(ID, recv, gov, nodeSetCache, db, logger)
+ dkg, err := recoverDKGProtocol(ID, recv, initRound, utils.GetDKGThreshold(initConfig), db)
+ if err != nil {
+ panic(err)
+ }
+ cfgModule.dkg = dkg
recv.cfgModule = cfgModule
appModule := app
if usingNonBlocking {
@@ -545,7 +550,7 @@ func newConsensusForRound(
}
bcConfig := blockChainConfig{}
bcConfig.fromConfig(initRound, initConfig)
- bcConfig.setRoundBeginHeight(initRoundBeginHeight)
+ bcConfig.SetRoundBeginHeight(initRoundBeginHeight)
bcModule := newBlockChain(ID, dMoment, initBlock, bcConfig, appModule,
NewTSigVerifierCache(gov, 7), signer, logger)
// Construct Consensus instance.
@@ -573,8 +578,7 @@ func newConsensusForRound(
con.ctx, con.ctxCancel = context.WithCancel(context.Background())
baConfig := agreementMgrConfig{}
baConfig.from(initRound, initConfig, initCRS)
- baConfig.setRoundBeginHeight(initRoundBeginHeight)
- var err error
+ baConfig.SetRoundBeginHeight(initRoundBeginHeight)
con.baMgr, err = newAgreementMgr(con, initRound, baConfig)
if err != nil {
panic(err)
@@ -845,6 +849,10 @@ func (con *Consensus) initialRound(
con.logger.Warn("Failed to update nodeSetCache",
"round", round+1, "error", err)
}
+ if _, _, err := con.bcModule.vGetter.UpdateAndGet(round + 1); err != nil {
+ con.logger.Warn("Failed to update tsigVerifierCache",
+ "round", round+1, "error", err)
+ }
}()
})
}
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/dkg.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/dkg.go
index f6b3e0e1b..425d96b95 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/dkg.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/dkg.go
@@ -131,6 +131,33 @@ func (prvs *PrivateKeyShares) Equal(other *PrivateKeyShares) bool {
return true
}
+// EncodeRLP implements rlp.Encoder
+func (prvs *PrivateKeyShares) EncodeRLP(w io.Writer) error {
+ mpks := make([][]byte, len(prvs.masterPrivateKey))
+ for i, m := range prvs.masterPrivateKey {
+ mpks[i] = m.GetLittleEndian()
+ }
+ return rlp.Encode(w, mpks)
+}
+
+// DecodeRLP implements rlp.Decoder
+func (prvs *PrivateKeyShares) DecodeRLP(s *rlp.Stream) error {
+ var dec [][]byte
+ if err := s.Decode(&dec); err != nil {
+ return err
+ }
+
+ for _, k := range dec {
+ var key bls.SecretKey
+ if err := key.SetLittleEndian(k); err != nil {
+ return err
+ }
+ prvs.masterPrivateKey = append(prvs.masterPrivateKey, key)
+ }
+
+ return nil
+}
+
// PublicKeyShares represents a public key shares for DKG protocol.
type PublicKeyShares struct {
shareCaches []PublicKey
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/interfaces.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/db/interfaces.go
index ebbbbd475..e95861112 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/interfaces.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/db/interfaces.go
@@ -50,6 +50,12 @@ var (
// ErrDKGPrivateKeyDoesNotExist raised when the DKG private key of the
// requested round does not exists.
ErrDKGPrivateKeyDoesNotExist = errors.New("dkg private key does not exists")
+ // ErrDKGMasterPrivateSharesExists raised when attempting to save DKG master private shares
+ // that already saved.
+ ErrDKGMasterPrivateSharesExists = errors.New("dkg master private shares exists")
+ // ErrDKGMasterPrivateSharesDoesNotExist raised when the DKG master private shares of the
+ // requested round does not exists.
+ ErrDKGMasterPrivateSharesDoesNotExist = errors.New("dkg master private shares does not exists")
)
// Database is the interface for a Database.
@@ -76,6 +82,7 @@ type Reader interface {
// DKG Private Key related methods.
HasDKGPrivateKey(round uint64) (bool, error)
GetDKGPrivateKey(round uint64) (dkg.PrivateKey, error)
+ GetDKGMasterPrivateShares(round uint64) (shares dkg.PrivateKeyShares, err error)
}
// Writer defines the interface for writing blocks into DB.
@@ -84,6 +91,7 @@ type Writer interface {
PutBlock(block types.Block) error
PutCompactionChainTipInfo(common.Hash, uint64) error
PutDKGPrivateKey(uint64, dkg.PrivateKey) error
+ PutOrUpdateDKGMasterPrivateShares(round uint64, shares dkg.PrivateKeyShares) error
}
// BlockIterator defines an iterator on blocks hold
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/level-db.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/db/level-db.go
index 1fe29fa10..efa1fecbc 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/level-db.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/db/level-db.go
@@ -29,9 +29,10 @@ import (
)
var (
- blockKeyPrefix = []byte("b-")
- compactionChainTipInfoKey = []byte("cc-tip")
- dkgPrivateKeyKeyPrefix = []byte("dkg-prvs")
+ blockKeyPrefix = []byte("b-")
+ compactionChainTipInfoKey = []byte("cc-tip")
+ dkgPrivateKeyKeyPrefix = []byte("dkg-prvs")
+ dkgMasterPrivateSharesPrefix = []byte("dkg-master-private-shares")
)
type compactionChainTipInfo struct {
@@ -188,6 +189,11 @@ func (lvl *LevelDBBackedDB) HasDKGPrivateKey(round uint64) (bool, error) {
return lvl.db.Has(lvl.getDKGPrivateKeyKey(round), nil)
}
+// HasDKGMasterPrivateSharesKey check existence of DKG master private shares of one round.
+func (lvl *LevelDBBackedDB) HasDKGMasterPrivateSharesKey(round uint64) (bool, error) {
+ return lvl.db.Has(lvl.getDKGMasterPrivateSharesKey(round), nil)
+}
+
// GetDKGPrivateKey get DKG private key of one round.
func (lvl *LevelDBBackedDB) GetDKGPrivateKey(round uint64) (
prv dkg.PrivateKey, err error) {
@@ -221,6 +227,32 @@ func (lvl *LevelDBBackedDB) PutDKGPrivateKey(
lvl.getDKGPrivateKeyKey(round), marshaled, nil)
}
+// GetDKGMasterPrivateShares get DKG master private shares of one round.
+func (lvl *LevelDBBackedDB) GetDKGMasterPrivateShares(round uint64) (
+ shares dkg.PrivateKeyShares, err error) {
+ queried, err := lvl.db.Get(lvl.getDKGMasterPrivateSharesKey(round), nil)
+ if err != nil {
+ if err == leveldb.ErrNotFound {
+ err = ErrDKGMasterPrivateSharesDoesNotExist
+ }
+ return
+ }
+
+ err = rlp.DecodeBytes(queried, &shares)
+ return
+}
+
+// PutOrUpdateDKGMasterPrivateShares save DKG master private shares of one round.
+func (lvl *LevelDBBackedDB) PutOrUpdateDKGMasterPrivateShares(
+ round uint64, shares dkg.PrivateKeyShares) error {
+ marshaled, err := rlp.EncodeToBytes(&shares)
+ if err != nil {
+ return err
+ }
+ return lvl.db.Put(
+ lvl.getDKGMasterPrivateSharesKey(round), marshaled, nil)
+}
+
func (lvl *LevelDBBackedDB) getBlockKey(hash common.Hash) (ret []byte) {
ret = make([]byte, len(blockKeyPrefix)+len(hash[:]))
copy(ret, blockKeyPrefix)
@@ -236,3 +268,10 @@ func (lvl *LevelDBBackedDB) getDKGPrivateKeyKey(
ret[len(dkgPrivateKeyKeyPrefix):], round)
return
}
+
+func (lvl *LevelDBBackedDB) getDKGMasterPrivateSharesKey(round uint64) (ret []byte) {
+ ret = make([]byte, len(dkgMasterPrivateSharesPrefix)+8)
+ copy(ret, dkgMasterPrivateSharesPrefix)
+ binary.LittleEndian.PutUint64(ret[len(dkgMasterPrivateSharesPrefix):], round)
+ return
+}
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/memory.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/db/memory.go
index 4bc08e704..548e41e90 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/memory.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/db/memory.go
@@ -42,24 +42,27 @@ func (seq *blockSeqIterator) NextBlock() (types.Block, error) {
// MemBackedDB is a memory backed DB implementation.
type MemBackedDB struct {
- blocksLock sync.RWMutex
- blockHashSequence common.Hashes
- blocksByHash map[common.Hash]*types.Block
- compactionChainTipLock sync.RWMutex
- compactionChainTipHash common.Hash
- compactionChainTipHeight uint64
- dkgPrivateKeysLock sync.RWMutex
- dkgPrivateKeys map[uint64]*dkg.PrivateKey
- persistantFilePath string
+ blocksLock sync.RWMutex
+ blockHashSequence common.Hashes
+ blocksByHash map[common.Hash]*types.Block
+ compactionChainTipLock sync.RWMutex
+ compactionChainTipHash common.Hash
+ compactionChainTipHeight uint64
+ dkgPrivateKeysLock sync.RWMutex
+ dkgPrivateKeys map[uint64]*dkg.PrivateKey
+ dkgMasterPrivateSharesLock sync.RWMutex
+ dkgMasterPrivateShares map[uint64]*dkg.PrivateKeyShares
+ persistantFilePath string
}
// NewMemBackedDB initialize a memory-backed database.
func NewMemBackedDB(persistantFilePath ...string) (
dbInst *MemBackedDB, err error) {
dbInst = &MemBackedDB{
- blockHashSequence: common.Hashes{},
- blocksByHash: make(map[common.Hash]*types.Block),
- dkgPrivateKeys: make(map[uint64]*dkg.PrivateKey),
+ blockHashSequence: common.Hashes{},
+ blocksByHash: make(map[common.Hash]*types.Block),
+ dkgPrivateKeys: make(map[uint64]*dkg.PrivateKey),
+ dkgMasterPrivateShares: make(map[uint64]*dkg.PrivateKeyShares),
}
if len(persistantFilePath) == 0 || len(persistantFilePath[0]) == 0 {
return
@@ -197,6 +200,34 @@ func (m *MemBackedDB) PutDKGPrivateKey(
return nil
}
+// HasDKGMasterPrivateShares check existence of DKG master private shares of one round.
+func (m *MemBackedDB) HasDKGMasterPrivateShares(round uint64) (bool, error) {
+ m.dkgMasterPrivateSharesLock.RLock()
+ defer m.dkgMasterPrivateSharesLock.RUnlock()
+ _, exists := m.dkgMasterPrivateShares[round]
+ return exists, nil
+}
+
+// GetDKGMasterPrivateShares get DKG master private shares of one round.
+func (m *MemBackedDB) GetDKGMasterPrivateShares(round uint64) (
+ dkg.PrivateKeyShares, error) {
+ m.dkgMasterPrivateSharesLock.RLock()
+ defer m.dkgMasterPrivateSharesLock.RUnlock()
+ if shares, exists := m.dkgMasterPrivateShares[round]; exists {
+ return *shares, nil
+ }
+ return dkg.PrivateKeyShares{}, ErrDKGMasterPrivateSharesDoesNotExist
+}
+
+// PutOrUpdateDKGMasterPrivateShares save DKG master private shares of one round.
+func (m *MemBackedDB) PutOrUpdateDKGMasterPrivateShares(
+ round uint64, shares dkg.PrivateKeyShares) error {
+ m.dkgMasterPrivateSharesLock.Lock()
+ defer m.dkgMasterPrivateSharesLock.Unlock()
+ m.dkgMasterPrivateShares[round] = &shares
+ return nil
+}
+
// Close implement Closer interface, which would release allocated resource.
func (m *MemBackedDB) Close() (err error) {
// Save internal state to a pretty-print json file. It's a temporary way
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go
index 6c812db73..259d07a4b 100644
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go
@@ -24,6 +24,7 @@ import (
"github.com/dexon-foundation/dexon-consensus/common"
"github.com/dexon-foundation/dexon-consensus/core/crypto"
"github.com/dexon-foundation/dexon-consensus/core/crypto/dkg"
+ "github.com/dexon-foundation/dexon-consensus/core/db"
"github.com/dexon-foundation/dexon-consensus/core/types"
typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg"
"github.com/dexon-foundation/dexon-consensus/core/utils"
@@ -164,6 +165,35 @@ func newDKGProtocol(
}
}
+func recoverDKGProtocol(
+ ID types.NodeID,
+ recv dkgReceiver,
+ round uint64,
+ threshold int,
+ coreDB db.Database) (*dkgProtocol, error) {
+ shares, err := coreDB.GetDKGMasterPrivateShares(round)
+ if err != nil {
+ if err == db.ErrDKGMasterPrivateSharesDoesNotExist {
+ return nil, nil
+ }
+
+ return nil, err
+ }
+ return &dkgProtocol{
+ ID: ID,
+ recv: recv,
+ round: round,
+ threshold: threshold,
+ idMap: make(map[types.NodeID]dkg.ID),
+ mpkMap: make(map[types.NodeID]*dkg.PublicKeyShares),
+ masterPrivateShare: &shares,
+ prvShares: dkg.NewEmptyPrivateKeyShares(),
+ prvSharesReceived: make(map[types.NodeID]struct{}),
+ nodeComplained: make(map[types.NodeID]struct{}),
+ antiComplaintReceived: make(map[types.NodeID]map[types.NodeID]struct{}),
+ }, nil
+}
+
func (d *dkgProtocol) processMasterPublicKeys(
mpks []*typesDKG.MasterPublicKey) (err error) {
d.idMap = make(map[types.NodeID]dkg.ID, len(mpks))
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/round-based-config.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/round-based-config.go
deleted file mode 100644
index 4f3a4cbf9..000000000
--- a/vendor/github.com/dexon-foundation/dexon-consensus/core/round-based-config.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2018 The dexon-consensus Authors
-// This file is part of the dexon-consensus library.
-//
-// The dexon-consensus library is free software: you can redistribute it
-// and/or modify it under the terms of the GNU Lesser General Public License as
-// published by the Free Software Foundation, either version 3 of the License,
-// or (at your option) any later version.
-//
-// The dexon-consensus library is distributed in the hope that it will be
-// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
-// General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the dexon-consensus library. If not, see
-// <http://www.gnu.org/licenses/>.
-
-package core
-
-import (
- "fmt"
-
- "github.com/dexon-foundation/dexon-consensus/core/types"
-)
-
-type roundBasedConfig struct {
- roundID uint64
- roundBeginHeight uint64
- roundEndHeight uint64
- roundInterval uint64
-}
-
-func (config *roundBasedConfig) setupRoundBasedFields(
- roundID uint64, cfg *types.Config) {
- config.roundID = roundID
- config.roundInterval = cfg.RoundLength
-}
-
-func (config *roundBasedConfig) setRoundBeginHeight(begin uint64) {
- config.roundBeginHeight = begin
- config.roundEndHeight = begin + config.roundInterval
-}
-
-// isLastBlock checks if a block is the last block of this round.
-func (config *roundBasedConfig) isLastBlock(b *types.Block) bool {
- if b.Position.Round != config.roundID {
- panic(fmt.Errorf("attempt to compare by different round: %s, %d",
- b, config.roundID))
- }
- return b.Position.Height+1 == config.roundEndHeight
-}
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-based-config.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-based-config.go
new file mode 100644
index 000000000..3219a1379
--- /dev/null
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-based-config.go
@@ -0,0 +1,112 @@
+// Copyright 2018 The dexon-consensus Authors
+// This file is part of the dexon-consensus library.
+//
+// The dexon-consensus library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus library is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package utils
+
+import (
+ "fmt"
+
+ "github.com/dexon-foundation/dexon-consensus/core/types"
+)
+
+// RoundBasedConfig is based config for rounds and provide boundary checking
+// for rounds.
+type RoundBasedConfig struct {
+ roundID uint64
+ roundBeginHeight uint64
+ roundEndHeight uint64
+ roundLength uint64
+}
+
+// SetupRoundBasedFields setup round based fields, including round ID, the
+// length of rounds.
+func (c *RoundBasedConfig) SetupRoundBasedFields(
+ roundID uint64, cfg *types.Config) {
+ if c.roundLength > 0 {
+ panic(fmt.Errorf("duplicated set round based fields: %d",
+ c.roundLength))
+ }
+ c.roundID = roundID
+ c.roundLength = cfg.RoundLength
+}
+
+// SetRoundBeginHeight gives the beginning height for the initial round provided
+// when constructed.
+func (c *RoundBasedConfig) SetRoundBeginHeight(begin uint64) {
+ if c.roundBeginHeight != 0 {
+ panic(fmt.Errorf("duplicated set round begin height: %d",
+ c.roundBeginHeight))
+ }
+ c.roundBeginHeight = begin
+ c.roundEndHeight = begin + c.roundLength
+}
+
+// IsLastBlock checks if a block is the last block of this round.
+func (c *RoundBasedConfig) IsLastBlock(b *types.Block) bool {
+ if b.Position.Round != c.roundID {
+ panic(fmt.Errorf("attempt to compare by different round: %s, %d",
+ b, c.roundID))
+ }
+ return b.Position.Height+1 == c.roundEndHeight
+}
+
+// ExtendLength extends round ending height by the length of current round.
+func (c *RoundBasedConfig) ExtendLength() {
+ c.roundEndHeight += c.roundLength
+}
+
+// Contains checks if a block height is in this round.
+func (c *RoundBasedConfig) Contains(h uint64) bool {
+ return c.roundBeginHeight <= h && c.roundEndHeight > h
+}
+
+// RoundID returns the round ID of this config.
+func (c *RoundBasedConfig) RoundID() uint64 {
+ if c.roundLength == 0 {
+ panic(fmt.Errorf("config is not initialized: %d", c.roundID))
+ }
+ return c.roundID
+}
+
+// RoundEndHeight returns next checkpoint to varify if this round is ended.
+func (c *RoundBasedConfig) RoundEndHeight() uint64 {
+ if c.roundLength == 0 {
+ panic(fmt.Errorf("config is not initialized: %d", c.roundID))
+ }
+ return c.roundEndHeight
+}
+
+// AppendTo a config in previous round.
+func (c *RoundBasedConfig) AppendTo(other RoundBasedConfig) {
+ if c.roundID != other.roundID+1 {
+ panic(fmt.Errorf("round IDs of configs not continuous: %d %d",
+ c.roundID, other.roundID))
+ }
+ c.SetRoundBeginHeight(other.roundEndHeight)
+}
+
+// LastPeriodBeginHeight returns the begin height of last period. For example,
+// if a round is extended twice, then the return from this method is:
+//
+// begin + 2 * roundLength - roundLength
+//
+func (c *RoundBasedConfig) LastPeriodBeginHeight() uint64 {
+ if c.roundLength == 0 {
+ panic(fmt.Errorf("config is not initialized: %d", c.roundID))
+ }
+ return c.roundEndHeight - c.roundLength
+}
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go
new file mode 100644
index 000000000..bab1d32d2
--- /dev/null
+++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go
@@ -0,0 +1,302 @@
+// Copyright 2019 The dexon-consensus Authors
+// This file is part of the dexon-consensus library.
+//
+// The dexon-consensus library is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// The dexon-consensus library is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+// General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the dexon-consensus library. If not, see
+// <http://www.gnu.org/licenses/>.
+
+package utils
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "time"
+
+ "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"
+)
+
+// ErrUnmatchedBlockHeightWithGov is for invalid parameters for NewRoundEvent.
+type ErrUnmatchedBlockHeightWithGov struct {
+ round uint64
+ reset uint64
+ blockHeight uint64
+}
+
+func (e ErrUnmatchedBlockHeightWithGov) Error() string {
+ return fmt.Sprintf("unsynced block height and gov: round:%d reset:%d h:%d",
+ e.round, e.reset, e.blockHeight)
+}
+
+// RoundEventParam defines the parameters passed to event handlers of
+// RoundEvent.
+type RoundEventParam struct {
+ // 'Round' of next checkpoint, might be identical to previous checkpoint.
+ Round uint64
+ // the count of reset DKG for 'Round+1'.
+ Reset uint64
+ // the begin block height of this event, the end block height of this event
+ // would be BeginHeight + config.RoundLength.
+ BeginHeight uint64
+ // The configuration for 'Round'.
+ Config *types.Config
+ // The CRS for 'Round'.
+ CRS common.Hash
+}
+
+// NextRoundCheckpoint returns the height to check if the next round is ready.
+func (e RoundEventParam) NextRoundCheckpoint() uint64 {
+ return e.BeginHeight + e.Config.RoundLength*8/10
+}
+
+// roundEventFn defines the fingerprint of handlers of round events.
+type roundEventFn func([]RoundEventParam)
+
+// governanceAccessor is a subset of core.Governance to break the dependency
+// between core and utils package.
+type governanceAccessor interface {
+ // Configuration returns the configuration at a given round.
+ // Return the genesis configuration if round == 0.
+ Configuration(round uint64) *types.Config
+
+ // CRS returns the CRS for a given round.
+ // Return the genesis CRS if round == 0.
+ CRS(round uint64) common.Hash
+
+ // DKGComplaints gets all the DKGComplaints of round.
+ DKGComplaints(round uint64) []*typesDKG.Complaint
+
+ // DKGMasterPublicKeys gets all the DKGMasterPublicKey of round.
+ DKGMasterPublicKeys(round uint64) []*typesDKG.MasterPublicKey
+
+ // IsDKGFinal checks if DKG is final.
+ IsDKGFinal(round uint64) bool
+
+ // DKGResetCount returns the reset count for DKG of given round.
+ DKGResetCount(round uint64) uint64
+}
+
+// RoundEvent would be triggered when either:
+// - the next DKG set setup is ready.
+// - the next DKG set setup is failed, and previous DKG set already reset the
+// CRS.
+type RoundEvent struct {
+ gov governanceAccessor
+ logger common.Logger
+ lock sync.Mutex
+ handlers []roundEventFn
+ config RoundBasedConfig
+ lastTriggeredRound uint64
+ lastTriggeredResetCount uint64
+ roundShift uint64
+ ctx context.Context
+ ctxCancel context.CancelFunc
+}
+
+// NewRoundEvent creates an RoundEvent instance.
+func NewRoundEvent(parentCtx context.Context, gov governanceAccessor,
+ logger common.Logger, initRound uint64,
+ initRoundBeginHeight, initBlockHeight uint64,
+ roundShift uint64) (*RoundEvent, error) {
+ // We need to generate valid ending block height of this round (taken
+ // DKG reset count into consideration).
+ e := &RoundEvent{
+ gov: gov,
+ logger: logger,
+ lastTriggeredRound: initRound,
+ roundShift: roundShift,
+ }
+ e.ctx, e.ctxCancel = context.WithCancel(parentCtx)
+ e.config = RoundBasedConfig{}
+ e.config.SetupRoundBasedFields(initRound, GetConfigWithPanic(
+ gov, initRound, logger))
+ e.config.SetRoundBeginHeight(initRoundBeginHeight)
+ // Make sure the DKG reset count in current governance can cover the initial
+ // block height.
+ resetCount := gov.DKGResetCount(initRound + 1)
+ remains := resetCount
+ for ; resetCount > 0 && !e.config.Contains(initBlockHeight); remains-- {
+ e.config.ExtendLength()
+ }
+ if !e.config.Contains(initBlockHeight) {
+ return nil, ErrUnmatchedBlockHeightWithGov{
+ round: initRound,
+ reset: resetCount,
+ blockHeight: initBlockHeight,
+ }
+ }
+ e.lastTriggeredResetCount = resetCount - remains
+ return e, nil
+}
+
+// Register a handler to be called when new round is confirmed or new DKG reset
+// is detected.
+func (e *RoundEvent) Register(h roundEventFn) {
+ e.lock.Lock()
+ defer e.lock.Unlock()
+ e.handlers = append(e.handlers, h)
+}
+
+// ValidateNextRound validate if the DKG set for next round is ready to go or
+// failed to setup, all registered handlers would be called once some decision
+// is made on chain.
+//
+// This method would block until at least one event is triggered. Multiple
+// trigger in one call is possible.
+func (e *RoundEvent) ValidateNextRound(blockHeight uint64) {
+ // To make triggers continuous and sequential, the next validation should
+ // wait for previous one finishing. That's why I use mutex here directly.
+ var events []RoundEventParam
+ e.lock.Lock()
+ defer e.lock.Unlock()
+ e.logger.Info("ValidateNextRound",
+ "height", blockHeight,
+ "round", e.lastTriggeredRound,
+ "count", e.lastTriggeredResetCount)
+ defer func() {
+ if len(events) == 0 {
+ return
+ }
+ for _, h := range e.handlers {
+ // To make sure all handlers receive triggers sequentially, we can't
+ // raise go routines here.
+ h(events)
+ }
+ }()
+ startRound := e.lastTriggeredRound
+ for {
+ var (
+ dkgFailed, triggered bool
+ param RoundEventParam
+ beginHeight = blockHeight
+ )
+ for {
+ param, dkgFailed, triggered = e.check(beginHeight, startRound,
+ dkgFailed)
+ if !triggered {
+ break
+ }
+ events = append(events, param)
+ beginHeight = param.BeginHeight
+ }
+ if len(events) > 0 {
+ break
+ }
+ select {
+ case <-e.ctx.Done():
+ return
+ case <-time.After(500 * time.Millisecond):
+ }
+ }
+}
+
+func (e *RoundEvent) check(blockHeight, startRound uint64, lastDKGCheck bool) (
+ param RoundEventParam, dkgFailed bool, triggered bool) {
+ defer func() {
+ if !triggered {
+ return
+ }
+ // A simple assertion to make sure we didn't pick the wrong round.
+ if e.config.RoundID() != e.lastTriggeredRound {
+ panic(fmt.Errorf("triggered round not matched: %d, %d",
+ e.config.RoundID(), e.lastTriggeredRound))
+ }
+ param.Round = e.lastTriggeredRound
+ param.Reset = e.lastTriggeredResetCount
+ param.BeginHeight = e.config.LastPeriodBeginHeight()
+ param.CRS = GetCRSWithPanic(e.gov, e.lastTriggeredRound, e.logger)
+ param.Config = GetConfigWithPanic(e.gov, e.lastTriggeredRound, e.logger)
+ e.logger.Info("new RoundEvent triggered",
+ "round", e.lastTriggeredRound,
+ "reset", e.lastTriggeredResetCount,
+ "begin-height", e.config.LastPeriodBeginHeight(),
+ "crs", param.CRS.String()[:6],
+ )
+ }()
+ // Make sure current last config covers the blockHeight.
+ if !e.config.Contains(blockHeight) {
+ panic(ErrUnmatchedBlockHeightWithGov{
+ round: e.lastTriggeredRound,
+ reset: e.lastTriggeredResetCount,
+ blockHeight: blockHeight,
+ })
+ }
+ nextRound := e.lastTriggeredRound + 1
+ if nextRound >= startRound+e.roundShift {
+ // Avoid access configuration newer than last confirmed one over
+ // 'roundShift' rounds. Fullnode might crash if we access it before it
+ // knows.
+ return
+ }
+ nextCfg := GetConfigWithPanic(e.gov, nextRound, e.logger)
+ resetCount := e.gov.DKGResetCount(nextRound)
+ if resetCount > e.lastTriggeredResetCount {
+ e.lastTriggeredResetCount++
+ e.config.ExtendLength()
+ triggered = true
+ return
+ }
+ if lastDKGCheck {
+ // We know that DKG already failed, now wait for the DKG set from
+ // previous round to reset DKG and don't have to reconstruct the
+ // group public key again.
+ dkgFailed = true
+ return
+ }
+ if nextRound >= dkgDelayRound {
+ if !e.gov.IsDKGFinal(nextRound) {
+ e.logger.Debug("DKG is not final, waiting for DKG reset",
+ "round", nextRound,
+ "reset", e.lastTriggeredResetCount)
+ return
+ }
+ if _, err := typesDKG.NewGroupPublicKey(
+ nextRound,
+ e.gov.DKGMasterPublicKeys(nextRound),
+ e.gov.DKGComplaints(nextRound),
+ GetDKGThreshold(nextCfg)); err != nil {
+ e.logger.Debug(
+ "group public key setup failed, waiting for DKG reset",
+ "round", nextRound,
+ "reset", e.lastTriggeredResetCount)
+ dkgFailed = true
+ return
+ }
+ }
+ // The DKG set for next round is well prepared.
+ e.lastTriggeredRound = nextRound
+ e.lastTriggeredResetCount = 0
+ rCfg := RoundBasedConfig{}
+ rCfg.SetupRoundBasedFields(nextRound, nextCfg)
+ rCfg.AppendTo(e.config)
+ e.config = rCfg
+ triggered = true
+ return
+}
+
+// Stop the event source and block until last trigger returns.
+func (e *RoundEvent) Stop() {
+ e.ctxCancel()
+}
+
+// LastPeriod returns block height related info of the last period, including
+// begin height and round length.
+func (e *RoundEvent) LastPeriod() (begin uint64, length uint64) {
+ e.lock.Lock()
+ defer e.lock.Unlock()
+ begin = e.config.LastPeriodBeginHeight()
+ length = e.config.RoundEndHeight() - e.config.LastPeriodBeginHeight()
+ return
+}