mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
add test and fix issue on happy path (#46)
* add test and fix issue on happy path * add prepare test * update comment
This commit is contained in:
parent
05d315d2e3
commit
ff0fcd3951
6 changed files with 200 additions and 88 deletions
|
|
@ -125,13 +125,13 @@ func (x *XDPoS_v2) Initial(chain consensus.ChainReader, header *types.Header, ma
|
|||
|
||||
log.Info("[Initial] highest QC for consensus v2 first block", "Block Num", header.Number.String(), "BlockHash", header.Hash())
|
||||
// Generate new parent blockInfo and put it into QC
|
||||
parentBlockInfo := &utils.BlockInfo{
|
||||
Hash: header.ParentHash,
|
||||
blockInfo := &utils.BlockInfo{
|
||||
Hash: header.Hash(),
|
||||
Round: utils.Round(0),
|
||||
Number: big.NewInt(0).Sub(header.Number, big.NewInt(1)),
|
||||
Number: header.Number,
|
||||
}
|
||||
quorumCert := &utils.QuorumCert{
|
||||
ProposedBlockInfo: parentBlockInfo,
|
||||
ProposedBlockInfo: blockInfo,
|
||||
Signatures: nil,
|
||||
}
|
||||
x.currentRound = 1
|
||||
|
|
@ -156,7 +156,7 @@ func (x *XDPoS_v2) Prepare(chain consensus.ChainReader, header *types.Header) er
|
|||
highestQC := x.highestQuorumCert
|
||||
x.lock.RUnlock()
|
||||
|
||||
if (highestQC == nil) || (header.ParentHash != highestQC.ProposedBlockInfo.Hash) {
|
||||
if header.ParentHash != highestQC.ProposedBlockInfo.Hash {
|
||||
return consensus.ErrNotReadyToPropose
|
||||
}
|
||||
|
||||
|
|
@ -165,6 +165,12 @@ func (x *XDPoS_v2) Prepare(chain consensus.ChainReader, header *types.Header) er
|
|||
QuorumCert: highestQC,
|
||||
}
|
||||
|
||||
extraBytes, err := extra.EncodeToBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header.Extra = extraBytes
|
||||
|
||||
header.Nonce = types.BlockNonce{}
|
||||
|
||||
number := header.Number.Uint64()
|
||||
|
|
@ -173,40 +179,32 @@ func (x *XDPoS_v2) Prepare(chain consensus.ChainReader, header *types.Header) er
|
|||
if parent == nil {
|
||||
return consensus.ErrUnknownAncestor
|
||||
}
|
||||
|
||||
// Set the correct difficulty
|
||||
header.Difficulty = x.calcDifficulty(chain, parent, x.signer)
|
||||
log.Debug("CalcDifficulty ", "number", header.Number, "difficulty", header.Difficulty)
|
||||
|
||||
// TODO: previous round should sit on previous Epoch and x.currentRound should >= Epoch number
|
||||
isEpochSwitchBlock, _, err := x.IsEpochSwitch(header)
|
||||
if err != nil {
|
||||
log.Error("[Prepare] Error while trying to determine if header is an epoch switch during Prepare", "header", header, "Error", err)
|
||||
return err
|
||||
}
|
||||
if isEpochSwitchBlock {
|
||||
snap, err := x.getSnapshot(chain, number-1)
|
||||
snap, err := x.getSnapshot(chain, number)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
masternodes := snap.NextEpochMasterNodes
|
||||
//TODO: remove penalty nodes and add comeback nodes
|
||||
//TODO: remove penalty nodes and add comeback nodes, or change this logic into yourturn function
|
||||
for _, v := range masternodes {
|
||||
header.Validators = append(header.Validators, v[:]...)
|
||||
}
|
||||
}
|
||||
|
||||
extraBytes, err := extra.EncodeToBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header.Extra = extraBytes
|
||||
|
||||
// Mix digest is reserved for now, set to empty
|
||||
header.MixDigest = common.Hash{}
|
||||
|
||||
// Ensure the timestamp has the correct delay
|
||||
|
||||
// TODO: Proper deal with time
|
||||
// TODO: if timestamp > current time, how to deal with future timestamp
|
||||
header.Time = new(big.Int).Add(parent.Time, new(big.Int).SetUint64(x.config.Period))
|
||||
|
|
@ -337,7 +335,7 @@ func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, s
|
|||
round := x.currentRound
|
||||
isEpochSwitch, _, err := x.IsEpochSwitchAtRound(round, parent)
|
||||
if err != nil {
|
||||
log.Error("[YourTurn]", "Error", err)
|
||||
log.Error("[YourTurn] check epoch switch at round failed", "Error", err)
|
||||
return false, err
|
||||
}
|
||||
var masterNodes []common.Address
|
||||
|
|
@ -345,14 +343,19 @@ func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, s
|
|||
if x.config.XDPoSV2Block.Cmp(parent.Number) == 0 {
|
||||
snap, err := x.getSnapshot(chain, x.config.XDPoSV2Block.Uint64())
|
||||
if err != nil {
|
||||
log.Error("[YourTurn]Cannot find snapshot at gap num of last V1", "err", err, "number", x.config.XDPoSV2Block.Uint64())
|
||||
log.Error("[YourTurn] Cannot find snapshot at gap num of last V1", "err", err, "number", x.config.XDPoSV2Block.Uint64())
|
||||
return false, err
|
||||
}
|
||||
// the initial snapshot of v1->v2 switch does not need penalty
|
||||
// the initial snapshot of v1->v2 switch containes penalites node
|
||||
masterNodes = snap.NextEpochMasterNodes
|
||||
} else {
|
||||
// TODO: calc master nodes by smart contract - penalty
|
||||
// TODO: related to snapshot
|
||||
snap, err := x.getSnapshot(chain, parent.Number.Uint64()+1)
|
||||
if err != nil {
|
||||
log.Error("[YourTurn] Cannot find snapshot at gap block", "err", err, "number", x.config.XDPoSV2Block.Uint64())
|
||||
return false, err
|
||||
}
|
||||
masterNodes = snap.NextEpochMasterNodes
|
||||
// TODO: calculate master nodes with penalty and comback
|
||||
}
|
||||
} else {
|
||||
// this block and parent belong to the same epoch
|
||||
|
|
@ -1137,7 +1140,7 @@ func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
|||
}
|
||||
parentRound := decodedExtraField.QuorumCert.ProposedBlockInfo.Round
|
||||
round := decodedExtraField.Round
|
||||
epochStart := round - round%utils.Round(x.config.Epoch)
|
||||
epochStartRound := round - round%utils.Round(x.config.Epoch)
|
||||
epochNum := x.config.XDPoSV2Block.Uint64()/x.config.Epoch + uint64(round)/x.config.Epoch
|
||||
// if parent is last v1 block and this is first v2 block, this is treated as epoch switch
|
||||
if decodedExtraField.QuorumCert.ProposedBlockInfo.Number.Cmp(x.config.XDPoSV2Block) == 0 {
|
||||
|
|
@ -1145,7 +1148,7 @@ func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
|||
return true, epochNum, nil
|
||||
}
|
||||
log.Info("[IsEpochSwitch]", "parent round", parentRound, "round", round, "number", header.Number.Uint64(), "hash", header.Hash())
|
||||
return parentRound < epochStart, epochNum, nil
|
||||
return parentRound < epochStartRound, epochNum, nil
|
||||
}
|
||||
|
||||
// IsEpochSwitchAtRound() is used by miner to check whether it mines a block in the same epoch with parent
|
||||
|
|
@ -1162,8 +1165,8 @@ func (x *XDPoS_v2) IsEpochSwitchAtRound(round utils.Round, parentHeader *types.H
|
|||
return false, 0, err
|
||||
}
|
||||
parentRound := decodedExtraField.Round
|
||||
epochStart := round - round%utils.Round(x.config.Epoch)
|
||||
return parentRound < epochStart, epochNum, nil
|
||||
epochStartRound := round - round%utils.Round(x.config.Epoch)
|
||||
return parentRound < epochStartRound, epochNum, nil
|
||||
}
|
||||
|
||||
// Given header and its hash, get epoch switch info from the epoch switch block of that epoch,
|
||||
|
|
|
|||
|
|
@ -63,3 +63,12 @@ func (s *SnapshotV2) GetMappedMasterNodes() map[common.Address]struct{} {
|
|||
}
|
||||
return ms
|
||||
}
|
||||
|
||||
func (s *SnapshotV2) IsMasterNodes(address common.Address) bool {
|
||||
for _, n := range s.NextEpochMasterNodes {
|
||||
if n.String() == address.String() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestYourTurnInitialV2(t *testing.T) {
|
||||
config := params.TestXDPoSMockChainConfigWithV2EngineEpochSwitch
|
||||
blockchain, _, parentBlock, _ := PrepareXDCTestBlockChain(t, int(config.XDPoS.Epoch)-1, config)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
||||
// Insert block 900
|
||||
t.Logf("Inserting block with propose at 900...")
|
||||
blockCoinbaseA := "0xaaa0000000000000000000000000000000000900"
|
||||
//Get from block validator error message
|
||||
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
|
||||
header := &types.Header{
|
||||
Root: common.HexToHash(merkleRoot),
|
||||
Number: big.NewInt(int64(900)),
|
||||
ParentHash: parentBlock.Hash(),
|
||||
Coinbase: common.HexToAddress(blockCoinbaseA),
|
||||
Extra: common.Hex2Bytes("d7830100018358444388676f312e31352e38856c696e757800000000000000000278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758ccef312ee5eea8d7bad5374c6a652150515d744508b61c1a4deb4e4e7bf057e4e3824c11fd2569bcb77a52905cda63b5a58507910bed335e4c9d87ae0ecdfafd400"),
|
||||
}
|
||||
block900, err := insertBlock(blockchain, header)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// YourTurn is called before mine first v2 block
|
||||
b, err := adaptor.YourTurn(blockchain, block900.Header(), common.HexToAddress("xdc0278C350152e15fa6FFC712a5A73D704Ce73E2E1"))
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, b)
|
||||
b, err = adaptor.YourTurn(blockchain, block900.Header(), common.HexToAddress("xdc03d9e17Ae3fF2c6712E44e25B09Ac5ee91f6c9ff"))
|
||||
assert.Nil(t, err)
|
||||
// round=1, so masternode[1] has YourTurn = True
|
||||
assert.True(t, b)
|
||||
assert.Equal(t, adaptor.EngineV2.GetCurrentRound(), utils.Round(1))
|
||||
|
||||
snap, err := adaptor.EngineV2.GetSnapshot(blockchain, block900.Header())
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, snap)
|
||||
masterNodes := adaptor.EngineV1.GetMasternodesFromCheckpointHeader(block900.Header())
|
||||
for i := 0; i < len(masterNodes); i++ {
|
||||
assert.Equal(t, masterNodes[i].Hex(), snap.NextEpochMasterNodes[i].Hex())
|
||||
}
|
||||
}
|
||||
155
consensus/tests/mine_test.go
Normal file
155
consensus/tests/mine_test.go
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestYourTurnInitialV2(t *testing.T) {
|
||||
config := params.TestXDPoSMockChainConfigWithV2EngineEpochSwitch
|
||||
blockchain, _, parentBlock, _ := PrepareXDCTestBlockChain(t, int(config.XDPoS.Epoch)-1, config)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
||||
// Insert block 900
|
||||
t.Logf("Inserting block with propose at 900...")
|
||||
blockCoinbaseA := "0xaaa0000000000000000000000000000000000900"
|
||||
//Get from block validator error message
|
||||
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
|
||||
header := &types.Header{
|
||||
Root: common.HexToHash(merkleRoot),
|
||||
Number: big.NewInt(int64(900)),
|
||||
ParentHash: parentBlock.Hash(),
|
||||
Coinbase: common.HexToAddress(blockCoinbaseA),
|
||||
Extra: common.Hex2Bytes("d7830100018358444388676f312e31352e38856c696e757800000000000000000278c350152e15fa6ffc712a5a73d704ce73e2e103d9e17ae3ff2c6712e44e25b09ac5ee91f6c9ff065551f0dcac6f00cae11192d462db709be3758ccef312ee5eea8d7bad5374c6a652150515d744508b61c1a4deb4e4e7bf057e4e3824c11fd2569bcb77a52905cda63b5a58507910bed335e4c9d87ae0ecdfafd400"),
|
||||
}
|
||||
block900, err := insertBlock(blockchain, header)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// YourTurn is called before mine first v2 block
|
||||
b, err := adaptor.YourTurn(blockchain, block900.Header(), common.HexToAddress("xdc0278C350152e15fa6FFC712a5A73D704Ce73E2E1"))
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, b)
|
||||
b, err = adaptor.YourTurn(blockchain, block900.Header(), common.HexToAddress("xdc03d9e17Ae3fF2c6712E44e25B09Ac5ee91f6c9ff"))
|
||||
assert.Nil(t, err)
|
||||
// round=1, so masternode[1] has YourTurn = True
|
||||
assert.True(t, b)
|
||||
assert.Equal(t, adaptor.EngineV2.GetCurrentRound(), utils.Round(1))
|
||||
|
||||
snap, err := adaptor.EngineV2.GetSnapshot(blockchain, block900.Header())
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, snap)
|
||||
masterNodes := adaptor.EngineV1.GetMasternodesFromCheckpointHeader(block900.Header())
|
||||
for i := 0; i < len(masterNodes); i++ {
|
||||
assert.Equal(t, masterNodes[i].Hex(), snap.NextEpochMasterNodes[i].Hex())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateMasterNodes(t *testing.T) {
|
||||
config := params.TestXDPoSMockChainConfigWithV2EngineEpochSwitch
|
||||
blockchain, backend, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch+config.XDPoS.Gap)-1, config, 0)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
x := adaptor.EngineV2
|
||||
snap, err := x.GetSnapshot(blockchain, currentBlock.Header())
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, int(snap.Number), 450)
|
||||
|
||||
// Insert block 1350
|
||||
t.Logf("Inserting block with propose at 1350...")
|
||||
blockCoinbaseA := "0xaaa0000000000000000000000000000000001350"
|
||||
tx, err := voteTX(37117, 0, acc1Addr.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
//Get from block validator error message
|
||||
merkleRoot := "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772"
|
||||
header := &types.Header{
|
||||
Root: common.HexToHash(merkleRoot),
|
||||
Number: big.NewInt(int64(1350)),
|
||||
ParentHash: currentBlock.Hash(),
|
||||
Coinbase: common.HexToAddress(blockCoinbaseA),
|
||||
}
|
||||
// insert header validator
|
||||
err = generateSignature(backend, adaptor, header)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parentBlock, err := insertBlockTxs(blockchain, header, []*types.Transaction{tx})
|
||||
assert.Nil(t, err)
|
||||
|
||||
t.Logf("Inserting block from 1351 to 1800...")
|
||||
for i := 1351; i <= 1800; i++ {
|
||||
blockCoinbase := fmt.Sprintf("0xaaa000000000000000000000000000000000%4d", i)
|
||||
//Get from block validator error message
|
||||
merkleRoot := "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772"
|
||||
header = &types.Header{
|
||||
Root: common.HexToHash(merkleRoot),
|
||||
Number: big.NewInt(int64(i)),
|
||||
ParentHash: parentBlock.Hash(),
|
||||
Coinbase: common.HexToAddress(blockCoinbase),
|
||||
}
|
||||
err = generateSignature(backend, adaptor, header)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block, err := insertBlock(blockchain, header)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parentBlock = block
|
||||
}
|
||||
|
||||
snap, err = x.GetSnapshot(blockchain, parentBlock.Header())
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, snap.IsMasterNodes(acc3Addr))
|
||||
assert.True(t, snap.IsMasterNodes(acc1Addr))
|
||||
assert.Equal(t, int(snap.Number), 1350)
|
||||
}
|
||||
|
||||
func TestPrepare(t *testing.T) {
|
||||
config := params.TestXDPoSMockChainConfigWithV2EngineEpochSwitch
|
||||
blockchain, _, currentBlock, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch), config, 0)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
|
||||
adaptor.YourTurn(blockchain, currentBlock.Header(), common.HexToAddress("xdc0278C350152e15fa6FFC712a5A73D704Ce73E2E1"))
|
||||
|
||||
tstamp := time.Now().Unix()
|
||||
header901 := &types.Header{
|
||||
ParentHash: currentBlock.Hash(),
|
||||
Number: big.NewInt(int64(901)),
|
||||
GasLimit: params.TargetGasLimit,
|
||||
Time: big.NewInt(tstamp),
|
||||
}
|
||||
|
||||
err := adaptor.Prepare(blockchain, header901)
|
||||
assert.Nil(t, err)
|
||||
|
||||
snap, err := adaptor.EngineV2.GetSnapshot(blockchain, currentBlock.Header())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
validators := []byte{}
|
||||
for _, v := range snap.NextEpochMasterNodes {
|
||||
validators = append(validators, v[:]...)
|
||||
}
|
||||
assert.Equal(t, validators, header901.Validators)
|
||||
|
||||
var decodedExtraField utils.ExtraFields_v2
|
||||
err = utils.DecodeBytesExtraFields(header901.Extra, &decodedExtraField)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, utils.Round(1), decodedExtraField.Round)
|
||||
assert.Equal(t, utils.Round(0), decodedExtraField.QuorumCert.ProposedBlockInfo.Round)
|
||||
}
|
||||
|
|
@ -242,8 +242,10 @@ func PrepareXDCTestBlockChain(t *testing.T, numOfBlocks int, chainConfig *params
|
|||
currentBlock := blockchain.Genesis()
|
||||
|
||||
go func() {
|
||||
checkpointChanMsg := <-core.CheckpointCh
|
||||
log.Info("[V1] Got a message from core CheckpointChan!", "msg", checkpointChanMsg)
|
||||
for range core.CheckpointCh {
|
||||
checkpointChanMsg := <-core.CheckpointCh
|
||||
log.Info("[V1] Got a message from core CheckpointChan!", "msg", checkpointChanMsg)
|
||||
}
|
||||
}()
|
||||
|
||||
// Insert initial blocks
|
||||
|
|
@ -290,8 +292,10 @@ func PrepareXDCTestBlockChainForV2Engine(t *testing.T, numOfBlocks int, chainCon
|
|||
var currentForkBlock *types.Block
|
||||
|
||||
go func() {
|
||||
checkpointChanMsg := <-core.CheckpointCh
|
||||
log.Info("[V2] Got a message from core CheckpointChan!", "msg", checkpointChanMsg)
|
||||
for range core.CheckpointCh {
|
||||
checkpointChanMsg := <-core.CheckpointCh
|
||||
log.Info("[V2] Got a message from core CheckpointChan!", "msg", checkpointChanMsg)
|
||||
}
|
||||
}()
|
||||
|
||||
var masternodesFromV1LastEpoch []common.Address
|
||||
|
|
|
|||
|
|
@ -2052,7 +2052,6 @@ func (bc *BlockChain) insertBlock(block *types.Block) ([]interface{}, []*types.L
|
|||
}
|
||||
if isEpochSwithBlock {
|
||||
CheckpointCh <- 1
|
||||
|
||||
}
|
||||
}
|
||||
// Append a single chain head event if we've progressed the chain
|
||||
|
|
@ -2480,16 +2479,12 @@ func (bc *BlockChain) UpdateM1() error {
|
|||
// if can't get anything, request from contracts
|
||||
stateDB, err := bc.State()
|
||||
if err != nil {
|
||||
|
||||
candidates, err = validator.GetCandidates(opts)
|
||||
if err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
||||
candidates = state.GetCandidates(stateDB)
|
||||
|
||||
}
|
||||
|
||||
var ms []utils.Masternode
|
||||
|
|
|
|||
Loading…
Reference in a new issue