OSDN Git Service

dpos process sign message (#81)
authormuscle_boy <shenao.78@163.com>
Thu, 23 May 2019 01:55:12 +0000 (09:55 +0800)
committerPaladz <yzhu101@uottawa.ca>
Thu, 23 May 2019 01:55:12 +0000 (09:55 +0800)
* dpos process sign message

* opt code

* opt code

protocol/bbft.go
protocol/protocol.go
protocol/state/blockindex.go

index 9315ca8..7496591 100644 (file)
@@ -2,27 +2,42 @@ package protocol
 
 import (
        "encoding/hex"
+       "fmt"
        "time"
 
+       "github.com/golang/groupcache/lru"
+       log "github.com/sirupsen/logrus"
+
        "github.com/vapor/crypto/ed25519"
        "github.com/vapor/crypto/ed25519/chainkd"
        "github.com/vapor/errors"
        "github.com/vapor/math/checked"
+       "github.com/vapor/protocol/bc"
        "github.com/vapor/protocol/bc/types"
        "github.com/vapor/protocol/state"
 )
 
+const (
+       maxSignatureCacheSize = 10000
+)
+
 var (
        errVotingOperationOverFlow = errors.New("voting operation result overflow")
+       errDoubleSignBlock         = errors.New("the consensus is double sign in same height of different block")
+       errInvalidSignature        = errors.New("the signature of block is invalid")
 )
 
 type bbft struct {
        consensusNodeManager *consensusNodeManager
+       orphanManage         *OrphanManage
+       signatureCache       *lru.Cache
 }
 
-func newBbft(store Store, blockIndex *state.BlockIndex) *bbft {
+func newBbft(store Store, blockIndex *state.BlockIndex, orphanManage *OrphanManage) *bbft {
        return &bbft{
+               orphanManage:         orphanManage,
                consensusNodeManager: newConsensusNodeManager(store, blockIndex),
+               signatureCache:       lru.New(maxSignatureCacheSize),
        }
 }
 
@@ -81,7 +96,7 @@ func (b *bbft) ApplyBlock(voteResultMap map[uint64]*state.VoteResult, block *typ
                        if !ok {
                                continue
                        }
-                       
+
                        pubkey := hex.EncodeToString(unVoteInput.Vote)
                        voteResult.NumOfVote[pubkey], ok = checked.SubUint64(voteResult.NumOfVote[pubkey], unVoteInput.Amount)
                        if !ok {
@@ -130,7 +145,7 @@ func (b *bbft) DetachBlock(voteResultMap map[uint64]*state.VoteResult, block *ty
                        if !ok {
                                continue
                        }
-                       
+
                        pubkey := hex.EncodeToString(unVoteInput.Vote)
                        voteResult.NumOfVote[pubkey], ok = checked.AddUint64(voteResult.NumOfVote[pubkey], unVoteInput.Amount)
                        if !ok {
@@ -142,7 +157,7 @@ func (b *bbft) DetachBlock(voteResultMap map[uint64]*state.VoteResult, block *ty
                        if !ok {
                                continue
                        }
-                       
+
                        pubkey := hex.EncodeToString(voteOutput.Vote)
                        voteResult.NumOfVote[pubkey], ok = checked.SubUint64(voteResult.NumOfVote[pubkey], voteOutput.Amount)
                        if !ok {
@@ -156,6 +171,50 @@ func (b *bbft) DetachBlock(voteResultMap map[uint64]*state.VoteResult, block *ty
        return nil
 }
 
+// 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(blockHeight, hex.EncodeToString(pubkey))
+       if err != nil {
+               return false, err
+       }
+
+       if !ed25519.Verify(ed25519.PublicKey(pubkey), blockHash.Bytes(), signature) {
+               return false, errInvalidSignature
+       }
+
+       isDoubleSign, err := b.checkDoubleSign(consensusNode.order, blockHeight, *blockHash)
+       if err != nil {
+               return false, 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")
+               return false, errDoubleSignBlock
+       }
+
+       orphanBlock, ok := b.orphanManage.Get(blockHash)
+       if ok {
+               orphanBlock.Witness[consensusNode.order] = signature
+               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
+}
+
 // ValidateBlock verify whether the block is valid
 func (b *bbft) ValidateBlock(block *types.Block) error {
        signNum, err := b.validateSign(block)
@@ -185,26 +244,34 @@ func (b *bbft) validateSign(block *types.Block) (uint64, error) {
                        continue
                }
 
-               blocks := b.consensusNodeManager.blockIndex.NodesByHeight(block.Height)
-               for _, b := range blocks {
-                       if b.Hash == block.Hash() {
-                               continue
-                       }
-                       if ok, err := b.BlockWitness.Test(uint32(node.order)); err != nil && ok {
-                               // Consensus node is signed twice with the same block height, discard the signature
-                               block.Witness[node.order] = nil
-                               break
+               blockHash := block.Hash()
+               if block.Witness[node.order] == nil {
+                       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), block.Hash().Bytes(), block.Witness[node.order]) {
-                       correctSignNum++
-                       isBlocker, err := b.consensusNodeManager.isBlocker(block.Height, block.Timestamp, pubkey)
+               if ed25519.Verify(ed25519.PublicKey(pubkey), blockHash.Bytes(), block.Witness[node.order]) {
+                       isDoubleSign, err := b.checkDoubleSign(node.order, block.Height, block.Hash())
                        if err != nil {
                                return 0, err
                        }
-                       if isBlocker {
-                               hasBlockerSign = true
+
+                       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")
+                               // 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(block.Height, block.Timestamp, pubkey)
+                               if err != nil {
+                                       return 0, err
+                               }
+                               if isBlocker {
+                                       hasBlockerSign = true
+                               }
                        }
                } else {
                        // discard the invalid signature
@@ -217,6 +284,27 @@ func (b *bbft) validateSign(block *types.Block) (uint64, error) {
        return correctSignNum, nil
 }
 
+func (b *bbft) checkDoubleSign(nodeOrder, blockHeight uint64, blockHash bc.Hash) (bool, error) {
+       blockNodes := b.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)
+                       if err != nil {
+                               return false, err
+                       }
+
+                       // reset nil to discard signature
+                       if err := b.updateBlockSignature(block, nodeOrder, nil); err != nil {
+                               return false, err
+                       }
+               }
+       }
+       return false, nil
+}
+
 // SignBlock signing the block if current node is consensus node
 func (b *bbft) SignBlock(block *types.Block) error {
        var xprv chainkd.XPrv
@@ -238,3 +326,26 @@ func (b *bbft) SignBlock(block *types.Block) error {
 func (b *bbft) UpdateConsensusNodes(blockHeight uint64) error {
        return b.consensusNodeManager.updateConsensusNodes(blockHeight)
 }
+
+func (b *bbft) updateBlockSignature(block *types.Block, nodeOrder uint64, signature []byte) error {
+       blockHash := block.Hash()
+       blockNode := b.consensusNodeManager.blockIndex.GetNode(&blockHash)
+
+       if len(signature) != 0 {
+               if err := blockNode.BlockWitness.Set(uint32(nodeOrder)); err != nil {
+                       return err
+               }
+       } else {
+               if err := blockNode.BlockWitness.Clean(uint32(nodeOrder)); err != nil {
+                       return err
+               }
+       }
+
+       block.Witness[nodeOrder] = signature
+       txStatus, err := b.consensusNodeManager.store.GetTransactionStatus(&blockHash)
+       if err != nil {
+               return err
+       }
+
+       return b.consensusNodeManager.store.SaveBlock(block, txStatus)
+}
index 3908c72..2ad9d6e 100644 (file)
@@ -52,7 +52,7 @@ func NewChain(store Store, txPool *TxPool) (*Chain, error) {
 
        c.bestNode = c.index.GetNode(storeStatus.Hash)
        c.index.SetMainChain(c.bestNode)
-       c.bbft = newBbft(store, c.index)
+       c.bbft = newBbft(store, c.index, c.orphanManage)
        go c.blockProcesser()
        return c, nil
 }
index 61b1164..f1810b6 100644 (file)
@@ -47,7 +47,9 @@ func NewBlockNode(bh *types.BlockHeader, parent *BlockNode) (*BlockNode, error)
        node.BlockWitness = common.NewBitMap(uint32(len(bh.Witness)))
        for i, witness := range bh.Witness {
                if len(witness) != 0 {
-                       node.BlockWitness.Set(uint32(i))
+                       if err := node.BlockWitness.Set(uint32(i)); err != nil {
+                               return nil, err
+                       }
                }
        }
        return node, nil