From 1cac82825df72ae46fcf497a175d656405d253e9 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 5 Jun 2022 12:53:50 +0200 Subject: [PATCH] xin-176 use local masternode to verify signature (#98) * use local masternode to verify signature * refactor verify header --- .../XDPoS/engines/engine_v2/verifyHeader.go | 51 +++++-------------- consensus/XDPoS/utils/errors.go | 3 +- consensus/XDPoS/utils/utils.go | 23 ++++++--- .../engine_v2_tests/verify_header_test.go | 11 ++-- 4 files changed, 39 insertions(+), 49 deletions(-) diff --git a/consensus/XDPoS/engines/engine_v2/verifyHeader.go b/consensus/XDPoS/engines/engine_v2/verifyHeader.go index c4207b90a1..bb2932240f 100644 --- a/consensus/XDPoS/engines/engine_v2/verifyHeader.go +++ b/consensus/XDPoS/engines/engine_v2/verifyHeader.go @@ -86,6 +86,7 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade return utils.ErrInvalidDifficulty } + var masterNodes []common.Address isEpochSwitch, _, err := x.IsEpochSwitch(header) // Verify v2 block that is on the epoch switch if err != nil { log.Error("[verifyHeader] error when checking if header is epoch switch header", "Hash", header.Hash(), "Number", header.Number, "Error", err) @@ -102,20 +103,23 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade return utils.ErrInvalidCheckpointSigners } - _, localPenalties, err := x.calcMasternodes(chain, header.Number, header.ParentHash) + localMasterNodes, localPenalties, err := x.calcMasternodes(chain, header.Number, header.ParentHash) + masterNodes = localMasterNodes 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 - } - if !isLegit { + validatorsAddress := common.ExtractAddressFromBytes(header.Validators) + if !utils.CompareSignersLists(localMasterNodes, validatorsAddress) { return utils.ErrValidatorsNotLegit } + + penaltiesAddress := common.ExtractAddressFromBytes(header.Penalties) + if !utils.CompareSignersLists(localPenalties, penaltiesAddress) { + return utils.ErrPenaltiesNotLegit + } + } 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) @@ -125,6 +129,7 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade log.Warn("[verifyHeader] Penalties shall not have values in non-epochSwitch block", "Hash", header.Hash(), "Number", header.Number, "header.Penalties", header.Penalties) return utils.ErrInvalidFieldInNonEpochSwitch } + masterNodes = x.GetMasternodes(chain, header) } // If all checks passed, validate any special fields for hard forks @@ -133,7 +138,6 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade } // Check its validator - masterNodes := x.GetMasternodes(chain, header) verified, validatorAddress, err := x.verifyMsgSignature(sigHash(header), header.Validator, masterNodes) if err != nil { for index, mn := range masterNodes { @@ -161,34 +165,3 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade x.verifiedHeaders.Add(header.Hash(), true) return nil } - -// 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, penalties []common.Address) (bool, error) { - - if header.Number.Cmp(x.config.V2.SwitchBlock) == 0 { - log.Info("[isValidatorsLegit] examing last v1 block") - return true, nil - } - - 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 - penaltyMap := make(map[common.Address]bool) - for _, item := range penalties { - penaltyMap[item] = true - } - - var finalValidMasternodes []common.Address - for _, mn := range snap.NextEpochMasterNodes { - if penaltyMap[mn] { - continue - } else { - finalValidMasternodes = append(finalValidMasternodes, mn) - } - } - validatorsAddress := common.ExtractAddressFromBytes(header.Validators) - return utils.CompareSignersLists(finalValidMasternodes, validatorsAddress), nil -} diff --git a/consensus/XDPoS/utils/errors.go b/consensus/XDPoS/utils/errors.go index 275cf6ce49..3a096e03eb 100644 --- a/consensus/XDPoS/utils/errors.go +++ b/consensus/XDPoS/utils/errors.go @@ -47,7 +47,8 @@ var ( ErrInvalidCheckpointPenalties = errors.New("invalid penalty list on checkpoint block") - ErrValidatorsNotLegit = errors.New("Validators does not match what's stored in snapshot minutes its penalty") + ErrValidatorsNotLegit = errors.New("validators does not match what's stored in snapshot minutes its penalty") + ErrPenaltiesNotLegit = errors.New("penalties does not match") // errInvalidMixDigest is returned if a block's mix digest is non-zero. ErrInvalidMixDigest = errors.New("non-zero mix digest") diff --git a/consensus/XDPoS/utils/utils.go b/consensus/XDPoS/utils/utils.go index 0bf8924fe9..8b4a5a6667 100644 --- a/consensus/XDPoS/utils/utils.go +++ b/consensus/XDPoS/utils/utils.go @@ -53,16 +53,27 @@ func ExtractValidatorsFromBytes(byteValidators []byte) []int64 { // compare 2 signers lists // return true if they are same elements, otherwise return false func CompareSignersLists(list1 []common.Address, list2 []common.Address) bool { - if len(list1) == 0 && len(list2) == 0 { + l1 := make([]common.Address, len(list1)) + l2 := make([]common.Address, len(list2)) + + copy(l1, list1) + copy(l2, list2) + + if len(l1) == 0 && len(l2) == 0 { return true } - sort.Slice(list1, func(i, j int) bool { - return list1[i].String() <= list1[j].String() + + if len(l1) != len(l2) { + return false + } + + sort.Slice(l1, func(i, j int) bool { + return l1[i].String() <= l1[j].String() }) - sort.Slice(list2, func(i, j int) bool { - return list2[i].String() <= list2[j].String() + sort.Slice(l2, func(i, j int) bool { + return l2[i].String() <= l2[j].String() }) - return reflect.DeepEqual(list1, list2) + return reflect.DeepEqual(l1, l2) } // Decode extra fields for consensus version >= 2 (XDPoS 2.0 and future versions) diff --git a/consensus/tests/engine_v2_tests/verify_header_test.go b/consensus/tests/engine_v2_tests/verify_header_test.go index d2ddb32965..bdd5d8784f 100644 --- a/consensus/tests/engine_v2_tests/verify_header_test.go +++ b/consensus/tests/engine_v2_tests/verify_header_test.go @@ -98,7 +98,7 @@ func TestShouldVerifyBlock(t *testing.T) { assert.Equal(t, consensus.ErrUnknownAncestor, err) tooFastMinedBlock := blockchain.GetBlockByNumber(902).Header() - tooFastMinedBlock.Time = big.NewInt(time.Now().Unix() - 2) + tooFastMinedBlock.Time = big.NewInt(time.Now().Unix() - 10) err = adaptor.VerifyHeader(blockchain, tooFastMinedBlock, true) assert.Equal(t, utils.ErrInvalidTimestamp, err) @@ -156,12 +156,17 @@ func TestShouldVerifyBlock(t *testing.T) { err = adaptor.VerifyHeader(blockchain, coinbaseValidatorMismatchBlock, true) assert.Equal(t, utils.ErrCoinbaseAndValidatorMismatch, err) - // Make the validators not legit by adding something to the penalty + // Make the validators not legit by adding something to the validator validatorsNotLegit := blockchain.GetBlockByNumber(901).Header() - validatorsNotLegit.Validators = append(validatorsNotLegit.Validators, acc1Addr[:]...) err = adaptor.VerifyHeader(blockchain, validatorsNotLegit, true) assert.Equal(t, utils.ErrValidatorsNotLegit, err) + + // Make the penalties not legit by adding something to the penalty + penaltiesNotLegit := blockchain.GetBlockByNumber(901).Header() + penaltiesNotLegit.Penalties = append(penaltiesNotLegit.Penalties, acc1Addr[:]...) + err = adaptor.VerifyHeader(blockchain, penaltiesNotLegit, true) + assert.Equal(t, utils.ErrPenaltiesNotLegit, err) } func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {