diff --git a/accounts/scwallet/hub.go b/accounts/scwallet/hub.go
index dfcc5ac4bf16735e3d20b8b1cfcd0e07b59074f5..66005b04e986024055d5332190a9dd6a71b37002 100644
--- a/accounts/scwallet/hub.go
+++ b/accounts/scwallet/hub.go
@@ -41,11 +41,11 @@ import (
 	"sync"
 	"time"
 
+	pcsc "github.com/gballet/go-libpcsclite"
 	"github.com/maticnetwork/bor/accounts"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/event"
 	"github.com/maticnetwork/bor/log"
-	pcsc "github.com/gballet/go-libpcsclite"
 )
 
 // Scheme is the URI prefix for smartcard wallets.
diff --git a/accounts/scwallet/securechannel.go b/accounts/scwallet/securechannel.go
index 3d0be4728ea2161a4b24c8174efcb77c84c7feef..7f0a8df4ac9a7fb4f636bcff734ed50f86d58b94 100644
--- a/accounts/scwallet/securechannel.go
+++ b/accounts/scwallet/securechannel.go
@@ -25,8 +25,8 @@ import (
 	"crypto/sha512"
 	"fmt"
 
-	"github.com/maticnetwork/bor/crypto"
 	pcsc "github.com/gballet/go-libpcsclite"
+	"github.com/maticnetwork/bor/crypto"
 	"github.com/wsddn/go-ecdh"
 	"golang.org/x/crypto/pbkdf2"
 	"golang.org/x/text/unicode/norm"
diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go
index 540bcc1a60dffe9e528545c62529387c1c523d70..6b986ff946c34a4d3b447a91111944947ae21f28 100644
--- a/accounts/scwallet/wallet.go
+++ b/accounts/scwallet/wallet.go
@@ -33,13 +33,13 @@ import (
 	"sync"
 	"time"
 
+	pcsc "github.com/gballet/go-libpcsclite"
 	ethereum "github.com/maticnetwork/bor"
 	"github.com/maticnetwork/bor/accounts"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/core/types"
 	"github.com/maticnetwork/bor/crypto"
 	"github.com/maticnetwork/bor/log"
-	pcsc "github.com/gballet/go-libpcsclite"
 	"github.com/status-im/keycard-go/derivationpath"
 )
 
diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go
index a80eff5a93a95e5b96a4792f46de5b9419701f5a..e742e49fe01b3818d5f62d3baef15f706e94b3bf 100644
--- a/accounts/usbwallet/hub.go
+++ b/accounts/usbwallet/hub.go
@@ -23,10 +23,10 @@ import (
 	"sync/atomic"
 	"time"
 
+	"github.com/karalabe/usb"
 	"github.com/maticnetwork/bor/accounts"
 	"github.com/maticnetwork/bor/event"
 	"github.com/maticnetwork/bor/log"
-	"github.com/karalabe/usb"
 )
 
 // LedgerScheme is the protocol scheme prefixing account and wallet URLs.
diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go
index f88501e32f503c3f471f5917fe228486daf784ac..49c71cb0283b1550bf035c57c0c3a4f4e5afc9f7 100644
--- a/accounts/usbwallet/trezor.go
+++ b/accounts/usbwallet/trezor.go
@@ -27,13 +27,13 @@ import (
 	"io"
 	"math/big"
 
+	"github.com/golang/protobuf/proto"
 	"github.com/maticnetwork/bor/accounts"
 	"github.com/maticnetwork/bor/accounts/usbwallet/trezor"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/common/hexutil"
 	"github.com/maticnetwork/bor/core/types"
 	"github.com/maticnetwork/bor/log"
-	"github.com/golang/protobuf/proto"
 )
 
 // ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In
diff --git a/accounts/usbwallet/wallet.go b/accounts/usbwallet/wallet.go
index 09a140a756441555a170fa8a9b3b62f1cab23a2f..29f7cf661e9c8291665584b1b3cf273abb8e8d26 100644
--- a/accounts/usbwallet/wallet.go
+++ b/accounts/usbwallet/wallet.go
@@ -25,13 +25,13 @@ import (
 	"sync"
 	"time"
 
+	"github.com/karalabe/usb"
 	ethereum "github.com/maticnetwork/bor"
 	"github.com/maticnetwork/bor/accounts"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/core/types"
 	"github.com/maticnetwork/bor/crypto"
 	"github.com/maticnetwork/bor/log"
-	"github.com/karalabe/usb"
 )
 
 // Maximum time between wallet health checks to detect USB unplugs.
diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go
index a33681c1d827e07649646c737f4c9566289f78a8..84fabf3336685fc8a33671fea37bfe9e94f6a3a0 100644
--- a/consensus/bor/bor.go
+++ b/consensus/bor/bor.go
@@ -201,8 +201,8 @@ func encodeSigHeader(w io.Writer, header *types.Header) {
 // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
 // that a new block should have based on the previous blocks in the chain and the
 // current signer.
-func CalcDifficulty(snap *Snapshot, signer common.Address, epoch uint64) *big.Int {
-	return big.NewInt(0).SetUint64(snap.inturn(snap.Number+1, signer, epoch))
+func CalcDifficulty(snap *Snapshot, signer common.Address, sprint uint64) *big.Int {
+	return big.NewInt(0).SetUint64(snap.inturn(snap.Number+1, signer, sprint))
 }
 
 // CalcProducerDelay is the block delay algorithm based on block time and period / producerDelay values in genesis
@@ -346,12 +346,9 @@ func (c *Bor) verifyHeader(chain consensus.ChainReader, header *types.Header, pa
 	if header.Time > uint64(time.Now().Unix()) {
 		return consensus.ErrFutureBlock
 	}
-	// Check that the extra-data contains both the vanity and signature
-	if len(header.Extra) < extraVanity {
-		return errMissingVanity
-	}
-	if len(header.Extra) < extraVanity+extraSeal {
-		return errMissingSignature
+
+	if err := validateHeaderExtraField(header.Extra); err != nil {
+		return err
 	}
 
 	// check extr adata
@@ -387,6 +384,18 @@ func (c *Bor) verifyHeader(chain consensus.ChainReader, header *types.Header, pa
 	return c.verifyCascadingFields(chain, header, parents)
 }
 
+// validateHeaderExtraField validates that the extra-data contains both the vanity and signature.
+// header.Extra = header.Vanity + header.ProducerBytes (optional) + header.Seal
+func validateHeaderExtraField(extraBytes []byte) error {
+	if len(extraBytes) < extraVanity {
+		return errMissingVanity
+	}
+	if len(extraBytes) < extraVanity+extraSeal {
+		return errMissingSignature
+	}
+	return nil
+}
+
 // verifyCascadingFields verifies all the header fields that are not standalone,
 // rather depend on a batch of previous headers. The caller may optionally pass
 // in a batch of parents (ascending order) to avoid looking those up from the
@@ -420,8 +429,9 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainReader, header *types.H
 		return err
 	}
 
-	// If the block is a sprint end block, verify the validator list
-	if number%c.config.Sprint == 0 {
+	isSprintEnd := (number+1)%c.config.Sprint == 0
+	// verify the validator list in the last sprint block
+	if isSprintEnd {
 		validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength)
 
 		currentValidators := snap.ValidatorSet.Copy().Validators
@@ -430,14 +440,9 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainReader, header *types.H
 		for i, validator := range currentValidators {
 			copy(validatorsBytes[i*validatorHeaderBytesLength:], validator.HeaderBytes())
 		}
-
-		extraSuffix := len(header.Extra) - extraSeal
-
-		// fmt.Println("validatorsBytes ==> verify seal ==> ", hex.EncodeToString(validatorsBytes))
-		// fmt.Println("header.Extra ==> verify seal ==> ", hex.EncodeToString(header.Extra[extraVanity:extraSuffix]))
-
-		if !bytes.Equal(header.Extra[extraVanity:extraSuffix], validatorsBytes) {
-			// return errMismatchingSprintValidators
+		// len(header.Extra) >= extraVanity+extraSeal has already been validated in validateHeaderExtraField, so this won't result in a panic
+		if !bytes.Equal(header.Extra[extraVanity : len(header.Extra)-extraSeal], validatorsBytes) {
+			return errMismatchingSprintValidators
 		}
 	}
 
@@ -474,7 +479,7 @@ func (c *Bor) snapshot(chain consensus.ChainReader, number uint64, hash common.H
 		// up more headers than allowed to be reorged (chain reinit from a freezer),
 		// consider the checkpoint trusted and snapshot it.
 		// TODO fix this
-		if number == 0 /* || (number%c.config.Sprint == 0 && (len(headers) > params.ImmutabilityThreshold || chain.GetHeaderByNumber(number-1) == nil)) */ {
+		if number == 0 {
 			checkpoint := chain.GetHeaderByNumber(number)
 			if checkpoint != nil {
 				// get checkpoint data
@@ -582,27 +587,8 @@ func (c *Bor) verifySeal(chain consensus.ChainReader, header *types.Header, pare
 		return errUnauthorizedSigner
 	}
 
-	// check if signer is correct
-	validators := snap.ValidatorSet.Validators
-	// proposer will be the last signer if block is not epoch block
-	proposer := snap.ValidatorSet.GetProposer().Address
-	if number%c.config.Sprint != 0 {
-		// proposer = snap.Recents[number-1]
-	}
-	proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
-	signerIndex, _ := snap.ValidatorSet.GetByAddress(signer)
-	limit := len(validators)/2 + 1
-
-	// temp index
-	tempIndex := signerIndex
-	if proposerIndex != tempIndex && limit > 0 {
-		if tempIndex < proposerIndex {
-			tempIndex = tempIndex + len(validators)
-		}
-
-		if tempIndex-proposerIndex > limit {
-			return errRecentlySigned
-		}
+	if _, err = snap.GetSignerSuccessionNumber(signer); err != nil {
+		return err
 	}
 
 	// Ensure that the difficulty corresponds to the turn-ness of the signer
@@ -766,35 +752,18 @@ func (c *Bor) Seal(chain consensus.ChainReader, block *types.Block, results chan
 		return errUnauthorizedSigner
 	}
 
-	validators := snap.ValidatorSet.Validators
-	// proposer will be the last signer if block is not epoch block
-	proposer := snap.ValidatorSet.GetProposer().Address
-	if number%c.config.Sprint != 0 {
-		// proposer = snap.Recents[number-1]
-	}
-
-	proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
-	signerIndex, _ := snap.ValidatorSet.GetByAddress(signer)
-	limit := len(validators)/2 + 1
-
-	// temp index
-	tempIndex := signerIndex
-	if tempIndex < proposerIndex {
-		tempIndex = tempIndex + len(validators)
-	}
-
-	if limit > 0 && tempIndex-proposerIndex > limit {
-		log.Info("Signed recently, must wait for others")
-		return nil
+	successionNumber, err := snap.GetSignerSuccessionNumber(signer)
+	if err != nil {
+		return err
 	}
 
 	// Sweet, the protocol permits us to sign the block, wait for our time
 	delay := time.Unix(int64(header.Time), 0).Sub(time.Now()) // nolint: gosimple
-	wiggle := time.Duration(2*c.config.Period) * time.Second * time.Duration(tempIndex-proposerIndex)
+	wiggle := time.Duration(2*c.config.Period) * time.Second * time.Duration(successionNumber)
 	delay += wiggle
 
 	log.Info("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle))
-	log.Info("Sealing block with", "number", number, "delay", delay, "headerDifficulty", header.Difficulty, "signer", signer.Hex(), "proposer", proposer.Hex())
+	log.Info("Sealing block with", "number", number, "delay", delay, "headerDifficulty", header.Difficulty, "signer", signer.Hex(), "proposer", snap.ValidatorSet.GetProposer().Address.Hex())
 
 	// Sign all the things!
 	sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header))
@@ -854,7 +823,7 @@ func (c *Bor) Close() error {
 	return nil
 }
 
-// Checks if new span is pending
+// Checks if "force" proposeSpan has been set
 func (c *Bor) isSpanPending(snapshotNumber uint64) (bool, error) {
 	blockNr := rpc.BlockNumber(snapshotNumber)
 	method := "spanProposalPending"
@@ -866,14 +835,10 @@ func (c *Bor) isSpanPending(snapshotNumber uint64) (bool, error) {
 		return false, err
 	}
 
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel() // cancel when we are finished consuming integers
-
-	// call
 	msgData := (hexutil.Bytes)(data)
 	toAddress := common.HexToAddress(c.config.ValidatorContract)
 	gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
-	result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{
+	result, err := c.ethAPI.Call(context.Background(), ethapi.CallArgs{
 		Gas:  &gas,
 		To:   &toAddress,
 		Data: &msgData,
@@ -904,14 +869,10 @@ func (c *Bor) GetCurrentSpan(snapshotNumber uint64) (*Span, error) {
 		return nil, err
 	}
 
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel() // cancel when we are finished consuming integers
-
-	// call
 	msgData := (hexutil.Bytes)(data)
 	toAddress := common.HexToAddress(c.config.ValidatorContract)
 	gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
-	result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{
+	result, err := c.ethAPI.Call(context.Background(), ethapi.CallArgs{
 		Gas:  &gas,
 		To:   &toAddress,
 		Data: &msgData,
@@ -954,14 +915,11 @@ func (c *Bor) GetCurrentValidators(snapshotNumber uint64, blockNumber uint64) ([
 		return nil, err
 	}
 
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel() // cancel when we are finished consuming integers
-
 	// call
 	msgData := (hexutil.Bytes)(data)
 	toAddress := common.HexToAddress(c.config.ValidatorContract)
 	gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
-	result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{
+	result, err := c.ethAPI.Call(context.Background(), ethapi.CallArgs{
 		Gas:  &gas,
 		To:   &toAddress,
 		Data: &msgData,
@@ -1144,13 +1102,10 @@ func (c *Bor) GetPendingStateProposals(snapshotNumber uint64) ([]*big.Int, error
 		return nil, err
 	}
 
-	ctx, cancel := context.WithCancel(context.Background())
-	defer cancel() // cancel when we are finished consuming integers
-
 	msgData := (hexutil.Bytes)(data)
 	toAddress := common.HexToAddress(c.config.StateReceiverContract)
 	gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
-	result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{
+	result, err := c.ethAPI.Call(context.Background(), ethapi.CallArgs{
 		Gas:  &gas,
 		To:   &toAddress,
 		Data: &msgData,
diff --git a/consensus/bor/bor_test/helper.go b/consensus/bor/bor_test/helper.go
index 9a5c0facc561a073075ff4150a590103ce8f3908..1ead54ed88a9d02c3bdc2a5c8176700dfd6a2ab2 100644
--- a/consensus/bor/bor_test/helper.go
+++ b/consensus/bor/bor_test/helper.go
@@ -105,7 +105,16 @@ func buildMinimalNextHeader(t *testing.T, block *types.Block, borConfig *params.
 	header.Number.Add(header.Number, big.NewInt(1))
 	header.ParentHash = block.Hash()
 	header.Time += bor.CalcProducerDelay(header.Number.Uint64(), borConfig.Period, borConfig.Sprint, borConfig.ProducerDelay)
-	header.Extra = make([]byte, 97) // vanity (32) + extraSeal (65)
+	isSprintEnd := (header.Number.Uint64()+1)%borConfig.Sprint == 0
+	if isSprintEnd {
+		header.Extra = make([]byte, 32 + 40 + 65) // vanity + validatorBytes + extraSeal
+		// the genesis file was initialized with a validator 0x71562b71999873db5b286df957af199ec94617f7 with power 10
+		// So, if you change ./genesis.json, do change the following as well
+		validatorBytes, _ := hex.DecodeString("71562b71999873db5b286df957af199ec94617f7000000000000000000000000000000000000000a")
+		copy(header.Extra[32:72], validatorBytes)
+	} else {
+		header.Extra = make([]byte, 32 + 65) // vanity + extraSeal
+	}
 	_key, _ := hex.DecodeString(privKey)
 	sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), _key)
 	if err != nil {
diff --git a/consensus/bor/bor_test/snapshot_test.go b/consensus/bor/bor_test/snapshot_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..264c63295299f6967f16c4fd124bd4266a2f3a63
--- /dev/null
+++ b/consensus/bor/bor_test/snapshot_test.go
@@ -0,0 +1,125 @@
+package bortest
+
+import (
+	"math/rand"
+	"sort"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/maticnetwork/bor/common"
+	"github.com/maticnetwork/bor/consensus/bor"
+)
+
+const (
+	numVals = 100
+)
+
+func TestGetSignerSuccessionNumber_ProposerIsSigner(t *testing.T) {
+	validators := buildRandomValidatorSet(numVals)
+	validatorSet := bor.NewValidatorSet(validators)
+	snap := bor.Snapshot{
+		ValidatorSet: validatorSet,
+	}
+
+	// proposer is signer
+	signer := validatorSet.Proposer.Address
+	successionNumber, err := snap.GetSignerSuccessionNumber(signer)
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	assert.Equal(t, 0, successionNumber)
+}
+
+func TestGetSignerSuccessionNumber_SignerIndexIsLarger(t *testing.T) {
+	validators := buildRandomValidatorSet(numVals)
+
+	// sort validators by address, which is what bor.NewValidatorSet also does
+	sort.Sort(bor.ValidatorsByAddress(validators))
+	proposerIndex := 32
+	signerIndex := 56
+	// give highest ProposerPriority to a particular val, so that they become the proposer
+	validators[proposerIndex].VotingPower = 200
+	snap := bor.Snapshot{
+		ValidatorSet: bor.NewValidatorSet(validators),
+	}
+
+	// choose a signer at an index greater than proposer index
+	signer := snap.ValidatorSet.Validators[signerIndex].Address
+	successionNumber, err := snap.GetSignerSuccessionNumber(signer)
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	assert.Equal(t, signerIndex-proposerIndex, successionNumber)
+}
+
+func TestGetSignerSuccessionNumber_SignerIndexIsSmaller(t *testing.T) {
+	validators := buildRandomValidatorSet(numVals)
+	proposerIndex := 98
+	signerIndex := 11
+	// give highest ProposerPriority to a particular val, so that they become the proposer
+	validators[proposerIndex].VotingPower = 200
+	snap := bor.Snapshot{
+		ValidatorSet: bor.NewValidatorSet(validators),
+	}
+
+	// choose a signer at an index greater than proposer index
+	signer := snap.ValidatorSet.Validators[signerIndex].Address
+	successionNumber, err := snap.GetSignerSuccessionNumber(signer)
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	assert.Equal(t, signerIndex+numVals-proposerIndex, successionNumber)
+}
+
+func TestGetSignerSuccessionNumber_ProposerNotFound(t *testing.T) {
+	validators := buildRandomValidatorSet(numVals)
+	snap := bor.Snapshot{
+		ValidatorSet: bor.NewValidatorSet(validators),
+	}
+	dummyProposerAddress := randomAddress()
+	snap.ValidatorSet.Proposer = &bor.Validator{Address: dummyProposerAddress}
+	// choose any signer
+	signer := snap.ValidatorSet.Validators[3].Address
+	_, err := snap.GetSignerSuccessionNumber(signer)
+	assert.NotNil(t, err)
+	e, ok := err.(*bor.ProposerNotFoundError)
+	assert.True(t, ok)
+	assert.Equal(t, dummyProposerAddress, e.Address)
+}
+
+func TestGetSignerSuccessionNumber_SignerNotFound(t *testing.T) {
+	validators := buildRandomValidatorSet(numVals)
+	snap := bor.Snapshot{
+		ValidatorSet: bor.NewValidatorSet(validators),
+	}
+	dummySignerAddress := randomAddress()
+	_, err := snap.GetSignerSuccessionNumber(dummySignerAddress)
+	assert.NotNil(t, err)
+	e, ok := err.(*bor.SignerNotFoundError)
+	assert.True(t, ok)
+	assert.Equal(t, dummySignerAddress, e.Address)
+}
+
+func buildRandomValidatorSet(numVals int) []*bor.Validator {
+	rand.Seed(time.Now().Unix())
+	validators := make([]*bor.Validator, numVals)
+	for i := 0; i < numVals; i++ {
+		validators[i] = &bor.Validator{
+			Address: randomAddress(),
+			// cannot process validators with voting power 0, hence +1
+			VotingPower: int64(rand.Intn(99) + 1),
+		}
+	}
+
+	// sort validators by address, which is what bor.NewValidatorSet also does
+	sort.Sort(bor.ValidatorsByAddress(validators))
+	return validators
+}
+
+func randomAddress() common.Address {
+	bytes := make([]byte, 32)
+	rand.Read(bytes)
+	return common.BytesToAddress(bytes)
+}
diff --git a/consensus/bor/errors.go b/consensus/bor/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..a3b0dc656d08352a5a8ad3f5f1dddfca3aee52b3
--- /dev/null
+++ b/consensus/bor/errors.go
@@ -0,0 +1,42 @@
+package bor
+
+import (
+	"fmt"
+
+	"github.com/maticnetwork/bor/common"
+)
+
+// Will include any new bor consensus errors here in an attempt to make error messages more descriptive
+
+// ProposerNotFoundError is returned if the given proposer address is not present in the validator set
+type ProposerNotFoundError struct {
+	Address common.Address
+}
+
+func (e *ProposerNotFoundError) Error() string {
+	return fmt.Sprintf("Proposer: %s not found", e.Address.Hex())
+}
+
+// SignerNotFoundError is returned when the signer address is not present in the validator set
+type SignerNotFoundError struct {
+	Address common.Address
+}
+
+func (e *SignerNotFoundError) Error() string {
+	return fmt.Sprintf("Signer: %s not found", e.Address.Hex())
+}
+
+// TotalVotingPowerExceededError is returned when the maximum allowed total voting power is exceeded
+type TotalVotingPowerExceededError struct {
+	Sum        int64
+	Validators []*Validator
+}
+
+func (e *TotalVotingPowerExceededError) Error() string {
+	return fmt.Sprintf(
+		"Total voting power should be guarded to not exceed %v; got: %v; for validator set: %v",
+		MaxTotalVotingPower,
+		e.Sum,
+		e.Validators,
+	)
+}
diff --git a/consensus/bor/snapshot.go b/consensus/bor/snapshot.go
index d2f0e82ff49c047cede16743d2d4cfdae2d33250..08088d791103647145acc7e72744aa5a09863cec 100644
--- a/consensus/bor/snapshot.go
+++ b/consensus/bor/snapshot.go
@@ -87,7 +87,9 @@ func loadSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, db ethdb.Dat
 	snap.ethAPI = ethAPI
 
 	// update total voting power
-	snap.ValidatorSet.updateTotalVotingPower()
+	if err := snap.ValidatorSet.updateTotalVotingPower(); err != nil {
+		return nil, err
+	}
 
 	return snap, nil
 }
@@ -156,28 +158,8 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
 			return nil, errUnauthorizedSigner
 		}
 
-		//
-		// Check validator
-		//
-
-		validators := snap.ValidatorSet.Validators
-		// proposer will be the last signer if block is not epoch block
-		proposer := snap.ValidatorSet.GetProposer().Address
-		proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
-		signerIndex, _ := snap.ValidatorSet.GetByAddress(signer)
-		limit := len(validators)/2 + 1
-
-		// temp index
-		tempIndex := signerIndex
-		if proposerIndex != tempIndex && limit > 0 {
-			if tempIndex < proposerIndex {
-				tempIndex = tempIndex + len(validators)
-			}
-
-			if tempIndex-proposerIndex > limit {
-				log.Info("Invalid signer: error while applying headers", "proposerIndex", validators[proposerIndex].Address.Hex(), "signerIndex", validators[signerIndex].Address.Hex())
-				return nil, errRecentlySigned
-			}
+		if _, err = snap.GetSignerSuccessionNumber(signer); err != nil {
+			return nil, err
 		}
 
 		// add recents
@@ -185,6 +167,9 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
 
 		// change validator set and change proposer
 		if number > 0 && (number+1)%s.config.Sprint == 0 {
+			if err := validateHeaderExtraField(header.Extra); err != nil {
+				return nil, err
+			}
 			validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal]
 
 			// get validators from headers and use that for new validator set
@@ -200,6 +185,34 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
 	return snap, nil
 }
 
+// GetSignerSuccessionNumber returns the relative position of signer in terms of the in-turn proposer
+func (s *Snapshot) GetSignerSuccessionNumber(signer common.Address) (int, error) {
+	validators := s.ValidatorSet.Validators
+	proposer := s.ValidatorSet.GetProposer().Address
+	proposerIndex, _ := s.ValidatorSet.GetByAddress(proposer)
+	if proposerIndex == -1 {
+		return -1, &ProposerNotFoundError{proposer}
+	}
+	signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
+	if signerIndex == -1 {
+		return -1, &SignerNotFoundError{signer}
+	}
+	limit := len(validators)/2 + 1
+
+	tempIndex := signerIndex
+	if proposerIndex != tempIndex && limit > 0 {
+		if tempIndex < proposerIndex {
+			tempIndex = tempIndex + len(validators)
+		}
+
+		if tempIndex-proposerIndex > limit {
+			log.Info("errRecentlySigned", "proposerIndex", validators[proposerIndex].Address.Hex(), "signerIndex", validators[signerIndex].Address.Hex())
+			return -1, errRecentlySigned
+		}
+	}
+	return tempIndex - proposerIndex, nil
+}
+
 // signers retrieves the list of authorized signers in ascending order.
 func (s *Snapshot) signers() []common.Address {
 	sigs := make([]common.Address, 0, len(s.ValidatorSet.Validators))
diff --git a/consensus/bor/validator.go b/consensus/bor/validator.go
index 0592ab3b138a279d9bcc43d28feabd25913b5112..dab50e7b2c7eb9efa83d5fbb535d08b36c3e9ced 100644
--- a/consensus/bor/validator.go
+++ b/consensus/bor/validator.go
@@ -2,7 +2,7 @@ package bor
 
 import (
 	"bytes"
-	"encoding/json"
+	// "encoding/json"
 	"errors"
 	"fmt"
 	"math/big"
@@ -13,8 +13,6 @@ import (
 )
 
 // Validator represets Volatile state for each Validator
-// NOTE: The ProposerPriority is not included in Validator.Hash();
-// make sure to update that method if changes are made here
 type Validator struct {
 	ID               uint64         `json:"ID"`
 	Address          common.Address `json:"signer"`
@@ -31,18 +29,23 @@ func NewValidator(address common.Address, votingPower int64) *Validator {
 	}
 }
 
-// Creates a new copy of the validator so we can mutate ProposerPriority.
+// Copy creates a new copy of the validator so we can mutate ProposerPriority.
 // Panics if the validator is nil.
 func (v *Validator) Copy() *Validator {
 	vCopy := *v
 	return &vCopy
 }
 
-// Returns the one with higher ProposerPriority.
-func (v *Validator) CompareProposerPriority(other *Validator) *Validator {
+// Cmp returns the one validator with a higher ProposerPriority.
+// If ProposerPriority is same, it returns the validator with lexicographically smaller address
+func (v *Validator) Cmp(other *Validator) *Validator {
+	// if both of v and other are nil, nil will be returned and that could possibly lead to nil pointer dereference bubbling up the stack
 	if v == nil {
 		return other
 	}
+	if other == nil {
+		return v
+	}
 	if v.ProposerPriority > other.ProposerPriority {
 		return v
 	} else if v.ProposerPriority < other.ProposerPriority {
@@ -55,7 +58,6 @@ func (v *Validator) CompareProposerPriority(other *Validator) *Validator {
 			return other
 		} else {
 			panic("Cannot compare identical validators")
-			return nil
 		}
 	}
 }
@@ -80,18 +82,6 @@ func ValidatorListString(vals []*Validator) string {
 	return strings.Join(chunks, ",")
 }
 
-// Bytes computes the unique encoding of a validator with a given voting power.
-// These are the bytes that gets hashed in consensus. It excludes address
-// as its redundant with the pubkey. This also excludes ProposerPriority
-// which changes every round.
-func (v *Validator) Bytes() []byte {
-	b, err := json.Marshal(v)
-	if err != nil {
-		return b
-	}
-	return nil
-}
-
 // HeaderBytes return header bytes
 func (v *Validator) HeaderBytes() []byte {
 	result := make([]byte, 40)
diff --git a/consensus/bor/validator_set.go b/consensus/bor/validator_set.go
index 2f22d5b59f389460c62a95a93b44ba0aba0bee7f..dbe987ce780dedc3fe1b96d0b5a86d0b757409f7 100644
--- a/consensus/bor/validator_set.go
+++ b/consensus/bor/validator_set.go
@@ -11,6 +11,7 @@ import (
 	"strings"
 
 	"github.com/maticnetwork/bor/common"
+	"github.com/maticnetwork/bor/log"
 )
 
 // MaxTotalVotingPower - the maximum allowed total voting power.
@@ -182,7 +183,7 @@ func computeMaxMinPriorityDiff(vals *ValidatorSet) int64 {
 func (vals *ValidatorSet) getValWithMostPriority() *Validator {
 	var res *Validator
 	for _, val := range vals.Validators {
-		res = res.CompareProposerPriority(val)
+		res = res.Cmp(val)
 	}
 	return res
 }
@@ -256,28 +257,29 @@ func (vals *ValidatorSet) Size() int {
 }
 
 // Force recalculation of the set's total voting power.
-func (vals *ValidatorSet) updateTotalVotingPower() {
+func (vals *ValidatorSet) updateTotalVotingPower() error {
 
 	sum := int64(0)
 	for _, val := range vals.Validators {
 		// mind overflow
 		sum = safeAddClip(sum, val.VotingPower)
 		if sum > MaxTotalVotingPower {
-			panic(fmt.Sprintf(
-				"Total voting power should be guarded to not exceed %v; got: %v",
-				MaxTotalVotingPower,
-				sum))
+			return &TotalVotingPowerExceededError{sum, vals.Validators}
 		}
 	}
-
 	vals.totalVotingPower = sum
+	return nil
 }
 
 // TotalVotingPower returns the sum of the voting powers of all validators.
 // It recomputes the total voting power if required.
 func (vals *ValidatorSet) TotalVotingPower() int64 {
 	if vals.totalVotingPower == 0 {
-		vals.updateTotalVotingPower()
+		log.Info("invoking updateTotalVotingPower before returning it")
+		if err := vals.updateTotalVotingPower(); err != nil {
+			// Can/should we do better?
+			panic(err)
+		}
 	}
 	return vals.totalVotingPower
 }
@@ -298,7 +300,7 @@ func (vals *ValidatorSet) findProposer() *Validator {
 	var proposer *Validator
 	for _, val := range vals.Validators {
 		if proposer == nil || !bytes.Equal(val.Address.Bytes(), proposer.Address.Bytes()) {
-			proposer = proposer.CompareProposerPriority(val)
+			proposer = proposer.Cmp(val)
 		}
 	}
 	return proposer
@@ -562,7 +564,9 @@ func (vals *ValidatorSet) updateWithChangeSet(changes []*Validator, allowDeletes
 	vals.applyUpdates(updates)
 	vals.applyRemovals(deletes)
 
-	vals.updateTotalVotingPower()
+	if err := vals.updateTotalVotingPower(); err != nil {
+		return err
+	}
 
 	// Scale and center.
 	vals.RescalePriorities(PriorityWindowSizeFactor * vals.TotalVotingPower())
diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go
index b90f61176647554ead76da13b30215d89416a91d..799ee16b2dac4521c6459dab1269fc4158ed4a5f 100644
--- a/consensus/clique/clique.go
+++ b/consensus/clique/clique.go
@@ -26,6 +26,7 @@ import (
 	"sync"
 	"time"
 
+	lru "github.com/hashicorp/golang-lru"
 	"github.com/maticnetwork/bor/accounts"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/common/hexutil"
@@ -39,7 +40,6 @@ import (
 	"github.com/maticnetwork/bor/params"
 	"github.com/maticnetwork/bor/rlp"
 	"github.com/maticnetwork/bor/rpc"
-	lru "github.com/hashicorp/golang-lru"
 	"golang.org/x/crypto/sha3"
 )
 
diff --git a/consensus/clique/snapshot.go b/consensus/clique/snapshot.go
index 593dfe8b997b17c9c8b8100e02d309cdb47bde53..a4063e351695ac59dd7d1c1706b0a5810299f951 100644
--- a/consensus/clique/snapshot.go
+++ b/consensus/clique/snapshot.go
@@ -22,12 +22,12 @@ import (
 	"sort"
 	"time"
 
+	lru "github.com/hashicorp/golang-lru"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/core/types"
 	"github.com/maticnetwork/bor/ethdb"
 	"github.com/maticnetwork/bor/log"
 	"github.com/maticnetwork/bor/params"
-	lru "github.com/hashicorp/golang-lru"
 )
 
 // Vote represents a single vote that an authorized signer made to modify the
diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go
index 999d92012ac5532558521468dc95b4e960d895e0..08a80ae8195d11a1d6628018e7d11be26c3d2ed3 100644
--- a/consensus/ethash/ethash.go
+++ b/consensus/ethash/ethash.go
@@ -34,13 +34,13 @@ import (
 	"unsafe"
 
 	mmap "github.com/edsrzf/mmap-go"
+	"github.com/hashicorp/golang-lru/simplelru"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/consensus"
 	"github.com/maticnetwork/bor/core/types"
 	"github.com/maticnetwork/bor/log"
 	"github.com/maticnetwork/bor/metrics"
 	"github.com/maticnetwork/bor/rpc"
-	"github.com/hashicorp/golang-lru/simplelru"
 )
 
 var ErrInvalidDumpMagic = errors.New("invalid dump magic")
diff --git a/core/headerchain.go b/core/headerchain.go
index 95634891fe7d3d2a523aeb5a6a1b55b48c9e907e..07775a228ac43cf27ce384004574773f93dd7547 100644
--- a/core/headerchain.go
+++ b/core/headerchain.go
@@ -26,6 +26,7 @@ import (
 	"sync/atomic"
 	"time"
 
+	lru "github.com/hashicorp/golang-lru"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/consensus"
 	"github.com/maticnetwork/bor/core/rawdb"
@@ -33,7 +34,6 @@ import (
 	"github.com/maticnetwork/bor/ethdb"
 	"github.com/maticnetwork/bor/log"
 	"github.com/maticnetwork/bor/params"
-	lru "github.com/hashicorp/golang-lru"
 )
 
 const (
diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go
index 868d81f6a518bf704629931f52c6a4538a736ab8..33c1ca8b34a2b7278a5a0b6ce9bb78cd0aafc818 100644
--- a/core/rawdb/freezer_table.go
+++ b/core/rawdb/freezer_table.go
@@ -26,10 +26,10 @@ import (
 	"sync"
 	"sync/atomic"
 
+	"github.com/golang/snappy"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/log"
 	"github.com/maticnetwork/bor/metrics"
-	"github.com/golang/snappy"
 )
 
 var (
diff --git a/core/state/database.go b/core/state/database.go
index 834e8ad96b45145932884a9387800cb6f5a8b347..33ab998c611e1277799b2a6fec8ca3059df54777 100644
--- a/core/state/database.go
+++ b/core/state/database.go
@@ -19,10 +19,10 @@ package state
 import (
 	"fmt"
 
+	lru "github.com/hashicorp/golang-lru"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/ethdb"
 	"github.com/maticnetwork/bor/trie"
-	lru "github.com/hashicorp/golang-lru"
 )
 
 const (
diff --git a/graphql/service.go b/graphql/service.go
index 473e01b250aacd39715a0f96093252d4dedf10d2..6b2626d927000140133a5705220402a4de58a81a 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -21,12 +21,12 @@ import (
 	"net"
 	"net/http"
 
+	"github.com/graph-gophers/graphql-go"
+	"github.com/graph-gophers/graphql-go/relay"
 	"github.com/maticnetwork/bor/internal/ethapi"
 	"github.com/maticnetwork/bor/log"
 	"github.com/maticnetwork/bor/p2p"
 	"github.com/maticnetwork/bor/rpc"
-	"github.com/graph-gophers/graphql-go"
-	"github.com/graph-gophers/graphql-go/relay"
 )
 
 // Service encapsulates a GraphQL service.
diff --git a/internal/debug/flags.go b/internal/debug/flags.go
index 8bd64b9bb939dbd1ef1033df4915e680ea12652c..469dd8dff2a8adbb9d4e6782963913f17505a110 100644
--- a/internal/debug/flags.go
+++ b/internal/debug/flags.go
@@ -24,10 +24,10 @@ import (
 	"os"
 	"runtime"
 
+	"github.com/fjl/memsize/memsizeui"
 	"github.com/maticnetwork/bor/log"
 	"github.com/maticnetwork/bor/metrics"
 	"github.com/maticnetwork/bor/metrics/exp"
-	"github.com/fjl/memsize/memsizeui"
 	colorable "github.com/mattn/go-colorable"
 	"github.com/mattn/go-isatty"
 	"gopkg.in/urfave/cli.v1"
diff --git a/light/lightchain.go b/light/lightchain.go
index cfa684e84624bd81221bcb0b5651d21d02660094..99f14ee3caa60140b78404fd3b3c9a865a570838 100644
--- a/light/lightchain.go
+++ b/light/lightchain.go
@@ -26,6 +26,7 @@ import (
 	"sync/atomic"
 	"time"
 
+	lru "github.com/hashicorp/golang-lru"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/consensus"
 	"github.com/maticnetwork/bor/core"
@@ -37,7 +38,6 @@ import (
 	"github.com/maticnetwork/bor/log"
 	"github.com/maticnetwork/bor/params"
 	"github.com/maticnetwork/bor/rlp"
-	lru "github.com/hashicorp/golang-lru"
 )
 
 var (
diff --git a/metrics/influxdb/influxdb.go b/metrics/influxdb/influxdb.go
index 5971c50aa3b525b54582897c4f89d3070534d717..d4452bc6d35fcc63080976900c415a5fe7a6ee6d 100644
--- a/metrics/influxdb/influxdb.go
+++ b/metrics/influxdb/influxdb.go
@@ -5,9 +5,9 @@ import (
 	uurl "net/url"
 	"time"
 
+	"github.com/influxdata/influxdb/client"
 	"github.com/maticnetwork/bor/log"
 	"github.com/maticnetwork/bor/metrics"
-	"github.com/influxdata/influxdb/client"
 )
 
 type reporter struct {
diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go
index 08b7a39ddaf91ea2305f64cff4e53055e66191ba..0f5cd07c050515a47794c2bf9d8127a0fae6484b 100644
--- a/p2p/nat/nat.go
+++ b/p2p/nat/nat.go
@@ -25,8 +25,8 @@ import (
 	"sync"
 	"time"
 
-	"github.com/maticnetwork/bor/log"
 	"github.com/jackpal/go-nat-pmp"
+	"github.com/maticnetwork/bor/log"
 )
 
 // An implementation of nat.Interface can map local ports to ports
diff --git a/p2p/rlpx.go b/p2p/rlpx.go
index 1513ed9d09fb95883a75fc1e737cb439990d6d85..36f845332fb5ea144d93e5cf8cc080b4427a2731 100644
--- a/p2p/rlpx.go
+++ b/p2p/rlpx.go
@@ -35,11 +35,11 @@ import (
 	"sync"
 	"time"
 
+	"github.com/golang/snappy"
 	"github.com/maticnetwork/bor/common/bitutil"
 	"github.com/maticnetwork/bor/crypto"
 	"github.com/maticnetwork/bor/crypto/ecies"
 	"github.com/maticnetwork/bor/rlp"
-	"github.com/golang/snappy"
 	"golang.org/x/crypto/sha3"
 )
 
diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go
index c42f2e8a0c67f37df7aa08b166ae1844ae843814..55119851f289e29d0be3c2f8106f0d1bdca45592 100644
--- a/p2p/simulations/http.go
+++ b/p2p/simulations/http.go
@@ -29,12 +29,12 @@ import (
 	"strings"
 	"sync"
 
+	"github.com/julienschmidt/httprouter"
 	"github.com/maticnetwork/bor/event"
 	"github.com/maticnetwork/bor/p2p"
 	"github.com/maticnetwork/bor/p2p/enode"
 	"github.com/maticnetwork/bor/p2p/simulations/adapters"
 	"github.com/maticnetwork/bor/rpc"
-	"github.com/julienschmidt/httprouter"
 	"golang.org/x/net/websocket"
 )