From 70ab62c1b72c6fef8dd2c8e405d7f9823f70f475 Mon Sep 17 00:00:00 2001 From: Mission Liao Date: Tue, 18 Dec 2018 10:02:30 +0800 Subject: vendor: sync to latest core (#91) - Implement new methods in db to cache DKG private key. - Implement new methods in db to cache compaction chain tip. --- .../dexon-consensus/core/configuration-chain.go | 109 +++++++++---- .../dexon-consensus/core/consensus.go | 25 +-- .../dexon-consensus/core/crypto/dkg/utils.go | 21 +++ .../dexon-consensus/core/db/interfaces.go | 23 +++ .../dexon-consensus/core/db/level-db.go | 176 ++++++++++++++++++--- .../dexon-consensus/core/db/memory.go | 92 +++++++++-- .../dexon-consensus/core/dkg-tsig-protocol.go | 13 +- .../dexon-foundation/dexon-consensus/core/utils.go | 4 + 8 files changed, 383 insertions(+), 80 deletions(-) (limited to 'vendor/github.com/dexon-foundation/dexon-consensus') 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 364f2c75c..2b3a859ed 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 @@ -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/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" @@ -53,6 +54,7 @@ type configurationChain struct { tsigTouched map[common.Hash]struct{} tsigReady *sync.Cond cache *utils.NodeSetCache + db db.Database dkgSet map[types.NodeID]struct{} mpkReady bool pendingPrvShare map[types.NodeID]*typesDKG.PrivateShare @@ -66,6 +68,7 @@ func newConfigurationChain( recv dkgReceiver, gov Governance, cache *utils.NodeSetCache, + dbInst db.Database, logger common.Logger) *configurationChain { return &configurationChain{ ID: ID, @@ -78,6 +81,7 @@ func newConfigurationChain( tsigTouched: make(map[common.Hash]struct{}), tsigReady: sync.NewCond(&sync.Mutex{}), cache: cache, + db: dbInst, pendingPsig: make(map[common.Hash][]*typesDKG.PartialSignature), } } @@ -104,6 +108,10 @@ func (cc *configurationChain) registerDKG(round uint64, threshold int) { } func (cc *configurationChain) runDKG(round uint64) error { + // Check if corresponding DKG signer is ready. + if _, _, err := cc.getDKGInfo(round); err == nil { + return nil + } cc.dkgLock.Lock() defer cc.dkgLock.Unlock() if cc.dkg == nil || cc.dkg.round != round { @@ -113,20 +121,11 @@ func (cc *configurationChain) runDKG(round uint64) error { } return ErrDKGNotRegistered } - if func() bool { - cc.dkgResult.RLock() - defer cc.dkgResult.RUnlock() - _, exist := cc.gpk[round] - return exist - }() { - return nil - } cc.logger.Debug("Calling Governance.IsDKGFinal", "round", round) if cc.gov.IsDKGFinal(round) { cc.logger.Warn("DKG already final", "round", round) return nil } - ticker := newTicker(cc.gov, round, TickerDKG) cc.dkgLock.Unlock() <-ticker.Tick() @@ -153,7 +152,8 @@ func (cc *configurationChain) runDKG(round uint64) error { cc.dkgLock.Lock() // Phase 5(T = 2λ): Propose Anti nack complaint. cc.logger.Debug("Calling Governance.DKGComplaints", "round", round) - cc.dkg.processNackComplaints(cc.gov.DKGComplaints(round)) + complaints := cc.gov.DKGComplaints(round) + cc.dkg.processNackComplaints(complaints) cc.dkgLock.Unlock() <-ticker.Tick() cc.dkgLock.Lock() @@ -163,8 +163,7 @@ func (cc *configurationChain) runDKG(round uint64) error { <-ticker.Tick() cc.dkgLock.Lock() // Phase 7(T = 4λ): Enforce complaints and nack complaints. - cc.logger.Debug("Calling Governance.DKGComplaints", "round", round) - cc.dkg.enforceNackComplaints(cc.gov.DKGComplaints(round)) + cc.dkg.enforceNackComplaints(complaints) // Enforce complaint is done in `processPrivateShare`. // Phase 8(T = 5λ): DKG finalize. cc.dkgLock.Unlock() @@ -209,6 +208,10 @@ func (cc *configurationChain) runDKG(round uint64) error { if err != nil { return err } + // Save private shares to DB. + if err = cc.db.PutDKGPrivateKey(round, *signer.privateKey); err != nil { + return err + } cc.dkgResult.Lock() defer cc.dkgResult.Unlock() cc.dkgSigner[round] = signer @@ -220,23 +223,74 @@ func (cc *configurationChain) isDKGReady(round uint64) bool { if !cc.gov.IsDKGFinal(round) { return false } - return func() bool { + _, _, err := cc.getDKGInfo(round) + return err == nil +} + +func (cc *configurationChain) getDKGInfo( + round uint64) (*DKGGroupPublicKey, *dkgShareSecret, error) { + getFromCache := func() (*DKGGroupPublicKey, *dkgShareSecret) { cc.dkgResult.RLock() defer cc.dkgResult.RUnlock() - _, exist := cc.gpk[round] - return exist - }() + gpk := cc.gpk[round] + signer := cc.dkgSigner[round] + return gpk, signer + } + gpk, signer := getFromCache() + if gpk == nil || signer == nil { + if err := cc.recoverDKGInfo(round); err != nil { + return nil, nil, err + } + gpk, signer = getFromCache() + } + if gpk == nil || signer == nil { + return nil, nil, ErrDKGNotReady + } + return gpk, signer, nil +} + +func (cc *configurationChain) recoverDKGInfo(round uint64) error { + cc.dkgResult.Lock() + defer cc.dkgResult.Unlock() + _, signerExists := cc.dkgSigner[round] + _, gpkExists := cc.gpk[round] + if signerExists && gpkExists { + return nil + } + if !cc.gov.IsDKGFinal(round) { + return ErrDKGNotReady + } + + threshold := getDKGThreshold(cc.gov.Configuration(round)) + // Restore group public key. + gpk, err := NewDKGGroupPublicKey(round, + cc.gov.DKGMasterPublicKeys(round), + cc.gov.DKGComplaints(round), + threshold) + if err != nil { + return err + } + // Restore DKG share secret, this segment of code is copied from + // dkgProtocol.recoverShareSecret. + if len(gpk.qualifyIDs) < threshold { + return ErrNotReachThreshold + } + // Check if we have private shares in DB. + prvKey, err := cc.db.GetDKGPrivateKey(round) + if err != nil { + return err + } + cc.gpk[round] = gpk + cc.dkgSigner[round] = &dkgShareSecret{ + privateKey: &prvKey, + } + return nil } func (cc *configurationChain) preparePartialSignature( round uint64, hash common.Hash) (*typesDKG.PartialSignature, error) { - signer, exist := func() (*dkgShareSecret, bool) { - cc.dkgResult.RLock() - defer cc.dkgResult.RUnlock() - signer, exist := cc.dkgSigner[round] - return signer, exist - }() - if !exist { + _, signer, _ := cc.getDKGInfo(round) + if signer == nil { return nil, ErrDKGNotReady } return &typesDKG.PartialSignature{ @@ -264,13 +318,8 @@ func (cc *configurationChain) untouchTSigHash(hash common.Hash) { func (cc *configurationChain) runTSig( round uint64, hash common.Hash) ( crypto.Signature, error) { - gpk, exist := func() (*DKGGroupPublicKey, bool) { - cc.dkgResult.RLock() - defer cc.dkgResult.RUnlock() - gpk, exist := cc.gpk[round] - return gpk, exist - }() - if !exist { + gpk, _, _ := cc.getDKGInfo(round) + if gpk == nil { return crypto.Signature{}, ErrDKGNotReady } cc.tsigReady.L.Lock() 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 a6d80371d..5beaf546a 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go @@ -424,6 +424,7 @@ func NewConsensus( recv, gov, nodeSetCache, + db, logger) recv.cfgModule = cfgModule // Construct Consensus instance. @@ -490,6 +491,7 @@ func NewConsensusFromSyncer( recv, gov, nodeSetCache, + db, logger) recv.cfgModule = cfgModule // Setup Consensus instance. @@ -576,7 +578,7 @@ func (con *Consensus) prepare(initBlock *types.Block) error { } if _, exist := dkgSet[con.ID]; exist { con.logger.Info("Selected as DKG set", "round", initRound) - con.cfgModule.registerDKG(initRound, int(initConfig.DKGSetSize)/3+1) + con.cfgModule.registerDKG(initRound, getDKGThreshold(initConfig)) con.event.RegisterTime(con.dMoment.Add(initConfig.RoundInterval/4), func(time.Time) { con.runDKG(initRound, initConfig) @@ -742,8 +744,7 @@ func (con *Consensus) initialRound( return } con.logger.Info("Selected as DKG set", "round", nextRound) - con.cfgModule.registerDKG( - nextRound, int(config.DKGSetSize/3)+1) + con.cfgModule.registerDKG(nextRound, getDKGThreshold(config)) con.event.RegisterTime( startTime.Add(config.RoundInterval*2/3), func(time.Time) { @@ -1003,6 +1004,14 @@ func (con *Consensus) preProcessBlock(b *types.Block) (err error) { // deliverBlock deliver a block to application layer. func (con *Consensus) deliverBlock(b *types.Block) { + if err := con.db.UpdateBlock(*b); err != nil { + panic(err) + } + if err := con.db.PutCompactionChainTipInfo( + b.Hash, b.Finalization.Height); err != nil { + panic(err) + } + con.cfgModule.untouchTSigHash(b.Hash) con.logger.Debug("Calling Application.BlockDelivered", "block", b) con.app.BlockDelivered(b.Hash, b.Position, b.Finalization.Clone()) if b.Position.Round == con.roundToNotify { @@ -1032,6 +1041,9 @@ func (con *Consensus) deliverBlock(b *types.Block) { con.roundToNotify, b.Finalization.Height) con.roundToNotify++ } + if con.debugApp != nil { + con.debugApp.BlockReady(b.Hash) + } } // processBlock is the entry point to submit one block to a Consensus instance. @@ -1072,14 +1084,7 @@ func (con *Consensus) processBlock(block *types.Block) (err error) { "delivered", con.ccModule.lastDeliveredBlock(), "pending", con.ccModule.lastPendingBlock()) for _, b := range deliveredBlocks { - if err = con.db.UpdateBlock(*b); err != nil { - panic(err) - } - con.cfgModule.untouchTSigHash(b.Hash) con.deliverBlock(b) - if con.debugApp != nil { - con.debugApp.BlockReady(b.Hash) - } } if err = con.lattice.PurgeBlocks(deliveredBlocks); err != nil { return diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/utils.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/utils.go index fa4ad9f05..9e470f0cf 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/utils.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/utils.go @@ -18,7 +18,9 @@ package dkg import ( + "encoding/binary" "fmt" + "math/rand" "github.com/dexon-foundation/bls/ffi/go/bls" @@ -69,3 +71,22 @@ func RecoverGroupPublicKey(pubShares []*PublicKeyShares) *PublicKey { } return pub } + +// NewRandomPrivateKeyShares constructs a private key shares randomly. +func NewRandomPrivateKeyShares() *PrivateKeyShares { + // Generate IDs. + rndIDs := make(IDs, 0, 10) + for i := range rndIDs { + id := make([]byte, 8) + binary.LittleEndian.PutUint64(id, rand.Uint64()) + rndIDs[i] = NewID(id) + } + prvShares := NewEmptyPrivateKeyShares() + prvShares.SetParticipants(rndIDs) + for _, id := range rndIDs { + if err := prvShares.AddShare(id, NewPrivateKey()); err != nil { + panic(err) + } + } + return prvShares +} 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 5e13dc604..ebbbbd475 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 @@ -22,6 +22,7 @@ import ( "fmt" "github.com/dexon-foundation/dexon-consensus/common" + "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" "github.com/dexon-foundation/dexon-consensus/core/types" ) @@ -38,6 +39,17 @@ var ( ErrClosed = fmt.Errorf("db closed") // ErrNotImplemented is the error that some interface is not implemented. ErrNotImplemented = fmt.Errorf("not implemented") + // ErrInvalidCompactionChainTipHeight means the newly updated height of + // the tip of compaction chain is invalid, usually means it's smaller than + // current cached one. + ErrInvalidCompactionChainTipHeight = fmt.Errorf( + "invalid compaction chain tip height") + // ErrDKGPrivateKeyExists raised when attempting to save DKG private key + // that already saved. + ErrDKGPrivateKeyExists = errors.New("dkg private key exists") + // ErrDKGPrivateKeyDoesNotExist raised when the DKG private key of the + // requested round does not exists. + ErrDKGPrivateKeyDoesNotExist = errors.New("dkg private key does not exists") ) // Database is the interface for a Database. @@ -55,12 +67,23 @@ type Reader interface { HasBlock(hash common.Hash) bool GetBlock(hash common.Hash) (types.Block, error) GetAllBlocks() (BlockIterator, error) + + // GetCompactionChainTipInfo returns the block hash and finalization height + // of the tip block of compaction chain. Empty hash and zero height means + // the compaction chain is empty. + GetCompactionChainTipInfo() (common.Hash, uint64) + + // DKG Private Key related methods. + HasDKGPrivateKey(round uint64) (bool, error) + GetDKGPrivateKey(round uint64) (dkg.PrivateKey, error) } // Writer defines the interface for writing blocks into DB. type Writer interface { UpdateBlock(block types.Block) error PutBlock(block types.Block) error + PutCompactionChainTipInfo(common.Hash, uint64) error + PutDKGPrivateKey(uint64, dkg.PrivateKey) 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 6983d3a5e..3b5994b26 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 @@ -18,14 +18,27 @@ package db import ( - "encoding/json" + "encoding/binary" "github.com/syndtr/goleveldb/leveldb" "github.com/dexon-foundation/dexon-consensus/common" + "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" "github.com/dexon-foundation/dexon-consensus/core/types" + "github.com/dexon-foundation/dexon/rlp" ) +var ( + blockKeyPrefix = []byte("b-") + compactionChainTipInfoKey = []byte("cc-tip") + dkgPrivateKeyKeyPrefix = []byte("dkg-prvs") +) + +type compactionChainTipInfo struct { + Height uint64 `json:"height"` + Hash common.Hash `json:"hash"` +} + // LevelDBBackedDB is a leveldb backed DB implementation. type LevelDBBackedDB struct { db *leveldb.DB @@ -50,7 +63,7 @@ func (lvl *LevelDBBackedDB) Close() error { // HasBlock implements the Reader.Has method. func (lvl *LevelDBBackedDB) HasBlock(hash common.Hash) bool { - exists, err := lvl.db.Has([]byte(hash[:]), nil) + exists, err := lvl.internalHasBlock(lvl.getBlockKey(hash)) if err != nil { // TODO(missionliao): Modify the interface to return error. panic(err) @@ -58,18 +71,25 @@ func (lvl *LevelDBBackedDB) HasBlock(hash common.Hash) bool { return exists } +func (lvl *LevelDBBackedDB) internalHasBlock(key []byte) (bool, error) { + exists, err := lvl.db.Has(key, nil) + if err != nil { + return false, err + } + return exists, nil +} + // GetBlock implements the Reader.GetBlock method. func (lvl *LevelDBBackedDB) GetBlock( hash common.Hash) (block types.Block, err error) { - - queried, err := lvl.db.Get([]byte(hash[:]), nil) + queried, err := lvl.db.Get(lvl.getBlockKey(hash), nil) if err != nil { if err == leveldb.ErrNotFound { err = ErrBlockDoesNotExist } return } - err = json.Unmarshal(queried, &block) + err = rlp.DecodeBytes(queried, &block) if err != nil { return } @@ -80,20 +100,20 @@ func (lvl *LevelDBBackedDB) GetBlock( func (lvl *LevelDBBackedDB) UpdateBlock(block types.Block) (err error) { // NOTE: we didn't handle changes of block hash (and it // should not happen). - marshaled, err := json.Marshal(&block) + marshaled, err := rlp.EncodeToBytes(&block) if err != nil { return } - - if !lvl.HasBlock(block.Hash) { + blockKey := lvl.getBlockKey(block.Hash) + exists, err := lvl.internalHasBlock(blockKey) + if err != nil { + return + } + if !exists { err = ErrBlockDoesNotExist return } - err = lvl.db.Put( - []byte(block.Hash[:]), - marshaled, - nil) - if err != nil { + if err = lvl.db.Put(blockKey, marshaled, nil); err != nil { return } return @@ -101,19 +121,20 @@ func (lvl *LevelDBBackedDB) UpdateBlock(block types.Block) (err error) { // PutBlock implements the Writer.PutBlock method. func (lvl *LevelDBBackedDB) PutBlock(block types.Block) (err error) { - marshaled, err := json.Marshal(&block) + marshaled, err := rlp.EncodeToBytes(&block) if err != nil { return } - if lvl.HasBlock(block.Hash) { + blockKey := lvl.getBlockKey(block.Hash) + exists, err := lvl.internalHasBlock(blockKey) + if err != nil { + return + } + if exists { err = ErrBlockExists return } - err = lvl.db.Put( - []byte(block.Hash[:]), - marshaled, - nil) - if err != nil { + if err = lvl.db.Put(blockKey, marshaled, nil); err != nil { return } return @@ -125,3 +146,118 @@ func (lvl *LevelDBBackedDB) GetAllBlocks() (BlockIterator, error) { // TODO (mission): Implement this part via goleveldb's iterator. return nil, ErrNotImplemented } + +// PutCompactionChainTipInfo saves tip of compaction chain into the database. +func (lvl *LevelDBBackedDB) PutCompactionChainTipInfo( + blockHash common.Hash, height uint64) error { + marshaled, err := rlp.EncodeToBytes(&compactionChainTipInfo{ + Hash: blockHash, + Height: height, + }) + if err != nil { + return err + } + // Check current cached tip info to make sure the one to be updated is + // valid. + info, err := lvl.internalGetCompactionChainTipInfo() + if err != nil { + return err + } + if info.Height >= height { + return ErrInvalidCompactionChainTipHeight + } + if err = lvl.db.Put(compactionChainTipInfoKey, marshaled, nil); err != nil { + return err + } + return nil +} + +func (lvl *LevelDBBackedDB) internalGetCompactionChainTipInfo() ( + info compactionChainTipInfo, err error) { + queried, err := lvl.db.Get(compactionChainTipInfoKey, nil) + if err != nil { + if err == leveldb.ErrNotFound { + err = nil + } + return + } + if err = rlp.DecodeBytes(queried, &info); err != nil { + return + } + return +} + +// GetCompactionChainTipInfo get the tip info of compaction chain into the +// database. +func (lvl *LevelDBBackedDB) GetCompactionChainTipInfo() ( + hash common.Hash, height uint64) { + info, err := lvl.internalGetCompactionChainTipInfo() + if err != nil { + panic(err) + } + hash, height = info.Hash, info.Height + return +} + +// HasDKGPrivateKey check existence of DKG private key of one round. +func (lvl *LevelDBBackedDB) HasDKGPrivateKey(round uint64) (bool, error) { + exists, err := lvl.db.Has(lvl.getDKGPrivateKeyKey(round), nil) + if err != nil { + return false, err + } + return exists, nil +} + +// GetDKGPrivateKey get DKG private key of one round. +func (lvl *LevelDBBackedDB) GetDKGPrivateKey(round uint64) ( + prv dkg.PrivateKey, err error) { + queried, err := lvl.db.Get(lvl.getDKGPrivateKeyKey(round), nil) + if err != nil { + if err == leveldb.ErrNotFound { + err = ErrDKGPrivateKeyDoesNotExist + } + return + } + if err = rlp.DecodeBytes(queried, &prv); err != nil { + return + } + return +} + +// PutDKGPrivateKey save DKG private key of one round. +func (lvl *LevelDBBackedDB) PutDKGPrivateKey( + round uint64, prv dkg.PrivateKey) error { + // Check existence. + exists, err := lvl.HasDKGPrivateKey(round) + if err != nil { + return err + } + if exists { + return ErrDKGPrivateKeyExists + } + marshaled, err := rlp.EncodeToBytes(&prv) + if err != nil { + return err + } + if err := lvl.db.Put( + lvl.getDKGPrivateKeyKey(round), marshaled, nil); err != nil { + return err + } + return nil +} + +func (lvl *LevelDBBackedDB) getBlockKey(hash common.Hash) (ret []byte) { + ret = make([]byte, len(blockKeyPrefix)+len(hash[:])) + copy(ret, blockKeyPrefix) + copy(ret[len(blockKeyPrefix):], hash[:]) + return +} + +func (lvl *LevelDBBackedDB) getDKGPrivateKeyKey( + round uint64) (ret []byte) { + ret = make([]byte, len(dkgPrivateKeyKeyPrefix)+8) + copy(ret, dkgPrivateKeyKeyPrefix) + binary.LittleEndian.PutUint64( + ret[len(dkgPrivateKeyKeyPrefix):], 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 4246e4fe1..7393de9db 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 @@ -24,6 +24,7 @@ import ( "sync" "github.com/dexon-foundation/dexon-consensus/common" + "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" "github.com/dexon-foundation/dexon-consensus/core/types" ) @@ -41,10 +42,15 @@ func (seq *blockSeqIterator) NextBlock() (types.Block, error) { // MemBackedDB is a memory backed DB implementation. type MemBackedDB struct { - blocksMutex sync.RWMutex - blockHashSequence common.Hashes - blocksByHash map[common.Hash]*types.Block - 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 + persistantFilePath string } // NewMemBackedDB initialize a memory-backed database. @@ -53,6 +59,7 @@ func NewMemBackedDB(persistantFilePath ...string) ( dbInst = &MemBackedDB{ blockHashSequence: common.Hashes{}, blocksByHash: make(map[common.Hash]*types.Block), + dkgPrivateKeys: make(map[uint64]*dkg.PrivateKey), } if len(persistantFilePath) == 0 || len(persistantFilePath[0]) == 0 { return @@ -87,8 +94,8 @@ func NewMemBackedDB(persistantFilePath ...string) ( // HasBlock returns wheter or not the DB has a block identified with the hash. func (m *MemBackedDB) HasBlock(hash common.Hash) bool { - m.blocksMutex.RLock() - defer m.blocksMutex.RUnlock() + m.blocksLock.RLock() + defer m.blocksLock.RUnlock() _, ok := m.blocksByHash[hash] return ok @@ -96,8 +103,8 @@ func (m *MemBackedDB) HasBlock(hash common.Hash) bool { // GetBlock returns a block given a hash. func (m *MemBackedDB) GetBlock(hash common.Hash) (types.Block, error) { - m.blocksMutex.RLock() - defer m.blocksMutex.RUnlock() + m.blocksLock.RLock() + defer m.blocksLock.RUnlock() return m.internalGetBlock(hash) } @@ -116,8 +123,8 @@ func (m *MemBackedDB) PutBlock(block types.Block) error { return ErrBlockExists } - m.blocksMutex.Lock() - defer m.blocksMutex.Unlock() + m.blocksLock.Lock() + defer m.blocksLock.Unlock() m.blockHashSequence = append(m.blockHashSequence, block.Hash) m.blocksByHash[block.Hash] = &block @@ -130,13 +137,66 @@ func (m *MemBackedDB) UpdateBlock(block types.Block) error { return ErrBlockDoesNotExist } - m.blocksMutex.Lock() - defer m.blocksMutex.Unlock() + m.blocksLock.Lock() + defer m.blocksLock.Unlock() m.blocksByHash[block.Hash] = &block return nil } +// PutCompactionChainTipInfo saves tip of compaction chain into the database. +func (m *MemBackedDB) PutCompactionChainTipInfo( + blockHash common.Hash, height uint64) error { + m.compactionChainTipLock.Lock() + defer m.compactionChainTipLock.Unlock() + if m.compactionChainTipHeight >= height { + return ErrInvalidCompactionChainTipHeight + } + m.compactionChainTipHeight = height + m.compactionChainTipHash = blockHash + return nil +} + +// GetCompactionChainTipInfo get the tip info of compaction chain into the +// database. +func (m *MemBackedDB) GetCompactionChainTipInfo() ( + hash common.Hash, height uint64) { + m.compactionChainTipLock.RLock() + defer m.compactionChainTipLock.RUnlock() + return m.compactionChainTipHash, m.compactionChainTipHeight +} + +// HasDKGPrivateKey check existence of DKG private key of one round. +func (m *MemBackedDB) HasDKGPrivateKey(round uint64) (bool, error) { + m.dkgPrivateKeysLock.RLock() + defer m.dkgPrivateKeysLock.RUnlock() + _, exists := m.dkgPrivateKeys[round] + return exists, nil +} + +// GetDKGPrivateKey get DKG private key of one round. +func (m *MemBackedDB) GetDKGPrivateKey(round uint64) ( + dkg.PrivateKey, error) { + m.dkgPrivateKeysLock.RLock() + defer m.dkgPrivateKeysLock.RUnlock() + if prv, exists := m.dkgPrivateKeys[round]; exists { + return *prv, nil + } + return dkg.PrivateKey{}, ErrDKGPrivateKeyDoesNotExist +} + +// PutDKGPrivateKey save DKG private key of one round. +func (m *MemBackedDB) PutDKGPrivateKey( + round uint64, prv dkg.PrivateKey) error { + m.dkgPrivateKeysLock.Lock() + defer m.dkgPrivateKeysLock.Unlock() + if _, exists := m.dkgPrivateKeys[round]; exists { + return ErrDKGPrivateKeyExists + } + m.dkgPrivateKeys[round] = &prv + 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 @@ -145,8 +205,8 @@ func (m *MemBackedDB) Close() (err error) { return } - m.blocksMutex.RLock() - defer m.blocksMutex.RUnlock() + m.blocksLock.RLock() + defer m.blocksLock.RUnlock() toDump := struct { Sequence common.Hashes @@ -167,8 +227,8 @@ func (m *MemBackedDB) Close() (err error) { } func (m *MemBackedDB) getBlockByIndex(idx int) (types.Block, error) { - m.blocksMutex.RLock() - defer m.blocksMutex.RUnlock() + m.blocksLock.RLock() + defer m.blocksLock.RUnlock() if idx >= len(m.blockHashSequence) { return types.Block{}, ErrIterationFinished 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 6645ecbae..8e03cbbda 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 @@ -378,16 +378,21 @@ func NewDKGGroupPublicKey( // Calculate qualify members. disqualifyIDs := map[types.NodeID]struct{}{} - complaintsByID := map[types.NodeID]int{} + complaintsByID := map[types.NodeID]map[types.NodeID]struct{}{} for _, complaint := range complaints { if complaint.IsNack() { - complaintsByID[complaint.PrivateShare.ProposerID]++ + if _, exist := complaintsByID[complaint.PrivateShare.ProposerID]; !exist { + complaintsByID[complaint.PrivateShare.ProposerID] = + make(map[types.NodeID]struct{}) + } + complaintsByID[complaint.PrivateShare.ProposerID][complaint.ProposerID] = + struct{}{} } else { disqualifyIDs[complaint.PrivateShare.ProposerID] = struct{}{} } } - for nID, num := range complaintsByID { - if num > threshold { + for nID, complaints := range complaintsByID { + if len(complaints) > threshold { disqualifyIDs[nID] = struct{}{} } } diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go index 2ef243757..671d68018 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go @@ -231,3 +231,7 @@ func isCircleCI() bool { func isTravisCI() bool { return isCI() && os.Getenv("TRAVIS") == "true" } + +func getDKGThreshold(config *types.Config) int { + return int(config.DKGSetSize/3) + 1 +} -- cgit v1.2.3