1313// You should have received a copy of the GNU Lesser General Public License
1414// along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
16- // Package XDPoS implements the delegated- proof-of-stake consensus engine.
16+ // Package XDPoS implements the proof-of-stake-voting consensus engine.
1717package XDPoS
1818
1919import (
@@ -25,6 +25,8 @@ import (
2525 "math/big"
2626 "math/rand"
2727 "path/filepath"
28+ "reflect"
29+ "sort"
2830 "strconv"
2931 "sync"
3032 "time"
@@ -58,7 +60,7 @@ type Masternode struct {
5860 Stake * big.Int
5961}
6062
61- // XDPoS delegated- proof-of-stake protocol constants.
63+ // XDPoS proof-of-stake-voting protocol constants.
6264var (
6365 epochLength = uint64 (900 ) // Default number of blocks after which to checkpoint and reset the pending votes
6466
@@ -149,7 +151,7 @@ var (
149151// backing account.
150152//type SignerFn func(accounts.Account, []byte) ([]byte, error)
151153
152- // sigHash returns the hash which is used as input for the delegated- proof-of-stake
154+ // sigHash returns the hash which is used as input for the proof-of-stake-voting
153155// signing. It is the hash of the entire header apart from the 65 byte signature
154156// contained at the end of the extra data.
155157//
@@ -209,7 +211,7 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, er
209211 return signer , nil
210212}
211213
212- // XDPoS is the delegated- proof-of-stake consensus engine proposed to support the
214+ // XDPoS is the proof-of-stake-voting consensus engine proposed to support the
213215// Ethereum testnet following the Ropsten attacks.
214216type XDPoS struct {
215217 config * params.XDPoSConfig // Consensus engine configuration parameters
@@ -225,15 +227,15 @@ type XDPoS struct {
225227 signFn clique.SignerFn // Signer function to authorize hashes with
226228 lock sync.RWMutex // Protects the signer fields
227229
228- BlockSigners * lru.Cache
229- HookReward func (chain consensus.ChainReader , state * state.StateDB , header * types.Header ) (error , map [string ]interface {})
230+ BlockSigners * lru.Cache
231+ HookReward func (chain consensus.ChainReader , state * state.StateDB , header * types.Header ) (error , map [string ]interface {})
230232 HookPenalty func (chain consensus.ChainReader , blockNumberEpoc uint64 ) ([]common.Address , error )
231233 HookPenaltyTIPSigning func (chain consensus.ChainReader , header * types.Header , candidate []common.Address ) ([]common.Address , error )
232234 HookValidator func (header * types.Header , signers []common.Address ) ([]byte , error )
233235 HookVerifyMNs func (header * types.Header , signers []common.Address ) error
234236}
235237
236- // New creates a XDPoS delegated- proof-of-stake consensus engine with the initial
238+ // New creates a XDPoS proof-of-stake-voting consensus engine with the initial
237239// signers set to the ones provided by the user.
238240func New (config * params.XDPoSConfig , db ethdb.Database ) * XDPoS {
239241 // Set any missing consensus parameters to their defaults
@@ -424,9 +426,11 @@ func (c *XDPoS) verifyCascadingFields(chain consensus.ChainReader, header *types
424426 signers = RemovePenaltiesFromBlock (chain , signers , number - uint64 (i )* c .config .Epoch )
425427 }
426428 }
427- byteMasterNodes := common .ExtractAddressToBytes (signers )
428429 extraSuffix := len (header .Extra ) - extraSeal
429- if ! bytes .Equal (header .Extra [extraVanity :extraSuffix ], byteMasterNodes ) {
430+ masternodesFromCheckpointHeader := common .ExtractAddressFromBytes (header .Extra [extraVanity :extraSuffix ])
431+ validSigners := compareSignersLists (masternodesFromCheckpointHeader , signers )
432+ if ! validSigners {
433+ log .Error ("Masternodes lists are different in checkpoint header and snapshot" , "number" , number , "masternodes_from_checkpoint_header" , masternodesFromCheckpointHeader , "masternodes_in_snapshot" , signers , "penList" , penPenalties )
430434 return errInvalidCheckpointSigners
431435 }
432436 if c .HookVerifyMNs != nil {
@@ -440,6 +444,21 @@ func (c *XDPoS) verifyCascadingFields(chain consensus.ChainReader, header *types
440444 return c .verifySeal (chain , header , parents , fullVerify )
441445}
442446
447+ // compare 2 signers lists
448+ // return true if they are same elements, otherwise return false
449+ func compareSignersLists (list1 []common.Address , list2 []common.Address ) bool {
450+ if len (list1 ) == 0 && len (list2 ) == 0 {
451+ return true
452+ }
453+ sort .Slice (list1 , func (i , j int ) bool {
454+ return list1 [i ].String () <= list1 [j ].String ()
455+ })
456+ sort .Slice (list2 , func (i , j int ) bool {
457+ return list2 [i ].String () <= list2 [j ].String ()
458+ })
459+ return reflect .DeepEqual (list1 , list2 )
460+ }
461+
443462func (c * XDPoS ) GetSnapshot (chain consensus.ChainReader , header * types.Header ) (* Snapshot , error ) {
444463 number := header .Number .Uint64 ()
445464 log .Trace ("take snapshot" , "number" , number , "hash" , header .Hash ())
@@ -739,7 +758,7 @@ func (c *XDPoS) GetValidator(creator common.Address, chain consensus.ChainReader
739758 return common.Address {}, fmt .Errorf ("couldn't find checkpoint header" )
740759 }
741760 }
742- m , err := GetM1M2FromCheckpointHeader (cpHeader )
761+ m , err := GetM1M2FromCheckpointHeader (cpHeader , header , chain . Config () )
743762 if err != nil {
744763 return common.Address {}, err
745764 }
@@ -977,7 +996,13 @@ func (c *XDPoS) Seal(chain consensus.ChainReader, block *types.Block, stop <-cha
977996 return nil , err
978997 }
979998 copy (header .Extra [len (header .Extra )- extraSeal :], sighash )
980-
999+ m2 , err := c .GetValidator (signer , chain , header )
1000+ if err != nil {
1001+ return nil , fmt .Errorf ("can't get block validator: %v" , err )
1002+ }
1003+ if m2 == signer {
1004+ header .Validator = sighash
1005+ }
9811006 return block .WithSeal (header ), nil
9821007}
9831008
@@ -1119,24 +1144,39 @@ func GetMasternodesFromCheckpointHeader(checkpointHeader *types.Header) []common
11191144}
11201145
11211146// Get m2 list from checkpoint block.
1122- func GetM1M2FromCheckpointHeader (checkpointHeader * types.Header ) (map [common.Address ]common.Address , error ) {
1147+ func GetM1M2FromCheckpointHeader (checkpointHeader * types.Header , currentHeader * types. Header , config * params. ChainConfig ) (map [common.Address ]common.Address , error ) {
11231148 if checkpointHeader .Number .Uint64 ()% common .EpocBlockRandomize != 0 {
11241149 return nil , errors .New ("This block is not checkpoint block epoc." )
11251150 }
1126- m1m2 := map [common.Address ]common.Address {}
11271151 // Get signers from this block.
11281152 masternodes := GetMasternodesFromCheckpointHeader (checkpointHeader )
11291153 validators := ExtractValidatorsFromBytes (checkpointHeader .Validators )
1130-
1131- if len ( validators ) < len ( masternodes ) {
1132- return nil , errors . New ( "len(m2) is less than len(m1)" )
1154+ m1m2 , _ , err := getM1M2 ( masternodes , validators , currentHeader , config )
1155+ if err != nil {
1156+ return map [common. Address ]common. Address {}, err
11331157 }
1134- if len (masternodes ) > 0 {
1158+ return m1m2 , nil
1159+ }
1160+
1161+ func getM1M2 (masternodes []common.Address , validators []int64 , currentHeader * types.Header , config * params.ChainConfig ) (map [common.Address ]common.Address , uint64 , error ) {
1162+ m1m2 := map [common.Address ]common.Address {}
1163+ maxMNs := len (masternodes )
1164+ moveM2 := uint64 (0 )
1165+ if len (validators ) < maxMNs {
1166+ return nil , moveM2 , errors .New ("len(m2) is less than len(m1)" )
1167+ }
1168+ if maxMNs > 0 {
1169+ isForked := config .IsTIPRandomize (currentHeader .Number )
1170+ if isForked {
1171+ moveM2 = ((currentHeader .Number .Uint64 () % config .XDPoS .Epoch ) / uint64 (maxMNs )) % uint64 (maxMNs )
1172+ }
11351173 for i , m1 := range masternodes {
1136- m1m2 [m1 ] = masternodes [validators [i ]% int64 (len (masternodes ))]
1174+ m2Index := uint64 (validators [i ] % int64 (maxMNs ))
1175+ m2Index = (m2Index + moveM2 ) % uint64 (maxMNs )
1176+ m1m2 [m1 ] = masternodes [m2Index ]
11371177 }
11381178 }
1139- return m1m2 , nil
1179+ return m1m2 , moveM2 , nil
11401180}
11411181
11421182// Extract validators from byte array.
0 commit comments