7 "github.com/vapor/crypto/ed25519"
8 "github.com/vapor/crypto/ed25519/chainkd"
9 "github.com/vapor/errors"
10 "github.com/vapor/math/checked"
11 "github.com/vapor/protocol/bc/types"
12 "github.com/vapor/protocol/state"
16 errVotingOperationOverFlow = errors.New("voting operation result overflow")
20 consensusNodeManager *consensusNodeManager
23 func newBbft(store Store, blockIndex *state.BlockIndex) *bbft {
25 consensusNodeManager: newConsensusNodeManager(store, blockIndex),
29 // IsConsensusPubkey determine whether a public key is a consensus node at a specified height
30 func (b *bbft) IsConsensusPubkey(height uint64, pubkey []byte) (bool, error) {
31 node, err := b.consensusNodeManager.getConsensusNode(height, hex.EncodeToString(pubkey))
32 if err != nil && err != errNotFoundConsensusNode {
35 return node != nil, nil
38 func (b *bbft) isIrreversible(block *types.Block) bool {
39 signNum, err := b.validateSign(block)
44 return signNum > (numOfConsensusNode * 2 / 3)
47 // NextLeaderTime returns the start time of the specified public key as the next leader node
48 func (b *bbft) NextLeaderTime(pubkey []byte, bestBlockTimestamp, bestBlockHeight uint64) (*time.Time, error) {
49 return b.consensusNodeManager.nextLeaderTime(pubkey, bestBlockTimestamp, bestBlockHeight)
52 func (b *bbft) ApplyBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) (err error) {
53 voteSeq := block.Height / roundVoteBlockNums
54 voteResult := voteResultMap[voteSeq]
56 if voteResult == nil {
57 store := b.consensusNodeManager.store
58 voteResult, err = store.GetVoteResult(voteSeq)
59 if err != nil && err != ErrNotFoundVoteResult {
64 if voteResult == nil {
65 voteResult = &state.VoteResult{
67 NumOfVote: make(map[string]uint64),
68 LastBlockHeight: block.Height,
72 voteResultMap[voteSeq] = voteResult
74 if voteResult.LastBlockHeight+1 != block.Height {
75 return errors.New("bbft append block error, the block height is not equals last block height plus 1 of vote result")
78 for _, tx := range block.Transactions {
79 for _, input := range tx.Inputs {
80 unVoteInput, ok := input.TypedInput.(*types.UnvoteInput)
85 pubkey := hex.EncodeToString(unVoteInput.Vote)
86 voteResult.NumOfVote[pubkey], ok = checked.SubUint64(voteResult.NumOfVote[pubkey], unVoteInput.Amount)
88 return errVotingOperationOverFlow
91 for _, output := range tx.Outputs {
92 voteOutput, ok := output.TypedOutput.(*types.VoteTxOutput)
97 pubkey := hex.EncodeToString(voteOutput.Vote)
98 voteResult.NumOfVote[pubkey], ok = checked.AddUint64(voteResult.NumOfVote[pubkey], voteOutput.Amount)
100 return errVotingOperationOverFlow
105 voteResult.LastBlockHeight++
106 voteResult.Finalized = (block.Height+1)%roundVoteBlockNums == 0
110 func (b *bbft) DetachBlock(voteResultMap map[uint64]*state.VoteResult, block *types.Block) error {
111 voteSeq := block.Height / roundVoteBlockNums
112 voteResult := voteResultMap[voteSeq]
114 if voteResult == nil {
115 store := b.consensusNodeManager.store
116 voteResult, err := store.GetVoteResult(voteSeq)
120 voteResultMap[voteSeq] = voteResult
123 if voteResult.LastBlockHeight != block.Height {
124 return errors.New("bbft detach block error, the block height is not equals last block height of vote result")
127 for _, tx := range block.Transactions {
128 for _, input := range tx.Inputs {
129 unVoteInput, ok := input.TypedInput.(*types.UnvoteInput)
134 pubkey := hex.EncodeToString(unVoteInput.Vote)
135 voteResult.NumOfVote[pubkey], ok = checked.AddUint64(voteResult.NumOfVote[pubkey], unVoteInput.Amount)
137 return errVotingOperationOverFlow
140 for _, output := range tx.Outputs {
141 voteOutput, ok := output.TypedOutput.(*types.VoteTxOutput)
146 pubkey := hex.EncodeToString(voteOutput.Vote)
147 voteResult.NumOfVote[pubkey], ok = checked.SubUint64(voteResult.NumOfVote[pubkey], voteOutput.Amount)
149 return errVotingOperationOverFlow
154 voteResult.LastBlockHeight--
155 voteResult.Finalized = false
159 // ValidateBlock verify whether the block is valid
160 func (b *bbft) ValidateBlock(block *types.Block) error {
161 signNum, err := b.validateSign(block)
167 return errors.New("no valid signature")
172 // validateSign verify the signatures of block, and return the number of correct signature
173 // if some signature is invalid, they will be reset to nil
174 // if the block has not the signature of blocker, it will return error
175 func (b *bbft) validateSign(block *types.Block) (uint64, error) {
176 var correctSignNum uint64
177 consensusNodeMap, err := b.consensusNodeManager.getConsensusNodesByVoteResult(block.Height)
182 hasBlockerSign := false
183 for pubkey, node := range consensusNodeMap {
184 if len(block.Witness) <= int(node.order) {
188 blocks := b.consensusNodeManager.blockIndex.NodesByHeight(block.Height)
189 for _, b := range blocks {
190 if b.Hash == block.Hash() {
193 if ok, err := b.BlockWitness.Test(uint32(node.order)); err != nil && ok {
194 // Consensus node is signed twice with the same block height, discard the signature
195 block.Witness[node.order] = nil
200 if ed25519.Verify(ed25519.PublicKey(pubkey), block.Hash().Bytes(), block.Witness[node.order]) {
202 isBlocker, err := b.consensusNodeManager.isBlocker(block.Height, block.Timestamp, pubkey)
207 hasBlockerSign = true
210 // discard the invalid signature
211 block.Witness[node.order] = nil
215 return 0, errors.New("the block has no signature of the blocker")
217 return correctSignNum, nil
220 // SignBlock signing the block if current node is consensus node
221 func (b *bbft) SignBlock(block *types.Block) error {
222 var xprv chainkd.XPrv
223 xpub := [64]byte(xprv.XPub())
224 node, err := b.consensusNodeManager.getConsensusNode(block.Height, hex.EncodeToString(xpub[:]))
225 if err != nil && err != errNotFoundConsensusNode {
233 block.Witness[node.order] = xprv.Sign(block.Hash().Bytes())
237 // UpdateConsensusNodes used to update consensus node after each round of voting
238 func (b *bbft) UpdateConsensusNodes(blockHeight uint64) error {
239 return b.consensusNodeManager.updateConsensusNodes(blockHeight)