Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 84 additions & 8 deletions consensus/cbft/cbft.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ import (
"crypto/elliptic"
"encoding/json"
"fmt"
"github.com/PlatONnetwork/PlatON-Go/common/base"
"github.com/PlatONnetwork/PlatON-Go/core/sdk"
"math/big"
"reflect"
"strings"
"sync"
"sync/atomic"
"time"

"github.com/PlatONnetwork/PlatON-Go/common/base"
"github.com/PlatONnetwork/PlatON-Go/core/sdk"

mapset "github.com/deckarep/golang-set"
"github.com/pkg/errors"

"github.com/PlatONnetwork/PlatON-Go/common"
"github.com/PlatONnetwork/PlatON-Go/common/hexutil"
"github.com/PlatONnetwork/PlatON-Go/consensus"
Expand Down Expand Up @@ -59,8 +64,6 @@ import (
"github.com/PlatONnetwork/PlatON-Go/params"
"github.com/PlatONnetwork/PlatON-Go/rpc"
"github.com/PlatONnetwork/PlatON-Go/trie"
mapset "github.com/deckarep/golang-set"
"github.com/pkg/errors"
)

const (
Expand Down Expand Up @@ -1379,6 +1382,10 @@ func (cbft *Cbft) threshold(num int) int {
return num - (num-1)/3
}

func (cbft *Cbft) thresholdShares(num uint64) uint64 {
return num - (num-1)/3
}

func (cbft *Cbft) commitBlock(commitBlock *types.Block, commitQC *ctypes.QuorumCert, lockBlock *types.Block, qcBlock *types.Block) {
extra, err := ctypes.EncodeExtra(byte(cbftVersion), commitQC)
if err != nil {
Expand Down Expand Up @@ -1821,9 +1828,11 @@ func (cbft *Cbft) verifyPrepareQC(oriNum uint64, oriHash common.Hash, qc *ctypes
return err
}
// check signature number
threshold := cbft.threshold(cbft.validatorPool.Len(qc.Epoch))
//threshold := cbft.threshold(cbft.validatorPool.Len(qc.Epoch))
//signsTotal := qc.Len()
threshold := cbft.thresholdShares(cbft.epochValidatorShares(qc.Epoch))
signsTotal := cbft.PrepareQCShares(qc)

signsTotal := qc.Len()
if signsTotal < threshold {
return authFailedError{err: fmt.Errorf("block qc has small number of signature total:%d, threshold:%d", signsTotal, threshold)}
}
Expand Down Expand Up @@ -1855,9 +1864,12 @@ func (cbft *Cbft) validateViewChangeQC(viewChangeQC *ctypes.ViewChangeQC) error
return fmt.Errorf("viewchangeQC exceed validator max limit, total:%d, threshold:%d", len(viewChangeQC.QCs), maxLimit)
}
// the threshold of validator on current epoch
threshold := cbft.threshold(maxLimit)
//threshold := cbft.threshold(maxLimit)
// check signature number
signsTotal := viewChangeQC.Len()
//signsTotal := viewChangeQC.Len()

threshold := cbft.thresholdShares(cbft.epochValidatorShares(vcEpoch))
signsTotal := cbft.ViewChangeQCShares(viewChangeQC)
if signsTotal < threshold {
return fmt.Errorf("viewchange has small number of signature total:%d, threshold:%d", signsTotal, threshold)
}
Expand Down Expand Up @@ -1979,3 +1991,67 @@ func (cbft *Cbft) IsCurrentValidator() (*cbfttypes.ValidateNode, error) {
func (cbft *Cbft) ValidatorLen(epoch uint64) int {
return cbft.validatorPool.Len(epoch)
}

func (cbft *Cbft) SortedValidators(epoch uint64) cbfttypes.SortedValidatorNode {
return cbft.validatorPool.SortedValidators(epoch)
}

func (cbft *Cbft) PrepareVoteSharesByIndex(blockIndex uint32) uint64 {
shares := new(big.Int)
ps := cbft.state.AllPrepareVoteByIndex(blockIndex)
currentValidators := cbft.SortedValidators(cbft.Epoch())

for nodeIndex, v := range currentValidators {
if _, e := ps[uint32(nodeIndex)]; e {
shares.Add(shares, v.Shares)
}
}

return shares.Uint64()
}

func (cbft *Cbft) ViewChangeShares() uint64 {
shares := new(big.Int)
vc := cbft.state.AllViewChange()
currentValidators := cbft.SortedValidators(cbft.Epoch())

for nodeIndex, v := range currentValidators {
if _, e := vc[uint32(nodeIndex)]; e {
shares.Add(shares, v.Shares)
}
}

return shares.Uint64()
}

func (cbft *Cbft) PrepareQCShares(qc *ctypes.QuorumCert) uint64 {
validators := cbft.SortedValidators(qc.Epoch)

shares := new(big.Int)
for i := uint32(0); i < qc.ValidatorSet.Size(); i++ {
if qc.ValidatorSet.GetIndex(i) {
shares.Add(shares, validators[i].Shares)
}
}
return shares.Uint64()
}

func (cbft *Cbft) ViewChangeQCShares(viewChangeQC *ctypes.ViewChangeQC) uint64 {
vcEpoch, _, _, _, _, _ := viewChangeQC.MaxBlock()
validators := cbft.SortedValidators(vcEpoch)

shares := new(big.Int)
for _, qc := range viewChangeQC.QCs {
for i := uint32(0); i < qc.ValidatorSet.Size(); i++ {
if qc.ValidatorSet.GetIndex(i) {
shares.Add(shares, validators[i].Shares)
}
}
}

return shares.Uint64()
}

func (cbft *Cbft) epochValidatorShares(epoch uint64) uint64 {
return cbft.validatorPool.TotalShares(epoch)
}
8 changes: 5 additions & 3 deletions consensus/cbft/cbft_common_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ import (
"net"
"time"

"github.com/PlatONnetwork/PlatON-Go/ethdb"
"github.com/PlatONnetwork/PlatON-Go/p2p/enode"

"github.com/PlatONnetwork/PlatON-Go/core/cbfttypes"
"github.com/PlatONnetwork/PlatON-Go/core/rawdb"
"github.com/PlatONnetwork/PlatON-Go/ethdb"
"github.com/PlatONnetwork/PlatON-Go/p2p/enode"

"github.com/PlatONnetwork/PlatON-Go/consensus/cbft/network"
"github.com/PlatONnetwork/PlatON-Go/consensus/cbft/protocols"
Expand Down Expand Up @@ -296,6 +295,9 @@ func (m *mockConsensusApp) VerifyExtendData(ctx consensus.ConsensusContext, data
func (m *mockConsensusApp) PrepareQC(ctx consensus.ConsensusContext, block *protocols.PrepareBlock, votes map[uint32]*protocols.PrepareVote) {
}

func (m *mockConsensusApp) ViewChange(ctx consensus.ConsensusContext, validators []*cbfttypes.ValidateNode) {
}

func (m *mockConsensusApp) NewHeader(ctx consensus.ConsensusContext, header *types.Header) error {
return nil
}
Expand Down
27 changes: 20 additions & 7 deletions consensus/cbft/consensus_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"fmt"
"time"

"github.com/pkg/errors"

"github.com/PlatONnetwork/PlatON-Go/common"
"github.com/PlatONnetwork/PlatON-Go/common/math"
"github.com/PlatONnetwork/PlatON-Go/consensus/cbft/context"
Expand All @@ -32,7 +34,6 @@ import (
"github.com/PlatONnetwork/PlatON-Go/core/types"
"github.com/PlatONnetwork/PlatON-Go/crypto/bls"
"github.com/PlatONnetwork/PlatON-Go/log"
"github.com/pkg/errors"
)

// OnPrepareBlock performs security rule verification,store in blockTree,
Expand Down Expand Up @@ -206,7 +207,7 @@ func (cbft *Cbft) OnViewTimeout() {
cbft.bridge.SendViewChange(viewChange)
}

cbft.state.AddViewChange(uint32(node.Index), viewChange)
cbft.state.AddViewChange(node.Index, viewChange)
cbft.network.Broadcast(viewChange)
cbft.log.Info("Local add viewChange", "index", node.Index, "viewChange", viewChange.String(), "total", cbft.state.ViewChangeLen())

Expand Down Expand Up @@ -501,10 +502,14 @@ func (cbft *Cbft) findExecutableBlock() {
func (cbft *Cbft) findQCBlock() {
index := cbft.state.MaxQCIndex()
next := index + 1
size := cbft.state.PrepareVoteLenByIndex(next)
//size := cbft.state.PrepareVoteLenByIndex(next)
//prepareQC := func() bool {
// return size >= cbft.threshold(cbft.currentValidatorLen()) && cbft.state.HadSendPrepareVote().Had(next)
//}

shares := cbft.PrepareVoteSharesByIndex(next)
prepareQC := func() bool {
return size >= cbft.threshold(cbft.currentValidatorLen()) && cbft.state.HadSendPrepareVote().Had(next)
return shares >= cbft.thresholdShares(cbft.epochValidatorShares(cbft.Epoch())) && cbft.state.HadSendPrepareVote().Had(next)
}

if prepareQC() {
Expand Down Expand Up @@ -609,11 +614,15 @@ func (cbft *Cbft) tryChangeView() {
return
}

shares := cbft.ViewChangeShares()
viewChangeQC := func() bool {
if cbft.state.ViewChangeLen() >= cbft.threshold(cbft.currentValidatorLen()) {
//if cbft.state.ViewChangeLen() >= cbft.threshold(cbft.currentValidatorLen()) {
// return true
//}
if shares >= cbft.thresholdShares(cbft.epochValidatorShares(cbft.Epoch())) {
return true
}
cbft.log.Debug("Try change view failed, had receive viewchange", "len", cbft.state.ViewChangeLen(), "view", cbft.state.ViewString())
cbft.log.Debug("Try change view failed, had receive viewchange", "len", cbft.state.ViewChangeLen(), "shares", shares, "view", cbft.state.ViewString())
return false
}

Expand Down Expand Up @@ -728,7 +737,7 @@ func (cbft *Cbft) generateViewChange(qc *ctypes.QuorumCert) (*protocols.ViewChan
ViewNumber: cbft.state.ViewNumber(),
BlockHash: qc.BlockHash,
BlockNumber: qc.BlockNumber,
ValidatorIndex: uint32(node.Index),
ValidatorIndex: node.Index,
PrepareQC: qc,
}
if err := cbft.signMsgByBls(v); err != nil {
Expand Down Expand Up @@ -774,6 +783,10 @@ func (cbft *Cbft) changeView(epoch, viewNumber uint64, block *types.Block, qc *c
if !cbft.isLoading() {
cbft.bridge.ConfirmViewChange(epoch, viewNumber, block, qc, viewChangeQC, preEpoch, preViewNumber)
}
if cbft.app != nil {
cbft.app.ViewChange(context.NewContext(cbft, 0, nil), cbft.SortedValidators(cbft.Epoch()))
}

cbft.clearInvalidBlocks(block)
cbft.evPool.Clear(epoch, viewNumber)
// view change maybe lags behind the other nodes,active sync prepare block
Expand Down
19 changes: 11 additions & 8 deletions consensus/cbft/sync_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,17 +371,18 @@ func (cbft *Cbft) OnGetPrepareVote(id string, msg *protocols.GetPrepareVote) err
// Defining an array for receiving PrepareVote.
votes := make([]*protocols.PrepareVote, 0, len(prepareVoteMap))
if prepareVoteMap != nil {
threshold := cbft.threshold(cbft.currentValidatorLen())
remain := threshold - (cbft.currentValidatorLen() - int(msg.UnKnownSet.Size()))
//threshold := cbft.threshold(cbft.currentValidatorLen())
//remain := threshold - (cbft.currentValidatorLen() - int(msg.UnKnownSet.Size()))
for k, v := range prepareVoteMap {
if msg.UnKnownSet.GetIndex(k) {
votes = append(votes, v)
}

// Limit response votes
if remain > 0 && len(votes) >= remain {
break
}
// 此处不做 vote shares 的 remain 计算,把对方缺失的 vote 全部返回 TODO
//// Limit response votes
//if remain > 0 && len(votes) >= remain {
// break
//}
}
}
if len(votes) > 0 {
Expand Down Expand Up @@ -677,7 +678,8 @@ func (cbft *Cbft) MissingViewChangeNodes() (v *protocols.GetViewChange, err erro
vbits := utils.NewBitArray(uint32(length))

// enough qc or did not reach deadline
if len(allViewChange) >= cbft.threshold(length) || !cbft.state.IsDeadline() {
//if len(allViewChange) >= cbft.threshold(length) || !cbft.state.IsDeadline() {
if !cbft.state.IsDeadline() {
v, err = nil, fmt.Errorf("no need sync viewchange")
return
}
Expand Down Expand Up @@ -717,7 +719,8 @@ func (cbft *Cbft) MissingPrepareVote() (v *protocols.GetPrepareVote, err error)
cbft.log.Debug("The length of prepare vote", "index", index, "size", size)

// We need sync prepare votes when a long time not arrived QC.
if size < cbft.threshold(len) && time.Since(blockTime) >= syncPrepareVotesInterval { // need sync prepare votes
//if size < cbft.threshold(len) && time.Since(blockTime) >= syncPrepareVotesInterval { // need sync prepare votes
if time.Since(blockTime) >= syncPrepareVotesInterval { // need sync prepare votes
knownVotes := cbft.state.AllPrepareVoteByIndex(index)
unKnownSet := utils.NewBitArray(uint32(len))
for i := uint32(0); i < unKnownSet.Size(); i++ {
Expand Down
16 changes: 16 additions & 0 deletions consensus/cbft/validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,22 @@ func (vp *ValidatorPool) Validators(epoch uint64) *cbfttypes.Validators {
return vp.currentValidators
}

func (vp *ValidatorPool) SortedValidators(epoch uint64) cbfttypes.SortedValidatorNode {
vp.lock.RLock()
defer vp.lock.RUnlock()

validators := vp.Validators(epoch)
return validators.SortedValidators()
}

func (vp *ValidatorPool) TotalShares(epoch uint64) uint64 {
vp.lock.RLock()
defer vp.lock.RUnlock()

validators := vp.Validators(epoch)
return validators.TotalShares()
}

// VerifyHeader verify block's header.
func (vp *ValidatorPool) VerifyHeader(header *types.Header) error {
_, err := crypto.Ecrecover(header.SealHash().Bytes(), header.Signature())
Expand Down
3 changes: 2 additions & 1 deletion consensus/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ type ConsensusContext interface {
type ConsensusApp interface {
ElectionApp
ConsensusExtendApp
ConsensusViewChange
}
type ConsensusExtendApp interface {
ExtendData(ctx ConsensusContext) []byte
VerifyExtendData(ctx ConsensusContext, data []byte) (common.Hash, error)
PrepareQC(ctx ConsensusContext, block *protocols.PrepareBlock, votes map[uint32]*protocols.PrepareVote)
}
type ConsensusViewChange interface {
ViewChange(epoch uint64, ViewNumber uint64, validators []*cbfttypes.ValidateNode)
ViewChange(ctx ConsensusContext, validators []*cbfttypes.ValidateNode)
}
type ElectionApp interface {
NewHeader(ctx ConsensusContext, header *types.Header) error
Expand Down
27 changes: 27 additions & 0 deletions core/cbfttypes/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"errors"
"fmt"
"math"
"math/big"
"sort"

"github.com/PlatONnetwork/PlatON-Go/common"
Expand Down Expand Up @@ -59,6 +60,7 @@ type ValidateNode struct {
PubKey *ecdsa.PublicKey `json:"-"`
NodeID enode.ID `json:"nodeID"`
BlsPubKey *bls.PublicKey `json:"blsPubKey"`
Shares *big.Int `json:"shares"`
}

type ValidateNodeMap map[enode.ID]*ValidateNode
Expand All @@ -74,6 +76,7 @@ type Validators struct {
ValidBlockNumber uint64 `json:"validateBlockNumber"`

sortedNodes SortedValidatorNode
totalShares *big.Int
}

func (vn *ValidateNode) String() string {
Expand Down Expand Up @@ -115,6 +118,30 @@ func (vs *Validators) NodeList() []enode.ID {
return nodeList
}

func (vs *Validators) SortedValidators() SortedValidatorNode {
if len(vs.sortedNodes) == 0 {
vs.sort()
}
return vs.sortedNodes
}

func (vs *Validators) TotalShares() uint64 {
if vs.totalShares != nil {
return vs.totalShares.Uint64()
}

if len(vs.sortedNodes) == 0 {
vs.sort()
}

shares := new(big.Int)
for _, v := range vs.sortedNodes {
shares.Add(shares, v.Shares)
}
vs.totalShares = shares
return shares.Uint64()
}

func (vs *Validators) NodeListByIndexes(indexes []uint32) ([]*ValidateNode, error) {
if len(vs.sortedNodes) == 0 {
vs.sort()
Expand Down
3 changes: 3 additions & 0 deletions sdk/simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ func (app *SimApp) VerifyExtendData(ctx sdk.ConsensusContext, data []byte) (comm
func (app *SimApp) PrepareQC(ctx sdk.ConsensusContext, block *protocols.PrepareBlock, votes map[uint32]*protocols.PrepareVote) {
}

func (app *SimApp) ViewChange(ctx sdk.ConsensusContext, validators []*cbfttypes.ValidateNode) {
}

func (app *SimApp) NewHeader(ctx sdk.ConsensusContext, header *types.Header) error {
return nil
}
Expand Down
Loading