From: muscle_boy Date: Thu, 23 May 2019 01:55:12 +0000 (+0800) Subject: dpos process sign message (#81) X-Git-Tag: v1.0.5~208^2~105 X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=commitdiff_plain;h=d5fbf5bf9d26847b1e884c76337077f32db86b7f dpos process sign message (#81) * dpos process sign message * opt code * opt code --- diff --git a/protocol/bbft.go b/protocol/bbft.go index 9315ca89..74965919 100644 --- a/protocol/bbft.go +++ b/protocol/bbft.go @@ -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) +} diff --git a/protocol/protocol.go b/protocol/protocol.go index 3908c72a..2ad9d6e4 100644 --- a/protocol/protocol.go +++ b/protocol/protocol.go @@ -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 } diff --git a/protocol/state/blockindex.go b/protocol/state/blockindex.go index 61b11646..f1810b6f 100644 --- a/protocol/state/blockindex.go +++ b/protocol/state/blockindex.go @@ -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