xin-176 use local masternode to verify signature (#98)

* use local masternode to verify signature

* refactor verify header
This commit is contained in:
Liam 2022-06-05 12:53:50 +02:00 committed by GitHub
parent 50ae0c95fd
commit 1cac82825d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 49 deletions

View file

@ -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
}

View file

@ -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")

View file

@ -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)

View file

@ -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) {