mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-23 07:04:35 +00:00
* New struct in consensus/XDPoS/utils/types.go, util functions, and test. (#14) * define vote, timeout, sync info, qc, tc, extra fields in types.go, add test in types_test.go * add json tag in types.go, refine encoder decoder of extra fields * refactor types.go utils.go * re-write types, comments * add Hash SigHash for types, and tests * define Round type * remove unnecessary logs * add v2 engine functions placeholder * typo fix on the consensus v2 function placeholders * add countdown timer * make initilised private to countdown * add v2 specific config struct * rename some config variables * Implement BFT Message receiver (#13) * fix or skip tests due to PR-136 changes * add bft receiver functions * add bft receiver functions * rename tc to TimeoutCert * implement more functions * New struct in consensus/XDPoS/utils/types.go, util functions, and test. (#14) * define vote, timeout, sync info, qc, tc, extra fields in types.go, add test in types_test.go * add json tag in types.go, refine encoder decoder of extra fields * refactor types.go utils.go * re-write types, comments * add Hash SigHash for types, and tests * define Round type * remove unnecessary logs * add temp functions * add v2 engine functions placeholder * typo fix on the consensus v2 function placeholders * add countdown timer * make initilised private to countdown * push verify function * add test on receiving vote * revert type change * add async on broadcast function * add quit initial * fix test Co-authored-by: Jianrong <wjrjerome@gmail.com> Co-authored-by: wgr523 <wgr523@gmail.com> * generate and verify timeout message * Consensus V2 variable, timeout pool (#19) * fill in XDPoS_v2 variables and processQC/TC * add timeout pool, refine engine variables * refactor type functions * solve a small pointer bug * create general pool and its test, refine engine * refine pool, add xdpos v2 config cert threshold * refine config * vote and timeout handlers * fix pool test * bft miner preparation * review comment improvement * update * relocate tests * add and remove comment * fix the syntax error * update network layer and add handler functions (#23) * update network layer and add handler functions * fix test syntax error * add ProcessQC implementation * add ProcessQC tests * add snapshot test * add wait qc process * remove testing files * add route snapshot * fix merge issue * add default v2 behaviour (#24) * add v2 ecrecover functions and refactor test * fix all the tests * put minimun lock variable * debugging prepare and seal v2 blocks * Trigger proposeBlockHandler after v2 block received and verified in fetcher * skip snapshot apply related tests * update test check * rename bfter to bft handler and ignore normal behviour * fix bugs during local 4 node run * fix test * fix sync info test * fix bugs during local 4 node run * rebase and fix bug * remove hook validators function" Co-authored-by: wgr523 <wgr523@gmail.com> Co-authored-by: Jianrong <wjrjerome@gmail.com>
205 lines
5.7 KiB
Go
205 lines
5.7 KiB
Go
package bft
|
|
|
|
import (
|
|
"fmt"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/XinFinOrg/XDPoSChain/consensus"
|
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/engines/engine_v2"
|
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
|
"github.com/XinFinOrg/XDPoSChain/core"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// make different votes based on Signatures
|
|
func makeVotes(n int) []utils.Vote {
|
|
var votes []utils.Vote
|
|
for i := 0; i < n; i++ {
|
|
votes = append(votes, utils.Vote{
|
|
ProposedBlockInfo: &utils.BlockInfo{},
|
|
Signature: []byte{byte(i)},
|
|
})
|
|
}
|
|
return votes
|
|
}
|
|
|
|
// bfterTester is a test simulator for mocking out bfter worker.
|
|
type bfterTester struct {
|
|
bfter *Bfter
|
|
}
|
|
|
|
// newTester creates a new bft fetcher test mocker.
|
|
func newTester() *bfterTester {
|
|
testConsensus := &XDPoS.XDPoS{EngineV2: &engine_v2.XDPoS_v2{}}
|
|
broadcasts := BroadcastFns{}
|
|
blockChain := &core.BlockChain{}
|
|
|
|
tester := &bfterTester{}
|
|
tester.bfter = New(broadcasts, blockChain)
|
|
tester.bfter.SetConsensusFuns(testConsensus)
|
|
tester.bfter.broadcastCh = make(chan interface{})
|
|
tester.bfter.Start()
|
|
|
|
return tester
|
|
}
|
|
|
|
// Tests that a bfter accepts vote and process verfiy and broadcast
|
|
func TestSequentialVotes(t *testing.T) {
|
|
tester := newTester()
|
|
verifyCounter := uint32(0)
|
|
handlerCounter := uint32(0)
|
|
broadcastCounter := uint32(0)
|
|
targetVotes := 10
|
|
|
|
tester.bfter.consensus.verifyVote = func(vote *utils.Vote) error {
|
|
atomic.AddUint32(&verifyCounter, 1)
|
|
return nil
|
|
}
|
|
|
|
tester.bfter.consensus.voteHandler = func(chain consensus.ChainReader, vote *utils.Vote) error {
|
|
atomic.AddUint32(&handlerCounter, 1)
|
|
return nil
|
|
}
|
|
|
|
tester.bfter.broadcast.Vote = func(*utils.Vote) {
|
|
atomic.AddUint32(&broadcastCounter, 1)
|
|
}
|
|
|
|
votes := makeVotes(targetVotes)
|
|
for _, vote := range votes {
|
|
err := tester.bfter.Vote(&vote)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
if int(verifyCounter) != targetVotes || int(handlerCounter) != targetVotes || int(broadcastCounter) != targetVotes {
|
|
t.Fatalf("count mismatch: have %v on verify, %v on handler, %v on broadcast, want %v", verifyCounter, handlerCounter, broadcastCounter, targetVotes)
|
|
}
|
|
}
|
|
|
|
// Tests that vote already being retrieved will not be duplicated.
|
|
func TestDuplicateVotes(t *testing.T) {
|
|
tester := newTester()
|
|
verifyCounter := uint32(0)
|
|
handlerCounter := uint32(0)
|
|
broadcastCounter := uint32(0)
|
|
targetVotes := 1
|
|
|
|
tester.bfter.consensus.verifyVote = func(vote *utils.Vote) error {
|
|
atomic.AddUint32(&verifyCounter, 1)
|
|
return nil
|
|
}
|
|
|
|
tester.bfter.consensus.voteHandler = func(chain consensus.ChainReader, vote *utils.Vote) error {
|
|
atomic.AddUint32(&handlerCounter, 1)
|
|
return nil
|
|
}
|
|
|
|
tester.bfter.broadcast.Vote = func(*utils.Vote) {
|
|
atomic.AddUint32(&broadcastCounter, 1)
|
|
}
|
|
|
|
vote := utils.Vote{ProposedBlockInfo: &utils.BlockInfo{}}
|
|
|
|
// send twice
|
|
tester.bfter.Vote(&vote)
|
|
tester.bfter.Vote(&vote)
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
if int(verifyCounter) != targetVotes || int(handlerCounter) != targetVotes || int(broadcastCounter) != targetVotes {
|
|
t.Fatalf("count mismatch: have %v on verify, %v on handler, %v on broadcast, want %v", verifyCounter, handlerCounter, broadcastCounter, targetVotes)
|
|
}
|
|
}
|
|
|
|
// Test that avoid boardcast if there is bad vote
|
|
func TestNotBoardcastInvalidVote(t *testing.T) {
|
|
tester := newTester()
|
|
handlerCounter := uint32(0)
|
|
broadcastCounter := uint32(0)
|
|
targetVotes := 0
|
|
|
|
tester.bfter.consensus.verifyVote = func(vote *utils.Vote) error {
|
|
return fmt.Errorf("This is invalid vote")
|
|
}
|
|
|
|
tester.bfter.consensus.voteHandler = func(chain consensus.ChainReader, vote *utils.Vote) error {
|
|
atomic.AddUint32(&handlerCounter, 1)
|
|
return nil
|
|
}
|
|
tester.bfter.broadcast.Vote = func(*utils.Vote) {
|
|
atomic.AddUint32(&broadcastCounter, 1)
|
|
}
|
|
|
|
vote := utils.Vote{ProposedBlockInfo: &utils.BlockInfo{}}
|
|
tester.bfter.Vote(&vote)
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
if int(handlerCounter) != targetVotes || int(broadcastCounter) != targetVotes {
|
|
t.Fatalf("count mismatch: have %v on handler, %v on broadcast, want %v", handlerCounter, broadcastCounter, targetVotes)
|
|
}
|
|
}
|
|
|
|
// TODO: SyncInfo and Timeout Test, should be same as Vote.
|
|
// Once all test on vote covered, then duplicate to others
|
|
|
|
func TestTimeoutHandler(t *testing.T) {
|
|
tester := newTester()
|
|
verifyCounter := uint32(0)
|
|
handlerCounter := uint32(0)
|
|
broadcastCounter := uint32(0)
|
|
targetVotes := 1
|
|
|
|
tester.bfter.consensus.verifyTimeout = func(timeout *utils.Timeout) error {
|
|
atomic.AddUint32(&verifyCounter, 1)
|
|
return nil
|
|
}
|
|
|
|
tester.bfter.consensus.timeoutHandler = func(timeout *utils.Timeout) error {
|
|
atomic.AddUint32(&handlerCounter, 1)
|
|
return nil
|
|
}
|
|
|
|
tester.bfter.broadcast.Timeout = func(*utils.Timeout) {
|
|
atomic.AddUint32(&broadcastCounter, 1)
|
|
}
|
|
|
|
timeoutMsg := &utils.Timeout{}
|
|
|
|
err := tester.bfter.Timeout(timeoutMsg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
if int(verifyCounter) != targetVotes || int(handlerCounter) != targetVotes || int(broadcastCounter) != targetVotes {
|
|
t.Fatalf("count mismatch: have %v on verify, %v on handler, %v on broadcast, want %v", verifyCounter, handlerCounter, broadcastCounter, targetVotes)
|
|
}
|
|
}
|
|
|
|
func TestTimeoutHandlerRoundNotEqual(t *testing.T) {
|
|
tester := newTester()
|
|
|
|
tester.bfter.consensus.verifyTimeout = func(timeout *utils.Timeout) error {
|
|
return nil
|
|
}
|
|
|
|
tester.bfter.consensus.timeoutHandler = func(timeout *utils.Timeout) error {
|
|
return &utils.ErrIncomingMessageRoundNotEqualCurrentRound{utils.Round(1), utils.Round(2)}
|
|
}
|
|
|
|
tester.bfter.broadcast.Timeout = func(*utils.Timeout) {
|
|
return
|
|
}
|
|
|
|
timeoutMsg := &utils.Timeout{}
|
|
|
|
err := tester.bfter.Timeout(timeoutMsg)
|
|
assert.Equal(t, "Timeout message round number: 1 does not match currentRound: 2", err.Error())
|
|
}
|