OSDN Git Service

edit the consensus node
authorpaladz <453256728@qq.com>
Tue, 4 Jun 2019 19:00:20 +0000 (03:00 +0800)
committerpaladz <453256728@qq.com>
Tue, 4 Jun 2019 19:00:20 +0000 (03:00 +0800)
database/store.go
database/store_test.go
protocol/bbft.go
protocol/block.go
protocol/consensus_node_manager.go
protocol/protocol.go
protocol/state/vote_result.go
protocol/store.go
protocol/txpool_test.go
test/utxo_view/utxo_view_test.go

index 7db4a92..4a61726 100644 (file)
@@ -224,13 +224,13 @@ func (s *Store) SaveBlock(block *types.Block, ts *bc.TransactionStatus) error {
 }
 
 // SaveChainStatus save the core's newest status && delete old status
-func (s *Store) SaveChainStatus(node, irreversibleNode *state.BlockNode, view *state.UtxoViewpoint, voteMap map[uint64]*state.VoteResult) error {
+func (s *Store) SaveChainStatus(node, irreversibleNode *state.BlockNode, view *state.UtxoViewpoint, voteResults []*state.VoteResult) error {
        batch := s.db.NewBatch()
        if err := saveUtxoView(batch, view); err != nil {
                return err
        }
 
-       if err := saveVoteResult(batch, voteMap); err != nil {
+       if err := saveVoteResult(batch, voteResults); err != nil {
                return err
        }
 
@@ -266,8 +266,8 @@ func (s *Store) SaveChainNodeStatus(bestNode, irreversibleNode *state.BlockNode)
 }
 
 // saveVoteResult update the voting results generated by each irreversible block
-func saveVoteResult(batch dbm.Batch, voteMap map[uint64]*state.VoteResult) error {
-       for _, vote := range voteMap {
+func saveVoteResult(batch dbm.Batch, voteResults []*state.VoteResult) error {
+       for _, vote := range voteResults {
                bytes, err := json.Marshal(vote)
                if err != nil {
                        return err
index 45ff016..68f62c3 100644 (file)
@@ -174,7 +174,7 @@ func TestSaveChainStatus(t *testing.T) {
                },
        }
 
-       if err := store.SaveChainStatus(node, node, view, map[uint64]*state.VoteResult{}); err != nil {
+       if err := store.SaveChainStatus(node, node, view, []*state.VoteResult{}); err != nil {
                t.Fatal(err)
        }
 
index 5667bc6..40b2730 100644 (file)
@@ -28,7 +28,7 @@ func signCacheKey(blockHash, pubkey string) string {
 }
 
 func (c *Chain) isIrreversible(blockNode *state.BlockNode) bool {
-       consensusNodes, err := c.consensusNodeManager.getConsensusNodesByVoteResult(&blockNode.Parent.Hash)
+       consensusNodes, err := c.consensusNodeManager.getConsensusNodes(&blockNode.Parent.Hash)
        if err != nil {
                return false
        }
@@ -97,7 +97,7 @@ func (c *Chain) ProcessBlockSignature(signature []byte, xPub [64]byte, blockHash
 // 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 (c *Chain) validateSign(block *types.Block) (uint64, error) {
-       consensusNodeMap, err := c.consensusNodeManager.getConsensusNodesByVoteResult(&block.PreviousBlockHash)
+       consensusNodeMap, err := c.consensusNodeManager.getConsensusNodes(&block.PreviousBlockHash)
        if err != nil {
                return 0, err
        }
index e3f0f83..45a5f2b 100644 (file)
@@ -90,8 +90,11 @@ func (c *Chain) connectBlock(block *types.Block) (err error) {
                return err
        }
 
-       voteResultMap := make(map[uint64]*state.VoteResult)
-       if err := c.consensusNodeManager.applyBlock(voteResultMap, block); err != nil {
+       voteResult, err := c.consensusNodeManager.getBestVoteResult()
+       if err != nil {
+               return err
+       }
+       if err := voteResult.ApplyBlock(block); err != nil {
                return err
        }
 
@@ -100,7 +103,7 @@ func (c *Chain) connectBlock(block *types.Block) (err error) {
                irreversibleNode = node
        }
 
-       if err := c.setState(node, irreversibleNode, utxoView, voteResultMap); err != nil {
+       if err := c.setState(node, irreversibleNode, utxoView, []*state.VoteResult{voteResult}); err != nil {
                return err
        }
 
@@ -113,8 +116,12 @@ func (c *Chain) connectBlock(block *types.Block) (err error) {
 func (c *Chain) reorganizeChain(node *state.BlockNode) error {
        attachNodes, detachNodes := c.calcReorganizeNodes(node)
        utxoView := state.NewUtxoViewpoint()
-       voteResultMap := make(map[uint64]*state.VoteResult)
+       voteResults := []*state.VoteResult{}
        irreversibleNode := c.bestIrreversibleNode
+       voteResult, err := c.consensusNodeManager.getBestVoteResult()
+       if err != nil {
+               return err
+       }
 
        for _, detachNode := range detachNodes {
                b, err := c.store.GetBlock(&detachNode.Hash)
@@ -140,7 +147,7 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error {
                        return err
                }
 
-               if err := c.consensusNodeManager.detachBlock(voteResultMap, b); err != nil {
+               if err := voteResult.DetachBlock(b); err != nil {
                        return err
                }
 
@@ -167,10 +174,14 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error {
                        return err
                }
 
-               if err := c.consensusNodeManager.applyBlock(voteResultMap, b); err != nil {
+               if err := voteResult.ApplyBlock(b); err != nil {
                        return err
                }
 
+               if voteResult.IsFinalize() {
+                       voteResults = append(voteResults, voteResult.Fork())
+               }
+
                if c.isIrreversible(attachNode) && b.Height > irreversibleNode.Height {
                        irreversibleNode = attachNode
                }
@@ -178,7 +189,8 @@ func (c *Chain) reorganizeChain(node *state.BlockNode) error {
                log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
        }
 
-       return c.setState(node, irreversibleNode, utxoView, voteResultMap)
+       voteResults = append(voteResults, voteResult.Fork())
+       return c.setState(node, irreversibleNode, utxoView, voteResults)
 }
 
 // SaveBlock will validate and save block into storage
index 1ea00c6..dd98cff 100644 (file)
@@ -5,7 +5,6 @@ import (
        "github.com/vapor/consensus"
        "github.com/vapor/errors"
        "github.com/vapor/protocol/bc"
-       "github.com/vapor/protocol/bc/types"
        "github.com/vapor/protocol/state"
 )
 
@@ -27,7 +26,7 @@ func newConsensusNodeManager(store Store, blockIndex *state.BlockIndex) *consens
 }
 
 func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey string) (*state.ConsensusNode, error) {
-       consensusNodeMap, err := c.getConsensusNodesByVoteResult(prevBlockHash)
+       consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
        if err != nil {
                return nil, err
        }
@@ -40,7 +39,7 @@ func (c *consensusNodeManager) getConsensusNode(prevBlockHash *bc.Hash, pubkey s
 }
 
 func (c *consensusNodeManager) isBlocker(prevBlockHash *bc.Hash, pubKey string, timeStamp uint64) (bool, error) {
-       consensusNodeMap, err := c.getConsensusNodesByVoteResult(prevBlockHash)
+       consensusNodeMap, err := c.getConsensusNodes(prevBlockHash)
        if err != nil {
                return false, err
        }
@@ -50,27 +49,27 @@ func (c *consensusNodeManager) isBlocker(prevBlockHash *bc.Hash, pubKey string,
                return false, nil
        }
 
-       prevVoteRoundLastBlock, err := c.getPrevRoundVoteLastBlock(prevBlockHash)
+       prevVoteRoundLastBlock, err := c.getPrevRoundLastBlock(prevBlockHash)
        if err != nil {
                return false, err
        }
 
        startTimestamp := prevVoteRoundLastBlock.Timestamp + consensus.BlockTimeInterval
-       begin := getLastBlockTimeInTimeRange(startTimestamp, timeStamp, consensusNode.Order, len(consensusNodeMap))
+       begin := getLastBlockTimeInTimeRange(startTimestamp, timeStamp, consensusNode.Order, uint64(len(consensusNodeMap)))
        end := begin + consensus.BlockNumEachNode*consensus.BlockTimeInterval
        return timeStamp >= begin && timeStamp < end, nil
 }
 
-func getLastBlockTimeInTimeRange(startTimestamp, endTimestamp, order uint64, numOfConsensusNode int) uint64 {
+func getLastBlockTimeInTimeRange(startTimestamp, endTimestamp, order, numOfConsensusNode uint64) uint64 {
        // One round of product block time for all consensus nodes
-       roundBlockTime := uint64(consensus.BlockNumEachNode * numOfConsensusNode * consensus.BlockTimeInterval)
+       roundBlockTime := consensus.BlockNumEachNode * numOfConsensusNode * consensus.BlockTimeInterval
        // The start time of the last round of product block
        lastRoundStartTime := startTimestamp + (endTimestamp-startTimestamp)/roundBlockTime*roundBlockTime
        // The time of product block of the consensus in last round
        return lastRoundStartTime + order*(consensus.BlockNumEachNode*consensus.BlockTimeInterval)
 }
 
-func (c *consensusNodeManager) getPrevRoundVoteLastBlock(prevBlockHash *bc.Hash) (*state.BlockNode, error) {
+func (c *consensusNodeManager) getPrevRoundLastBlock(prevBlockHash *bc.Hash) (*state.BlockNode, error) {
        node := c.blockIndex.GetNode(prevBlockHash)
        if node == nil {
                return nil, errNotFoundBlockNode
@@ -82,7 +81,7 @@ func (c *consensusNodeManager) getPrevRoundVoteLastBlock(prevBlockHash *bc.Hash)
        return node, nil
 }
 
-func (c *consensusNodeManager) getConsensusNodesByVoteResult(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) {
+func (c *consensusNodeManager) getConsensusNodes(prevBlockHash *bc.Hash) (map[string]*state.ConsensusNode, error) {
        prevBlockNode := c.blockIndex.GetNode(prevBlockHash)
        if prevBlockNode == nil {
                return nil, errNotFoundBlockNode
@@ -93,13 +92,13 @@ func (c *consensusNodeManager) getConsensusNodesByVoteResult(prevBlockHash *bc.H
                seqHeight = bestHeight
        }
 
-       seq := seqHeight / consensus.RoundVoteBlockNums
-       voteResult, err := c.store.GetVoteResult(seq)
+       preSeq := (seqHeight - 1) / consensus.RoundVoteBlockNums
+       voteResult, err := c.store.GetVoteResult(preSeq)
        if err != nil {
                return nil, err
        }
 
-       lastBlockNode, err := c.getPrevRoundVoteLastBlock(prevBlockHash)
+       lastBlockNode, err := c.getPrevRoundLastBlock(prevBlockHash)
        if err != nil {
                return nil, err
        }
@@ -109,22 +108,36 @@ func (c *consensusNodeManager) getConsensusNodesByVoteResult(prevBlockHash *bc.H
        }
 
        if len(voteResult.NumOfVote) == 0 {
-               return initConsensusNodes(), nil
+               return federationNodes(), nil
        }
        return voteResult.ConsensusNodes()
 }
 
-func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, forkChainNode *state.BlockNode) error {
-       mainChainNode := c.blockIndex.GetNode(&voteResult.LastBlockHash)
+func (c *consensusNodeManager) getBestVoteResult() (*state.VoteResult, error) {
+       blockNode := c.blockIndex.BestNode()
+       seq := (blockNode.Height-1)/consensus.RoundVoteBlockNums + 1
+       voteResult, err := c.store.GetVoteResult(seq)
+       if err != nil {
+               return nil, err
+       }
+
+       if err := c.reorganizeVoteResult(voteResult, blockNode); err != nil {
+               return nil, err
+       }
+
+       return voteResult, nil
+}
+
+func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult, node *state.BlockNode) error {
+       mainChainNode := c.blockIndex.GetNode(&voteResult.BlockHash)
        var attachNodes []*state.BlockNode
        var detachNodes []*state.BlockNode
-       for mainChainNode != forkChainNode {
+       for forkChainNode := node; mainChainNode != forkChainNode; node = node.Parent {
                if forkChainNode.Height == mainChainNode.Height {
                        detachNodes = append(detachNodes, mainChainNode)
                        mainChainNode = mainChainNode.Parent
                }
                attachNodes = append([]*state.BlockNode{forkChainNode}, attachNodes...)
-               forkChainNode = forkChainNode.Parent
        }
 
        for _, node := range detachNodes {
@@ -151,81 +164,7 @@ func (c *consensusNodeManager) reorganizeVoteResult(voteResult *state.VoteResult
        return nil
 }
 
-func (c *consensusNodeManager) applyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
-       voteResult, err := c.getVoteResult(voteResultMap, block.Height)
-       if err != nil {
-               return err
-       }
-
-       return voteResult.ApplyBlock(block)
-}
-
-func (c *consensusNodeManager) getVoteResult(voteResultMap map[uint64]*state.VoteResult, blockHeight uint64) (*state.VoteResult, error) {
-       var err error
-       // This round of voting prepares for the next round
-       seq := blockHeight/consensus.RoundVoteBlockNums + 1
-       voteResult := voteResultMap[seq]
-       if blockHeight == 0 {
-               voteResult = &state.VoteResult{
-                       Seq:       seq,
-                       NumOfVote: make(map[string]uint64),
-               }
-       }
-
-       if voteResult == nil {
-               prevVoteResult := voteResultMap[seq-1]
-               if prevVoteResult != nil {
-                       voteResult = &state.VoteResult{
-                               Seq:       seq,
-                               NumOfVote: prevVoteResult.NumOfVote,
-                       }
-               }
-       }
-
-       if voteResult == nil {
-               voteResult, err = c.store.GetVoteResult(seq)
-               if err != nil && err != ErrNotFoundVoteResult {
-                       return nil, err
-               }
-       }
-
-       if voteResult == nil {
-               voteResult, err = c.store.GetVoteResult(seq - 1)
-               if err != nil && err != ErrNotFoundVoteResult {
-                       return nil, err
-               }
-
-               if voteResult != nil {
-                       voteResult.Seq = seq
-                       voteResult.LastBlockHash = bc.Hash{}
-               }
-       }
-
-       if voteResult == nil {
-               return nil, errors.New("fail to get vote result")
-       }
-
-       voteResultMap[seq] = voteResult
-       return voteResult, nil
-}
-
-func (c *consensusNodeManager) detachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
-       voteSeq := block.Height / consensus.RoundVoteBlockNums
-       voteResult := voteResultMap[voteSeq]
-
-       if voteResult == nil {
-               voteResult, err := c.store.GetVoteResult(voteSeq)
-               if err != nil {
-                       return err
-               }
-               voteResultMap[voteSeq] = voteResult
-       }
-
-       voteResult.DetachBlock(block)
-       return nil
-}
-
-func initConsensusNodes() map[string]*state.ConsensusNode {
+func federationNodes() map[string]*state.ConsensusNode {
        voteResult := map[string]*state.ConsensusNode{}
        for i, xpub := range config.CommonConfig.Federation.Xpubs {
                voteResult[xpub.String()] = &state.ConsensusNode{XPub: xpub, VoteNum: 0, Order: uint64(i)}
index b893e8a..1079588 100644 (file)
@@ -85,17 +85,18 @@ func (c *Chain) initChainStatus() error {
                return err
        }
 
-       voteResultMap := make(map[uint64]*state.VoteResult)
-       if err := c.consensusNodeManager.applyBlock(voteResultMap, genesisBlock); err != nil {
-               return err
-       }
-
+       voteResults := []*state.VoteResult{&state.VoteResult{
+               Seq:         0,
+               NumOfVote:   map[string]uint64{},
+               BlockHash:   genesisBlock.Hash(),
+               BlockHeight: 0,
+       }}
        node, err := state.NewBlockNode(&genesisBlock.BlockHeader, nil)
        if err != nil {
                return err
        }
 
-       return c.store.SaveChainStatus(node, node, utxoView, voteResultMap)
+       return c.store.SaveChainStatus(node, node, utxoView, voteResults)
 }
 
 // BestBlockHeight returns the current height of the blockchain.
@@ -124,8 +125,8 @@ func (c *Chain) InMainChain(hash bc.Hash) bool {
 }
 
 // This function must be called with mu lock in above level
-func (c *Chain) setState(node *state.BlockNode, irreversibleNode *state.BlockNode, view *state.UtxoViewpoint, voteMap map[uint64]*state.VoteResult) error {
-       if err := c.store.SaveChainStatus(node, irreversibleNode, view, voteMap); err != nil {
+func (c *Chain) setState(node *state.BlockNode, irreversibleNode *state.BlockNode, view *state.UtxoViewpoint, voteResults []*state.VoteResult) error {
+       if err := c.store.SaveChainStatus(node, irreversibleNode, view, voteResults); err != nil {
                return err
        }
 
index acbd58f..1944fd7 100644 (file)
@@ -28,18 +28,24 @@ func (c byVote) Less(i, j int) bool {
 }
 func (c byVote) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
 
+// seq 0 is the genesis block
+// seq 1 is the the block height 1, to block height RoundVoteBlockNums
+// seq 2 is the block height RoundVoteBlockNums + 1 to block height 2 * RoundVoteBlockNums
+// consensus node of the current round is the final result of previous round
+
 // VoteResult represents a snapshot of each round of DPOS voting
 // Seq indicates the sequence of current votes, which start from zero
 // NumOfVote indicates the number of votes each consensus node receives, the key of map represent public key
 // Finalized indicates whether this vote is finalized
 type VoteResult struct {
-       Seq           uint64
-       NumOfVote     map[string]uint64
-       LastBlockHash bc.Hash
+       Seq         uint64
+       NumOfVote   map[string]uint64
+       BlockHash   bc.Hash
+       BlockHeight uint64
 }
 
 func (v *VoteResult) ApplyBlock(block *types.Block) error {
-       if v.LastBlockHash != block.PreviousBlockHash {
+       if v.BlockHash != block.PreviousBlockHash {
                return errors.New("block parent hash is not equals last block hash of vote result")
        }
 
@@ -74,7 +80,9 @@ func (v *VoteResult) ApplyBlock(block *types.Block) error {
                }
        }
 
-       v.LastBlockHash = block.Hash()
+       v.BlockHash = block.Hash()
+       v.BlockHeight = block.Height
+       v.Seq = (block.Height-1)/consensus.RoundVoteBlockNums + 1
        return nil
 }
 
@@ -102,7 +110,7 @@ func (v *VoteResult) ConsensusNodes() (map[string]*ConsensusNode, error) {
 }
 
 func (v *VoteResult) DetachBlock(block *types.Block) error {
-       if v.LastBlockHash != block.Hash() {
+       if v.BlockHash != block.Hash() {
                return errors.New("block hash is not equals last block hash of vote result")
        }
 
@@ -137,6 +145,26 @@ func (v *VoteResult) DetachBlock(block *types.Block) error {
                }
        }
 
-       v.LastBlockHash = block.PreviousBlockHash
+       v.BlockHash = block.PreviousBlockHash
+       v.BlockHeight = block.Height - 1
+       v.Seq = (block.Height-2)/consensus.RoundVoteBlockNums + 1
        return nil
 }
+
+func (v *VoteResult) Fork() *VoteResult {
+       f := &VoteResult{
+               Seq:         v.Seq,
+               NumOfVote:   map[string]uint64{},
+               BlockHash:   v.BlockHash,
+               BlockHeight: v.BlockHeight,
+       }
+
+       for key, value := range v.NumOfVote {
+               f.NumOfVote[key] = value
+       }
+       return f
+}
+
+func (v *VoteResult) IsFinalize() bool {
+       return v.BlockHeight%consensus.RoundVoteBlockNums == 0
+}
index 48ac4e8..d2d1126 100644 (file)
@@ -26,7 +26,7 @@ type Store interface {
 
        LoadBlockIndex(uint64) (*state.BlockIndex, error)
        SaveBlock(*types.Block, *bc.TransactionStatus) error
-       SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error
+       SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, []*state.VoteResult) error
        SaveChainNodeStatus(*state.BlockNode, *state.BlockNode) error
 }
 
index c389133..38200c3 100644 (file)
@@ -120,7 +120,7 @@ func (s *mockStore) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)
 func (s *mockStore) GetVoteResult(uint64) (*state.VoteResult, error)              { return nil, nil }
 func (s *mockStore) LoadBlockIndex(uint64) (*state.BlockIndex, error)             { return nil, nil }
 func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error          { return nil }
-func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error {
+func (s *mockStore) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, []*state.VoteResult) error {
        return nil
 }
 func (s *mockStore) SaveChainNodeStatus(*state.BlockNode, *state.BlockNode) error { return nil }
@@ -669,7 +669,7 @@ func (s *mockStore1) GetUtxo(*bc.Hash) (*storage.UtxoEntry, error)        { retu
 func (s *mockStore1) GetVoteResult(uint64) (*state.VoteResult, error)     { return nil, nil }
 func (s *mockStore1) LoadBlockIndex(uint64) (*state.BlockIndex, error)    { return nil, nil }
 func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
-func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, map[uint64]*state.VoteResult) error {
+func (s *mockStore1) SaveChainStatus(*state.BlockNode, *state.BlockNode, *state.UtxoViewpoint, []*state.VoteResult) error {
        return nil
 }
 func (s *mockStore1) SaveChainNodeStatus(*state.BlockNode, *state.BlockNode) error { return nil }
index ac7cfff..bddeb54 100644 (file)
@@ -414,7 +414,7 @@ func TestAttachOrDetachBlocks(t *testing.T) {
                for k, v := range c.before {
                        utxoViewpoint.Entries[k] = v
                }
-               if err := store.SaveChainStatus(node, node, utxoViewpoint, map[uint64]*state.VoteResult{}); err != nil {
+               if err := store.SaveChainStatus(node, node, utxoViewpoint, []*state.VoteResult{}); err != nil {
                        t.Error(err)
                }
 
@@ -436,7 +436,7 @@ func TestAttachOrDetachBlocks(t *testing.T) {
                                t.Error(err)
                        }
                }
-               if err := store.SaveChainStatus(node, node, utxoViewpoint, map[uint64]*state.VoteResult{}); err != nil {
+               if err := store.SaveChainStatus(node, node, utxoViewpoint, []*state.VoteResult{}); err != nil {
                        t.Error(err)
                }