generate and verify timeout message

This commit is contained in:
Jianrong 2021-11-07 10:30:14 +11:00
parent a1b77f3ca8
commit 4addb69561
10 changed files with 198 additions and 57 deletions

View file

@ -20,7 +20,9 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"math/big" "math/big"
"os"
"sync" "sync"
"time" "time"
@ -29,7 +31,9 @@ import (
"github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain" "github.com/XinFinOrg/XDPoSChain"
"github.com/XinFinOrg/XDPoSChain/accounts"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/accounts/keystore"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math" "github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
@ -69,6 +73,28 @@ type SimulatedBackend struct {
config *params.ChainConfig config *params.ChainConfig
} }
func SimulateWalletAddressAndSignFn() (common.Address, func(account accounts.Account, hash []byte) ([]byte, error), error) {
veryLightScryptN := 2
veryLightScryptP := 1
dir, _ := ioutil.TempDir("", "eth-SimulateWalletAddressAndSignFn-test")
new := func(kd string) *keystore.KeyStore {
return keystore.NewKeyStore(kd, veryLightScryptN, veryLightScryptP)
}
defer os.RemoveAll(dir)
ks := new(dir)
pass := "" // not used but required by API
a1, err := ks.NewAccount(pass)
if err != nil {
return common.Address{}, nil, fmt.Errorf(err.Error())
}
if err := ks.Unlock(a1, ""); err != nil {
return a1.Address, nil, fmt.Errorf(err.Error())
}
return a1.Address, ks.SignHash, nil
}
// XDC simulated backend for testing purpose. // XDC simulated backend for testing purpose.
func NewXDCSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64, chainConfig *params.ChainConfig) *SimulatedBackend { func NewXDCSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64, chainConfig *params.ChainConfig) *SimulatedBackend {
// database := ethdb.NewMemDatabase() // database := ethdb.NewMemDatabase()

View file

@ -210,6 +210,7 @@ func (x *XDPoS) CalcDifficulty(chain consensus.ChainReader, time uint64, parent
func (x *XDPoS) Authorize(signer common.Address, signFn clique.SignerFn) { func (x *XDPoS) Authorize(signer common.Address, signFn clique.SignerFn) {
// Authorize each consensus individually // Authorize each consensus individually
x.EngineV1.Authorize(signer, signFn) x.EngineV1.Authorize(signer, signFn)
x.EngineV2.Authorize(signer, signFn)
} }
func (x *XDPoS) GetPeriod() uint64 { func (x *XDPoS) GetPeriod() uint64 {

View file

@ -1,24 +1,36 @@
package engine_v2 package engine_v2
import ( import (
"fmt"
"sync"
"time" "time"
"github.com/XinFinOrg/XDPoSChain/accounts"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/countdown" "github.com/XinFinOrg/XDPoSChain/common/countdown"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
"github.com/XinFinOrg/XDPoSChain/consensus/clique"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
) )
type XDPoS_v2 struct { type XDPoS_v2 struct {
config *params.XDPoSConfig // Consensus engine configuration parameters config *params.XDPoSConfig // Consensus engine configuration parameters
db ethdb.Database // Database to store and retrieve snapshot checkpoints db ethdb.Database // Database to store and retrieve snapshot checkpoints
signer common.Address // Ethereum address of the signing key
signFn clique.SignerFn // Signer function to authorize hashes with
lock sync.RWMutex // Protects the signer fields
BroadcastCh chan interface{} BroadcastCh chan interface{}
BFTQueue chan interface{} BFTQueue chan interface{}
timeoutWorker *countdown.CountdownTimer // Timer to generate broadcast timeout msg if threashold reached timeoutWorker *countdown.CountdownTimer // Timer to generate broadcast timeout msg if threashold reached
currentRound utils.Round
} }
func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v2 { func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v2 {
@ -30,6 +42,8 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v2 {
config: config, config: config,
db: db, db: db,
timeoutWorker: timer, timeoutWorker: timer,
BroadcastCh: make(chan interface{}),
BFTQueue: make(chan interface{}),
} }
// Add callback to the timer // Add callback to the timer
timer.OnTimeoutFn = engine.onCountdownTimeout timer.OnTimeoutFn = engine.onCountdownTimeout
@ -37,6 +51,10 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v2 {
return engine return engine
} }
/*
Testing tools
*/
// Test only. Never to be used for mainnet implementation
func NewFaker(db ethdb.Database, config *params.XDPoSConfig) *XDPoS_v2 { func NewFaker(db ethdb.Database, config *params.XDPoSConfig) *XDPoS_v2 {
var fakeEngine *XDPoS_v2 var fakeEngine *XDPoS_v2
// Set any missing consensus parameters to their defaults // Set any missing consensus parameters to their defaults
@ -50,25 +68,45 @@ func NewFaker(db ethdb.Database, config *params.XDPoSConfig) *XDPoS_v2 {
config: conf, config: conf,
db: db, db: db,
timeoutWorker: timer, timeoutWorker: timer,
BroadcastCh: make(chan interface{}),
BFTQueue: make(chan interface{}),
} }
// Add callback to the timer
timer.OnTimeoutFn = fakeEngine.onCountdownTimeout
return fakeEngine return fakeEngine
} }
func (consensus *XDPoS_v2) Author(header *types.Header) (common.Address, error) { // Test only.
func (x *XDPoS_v2) SetNewRoundFaker(newRound utils.Round) {
// Reset a bunch of things
x.timeoutWorker.Reset()
x.currentRound = newRound
}
// Authorize injects a private key into the consensus engine to mint new blocks with.
func (x *XDPoS_v2) Authorize(signer common.Address, signFn clique.SignerFn) {
x.lock.Lock()
defer x.lock.Unlock()
x.signer = signer
x.signFn = signFn
}
func (x *XDPoS_v2) Author(header *types.Header) (common.Address, error) {
return common.Address{}, nil return common.Address{}, nil
} }
func (consensus *XDPoS_v2) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error { func (x *XDPoS_v2) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error {
return nil return nil
} }
// Push mesages(i.e vote, sync info & timeout) into BFTQueue. This funciton shall be called by BFT protocal manager // Push mesages(i.e vote, sync info & timeout) into BFTQueue. This funciton shall be called by BFT protocal manager
func (consensus *XDPoS_v2) Enqueue() error { func (x *XDPoS_v2) Enqueue() error {
return nil return nil
} }
// Main function for the v2 consensus. // Main function for the v2 consensus.
func (consensus *XDPoS_v2) Dispatcher() error { func (x *XDPoS_v2) Dispatcher() error {
// 1. Pull message from the BFTQueue and call the relevant handler by message type, such as vote, timeout or syncInfo // 1. Pull message from the BFTQueue and call the relevant handler by message type, such as vote, timeout or syncInfo
// 2. Only 1 message processing at the time // 2. Only 1 message processing at the time
return nil return nil
@ -78,7 +116,7 @@ func (consensus *XDPoS_v2) Dispatcher() error {
SyncInfo workflow SyncInfo workflow
*/ */
// Verify syncInfo and trigger trigger process QC or TC if successful // Verify syncInfo and trigger trigger process QC or TC if successful
func (consensus *XDPoS_v2) VerifySyncInfoMessage(syncInfo utils.SyncInfo) error { func (x *XDPoS_v2) VerifySyncInfoMessage(syncInfo utils.SyncInfo) error {
/* /*
1. Verify items including: 1. Verify items including:
- verifyQC - verifyQC
@ -88,7 +126,7 @@ func (consensus *XDPoS_v2) VerifySyncInfoMessage(syncInfo utils.SyncInfo) error
return nil return nil
} }
func (consensus *XDPoS_v2) SyncInfoHandler(header *types.Header) error { func (x *XDPoS_v2) SyncInfoHandler(header *types.Header) error {
/* /*
1. processQC 1. processQC
2. processTC 2. processTC
@ -99,7 +137,7 @@ func (consensus *XDPoS_v2) SyncInfoHandler(header *types.Header) error {
/* /*
Vote workflow Vote workflow
*/ */
func (consensus *XDPoS_v2) VerifyVoteMessage(vote utils.Vote) error { func (x *XDPoS_v2) VerifyVoteMessage(vote utils.Vote) error {
/* /*
1. Check signature: 1. Check signature:
- Use ecRecover to get the public key - Use ecRecover to get the public key
@ -111,7 +149,7 @@ func (consensus *XDPoS_v2) VerifyVoteMessage(vote utils.Vote) error {
return nil return nil
} }
func (consensus *XDPoS_v2) VoteHandler() { func (x *XDPoS_v2) VoteHandler() {
/* /*
1. checkRoundNumber 1. checkRoundNumber
3. Collect vote (TODO) 3. Collect vote (TODO)
@ -124,18 +162,32 @@ func (consensus *XDPoS_v2) VoteHandler() {
Timeout workflow Timeout workflow
*/ */
// Verify timeout message type from peers in bft.go // Verify timeout message type from peers in bft.go
func (consensus *XDPoS_v2) VerifyTimeoutMessage(utils.Timeout) error { /*
/* 1. Check signature:
1. Check signature: - Use ecRecover to get the public key
- Use ecRecover to get the public key - Use the above public key to find out the xdc address
- Use the above public key to find out the xdc address - Use the above xdc address to check against the master node(For the running epoch)
- Use the above xdc address to check against the master node(For the running epoch) 2. Broadcast(Not part of consensus)
2. Broadcast(Not part of consensus) */
*/ func (x *XDPoS_v2) VerifyTimeoutMessage(timeoutMsg utils.Timeout) (bool, error) {
return nil // Recover the public key and the Ethereum address
pubkey, err := crypto.Ecrecover(utils.TimeoutSigHash(timeoutMsg.Round).Bytes(), timeoutMsg.Signature)
if err != nil {
return false, fmt.Errorf("Error while verifying time out message: %v", err)
}
var signerAddress common.Address
copy(signerAddress[:], crypto.Keccak256(pubkey[1:])[12:])
masternodes := x.getCurrentRoundMasterNodes()
for _, mn := range masternodes {
if mn == signerAddress {
return true, nil
}
}
return false, fmt.Errorf("Masternodes does not contain signer address. Master node list %v, Signer address: %v", masternodes, signerAddress)
} }
func (consensus *XDPoS_v2) TimeoutHandler() { func (x *XDPoS_v2) TimeoutHandler() {
/* /*
1. checkRoundNumber() 1. checkRoundNumber()
2. Collect timeout (TODO) 2. Collect timeout (TODO)
@ -148,7 +200,7 @@ func (consensus *XDPoS_v2) TimeoutHandler() {
/* /*
Process Block workflow Process Block workflow
*/ */
func (consensus *XDPoS_v2) ProcessBlockHandler() { func (x *XDPoS_v2) ProcessBlockHandler() {
/* /*
1. processQC() 1. processQC()
2. verifyVotingRule() 2. verifyVotingRule()
@ -162,16 +214,16 @@ func (consensus *XDPoS_v2) ProcessBlockHandler() {
*/ */
// Genrate blockInfo which contains Hash, round and blockNumber and send to queue // Genrate blockInfo which contains Hash, round and blockNumber and send to queue
func (consensus *XDPoS_v2) generateBlockInfo() error { func (x *XDPoS_v2) generateBlockInfo() error {
return nil return nil
} }
// To be used by different message verification. Verify local DB block info against the received block information(i.e hash, blockNum, round) // To be used by different message verification. Verify local DB block info against the received block information(i.e hash, blockNum, round)
func (consensus *XDPoS_v2) VerifyBlockInfo(blockInfo utils.BlockInfo) error { func (x *XDPoS_v2) VerifyBlockInfo(blockInfo utils.BlockInfo) error {
return nil return nil
} }
func (consensus *XDPoS_v2) verifyQC(header *types.Header) error { func (x *XDPoS_v2) verifyQC(header *types.Header) error {
/* /*
1. Verify signer signatures: (List of signatures) 1. Verify signer signatures: (List of signatures)
- Use ecRecover to get the public key - Use ecRecover to get the public key
@ -182,7 +234,7 @@ func (consensus *XDPoS_v2) verifyQC(header *types.Header) error {
return nil return nil
} }
func (consensus *XDPoS_v2) verifyTC(header *types.Header) error { func (x *XDPoS_v2) verifyTC(header *types.Header) error {
/* /*
1. Verify signer signature: (List of signatures) 1. Verify signer signature: (List of signatures)
- Use ecRecover to get the public key - Use ecRecover to get the public key
@ -193,7 +245,7 @@ func (consensus *XDPoS_v2) verifyTC(header *types.Header) error {
} }
// Update local QC variables including highestQC & lockQC, as well as update commit blockInfo before call // Update local QC variables including highestQC & lockQC, as well as update commit blockInfo before call
func (consensus *XDPoS_v2) processQC(header *types.Header) error { func (x *XDPoS_v2) processQC(header *types.Header) error {
/* /*
1. Update HighestQC and LockQC 1. Update HighestQC and LockQC
2. Update commit block info (TODO) 2. Update commit block info (TODO)
@ -202,7 +254,7 @@ func (consensus *XDPoS_v2) processQC(header *types.Header) error {
return nil return nil
} }
func (consensus *XDPoS_v2) processTC(header *types.Header) error { func (x *XDPoS_v2) processTC(header *types.Header) error {
/* /*
1. Update highestTC 1. Update highestTC
2. Check TC round >= node's currentRound. If yes, call setNewRound 2. Check TC round >= node's currentRound. If yes, call setNewRound
@ -210,7 +262,7 @@ func (consensus *XDPoS_v2) processTC(header *types.Header) error {
return nil return nil
} }
func (consensus *XDPoS_v2) setNewRound() error { func (x *XDPoS_v2) setNewRound() error {
/* /*
1. Set currentRound = QC round + 1 (or TC round +1) 1. Set currentRound = QC round + 1 (or TC round +1)
2. Reset timer 2. Reset timer
@ -220,12 +272,12 @@ func (consensus *XDPoS_v2) setNewRound() error {
} }
// Verify round number against node's local round number(Should be equal) // Verify round number against node's local round number(Should be equal)
func (consensus *XDPoS_v2) checkRoundNumber(header *types.Header) error { func (x *XDPoS_v2) checkRoundNumber(header *types.Header) error {
return nil return nil
} }
// Hot stuff rule to decide whether this node is eligible to vote for the received block // Hot stuff rule to decide whether this node is eligible to vote for the received block
func (consensus *XDPoS_v2) verifyVotingRule(header *types.Header) error { func (x *XDPoS_v2) verifyVotingRule(header *types.Header) error {
/* /*
Make sure this node has not voted for this round. We can have a variable highestVotedRound, and check currentRound > highestVotedRound. Make sure this node has not voted for this round. We can have a variable highestVotedRound, and check currentRound > highestVotedRound.
HotStuff Voting rule: HotStuff Voting rule:
@ -237,7 +289,7 @@ func (consensus *XDPoS_v2) verifyVotingRule(header *types.Header) error {
} }
// Once Hot stuff voting rule has verified, this node can then send vote // Once Hot stuff voting rule has verified, this node can then send vote
func (consensus *XDPoS_v2) sendVote(header *types.Header) error { func (x *XDPoS_v2) sendVote(header *types.Header) error {
// First step: Generate the signature by using node's private key(The signature is the blockInfo signature) // First step: Generate the signature by using node's private key(The signature is the blockInfo signature)
// Second step: Construct the vote struct with the above signature & blockinfo struct // Second step: Construct the vote struct with the above signature & blockinfo struct
// Third step: Send the vote to broadcast channel // Third step: Send the vote to broadcast channel
@ -245,17 +297,31 @@ func (consensus *XDPoS_v2) sendVote(header *types.Header) error {
} }
// Generate and send timeout into BFT channel. // Generate and send timeout into BFT channel.
func (consensus *XDPoS_v2) sendTimeout() error { /*
/* 1. timeout.round = currentRound
1. timeout.round = currentRound 2. Sign the signature
2. Sign the signature 3. send to broadcast channel
3. send to broadcast channel */
*/ func (x *XDPoS_v2) sendTimeout() error {
// Don't hold the signer fields for the entire sealing procedure
x.lock.RLock()
signer, signFn := x.signer, x.signFn
x.lock.RUnlock()
signedHash, err := signFn(accounts.Account{Address: signer}, utils.TimeoutSigHash(x.currentRound).Bytes())
if err != nil {
return fmt.Errorf("Error while signing for timeout message")
}
timeoutMsg := &utils.Timeout{
Round: x.currentRound,
Signature: signedHash,
}
x.broadcastToBftChannel(timeoutMsg)
return nil return nil
} }
// Generate and send syncInfo into Broadcast channel. The SyncInfo includes local highest QC & TC // Generate and send syncInfo into Broadcast channel. The SyncInfo includes local highest QC & TC
func (consensus *XDPoS_v2) sendSyncInfo() error { func (x *XDPoS_v2) sendSyncInfo() error {
return nil return nil
} }
@ -263,10 +329,19 @@ func (consensus *XDPoS_v2) sendSyncInfo() error {
Function that will be called by timer when countdown reaches its threshold. Function that will be called by timer when countdown reaches its threshold.
In the engine v2, we would need to broadcast timeout messages to other peers In the engine v2, we would need to broadcast timeout messages to other peers
*/ */
func (consensus *XDPoS_v2) onCountdownTimeout(time time.Time) error { func (x *XDPoS_v2) onCountdownTimeout(time time.Time) error {
err := consensus.sendTimeout() err := x.sendTimeout()
if err != nil { if err != nil {
log.Error("Error while sending out timeout message at time: ", time) log.Error("Error while sending out timeout message at time: ", time)
return err
} }
return nil return nil
} }
func (x *XDPoS_v2) broadcastToBftChannel(msg interface{}) {
x.BroadcastCh <- msg
}
func (x *XDPoS_v2) getCurrentRoundMasterNodes() []common.Address {
return []common.Address{}
}

View file

@ -178,7 +178,10 @@ func DecodeBytesExtraFields(b []byte, val interface{}) error {
func rlpHash(x interface{}) (h common.Hash) { func rlpHash(x interface{}) (h common.Hash) {
hw := sha3.NewKeccak256() hw := sha3.NewKeccak256()
rlp.Encode(hw, x) err := rlp.Encode(hw, x)
if err != nil {
log.Error("rlpHash failed", err)
}
hw.Sum(h[:0]) hw.Sum(h[:0])
return h return h
} }
@ -195,10 +198,10 @@ func (m *SyncInfo) Hash() common.Hash {
return rlpHash(m) return rlpHash(m)
} }
func VoteSigHash(m *BlockInfo) common.Hash { func VoteSigHash(m BlockInfo) common.Hash {
return rlpHash(m) return rlpHash(m)
} }
func TimeoutSigHash(m *Round) common.Hash { func TimeoutSigHash(m Round) common.Hash {
return rlpHash(m) return rlpHash(m)
} }

View file

@ -134,11 +134,11 @@ func TestHashAndSigHash(t *testing.T) {
if syncInfo1.Hash() == syncInfo2.Hash() { if syncInfo1.Hash() == syncInfo2.Hash() {
t.Fatalf("Hash of two sync info shouldn't equal") t.Fatalf("Hash of two sync info shouldn't equal")
} }
if VoteSigHash(&blockInfo1) == VoteSigHash(&blockInfo2) { if VoteSigHash(blockInfo1) == VoteSigHash(blockInfo2) {
t.Fatalf("SigHash of two block info shouldn't equal") t.Fatalf("SigHash of two block info shouldn't equal")
} }
round2 := Round(999) round2 := Round(999)
if TimeoutSigHash(&round) == TimeoutSigHash(&round2) { if TimeoutSigHash(round) == TimeoutSigHash(round2) {
t.Fatalf("SigHash of two round shouldn't equal") t.Fatalf("SigHash of two round shouldn't equal")
} }
} }

View file

@ -38,6 +38,9 @@ var (
XDPoSV2Config = &V2{ XDPoSV2Config = &V2{
TimeoutWorkerDuration: 50000, TimeoutWorkerDuration: 50000,
} }
TestXDPoSV2Config = &V2{
TimeoutWorkerDuration: 5000,
}
// XDPoSChain mainnet config // XDPoSChain mainnet config
XDCMainnetChainConfig = &ChainConfig{ XDCMainnetChainConfig = &ChainConfig{
@ -125,9 +128,9 @@ var (
TestXDPoSChanConfig = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &XDPoSConfig{Period: 2, Epoch: 900, Reward: 250, RewardCheckpoint: 900, Gap: 890, FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"), V2: *XDPoSV2Config}} TestXDPoSChanConfig = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &XDPoSConfig{Period: 2, Epoch: 900, Reward: 250, RewardCheckpoint: 900, Gap: 890, FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068"), V2: *XDPoSV2Config}}
// XDPoS config in use for v1 engine only // XDPoS config in use for v1 engine only
TestXDPoSMockChainConfig = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, &XDPoSConfig{Epoch: 900, Gap: 450, SkipValidation: true, V2: *XDPoSV2Config}} TestXDPoSMockChainConfig = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, &XDPoSConfig{Epoch: 900, Gap: 450, SkipValidation: true, V2: *TestXDPoSV2Config}}
// XDPoS config with v2 engine after block 10 // XDPoS config with v2 engine after block 10
TestXDPoSMockChainConfigWithV2Engine = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, &XDPoSConfig{Epoch: 900, Gap: 450, SkipValidation: true, XDPoSV2Block: big.NewInt(10), V2: *XDPoSV2Config}} TestXDPoSMockChainConfigWithV2Engine = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, &XDPoSConfig{Epoch: 900, Gap: 450, SkipValidation: true, XDPoSV2Block: big.NewInt(10), V2: *TestXDPoSV2Config}}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil} TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil}
TestRules = TestChainConfig.Rules(new(big.Int)) TestRules = TestChainConfig.Rules(new(big.Int))

View file

@ -10,7 +10,7 @@ import (
) )
func TestAdaptorShouldGetAuthorForDifferentConsensusVersion(t *testing.T) { func TestAdaptorShouldGetAuthorForDifferentConsensusVersion(t *testing.T) {
blockchain, _, currentBlock := PrepareXDCTestBlockChain(t, 10, params.TestXDPoSMockChainConfigWithV2Engine) blockchain, _, currentBlock, _ := PrepareXDCTestBlockChain(t, 10, params.TestXDPoSMockChainConfigWithV2Engine)
adaptor := blockchain.Engine().(*XDPoS.XDPoS) adaptor := blockchain.Engine().(*XDPoS.XDPoS)
addressFromAdaptor, errorAdaptor := adaptor.Author(currentBlock.Header()) addressFromAdaptor, errorAdaptor := adaptor.Author(currentBlock.Header())

View file

@ -12,7 +12,7 @@ import (
// Should NOT update signerList if not on the gap block // Should NOT update signerList if not on the gap block
func TestNotUpdateSignerListIfNotOnGapBlock(t *testing.T) { func TestNotUpdateSignerListIfNotOnGapBlock(t *testing.T) {
blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, 400, params.TestXDPoSMockChainConfig) blockchain, backend, parentBlock, _ := PrepareXDCTestBlockChain(t, 400, params.TestXDPoSMockChainConfig)
parentSigners, err := GetSnapshotSigner(blockchain, parentBlock.Header()) parentSigners, err := GetSnapshotSigner(blockchain, parentBlock.Header())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -50,7 +50,7 @@ func TestNotUpdateSignerListIfNotOnGapBlock(t *testing.T) {
// Should call updateM1 at the gap block, and have the same snapshot values as the parent block if no SM transaction is involved // Should call updateM1 at the gap block, and have the same snapshot values as the parent block if no SM transaction is involved
func TestNotChangeSingerListIfNothingProposedOrVoted(t *testing.T) { func TestNotChangeSingerListIfNothingProposedOrVoted(t *testing.T) {
blockchain, _, parentBlock := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig) blockchain, _, parentBlock, _ := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig)
// Insert block 450 // Insert block 450
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", 450) blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", 450)
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930" merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
@ -78,7 +78,7 @@ func TestNotChangeSingerListIfNothingProposedOrVoted(t *testing.T) {
//Should call updateM1 at gap block, and update the snapshot if there are SM transactions involved //Should call updateM1 at gap block, and update the snapshot if there are SM transactions involved
func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) { func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) {
blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-2, params.TestXDPoSMockChainConfig) blockchain, backend, parentBlock, _ := PrepareXDCTestBlockChain(t, GAP-2, params.TestXDPoSMockChainConfig)
// Insert first Block 449 // Insert first Block 449
t.Logf("Inserting block with propose at 449...") t.Logf("Inserting block with propose at 449...")
blockCoinbaseA := "0xaaa0000000000000000000000000000000000449" blockCoinbaseA := "0xaaa0000000000000000000000000000000000449"
@ -136,7 +136,7 @@ func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) {
//Should call updateM1 before gap block, and update the snapshot if there are SM transactions involved //Should call updateM1 before gap block, and update the snapshot if there are SM transactions involved
func TestCallUpdateM1WithSmartContractTranscation(t *testing.T) { func TestCallUpdateM1WithSmartContractTranscation(t *testing.T) {
blockchain, backend, currentBlock := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig) blockchain, backend, currentBlock, _ := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig)
// Insert first Block 450 A // Insert first Block 450 A
t.Logf("Inserting block with propose at 450 A...") t.Logf("Inserting block with propose at 450 A...")
blockCoinbaseA := "0xaaa0000000000000000000000000000000000450" blockCoinbaseA := "0xaaa0000000000000000000000000000000000450"
@ -165,7 +165,7 @@ func TestCallUpdateM1WithSmartContractTranscation(t *testing.T) {
// Should call updateM1 and update snapshot when a forked block(at gap block number) is inserted back into main chain (Edge case) // Should call updateM1 and update snapshot when a forked block(at gap block number) is inserted back into main chain (Edge case)
func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) { func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) {
blockchain, backend, currentBlock := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig) blockchain, backend, currentBlock, _ := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig)
// Check initial signer, by default, acc3 is in the signerList // Check initial signer, by default, acc3 is in the signerList
signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header())
if err != nil { if err != nil {
@ -288,7 +288,7 @@ func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) {
func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testing.T) { func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testing.T) {
blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig) blockchain, backend, parentBlock, _ := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig)
state, err := blockchain.State() state, err := blockchain.State()
if err != nil { if err != nil {
@ -422,7 +422,7 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin
} }
func TestVoteShouldNotBeAffectedByFork(t *testing.T) { func TestVoteShouldNotBeAffectedByFork(t *testing.T) {
blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig) blockchain, backend, parentBlock, _ := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig)
// Check initial signer, by default, acc3 is in the signerList // Check initial signer, by default, acc3 is in the signerList
signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header())
if err != nil { if err != nil {

View file

@ -223,13 +223,20 @@ func GetCandidateFromCurrentSmartContract(backend bind.ContractBackend, t *testi
return ms return ms
} }
func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig) (*BlockChain, *backends.SimulatedBackend, *types.Block) { func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params.ChainConfig) (*BlockChain, *backends.SimulatedBackend, *types.Block, common.Address) {
// Preparation // Preparation
var err error var err error
backend := getCommonBackend(t, chainConfig) backend := getCommonBackend(t, chainConfig)
blockchain := backend.GetBlockChain() blockchain := backend.GetBlockChain()
blockchain.Client = backend blockchain.Client = backend
// Authorise
signer, signFn, err := backends.SimulateWalletAddressAndSignFn()
if err != nil {
panic(fmt.Errorf("Error while creating simulated wallet for generating singer address and signer fn: %v", err))
}
blockchain.Engine().(*XDPoS.XDPoS).Authorize(signer, signFn)
currentBlock := blockchain.Genesis() currentBlock := blockchain.Genesis()
// Insert initial blocks // Insert initial blocks
@ -248,7 +255,7 @@ func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params
t.Fatal(err) t.Fatal(err)
} }
return blockchain, backend, currentBlock return blockchain, backend, currentBlock, signer
} }
// insert Block without transcation attached // insert Block without transcation attached

View file

@ -0,0 +1,26 @@
package consensus
import (
"testing"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/stretchr/testify/assert"
)
func TestCountdownTimeoutToSendTimeoutMessage(t *testing.T) {
blockchain, _, _, _ := PrepareXDCTestBlockChain(t, 11, params.TestXDPoSMockChainConfigWithV2Engine)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
engineV2.SetNewRoundFaker(utils.Round(1))
timeoutMsg := <-engineV2.BroadcastCh
assert.NotNil(t, timeoutMsg)
valid, err := engineV2.VerifyTimeoutMessage(*timeoutMsg.(*utils.Timeout))
// We can only test valid = false for now as the implementation for getCurrentRoundMasterNodes is not complete
assert.False(t, valid)
// This shows we are able to decode the timeout message, which is what this test is all about
assert.Regexp(t, "^Masternodes does not contain signer addres.*", err.Error())
}