From 6c48d5be6cf2b0792b5645246b5792cd881027ae Mon Sep 17 00:00:00 2001 From: Jerome Date: Sun, 10 Apr 2022 09:40:32 +1000 Subject: [PATCH] Xin 181 178 (#80) * add skeleton forensics * remove duplicated penalty check in verify header --- consensus/XDPoS/engines/engine_v2/engine.go | 4 ++ .../XDPoS/engines/engine_v2/forensics.go | 52 +++++++++++++++++++ .../XDPoS/engines/engine_v2/verifyHeader.go | 25 ++++----- consensus/XDPoS/utils/errors.go | 3 +- .../engine_v2_tests/verify_header_test.go | 13 ++--- 5 files changed, 70 insertions(+), 27 deletions(-) create mode 100644 consensus/XDPoS/engines/engine_v2/forensics.go diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index c1eb7ebbf5..bdd0c18472 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -57,6 +57,8 @@ type XDPoS_v2 struct { HookReward func(chain consensus.ChainReader, state *state.StateDB, parentState *state.StateDB, header *types.Header) (map[string]interface{}, error) HookPenalty func(chain consensus.ChainReader, number *big.Int, parentHash common.Hash, candidates []common.Address) ([]common.Address, error) + + forensics *Forensics } func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *XDPoS_v2 { @@ -110,6 +112,8 @@ func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) * timeoutTimer.OnTimeoutFn = engine.OnCountdownTimeout engine.periodicJob() + + engine.AttachForensics() return engine } diff --git a/consensus/XDPoS/engines/engine_v2/forensics.go b/consensus/XDPoS/engines/engine_v2/forensics.go new file mode 100644 index 0000000000..29108c69a4 --- /dev/null +++ b/consensus/XDPoS/engines/engine_v2/forensics.go @@ -0,0 +1,52 @@ +package engine_v2 + +import ( + "github.com/XinFinOrg/XDPoSChain/common" + "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils" + "github.com/XinFinOrg/XDPoSChain/log" +) + +type ForensicProof struct { + QcWithSmallerRound utils.QuorumCert + QcWithLargerRound utils.QuorumCert + DivergingHash common.Hash + HashesTillSmallerRoundQc []common.Hash + HashesTillLargerRoundQc []common.Hash + AcrossEpochs bool + QcWithSmallerRoundAddresses []common.Address + QcWithLargerRoundAddresses []common.Address +} + +type Forensics struct { + ReceiverCh <-chan utils.QuorumCert + Abort chan<- struct{} +} + +// Initiate a forensics process +func (x *XDPoS_v2) AttachForensics() { + receiver := make(chan utils.QuorumCert) + abort := make(chan struct{}) + + go func() { + for { + // A real event arrived, process interesting content + select { + case quorumCert := <-receiver: + x.ProcessForensics(quorumCert) + case <-abort: + return + } + } + }() + x.forensics = &Forensics{ + ReceiverCh: receiver, + Abort: abort, + } +} + +func (x *XDPoS_v2) SendForensicProof() { +} + +func (x *XDPoS_v2) ProcessForensics(quorumCert utils.QuorumCert) { + log.Info("Received a QC in forensics", "QC", quorumCert) +} diff --git a/consensus/XDPoS/engines/engine_v2/verifyHeader.go b/consensus/XDPoS/engines/engine_v2/verifyHeader.go index 2b78022fe6..535221aea3 100644 --- a/consensus/XDPoS/engines/engine_v2/verifyHeader.go +++ b/consensus/XDPoS/engines/engine_v2/verifyHeader.go @@ -101,7 +101,14 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade if len(header.Validators)%common.AddressLength != 0 { return utils.ErrInvalidCheckpointSigners } - isLegit, err := x.isValidatorsLegit(chain, header) + + _, localPenalties, err := x.calcMasternodes(chain, header.Number, header.ParentHash) + if err != nil { + log.Error("[verifyHeader] Fail to calculate master nodes list with penalty", "Number", header.Number, "Hash", header.Hash()) + return err + } + + isLegit, err := x.isValidatorsLegit(chain, header, localPenalties) if err != nil { log.Error("[verifyHeader] Error while trying to check if the validators are legit", "Hash", header.Hash(), "Number", header.Number, "ValidatorsLength", len(header.Validators)) return err @@ -109,17 +116,6 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade if !isLegit { return utils.ErrValidatorsNotLegit } - - _, penalties, err := x.calcMasternodes(chain, header.Number, header.ParentHash) - if err != nil { - log.Error("[verifyHeader] Fail to calculate master nodes list with penalty", "Number", header.Number, "Hash", header.Hash()) - return err - } - - if !utils.CompareSignersLists(common.ExtractAddressFromBytes(header.Penalties), penalties) { - return utils.ErrPenaltyListDoesNotMatch - } - } else { if len(header.Validators) != 0 { log.Warn("[verifyHeader] Validators shall not have values in non-epochSwitch block", "Hash", header.Hash(), "Number", header.Number, "header.Validators", header.Validators) @@ -167,16 +163,15 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade } // Verify the header validators address is legit by checking against its snapshot masternode list minutes the penalty list, we also ensure the order matches -func (x *XDPoS_v2) isValidatorsLegit(chain consensus.ChainReader, header *types.Header) (bool, error) { +func (x *XDPoS_v2) isValidatorsLegit(chain consensus.ChainReader, header *types.Header, penalties []common.Address) (bool, error) { snap, err := x.getSnapshot(chain, header.Number.Uint64(), false) if err != nil { log.Error("[isValidatorsLegit] Error while trying to get snapshot", "BlockNumber", header.Number.Int64(), "Hash", header.Hash().Hex(), "error", err) return false, err } // snap.NextEpochMasterNodes - penaltyList := common.ExtractAddressFromBytes(header.Penalties) penaltyMap := make(map[common.Address]bool) - for _, item := range penaltyList { + for _, item := range penalties { penaltyMap[item] = true } diff --git a/consensus/XDPoS/utils/errors.go b/consensus/XDPoS/utils/errors.go index 8ebd5438fd..2dfbb6d538 100644 --- a/consensus/XDPoS/utils/errors.go +++ b/consensus/XDPoS/utils/errors.go @@ -91,8 +91,7 @@ var ( ErrCoinbaseAndValidatorMismatch = errors.New("Validaotor and coinbase address in header does not match") ErrNotItsTurn = errors.New("Not validator's turn to mine this block") - ErrPenaltyListDoesNotMatch = errors.New("Incoming block penalty list does not match") - ErrRoundInvalid = errors.New("Invalid Round, it shall be bigger than QC round") + ErrRoundInvalid = errors.New("Invalid Round, it shall be bigger than QC round") ErrAlreadyMined = errors.New("Already mined") ) diff --git a/consensus/tests/engine_v2_tests/verify_header_test.go b/consensus/tests/engine_v2_tests/verify_header_test.go index 5a698379ae..3c6a1e7fc3 100644 --- a/consensus/tests/engine_v2_tests/verify_header_test.go +++ b/consensus/tests/engine_v2_tests/verify_header_test.go @@ -80,18 +80,13 @@ func TestShouldVerifyBlock(t *testing.T) { err = adaptor.VerifyHeader(blockchain, invalidValidatorsSignerBlock, true) assert.Equal(t, utils.ErrInvalidCheckpointSigners, err) - invalidPenaltiesExistBlock := blockchain.GetBlockByNumber(901).Header() - invalidPenaltiesExistBlock.Penalties = common.Hex2BytesFixed("123131231", 20) - err = adaptor.VerifyHeader(blockchain, invalidPenaltiesExistBlock, true) - assert.Equal(t, utils.ErrPenaltyListDoesNotMatch, 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 := blockchain.GetBlockByNumber(902).Header() invalidPenaltiesExistBlock.Penalties = common.Hex2BytesFixed("123131231", 20) err = adaptor.VerifyHeader(blockchain, invalidPenaltiesExistBlock, true) assert.Equal(t, utils.ErrInvalidFieldInNonEpochSwitch, err) @@ -163,10 +158,8 @@ func TestShouldVerifyBlock(t *testing.T) { // Make the validators not legit by adding something to the penalty validatorsNotLegit := blockchain.GetBlockByNumber(901).Header() - penalties := []common.Address{acc1Addr} - for _, v := range penalties { - validatorsNotLegit.Penalties = append(validatorsNotLegit.Penalties, v[:]...) - } + + validatorsNotLegit.Validators = append(validatorsNotLegit.Validators, acc1Addr[:]...) err = adaptor.VerifyHeader(blockchain, validatorsNotLegit, true) assert.Equal(t, utils.ErrValidatorsNotLegit, err) }