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/db/interfaces.go | 23 +++ .../dexon-consensus/core/db/level-db.go | 176 ++++++++++++++++++--- .../dexon-consensus/core/db/memory.go | 92 +++++++++-- 3 files changed, 255 insertions(+), 36 deletions(-) (limited to 'vendor/github.com/dexon-foundation/dexon-consensus/core/db') 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 -- cgit