diff --git a/consensus/XDPoS/engines/engine_v2/epochSwitch.go b/consensus/XDPoS/engines/engine_v2/epochSwitch.go index 8f718de0bec8..907f1071990f 100644 --- a/consensus/XDPoS/engines/engine_v2/epochSwitch.go +++ b/consensus/XDPoS/engines/engine_v2/epochSwitch.go @@ -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{ diff --git a/consensus/XDPoS/engines/engine_v2/timeout.go b/consensus/XDPoS/engines/engine_v2/timeout.go index 2f077b2a0018..86647850c362 100644 --- a/consensus/XDPoS/engines/engine_v2/timeout.go +++ b/consensus/XDPoS/engines/engine_v2/timeout.go @@ -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)) } } + 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 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, chain.CurrentHeader(), chain.CurrentHeader().Hash()) + epochInfo, err := x.getEpochSwitchInfo(chain, nil, epochBlockInfo.Hash) if err != nil { - log.Error("[verifyTC] Error when getting epoch switch Info", "error", err) + 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 { diff --git a/consensus/tests/engine_v2_tests/sync_info_test.go b/consensus/tests/engine_v2_tests/sync_info_test.go index 8219b37a4e15..e3ac910b235b 100644 --- a/consensus/tests/engine_v2_tests/sync_info_test.go +++ b/consensus/tests/engine_v2_tests/sync_info_test.go @@ -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) +} diff --git a/core/types/consensus_v2.go b/core/types/consensus_v2.go index 8dae6aaa0728..f69892532dea 100644 --- a/core/types/consensus_v2.go +++ b/core/types/consensus_v2.go @@ -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 diff --git a/params/version.go b/params/version.go index 45407ecbb3e9..23a1aad9acc8 100644 --- a/params/version.go +++ b/params/version.go @@ -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 )