mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
Merge pull request #770 from XinFinOrg/fix-tc-cross-epoch-different-masternode-counts-issue
Fix tc cross epoch different masternode counts issue
This commit is contained in:
commit
b2a41afb87
5 changed files with 147 additions and 13 deletions
|
|
@ -152,7 +152,7 @@ func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) {
|
|||
log.Info("[IsEpochSwitch] true, parent equals V2.SwitchBlock", "round", round, "number", header.Number.Uint64(), "hash", header.Hash())
|
||||
return true, epochNum, nil
|
||||
}
|
||||
log.Debug("[IsEpochSwitch]", "is", parentRound < epochStartRound, "parentRound", parentRound, "round", round, "number", header.Number.Uint64(), "epochNum", epochNum, "hash", header.Hash())
|
||||
log.Debug("[IsEpochSwitch]", "is", parentRound < epochStartRound, "parentRound", parentRound, "round", round, "number", header.Number.Uint64(), "epochNum", epochNum, "hash", header.Hash().Hex())
|
||||
// if isEpochSwitch, add to cache
|
||||
if parentRound < epochStartRound {
|
||||
x.round2epochBlockInfo.Add(round, &types.BlockInfo{
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
|||
|
||||
snap, err := x.getSnapshot(chain, timeoutCert.GapNumber, true)
|
||||
if err != nil {
|
||||
log.Error("[verifyTC] Fail to get snapshot when verifying TC!", "TCGapNumber", timeoutCert.GapNumber)
|
||||
log.Error("[verifyTC] Fail to get snapshot when verifying TC!", "tcGapNumber", timeoutCert.GapNumber)
|
||||
return fmt.Errorf("[verifyTC] Unable to get snapshot, %s", err)
|
||||
}
|
||||
if snap == nil || len(snap.NextEpochCandidates) == 0 {
|
||||
|
|
@ -109,16 +109,22 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
|||
log.Warn("[verifyQC] duplicated signature in QC", "duplicate", common.Bytes2Hex(d))
|
||||
}
|
||||
}
|
||||
|
||||
epochInfo, err := x.getEpochSwitchInfo(chain, chain.CurrentHeader(), chain.CurrentHeader().Hash())
|
||||
tcEpoch := x.config.V2.SwitchBlock.Uint64()/x.config.Epoch + uint64(timeoutCert.Round)/x.config.Epoch
|
||||
epochBlockInfo, err := x.GetBlockByEpochNumber(chain, tcEpoch)
|
||||
if err != nil {
|
||||
log.Error("[verifyTC] Error when getting epoch switch Info", "error", err)
|
||||
log.Error("[verifyTC] Error when getting epoch block info by tc round", "error", err)
|
||||
return fmt.Errorf("fail on verifyTC due to failure in getting epoch block info tc round, %s", err)
|
||||
}
|
||||
|
||||
epochInfo, err := x.getEpochSwitchInfo(chain, nil, epochBlockInfo.Hash)
|
||||
if err != nil {
|
||||
log.Error("[verifyTC] Error when getting epoch switch info", "error", err)
|
||||
return fmt.Errorf("fail on verifyTC due to failure in getting epoch switch info, %s", err)
|
||||
}
|
||||
|
||||
certThreshold := x.config.V2.Config(uint64(timeoutCert.Round)).CertThreshold
|
||||
if float64(len(signatures)) < float64(epochInfo.MasternodesLen)*certThreshold {
|
||||
log.Warn("[verifyTC] Invalid TC Signature is nil or empty", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(timeoutCert.Signatures), "CertThreshold", float64(epochInfo.MasternodesLen)*certThreshold)
|
||||
log.Warn("[verifyTC] Invalid TC Signature is less or empty", "tcRound", timeoutCert.Round, "tcGapNumber", timeoutCert.GapNumber, "tcSignLen", len(timeoutCert.Signatures), "certThreshold", float64(epochInfo.MasternodesLen)*certThreshold)
|
||||
return utils.ErrInvalidTCSignatures
|
||||
}
|
||||
|
||||
|
|
@ -138,14 +144,14 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
|||
defer wg.Done()
|
||||
verified, _, err := x.verifyMsgSignature(signedTimeoutObj, sig, snap.NextEpochCandidates)
|
||||
if err != nil || !verified {
|
||||
log.Error("[verifyTC] Error or verification failure", "Signature", sig, "Error", err)
|
||||
log.Error("[verifyTC] Error or verification failure", "signature", sig, "error", err)
|
||||
mutex.Lock() // Lock before accessing haveError
|
||||
if haveError == nil {
|
||||
if err != nil {
|
||||
log.Error("[verifyTC] Error while verfying TC message signatures", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(signatures), "Error", err)
|
||||
log.Error("[verifyTC] Error while verfying TC message signatures", "tcRound", timeoutCert.Round, "tcGapNumber", timeoutCert.GapNumber, "tcSignLen", len(signatures), "error", err)
|
||||
haveError = fmt.Errorf("error while verifying TC message signatures, %s", err)
|
||||
} else {
|
||||
log.Warn("[verifyTC] Signature not verified doing TC verification", "timeoutCert.Round", timeoutCert.Round, "timeoutCert.GapNumber", timeoutCert.GapNumber, "Signatures len", len(signatures))
|
||||
log.Warn("[verifyTC] Signature not verified doing TC verification", "tcRound", timeoutCert.Round, "tcGapNumber", timeoutCert.GapNumber, "tcSignLen", len(signatures))
|
||||
haveError = errors.New("fail to verify TC due to signature mis-match")
|
||||
}
|
||||
}
|
||||
|
|
@ -219,6 +225,8 @@ func (x *XDPoS_v2) sendTimeout(chain consensus.ChainReader) error {
|
|||
Signature: signedHash,
|
||||
GapNumber: gapNumber,
|
||||
}
|
||||
|
||||
timeoutMsg.SetSigner(x.signer)
|
||||
log.Warn("[sendTimeout] Timeout message generated, ready to send!", "timeoutMsgRound", timeoutMsg.Round, "timeoutMsgGapNumber", timeoutMsg.GapNumber, "whosTurn", x.whosTurn)
|
||||
err = x.timeoutHandler(chain, timeoutMsg)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package engine_v2_tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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"
|
||||
|
|
@ -100,3 +102,127 @@ func TestSkipVerifySyncInfoIfBothQcTcNotQualified(t *testing.T) {
|
|||
assert.False(t, verified)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestVerifySyncInfoIfTcUseDifferentEpoch(t *testing.T) {
|
||||
config := params.TestXDPoSMockChainConfig
|
||||
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 1349, config, nil)
|
||||
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||
x := adaptor.EngineV2
|
||||
|
||||
// Insert block 1350
|
||||
t.Logf("Inserting block with propose at 1350...")
|
||||
blockCoinbaseA := "0xaaa0000000000000000000000000000000001350"
|
||||
// NOTE: voterAddr never exist in the Masternode list, but all acc1,2,3 already does
|
||||
tx, err := voteTX(37117, 0, signer.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
//Get from block validator error message
|
||||
merkleRoot := "8a355a8636d1aae24d5a63df0318534e09110891d6ab7bf20587da64725083be"
|
||||
header := &types.Header{
|
||||
Root: common.HexToHash(merkleRoot),
|
||||
Number: big.NewInt(int64(1350)),
|
||||
ParentHash: currentBlock.Hash(),
|
||||
Coinbase: common.HexToAddress(blockCoinbaseA),
|
||||
}
|
||||
|
||||
header.Extra = generateV2Extra(450, currentBlock, signer, signFn, nil)
|
||||
|
||||
parentBlock, err := createBlockFromHeader(blockchain, header, []*types.Transaction{tx}, signer, signFn, config)
|
||||
assert.Nil(t, err)
|
||||
err = blockchain.InsertBlock(parentBlock)
|
||||
assert.Nil(t, err)
|
||||
// 1350 is a gap block, need to update the snapshot
|
||||
err = blockchain.UpdateM1()
|
||||
assert.Nil(t, err)
|
||||
t.Logf("Inserting block from 1351 to 1799...")
|
||||
for i := 1351; i <= 1799; i++ {
|
||||
blockCoinbase := fmt.Sprintf("0xaaa000000000000000000000000000000000%4d", i)
|
||||
//Get from block validator error message
|
||||
header = &types.Header{
|
||||
Root: common.HexToHash(merkleRoot),
|
||||
Number: big.NewInt(int64(i)),
|
||||
ParentHash: parentBlock.Hash(),
|
||||
Coinbase: common.HexToAddress(blockCoinbase),
|
||||
}
|
||||
|
||||
header.Extra = generateV2Extra(int64(i)-900, parentBlock, signer, signFn, nil)
|
||||
|
||||
block, err := createBlockFromHeader(blockchain, header, nil, signer, signFn, config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = blockchain.InsertBlock(block)
|
||||
assert.Nil(t, err)
|
||||
parentBlock = block
|
||||
}
|
||||
t.Logf("build epoch block with new set of masternodes")
|
||||
blockCoinbase := fmt.Sprintf("0xaaa0000000000000000000000000000000001800")
|
||||
//Get from block validator error message
|
||||
header = &types.Header{
|
||||
Root: common.HexToHash(merkleRoot),
|
||||
Number: big.NewInt(int64(1800)),
|
||||
ParentHash: parentBlock.Hash(),
|
||||
Coinbase: common.HexToAddress(blockCoinbase),
|
||||
}
|
||||
|
||||
header.Extra = generateV2Extra(900, parentBlock, signer, signFn, nil)
|
||||
validators := []byte{}
|
||||
|
||||
snap, err := x.GetSnapshot(blockchain, parentBlock.Header())
|
||||
assert.Nil(t, err)
|
||||
|
||||
for _, v := range snap.NextEpochCandidates {
|
||||
validators = append(validators, v[:]...)
|
||||
}
|
||||
// set up 1 more masternode to make it difference
|
||||
validators = append(validators, voterAddr[:]...)
|
||||
header.Validators = validators
|
||||
block, err := createBlockFromHeader(blockchain, header, nil, signer, signFn, config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = blockchain.InsertBlock(block)
|
||||
assert.Nil(t, err)
|
||||
parentBlock = block
|
||||
|
||||
var extraField types.ExtraFields_v2
|
||||
err = utils.DecodeBytesExtraFields(parentBlock.Extra(), &extraField)
|
||||
if err != nil {
|
||||
t.Fatal("Fail to decode extra data", err)
|
||||
}
|
||||
|
||||
timeoutForSign := &types.TimeoutForSign{
|
||||
Round: types.Round(899),
|
||||
GapNumber: 450,
|
||||
}
|
||||
|
||||
// Sign from acc 1, 2, 3 and voter
|
||||
acc1SignedHash := SignHashByPK(acc1Key, types.TimeoutSigHash(timeoutForSign).Bytes())
|
||||
acc2SignedHash := SignHashByPK(acc2Key, types.TimeoutSigHash(timeoutForSign).Bytes())
|
||||
acc3SignedHash := SignHashByPK(acc3Key, types.TimeoutSigHash(timeoutForSign).Bytes())
|
||||
voterSignedHash := SignHashByPK(voterKey, types.TimeoutSigHash(timeoutForSign).Bytes())
|
||||
|
||||
var signatures []types.Signature
|
||||
signatures = append(signatures, acc1SignedHash, acc2SignedHash, acc3SignedHash, voterSignedHash)
|
||||
|
||||
newTC := &types.TimeoutCert{
|
||||
Round: timeoutForSign.Round,
|
||||
Signatures: signatures,
|
||||
GapNumber: timeoutForSign.GapNumber,
|
||||
}
|
||||
|
||||
syncInfoMsg := &types.SyncInfo{
|
||||
HighestQuorumCert: extraField.QuorumCert,
|
||||
HighestTimeoutCert: newTC,
|
||||
}
|
||||
|
||||
x.SetPropertiesFaker(syncInfoMsg.HighestQuorumCert, &types.TimeoutCert{
|
||||
Round: types.Round(898),
|
||||
Signatures: []types.Signature{},
|
||||
})
|
||||
|
||||
verified, err := x.VerifySyncInfoMessage(blockchain, syncInfoMsg)
|
||||
assert.True(t, verified)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ type BlockInfo struct {
|
|||
|
||||
// Vote message in XDPoS 2.0
|
||||
type Vote struct {
|
||||
signer common.Address //field not exported
|
||||
signer common.Address //field not exported
|
||||
ProposedBlockInfo *BlockInfo `json:"proposedBlockInfo"`
|
||||
Signature Signature `json:"signature"`
|
||||
GapNumber uint64 `json:"gapNumber"`
|
||||
|
|
@ -81,9 +81,9 @@ func (s *SyncInfo) Hash() common.Hash {
|
|||
|
||||
// Quorum Certificate struct in XDPoS 2.0
|
||||
type QuorumCert struct {
|
||||
ProposedBlockInfo *BlockInfo `json:"proposedBlockInfo"`
|
||||
ProposedBlockInfo *BlockInfo `json:"proposedBlockInfo"`
|
||||
Signatures []Signature `json:"signatures"`
|
||||
GapNumber uint64 `json:"gapNumber"`
|
||||
GapNumber uint64 `json:"gapNumber"`
|
||||
}
|
||||
|
||||
// Timeout Certificate struct in XDPoS 2.0
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import (
|
|||
const (
|
||||
VersionMajor = 2 // Major version component of the current release
|
||||
VersionMinor = 4 // Minor version component of the current release
|
||||
VersionPatch = 4 // Patch version component of the current release
|
||||
VersionPatch = 5 // Patch version component of the current release
|
||||
VersionMeta = "beta1" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue