"encoding/hex"
"fmt"
- "github.com/golang/groupcache/lru"
log "github.com/sirupsen/logrus"
"github.com/vapor/config"
"github.com/vapor/crypto/ed25519"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/errors"
- "github.com/vapor/event"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
"github.com/vapor/protocol/state"
errInvalidSignature = errors.New("the signature of block is invalid")
)
-type bbft struct {
- consensusNodeManager *consensusNodeManager
- orphanManage *OrphanManage
- signatureCache *lru.Cache
- eventDispatcher *event.Dispatcher
-}
-
-func newBbft(store Store, blockIndex *state.BlockIndex, orphanManage *OrphanManage, eventDispatcher *event.Dispatcher) *bbft {
- return &bbft{
- orphanManage: orphanManage,
- consensusNodeManager: newConsensusNodeManager(store, blockIndex),
- signatureCache: lru.New(maxSignatureCacheSize),
- eventDispatcher: eventDispatcher,
- }
-}
-
-func (b *bbft) isIrreversible(block *types.Block) bool {
- consensusNodes, err := b.consensusNodeManager.getConsensusNodesByVoteResult(&block.PreviousBlockHash)
+func (c *Chain) isIrreversible(block *types.Block) bool {
+ consensusNodes, err := c.consensusNodeManager.getConsensusNodesByVoteResult(&block.PreviousBlockHash)
if err != nil {
return false
}
- signNum, err := b.validateSign(block)
+ signNum, err := c.validateSign(block)
if err != nil {
return false
}
}
// NextLeaderTime returns the start time of the specified public key as the next leader node
-func (b *bbft) IsBlocker(prevBlockHash *bc.Hash, pubkey string, timeStamp uint64) (bool, error) {
- return b.consensusNodeManager.isBlocker(prevBlockHash, pubkey, timeStamp)
+func (c *Chain) IsBlocker(prevBlockHash *bc.Hash, pubkey string, timeStamp uint64) (bool, error) {
+ return c.consensusNodeManager.isBlocker(prevBlockHash, pubkey, timeStamp)
}
-func (b *bbft) ApplyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
- return b.consensusNodeManager.applyBlock(voteResultMap, block)
+func (c *Chain) ApplyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
+ return c.consensusNodeManager.applyBlock(voteResultMap, block)
}
-func (b *bbft) DetachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
- return b.consensusNodeManager.detachBlock(voteResultMap, block)
+func (c *Chain) DetachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
+ return c.consensusNodeManager.detachBlock(voteResultMap, block)
}
// ProcessBlockSignature process the received block signature messages
// return whether a block become irreversible, if so, the chain module must update status
-func (b *bbft) ProcessBlockSignature(signature []byte, xPub [64]byte, blockHeight uint64, blockHash *bc.Hash) (bool, error) {
- block, err := b.consensusNodeManager.store.GetBlock(blockHash)
+func (c *Chain) ProcessBlockSignature(signature []byte, xPub [64]byte, blockHeight uint64, blockHash *bc.Hash) error {
+ block, err := c.consensusNodeManager.store.GetBlock(blockHash)
if err != nil {
// block is not exist, save the signature
key := fmt.Sprintf("%s:%s", blockHash.String(), hex.EncodeToString(xPub[:]))
- b.signatureCache.Add(key, signature)
- return false, err
+ c.signatureCache.Add(key, signature)
+ return err
}
- consensusNode, err := b.consensusNodeManager.getConsensusNode(&block.PreviousBlockHash, hex.EncodeToString(xPub[:]))
+ consensusNode, err := c.consensusNodeManager.getConsensusNode(&block.PreviousBlockHash, hex.EncodeToString(xPub[:]))
if err != nil {
- return false, err
+ return err
}
if chainkd.XPub(xPub).Verify(blockHash.Bytes(), signature) {
- return false, errInvalidSignature
+ return errInvalidSignature
}
- isDoubleSign, err := b.checkDoubleSign(consensusNode.order, blockHeight, *blockHash)
+ isDoubleSign, err := c.checkDoubleSign(consensusNode.order, blockHeight, *blockHash)
if err != nil {
- return false, err
+ return err
}
if isDoubleSign {
log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "xPub": hex.EncodeToString(xPub[:])}).Warn("the consensus node double sign the same height of different block")
- return false, errDoubleSignBlock
+ return errDoubleSignBlock
}
- orphanBlock, ok := b.orphanManage.Get(blockHash)
+ orphanBlock, ok := c.orphanManage.Get(blockHash)
if ok {
orphanBlock.Witness[consensusNode.order] = signature
- return false, nil
+ return nil
}
- if err := b.updateBlockSignature(block, consensusNode.order, signature); err != nil {
- return false, err
+ if err := c.updateBlockSignature(block, consensusNode.order, signature); err != nil {
+ return err
}
- return b.isIrreversible(block), nil
+ if c.isIrreversible(block) && blockHeight > c.bestIrreversibleNode.Height {
+ bestIrreversibleNode := c.index.GetNode(blockHash)
+ if err := c.store.SaveChainNodeStatus(c.bestNode, bestIrreversibleNode); err != nil {
+ return err
+ }
+
+ c.bestIrreversibleNode = bestIrreversibleNode
+ }
+ return nil
}
// ValidateBlock verify whether the block is valid
-func (b *bbft) ValidateBlock(block *types.Block) error {
- signNum, err := b.validateSign(block)
+func (c *Chain) ValidateBlock(block *types.Block) error {
+ signNum, err := c.validateSign(block)
if err != nil {
return err
}
// validateSign verify the signatures of block, and return the number of correct signature
// if some signature is invalid, they will be reset to nil
// if the block has not the signature of blocker, it will return error
-func (b *bbft) validateSign(block *types.Block) (uint64, error) {
+func (c *Chain) validateSign(block *types.Block) (uint64, error) {
var correctSignNum uint64
- consensusNodeMap, err := b.consensusNodeManager.getConsensusNodesByVoteResult(&block.PreviousBlockHash)
+ consensusNodeMap, err := c.consensusNodeManager.getConsensusNodesByVoteResult(&block.PreviousBlockHash)
if err != nil {
return 0, err
}
blockHash := block.Hash()
if block.Witness[node.order] == nil {
key := fmt.Sprintf("%s:%s", blockHash.String(), pubKey)
- signature, ok := b.signatureCache.Get(key)
+ signature, ok := c.signatureCache.Get(key)
if ok {
block.Witness[node.order] = signature.([]byte)
}
}
if ed25519.Verify(ed25519.PublicKey(pubKeyBytes[:32]), blockHash.Bytes(), block.Witness[node.order]) {
- isDoubleSign, err := b.checkDoubleSign(node.order, block.Height, block.Hash())
+ isDoubleSign, err := c.checkDoubleSign(node.order, block.Height, block.Hash())
if err != nil {
return 0, err
}
block.Witness[node.order] = nil
} else {
correctSignNum++
- isBlocker, err := b.consensusNodeManager.isBlocker(&block.PreviousBlockHash, pubKey, block.Timestamp)
+ isBlocker, err := c.consensusNodeManager.isBlocker(&block.PreviousBlockHash, pubKey, block.Timestamp)
if err != nil {
return 0, err
}
return correctSignNum, nil
}
-func (b *bbft) checkDoubleSign(nodeOrder, blockHeight uint64, blockHash bc.Hash) (bool, error) {
- blockNodes := b.consensusNodeManager.blockIndex.NodesByHeight(blockHeight)
+func (c *Chain) checkDoubleSign(nodeOrder, blockHeight uint64, blockHash bc.Hash) (bool, error) {
+ blockNodes := c.consensusNodeManager.blockIndex.NodesByHeight(blockHeight)
for _, blockNode := range blockNodes {
if blockNode.Hash == blockHash {
continue
}
if ok, err := blockNode.BlockWitness.Test(uint32(nodeOrder)); err != nil && ok {
- block, err := b.consensusNodeManager.store.GetBlock(&blockHash)
+ block, err := c.consensusNodeManager.store.GetBlock(&blockHash)
if err != nil {
return false, err
}
// reset nil to discard signature
- if err := b.updateBlockSignature(block, nodeOrder, nil); err != nil {
+ if err := c.updateBlockSignature(block, nodeOrder, nil); err != nil {
return false, err
}
}
// SignBlock signing the block if current node is consensus node
-func (b *bbft) SignBlock(block *types.Block) ([]byte, error) {
+func (c *Chain) SignBlock(block *types.Block) ([]byte, error) {
xprv := config.CommonConfig.PrivateKey()
xpub := [64]byte(xprv.XPub())
- node, err := b.consensusNodeManager.getConsensusNode(&block.PreviousBlockHash, hex.EncodeToString(xpub[:]))
+ node, err := c.consensusNodeManager.getConsensusNode(&block.PreviousBlockHash, hex.EncodeToString(xpub[:]))
if err != nil && err != errNotFoundConsensusNode {
return nil, err
}
return nil, nil
}
- blockNodes := b.consensusNodeManager.blockIndex.NodesByHeight(block.Height)
+ blockNodes := c.consensusNodeManager.blockIndex.NodesByHeight(block.Height)
for _, blockNode := range blockNodes {
// Has already signed the same height block
if ok, err := blockNode.BlockWitness.Test(uint32(node.order)); err != nil && ok {
return signature, nil
}
-func (b *bbft) updateBlockSignature(block *types.Block, nodeOrder uint64, signature []byte) error {
+func (c *Chain) updateBlockSignature(block *types.Block, nodeOrder uint64, signature []byte) error {
blockHash := block.Hash()
- blockNode := b.consensusNodeManager.blockIndex.GetNode(&blockHash)
+ blockNode := c.consensusNodeManager.blockIndex.GetNode(&blockHash)
if len(signature) != 0 {
if err := blockNode.BlockWitness.Set(uint32(nodeOrder)); err != nil {
}
block.Witness[nodeOrder] = signature
- txStatus, err := b.consensusNodeManager.store.GetTransactionStatus(&blockHash)
+ txStatus, err := c.consensusNodeManager.store.GetTransactionStatus(&blockHash)
if err != nil {
return err
}
- return b.consensusNodeManager.store.SaveBlock(block, txStatus)
-}
-
-// SetBlockIndex set the block index field
-func (b *bbft) SetBlockIndex(blockIndex *state.BlockIndex) {
- b.consensusNodeManager.blockIndex = blockIndex
+ return c.consensusNodeManager.store.SaveBlock(block, txStatus)
}
import (
log "github.com/sirupsen/logrus"
+ "github.com/vapor/config"
"github.com/vapor/errors"
"github.com/vapor/event"
- "github.com/vapor/config"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
"github.com/vapor/protocol/state"
}
voteResultMap := make(map[uint64]*state.VoteResult)
- if err := c.bbft.ApplyBlock(voteResultMap, block); err != nil {
+ if err := c.ApplyBlock(voteResultMap, block); err != nil {
return err
}
node := c.index.GetNode(&bcBlock.ID)
- if c.bbft.isIrreversible(block) && block.Height > irreversibleNode.Height {
+ if c.isIrreversible(block) && block.Height > irreversibleNode.Height {
irreversibleNode = node
}
return err
}
- if err := c.bbft.DetachBlock(voteResultMap, b); err != nil {
+ if err := c.DetachBlock(voteResultMap, b); err != nil {
return err
}
return err
}
- if err := c.bbft.ApplyBlock(voteResultMap, b); err != nil {
+ if err := c.ApplyBlock(voteResultMap, b); err != nil {
return err
}
- if c.bbft.isIrreversible(b) && b.Height > irreversibleNode.Height {
+ if c.isIrreversible(b) && b.Height > irreversibleNode.Height {
irreversibleNode = attachNode
}
// SaveBlock will validate and save block into storage
func (c *Chain) saveBlock(block *types.Block) error {
- if err := c.bbft.ValidateBlock(block); err != nil {
+ if err := c.ValidateBlock(block); err != nil {
return errors.Sub(ErrBadBlock, err)
}
return errors.Sub(ErrBadBlock, err)
}
- signature, err := c.bbft.SignBlock(block)
+ signature, err := c.SignBlock(block)
if err != nil {
return errors.Sub(ErrBadBlock, err)
}
if len(signature) != 0 {
xPub := config.CommonConfig.PrivateKey().XPub()
- if err := c.bbft.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: block.Hash(), Signature: signature, XPub: xPub}); err != nil {
+ if err := c.eventDispatcher.Post(event.BlockSignatureEvent{BlockHash: block.Hash(), Signature: signature, XPub: xPub}); err != nil {
return err
}
}
}
return false, nil
}
-
-func (c *Chain) ProcessBlockSignature(signature []byte, xPub [64]byte, blockHeight uint64, blockHash *bc.Hash) error {
- isIrreversible, err := c.bbft.ProcessBlockSignature(signature, xPub, blockHeight, blockHash)
- if err != nil {
- return err
- }
-
- if isIrreversible && blockHeight > c.bestIrreversibleNode.Height {
- bestIrreversibleNode := c.index.GetNode(blockHash)
- if err := c.store.SaveChainNodeStatus(c.bestNode, bestIrreversibleNode); err != nil {
- return err
- }
-
- c.bestIrreversibleNode = bestIrreversibleNode
- }
- return nil
-}
import (
"sync"
+ "github.com/golang/groupcache/lru"
log "github.com/sirupsen/logrus"
"github.com/vapor/config"
orphanManage *OrphanManage
txPool *TxPool
store Store
- bbft *bbft
processBlockCh chan *processBlockMsg
+ consensusNodeManager *consensusNodeManager
+ signatureCache *lru.Cache
+ eventDispatcher *event.Dispatcher
+
cond sync.Cond
bestNode *state.BlockNode
bestIrreversibleNode *state.BlockNode
// NewChain returns a new Chain using store as the underlying storage.
func NewChain(store Store, txPool *TxPool, eventDispatcher *event.Dispatcher) (*Chain, error) {
c := &Chain{
- orphanManage: NewOrphanManage(),
- txPool: txPool,
- store: store,
- processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
+ orphanManage: NewOrphanManage(),
+ txPool: txPool,
+ store: store,
+ signatureCache: lru.New(maxSignatureCacheSize),
+ consensusNodeManager: newConsensusNodeManager(store, nil),
+ eventDispatcher: eventDispatcher,
+ processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
}
c.cond.L = new(sync.Mutex)
- c.bbft = newBbft(store, nil, c.orphanManage, eventDispatcher)
storeStatus := store.GetStoreStatus()
if storeStatus == nil {
if err := c.initChainStatus(); err != nil {
c.bestNode = c.index.GetNode(storeStatus.Hash)
c.bestIrreversibleNode = c.index.GetNode(storeStatus.IrreversibleHash)
c.index.SetMainChain(c.bestNode)
- c.bbft.SetBlockIndex(c.index)
+ c.consensusNodeManager.blockIndex = c.index
go c.blockProcesser()
return c, nil
}
}
voteResultMap := make(map[uint64]*state.VoteResult)
- if err := c.bbft.ApplyBlock(voteResultMap, genesisBlock); err != nil {
+ if err := c.ApplyBlock(voteResultMap, genesisBlock); err != nil {
return err
}
func (c *Chain) GetTxPool() *TxPool {
return c.txPool
}
-
-// GetBBFT return chain bbft
-func (c *Chain) GetBBFT() *bbft {
- return c.bbft
-}