From 2f40b63ca8932e76645679516a62c33a21104871 Mon Sep 17 00:00:00 2001 From: Jerome Date: Mon, 16 May 2022 17:30:45 +1000 Subject: [PATCH] Re-define the forensics report format and complete the internal forensics logic (#90) --- consensus/XDPoS/engines/engine_v2/engine.go | 39 +---- .../XDPoS/engines/engine_v2/epochSwitch.go | 38 +++++ .../XDPoS/engines/engine_v2/forensics.go | 159 +++++++++++++----- .../XDPoS/engines/engine_v2/forensics_test.go | 78 +-------- .../tests/engine_v2_tests/forensics_test.go | 6 +- 5 files changed, 158 insertions(+), 162 deletions(-) diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index b11b39bdaf..f1cb161eb3 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -933,7 +933,7 @@ func (x *XDPoS_v2) commitBlocks(blockChainReader consensus.ChainReader, proposed // Perform forensics related operation var headerQcToBeCommitted []types.Header headerQcToBeCommitted = append(headerQcToBeCommitted, *parentBlock, *proposedBlockHeader) - go x.forensics.ForensicsMonitoring(blockChainReader, headerQcToBeCommitted, *incomingQc) + go x.forensics.ForensicsMonitoring(blockChainReader, x, headerQcToBeCommitted, *incomingQc) return true, nil } // Everything else, fail to commit @@ -954,30 +954,6 @@ func (x *XDPoS_v2) GetMasternodesFromEpochSwitchHeader(epochSwitchHeader *types. return masternodes } -func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) { - // Return true directly if we are examing the last v1 block. This could happen if the calling function is examing parent block - if header.Number.Cmp(x.config.V2.SwitchBlock) == 0 { - log.Info("[IsEpochSwitch] examing last v1 block") - return true, header.Number.Uint64() / x.config.Epoch, nil - } - - quorumCert, round, _, err := x.getExtraFields(header) - if err != nil { - log.Error("[IsEpochSwitch] decode header error", "err", err, "header", header, "extra", common.Bytes2Hex(header.Extra)) - return false, 0, err - } - parentRound := quorumCert.ProposedBlockInfo.Round - epochStartRound := round - round%utils.Round(x.config.Epoch) - epochNum := x.config.V2.SwitchBlock.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 quorumCert.ProposedBlockInfo.Number.Cmp(x.config.V2.SwitchBlock) == 0 { - log.Info("[IsEpochSwitch] true, parent equals V2.SwitchBlock", "round", round, "number", header.Number.Uint64(), "hash", header.Hash()) - return true, epochNum, nil - } - log.Info("[IsEpochSwitch]", "parent round", parentRound, "round", round, "number", header.Number.Uint64(), "hash", header.Hash()) - return parentRound < epochStartRound, epochNum, nil -} - // Given header, get master node from the epoch switch block of that epoch func (x *XDPoS_v2) GetMasternodes(chain consensus.ChainReader, header *types.Header) []common.Address { epochSwitchInfo, err := x.getEpochSwitchInfo(chain, header, header.Hash()) @@ -988,19 +964,6 @@ func (x *XDPoS_v2) GetMasternodes(chain consensus.ChainReader, header *types.Hea return epochSwitchInfo.Masternodes } -func (x *XDPoS_v2) GetCurrentEpochSwitchBlock(chain consensus.ChainReader, blockNum *big.Int) (uint64, uint64, error) { - header := chain.GetHeaderByNumber(blockNum.Uint64()) - epochSwitchInfo, err := x.getEpochSwitchInfo(chain, header, header.Hash()) - if err != nil { - log.Error("[GetCurrentEpochSwitchBlock] Fail to get epoch switch info", "Num", header.Number, "Hash", header.Hash()) - return 0, 0, err - } - - currentCheckpointNumber := epochSwitchInfo.EpochSwitchBlockInfo.Number.Uint64() - epochNum := x.config.V2.SwitchBlock.Uint64()/x.config.Epoch + uint64(epochSwitchInfo.EpochSwitchBlockInfo.Round)/x.config.Epoch - return currentCheckpointNumber, epochNum, nil -} - func (x *XDPoS_v2) calcMasternodes(chain consensus.ChainReader, blockNum *big.Int, parentHash common.Hash) ([]common.Address, []common.Address, error) { snap, err := x.getSnapshot(chain, blockNum.Uint64(), false) if err != nil { diff --git a/consensus/XDPoS/engines/engine_v2/epochSwitch.go b/consensus/XDPoS/engines/engine_v2/epochSwitch.go index 1bb195a5e9..45dc074324 100644 --- a/consensus/XDPoS/engines/engine_v2/epochSwitch.go +++ b/consensus/XDPoS/engines/engine_v2/epochSwitch.go @@ -2,6 +2,7 @@ package engine_v2 import ( "fmt" + "math/big" "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/consensus" @@ -101,3 +102,40 @@ func (x *XDPoS_v2) isEpochSwitchAtRound(round utils.Round, parentHeader *types.H epochStartRound := round - round%utils.Round(x.config.Epoch) return parentRound < epochStartRound, epochNum, nil } + +func (x *XDPoS_v2) GetCurrentEpochSwitchBlock(chain consensus.ChainReader, blockNum *big.Int) (uint64, uint64, error) { + header := chain.GetHeaderByNumber(blockNum.Uint64()) + epochSwitchInfo, err := x.getEpochSwitchInfo(chain, header, header.Hash()) + if err != nil { + log.Error("[GetCurrentEpochSwitchBlock] Fail to get epoch switch info", "Num", header.Number, "Hash", header.Hash()) + return 0, 0, err + } + + currentCheckpointNumber := epochSwitchInfo.EpochSwitchBlockInfo.Number.Uint64() + epochNum := x.config.V2.SwitchBlock.Uint64()/x.config.Epoch + uint64(epochSwitchInfo.EpochSwitchBlockInfo.Round)/x.config.Epoch + return currentCheckpointNumber, epochNum, nil +} + +func (x *XDPoS_v2) IsEpochSwitch(header *types.Header) (bool, uint64, error) { + // Return true directly if we are examing the last v1 block. This could happen if the calling function is examing parent block + if header.Number.Cmp(x.config.V2.SwitchBlock) == 0 { + log.Info("[IsEpochSwitch] examing last v1 block") + return true, header.Number.Uint64() / x.config.Epoch, nil + } + + quorumCert, round, _, err := x.getExtraFields(header) + if err != nil { + log.Error("[IsEpochSwitch] decode header error", "err", err, "header", header, "extra", common.Bytes2Hex(header.Extra)) + return false, 0, err + } + parentRound := quorumCert.ProposedBlockInfo.Round + epochStartRound := round - round%utils.Round(x.config.Epoch) + epochNum := x.config.V2.SwitchBlock.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 quorumCert.ProposedBlockInfo.Number.Cmp(x.config.V2.SwitchBlock) == 0 { + log.Info("[IsEpochSwitch] true, parent equals V2.SwitchBlock", "round", round, "number", header.Number.Uint64(), "hash", header.Hash()) + return true, epochNum, nil + } + log.Info("[IsEpochSwitch]", "parent round", parentRound, "round", round, "number", header.Number.Uint64(), "hash", header.Hash()) + return parentRound < epochStartRound, epochNum, nil +} diff --git a/consensus/XDPoS/engines/engine_v2/forensics.go b/consensus/XDPoS/engines/engine_v2/forensics.go index a09508144b..ea7c577846 100644 --- a/consensus/XDPoS/engines/engine_v2/forensics.go +++ b/consensus/XDPoS/engines/engine_v2/forensics.go @@ -17,14 +17,17 @@ const ( NUM_OF_FORENSICS_QC = 3 ) +type ForensicsInfo struct { + HashPath []string // HashesTillSmallerRoundQc or HashesTillLargerRoundQc + QuorumCert utils.QuorumCert + SignerAddresses []string +} + type ForensicProof struct { - QcWithSmallerRound utils.QuorumCert - QcWithLargerRound utils.QuorumCert - DivergingHash common.Hash - HashesTillSmallerRoundQc []common.Hash - HashesTillLargerRoundQc []common.Hash - AcrossEpochs bool - Attackers []common.Address + SmallerRoundInfo *ForensicsInfo + LargerRoundInfo *ForensicsInfo + DivergingHash common.Hash + AcrossEpochs bool } // Forensics instance. Placeholder for future properties to be added @@ -37,8 +40,8 @@ func NewForensics() *Forensics { return &Forensics{} } -func (f *Forensics) ForensicsMonitoring(chain consensus.ChainReader, headerQcToBeCommitted []types.Header, incomingQC utils.QuorumCert) error { - f.ProcessForensics(chain, incomingQC) +func (f *Forensics) ForensicsMonitoring(chain consensus.ChainReader, engine *XDPoS_v2, headerQcToBeCommitted []types.Header, incomingQC utils.QuorumCert) error { + f.ProcessForensics(chain, engine, incomingQC) return f.SetCommittedQCs(headerQcToBeCommitted, incomingQC) } @@ -83,7 +86,7 @@ func (f *Forensics) SetCommittedQCs(headers []types.Header, incomingQC utils.Quo Forensics runs in a seperate go routine as its no system critical Link to the flow diagram: https://hashlabs.atlassian.net/wiki/spaces/HASHLABS/pages/97878029/Forensics+Diagram+flow */ -func (f *Forensics) ProcessForensics(chain consensus.ChainReader, incomingQC utils.QuorumCert) error { +func (f *Forensics) ProcessForensics(chain consensus.ChainReader, engine *XDPoS_v2, incomingQC utils.QuorumCert) error { log.Debug("Received a QC in forensics", "QC", incomingQC) // Clone the values to a temporary variable highestCommittedQCs := f.HighestCommittedQCs @@ -110,25 +113,62 @@ func (f *Forensics) ProcessForensics(chain consensus.ChainReader, incomingQC uti foundSameRoundQC, sameRoundHCQC, sameRoundQC := f.findQCsInSameRound(highestCommittedQCs, incomingQuorunCerts) if foundSameRoundQC { - attackersAddress := f.findCommonSigners(sameRoundHCQC, sameRoundQC) - f.SendForensicProof(attackersAddress, sameRoundHCQC, sameRoundQC) + f.SendForensicProof(chain, engine, sameRoundHCQC, sameRoundQC) } else { // Not found, need a more complex approach to find the two QC ancestorQC, lowerRoundQCs, _, err := f.findAncestorQcThroughRound(chain, highestCommittedQCs, incomingQuorunCerts) if err != nil { log.Error("[ProcessForensics] Error while trying to find ancestor QC through round number", "Error", err) } - // Find the common signers within ancestorQC and lowerRoundQCs[NUM_OF_FORENSICS_QC-1] - attackersAddress := f.findCommonSigners(ancestorQC, lowerRoundQCs[NUM_OF_FORENSICS_QC-1]) - f.SendForensicProof(attackersAddress, ancestorQC, lowerRoundQCs[NUM_OF_FORENSICS_QC-1]) + f.SendForensicProof(chain, engine, ancestorQC, lowerRoundQCs[NUM_OF_FORENSICS_QC-1]) } return nil } // Last step of forensics which sends out detailed proof to report service. -func (f *Forensics) SendForensicProof(attackersAddress []common.Address, lqc utils.QuorumCert, hqc utils.QuorumCert) { +func (f *Forensics) SendForensicProof(chain consensus.ChainReader, engine *XDPoS_v2, firstQc utils.QuorumCert, secondQc utils.QuorumCert) error { + // Re-order the QC by its round number to make the function cleaner. + lowerRoundQC := firstQc + higherRoundQC := secondQc + if (secondQc.ProposedBlockInfo.Round - firstQc.ProposedBlockInfo.Round) < 0 { + lowerRoundQC = secondQc + higherRoundQC = firstQc + } + + // Find common ancestor block + ancestorHash, ancestorToLowerRoundPath, ancestorToHigherRoundPath, err := f.FindAncestorBlockHash(chain, lowerRoundQC.ProposedBlockInfo, higherRoundQC.ProposedBlockInfo) + if err != nil { + log.Error("[SendForensicProof] Error while trying to find ancestor block hash", err) + return err + } + + // Check if two QCs are across epoch, this is used as a indicator for the "prone to attack" scenario + lowerRoundQcEpochSwitchInfo, err := engine.getEpochSwitchInfo(chain, nil, lowerRoundQC.ProposedBlockInfo.Hash) + higherRoundQcEpochSwitchInfo, err := engine.getEpochSwitchInfo(chain, nil, higherRoundQC.ProposedBlockInfo.Hash) + accrossEpoches := false + if lowerRoundQcEpochSwitchInfo.EpochSwitchBlockInfo.Hash != higherRoundQcEpochSwitchInfo.EpochSwitchBlockInfo.Hash { + accrossEpoches = true + } + + forensicsProof := &ForensicProof{ + DivergingHash: ancestorHash, + AcrossEpochs: accrossEpoches, + SmallerRoundInfo: &ForensicsInfo{ + HashPath: ancestorToLowerRoundPath, + QuorumCert: lowerRoundQC, + SignerAddresses: f.getQcSignerAddresses(lowerRoundQC), + }, + LargerRoundInfo: &ForensicsInfo{ + HashPath: ancestorToHigherRoundPath, + QuorumCert: higherRoundQC, + SignerAddresses: f.getQcSignerAddresses(higherRoundQC), + }, + } + // TODO: send to dedicated channel which will redirect to stats server + log.Info("Forensics proof report generated, sending to the stats server", forensicsProof) + return nil } // Utils function to help find the n-th previous QC. It returns an array of QC in ascending order including the currentQc as the last item in the array @@ -177,7 +217,7 @@ func (f *Forensics) checkQCsOnTheSameChain(chain consensus.ChainReader, highestC var decodedExtraField utils.ExtraFields_v2 err := utils.DecodeBytesExtraFields(parentHeader.Extra, &decodedExtraField) if err != nil { - log.Error("[ProcessForensics] Fail to decode extra when checking the two QCs set on the same chain", "Error", err) + log.Error("[checkQCsOnTheSameChain] Fail to decode extra when checking the two QCs set on the same chain", "Error", err) return false, err } proposedBlockInfo = decodedExtraField.QuorumCert.ProposedBlockInfo @@ -202,43 +242,26 @@ func (f *Forensics) findQCsInSameRound(quorumCerts1 []utils.QuorumCert, quorumCe return false, utils.QuorumCert{}, utils.QuorumCert{} } -// Find the common address that have signed both QCs -func (f *Forensics) findCommonSigners(quorumCert1 utils.QuorumCert, quorumCert2 utils.QuorumCert) []common.Address { - var commonSigners []common.Address - quorumCert1SignersMap := make(map[string]bool) +// Find the signer list from QC signatures +func (f *Forensics) getQcSignerAddresses(quorumCert utils.QuorumCert) []string { + var signerList []string + // The QC signatures are signed by votes special struct VoteForSign - quorumCert1SignedHash := utils.VoteSigHash(&utils.VoteForSign{ - ProposedBlockInfo: quorumCert1.ProposedBlockInfo, - GapNumber: quorumCert1.GapNumber, + quorumCertSignedHash := utils.VoteSigHash(&utils.VoteForSign{ + ProposedBlockInfo: quorumCert.ProposedBlockInfo, + GapNumber: quorumCert.GapNumber, }) - for _, signature := range quorumCert1.Signatures { + for _, signature := range quorumCert.Signatures { var signerAddress common.Address - pubkey, err := crypto.Ecrecover(quorumCert1SignedHash.Bytes(), signature) + pubkey, err := crypto.Ecrecover(quorumCertSignedHash.Bytes(), signature) if err != nil { - log.Error("[findCommonSigners] Fail to Ecrecover signer from the quorumCert1SignedHash", "quorumCert1.GapNumber", quorumCert1.GapNumber, "quorumCert1.ProposedBlockInfo", quorumCert1.ProposedBlockInfo) + log.Error("[getQcSignerAddresses] Fail to Ecrecover signer from the quorumCertSignedHash", "quorumCert.GapNumber", quorumCert.GapNumber, "quorumCert.ProposedBlockInfo", quorumCert.ProposedBlockInfo) } copy(signerAddress[:], crypto.Keccak256(pubkey[1:])[12:]) - quorumCert1SignersMap[signerAddress.Hex()] = true + signerList = append(signerList, signerAddress.Hex()) } - // Now, Let's check if quorumCert2 have any signers that have in common with quorumCert1SignersMap(from quorumCert1) - quorumCert2SignedHash := utils.VoteSigHash(&utils.VoteForSign{ - ProposedBlockInfo: quorumCert2.ProposedBlockInfo, - GapNumber: quorumCert2.GapNumber, - }) - for _, signature := range quorumCert2.Signatures { - var signerAddress common.Address - pubkey, err := crypto.Ecrecover(quorumCert2SignedHash.Bytes(), signature) - if err != nil { - log.Error("[findCommonSigners] Fail to Ecrecover signer from the quorumCert2SignedHash", "quorumCert2.GapNumber", quorumCert2.GapNumber, "quorumCert2.ProposedBlockInfo", quorumCert2.ProposedBlockInfo) - } - - copy(signerAddress[:], crypto.Keccak256(pubkey[1:])[12:]) - if quorumCert1SignersMap[signerAddress.Hex()] { - commonSigners = append(commonSigners, signerAddress) - } - } - return commonSigners + return signerList } // Check whether the given QCs are on the same chain as the stored committed QCs(f.HighestCommittedQCs) regardless their orders @@ -271,3 +294,47 @@ func (f *Forensics) findAncestorQcThroughRound(chain consensus.ChainReader, high } return ancestorQC, lowerRoundQCs, higherRoundQCs, fmt.Errorf("[findAncestorQcThroughRound] Could not find ancestor QC") } + +func (f *Forensics) FindAncestorBlockHash(chain consensus.ChainReader, firstBlockInfo *utils.BlockInfo, secondBlockInfo *utils.BlockInfo) (common.Hash, []string, []string, error) { + // Re-arrange by block number + lowerBlockNumHash := firstBlockInfo.Hash + higherBlockNumberHash := secondBlockInfo.Hash + + var ancestorToLowerBlockNumHashPath []string + var ancestorToHigherBlockNumHashPath []string + orderSwapped := false + + blockNumberDifference := big.NewInt(0).Sub(secondBlockInfo.Number, firstBlockInfo.Number).Int64() + if blockNumberDifference < 0 { + lowerBlockNumHash = secondBlockInfo.Hash + higherBlockNumberHash = firstBlockInfo.Hash + blockNumberDifference = -blockNumberDifference // and make it positive + orderSwapped = true + } + ancestorToLowerBlockNumHashPath = append(ancestorToLowerBlockNumHashPath, lowerBlockNumHash.Hex()) + ancestorToHigherBlockNumHashPath = append(ancestorToHigherBlockNumHashPath, higherBlockNumberHash.Hex()) + + // First, make their block number the same to start with + for i := 0; i < int(blockNumberDifference); i++ { + ph := chain.GetHeaderByHash(higherBlockNumberHash) + if ph == nil { + return common.Hash{}, ancestorToLowerBlockNumHashPath, ancestorToHigherBlockNumHashPath, fmt.Errorf("Unable to find parent block of hash %v", higherBlockNumberHash) + } + higherBlockNumberHash = ph.ParentHash + ancestorToHigherBlockNumHashPath = append(ancestorToHigherBlockNumHashPath, ph.ParentHash.Hex()) + } + + // Now, they are on the same starting line, we try find the common ancestor + for lowerBlockNumHash.Hex() != higherBlockNumberHash.Hex() { + lowerBlockNumHash = chain.GetHeaderByHash(lowerBlockNumHash).ParentHash + higherBlockNumberHash = chain.GetHeaderByHash(higherBlockNumberHash).ParentHash + // Append the path + ancestorToLowerBlockNumHashPath = append(ancestorToLowerBlockNumHashPath, lowerBlockNumHash.Hex()) + ancestorToHigherBlockNumHashPath = append(ancestorToHigherBlockNumHashPath, higherBlockNumberHash.Hex()) + } + // Swap back the order. We must return in the order that matches what we acceptted in the parameter of firstBlock & secondBlock + if orderSwapped { + return lowerBlockNumHash, ancestorToHigherBlockNumHashPath, ancestorToLowerBlockNumHashPath, nil + } + return lowerBlockNumHash, ancestorToLowerBlockNumHashPath, ancestorToHigherBlockNumHashPath, nil +} diff --git a/consensus/XDPoS/engines/engine_v2/forensics_test.go b/consensus/XDPoS/engines/engine_v2/forensics_test.go index 9ccd4239c2..358beda50e 100644 --- a/consensus/XDPoS/engines/engine_v2/forensics_test.go +++ b/consensus/XDPoS/engines/engine_v2/forensics_test.go @@ -67,81 +67,6 @@ func getSignerAndSignFn(pk *ecdsa.PrivateKey) (common.Address, func(account acco return a1.Address, ks.SignHash, nil } -func TestFindCommonSigners(t *testing.T) { - forensics := &Forensics{} - proposedBlockInfo := &utils.BlockInfo{ - Hash: common.StringToHash("123"), - Round: utils.Round(10), - Number: big.NewInt(910), - } - gapNumber := 450 - voteForSign := &utils.VoteForSign{ - ProposedBlockInfo: proposedBlockInfo, - GapNumber: uint64(gapNumber), - } - signatureFromSigner1 := SignHashByPK(signer1, utils.VoteSigHash(voteForSign).Bytes()) - signatureFromSigner2 := SignHashByPK(signer2, utils.VoteSigHash(voteForSign).Bytes()) - signatureFromSigner3 := SignHashByPK(signer3, utils.VoteSigHash(voteForSign).Bytes()) - - // If ONE in common - var signaturesForQC1 []utils.Signature - qc1 := &utils.QuorumCert{ - ProposedBlockInfo: proposedBlockInfo, - Signatures: append(signaturesForQC1, signatureFromSigner1, signatureFromSigner2), - GapNumber: uint64(gapNumber), - } - - var signaturesForQC2 []utils.Signature - qc2 := &utils.QuorumCert{ - ProposedBlockInfo: proposedBlockInfo, - Signatures: append(signaturesForQC2, signatureFromSigner2, signatureFromSigner3), - GapNumber: uint64(gapNumber), - } - - commonSigners := forensics.findCommonSigners(*qc1, *qc2) - assert.Equal(t, 1, len(commonSigners)) - assert.Equal(t, crypto.PubkeyToAddress(signer2.PublicKey), commonSigners[0]) - - // If none in common - var signaturesForQC1NoneInCommon []utils.Signature - qc1 = &utils.QuorumCert{ - ProposedBlockInfo: proposedBlockInfo, - Signatures: append(signaturesForQC1NoneInCommon, signatureFromSigner1), - GapNumber: uint64(gapNumber), - } - - var signaturesForQC2NoneInCommon []utils.Signature - qc2 = &utils.QuorumCert{ - ProposedBlockInfo: proposedBlockInfo, - Signatures: append(signaturesForQC2NoneInCommon, signatureFromSigner2, signatureFromSigner3), - GapNumber: uint64(gapNumber), - } - - commonSigners = forensics.findCommonSigners(*qc1, *qc2) - assert.Equal(t, 0, len(commonSigners)) - - // All in common - var signaturesForQC1AllInCommon []utils.Signature - qc1 = &utils.QuorumCert{ - ProposedBlockInfo: proposedBlockInfo, - Signatures: append(signaturesForQC1AllInCommon, signatureFromSigner1, signatureFromSigner2, signatureFromSigner3), - GapNumber: uint64(gapNumber), - } - - var signaturesForQC2AllInCommon []utils.Signature - qc2 = &utils.QuorumCert{ - ProposedBlockInfo: proposedBlockInfo, - Signatures: append(signaturesForQC2AllInCommon, signatureFromSigner1, signatureFromSigner2, signatureFromSigner3), - GapNumber: uint64(gapNumber), - } - - commonSigners = forensics.findCommonSigners(*qc1, *qc2) - assert.Equal(t, 3, len(commonSigners)) - assert.Equal(t, crypto.PubkeyToAddress(signer1.PublicKey), commonSigners[0]) - assert.Equal(t, crypto.PubkeyToAddress(signer2.PublicKey), commonSigners[1]) - assert.Equal(t, crypto.PubkeyToAddress(signer3.PublicKey), commonSigners[2]) -} - func TestFindQCsInSameRound(t *testing.T) { forensics := &Forensics{} gapNumber := 450 @@ -216,3 +141,6 @@ func TestFindQCsInSameRound(t *testing.T) { assert.Equal(t, *qc2, first) assert.Equal(t, *qc4, second) } + +// TODO: Add test for FindAncestorBlockHash +// TODO: Add test for SendForensicProof diff --git a/consensus/tests/engine_v2_tests/forensics_test.go b/consensus/tests/engine_v2_tests/forensics_test.go index d96165487f..9bfddd00d6 100644 --- a/consensus/tests/engine_v2_tests/forensics_test.go +++ b/consensus/tests/engine_v2_tests/forensics_test.go @@ -125,7 +125,7 @@ func TestForensicsMonitoring(t *testing.T) { assert.Nil(t, err) var newIncomingQcHeaders []types.Header newIncomingQcHeaders = append(newIncomingQcHeaders, *blockchain.GetHeaderByNumber(913), *blockchain.GetHeaderByNumber(914)) - err = forensics.ForensicsMonitoring(blockchain, newIncomingQcHeaders, *incomingQC) + err = forensics.ForensicsMonitoring(blockchain, blockchain.Engine().(*XDPoS.XDPoS).EngineV2, newIncomingQcHeaders, *incomingQC) assert.Nil(t, err) } @@ -156,7 +156,7 @@ func TestForensicsMonitoringNotOnSameChainButHaveSameRoundQC(t *testing.T) { parentOfForkedHeader := blockchain.GetBlockByHash(currentForkBlock.ParentHash()).Header() grandParentOfForkedHeader := blockchain.GetBlockByHash(parentOfForkedHeader.ParentHash).Header() forkedHeaders = append(forkedHeaders, *grandParentOfForkedHeader, *parentOfForkedHeader) - err = forensics.ForensicsMonitoring(blockchain, forkedHeaders, *incomingQC) + err = forensics.ForensicsMonitoring(blockchain, blockchain.Engine().(*XDPoS.XDPoS).EngineV2, forkedHeaders, *incomingQC) assert.Nil(t, err) // TODO: Check SendForensicProof triggered } @@ -190,7 +190,7 @@ func TestForensicsMonitoringNotOnSameChainDoNotHaveSameRoundQC(t *testing.T) { grandParentOfForkedHeader := blockchain.GetBlockByHash(parentOfForkedHeader.ParentHash).Header() forkedHeaders = append(forkedHeaders, *grandParentOfForkedHeader, *parentOfForkedHeader) - err = forensics.ForensicsMonitoring(blockchain, forkedHeaders, *incomingQC) + err = forensics.ForensicsMonitoring(blockchain, blockchain.Engine().(*XDPoS.XDPoS).EngineV2, forkedHeaders, *incomingQC) assert.Nil(t, err) // TODO: Check SendForensicProof triggered }