diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 7508a24fc8..6804f348d5 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -25,6 +25,8 @@ import ( "math/big" "math/rand" "path/filepath" + "reflect" + "sort" "strconv" "sync" "time" @@ -424,9 +426,11 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types. signers = RemovePenaltiesFromBlock(chain, signers, number-uint64(i)*c.config.Epoch) } } - byteMasterNodes := common.ExtractAddressToBytes(signers) extraSuffix := len(header.Extra) - extraSeal - if !bytes.Equal(header.Extra[extraVanity:extraSuffix], byteMasterNodes) { + masternodesFromCheckpointHeader := common.ExtractAddressFromBytes(header.Extra[extraVanity:extraSuffix]) + validSigners := compareSignersLists(masternodesFromCheckpointHeader, signers) + if !validSigners { + log.Error("Masternodes lists are different in checkpoint header and snapshot", "number", number, "masternodes_from_checkpoint_header", masternodesFromCheckpointHeader, "masternodes_in_snapshot", signers, "penList", penPenalties) return errInvalidCheckpointSigners } if c.HookVerifyMNs != nil { @@ -440,6 +444,21 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types. return c.verifySeal(chain, header, parents, fullVerify) } +// 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 { + return true + } + sort.Slice(list1, func(i, j int) bool { + return list1[i].String() <= list1[j].String() + }) + sort.Slice(list2, func(i, j int) bool { + return list2[i].String() <= list2[j].String() + }) + return reflect.DeepEqual(list1, list2) +} + func (c *Posv) GetSnapshot(chain consensus.ChainReader, header *types.Header) (*Snapshot, error) { number := header.Number.Uint64() log.Trace("take snapshot", "number", number, "hash", header.Hash()) diff --git a/consensus/posv/posv_test.go b/consensus/posv/posv_test.go index 2f41f1395c..7019cd4a52 100644 --- a/consensus/posv/posv_test.go +++ b/consensus/posv/posv_test.go @@ -47,3 +47,38 @@ func TestGetM1M2FromCheckpointHeader(t *testing.T) { } } } + +func TestCompareSignersLists(t *testing.T) { + list1 := []common.Address{ + common.StringToAddress("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + common.StringToAddress("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), + common.StringToAddress("cccccccccccccccccccccccccccccccccccccccc"), + common.StringToAddress("dddddddddddddddddddddddddddddddddddddddd"), + } + list2 := []common.Address{ + common.StringToAddress("cccccccccccccccccccccccccccccccccccccccc"), + common.StringToAddress("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + common.StringToAddress("dddddddddddddddddddddddddddddddddddddddd"), + common.StringToAddress("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), + } + list3 := []common.Address{ + common.StringToAddress("cccccccccccccccccccccccccccccccccccccccc"), + common.StringToAddress("dddddddddddddddddddddddddddddddddddddddd"), + common.StringToAddress("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), + } + if !compareSignersLists(list1, list2) { + t.Error("list1 should be equal to list2", "list1", list1, "list2", list2) + } + if compareSignersLists(list1, list3) { + t.Error("list1 and list3 should not be same", "list1", list1, "list3", list3) + } + if !compareSignersLists([]common.Address{}, []common.Address{}) { + t.Error("Failed with empty list") + } + if !compareSignersLists([]common.Address{common.StringToAddress("cccccccccccccccccccccccccccccccccccccccc")}, []common.Address{common.StringToAddress("cccccccccccccccccccccccccccccccccccccccc")}) { + t.Error("Failed with list has only one signer") + } + if compareSignersLists([]common.Address{common.StringToAddress("aaaaaaaaaaaaaaaa")}, []common.Address{common.StringToAddress("cccccccccccccccccccccccccccccccccccccccc")}) { + t.Error("Failed with list has only one signer") + } +}