OSDN Git Service

fix sign block (#112)
[bytom/vapor.git] / protocol / bbft.go
index 3a59e47..d026e95 100644 (file)
@@ -7,6 +7,7 @@ import (
        "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"
@@ -42,27 +43,23 @@ func newBbft(store Store, blockIndex *state.BlockIndex, orphanManage *OrphanMana
        }
 }
 
-// IsConsensusPubkey determine whether a public key is a consensus node at a specified height
-func (b *bbft) IsConsensusPubkey(blockHash *bc.Hash, pubkey []byte) (bool, error) {
-       node, err := b.consensusNodeManager.getConsensusNode(blockHash, hex.EncodeToString(pubkey))
-       if err != nil && err != errNotFoundConsensusNode {
-               return false, err
+func (b *bbft) isIrreversible(block *types.Block) bool {
+       consensusNodes, err := b.consensusNodeManager.getConsensusNodesByVoteResult(&block.PreviousBlockHash)
+       if err != nil {
+               return false
        }
-       return node != nil, nil
-}
 
-func (b *bbft) isIrreversible(block *types.Block) bool {
        signNum, err := b.validateSign(block)
        if err != nil {
                return false
        }
 
-       return signNum > (numOfConsensusNode * 2 / 3)
+       return signNum > (uint64(len(consensusNodes)) * 2 / 3)
 }
 
 // NextLeaderTime returns the start time of the specified public key as the next leader node
-func (b *bbft) NextLeaderTimeRange(pubkey []byte, bestBlockHash *bc.Hash) (uint64, uint64, error) {
-       return b.consensusNodeManager.nextLeaderTimeRange(pubkey, bestBlockHash)
+func (b *bbft) NextLeaderTimeRange(pubkey []byte, prevBlockHash *bc.Hash) (uint64, uint64, error) {
+       return b.consensusNodeManager.nextLeaderTimeRange(pubkey, prevBlockHash)
 }
 
 func (b *bbft) ApplyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
@@ -74,15 +71,22 @@ func (b *bbft) DetachBlock(voteResultMap map[uint64]*state.VoteResult, block *ty
 }
 
 // ProcessBlockSignature process the received block signature messages
-// return once a block become irreversible, whether it's height greater than best block height
-// if so, the chain module must update status
-func (b *bbft) ProcessBlockSignature(signature, pubkey []byte, blockHeight uint64, blockHash *bc.Hash) (bool, error) {
-       consensusNode, err := b.consensusNodeManager.getConsensusNode(blockHash, hex.EncodeToString(pubkey))
+// 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)
+       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
+       }
+
+       consensusNode, err := b.consensusNodeManager.getConsensusNode(&block.PreviousBlockHash, hex.EncodeToString(xPub[:]))
        if err != nil {
                return false, err
        }
 
-       if !ed25519.Verify(ed25519.PublicKey(pubkey), blockHash.Bytes(), signature) {
+       if chainkd.XPub(xPub).Verify(blockHash.Bytes(), signature) {
                return false, errInvalidSignature
        }
 
@@ -92,7 +96,7 @@ func (b *bbft) ProcessBlockSignature(signature, pubkey []byte, blockHeight uint6
        }
 
        if isDoubleSign {
-               log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "pubkey": pubkey}).Warn("the consensus node double sign the same height of different block")
+               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
        }
 
@@ -102,19 +106,11 @@ func (b *bbft) ProcessBlockSignature(signature, pubkey []byte, blockHeight uint6
                return false, nil
        }
 
-       block, err := b.consensusNodeManager.store.GetBlock(blockHash)
-       if err != nil {
-               // block is not exist, save the signature
-               key := fmt.Sprintf("%s:%s", blockHash.String(), hex.EncodeToString(pubkey))
-               b.signatureCache.Add(key, signature)
-               return false, err
-       }
-
        if err := b.updateBlockSignature(block, consensusNode.order, signature); err != nil {
                return false, err
        }
 
-       return b.isIrreversible(block) && blockHeight > b.consensusNodeManager.blockIndex.BestNode().Height, nil
+       return b.isIrreversible(block), nil
 }
 
 // ValidateBlock verify whether the block is valid
@@ -135,40 +131,44 @@ func (b *bbft) ValidateBlock(block *types.Block) error {
 // if the block has not the signature of blocker, it will return error
 func (b *bbft) validateSign(block *types.Block) (uint64, error) {
        var correctSignNum uint64
-       blockHash := block.Hash()
-       consensusNodeMap, err := b.consensusNodeManager.getConsensusNodesByVoteResult(&blockHash)
+       consensusNodeMap, err := b.consensusNodeManager.getConsensusNodesByVoteResult(&block.PreviousBlockHash)
        if err != nil {
                return 0, err
        }
 
        hasBlockerSign := false
-       for pubkey, node := range consensusNodeMap {
+       for pubKey, node := range consensusNodeMap {
                if len(block.Witness) <= int(node.order) {
                        continue
                }
 
                blockHash := block.Hash()
                if block.Witness[node.order] == nil {
-                       key := fmt.Sprintf("%s:%s", blockHash.String(), pubkey)
+                       key := fmt.Sprintf("%s:%s", blockHash.String(), pubKey)
                        signature, ok := b.signatureCache.Get(key)
                        if ok {
                                block.Witness[node.order] = signature.([]byte)
                        }
                }
 
-               if ed25519.Verify(ed25519.PublicKey(pubkey), blockHash.Bytes(), block.Witness[node.order]) {
+               pubKeyBytes, err := hex.DecodeString(pubKey)
+               if err != nil {
+                       return 0, err
+               }
+
+               if ed25519.Verify(ed25519.PublicKey(pubKeyBytes[:32]), blockHash.Bytes(), block.Witness[node.order]) {
                        isDoubleSign, err := b.checkDoubleSign(node.order, block.Height, block.Hash())
                        if err != nil {
                                return 0, err
                        }
 
                        if isDoubleSign {
-                               log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "pubkey": pubkey}).Warn("the consensus node double sign the same height of different block")
+                               log.WithFields(log.Fields{"module": logModule, "blockHash": blockHash.String(), "pubKey": pubKey}).Warn("the consensus node double sign the same height of different block")
                                // Consensus node is signed twice with the same block height, discard the signature
                                block.Witness[node.order] = nil
                        } else {
                                correctSignNum++
-                               isBlocker, err := b.consensusNodeManager.isBlocker(&blockHash, pubkey)
+                               isBlocker, err := b.consensusNodeManager.isBlocker(block, pubKey)
                                if err != nil {
                                        return 0, err
                                }
@@ -212,10 +212,9 @@ func (b *bbft) checkDoubleSign(nodeOrder, blockHeight uint64, blockHash bc.Hash)
 
 // SignBlock signing the block if current node is consensus node
 func (b *bbft) SignBlock(block *types.Block) ([]byte, error) {
-       var xprv chainkd.XPrv
+       xprv := config.CommonConfig.PrivateKey()
        xpub := [64]byte(xprv.XPub())
-       blockHash := block.Hash()
-       node, err := b.consensusNodeManager.getConsensusNode(&blockHash, hex.EncodeToString(xpub[:]))
+       node, err := b.consensusNodeManager.getConsensusNode(&block.PreviousBlockHash, hex.EncodeToString(xpub[:]))
        if err != nil && err != errNotFoundConsensusNode {
                return nil, err
        }
@@ -224,8 +223,19 @@ func (b *bbft) SignBlock(block *types.Block) ([]byte, error) {
                return nil, nil
        }
 
-       signature := xprv.Sign(block.Hash().Bytes())
-       block.Witness[node.order] = signature
+       blockNodes := b.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 nil, nil
+               }
+       }
+
+       signature := block.Witness[node.order]
+       if len(signature) == 0 {
+               signature = xprv.Sign(block.Hash().Bytes())
+               block.Witness[node.order] = signature
+       }
        return signature, nil
 }
 
@@ -251,3 +261,8 @@ func (b *bbft) updateBlockSignature(block *types.Block, nodeOrder uint64, signat
 
        return b.consensusNodeManager.store.SaveBlock(block, txStatus)
 }
+
+// SetBlockIndex set the block index field
+func (b *bbft) SetBlockIndex(blockIndex *state.BlockIndex) {
+       b.consensusNodeManager.blockIndex = blockIndex
+}