mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
* move masternode in v2 config * update number to meet 7 vote for current setup * add test * update all failed test * fix test * remove comment * remove comment * fix test
454 lines
17 KiB
Go
454 lines
17 KiB
Go
package engine_v2_tests
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/big"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/XinFinOrg/XDPoSChain/accounts"
|
|
"github.com/XinFinOrg/XDPoSChain/common"
|
|
"github.com/XinFinOrg/XDPoSChain/consensus"
|
|
"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 TestShouldVerifyBlock(t *testing.T) {
|
|
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
|
assert.Nil(t, err)
|
|
configString := string(b)
|
|
|
|
var config params.ChainConfig
|
|
err = json.Unmarshal([]byte(configString), &config)
|
|
assert.Nil(t, err)
|
|
// Enable verify
|
|
config.XDPoS.V2.SkipV2Validation = false
|
|
// Block 901 is the first v2 block with round of 1
|
|
blockchain, _, _, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
|
|
|
// Happy path
|
|
happyPathHeader := blockchain.GetBlockByNumber(901).Header()
|
|
err = adaptor.VerifyHeader(blockchain, happyPathHeader, true)
|
|
assert.Nil(t, err)
|
|
|
|
// Unhappy path
|
|
|
|
// Verify non-epoch switch block
|
|
err = adaptor.VerifyHeader(blockchain, blockchain.GetBlockByNumber(902).Header(), true)
|
|
assert.Nil(t, err)
|
|
|
|
nonEpochSwitchWithValidators := blockchain.GetBlockByNumber(902).Header()
|
|
nonEpochSwitchWithValidators.Validators = acc1Addr.Bytes()
|
|
err = adaptor.VerifyHeader(blockchain, nonEpochSwitchWithValidators, true)
|
|
assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err)
|
|
|
|
noValidatorBlock := blockchain.GetBlockByNumber(902).Header()
|
|
noValidatorBlock.Validator = []byte{}
|
|
err = adaptor.VerifyHeader(blockchain, noValidatorBlock, true)
|
|
assert.Equal(t, consensus.ErrNoValidatorSignature, err)
|
|
|
|
blockFromFuture := blockchain.GetBlockByNumber(902).Header()
|
|
blockFromFuture.Time = big.NewInt(time.Now().Unix() + 10000)
|
|
err = adaptor.VerifyHeader(blockchain, blockFromFuture, true)
|
|
assert.Equal(t, consensus.ErrFutureBlock, err)
|
|
|
|
invalidQcBlock := blockchain.GetBlockByNumber(902).Header()
|
|
invalidQcBlock.Extra = []byte{2}
|
|
err = adaptor.VerifyHeader(blockchain, invalidQcBlock, true)
|
|
assert.Equal(t, utils.ErrInvalidV2Extra, err)
|
|
|
|
// Epoch switch
|
|
invalidAuthNonceBlock := blockchain.GetBlockByNumber(901).Header()
|
|
invalidAuthNonceBlock.Nonce = types.BlockNonce{123}
|
|
err = adaptor.VerifyHeader(blockchain, invalidAuthNonceBlock, true)
|
|
assert.Equal(t, utils.ErrInvalidVote, err)
|
|
|
|
emptyValidatorsBlock := blockchain.GetBlockByNumber(901).Header()
|
|
emptyValidatorsBlock.Validators = []byte{}
|
|
err = adaptor.VerifyHeader(blockchain, emptyValidatorsBlock, true)
|
|
assert.Equal(t, utils.ErrEmptyEpochSwitchValidators, err)
|
|
|
|
invalidValidatorsSignerBlock := blockchain.GetBlockByNumber(901).Header()
|
|
invalidValidatorsSignerBlock.Validators = []byte{123}
|
|
err = adaptor.VerifyHeader(blockchain, invalidValidatorsSignerBlock, true)
|
|
assert.Equal(t, utils.ErrInvalidCheckpointSigners, err)
|
|
|
|
// non-epoch switch
|
|
invalidValidatorsExistBlock := blockchain.GetBlockByNumber(902).Header()
|
|
invalidValidatorsExistBlock.Validators = []byte{123}
|
|
err = adaptor.VerifyHeader(blockchain, invalidValidatorsExistBlock, true)
|
|
assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err)
|
|
|
|
invalidPenaltiesExistBlock := blockchain.GetBlockByNumber(902).Header()
|
|
invalidPenaltiesExistBlock.Penalties = common.Hex2BytesFixed("123131231", 20)
|
|
err = adaptor.VerifyHeader(blockchain, invalidPenaltiesExistBlock, true)
|
|
assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err)
|
|
|
|
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb123"
|
|
parentNotExistBlock := blockchain.GetBlockByNumber(901).Header()
|
|
parentNotExistBlock.ParentHash = common.HexToHash(merkleRoot)
|
|
err = adaptor.VerifyHeader(blockchain, parentNotExistBlock, true)
|
|
assert.Equal(t, consensus.ErrUnknownAncestor, err)
|
|
|
|
block901 := blockchain.GetBlockByNumber(901).Header()
|
|
tooFastMinedBlock := blockchain.GetBlockByNumber(902).Header()
|
|
tooFastMinedBlock.Time = big.NewInt(block901.Time.Int64() - 10)
|
|
err = adaptor.VerifyHeader(blockchain, tooFastMinedBlock, true)
|
|
assert.Equal(t, utils.ErrInvalidTimestamp, err)
|
|
|
|
invalidDifficultyBlock := blockchain.GetBlockByNumber(902).Header()
|
|
invalidDifficultyBlock.Difficulty = big.NewInt(2)
|
|
err = adaptor.VerifyHeader(blockchain, invalidDifficultyBlock, true)
|
|
assert.Equal(t, utils.ErrInvalidDifficulty, err)
|
|
|
|
// Create an invalid QC round
|
|
proposedBlockInfo := &types.BlockInfo{
|
|
Hash: blockchain.GetBlockByNumber(902).Hash(),
|
|
Round: types.Round(2),
|
|
Number: blockchain.GetBlockByNumber(902).Number(),
|
|
}
|
|
voteForSign := &types.VoteForSign{
|
|
ProposedBlockInfo: proposedBlockInfo,
|
|
GapNumber: 450,
|
|
}
|
|
// Genrate QC
|
|
signedHash, err := signFn(accounts.Account{Address: signer}, types.VoteSigHash(voteForSign).Bytes())
|
|
if err != nil {
|
|
panic(fmt.Errorf("Error generate QC by creating signedHash: %v", err))
|
|
}
|
|
// Sign from acc 1, 2, 3
|
|
acc1SignedHash := SignHashByPK(acc1Key, types.VoteSigHash(voteForSign).Bytes())
|
|
acc2SignedHash := SignHashByPK(acc2Key, types.VoteSigHash(voteForSign).Bytes())
|
|
acc3SignedHash := SignHashByPK(acc3Key, types.VoteSigHash(voteForSign).Bytes())
|
|
var signatures []types.Signature
|
|
signatures = append(signatures, signedHash, acc1SignedHash, acc2SignedHash, acc3SignedHash)
|
|
quorumCert := &types.QuorumCert{
|
|
ProposedBlockInfo: proposedBlockInfo,
|
|
Signatures: signatures,
|
|
GapNumber: 450,
|
|
}
|
|
|
|
extra := types.ExtraFields_v2{
|
|
Round: types.Round(2),
|
|
QuorumCert: quorumCert,
|
|
}
|
|
extraInBytes, err := extra.EncodeToBytes()
|
|
if err != nil {
|
|
panic(fmt.Errorf("Error encode extra into bytes: %v", err))
|
|
}
|
|
|
|
invalidRoundBlock := blockchain.GetBlockByNumber(902).Header()
|
|
invalidRoundBlock.Extra = extraInBytes
|
|
err = adaptor.VerifyHeader(blockchain, invalidRoundBlock, true)
|
|
assert.Equal(t, utils.ErrRoundInvalid, err)
|
|
|
|
// Not valid validator
|
|
coinbaseValidatorMismatchBlock := blockchain.GetBlockByNumber(902).Header()
|
|
notQualifiedSigner, notQualifiedSignFn, err := getSignerAndSignFn(voterKey)
|
|
assert.Nil(t, err)
|
|
sealHeader(blockchain, coinbaseValidatorMismatchBlock, notQualifiedSigner, notQualifiedSignFn)
|
|
err = adaptor.VerifyHeader(blockchain, coinbaseValidatorMismatchBlock, true)
|
|
assert.Equal(t, utils.ErrCoinbaseAndValidatorMismatch, err)
|
|
|
|
// Make the validators not legit by adding something to the validator
|
|
validatorsNotLegit := blockchain.GetBlockByNumber(901).Header()
|
|
validatorsNotLegit.Validators = append(validatorsNotLegit.Validators, acc1Addr[:]...)
|
|
err = adaptor.VerifyHeader(blockchain, validatorsNotLegit, true)
|
|
assert.Equal(t, utils.ErrValidatorsNotLegit, err)
|
|
|
|
// Make the penalties not legit by adding something to the penalty
|
|
penaltiesNotLegit := blockchain.GetBlockByNumber(901).Header()
|
|
penaltiesNotLegit.Penalties = append(penaltiesNotLegit.Penalties, acc1Addr[:]...)
|
|
err = adaptor.VerifyHeader(blockchain, penaltiesNotLegit, true)
|
|
assert.Equal(t, utils.ErrPenaltiesNotLegit, err)
|
|
}
|
|
|
|
func TestConfigSwitchOnDifferentCertThreshold(t *testing.T) {
|
|
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
|
assert.Nil(t, err)
|
|
configString := string(b)
|
|
|
|
var config params.ChainConfig
|
|
err = json.Unmarshal([]byte(configString), &config)
|
|
assert.Nil(t, err)
|
|
// Enable verify
|
|
config.XDPoS.V2.SkipV2Validation = false
|
|
// Block 901 is the first v2 block with round of 1
|
|
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 915, &config, nil)
|
|
|
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
|
|
|
// Genrate 911 QC
|
|
proposedBlockInfo := &types.BlockInfo{
|
|
Hash: blockchain.GetBlockByNumber(911).Hash(),
|
|
Round: types.Round(11),
|
|
Number: blockchain.GetBlockByNumber(911).Number(),
|
|
}
|
|
voteForSign := &types.VoteForSign{
|
|
ProposedBlockInfo: proposedBlockInfo,
|
|
GapNumber: 450,
|
|
}
|
|
|
|
// Sign from acc 1, 2, 3
|
|
acc1SignedHash := SignHashByPK(acc1Key, types.VoteSigHash(voteForSign).Bytes())
|
|
acc2SignedHash := SignHashByPK(acc2Key, types.VoteSigHash(voteForSign).Bytes())
|
|
acc3SignedHash := SignHashByPK(acc3Key, types.VoteSigHash(voteForSign).Bytes())
|
|
var signaturesFirst []types.Signature
|
|
signaturesFirst = append(signaturesFirst, acc1SignedHash, acc2SignedHash, acc3SignedHash)
|
|
quorumCert := &types.QuorumCert{
|
|
ProposedBlockInfo: proposedBlockInfo,
|
|
Signatures: signaturesFirst,
|
|
GapNumber: 450,
|
|
}
|
|
|
|
extra := types.ExtraFields_v2{
|
|
Round: types.Round(12),
|
|
QuorumCert: quorumCert,
|
|
}
|
|
extraInBytes, _ := extra.EncodeToBytes()
|
|
|
|
// after 910 require 4 signs, but we only give 3 signs
|
|
block912 := blockchain.GetBlockByNumber(912).Header()
|
|
block912.Extra = extraInBytes
|
|
err = adaptor.VerifyHeader(blockchain, block912, true)
|
|
|
|
assert.Equal(t, utils.ErrInvalidQCSignatures, err)
|
|
|
|
// Make we verification process use the corresponding config
|
|
// Genrate 910 QC
|
|
proposedBlockInfo = &types.BlockInfo{
|
|
Hash: blockchain.GetBlockByNumber(910).Hash(),
|
|
Round: types.Round(10),
|
|
Number: blockchain.GetBlockByNumber(910).Number(),
|
|
}
|
|
voteForSign = &types.VoteForSign{
|
|
ProposedBlockInfo: proposedBlockInfo,
|
|
GapNumber: 450,
|
|
}
|
|
|
|
// Sign from acc 1, 2, 3
|
|
acc1SignedHash = SignHashByPK(acc1Key, types.VoteSigHash(voteForSign).Bytes())
|
|
acc2SignedHash = SignHashByPK(acc2Key, types.VoteSigHash(voteForSign).Bytes())
|
|
acc3SignedHash = SignHashByPK(acc3Key, types.VoteSigHash(voteForSign).Bytes())
|
|
voteSignedHash := SignHashByPK(voterKey, types.VoteSigHash(voteForSign).Bytes())
|
|
|
|
var signaturesThr []types.Signature
|
|
signaturesThr = append(signaturesThr, acc1SignedHash, acc2SignedHash, acc3SignedHash, voteSignedHash)
|
|
quorumCert = &types.QuorumCert{
|
|
ProposedBlockInfo: proposedBlockInfo,
|
|
Signatures: signaturesThr,
|
|
GapNumber: 450,
|
|
}
|
|
|
|
extra = types.ExtraFields_v2{
|
|
Round: types.Round(11),
|
|
QuorumCert: quorumCert,
|
|
}
|
|
extraInBytes, _ = extra.EncodeToBytes()
|
|
|
|
// QC contains 910, so it requires 3 signatures, not use block number to determine which config to use
|
|
block911 := blockchain.GetBlockByNumber(911).Header()
|
|
block911.Extra = extraInBytes
|
|
err = adaptor.VerifyHeader(blockchain, block911, true)
|
|
|
|
// error ErrValidatorNotWithinMasternodes means verifyQC is passed and move to next verification process
|
|
assert.Equal(t, utils.ErrValidatorNotWithinMasternodes, err)
|
|
}
|
|
|
|
func TestConfigSwitchOnDifferentMindPeriod(t *testing.T) {
|
|
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
|
assert.Nil(t, err)
|
|
configString := string(b)
|
|
|
|
var config params.ChainConfig
|
|
err = json.Unmarshal([]byte(configString), &config)
|
|
assert.Nil(t, err)
|
|
// Enable verify
|
|
config.XDPoS.V2.SkipV2Validation = false
|
|
// Block 901 is the first v2 block with round of 1
|
|
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 915, &config, nil)
|
|
|
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
|
|
|
// Genrate 911 QC
|
|
proposedBlockInfo := &types.BlockInfo{
|
|
Hash: blockchain.GetBlockByNumber(911).Hash(),
|
|
Round: types.Round(11),
|
|
Number: blockchain.GetBlockByNumber(911).Number(),
|
|
}
|
|
voteForSign := &types.VoteForSign{
|
|
ProposedBlockInfo: proposedBlockInfo,
|
|
GapNumber: 450,
|
|
}
|
|
|
|
// Sign from acc 1, 2, 3
|
|
acc1SignedHash := SignHashByPK(acc1Key, types.VoteSigHash(voteForSign).Bytes())
|
|
acc2SignedHash := SignHashByPK(acc2Key, types.VoteSigHash(voteForSign).Bytes())
|
|
acc3SignedHash := SignHashByPK(acc3Key, types.VoteSigHash(voteForSign).Bytes())
|
|
var signaturesFirst []types.Signature
|
|
signaturesFirst = append(signaturesFirst, acc1SignedHash, acc2SignedHash, acc3SignedHash)
|
|
quorumCert := &types.QuorumCert{
|
|
ProposedBlockInfo: proposedBlockInfo,
|
|
Signatures: signaturesFirst,
|
|
GapNumber: 450,
|
|
}
|
|
|
|
extra := types.ExtraFields_v2{
|
|
Round: types.Round(12),
|
|
QuorumCert: quorumCert,
|
|
}
|
|
extraInBytes, _ := extra.EncodeToBytes()
|
|
|
|
// after 910 require 5 signs, but we only give 3 signs
|
|
block911 := blockchain.GetBlockByNumber(911).Header()
|
|
block911.Extra = extraInBytes
|
|
block911.Time = big.NewInt(blockchain.GetBlockByNumber(910).Time().Int64() + 2) //2 is previous config, should get the right config from round
|
|
err = adaptor.VerifyHeader(blockchain, block911, true)
|
|
|
|
assert.Equal(t, utils.ErrInvalidTimestamp, err)
|
|
}
|
|
|
|
func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
|
|
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
|
assert.Nil(t, err)
|
|
configString := string(b)
|
|
|
|
var config params.ChainConfig
|
|
err = json.Unmarshal([]byte(configString), &config)
|
|
assert.Nil(t, err)
|
|
// Enable verify
|
|
config.XDPoS.V2.SkipV2Validation = false
|
|
// Block 901 is the first v2 block with round of 1
|
|
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 902, &config, nil)
|
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
|
|
|
parentBlock := blockchain.GetBlockByNumber(901)
|
|
proposedBlockInfo := &types.BlockInfo{
|
|
Hash: parentBlock.Hash(),
|
|
Round: types.Round(1),
|
|
Number: parentBlock.Number(),
|
|
}
|
|
voteForSign := &types.VoteForSign{
|
|
ProposedBlockInfo: proposedBlockInfo,
|
|
GapNumber: 450,
|
|
}
|
|
signedHash, err := signFn(accounts.Account{Address: signer}, types.VoteSigHash(voteForSign).Bytes())
|
|
assert.Nil(t, err)
|
|
var signatures []types.Signature
|
|
// Duplicate the signatures
|
|
signatures = append(signatures, signedHash, signedHash, signedHash, signedHash, signedHash, signedHash)
|
|
quorumCert := &types.QuorumCert{
|
|
ProposedBlockInfo: proposedBlockInfo,
|
|
Signatures: signatures,
|
|
GapNumber: 450,
|
|
}
|
|
|
|
extra := types.ExtraFields_v2{
|
|
Round: types.Round(2),
|
|
QuorumCert: quorumCert,
|
|
}
|
|
extraInBytes, err := extra.EncodeToBytes()
|
|
if err != nil {
|
|
panic(fmt.Errorf("Error encode extra into bytes: %v", err))
|
|
}
|
|
headerWithDuplicatedSignatures := currentBlock.Header()
|
|
headerWithDuplicatedSignatures.Extra = extraInBytes
|
|
// Happy path
|
|
err = adaptor.VerifyHeader(blockchain, headerWithDuplicatedSignatures, true)
|
|
assert.Equal(t, utils.ErrInvalidQCSignatures, err)
|
|
|
|
}
|
|
|
|
func TestShouldVerifyHeaders(t *testing.T) {
|
|
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
|
assert.Nil(t, err)
|
|
configString := string(b)
|
|
|
|
var config params.ChainConfig
|
|
err = json.Unmarshal([]byte(configString), &config)
|
|
assert.Nil(t, err)
|
|
// Enable verify
|
|
config.XDPoS.V2.SkipV2Validation = false
|
|
// Block 901 is the first v2 block with round of 1
|
|
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
|
|
|
// Happy path
|
|
var happyPathHeaders []*types.Header
|
|
happyPathHeaders = append(happyPathHeaders, blockchain.GetBlockByNumber(899).Header(), blockchain.GetBlockByNumber(900).Header(), blockchain.GetBlockByNumber(901).Header(), blockchain.GetBlockByNumber(902).Header())
|
|
// Randomly set full verify
|
|
var fullVerifies []bool
|
|
fullVerifies = append(fullVerifies, false, true, true, false)
|
|
_, results := adaptor.VerifyHeaders(blockchain, happyPathHeaders, fullVerifies)
|
|
var verified []bool
|
|
for {
|
|
select {
|
|
case result := <-results:
|
|
if result != nil {
|
|
panic("Error received while verifying headers")
|
|
}
|
|
verified = append(verified, true)
|
|
case <-time.After(time.Duration(5) * time.Second): // It should be very fast to verify headers
|
|
if len(verified) == len(happyPathHeaders) {
|
|
return
|
|
} else {
|
|
panic("Suppose to have verified 3 block headers")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestShouldVerifyHeadersEvenIfParentsNotYetWrittenIntoDB(t *testing.T) {
|
|
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
|
assert.Nil(t, err)
|
|
configString := string(b)
|
|
|
|
var config params.ChainConfig
|
|
err = json.Unmarshal([]byte(configString), &config)
|
|
assert.Nil(t, err)
|
|
// Enable verify
|
|
config.XDPoS.V2.SkipV2Validation = false
|
|
// Block 901 is the first v2 block with round of 1
|
|
blockchain, _, block910, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, nil)
|
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
|
|
|
var headersTobeVerified []*types.Header
|
|
|
|
// Create block 911 but don't write into DB
|
|
blockNumber := 911
|
|
roundNumber := int64(blockNumber) - config.XDPoS.V2.SwitchBlock.Int64()
|
|
block911 := CreateBlock(blockchain, &config, block910, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil, "")
|
|
|
|
// Create block 912 and not write into DB as well
|
|
blockNumber = 912
|
|
roundNumber = int64(blockNumber) - config.XDPoS.V2.SwitchBlock.Int64()
|
|
block912 := CreateBlock(blockchain, &config, block911, blockNumber, roundNumber, signer.Hex(), signer, signFn, nil, nil, "")
|
|
|
|
headersTobeVerified = append(headersTobeVerified, block910.Header(), block911.Header(), block912.Header())
|
|
// Randomly set full verify
|
|
var fullVerifies []bool
|
|
fullVerifies = append(fullVerifies, true, true, true)
|
|
_, results := adaptor.VerifyHeaders(blockchain, headersTobeVerified, fullVerifies)
|
|
|
|
var verified []bool
|
|
for {
|
|
select {
|
|
case result := <-results:
|
|
if result != nil {
|
|
panic("Error received while verifying headers")
|
|
}
|
|
verified = append(verified, true)
|
|
case <-time.After(time.Duration(5) * time.Second): // It should be very fast to verify headers
|
|
if len(verified) == len(headersTobeVerified) {
|
|
return
|
|
} else {
|
|
panic("Suppose to have verified 3 block headers")
|
|
}
|
|
}
|
|
}
|
|
}
|