mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-22 22:54:33 +00:00
Re-define the forensics report format and complete the internal forensics logic (#90)
This commit is contained in:
parent
ba144d898f
commit
2f40b63ca8
5 changed files with 158 additions and 162 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue