diff --git a/.github/workflows/linuxpackage.yml b/.github/workflows/linuxpackage.yml
index 71c2ff477ebe46108a27fd41b6f3ea82721f6bcc..f41bc311ad2a62f6d46222fa38fc7688a7c2a5bc 100644
--- a/.github/workflows/linuxpackage.yml
+++ b/.github/workflows/linuxpackage.yml
@@ -3,7 +3,7 @@ name: Linux package
 on:
   push:
     tags:
-      - 'v*.*.*'
+      - "v*.*.*"
 jobs:
   build:
     runs-on: ubuntu-latest
@@ -30,7 +30,7 @@ jobs:
           sudo apt-get -yqq install libpq-dev build-essential
           gem install --no-document fpm
           fpm --version
-          
+
           make bor
 
           cat > bor.service <<- "EOF"
@@ -39,8 +39,7 @@ jobs:
           [Service]
           WorkingDirectory=/etc/bor/
           EnvironmentFile=/etc/bor/metadata
-          ExecStartPre=/bin/mkdir -p /var/log/matic-logs/
-          ExecStart=/bin/bash -c "/usr/bin/bor --datadir /etc/bor/dataDir --port '30303' --rpc --rpcaddr '0.0.0.0' --rpcvhosts '*' --rpccorsdomain '*' --rpcport '8545' --ipcpath /etc/bor/geth.ipc --rpcapi 'bor,db,eth,net,web3,txpool' --networkid ${NETWORK_ID} --gasprice '0' --keystore /etc/bor/dataDir/keystore --unlock ${VALIDATOR_ADDRESS} --password /etc/bor/dataDir/password.txt --allow-insecure-unlock --maxpeers 150 --mine > /var/log/matic-logs/bor.log 2>&1"
+          ExecStart=/bin/bash -c "/usr/bin/bor --datadir /etc/bor/dataDir --port '30303' --rpc --rpcaddr '0.0.0.0' --rpcvhosts '*' --rpccorsdomain '*' --rpcport '8545' --ipcpath /etc/bor/bor.ipc --rpcapi 'db,eth,net,web3,txpool,bor' --networkid ${NETWORK_ID} --miner.gaslimit '20000000' --txpool.nolocals --txpool.accountslots '128' --txpool.globalslots '20000' --txpool.lifetime '0h16m0s' --keystore /etc/bor/dataDir/keystore --unlock ${VALIDATOR_ADDRESS} --password /etc/bor/dataDir/password.txt --allow-insecure-unlock --maxpeers 150 --mine"
           Type=simple
           User=root
           EOF
@@ -60,7 +59,7 @@ jobs:
             bor.service=/etc/systemd/system/ \
             build/bin/bor=/usr/bin/ \
             metadata=/etc/bor/
-          
+
           mkdir packages-v${{ env.RELEASE_VERSION }}
 
           mv matic-bor_${{ env.RELEASE_VERSION }}_amd64.deb packages-v${{ env.RELEASE_VERSION }}/
@@ -75,14 +74,14 @@ jobs:
           AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
           AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
           AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
-          AWS_REGION: 'us-east-1'   # optional: defaults to us-east-1
-          SOURCE_DIR: 'packages-v${{ env.RELEASE_VERSION }}'
-          DEST_DIR: 'v${{ env.RELEASE_VERSION }}'
+          AWS_REGION: "us-east-1" # optional: defaults to us-east-1
+          SOURCE_DIR: "packages-v${{ env.RELEASE_VERSION }}"
+          DEST_DIR: "v${{ env.RELEASE_VERSION }}"
 
       - name: Slack Notification
         uses: rtCamp/action-slack-notify@v2.0.0
         env:
           SLACK_CHANNEL: code-releases
           SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
-          SLACK_TITLE: 'New linux package for Bor v${{ env.RELEASE_VERSION }} just got released'
-          SLACK_MESSAGE: 'Package has been uploaded to S3 bucket for public use and available at https://matic-public.s3.amazonaws.com/v${{ env.RELEASE_VERSION }}/matic-bor_${{ env.RELEASE_VERSION }}_amd64.deb'
+          SLACK_TITLE: "New linux package for Bor v${{ env.RELEASE_VERSION }} just got released"
+          SLACK_MESSAGE: "Package has been uploaded to S3 bucket for public use and available at https://matic-public.s3.amazonaws.com/v${{ env.RELEASE_VERSION }}/matic-bor_${{ env.RELEASE_VERSION }}_amd64.deb"
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/cmd/bor/chaincmd.go b/cmd/bor/chaincmd.go
index bbb8792a16e83879cb37f70bc92e6561a7eb79e7..83d3261566ec92a157dde9adce7cee4c6fcff5ba 100644
--- a/cmd/bor/chaincmd.go
+++ b/cmd/bor/chaincmd.go
@@ -64,6 +64,7 @@ It expects the genesis file as argument.`,
 		ArgsUsage: "<filename> (<filename 2> ... <filename N>) <genesisPath>",
 		Flags: []cli.Flag{
 			utils.DataDirFlag,
+			utils.HeimdallURLFlag,
 			utils.CacheFlag,
 			utils.SyncModeFlag,
 			utils.GCModeFlag,
diff --git a/cmd/bor/config.go b/cmd/bor/config.go
index 4929d826eb0be37d7b9cec6c3f56d8130a33ac4e..9202fec7c4daebd0b9775f94d19689979466101c 100644
--- a/cmd/bor/config.go
+++ b/cmd/bor/config.go
@@ -151,7 +151,7 @@ func enableWhisper(ctx *cli.Context) bool {
 
 func makeFullNode(ctx *cli.Context) *node.Node {
 	stack, cfg := makeConfigNode(ctx)
-	cfg.Eth.HeimdallURL = ctx.String(utils.HeimdallURLFlag.Name)
+	cfg.Eth.HeimdallURL = ctx.GlobalString(utils.HeimdallURLFlag.Name)
 	log.Info("Connecting to heimdall service on...", "heimdallURL", cfg.Eth.HeimdallURL)
 	utils.RegisterEthService(stack, &cfg.Eth)
 
diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go
index 695005f0907af8c41a6c6bf5c53c1644cad8cc53..e431c17dd5b5bd69cc255db95c4c6a90cf924b26 100644
--- a/cmd/puppeth/wizard_genesis.go
+++ b/cmd/puppeth/wizard_genesis.go
@@ -111,6 +111,7 @@ func (w *wizard) makeGenesis() {
 			Period:                1,
 			ProducerDelay:         5,
 			Sprint:                60,
+			BackupMultiplier:      1,
 			ValidatorContract:     "0x0000000000000000000000000000000000001000",
 			StateReceiverContract: "0x0000000000000000000000000000000000001001",
 		}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index fa0aa9bf163027368bad09af0375bb4f6687c11f..78a70beabeba715c8758671bdbd8bd9f2295b669 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1694,7 +1694,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
 	if config.Clique != nil {
 		engine = clique.New(config.Clique, chainDb)
 	} else if config.Bor != nil {
-		cfg := &eth.Config{Genesis: genesis}
+		cfg := &eth.Config{Genesis: genesis, HeimdallURL: ctx.GlobalString(HeimdallURLFlag.Name)}
 		workspace, err := ioutil.TempDir("", "console-tester-")
 		if err != nil {
 			Fatalf("failed to create temporary keystore: %v", err)
diff --git a/consensus/bor/api.go b/consensus/bor/api.go
index 98f7c46b6e615f3adc7625b0c7699cfdc189fc85..5af1ddbc39c2b6acd3c0531b71c3ba05d6e70d75 100644
--- a/consensus/bor/api.go
+++ b/consensus/bor/api.go
@@ -17,17 +17,33 @@
 package bor
 
 import (
+	"encoding/hex"
+	"math"
+	"math/big"
+	"strconv"
+	"sync"
+
+	lru "github.com/hashicorp/golang-lru"
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/consensus"
 	"github.com/maticnetwork/bor/core/types"
+	"github.com/maticnetwork/bor/crypto"
 	"github.com/maticnetwork/bor/rpc"
+	"github.com/xsleonard/go-merkle"
+	"golang.org/x/crypto/sha3"
+)
+
+var (
+	// MaxCheckpointLength is the maximum number of blocks that can be requested for constructing a checkpoint root hash
+	MaxCheckpointLength = uint64(math.Pow(2, 15))
 )
 
 // API is a user facing RPC API to allow controlling the signer and voting
 // mechanisms of the proof-of-authority scheme.
 type API struct {
-	chain consensus.ChainReader
-	bor   *Bor
+	chain         consensus.ChainReader
+	bor           *Bor
+	rootHashCache *lru.ARCCache
 }
 
 // GetSnapshot retrieves the state snapshot at a given block.
@@ -105,3 +121,71 @@ func (api *API) GetCurrentValidators() ([]*Validator, error) {
 	}
 	return snap.ValidatorSet.Validators, nil
 }
+
+// GetRootHash returns the merkle root of the start to end block headers
+func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
+	if err := api.initializeRootHashCache(); err != nil {
+		return "", err
+	}
+	key := getRootHashKey(start, end)
+	if root, known := api.rootHashCache.Get(key); known {
+		return root.(string), nil
+	}
+	length := uint64(end - start + 1)
+	if length > MaxCheckpointLength {
+		return "", &MaxCheckpointLengthExceededError{start, end}
+	}
+	currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64()
+	if start > end || end > currentHeaderNumber {
+		return "", &InvalidStartEndBlockError{start, end, currentHeaderNumber}
+	}
+	blockHeaders := make([]*types.Header, end-start+1)
+	wg := new(sync.WaitGroup)
+	concurrent := make(chan bool, 20)
+	for i := start; i <= end; i++ {
+		wg.Add(1)
+		concurrent <- true
+		go func(number uint64) {
+			blockHeaders[number-start] = api.chain.GetHeaderByNumber(uint64(number))
+			<-concurrent
+			wg.Done()
+		}(i)
+	}
+	wg.Wait()
+	close(concurrent)
+
+	headers := make([][32]byte, nextPowerOfTwo(length))
+	for i := 0; i < len(blockHeaders); i++ {
+		blockHeader := blockHeaders[i]
+		header := crypto.Keccak256(appendBytes32(
+			blockHeader.Number.Bytes(),
+			new(big.Int).SetUint64(blockHeader.Time).Bytes(),
+			blockHeader.TxHash.Bytes(),
+			blockHeader.ReceiptHash.Bytes(),
+		))
+
+		var arr [32]byte
+		copy(arr[:], header)
+		headers[i] = arr
+	}
+
+	tree := merkle.NewTreeWithOpts(merkle.TreeOptions{EnableHashSorting: false, DisableHashLeaves: true})
+	if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil {
+		return "", err
+	}
+	root := hex.EncodeToString(tree.Root().Hash)
+	api.rootHashCache.Add(key, root)
+	return root, nil
+}
+
+func (api *API) initializeRootHashCache() error {
+	var err error
+	if api.rootHashCache == nil {
+		api.rootHashCache, err = lru.NewARC(10)
+	}
+	return err
+}
+
+func getRootHashKey(start uint64, end uint64) string {
+	return strconv.FormatUint(start, 10) + "-" + strconv.FormatUint(end, 10)
+}
diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go
index a59fecd2e8f3750ad9fe7fbbb21d808dacf7fc6d..f456dc871c16d10f33c1d31e55a0633393eff96f 100644
--- a/consensus/bor/bor.go
+++ b/consensus/bor/bor.go
@@ -12,7 +12,6 @@ import (
 	"math/big"
 
 	"sort"
-	"strconv"
 	"strings"
 	"sync"
 	"time"
@@ -41,9 +40,6 @@ import (
 	"golang.org/x/crypto/sha3"
 )
 
-const validatorsetABI = `[{"constant":true,"inputs":[{"name":"span","type":"uint256"}],"name":"getSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"number","type":"uint256"}],"name":"getBorValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"span","type":"uint256"},{"name":"signer","type":"address"}],"name":"isProducer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newSpan","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"},{"name":"validatorBytes","type":"bytes"},{"name":"producerBytes","type":"bytes"}],"name":"commitSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"span","type":"uint256"},{"name":"signer","type":"address"}],"name":"isValidator","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"proposeSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentSpanNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNextSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitialValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"spanProposalPending","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"number","type":"uint256"}],"name":"getSpanByBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"vote","type":"bytes"},{"name":"sigs","type":"bytes"},{"name":"txBytes","type":"bytes"},{"name":"proof","type":"bytes"}],"name":"validateValidatorSet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
-const stateReceiverABI = `[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"states","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"recordBytes","type":"bytes"}],"name":"commitState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getPendingStates","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"validatorSet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"vote","type":"bytes"},{"name":"sigs","type":"bytes"},{"name":"txBytes","type":"bytes"},{"name":"proof","type":"bytes"}],"name":"validateValidatorSet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isValidatorSetContract","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"stateId","type":"uint256"}],"name":"proposeState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"signer","type":"address"}],"name":"isProducer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"signer","type":"address"}],"name":"isValidator","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]`
-
 const (
 	checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database
 	inmemorySnapshots  = 128  // Number of recent vote snapshots to keep in memory
@@ -105,10 +101,6 @@ var (
 	// invalid list of validators (i.e. non divisible by 40 bytes).
 	errInvalidSpanValidators = errors.New("invalid validator list on sprint end block")
 
-	// errMismatchingSprintValidators is returned if a sprint block contains a
-	// list of validators different than the one the local node calculated.
-	errMismatchingSprintValidators = errors.New("mismatching validator list on sprint block")
-
 	// errInvalidMixDigest is returned if a block's mix digest is non-zero.
 	errInvalidMixDigest = errors.New("non-zero mix digest")
 
@@ -118,10 +110,6 @@ var (
 	// errInvalidDifficulty is returned if the difficulty of a block neither 1 or 2.
 	errInvalidDifficulty = errors.New("invalid difficulty")
 
-	// errWrongDifficulty is returned if the difficulty of a block doesn't match the
-	// turn of the signer.
-	errWrongDifficulty = errors.New("wrong difficulty")
-
 	// ErrInvalidTimestamp is returned if the timestamp of a block is lower than
 	// the previous block's timestamp + the minimum block period.
 	ErrInvalidTimestamp = errors.New("invalid timestamp")
@@ -129,13 +117,6 @@ var (
 	// errOutOfRangeChain is returned if an authorization list is attempted to
 	// be modified via out-of-range or non-contiguous headers.
 	errOutOfRangeChain = errors.New("out of range or non-contiguous chain")
-
-	// errUnauthorizedSigner is returned if a header is signed by a non-authorized entity.
-	errUnauthorizedSigner = errors.New("unauthorized signer")
-
-	// errRecentlySigned is returned if a header is signed by an authorized entity
-	// that already signed a header recently, thus is temporarily not allowed to.
-	errRecentlySigned = errors.New("recently signed")
 )
 
 // SignerFn is a signer callback function to request a header to be signed by a
@@ -198,21 +179,18 @@ 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))
-}
-
-// CalcProducerDelay is the producer delay algorithm based on block time.
-func CalcProducerDelay(snap *Snapshot, signer common.Address, period uint64, epoch uint64, producerDelay uint64) uint64 {
-	// if block is epoch start block, proposer will be inturn signer
-	if (snap.Number+1)%epoch == 0 {
-		return producerDelay
+// CalcProducerDelay is the block delay algorithm based on block time, period, producerDelay and turn-ness of a signer
+func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint64 {
+	// When the block is the first block of the sprint, it is expected to be delayed by `producerDelay`.
+	// That is to allow time for block propagation in the last sprint
+	delay := c.Period
+	if number%c.Sprint == 0 {
+		delay = c.ProducerDelay
 	}
-
-	return period
+	if succession > 0 {
+		delay += uint64(succession) * c.BackupMultiplier
+	}
+	return delay
 }
 
 // BorRLP returns the rlp bytes which needs to be signed for the bor
@@ -241,10 +219,11 @@ type Bor struct {
 	signFn SignerFn       // Signer function to authorize hashes with
 	lock   sync.RWMutex   // Protects the signer fields
 
-	ethAPI           *ethapi.PublicBlockChainAPI
-	validatorSetABI  abi.ABI
-	stateReceiverABI abi.ABI
-	HeimdallClient   IHeimdallClient
+	ethAPI                 *ethapi.PublicBlockChainAPI
+	GenesisContractsClient *GenesisContractsClient
+	validatorSetABI        abi.ABI
+	stateReceiverABI       abi.ABI
+	HeimdallClient         IHeimdallClient
 
 	stateDataFeed event.Feed
 	scope         event.SubscriptionScope
@@ -273,17 +252,18 @@ func New(
 	vABI, _ := abi.JSON(strings.NewReader(validatorsetABI))
 	sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI))
 	heimdallClient, _ := NewHeimdallClient(heimdallURL)
-
+	genesisContractsClient := NewGenesisContractsClient(chainConfig, borConfig.ValidatorContract, borConfig.StateReceiverContract, ethAPI)
 	c := &Bor{
-		chainConfig:      chainConfig,
-		config:           borConfig,
-		db:               db,
-		ethAPI:           ethAPI,
-		recents:          recents,
-		signatures:       signatures,
-		validatorSetABI:  vABI,
-		stateReceiverABI: sABI,
-		HeimdallClient:   heimdallClient,
+		chainConfig:            chainConfig,
+		config:                 borConfig,
+		db:                     db,
+		ethAPI:                 ethAPI,
+		recents:                recents,
+		signatures:             signatures,
+		validatorSetABI:        vABI,
+		stateReceiverABI:       sABI,
+		GenesisContractsClient: genesisContractsClient,
+		HeimdallClient:         heimdallClient,
 	}
 
 	return c
@@ -335,12 +315,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
@@ -376,6 +353,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
@@ -409,8 +398,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 {
+	// verify the validator list in the last sprint block
+	if isSprintStart(number, c.config.Sprint) {
+		parentValidatorBytes := parent.Extra[extraVanity : len(parent.Extra)-extraSeal]
 		validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength)
 
 		currentValidators := snap.ValidatorSet.Copy().Validators
@@ -419,14 +409,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(parentValidatorBytes, validatorsBytes) {
+			return &MismatchingValidatorsError{number - 1, validatorsBytes, parentValidatorBytes}
 		}
 	}
 
@@ -463,7 +448,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
@@ -568,37 +553,31 @@ func (c *Bor) verifySeal(chain consensus.ChainReader, header *types.Header, pare
 		return err
 	}
 	if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
-		return errUnauthorizedSigner
+		// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
+		return &UnauthorizedSignerError{number - 1, signer.Bytes()}
 	}
 
-	// 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]
+	succession, err := snap.GetSignerSuccessionNumber(signer)
+	if err != nil {
+		return err
 	}
-	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)
-		}
+	var parent *types.Header
+	if len(parents) > 0 { // if parents is nil, len(parents) is zero
+		parent = parents[len(parents)-1]
+	} else if number > 0 {
+		parent = chain.GetHeader(header.ParentHash, number-1)
+	}
 
-		if tempIndex-proposerIndex > limit {
-			return errRecentlySigned
-		}
+	if parent != nil && header.Time < parent.Time+CalcProducerDelay(number, succession, c.config) {
+		return &BlockTooSoonError{number, succession}
 	}
 
 	// Ensure that the difficulty corresponds to the turn-ness of the signer
 	if !c.fakeDiff {
-		difficulty := snap.inturn(header.Number.Uint64(), signer, c.config.Sprint)
+		difficulty := snap.Difficulty(signer)
 		if header.Difficulty.Uint64() != difficulty {
-			return errWrongDifficulty
+			return &WrongDifficultyError{number, difficulty, header.Difficulty.Uint64(), signer.Bytes()}
 		}
 	}
 
@@ -620,7 +599,7 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error {
 	}
 
 	// Set the correct difficulty
-	header.Difficulty = CalcDifficulty(snap, c.signer, c.config.Sprint)
+	header.Difficulty = new(big.Int).SetUint64(snap.Difficulty(c.signer))
 
 	// Ensure the extra data has all it's components
 	if len(header.Extra) < extraVanity {
@@ -654,7 +633,16 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error {
 		return consensus.ErrUnknownAncestor
 	}
 
-	header.Time = parent.Time + CalcProducerDelay(snap, c.signer, c.config.Period, c.config.Sprint, c.config.ProducerDelay)
+	var succession int
+	// if signer is not empty
+	if bytes.Compare(c.signer.Bytes(), common.Address{}.Bytes()) != 0 {
+		succession, err = snap.GetSignerSuccessionNumber(c.signer)
+		if err != nil {
+			return err
+		}
+	}
+
+	header.Time = parent.Time + CalcProducerDelay(number, succession, c.config)
 	if header.Time < uint64(time.Now().Unix()) {
 		header.Time = uint64(time.Now().Unix())
 	}
@@ -664,9 +652,7 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error {
 // Finalize implements consensus.Engine, ensuring no uncles are set, nor block
 // rewards given.
 func (c *Bor) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) {
-	// commit span
 	headerNumber := header.Number.Uint64()
-
 	if headerNumber%c.config.Sprint == 0 {
 		cx := chainContext{Chain: chain, Bor: c}
 		// check and commit span
@@ -674,6 +660,7 @@ func (c *Bor) Finalize(chain consensus.ChainReader, header *types.Header, state
 			log.Error("Error while committing span", "error", err)
 			return
 		}
+
 		// commit statees
 		if err := c.CommitStates(state, header, cx); err != nil {
 			log.Error("Error while committing states", "error", err)
@@ -689,8 +676,8 @@ func (c *Bor) Finalize(chain consensus.ChainReader, header *types.Header, state
 // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
 // nor block rewards given, and returns the final block.
 func (c *Bor) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
-	// commit span
-	if header.Number.Uint64()%c.config.Sprint == 0 {
+	headerNumber := header.Number.Uint64()
+	if headerNumber%c.config.Sprint == 0 {
 		cx := chainContext{Chain: chain, Bor: c}
 
 		// check and commit span
@@ -703,7 +690,7 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Hea
 		// commit statees
 		if err := c.CommitStates(state, header, cx); err != nil {
 			log.Error("Error while committing states", "error", err)
-			// return nil, err
+			return nil, err
 		}
 	}
 
@@ -752,38 +739,19 @@ func (c *Bor) Seal(chain consensus.ChainReader, block *types.Block, results chan
 
 	// Bail out if we're unauthorized to sign a block
 	if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
-		return errUnauthorizedSigner
+		// Check the UnauthorizedSignerError.Error() msg to see why we pass number-1
+		return &UnauthorizedSignerError{number - 1, signer.Bytes()}
 	}
 
-	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)
-	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())
+	// wiggle was already accounted for in header.Time, this is just for logging
+	wiggle := time.Duration(successionNumber) * time.Duration(c.config.BackupMultiplier) * time.Second
 
 	// Sign all the things!
 	sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header))
@@ -797,17 +765,30 @@ func (c *Bor) Seal(chain consensus.ChainReader, block *types.Block, results chan
 	go func() {
 		select {
 		case <-stop:
+			log.Debug("Discarding sealing operation for block", "number", number)
 			return
 		case <-time.After(delay):
+			if wiggle > 0 {
+				log.Info(
+					"Sealing out-of-turn",
+					"number", number,
+					"wiggle", common.PrettyDuration(wiggle),
+					"in-turn-signer", snap.ValidatorSet.GetProposer().Address.Hex(),
+				)
+			}
+			log.Info(
+				"Sealing successful",
+				"number", number,
+				"delay", delay,
+				"headerDifficulty", header.Difficulty,
+			)
 		}
-
 		select {
 		case results <- block.WithSeal(header):
 		default:
-			log.Warn("Sealing result is not read by miner", "sealhash", SealHash(header))
+			log.Warn("Sealing result was not read by miner", "number", number, "sealhash", SealHash(header))
 		}
 	}()
-
 	return nil
 }
 
@@ -819,7 +800,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *t
 	if err != nil {
 		return nil
 	}
-	return CalcDifficulty(snap, c.signer, c.config.Sprint)
+	return new(big.Int).SetUint64(snap.Difficulty(c.signer))
 }
 
 // SealHash returns the hash of a block prior to it being sealed.
@@ -843,42 +824,6 @@ func (c *Bor) Close() error {
 	return nil
 }
 
-// Checks if new span is pending
-func (c *Bor) isSpanPending(snapshotNumber uint64) (bool, error) {
-	blockNr := rpc.BlockNumber(snapshotNumber)
-	method := "spanProposalPending"
-
-	// get packed data
-	data, err := c.validatorSetABI.Pack(method)
-	if err != nil {
-		log.Error("Unable to pack tx for spanProposalPending", "error", err)
-		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{
-		Gas:  &gas,
-		To:   &toAddress,
-		Data: &msgData,
-	}, blockNr)
-	if err != nil {
-		return false, err
-	}
-
-	var ret0 = new(bool)
-	if err := c.validatorSetABI.Unpack(ret0, method, result); err != nil {
-		return false, err
-	}
-
-	return *ret0, nil
-}
-
 // GetCurrentSpan get current span from contract
 func (c *Bor) GetCurrentSpan(snapshotNumber uint64) (*Span, error) {
 	// block
@@ -893,14 +838,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,
@@ -943,14 +884,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,
@@ -990,37 +928,14 @@ func (c *Bor) checkAndCommitSpan(
 	chain core.ChainContext,
 ) error {
 	headerNumber := header.Number.Uint64()
-	pending := false
-	var span *Span = nil
-	errors := make(chan error)
-	go func() {
-		var err error
-		pending, err = c.isSpanPending(headerNumber - 1)
-		errors <- err
-	}()
-
-	go func() {
-		var err error
-		span, err = c.GetCurrentSpan(headerNumber - 1)
-		errors <- err
-	}()
-
-	var err error
-	for i := 0; i < 2; i++ {
-		err = <-errors
-		if err != nil {
-			close(errors)
-			return err
-		}
+	span, err := c.GetCurrentSpan(headerNumber - 1)
+	if err != nil {
+		return err
 	}
-	close(errors)
-
-	// commit span if there is new span pending or span is ending or end block is not set
-	if pending || c.needToCommitSpan(span, headerNumber) {
+	if c.needToCommitSpan(span, headerNumber) {
 		err := c.fetchAndCommitSpan(span.ID+1, state, header, chain)
 		return err
 	}
-
 	return nil
 }
 
@@ -1049,7 +964,7 @@ func (c *Bor) fetchAndCommitSpan(
 	header *types.Header,
 	chain core.ChainContext,
 ) error {
-	response, err := c.HeimdallClient.FetchWithRetry("bor", "span", strconv.FormatUint(newSpanID, 10))
+	response, err := c.HeimdallClient.FetchWithRetry(fmt.Sprintf("bor/span/%d", newSpanID), "")
 
 	if err != nil {
 		return err
@@ -1133,13 +1048,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,
@@ -1160,83 +1072,55 @@ func (c *Bor) GetPendingStateProposals(snapshotNumber uint64) ([]*big.Int, error
 func (c *Bor) CommitStates(
 	state *state.StateDB,
 	header *types.Header,
-	chain core.ChainContext,
+	chain chainContext,
 ) error {
-	// get pending state proposals
-	stateIds, err := c.GetPendingStateProposals(header.Number.Uint64() - 1)
+	number := header.Number.Uint64()
+	_lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
 	if err != nil {
 		return err
 	}
 
-	// state ids
-	if len(stateIds) > 0 {
-		log.Debug("Found new proposed states", "numberOfStates", len(stateIds))
-	}
-
-	method := "commitState"
+	to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.Sprint).Time), 0)
+	lastStateID := _lastStateID.Uint64()
+	log.Info(
+		"Fetching state updates from Heimdall",
+		"fromID", lastStateID+1,
+		"to", to.Format(time.RFC3339))
+	eventRecords, err := c.HeimdallClient.FetchStateSyncEvents(lastStateID+1, to.Unix())
 
-	// itereate through state ids
-	for _, stateID := range stateIds {
-		// fetch from heimdall
-		response, err := c.HeimdallClient.FetchWithRetry("clerk", "event-record", strconv.FormatUint(stateID.Uint64(), 10))
-		if err != nil {
-			return err
+	chainID := c.chainConfig.ChainID.String()
+	for _, eventRecord := range eventRecords {
+		if eventRecord.ID <= lastStateID {
+			continue
 		}
-
-		// get event record
-		var eventRecord EventRecord
-		if err := json.Unmarshal(response.Result, &eventRecord); err != nil {
-			return err
-		}
-
-		// check if chain id matches with event record
-		if eventRecord.ChainID != "" && eventRecord.ChainID != c.chainConfig.ChainID.String() {
-			return fmt.Errorf(
-				"Chain id proposed state in span, %s, and bor chain id, %s, doesn't match",
-				eventRecord.ChainID,
-				c.chainConfig.ChainID,
-			)
+		if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
+			log.Error(err.Error())
+			break
 		}
 
-		log.Info("→ committing new state",
-			"id", eventRecord.ID,
-			"contract", eventRecord.Contract,
-			"data", hex.EncodeToString(eventRecord.Data),
-			"txHash", eventRecord.TxHash,
-			"chainID", eventRecord.ChainID,
-		)
 		stateData := types.StateData{
 			Did:      eventRecord.ID,
 			Contract: eventRecord.Contract,
 			Data:     hex.EncodeToString(eventRecord.Data),
 			TxHash:   eventRecord.TxHash,
 		}
-
 		go func() {
 			c.stateDataFeed.Send(core.NewStateChangeEvent{StateData: &stateData})
 		}()
 
-		recordBytes, err := rlp.EncodeToBytes(eventRecord)
-		if err != nil {
-			return err
-		}
-
-		// get packed data for commit state
-		data, err := c.stateReceiverABI.Pack(method, recordBytes)
-		if err != nil {
-			log.Error("Unable to pack tx for commitState", "error", err)
-			return err
-		}
-
-		// get system message
-		msg := getSystemMessage(common.HexToAddress(c.config.StateReceiverContract), data)
-
-		// apply message
-		if err := applyMessage(msg, state, header, c.chainConfig, chain); err != nil {
+		if err := c.GenesisContractsClient.CommitState(eventRecord, state, header, chain); err != nil {
 			return err
 		}
+		lastStateID++
 	}
+	return nil
+}
 
+func validateEventRecord(eventRecord *EventRecordWithTime, number uint64, to time.Time, lastStateID uint64, chainID string) error {
+	// event id should be sequential and event.Time should lie in the range [from, to)
+	if lastStateID+1 != eventRecord.ID || eventRecord.ChainID != chainID || !eventRecord.Time.Before(to) {
+		return &InvalidStateReceivedError{number, lastStateID, &to, eventRecord}
+	}
 	return nil
 }
 
@@ -1249,48 +1133,6 @@ func (c *Bor) SetHeimdallClient(h IHeimdallClient) {
 	c.HeimdallClient = h
 }
 
-func (c *Bor) IsValidatorAction(chain consensus.ChainReader, from common.Address, tx *types.Transaction) bool {
-	header := chain.CurrentHeader()
-	validators, err := c.GetCurrentValidators(header.Number.Uint64(), header.Number.Uint64()+1)
-	if err != nil {
-		log.Error("Failed fetching snapshot", err)
-		return false
-	}
-
-	isValidator := false
-	for _, validator := range validators {
-		if bytes.Compare(validator.Address.Bytes(), from.Bytes()) == 0 {
-			isValidator = true
-			break
-		}
-	}
-
-	return isValidator && (isProposeSpanAction(tx, chain.Config().Bor.ValidatorContract) ||
-		isProposeStateAction(tx, chain.Config().Bor.StateReceiverContract))
-}
-
-func isProposeSpanAction(tx *types.Transaction, validatorContract string) bool {
-	// keccak256('proposeSpan()').slice(0, 4)
-	proposeSpanSig, _ := hex.DecodeString("4b0e4d17")
-	if tx.Data() == nil || len(tx.Data()) < 4 {
-		return false
-	}
-
-	return bytes.Compare(proposeSpanSig, tx.Data()[:4]) == 0 &&
-		tx.To().String() == validatorContract
-}
-
-func isProposeStateAction(tx *types.Transaction, stateReceiverContract string) bool {
-	// keccak256('proposeState(uint256)').slice(0, 4)
-	proposeStateSig, _ := hex.DecodeString("ede01f17")
-	if tx.Data() == nil || len(tx.Data()) < 4 {
-		return false
-	}
-
-	return bytes.Compare(proposeStateSig, tx.Data()[:4]) == 0 &&
-		tx.To().String() == stateReceiverContract
-}
-
 //
 // Private methods
 //
@@ -1403,3 +1245,7 @@ func getUpdatedValidatorSet(oldValidatorSet *ValidatorSet, newVals []*Validator)
 	v.UpdateWithChangeSet(changes)
 	return v
 }
+
+func isSprintStart(number, sprint uint64) bool {
+	return number%sprint == 0
+}
diff --git a/consensus/bor/bor_test/bor_test.go b/consensus/bor/bor_test/bor_test.go
index ce1585f6f2f8788c8b2c1d709b00a706685ee6fd..2994143d12a5f7d28271723d0436b9a0fa564a36 100644
--- a/consensus/bor/bor_test/bor_test.go
+++ b/consensus/bor/bor_test/bor_test.go
@@ -2,130 +2,269 @@ package bortest
 
 import (
 	"encoding/hex"
+	"encoding/json"
 	"math/big"
 	"testing"
+	"time"
 
-	"github.com/maticnetwork/bor/common"
-	"github.com/maticnetwork/bor/consensus/bor"
-	"github.com/maticnetwork/bor/core/rawdb"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
 
+	"github.com/maticnetwork/bor/consensus/bor"
+	"github.com/maticnetwork/bor/core/rawdb"
 	"github.com/maticnetwork/bor/core/types"
-
+	"github.com/maticnetwork/bor/crypto"
 	"github.com/maticnetwork/bor/mocks"
 )
 
-func TestCommitSpan(t *testing.T) {
+var (
+	spanPath         = "bor/span/1"
+	clerkPath        = "clerk/event-record/list"
+	clerkQueryParams = "from-time=%d&to-time=%d&page=%d&limit=50"
+)
+
+func TestInsertingSpanSizeBlocks(t *testing.T) {
 	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
 	chain := init.ethereum.BlockChain()
 	engine := init.ethereum.Engine()
 	_bor := engine.(*bor.Bor)
-
-	// Mock HeimdallClient.FetchWithRetry to return span data from span.json
-	res, heimdallSpan := loadSpanFromFile(t)
-	h := &mocks.IHeimdallClient{}
-	h.On("FetchWithRetry", "bor", "span", "1").
-		Return(res, nil).
-		Times(2) // both FinalizeAndAssemble and chain.InsertChain call HeimdallClient.FetchWithRetry. @todo Investigate this in depth
+	h, heimdallSpan := getMockedHeimdallClient(t)
 	_bor.SetHeimdallClient(h)
 
 	db := init.ethereum.ChainDb()
 	block := init.genesis.ToBlock(db)
-	// Build 1st block's header
-	header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period)
+	// to := int64(block.Header().Time)
 
-	statedb, err := chain.State()
-	if err != nil {
-		t.Fatalf("%s", err)
+	// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
+	for i := uint64(1); i <= spanSize; i++ {
+		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
+		insertNewBlock(t, chain, block)
 	}
 
-	_key, _ := hex.DecodeString(privKey)
-	insertNewBlock(t, _bor, chain, header, statedb, _key)
-
-	assert.True(t, h.AssertNumberOfCalls(t, "FetchWithRetry", 2))
-	validators, err := _bor.GetCurrentValidators(1, 256) // new span starts at 256
+	assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
+	validators, err := _bor.GetCurrentValidators(sprintSize, spanSize) // check validator set at the first block of new span
 	if err != nil {
 		t.Fatalf("%s", err)
 	}
 
-	assert.Equal(t, len(validators), 3)
+	assert.Equal(t, 3, len(validators))
 	for i, validator := range validators {
 		assert.Equal(t, validator.Address.Bytes(), heimdallSpan.SelectedProducers[i].Address.Bytes())
 		assert.Equal(t, validator.VotingPower, heimdallSpan.SelectedProducers[i].VotingPower)
 	}
 }
 
-func TestIsValidatorAction(t *testing.T) {
+func TestFetchStateSyncEvents(t *testing.T) {
 	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
 	chain := init.ethereum.BlockChain()
 	engine := init.ethereum.Engine()
 	_bor := engine.(*bor.Bor)
 
-	proposeStateData, _ := hex.DecodeString("ede01f170000000000000000000000000000000000000000000000000000000000000000")
-	proposeSpanData, _ := hex.DecodeString("4b0e4d17")
-	var tx *types.Transaction
-	tx = types.NewTransaction(
-		0,
-		common.HexToAddress(chain.Config().Bor.StateReceiverContract),
-		big.NewInt(0), 0, big.NewInt(0),
-		proposeStateData,
-	)
-	assert.True(t, _bor.IsValidatorAction(chain, addr, tx))
-
-	tx = types.NewTransaction(
-		0,
-		common.HexToAddress(chain.Config().Bor.ValidatorContract),
-		big.NewInt(0), 0, big.NewInt(0),
-		proposeSpanData,
-	)
-	assert.True(t, _bor.IsValidatorAction(chain, addr, tx))
+	// A. Insert blocks for 0th sprint
+	db := init.ethereum.ChainDb()
+	block := init.genesis.ToBlock(db)
+	// Insert sprintSize # of blocks so that span is fetched at the start of a new sprint
+	for i := uint64(1); i < sprintSize; i++ {
+		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
+		insertNewBlock(t, chain, block)
+	}
 
-	res, heimdallSpan := loadSpanFromFile(t)
+	// B. Before inserting 1st block of the next sprint, mock heimdall deps
+	// B.1 Mock /bor/span/1
+	res, _ := loadSpanFromFile(t)
+	h := &mocks.IHeimdallClient{}
+	h.On("FetchWithRetry", spanPath, "").Return(res, nil)
+
+	// B.2 Mock State Sync events
+	fromID := uint64(1)
+	// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
+	to := int64(chain.GetHeaderByNumber(0).Time)
+	eventCount := 50
+
+	sample := getSampleEventRecord(t)
+	sample.Time = time.Unix(to-int64(eventCount+1), 0) // last event.Time will be just < to
+	eventRecords := generateFakeStateSyncEvents(sample, eventCount)
+	h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
+	_bor.SetHeimdallClient(h)
+
+	block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
+	insertNewBlock(t, chain, block)
+
+	assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
+	assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
+}
+
+func TestFetchStateSyncEvents_2(t *testing.T) {
+	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
+	chain := init.ethereum.BlockChain()
+	engine := init.ethereum.Engine()
+	_bor := engine.(*bor.Bor)
+
+	// Mock /bor/span/1
+	res, _ := loadSpanFromFile(t)
 	h := &mocks.IHeimdallClient{}
-	h.On("FetchWithRetry", "bor", "span", "1").Return(res, nil)
+	h.On("FetchWithRetry", spanPath, "").Return(res, nil)
+
+	// Mock State Sync events
+	// at # sprintSize, events are fetched for [fromID, (block-sprint).Time)
+	fromID := uint64(1)
+	to := int64(chain.GetHeaderByNumber(0).Time)
+	sample := getSampleEventRecord(t)
+
+	// First query will be from [id=1, (block-sprint).Time]
+	// Insert 5 events in this time range
+	eventRecords := []*bor.EventRecordWithTime{
+		buildStateEvent(sample, 1, 3), // id = 1, time = 1
+		buildStateEvent(sample, 2, 1), // id = 2, time = 3
+		buildStateEvent(sample, 3, 2), // id = 3, time = 2
+		// event with id 5 is missing
+		buildStateEvent(sample, 4, 5), // id = 4, time = 5
+		buildStateEvent(sample, 6, 4), // id = 6, time = 4
+	}
+	h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
 	_bor.SetHeimdallClient(h)
 
-	// Build 1st block's header
+	// Insert blocks for 0th sprint
 	db := init.ethereum.ChainDb()
 	block := init.genesis.ToBlock(db)
+	for i := uint64(1); i <= sprintSize; i++ {
+		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
+		insertNewBlock(t, chain, block)
+	}
+	assert.True(t, h.AssertCalled(t, "FetchWithRetry", spanPath, ""))
+	assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
+	lastStateID, _ := _bor.GenesisContractsClient.LastStateId(sprintSize)
+	// state 6 was not written
+	assert.Equal(t, uint64(4), lastStateID.Uint64())
 
-	header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period)
-	statedb, err := chain.State()
-	if err != nil {
-		t.Fatalf("%s", err)
+	//
+	fromID = uint64(5)
+	to = int64(chain.GetHeaderByNumber(sprintSize).Time)
+	eventRecords = []*bor.EventRecordWithTime{
+		buildStateEvent(sample, 5, 7),
+		buildStateEvent(sample, 6, 4),
+	}
+	h.On("FetchStateSyncEvents", fromID, to).Return(eventRecords, nil)
+	for i := sprintSize + 1; i <= spanSize; i++ {
+		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
+		insertNewBlock(t, chain, block)
+	}
+	assert.True(t, h.AssertCalled(t, "FetchStateSyncEvents", fromID, to))
+	lastStateID, _ = _bor.GenesisContractsClient.LastStateId(spanSize)
+	assert.Equal(t, uint64(6), lastStateID.Uint64())
+}
+
+func TestOutOfTurnSigning(t *testing.T) {
+	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
+	chain := init.ethereum.BlockChain()
+	engine := init.ethereum.Engine()
+	_bor := engine.(*bor.Bor)
+	h, _ := getMockedHeimdallClient(t)
+	_bor.SetHeimdallClient(h)
+
+	db := init.ethereum.ChainDb()
+	block := init.genesis.ToBlock(db)
+
+	for i := uint64(1); i < spanSize; i++ {
+		block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
+		insertNewBlock(t, chain, block)
 	}
 
-	_key, _ := hex.DecodeString(privKey)
-	insertNewBlock(t, _bor, chain, header, statedb, _key)
+	// insert spanSize-th block
+	// This account is one the out-of-turn validators for 1st (0-indexed) span
+	signer := "c8deb0bea5c41afe8e37b4d1bd84e31adff11b09c8c96ff4b605003cce067cd9"
+	signerKey, _ := hex.DecodeString(signer)
+	key, _ = crypto.HexToECDSA(signer)
+	addr = crypto.PubkeyToAddress(key.PublicKey)
+	expectedSuccessionNumber := 2
+
+	block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
+	_, err := chain.InsertChain([]*types.Block{block})
+	assert.Equal(t,
+		*err.(*bor.BlockTooSoonError),
+		bor.BlockTooSoonError{Number: spanSize, Succession: expectedSuccessionNumber})
+
+	expectedDifficulty := uint64(3 - expectedSuccessionNumber) // len(validators) - succession
+	header := block.Header()
+	header.Time += (bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) -
+		bor.CalcProducerDelay(header.Number.Uint64(), 0, init.genesis.Config.Bor))
+	sign(t, header, signerKey)
 	block = types.NewBlockWithHeader(header)
+	_, err = chain.InsertChain([]*types.Block{block})
+	assert.Equal(t,
+		*err.(*bor.WrongDifficultyError),
+		bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: addr.Bytes()})
 
-	var headers []*types.Header
-	for i := int64(2); i <= 255; i++ {
-		header := buildMinimalNextHeader(t, block, init.genesis.Config.Bor.Period)
-		headers = append(headers, header)
-		block = types.NewBlockWithHeader(header)
-	}
-	t.Logf("inserting %v headers", len(headers))
-	if _, err := chain.InsertHeaderChain(headers, 0); err != nil {
-		t.Fatalf("%s", err)
+	header.Difficulty = new(big.Int).SetUint64(expectedDifficulty)
+	sign(t, header, signerKey)
+	block = types.NewBlockWithHeader(header)
+	_, err = chain.InsertChain([]*types.Block{block})
+	assert.Nil(t, err)
+}
+
+func TestSignerNotFound(t *testing.T) {
+	init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
+	chain := init.ethereum.BlockChain()
+	engine := init.ethereum.Engine()
+	_bor := engine.(*bor.Bor)
+	h, _ := getMockedHeimdallClient(t)
+	_bor.SetHeimdallClient(h)
+
+	db := init.ethereum.ChainDb()
+	block := init.genesis.ToBlock(db)
+
+	// random signer account that is not a part of the validator set
+	signer := "3714d99058cd64541433d59c6b391555b2fd9b54629c2b717a6c9c00d1127b6b"
+	signerKey, _ := hex.DecodeString(signer)
+	key, _ = crypto.HexToECDSA(signer)
+	addr = crypto.PubkeyToAddress(key.PublicKey)
+
+	block = buildNextBlock(t, _bor, chain, block, signerKey, init.genesis.Config.Bor)
+	_, err := chain.InsertChain([]*types.Block{block})
+	assert.Equal(t,
+		*err.(*bor.UnauthorizedSignerError),
+		bor.UnauthorizedSignerError{Number: 0, Signer: addr.Bytes()})
+}
+
+func getMockedHeimdallClient(t *testing.T) (*mocks.IHeimdallClient, *bor.HeimdallSpan) {
+	res, heimdallSpan := loadSpanFromFile(t)
+	h := &mocks.IHeimdallClient{}
+	h.On("FetchWithRetry", "bor/span/1", "").Return(res, nil)
+	h.On(
+		"FetchStateSyncEvents",
+		mock.AnythingOfType("uint64"),
+		mock.AnythingOfType("int64")).Return([]*bor.EventRecordWithTime{getSampleEventRecord(t)}, nil)
+	return h, heimdallSpan
+}
+
+func generateFakeStateSyncEvents(sample *bor.EventRecordWithTime, count int) []*bor.EventRecordWithTime {
+	events := make([]*bor.EventRecordWithTime, count)
+	event := *sample
+	event.ID = 1
+	events[0] = &bor.EventRecordWithTime{}
+	*events[0] = event
+	for i := 1; i < count; i++ {
+		event.ID = uint64(i)
+		event.Time = event.Time.Add(1 * time.Second)
+		events[i] = &bor.EventRecordWithTime{}
+		*events[i] = event
 	}
+	return events
+}
+
+func buildStateEvent(sample *bor.EventRecordWithTime, id uint64, timeStamp int64) *bor.EventRecordWithTime {
+	event := *sample
+	event.ID = id
+	event.Time = time.Unix(timeStamp, 0)
+	return &event
+}
 
-	for _, validator := range heimdallSpan.SelectedProducers {
-		_addr := validator.Address
-		tx = types.NewTransaction(
-			0,
-			common.HexToAddress(chain.Config().Bor.StateReceiverContract),
-			big.NewInt(0), 0, big.NewInt(0),
-			proposeStateData,
-		)
-		assert.True(t, _bor.IsValidatorAction(chain, _addr, tx))
-
-		tx = types.NewTransaction(
-			0,
-			common.HexToAddress(chain.Config().Bor.ValidatorContract),
-			big.NewInt(0), 0, big.NewInt(0),
-			proposeSpanData,
-		)
-		assert.True(t, _bor.IsValidatorAction(chain, _addr, tx))
+func getSampleEventRecord(t *testing.T) *bor.EventRecordWithTime {
+	res := stateSyncEventsPayload(t)
+	var _eventRecords []*bor.EventRecordWithTime
+	if err := json.Unmarshal(res.Result, &_eventRecords); err != nil {
+		t.Fatalf("%s", err)
 	}
+	_eventRecords[0].Time = time.Unix(1, 0)
+	return _eventRecords[0]
 }
diff --git a/consensus/bor/bor_test/genesis.json b/consensus/bor/bor_test/genesis.json
index 32b9cd5b2aa474f4d6a629a87dec04e5a5f32b3b..ca21f42e1ac5f30cf8bb6a34908b5afe49c796eb 100644
--- a/consensus/bor/bor_test/genesis.json
+++ b/consensus/bor/bor_test/genesis.json
@@ -11,7 +11,8 @@
     "bor": {
       "period": 1,
       "producerDelay": 4,
-      "sprint": 1,
+      "sprint": 4,
+      "backupMultiplier": 1,
       "validatorContract": "0x0000000000000000000000000000000000001000",
       "stateReceiverContract": "0x0000000000000000000000000000000000001001"
     }
@@ -26,15 +27,15 @@
   "alloc": {
     "0000000000000000000000000000000000001000": {
       "balance": "0x0",
-      "code": "0x608060405234801561001057600080fd5b50600436106102115760003560e01c806365b3a1e211610125578063b2472431116100ad578063d0504f891161007c578063d0504f89146106af578063d5b844eb146106cb578063dcf2793a146106e9578063e3b7c9241461071b578063f59cf5651461073957610211565b8063b247243114610612578063b71d7a6914610630578063b7ab4db514610660578063c1b3c9191461067f57610211565b806370ba5707116100f457806370ba57071461055657806398ab2b62146105865780639d11b807146105a4578063ae756451146105d4578063af26aa96146105f257610211565b806365b3a1e2146104c957806366332354146104e8578063687a9bd61461050657806369c49fac1461053857610211565b806335ddfeea116101a85780634b0e4d17116101775780634b0e4d17146104215780634dbc959f1461042b57806355614fcc14610449578063582a8d081461047957806360c8614d146104a957610211565b806335ddfeea1461037357806343ee8213146103a357806344c15cb1146103c157806344d6528f146103f157610211565b806323f2a73f116101e457806323f2a73f146102c55780632de3a180146102f55780632eddf352146103255780633434735f1461035557610211565b8063047a6c5b146102165780630c35b1cb146102485780631270b5741461027957806323c2a2b4146102a9575b600080fd5b610230600480360361022b9190810190612e7e565b61076b565b60405161023f93929190613903565b60405180910390f35b610262600480360361025d9190810190612e7e565b6107c2565b6040516102709291906136c4565b60405180910390f35b610293600480360361028e9190810190612ea7565b61099e565b6040516102a091906136fb565b60405180910390f35b6102c360048036036102be9190810190612f86565b610af6565b005b6102df60048036036102da9190810190612ea7565b611177565b6040516102ec91906136fb565b60405180910390f35b61030f600480360361030a9190810190612d18565b6112cf565b60405161031c9190613716565b60405180910390f35b61033f600480360361033a9190810190612e7e565b611350565b60405161034c91906138b1565b60405180910390f35b61035d611481565b60405161036a91906136a9565b60405180910390f35b61038d60048036036103889190810190612d54565b611499565b60405161039a91906136fb565b60405180910390f35b6103ab611564565b6040516103b89190613716565b60405180910390f35b6103db60048036036103d69190810190612ee3565b61157b565b6040516103e891906138b1565b60405180910390f35b61040b60048036036104069190810190612ea7565b611663565b6040516104189190613896565b60405180910390f35b6104296117cc565b005b610433611828565b60405161044091906138b1565b60405180910390f35b610463600480360361045e9190810190612c9d565b611838565b60405161047091906136fb565b60405180910390f35b610493600480360361048e9190810190612cc6565b611852565b6040516104a09190613716565b60405180910390f35b6104b16118d0565b6040516104c093929190613903565b60405180910390f35b6104d1611944565b6040516104df9291906136c4565b60405180910390f35b6104f0611a34565b6040516104fd91906138b1565b60405180910390f35b610520600480360361051b9190810190612f4a565b611a39565b60405161052f939291906138cc565b60405180910390f35b610540611a9d565b60405161054d91906136fb565b60405180910390f35b610570600480360361056b9190810190612c9d565b611ab4565b60405161057d91906136fb565b60405180910390f35b61058e611ace565b60405161059b9190613716565b60405180910390f35b6105be60048036036105b99190810190612e7e565b611ae5565b6040516105cb91906138b1565b60405180910390f35b6105dc611c16565b6040516105e99190613716565b60405180910390f35b6105fa611c2d565b60405161060993929190613903565b60405180910390f35b61061a611c8e565b60405161062791906138b1565b60405180910390f35b61064a60048036036106459190810190612e7e565b611c94565b60405161065791906138b1565b60405180910390f35b610668611d94565b6040516106769291906136c4565b60405180910390f35b61069960048036036106949190810190612e7e565b611da8565b6040516106a691906138b1565b60405180910390f35b6106c960048036036106c49190810190612dbb565b611dc9565b005b6106d361201f565b6040516106e0919061393a565b60405180910390f35b61070360048036036106fe9190810190612f4a565b612024565b604051610712939291906138cc565b60405180910390f35b610723612088565b60405161073091906138b1565b60405180910390f35b610753600480360361074e9190810190612e7e565b61209a565b60405161076293929190613903565b60405180910390f35b60008060006004600085815260200190815260200160002060000154600460008681526020019081526020016000206001015460046000878152602001908152602001600020600201549250925092509193909250565b60608060ff83116107de576107d5611944565b91509150610999565b60006107e984611c94565b9050606060036000838152602001908152602001600020805490506040519080825280602002602001820160405280156108325781602001602082028038833980820191505090505b5090506060600360008481526020019081526020016000208054905060405190808252806020026020018201604052801561087c5781602001602082028038833980820191505090505b50905060008090505b600360008581526020019081526020016000208054905081101561098e576003600085815260200190815260200160002081815481106108c157fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168382815181106108ff57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060036000858152602001908152602001600020818154811061095757fe5b90600052602060002090600302016001015482828151811061097557fe5b6020026020010181815250508080600101915050610885565b508181945094505050505b915091565b6000606060036000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a71578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050815260200190600101906109d5565b50505050905060008090505b8151811015610ae9578373ffffffffffffffffffffffffffffffffffffffff16828281518110610aa957fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610adc57600192505050610af0565b8080600101915050610a7d565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b4257600080fd5b6000610b4c611828565b90506000811415610b6057610b5f6120c4565b5b610b746001826123f090919063ffffffff16565b8814610bb5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bac906137b6565b60405180910390fd5b868611610bf7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bee90613816565b60405180910390fd5b6000805460018989030181610c0857fe5b0614610c49576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c40906137f6565b60405180910390fd5b8660046000838152602001908152602001600020600101541115610ca2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9990613776565b60405180910390fd5b6000600460008a81526020019081526020016000206000015414610cfb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cf2906137d6565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600460008a815260200190815260200160002060008201518160000155602082015181600101556040820151816002015590505060058890806001815401808255809150509060018203906000526020600020016000909192909190915055506000600260008a815260200190815260200160002081610d969190612a97565b506000600360008a815260200190815260200160002081610db79190612a97565b506060610e0f610e0a87878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061240f565b61243d565b905060008090505b8151811015610f83576060610e3e838381518110610e3157fe5b602002602001015161243d565b9050600260008c81526020019081526020016000208054809190600101610e659190612a97565b506040518060600160405280610e8e83600081518110610e8157fe5b602002602001015161251a565b8152602001610eb083600181518110610ea357fe5b602002602001015161251a565b8152602001610ed283600281518110610ec557fe5b602002602001015161258b565b73ffffffffffffffffffffffffffffffffffffffff16815250600260008d81526020019081526020016000208381548110610f0957fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610e17565b506060610fdb610fd686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061240f565b61243d565b905060008090505b815181101561114f57606061100a838381518110610ffd57fe5b602002602001015161243d565b9050600360008d815260200190815260200160002080548091906001016110319190612a97565b50604051806060016040528061105a8360008151811061104d57fe5b602002602001015161251a565b815260200161107c8360018151811061106f57fe5b602002602001015161251a565b815260200161109e8360028151811061109157fe5b602002602001015161258b565b73ffffffffffffffffffffffffffffffffffffffff16815250600360008e815260200190815260200160002083815481106110d557fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610fe3565b506000600160006101000a81548160ff02191690831515021790555050505050505050505050565b6000606060026000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561124a578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050815260200190600101906111ae565b50505050905060008090505b81518110156112c2578373ffffffffffffffffffffffffffffffffffffffff1682828151811061128257fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156112b5576001925050506112c9565b8080600101915050611256565b5060009150505b92915050565b60006002600160f81b84846040516020016112ec93929190613616565b6040516020818303038152906040526040516113089190613653565b602060405180830381855afa158015611325573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506113489190810190612cef565b905092915050565b6000606060026000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611423578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611387565b505050509050600080905060008090505b82518110156114765761146783828151811061144c57fe5b602002602001015160200151836123f090919063ffffffff16565b91508080600101915050611434565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b60008060008085905060006021808751816114b057fe5b0402905060008111156114c9576114c687611852565b91505b6000602190505b818111611553576000600182038801519050818801519550806000602081106114f557fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916141561153a5761153386856112cf565b9350611547565b61154484876112cf565b93505b506021810190506114d0565b508782149450505050509392505050565b6040516115709061367f565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff1610156116565760606115b8868367ffffffffffffffff1660416125ae565b905060006115cf828961263a90919063ffffffff16565b90506115d9612ac9565b6115e38a83611663565b90506115ef8a83611177565b801561162657508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b15611648578194506116458160200151876123f090919063ffffffff16565b95505b50505060418101905061158d565b5081925050509392505050565b61166b612ac9565b606060026000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561173c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681525050815260200190600101906116a0565b50505050905060008090505b81518110156117c4578373ffffffffffffffffffffffffffffffffffffffff1682828151811061177457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156117b7578181815181106117a857fe5b602002602001015192506117c4565b8080600101915050611748565b505092915050565b60006117d6611828565b90506117e28133611177565b6117eb57600080fd5b60001515600160009054906101000a900460ff1615151461180b57600080fd5b60018060006101000a81548160ff02191690831515021790555050565b600061183343611c94565b905090565b600061184b611845611828565b83611177565b9050919050565b60006002600060f81b8360405160200161186d9291906135ea565b6040516020818303038152906040526040516118899190613653565b602060405180830381855afa1580156118a6573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506118c99190810190612cef565b9050919050565b6000806000806118f160016118e3611828565b6123f090919063ffffffff16565b905060046000828152602001908152602001600020600001546004600083815260200190815260200160002060010154600460008481526020019081526020016000206002015493509350935050909192565b606080606060016040519080825280602002602001820160405280156119795781602001602082028038833980820191505090505b5090507371562b71999873db5b286df957af199ec94617f78160008151811061199e57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505060606001604051908082528060200260200182016040528015611a0a5781602001602082028038833980820191505090505b509050600a81600081518110611a1c57fe5b60200260200101818152505081819350935050509091565b60ff81565b60036020528160005260406000208181548110611a5257fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b6000600160009054906101000a900460ff16905090565b6000611ac7611ac1611828565b8361099e565b9050919050565b604051611ada9061366a565b604051809103902081565b6000606060036000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611bb8578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611b1c565b505050509050600080905060008090505b8251811015611c0b57611bfc838281518110611be157fe5b602002602001015160200151836123f090919063ffffffff16565b91508080600101915050611bc9565b508092505050919050565b604051611c2290613694565b604051809103902081565b600080600080611c3b611828565b905060046000828152602001908152602001600020600001546004600083815260200190815260200160002060010154600460008481526020019081526020016000206002015493509350935050909192565b60005481565b60008060058054905090505b6000811115611d5457611cb1612b00565b6004600060056001850381548110611cc557fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611d2257506000816040015114155b8015611d32575080604001518411155b15611d4557806000015192505050611d8f565b50808060019003915050611ca0565b5060006005805490501115611d8a57600560016005805490500381548110611d7857fe5b90600052602060002001549050611d8f565b600090505b919050565b606080611da0436107c2565b915091509091565b60058181548110611db557fe5b906000526020600020016000915090505481565b6060611ddc611dd78661240f565b61243d565b9050604051611dea9061367f565b6040518091039020611e0f82600081518110611e0257fe5b6020026020010151612744565b8051906020012014611e56576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e4d90613796565b60405180910390fd5b600260ff16611e7882600181518110611e6b57fe5b602002602001015161251a565b14611eb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611eaf90613836565b60405180910390fd5b611f31611ed882600481518110611ecb57fe5b602002602001015161251a565b60001b600285604051611eeb9190613653565b602060405180830381855afa158015611f08573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250611f2b9190810190612cef565b84611499565b611f70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f6790613856565b60405180910390fd5b6000611f7a611828565b90506000611f908288805190602001208861157b565b9050611fd46001611fc66003611fb86002611faa88611350565b6127d090919063ffffffff16565b61280a90919063ffffffff16565b6123f090919063ffffffff16565b811015612016576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161200d90613876565b60405180910390fd5b50505050505050565b600281565b6002602052816000526040600020818154811061203d57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b60006040438161209457fe5b04905090565b60046020528060005260406000206000915090508060000154908060010154908060020154905083565b60406000819055506060806120d7611944565b8092508193505050600080905060405180606001604052808281526020016000815260200160ff815250600460008381526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506005819080600181540180825580915050906001820390600052602060002001600090919290919091505550600060026000838152602001908152602001600020816121819190612a97565b50600060036000838152602001908152602001600020816121a29190612a97565b5060008090505b83518110156122c6576002600083815260200190815260200160002080548091906001016121d79190612a97565b5060405180606001604052808281526020018483815181106121f557fe5b6020026020010151815260200185838151811061220e57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060026000848152602001908152602001600020828154811061224d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505080806001019150506121a9565b5060008090505b83518110156123ea576003600083815260200190815260200160002080548091906001016122fb9190612a97565b50604051806060016040528082815260200184838151811061231957fe5b6020026020010151815260200185838151811061233257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060036000848152602001908152602001600020828154811061237157fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505080806001019150506122cd565b50505050565b60008082840190508381101561240557600080fd5b8091505092915050565b612417612b21565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061244882612830565b61245157600080fd5b600061245c8361287e565b905060608160405190808252806020026020018201604052801561249a57816020015b612487612b3b565b81526020019060019003908161247f5790505b50905060006124ac85602001516128ef565b8560200151019050600080600090505b8481101561250d576124cd83612978565b91506040518060400160405280838152602001848152508482815181106124f057fe5b6020026020010181905250818301925080806001019150506124bc565b5082945050505050919050565b600080826000015111801561253457506021826000015111155b61253d57600080fd5b600061254c83602001516128ef565b9050600081846000015103905060008083866020015101905080519150602083101561257f57826020036101000a820491505b81945050505050919050565b6000601582600001511461259e57600080fd5b6125a78261251a565b9050919050565b6060818301845110156125c057600080fd5b60608215600081146125dd5760405191506020820160405261262e565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561261b57805183526020830192506020810190506125fe565b50868552601f19601f8301166040525050505b50809150509392505050565b6000806000806041855114612655576000935050505061273e565b602085015192506040850151915060ff6041860151169050601b8160ff16101561268057601b810190505b601b8160ff16141580156126985750601c8160ff1614155b156126a9576000935050505061273e565b6000600187838686604051600081526020016040526040516126ce9493929190613731565b6020604051602081039080840390855afa1580156126f0573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561273657600080fd5b809450505050505b92915050565b6060600082600001511161275757600080fd5b600061276683602001516128ef565b905060008184600001510390506060816040519080825280601f01601f1916602001820160405280156127a85781602001600182028038833980820191505090505b50905060008160200190506127c4848760200151018285612a30565b81945050505050919050565b6000808314156127e35760009050612804565b60008284029050828482816127f457fe5b04146127ff57600080fd5b809150505b92915050565b600080821161281857600080fd5b600082848161282357fe5b0490508091505092915050565b600080826000015114156128475760009050612879565b60008083602001519050805160001a915060c060ff168260ff16101561287257600092505050612879565b6001925050505b919050565b6000808260000151141561289557600090506128ea565b600080905060006128a984602001516128ef565b84602001510190506000846000015185602001510190505b808210156128e3576128d282612978565b8201915082806001019350506128c1565b8293505050505b919050565b600080825160001a9050608060ff1681101561290f576000915050612973565b60b860ff16811080612934575060c060ff168110158015612933575060f860ff1681105b5b15612943576001915050612973565b60c060ff168110156129635760018060b80360ff16820301915050612973565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff168110156129995760019150612a26565b60b860ff168110156129b6576001608060ff168203019150612a25565b60c060ff168110156129e65760b78103600185019450806020036101000a85510460018201810193505050612a24565b60f860ff16811015612a0357600160c060ff168203019150612a23565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b6000811415612a3e57612a92565b5b602060ff168110612a6e5782518252602060ff1683019250602060ff1682019150602060ff1681039050612a3f565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b815481835581811115612ac457600302816003028360005260206000209182019101612ac39190612b55565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b612ba891905b80821115612ba45760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600301612b5b565b5090565b90565b600081359050612bba81613b33565b92915050565b600081359050612bcf81613b4a565b92915050565b600081519050612be481613b4a565b92915050565b60008083601f840112612bfc57600080fd5b8235905067ffffffffffffffff811115612c1557600080fd5b602083019150836001820283011115612c2d57600080fd5b9250929050565b600082601f830112612c4557600080fd5b8135612c58612c5382613982565b613955565b91508082526020830160208301858383011115612c7457600080fd5b612c7f838284613add565b50505092915050565b600081359050612c9781613b61565b92915050565b600060208284031215612caf57600080fd5b6000612cbd84828501612bab565b91505092915050565b600060208284031215612cd857600080fd5b6000612ce684828501612bc0565b91505092915050565b600060208284031215612d0157600080fd5b6000612d0f84828501612bd5565b91505092915050565b60008060408385031215612d2b57600080fd5b6000612d3985828601612bc0565b9250506020612d4a85828601612bc0565b9150509250929050565b600080600060608486031215612d6957600080fd5b6000612d7786828701612bc0565b9350506020612d8886828701612bc0565b925050604084013567ffffffffffffffff811115612da557600080fd5b612db186828701612c34565b9150509250925092565b60008060008060808587031215612dd157600080fd5b600085013567ffffffffffffffff811115612deb57600080fd5b612df787828801612c34565b945050602085013567ffffffffffffffff811115612e1457600080fd5b612e2087828801612c34565b935050604085013567ffffffffffffffff811115612e3d57600080fd5b612e4987828801612c34565b925050606085013567ffffffffffffffff811115612e6657600080fd5b612e7287828801612c34565b91505092959194509250565b600060208284031215612e9057600080fd5b6000612e9e84828501612c88565b91505092915050565b60008060408385031215612eba57600080fd5b6000612ec885828601612c88565b9250506020612ed985828601612bab565b9150509250929050565b600080600060608486031215612ef857600080fd5b6000612f0686828701612c88565b9350506020612f1786828701612bc0565b925050604084013567ffffffffffffffff811115612f3457600080fd5b612f4086828701612c34565b9150509250925092565b60008060408385031215612f5d57600080fd5b6000612f6b85828601612c88565b9250506020612f7c85828601612c88565b9150509250929050565b600080600080600080600060a0888a031215612fa157600080fd5b6000612faf8a828b01612c88565b9750506020612fc08a828b01612c88565b9650506040612fd18a828b01612c88565b955050606088013567ffffffffffffffff811115612fee57600080fd5b612ffa8a828b01612bea565b9450945050608088013567ffffffffffffffff81111561301957600080fd5b6130258a828b01612bea565b925092505092959891949750929550565b60006130428383613066565b60208301905092915050565b600061305a83836135bd565b60208301905092915050565b61306f81613a52565b82525050565b61307e81613a52565b82525050565b600061308f826139ce565b6130998185613a09565b93506130a4836139ae565b8060005b838110156130d55781516130bc8882613036565b97506130c7836139ef565b9250506001810190506130a8565b5085935050505092915050565b60006130ed826139d9565b6130f78185613a1a565b9350613102836139be565b8060005b8381101561313357815161311a888261304e565b9750613125836139fc565b925050600181019050613106565b5085935050505092915050565b61314981613a64565b82525050565b61316061315b82613a70565b613b1f565b82525050565b61316f81613a9c565b82525050565b61318661318182613a9c565b613b29565b82525050565b6000613197826139e4565b6131a18185613a2b565b93506131b1818560208601613aec565b80840191505092915050565b60006131ca600483613a47565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b600061320a602d83613a36565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000613270600f83613a47565b91507f6865696d64616c6c2d50357258776700000000000000000000000000000000006000830152600f82019050919050565b60006132b0601383613a36565b91507f436861696e20494420697320696e76616c6964000000000000000000000000006000830152602082019050919050565b60006132f0600f83613a36565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000613330601383613a36565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000613370604583613a36565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b60006133fc602a83613a36565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000613462601483613a36565b91507f566f7465207479706520697320696e76616c69640000000000000000000000006000830152602082019050919050565b60006134a2601683613a36565b91507f5472616e73616374696f6e20697320696e76616c6964000000000000000000006000830152602082019050919050565b60006134e2600583613a47565b91507f31353030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b6000613522602483613a36565b91507f4e6f7420656e6f7567687420706f77657220746f206368616e6765207468652060008301527f7370616e000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b60608201600082015161359160008501826135bd565b5060208201516135a460208501826135bd565b5060408201516135b76040850182613066565b50505050565b6135c681613ac6565b82525050565b6135d581613ac6565b82525050565b6135e481613ad0565b82525050565b60006135f6828561314f565b6001820191506136068284613175565b6020820191508190509392505050565b6000613622828661314f565b6001820191506136328285613175565b6020820191506136428284613175565b602082019150819050949350505050565b600061365f828461318c565b915081905092915050565b6000613675826131bd565b9150819050919050565b600061368a82613263565b9150819050919050565b600061369f826134d5565b9150819050919050565b60006020820190506136be6000830184613075565b92915050565b600060408201905081810360008301526136de8185613084565b905081810360208301526136f281846130e2565b90509392505050565b60006020820190506137106000830184613140565b92915050565b600060208201905061372b6000830184613166565b92915050565b60006080820190506137466000830187613166565b61375360208301866135db565b6137606040830185613166565b61376d6060830184613166565b95945050505050565b6000602082019050818103600083015261378f816131fd565b9050919050565b600060208201905081810360008301526137af816132a3565b9050919050565b600060208201905081810360008301526137cf816132e3565b9050919050565b600060208201905081810360008301526137ef81613323565b9050919050565b6000602082019050818103600083015261380f81613363565b9050919050565b6000602082019050818103600083015261382f816133ef565b9050919050565b6000602082019050818103600083015261384f81613455565b9050919050565b6000602082019050818103600083015261386f81613495565b9050919050565b6000602082019050818103600083015261388f81613515565b9050919050565b60006060820190506138ab600083018461357b565b92915050565b60006020820190506138c660008301846135cc565b92915050565b60006060820190506138e160008301866135cc565b6138ee60208301856135cc565b6138fb6040830184613075565b949350505050565b600060608201905061391860008301866135cc565b61392560208301856135cc565b61393260408301846135cc565b949350505050565b600060208201905061394f60008301846135db565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561397857600080fd5b8060405250919050565b600067ffffffffffffffff82111561399957600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b6000613a5d82613aa6565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b83811015613b0a578082015181840152602081019050613aef565b83811115613b19576000848401525b50505050565b6000819050919050565b6000819050919050565b613b3c81613a52565b8114613b4757600080fd5b50565b613b5381613a9c565b8114613b5e57600080fd5b50565b613b6a81613ac6565b8114613b7557600080fd5b5056fea365627a7a7231582041043c020490417f03b23833da19152e2e105982aaa0228db2459085c981a3f16c6578706572696d656e74616cf564736f6c63430005100040"
+      "code": "0x608060405234801561001057600080fd5b50600436106101f05760003560e01c806360c8614d1161010f578063af26aa96116100a2578063d5b844eb11610071578063d5b844eb14610666578063dcf2793a14610684578063e3b7c924146106b6578063f59cf565146106d4576101f0565b8063af26aa96146105c7578063b71d7a69146105e7578063b7ab4db514610617578063c1b3c91914610636576101f0565b806370ba5707116100de57806370ba57071461052b57806398ab2b621461055b5780639d11b80714610579578063ae756451146105a9576101f0565b806360c8614d1461049c57806365b3a1e2146104bc57806366332354146104db578063687a9bd6146104f9576101f0565b80633434735f1161018757806344d6528f1161015657806344d6528f146103ee5780634dbc959f1461041e57806355614fcc1461043c578063582a8d081461046c576101f0565b80633434735f1461035257806335ddfeea1461037057806343ee8213146103a057806344c15cb1146103be576101f0565b806323f2a73f116101c357806323f2a73f146102a45780632bc06564146102d45780632de3a180146102f25780632eddf35214610322576101f0565b8063047a6c5b146101f55780630c35b1cb146102275780631270b5741461025857806323c2a2b414610288575b600080fd5b61020f600480360361020a919081019061290d565b610706565b60405161021e939291906131ec565b60405180910390f35b610241600480360361023c919081019061290d565b61075d565b60405161024f92919061302d565b60405180910390f35b610272600480360361026d9190810190612936565b610939565b60405161027f9190613064565b60405180910390f35b6102a2600480360361029d9190810190612a15565b610a91565b005b6102be60048036036102b99190810190612936565b6110f4565b6040516102cb9190613064565b60405180910390f35b6102dc61124b565b6040516102e9919061319a565b60405180910390f35b61030c6004803603610307919081019061286a565b611250565b604051610319919061307f565b60405180910390f35b61033c6004803603610337919081019061290d565b6112d1565b604051610349919061319a565b60405180910390f35b61035a611401565b6040516103679190613012565b60405180910390f35b61038a600480360361038591908101906128a6565b611419565b6040516103979190613064565b60405180910390f35b6103a86114e4565b6040516103b5919061307f565b60405180910390f35b6103d860048036036103d39190810190612972565b6114fb565b6040516103e5919061319a565b60405180910390f35b61040860048036036104039190810190612936565b6115e3565b604051610415919061317f565b60405180910390f35b61042661174b565b604051610433919061319a565b60405180910390f35b610456600480360361045191908101906127ef565b61175b565b6040516104639190613064565b60405180910390f35b61048660048036036104819190810190612818565b611775565b604051610493919061307f565b60405180910390f35b6104a46117f3565b6040516104b3939291906131ec565b60405180910390f35b6104c4611867565b6040516104d292919061302d565b60405180910390f35b6104e3611957565b6040516104f0919061319a565b60405180910390f35b610513600480360361050e91908101906129d9565b61195c565b604051610522939291906131b5565b60405180910390f35b610545600480360361054091908101906127ef565b6119c0565b6040516105529190613064565b60405180910390f35b6105636119da565b604051610570919061307f565b60405180910390f35b610593600480360361058e919081019061290d565b6119f1565b6040516105a0919061319a565b60405180910390f35b6105b1611b22565b6040516105be919061307f565b60405180910390f35b6105cf611b39565b6040516105de939291906131ec565b60405180910390f35b61060160048036036105fc919081019061290d565b611b9a565b60405161060e919061319a565b60405180910390f35b61061f611c9a565b60405161062d92919061302d565b60405180910390f35b610650600480360361064b919081019061290d565b611cae565b60405161065d919061319a565b60405180910390f35b61066e611ccf565b60405161067b9190613223565b60405180910390f35b61069e600480360361069991908101906129d9565b611cd4565b6040516106ad939291906131b5565b60405180910390f35b6106be611d38565b6040516106cb919061319a565b60405180910390f35b6106ee60048036036106e9919081019061290d565b611d4a565b6040516106fd939291906131ec565b60405180910390f35b60008060006002600085815260200190815260200160002060000154600260008681526020019081526020016000206001015460026000878152602001908152602001600020600201549250925092509193909250565b6060806007831161077957610770611867565b91509150610934565b600061078484611b9a565b9050606060016000838152602001908152602001600020805490506040519080825280602002602001820160405280156107cd5781602001602082028038833980820191505090505b509050606060016000848152602001908152602001600020805490506040519080825280602002602001820160405280156108175781602001602082028038833980820191505090505b50905060008090505b60016000858152602001908152602001600020805490508110156109295760016000858152602001908152602001600020818154811061085c57fe5b906000526020600020906003020160020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683828151811061089a57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001600085815260200190815260200160002081815481106108f257fe5b90600052602060002090600302016001015482828151811061091057fe5b6020026020010181815250508080600101915050610820565b508181945094505050505b915091565b6000606060016000858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610a0c578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190610970565b50505050905060008090505b8151811015610a84578373ffffffffffffffffffffffffffffffffffffffff16828281518110610a4457fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff161415610a7757600192505050610a8b565b8080600101915050610a18565b5060009150505b92915050565b73fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610add57600080fd5b6000610ae761174b565b90506000811415610afb57610afa611d74565b5b610b0f60018261209590919063ffffffff16565b8814610b50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b47906130ff565b60405180910390fd5b868611610b92576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b899061315f565b60405180910390fd5b6000600460018989030181610ba357fe5b0614610be4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bdb9061313f565b60405180910390fd5b8660026000838152602001908152602001600020600101541115610c3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c34906130df565b60405180910390fd5b6000600260008a81526020019081526020016000206000015414610c96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c8d9061311f565b60405180910390fd5b604051806060016040528089815260200188815260200187815250600260008a8152602001908152602001600020600082015181600001556020820151816001015560408201518160020155905050600388908060018154018082558091505090600182039060005260206000200160009091929091909150555060008060008a815260200190815260200160002081610d3091906125e9565b506000600160008a815260200190815260200160002081610d5191906125e9565b506060610da9610da487878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506120b4565b6120e2565b905060008090505b8151811015610f1b576060610dd8838381518110610dcb57fe5b60200260200101516120e2565b90506000808c81526020019081526020016000208054809190600101610dfe91906125e9565b506040518060600160405280610e2783600081518110610e1a57fe5b60200260200101516121bf565b8152602001610e4983600181518110610e3c57fe5b60200260200101516121bf565b8152602001610e6b83600281518110610e5e57fe5b6020026020010151612230565b73ffffffffffffffffffffffffffffffffffffffff168152506000808d81526020019081526020016000208381548110610ea157fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610db1565b506060610f73610f6e86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506120b4565b6120e2565b905060008090505b81518110156110e7576060610fa2838381518110610f9557fe5b60200260200101516120e2565b9050600160008d81526020019081526020016000208054809190600101610fc991906125e9565b506040518060600160405280610ff283600081518110610fe557fe5b60200260200101516121bf565b81526020016110148360018151811061100757fe5b60200260200101516121bf565b81526020016110368360028151811061102957fe5b6020026020010151612230565b73ffffffffffffffffffffffffffffffffffffffff16815250600160008e8152602001908152602001600020838154811061106d57fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050508080600101915050610f7b565b5050505050505050505050565b60006060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156111c6578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061112a565b50505050905060008090505b815181101561123e578373ffffffffffffffffffffffffffffffffffffffff168282815181106111fe57fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff16141561123157600192505050611245565b80806001019150506111d2565b5060009150505b92915050565b600481565b60006002600160f81b848460405160200161126d93929190612f7f565b6040516020818303038152906040526040516112899190612fbc565b602060405180830381855afa1580156112a6573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506112c99190810190612841565b905092915050565b60006060600080848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156113a3578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611307565b505050509050600080905060008090505b82518110156113f6576113e78382815181106113cc57fe5b6020026020010151602001518361209590919063ffffffff16565b915080806001019150506113b4565b508092505050919050565b73fffffffffffffffffffffffffffffffffffffffe81565b600080600080859050600060218087518161143057fe5b0402905060008111156114495761144687611775565b91505b6000602190505b8181116114d35760006001820388015190508188015195508060006020811061147557fe5b1a60f81b9450600060f81b857effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614156114ba576114b38685611250565b93506114c7565b6114c48487611250565b93505b50602181019050611450565b508782149450505050509392505050565b6040516114f090612fe8565b604051809103902081565b60008060009050600080905060008090505b84518167ffffffffffffffff1610156115d6576060611538868367ffffffffffffffff166041612253565b9050600061154f82896122df90919063ffffffff16565b905061155961261b565b6115638a836115e3565b905061156f8a836110f4565b80156115a657508473ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16115b156115c8578194506115c581602001518761209590919063ffffffff16565b95505b50505060418101905061150d565b5081925050509392505050565b6115eb61261b565b6060600080858152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156116bb578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250508152602001906001019061161f565b50505050905060008090505b8151811015611743578373ffffffffffffffffffffffffffffffffffffffff168282815181106116f357fe5b60200260200101516040015173ffffffffffffffffffffffffffffffffffffffff1614156117365781818151811061172757fe5b60200260200101519250611743565b80806001019150506116c7565b505092915050565b600061175643611b9a565b905090565b600061176e61176861174b565b836110f4565b9050919050565b60006002600060f81b83604051602001611790929190612f53565b6040516020818303038152906040526040516117ac9190612fbc565b602060405180830381855afa1580156117c9573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052506117ec9190810190612841565b9050919050565b600080600080611814600161180661174b565b61209590919063ffffffff16565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b6060806060600160405190808252806020026020018201604052801561189c5781602001602082028038833980820191505090505b5090507371562b71999873db5b286df957af199ec94617f7816000815181106118c157fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506060600160405190808252806020026020018201604052801561192d5781602001602082028038833980820191505090505b509050600a8160008151811061193f57fe5b60200260200101818152505081819350935050509091565b600781565b6001602052816000526040600020818154811061197557fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b60006119d36119cd61174b565b83610939565b9050919050565b6040516119e690612fd3565b604051809103902081565b6000606060016000848152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611ac4578382906000526020600020906003020160405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505081526020019060010190611a28565b505050509050600080905060008090505b8251811015611b1757611b08838281518110611aed57fe5b6020026020010151602001518361209590919063ffffffff16565b91508080600101915050611ad5565b508092505050919050565b604051611b2e90612ffd565b604051809103902081565b600080600080611b4761174b565b905060026000828152602001908152602001600020600001546002600083815260200190815260200160002060010154600260008481526020019081526020016000206002015493509350935050909192565b60008060038054905090505b6000811115611c5a57611bb7612652565b6002600060036001850381548110611bcb57fe5b906000526020600020015481526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816020015111158015611c2857506000816040015114155b8015611c38575080604001518411155b15611c4b57806000015192505050611c95565b50808060019003915050611ba6565b5060006003805490501115611c9057600360016003805490500381548110611c7e57fe5b90600052602060002001549050611c95565b600090505b919050565b606080611ca64361075d565b915091509091565b60038181548110611cbb57fe5b906000526020600020016000915090505481565b600281565b60006020528160005260406000208181548110611ced57fe5b9060005260206000209060030201600091509150508060000154908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905083565b600060044381611d4457fe5b04905090565b60026020528060005260406000206000915090508060000154908060010154908060020154905083565b606080611d7f611867565b809250819350505060008090506040518060600160405280828152602001600081526020016007815250600260008381526020019081526020016000206000820151816000015560208201518160010155604082015181600201559050506003819080600181540180825580915050906001820390600052602060002001600090919290919091505550600080600083815260200190815260200160002081611e2891906125e9565b5060006001600083815260200190815260200160002081611e4991906125e9565b5060008090505b8351811015611f6b576000808381526020019081526020016000208054809190600101611e7d91906125e9565b506040518060600160405280828152602001848381518110611e9b57fe5b60200260200101518152602001858381518110611eb457fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff168152506000808481526020019081526020016000208281548110611ef257fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050611e50565b5060008090505b835181101561208f57600160008381526020019081526020016000208054809190600101611fa091906125e9565b506040518060600160405280828152602001848381518110611fbe57fe5b60200260200101518152602001858381518110611fd757fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1681525060016000848152602001908152602001600020828154811061201657fe5b9060005260206000209060030201600082015181600001556020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050508080600101915050611f72565b50505050565b6000808284019050838110156120aa57600080fd5b8091505092915050565b6120bc612673565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606120ed826123e9565b6120f657600080fd5b600061210183612437565b905060608160405190808252806020026020018201604052801561213f57816020015b61212c61268d565b8152602001906001900390816121245790505b509050600061215185602001516124a8565b8560200151019050600080600090505b848110156121b25761217283612531565b915060405180604001604052808381526020018481525084828151811061219557fe5b602002602001018190525081830192508080600101915050612161565b5082945050505050919050565b60008082600001511180156121d957506021826000015111155b6121e257600080fd5b60006121f183602001516124a8565b9050600081846000015103905060008083866020015101905080519150602083101561222457826020036101000a820491505b81945050505050919050565b6000601582600001511461224357600080fd5b61224c826121bf565b9050919050565b60608183018451101561226557600080fd5b6060821560008114612282576040519150602082016040526122d3565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156122c057805183526020830192506020810190506122a3565b50868552601f19601f8301166040525050505b50809150509392505050565b60008060008060418551146122fa57600093505050506123e3565b602085015192506040850151915060ff6041860151169050601b8160ff16101561232557601b810190505b601b8160ff161415801561233d5750601c8160ff1614155b1561234e57600093505050506123e3565b600060018783868660405160008152602001604052604051612373949392919061309a565b6020604051602081039080840390855afa158015612395573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156123db57600080fd5b809450505050505b92915050565b600080826000015114156124005760009050612432565b60008083602001519050805160001a915060c060ff168260ff16101561242b57600092505050612432565b6001925050505b919050565b6000808260000151141561244e57600090506124a3565b6000809050600061246284602001516124a8565b84602001510190506000846000015185602001510190505b8082101561249c5761248b82612531565b82019150828060010193505061247a565b8293505050505b919050565b600080825160001a9050608060ff168110156124c857600091505061252c565b60b860ff168110806124ed575060c060ff1681101580156124ec575060f860ff1681105b5b156124fc57600191505061252c565b60c060ff1681101561251c5760018060b80360ff1682030191505061252c565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561255257600191506125df565b60b860ff1681101561256f576001608060ff1682030191506125de565b60c060ff1681101561259f5760b78103600185019450806020036101000a855104600182018101935050506125dd565b60f860ff168110156125bc57600160c060ff1682030191506125dc565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b8154818355818111156126165760030281600302836000526020600020918201910161261591906126a7565b5b505050565b60405180606001604052806000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b60405180606001604052806000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b604051806040016040528060008152602001600081525090565b6126fa91905b808211156126f65760008082016000905560018201600090556002820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506003016126ad565b5090565b90565b60008135905061270c8161341c565b92915050565b60008135905061272181613433565b92915050565b60008151905061273681613433565b92915050565b60008083601f84011261274e57600080fd5b8235905067ffffffffffffffff81111561276757600080fd5b60208301915083600182028301111561277f57600080fd5b9250929050565b600082601f83011261279757600080fd5b81356127aa6127a58261326b565b61323e565b915080825260208301602083018583830111156127c657600080fd5b6127d18382846133c6565b50505092915050565b6000813590506127e98161344a565b92915050565b60006020828403121561280157600080fd5b600061280f848285016126fd565b91505092915050565b60006020828403121561282a57600080fd5b600061283884828501612712565b91505092915050565b60006020828403121561285357600080fd5b600061286184828501612727565b91505092915050565b6000806040838503121561287d57600080fd5b600061288b85828601612712565b925050602061289c85828601612712565b9150509250929050565b6000806000606084860312156128bb57600080fd5b60006128c986828701612712565b93505060206128da86828701612712565b925050604084013567ffffffffffffffff8111156128f757600080fd5b61290386828701612786565b9150509250925092565b60006020828403121561291f57600080fd5b600061292d848285016127da565b91505092915050565b6000806040838503121561294957600080fd5b6000612957858286016127da565b9250506020612968858286016126fd565b9150509250929050565b60008060006060848603121561298757600080fd5b6000612995868287016127da565b93505060206129a686828701612712565b925050604084013567ffffffffffffffff8111156129c357600080fd5b6129cf86828701612786565b9150509250925092565b600080604083850312156129ec57600080fd5b60006129fa858286016127da565b9250506020612a0b858286016127da565b9150509250929050565b600080600080600080600060a0888a031215612a3057600080fd5b6000612a3e8a828b016127da565b9750506020612a4f8a828b016127da565b9650506040612a608a828b016127da565b955050606088013567ffffffffffffffff811115612a7d57600080fd5b612a898a828b0161273c565b9450945050608088013567ffffffffffffffff811115612aa857600080fd5b612ab48a828b0161273c565b925092505092959891949750929550565b6000612ad18383612af5565b60208301905092915050565b6000612ae98383612f26565b60208301905092915050565b612afe8161333b565b82525050565b612b0d8161333b565b82525050565b6000612b1e826132b7565b612b2881856132f2565b9350612b3383613297565b8060005b83811015612b64578151612b4b8882612ac5565b9750612b56836132d8565b925050600181019050612b37565b5085935050505092915050565b6000612b7c826132c2565b612b868185613303565b9350612b91836132a7565b8060005b83811015612bc2578151612ba98882612add565b9750612bb4836132e5565b925050600181019050612b95565b5085935050505092915050565b612bd88161334d565b82525050565b612bef612bea82613359565b613408565b82525050565b612bfe81613385565b82525050565b612c15612c1082613385565b613412565b82525050565b6000612c26826132cd565b612c308185613314565b9350612c408185602086016133d5565b80840191505092915050565b6000612c59600483613330565b91507f766f7465000000000000000000000000000000000000000000000000000000006000830152600482019050919050565b6000612c99602d8361331f565b91507f537461727420626c6f636b206d7573742062652067726561746572207468616e60008301527f2063757272656e74207370616e000000000000000000000000000000000000006020830152604082019050919050565b6000612cff600f8361331f565b91507f496e76616c6964207370616e20696400000000000000000000000000000000006000830152602082019050919050565b6000612d3f60138361331f565b91507f5370616e20616c726561647920657869737473000000000000000000000000006000830152602082019050919050565b6000612d7f60458361331f565b91507f446966666572656e6365206265747765656e20737461727420616e6420656e6460008301527f20626c6f636b206d75737420626520696e206d756c7469706c6573206f66207360208301527f7072696e740000000000000000000000000000000000000000000000000000006040830152606082019050919050565b6000612e0b602a8361331f565b91507f456e6420626c6f636b206d7573742062652067726561746572207468616e207360008301527f7461727420626c6f636b000000000000000000000000000000000000000000006020830152604082019050919050565b6000612e71600e83613330565b91507f6865696d64616c6c2d31353030310000000000000000000000000000000000006000830152600e82019050919050565b6000612eb1600583613330565b91507f31353030310000000000000000000000000000000000000000000000000000006000830152600582019050919050565b606082016000820151612efa6000850182612f26565b506020820151612f0d6020850182612f26565b506040820151612f206040850182612af5565b50505050565b612f2f816133af565b82525050565b612f3e816133af565b82525050565b612f4d816133b9565b82525050565b6000612f5f8285612bde565b600182019150612f6f8284612c04565b6020820191508190509392505050565b6000612f8b8286612bde565b600182019150612f9b8285612c04565b602082019150612fab8284612c04565b602082019150819050949350505050565b6000612fc88284612c1b565b915081905092915050565b6000612fde82612c4c565b9150819050919050565b6000612ff382612e64565b9150819050919050565b600061300882612ea4565b9150819050919050565b60006020820190506130276000830184612b04565b92915050565b600060408201905081810360008301526130478185612b13565b9050818103602083015261305b8184612b71565b90509392505050565b60006020820190506130796000830184612bcf565b92915050565b60006020820190506130946000830184612bf5565b92915050565b60006080820190506130af6000830187612bf5565b6130bc6020830186612f44565b6130c96040830185612bf5565b6130d66060830184612bf5565b95945050505050565b600060208201905081810360008301526130f881612c8c565b9050919050565b6000602082019050818103600083015261311881612cf2565b9050919050565b6000602082019050818103600083015261313881612d32565b9050919050565b6000602082019050818103600083015261315881612d72565b9050919050565b6000602082019050818103600083015261317881612dfe565b9050919050565b60006060820190506131946000830184612ee4565b92915050565b60006020820190506131af6000830184612f35565b92915050565b60006060820190506131ca6000830186612f35565b6131d76020830185612f35565b6131e46040830184612b04565b949350505050565b60006060820190506132016000830186612f35565b61320e6020830185612f35565b61321b6040830184612f35565b949350505050565b60006020820190506132386000830184612f44565b92915050565b6000604051905081810181811067ffffffffffffffff8211171561326157600080fd5b8060405250919050565b600067ffffffffffffffff82111561328257600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006133468261338f565b9050919050565b60008115159050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b82818337600083830152505050565b60005b838110156133f35780820151818401526020810190506133d8565b83811115613402576000848401525b50505050565b6000819050919050565b6000819050919050565b6134258161333b565b811461343057600080fd5b50565b61343c81613385565b811461344757600080fd5b50565b613453816133af565b811461345e57600080fd5b5056fea365627a7a723158208af21d8e799fd1406e4b7808af903d8055606c3aa8d3ec80d8e21f0514e9bf676c6578706572696d656e74616cf564736f6c634300050c0040"
     },
     "0000000000000000000000000000000000001001": {
       "balance": "0x0",
-      "code": "0x"
+      "code": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e9610411565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610429565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461019757600080fd5b60606101ee6101e985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061042f565b61045d565b9050600061020f8260008151811061020257fe5b602002602001015161053a565b9050806001600054011461028b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006102bb836001815181106102ae57fe5b60200260200101516105ab565b905060606102dc846002815181106102cf57fe5b60200260200101516105ce565b90506102e78261065a565b15610406576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610341578082015181840152602081019050610326565b50505050905090810190601f16801561036e5780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104376108da565b600060208301905060405180604001604052808451815260200182815250915050919050565b606061046882610673565b61047157600080fd5b600061047c836106c1565b90506060816040519080825280602002602001820160405280156104ba57816020015b6104a76108f4565b81526020019060019003908161049f5790505b50905060006104cc8560200151610732565b8560200151019050600080600090505b8481101561052d576104ed836107bb565b915060405180604001604052808381526020018481525084828151811061051057fe5b6020026020010181905250818301925080806001019150506104dc565b5082945050505050919050565b600080826000015111801561055457506021826000015111155b61055d57600080fd5b600061056c8360200151610732565b9050600081846000015103905060008083866020015101905080519150602083101561059f57826020036101000a820491505b81945050505050919050565b600060158260000151146105be57600080fd5b6105c78261053a565b9050919050565b606060008260000151116105e157600080fd5b60006105f08360200151610732565b905060008184600001510390506060816040519080825280601f01601f1916602001820160405280156106325781602001600182028038833980820191505090505b509050600081602001905061064e848760200151018285610873565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b6000808260000151141561068a57600090506106bc565b60008083602001519050805160001a915060c060ff168260ff1610156106b5576000925050506106bc565b6001925050505b919050565b600080826000015114156106d8576000905061072d565b600080905060006106ec8460200151610732565b84602001510190506000846000015185602001510190505b8082101561072657610715826107bb565b820191508280600101935050610704565b8293505050505b919050565b600080825160001a9050608060ff168110156107525760009150506107b6565b60b860ff16811080610777575060c060ff168110158015610776575060f860ff1681105b5b156107865760019150506107b6565b60c060ff168110156107a65760018060b80360ff168203019150506107b6565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff168110156107dc5760019150610869565b60b860ff168110156107f9576001608060ff168203019150610868565b60c060ff168110156108295760b78103600185019450806020036101000a85510460018201810193505050610867565b60f860ff1681101561084657600160c060ff168203019150610866565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b6000811415610881576108d5565b5b602060ff1681106108b15782518252602060ff1683019250602060ff1682019150602060ff1681039050610882565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a723158206e562292874be6a994dcfabfea65957791c1491194eeb7dea6f7eaf1390c036e64736f6c634300050c0032"
     },
     "0000000000000000000000000000000000001010": {
       "balance": "0x204fce28085b549b31600000",
-      "code": "0x"
+      "code": "0x60806040526004361061019c5760003560e01c806377d32e94116100ec578063acd06cb31161008a578063e306f77911610064578063e306f77914610a7b578063e614d0d614610aa6578063f2fde38b14610ad1578063fc0c546a14610b225761019c565b8063acd06cb31461097a578063b789543c146109cd578063cc79f97b14610a505761019c565b80639025e64c116100c65780639025e64c146107c957806395d89b4114610859578063a9059cbb146108e9578063abceeba21461094f5761019c565b806377d32e94146106315780638da5cb5b146107435780638f32d59b1461079a5761019c565b806347e7ef24116101595780637019d41a116101335780637019d41a1461053357806370a082311461058a578063715018a6146105ef578063771282f6146106065761019c565b806347e7ef2414610410578063485cc9551461046b57806360f96a8f146104dc5761019c565b806306fdde03146101a15780631499c5921461023157806318160ddd1461028257806319d27d9c146102ad5780632e1a7d4d146103b1578063313ce567146103df575b600080fd5b3480156101ad57600080fd5b506101b6610b79565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101f65780820151818401526020810190506101db565b50505050905090810190601f1680156102235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023d57600080fd5b506102806004803603602081101561025457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bb6565b005b34801561028e57600080fd5b50610297610c24565b6040518082815260200191505060405180910390f35b3480156102b957600080fd5b5061036f600480360360a08110156102d057600080fd5b81019080803590602001906401000000008111156102ed57600080fd5b8201836020820111156102ff57600080fd5b8035906020019184600183028401116401000000008311171561032157600080fd5b9091929391929390803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c3a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103dd600480360360208110156103c757600080fd5b8101908080359060200190929190505050610e06565b005b3480156103eb57600080fd5b506103f4610f58565b604051808260ff1660ff16815260200191505060405180910390f35b34801561041c57600080fd5b506104696004803603604081101561043357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610f61565b005b34801561047757600080fd5b506104da6004803603604081101561048e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061111d565b005b3480156104e857600080fd5b506104f16111ec565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561053f57600080fd5b50610548611212565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561059657600080fd5b506105d9600480360360208110156105ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611238565b6040518082815260200191505060405180910390f35b3480156105fb57600080fd5b50610604611259565b005b34801561061257600080fd5b5061061b611329565b6040518082815260200191505060405180910390f35b34801561063d57600080fd5b506107016004803603604081101561065457600080fd5b81019080803590602001909291908035906020019064010000000081111561067b57600080fd5b82018360208201111561068d57600080fd5b803590602001918460018302840111640100000000831117156106af57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061132f565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561074f57600080fd5b506107586114b4565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156107a657600080fd5b506107af6114dd565b604051808215151515815260200191505060405180910390f35b3480156107d557600080fd5b506107de611534565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081e578082015181840152602081019050610803565b50505050905090810190601f16801561084b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561086557600080fd5b5061086e61156d565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ae578082015181840152602081019050610893565b50505050905090810190601f1680156108db5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610935600480360360408110156108ff57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506115aa565b604051808215151515815260200191505060405180910390f35b34801561095b57600080fd5b506109646115d0565b6040518082815260200191505060405180910390f35b34801561098657600080fd5b506109b36004803603602081101561099d57600080fd5b810190808035906020019092919050505061165d565b604051808215151515815260200191505060405180910390f35b3480156109d957600080fd5b50610a3a600480360360808110156109f057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061167d565b6040518082815260200191505060405180910390f35b348015610a5c57600080fd5b50610a6561169d565b6040518082815260200191505060405180910390f35b348015610a8757600080fd5b50610a906116a3565b6040518082815260200191505060405180910390f35b348015610ab257600080fd5b50610abb6116a9565b6040518082815260200191505060405180910390f35b348015610add57600080fd5b50610b2060048036036020811015610af457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611736565b005b348015610b2e57600080fd5b50610b37611753565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60606040518060400160405280600b81526020017f4d6174696320546f6b656e000000000000000000000000000000000000000000815250905090565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260108152602001807f44697361626c656420666561747572650000000000000000000000000000000081525060200191505060405180910390fd5b6000601260ff16600a0a6402540be40002905090565b6000808511610c4857600080fd5b6000831480610c575750824311155b610cc9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e6174757265206973206578706972656400000000000000000000000081525060200191505060405180910390fd5b6000610cd73387878761167d565b9050600015156005600083815260200190815260200160002060009054906101000a900460ff16151514610d73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600f8152602001807f536967206465616374697661746564000000000000000000000000000000000081525060200191505060405180910390fd5b60016005600083815260200190815260200160002060006101000a81548160ff021916908315150217905550610ded8189898080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061132f565b9150610dfa828488611779565b50509695505050505050565b60003390506000610e1682611238565b9050610e2d83600654611b3690919063ffffffff16565b600681905550600083118015610e4257508234145b610eb4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f496e73756666696369656e7420616d6f756e740000000000000000000000000081525060200191505060405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f8584610f3087611238565b60405180848152602001838152602001828152602001935050505060405180910390a3505050565b60006012905090565b610f696114dd565b610f7257600080fd5b600081118015610faf5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b611004576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e626023913960400191505060405180910390fd5b600061100f83611238565b905060008390508073ffffffffffffffffffffffffffffffffffffffff166108fc849081150290604051600060405180830381858888f1935050505015801561105c573d6000803e3d6000fd5b5061107283600654611b5690919063ffffffff16565b6006819055508373ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f685856110f489611238565b60405180848152602001838152602001828152602001935050505060405180910390a350505050565b600760009054906101000a900460ff1615611183576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611e3f6023913960400191505060405180910390fd5b6001600760006101000a81548160ff02191690831515021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506111e882611b75565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff16319050919050565b6112616114dd565b61126a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60065481565b600080600080604185511461134a57600093505050506114ae565b602085015192506040850151915060ff6041860151169050601b8160ff16101561137557601b810190505b601b8160ff161415801561138d5750601c8160ff1614155b1561139e57600093505050506114ae565b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156113fb573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4572726f7220696e2065637265636f766572000000000000000000000000000081525060200191505060405180910390fd5b5050505b92915050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b6040518060400160405280600281526020017f3a9900000000000000000000000000000000000000000000000000000000000081525081565b60606040518060400160405280600581526020017f4d41544943000000000000000000000000000000000000000000000000000000815250905090565b60008134146115bc57600090506115ca565b6115c7338484611779565b90505b92915050565b6040518060800160405280605b8152602001611ed7605b91396040516020018082805190602001908083835b6020831061161f57805182526020820191506020810190506020830392506115fc565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b60056020528060005260406000206000915054906101000a900460ff1681565b600061169361168e86868686611c6d565b611d43565b9050949350505050565b613a9981565b60015481565b604051806080016040528060528152602001611e85605291396040516020018082805190602001908083835b602083106116f857805182526020820191506020810190506020830392506116d5565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040528051906020012081565b61173e6114dd565b61174757600080fd5b61175081611b75565b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000803073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117f957600080fd5b505afa15801561180d573d6000803e3d6000fd5b505050506040513d602081101561182357600080fd5b8101908080519060200190929190505050905060003073ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156118b557600080fd5b505afa1580156118c9573d6000803e3d6000fd5b505050506040513d60208110156118df57600080fd5b810190808051906020019092919050505090506118fd868686611d8d565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c48786863073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611a0557600080fd5b505afa158015611a19573d6000803e3d6000fd5b505050506040513d6020811015611a2f57600080fd5b81019080805190602001909291905050503073ffffffffffffffffffffffffffffffffffffffff166370a082318e6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611abd57600080fd5b505afa158015611ad1573d6000803e3d6000fd5b505050506040513d6020811015611ae757600080fd5b8101908080519060200190929190505050604051808681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a46001925050509392505050565b600082821115611b4557600080fd5b600082840390508091505092915050565b600080828401905083811015611b6b57600080fd5b8091505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611baf57600080fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000806040518060800160405280605b8152602001611ed7605b91396040516020018082805190602001908083835b60208310611cbf5780518252602082019150602081019050602083039250611c9c565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405160208183030381529060405280519060200120905060405181815273ffffffffffffffffffffffffffffffffffffffff8716602082015285604082015284606082015283608082015260a0812092505081915050949350505050565b60008060015490506040517f190100000000000000000000000000000000000000000000000000000000000081528160028201528360228201526042812092505081915050919050565b8173ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611dd3573d6000803e3d6000fd5b508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350505056fe54686520636f6e747261637420697320616c726561647920696e697469616c697a6564496e73756666696369656e7420616d6f756e74206f7220696e76616c69642075736572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429546f6b656e5472616e736665724f726465722861646472657373207370656e6465722c75696e7432353620746f6b656e49644f72416d6f756e742c6279746573333220646174612c75696e743235362065787069726174696f6e29a265627a7a72315820539379fc818a23e69edb3d3a2323efa049847b7691be5bd708c0770ce4be296964736f6c634300050c0032"
     },
     "71562b71999873DB5b286dF957af199Ec94617F7": {
       "balance": "0x3635c9adc5dea00000"
diff --git a/consensus/bor/bor_test/helper.go b/consensus/bor/bor_test/helper.go
index 54ab949983a9861a096f4182bca649563ac1790a..d02c3463fc4e942ebab69c34c9f2952e62b55c4e 100644
--- a/consensus/bor/bor_test/helper.go
+++ b/consensus/bor/bor_test/helper.go
@@ -5,24 +5,38 @@ import (
 	"encoding/json"
 	"io/ioutil"
 	"math/big"
+	"sort"
 	"testing"
 
+	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/consensus/bor"
 	"github.com/maticnetwork/bor/core"
-	"github.com/maticnetwork/bor/core/state"
 	"github.com/maticnetwork/bor/core/types"
 	"github.com/maticnetwork/bor/crypto"
 	"github.com/maticnetwork/bor/crypto/secp256k1"
 	"github.com/maticnetwork/bor/eth"
 	"github.com/maticnetwork/bor/ethdb"
 	"github.com/maticnetwork/bor/node"
+	"github.com/maticnetwork/bor/params"
 )
 
 var (
+	// The genesis for tests was generated with following parameters
 	extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
-	privKey   = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
-	key, _    = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
-	addr      = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7
+
+	// Only this account is a validator for the 0th span
+	privKey = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
+	key, _  = crypto.HexToECDSA(privKey)
+	addr    = crypto.PubkeyToAddress(key.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7
+
+	// This account is one the validators for 1st span (0-indexed)
+	privKey2 = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3"
+	key2, _  = crypto.HexToECDSA(privKey2)
+	addr2    = crypto.PubkeyToAddress(key2.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
+
+	validatorHeaderBytesLength        = common.AddressLength + 20 // address + power
+	sprintSize                 uint64 = 4
+	spanSize                   uint64 = 8
 )
 
 type initializeData struct {
@@ -81,37 +95,77 @@ func buildEthereumInstance(t *testing.T, db ethdb.Database) *initializeData {
 	}
 }
 
-func insertNewBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, header *types.Header, statedb *state.StateDB, privKey []byte) {
-	_, err := _bor.FinalizeAndAssemble(chain, header, statedb, nil, nil, nil)
-	if err != nil {
+func insertNewBlock(t *testing.T, chain *core.BlockChain, block *types.Block) {
+	if _, err := chain.InsertChain([]*types.Block{block}); err != nil {
 		t.Fatalf("%s", err)
 	}
+}
+
+func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *types.Block, signer []byte, borConfig *params.BorConfig) *types.Block {
+	header := block.Header()
+	header.Number.Add(header.Number, big.NewInt(1))
+	number := header.Number.Uint64()
 
-	sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), privKey)
+	if signer == nil {
+		signer = getSignerKey(header.Number.Uint64())
+	}
+
+	header.ParentHash = block.Hash()
+	header.Time += bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig)
+	header.Extra = make([]byte, 32+65) // vanity + extraSeal
+
+	currentValidators := []*bor.Validator{bor.NewValidator(addr, 10)}
+
+	isSpanEnd := (number+1)%spanSize == 0
+	isSpanStart := number%spanSize == 0
+	isSprintEnd := (header.Number.Uint64()+1)%sprintSize == 0
+	if isSpanEnd {
+		_, heimdallSpan := loadSpanFromFile(t)
+		// this is to stash the validator bytes in the header
+		currentValidators = heimdallSpan.ValidatorSet.Validators
+	} else if isSpanStart {
+		header.Difficulty = new(big.Int).SetInt64(3)
+	}
+	if isSprintEnd {
+		sort.Sort(bor.ValidatorsByAddress(currentValidators))
+		validatorBytes := make([]byte, len(currentValidators)*validatorHeaderBytesLength)
+		header.Extra = make([]byte, 32+len(validatorBytes)+65) // vanity + validatorBytes + extraSeal
+		for i, val := range currentValidators {
+			copy(validatorBytes[i*validatorHeaderBytesLength:], val.HeaderBytes())
+		}
+		copy(header.Extra[32:], validatorBytes)
+	}
+
+	state, err := chain.State()
 	if err != nil {
 		t.Fatalf("%s", err)
 	}
-	copy(header.Extra[len(header.Extra)-extraSeal:], sig)
-
-	block := types.NewBlockWithHeader(header)
-	if _, err := chain.InsertChain([]*types.Block{block}); err != nil {
+	_, err = _bor.FinalizeAndAssemble(chain, header, state, nil, nil, nil)
+	if err != nil {
 		t.Fatalf("%s", err)
 	}
+	sign(t, header, signer)
+	return types.NewBlockWithHeader(header)
 }
 
-func buildMinimalNextHeader(t *testing.T, block *types.Block, period uint64) *types.Header {
-	header := block.Header()
-	header.Number.Add(header.Number, big.NewInt(1))
-	header.ParentHash = block.Hash()
-	header.Time += (period + 1)
-	header.Extra = make([]byte, 97) // vanity (32) + extraSeal (65)
-	_key, _ := hex.DecodeString(privKey)
-	sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), _key)
+func sign(t *testing.T, header *types.Header, signer []byte) {
+	sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), signer)
 	if err != nil {
 		t.Fatalf("%s", err)
 	}
 	copy(header.Extra[len(header.Extra)-extraSeal:], sig)
-	return header
+}
+
+func stateSyncEventsPayload(t *testing.T) *bor.ResponseWithHeight {
+	stateData, err := ioutil.ReadFile("states.json")
+	if err != nil {
+		t.Fatalf("%s", err)
+	}
+	res := &bor.ResponseWithHeight{}
+	if err := json.Unmarshal(stateData, res); err != nil {
+		t.Fatalf("%s", err)
+	}
+	return res
 }
 
 func loadSpanFromFile(t *testing.T) (*bor.ResponseWithHeight, *bor.HeimdallSpan) {
@@ -130,3 +184,14 @@ func loadSpanFromFile(t *testing.T) (*bor.ResponseWithHeight, *bor.HeimdallSpan)
 	}
 	return res, heimdallSpan
 }
+
+func getSignerKey(number uint64) []byte {
+	signerKey := privKey
+	isSpanStart := number%spanSize == 0
+	if isSpanStart {
+		// validator set in the new span has changed
+		signerKey = privKey2
+	}
+	_key, _ := hex.DecodeString(signerKey)
+	return _key
+}
diff --git a/consensus/bor/bor_test/snapshot_test.go b/consensus/bor/bor_test/snapshot_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6eb43b3e60374dc594cdbd02209e8a73de81607e
--- /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.UnauthorizedProposerError)
+	assert.True(t, ok)
+	assert.Equal(t, dummyProposerAddress.Bytes(), e.Proposer)
+}
+
+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.UnauthorizedSignerError)
+	assert.True(t, ok)
+	assert.Equal(t, dummySignerAddress.Bytes(), e.Signer)
+}
+
+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/bor_test/span.json b/consensus/bor/bor_test/span.json
index f4be94eeb8bb27061bff15ea983dd4754919268c..893d3db4a6e9b39e707bf0b143dd88a108767815 100644
--- a/consensus/bor/bor_test/span.json
+++ b/consensus/bor/bor_test/span.json
@@ -6,85 +6,57 @@
 		"end_block": 6655,
 		"validator_set": {
 			"validators": [{
-				"ID": 3,
-				"startEpoch": 0,
-				"endEpoch": 0,
-				"power": 10000,
-				"pubKey": "0x046434e10a34ade13c4fea917346a9fd1473eac2138a0b4e2a36426871918be63188fde4edbf598457592c9a49fe3b0036dd5497079495d132e5045bf499c4bdb1",
-				"signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c",
-				"last_updated": 0,
-				"accum": -40000
-			}, {
-				"ID": 4,
-				"startEpoch": 0,
-				"endEpoch": 0,
-				"power": 10000,
-				"pubKey": "0x04d9d09f2afc9da3cccc164e8112eb6911a63f5ede10169768f800df83cf99c73f944411e9d4fac3543b11c5f84a82e56b36cfcd34f1d065855c1e2b27af8b5247",
-				"signer": "0x461295d3d9249215e758e939a150ab180950720b",
-				"last_updated": 0,
-				"accum": 10000
-			}, {
 				"ID": 5,
 				"startEpoch": 0,
 				"endEpoch": 0,
-				"power": 10000,
+				"power": 30,
 				"pubKey": "0x04a36f6ed1f93acb0a38f4cacbe2467c72458ac41ce3b12b34d758205b2bc5d930a4e059462da7a0976c32fce766e1f7e8d73933ae72ac2af231fe161187743932",
-				"signer": "0x836fe3e3dd0a5f77d9d5b0f67e48048aaafcd5a0",
+				"signer": "0x9fB29AAc15b9A4B7F17c3385939b007540f4d791",
 				"last_updated": 0,
 				"accum": 10000
 			}, {
 				"ID": 1,
 				"startEpoch": 0,
 				"endEpoch": 0,
-				"power": 10000,
+				"power": 20,
 				"pubKey": "0x04a312814042a6655c8e5ecf0c52cba0b6a6f3291c87cc42260a3c0222410c0d0d59b9139d1c56542e5df0ce2fce3a86ce13e93bd9bde0dc8ff664f8dd5294dead",
-				"signer": "0x925a91f8003aaeabea6037103123b93c50b86ca3",
+				"signer": "0x96C42C56fdb78294F96B0cFa33c92bed7D75F96a",
 				"last_updated": 0,
 				"accum": 10000
 			}, {
 				"ID": 2,
 				"startEpoch": 0,
 				"endEpoch": 0,
-				"power": 10000,
+				"power": 10,
 				"pubKey": "0x0469536ae98030a7e83ec5ef3baffed2d05a32e31d978e58486f6bdb0fbbf240293838325116090190c0639db03f9cbd8b9aecfd269d016f46e3a2287fbf9ad232",
-				"signer": "0x1c4f0f054a0d6a1415382dc0fd83c6535188b220",
-				"last_updated": 0,
-				"accum": 10000
-			}],
-			"proposer": {
-				"ID": 3,
-				"startEpoch": 0,
-				"endEpoch": 0,
-				"power": 10000,
-				"pubKey": "0x046434e10a34ade13c4fea917346a9fd1473eac2138a0b4e2a36426871918be63188fde4edbf598457592c9a49fe3b0036dd5497079495d132e5045bf499c4bdb1",
-				"signer": "0x1c4f0f054a0d6a1415382dc0fd83c6535188b220",
+				"signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c",
 				"last_updated": 0,
-				"accum": -40000
-			}
+				"accum": 5000
+			}]
 		},
 		"selected_producers": [{
 			"ID": 5,
 			"startEpoch": 0,
 			"endEpoch": 0,
-			"power": 1,
+			"power": 30,
 			"pubKey": "0x04a36f6ed1f93acb0a38f4cacbe2467c72458ac41ce3b12b34d758205b2bc5d930a4e059462da7a0976c32fce766e1f7e8d73933ae72ac2af231fe161187743932",
-			"signer": "0x836fe3e3dd0a5f77d9d5b0f67e48048aaafcd5a0",
+			"signer": "0x9fB29AAc15b9A4B7F17c3385939b007540f4d791",
 			"last_updated": 0,
 			"accum": 10000
 		}, {
 			"ID": 1,
 			"startEpoch": 0,
 			"endEpoch": 0,
-			"power": 1,
+			"power": 20,
 			"pubKey": "0x04a312814042a6655c8e5ecf0c52cba0b6a6f3291c87cc42260a3c0222410c0d0d59b9139d1c56542e5df0ce2fce3a86ce13e93bd9bde0dc8ff664f8dd5294dead",
-			"signer": "0x925a91f8003aaeabea6037103123b93c50b86ca3",
+			"signer": "0x96C42C56fdb78294F96B0cFa33c92bed7D75F96a",
 			"last_updated": 0,
 			"accum": 10000
 		}, {
 			"ID": 2,
 			"startEpoch": 0,
 			"endEpoch": 0,
-			"power": 2,
+			"power": 10,
 			"pubKey": "0x0469536ae98030a7e83ec5ef3baffed2d05a32e31d978e58486f6bdb0fbbf240293838325116090190c0639db03f9cbd8b9aecfd269d016f46e3a2287fbf9ad232",
 			"signer": "0xc787af4624cb3e80ee23ae7faac0f2acea2be34c",
 			"last_updated": 0,
diff --git a/consensus/bor/bor_test/states.json b/consensus/bor/bor_test/states.json
new file mode 100644
index 0000000000000000000000000000000000000000..809998ad906d831de1a79793abcfabc506557998
--- /dev/null
+++ b/consensus/bor/bor_test/states.json
@@ -0,0 +1,23 @@
+{
+  "height": "0",
+  "result": [
+    {
+      "id": 1,
+      "contract": "0xb55969a6d60413a63291a1de572269875df541e3",
+      "data": "0x00000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f6500000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f65000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014",
+      "tx_hash": "0x7b113e09d98b6d4be1dedfbc0746e34876de767f2cb8b58ff00160a160811dd6",
+      "log_index": 0,
+      "bor_chain_id": "15001",
+      "record_time": "2020-05-15T13:36:38.580995Z"
+    },
+    {
+      "id": 2,
+      "contract": "0xb55969a6d60413a63291a1de572269875df541e3",
+      "data": "0x00000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f6500000000000000000000000048aa8d4af32551892fcf08ad63be7dd206d46f65000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000015",
+      "tx_hash": "0xb72358aff8e4d61f4de97a37a40ddda986c081e0de8036e0a78c4b61b067cba9",
+      "log_index": 0,
+      "bor_chain_id": "15001",
+      "record_time": "2020-05-15T13:42:37.319058Z"
+    }
+  ]
+}
diff --git a/consensus/bor/clerk.go b/consensus/bor/clerk.go
index adcbfb78b46df3a0d9fec7abb3c4cce7b87e6389..1c78b5fdd454fa8c7a7d3af353fcee73ce930a26 100644
--- a/consensus/bor/clerk.go
+++ b/consensus/bor/clerk.go
@@ -1,6 +1,9 @@
 package bor
 
 import (
+	"fmt"
+	"time"
+
 	"github.com/maticnetwork/bor/common"
 	"github.com/maticnetwork/bor/common/hexutil"
 )
@@ -14,3 +17,33 @@ type EventRecord struct {
 	LogIndex uint64         `json:"log_index" yaml:"log_index"`
 	ChainID  string         `json:"bor_chain_id" yaml:"bor_chain_id"`
 }
+
+type EventRecordWithTime struct {
+	EventRecord
+	Time time.Time `json:"record_time" yaml:"record_time"`
+}
+
+// String returns the string representatin of span
+func (e *EventRecordWithTime) String() string {
+	return fmt.Sprintf(
+		"id %v, contract %v, data: %v, txHash: %v, logIndex: %v, chainId: %v, time %s",
+		e.ID,
+		e.Contract.String(),
+		e.Data.String(),
+		e.TxHash.Hex(),
+		e.LogIndex,
+		e.ChainID,
+		e.Time.Format(time.RFC3339),
+	)
+}
+
+func (e *EventRecordWithTime) BuildEventRecord() *EventRecord {
+	return &EventRecord{
+		ID:       e.ID,
+		Contract: e.Contract,
+		Data:     e.Data,
+		TxHash:   e.TxHash,
+		LogIndex: e.LogIndex,
+		ChainID:  e.ChainID,
+	}
+}
diff --git a/consensus/bor/errors.go b/consensus/bor/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..a1e60d1e219e50241996df3199dd720d43abbac8
--- /dev/null
+++ b/consensus/bor/errors.go
@@ -0,0 +1,143 @@
+package bor
+
+import (
+	"fmt"
+	"time"
+)
+
+// 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,
+	)
+}
+
+type InvalidStartEndBlockError struct {
+	Start         uint64
+	End           uint64
+	CurrentHeader uint64
+}
+
+func (e *InvalidStartEndBlockError) Error() string {
+	return fmt.Sprintf(
+		"Invalid parameters start: %d and end block: %d params",
+		e.Start,
+		e.End,
+	)
+}
+
+type MaxCheckpointLengthExceededError struct {
+	Start uint64
+	End   uint64
+}
+
+func (e *MaxCheckpointLengthExceededError) Error() string {
+	return fmt.Sprintf(
+		"Start: %d and end block: %d exceed max allowed checkpoint length: %d",
+		e.Start,
+		e.End,
+		MaxCheckpointLength,
+	)
+}
+
+// MismatchingValidatorsError is returned if a last block in sprint contains a
+// list of validators different from the one that local node calculated
+type MismatchingValidatorsError struct {
+	Number             uint64
+	ValidatorSetSnap   []byte
+	ValidatorSetHeader []byte
+}
+
+func (e *MismatchingValidatorsError) Error() string {
+	return fmt.Sprintf(
+		"Mismatching validators at block %d\nValidatorBytes from snapshot: 0x%x\nValidatorBytes in Header: 0x%x\n",
+		e.Number,
+		e.ValidatorSetSnap,
+		e.ValidatorSetHeader,
+	)
+}
+
+type BlockTooSoonError struct {
+	Number     uint64
+	Succession int
+}
+
+func (e *BlockTooSoonError) Error() string {
+	return fmt.Sprintf(
+		"Block %d was created too soon. Signer turn-ness number is %d\n",
+		e.Number,
+		e.Succession,
+	)
+}
+
+// UnauthorizedProposerError is returned if a header is [being] signed by an unauthorized entity.
+type UnauthorizedProposerError struct {
+	Number   uint64
+	Proposer []byte
+}
+
+func (e *UnauthorizedProposerError) Error() string {
+	return fmt.Sprintf(
+		"Proposer 0x%x is not a part of the producer set at block %d",
+		e.Proposer,
+		e.Number,
+	)
+}
+
+// UnauthorizedSignerError is returned if a header is [being] signed by an unauthorized entity.
+type UnauthorizedSignerError struct {
+	Number uint64
+	Signer []byte
+}
+
+func (e *UnauthorizedSignerError) Error() string {
+	return fmt.Sprintf(
+		"Signer 0x%x is not a part of the producer set at block %d",
+		e.Signer,
+		e.Number,
+	)
+}
+
+// WrongDifficultyError is returned if the difficulty of a block doesn't match the
+// turn of the signer.
+type WrongDifficultyError struct {
+	Number   uint64
+	Expected uint64
+	Actual   uint64
+	Signer   []byte
+}
+
+func (e *WrongDifficultyError) Error() string {
+	return fmt.Sprintf(
+		"Wrong difficulty at block %d, expected: %d, actual %d. Signer was %x\n",
+		e.Number,
+		e.Expected,
+		e.Actual,
+		e.Signer,
+	)
+}
+
+type InvalidStateReceivedError struct {
+	Number      uint64
+	LastStateID uint64
+	To          *time.Time
+	Event       *EventRecordWithTime
+}
+
+func (e *InvalidStateReceivedError) Error() string {
+	return fmt.Sprintf(
+		"Received invalid event %s at block %d. Requested events until %s. Last state id was %d",
+		e.Event,
+		e.Number,
+		e.To.Format(time.RFC3339),
+		e.LastStateID,
+	)
+}
diff --git a/consensus/bor/genesis_contracts_client.go b/consensus/bor/genesis_contracts_client.go
new file mode 100644
index 0000000000000000000000000000000000000000..17323f278d973ebb6561d4063b8d6d781d3cc79a
--- /dev/null
+++ b/consensus/bor/genesis_contracts_client.go
@@ -0,0 +1,102 @@
+package bor
+
+import (
+	"context"
+	"math"
+	"math/big"
+	"strings"
+
+	"github.com/maticnetwork/bor/accounts/abi"
+	"github.com/maticnetwork/bor/common"
+	"github.com/maticnetwork/bor/common/hexutil"
+	"github.com/maticnetwork/bor/core/state"
+	"github.com/maticnetwork/bor/core/types"
+	"github.com/maticnetwork/bor/internal/ethapi"
+	"github.com/maticnetwork/bor/log"
+	"github.com/maticnetwork/bor/params"
+	"github.com/maticnetwork/bor/rlp"
+	"github.com/maticnetwork/bor/rpc"
+)
+
+type GenesisContractsClient struct {
+	validatorSetABI       abi.ABI
+	stateReceiverABI      abi.ABI
+	ValidatorContract     string
+	StateReceiverContract string
+	chainConfig           *params.ChainConfig
+	ethAPI                *ethapi.PublicBlockChainAPI
+}
+
+const validatorsetABI = `[{"constant":true,"inputs":[],"name":"SPRINT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CHAIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"FIRST_END_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"producers","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ROUND_TYPE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"BOR_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spanNumbers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"VOTE_TYPE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"validators","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"spans","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"endBlock","type":"uint256"}],"name":"NewSpan","type":"event"},{"constant":true,"inputs":[],"name":"currentSprint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNextSpan","outputs":[{"internalType":"uint256","name":"number","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getSpanByBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentSpanNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getValidatorsTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"}],"name":"getProducersTotalStakeBySpan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"getValidatorBySigner","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct BorValidatorSet.Validator","name":"result","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"name":"isProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isCurrentProducer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"number","type":"uint256"}],"name":"getBorValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitialValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newSpan","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"bytes","name":"validatorBytes","type":"bytes"},{"internalType":"bytes","name":"producerBytes","type":"bytes"}],"name":"commitSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"span","type":"uint256"},{"internalType":"bytes32","name":"dataHash","type":"bytes32"},{"internalType":"bytes","name":"sigs","type":"bytes"}],"name":"getStakePowerBySigs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"bytes32","name":"leaf","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"d","type":"bytes32"}],"name":"leafNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"left","type":"bytes32"},{"internalType":"bytes32","name":"right","type":"bytes32"}],"name":"innerNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"pure","type":"function"}]`
+const stateReceiverABI = `[{"constant":true,"inputs":[],"name":"SYSTEM_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastStateId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"syncTime","type":"uint256"},{"internalType":"bytes","name":"recordBytes","type":"bytes"}],"name":"commitState","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
+
+func NewGenesisContractsClient(
+	chainConfig *params.ChainConfig,
+	validatorContract,
+	stateReceiverContract string,
+	ethAPI *ethapi.PublicBlockChainAPI,
+) *GenesisContractsClient {
+	vABI, _ := abi.JSON(strings.NewReader(validatorsetABI))
+	sABI, _ := abi.JSON(strings.NewReader(stateReceiverABI))
+	return &GenesisContractsClient{
+		validatorSetABI:       vABI,
+		stateReceiverABI:      sABI,
+		ValidatorContract:     validatorContract,
+		StateReceiverContract: stateReceiverContract,
+		chainConfig:           chainConfig,
+		ethAPI:                ethAPI,
+	}
+}
+
+func (gc *GenesisContractsClient) CommitState(
+	event *EventRecordWithTime,
+	state *state.StateDB,
+	header *types.Header,
+	chCtx chainContext,
+) error {
+	eventRecord := event.BuildEventRecord()
+	recordBytes, err := rlp.EncodeToBytes(eventRecord)
+	if err != nil {
+		return err
+	}
+	method := "commitState"
+	t := event.Time.Unix()
+	data, err := gc.stateReceiverABI.Pack(method, big.NewInt(0).SetInt64(t), recordBytes)
+	if err != nil {
+		log.Error("Unable to pack tx for commitState", "error", err)
+		return err
+	}
+	log.Info("→ committing new state", "eventRecord", event.String())
+	msg := getSystemMessage(common.HexToAddress(gc.StateReceiverContract), data)
+	if err := applyMessage(msg, state, header, gc.chainConfig, chCtx); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (gc *GenesisContractsClient) LastStateId(snapshotNumber uint64) (*big.Int, error) {
+	method := "lastStateId"
+	data, err := gc.stateReceiverABI.Pack(method)
+	if err != nil {
+		log.Error("Unable to pack tx for LastStateId", "error", err)
+		return nil, err
+	}
+
+	msgData := (hexutil.Bytes)(data)
+	toAddress := common.HexToAddress(gc.StateReceiverContract)
+	gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
+	result, err := gc.ethAPI.Call(context.Background(), ethapi.CallArgs{
+		Gas:  &gas,
+		To:   &toAddress,
+		Data: &msgData,
+	}, rpc.BlockNumber(snapshotNumber))
+	if err != nil {
+		return nil, err
+	}
+
+	var ret = new(*big.Int)
+	if err := gc.stateReceiverABI.Unpack(ret, method, result); err != nil {
+		return nil, err
+	}
+	return *ret, nil
+}
diff --git a/consensus/bor/merkle.go b/consensus/bor/merkle.go
new file mode 100644
index 0000000000000000000000000000000000000000..bdfbaba9834eb57f23243a049b5f9e40592c31a7
--- /dev/null
+++ b/consensus/bor/merkle.go
@@ -0,0 +1,48 @@
+package bor
+
+func appendBytes32(data ...[]byte) []byte {
+	var result []byte
+	for _, v := range data {
+		paddedV, err := convertTo32(v)
+		if err == nil {
+			result = append(result, paddedV[:]...)
+		}
+	}
+	return result
+}
+
+func nextPowerOfTwo(n uint64) uint64 {
+	if n == 0 {
+		return 1
+	}
+	// http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+	n--
+	n |= n >> 1
+	n |= n >> 2
+	n |= n >> 4
+	n |= n >> 8
+	n |= n >> 16
+	n |= n >> 32
+	n++
+	return n
+}
+
+func convertTo32(input []byte) (output [32]byte, err error) {
+	l := len(input)
+	if l > 32 || l == 0 {
+		return
+	}
+	copy(output[32-l:], input[:])
+	return
+}
+
+func convert(input []([32]byte)) [][]byte {
+	var output [][]byte
+	for _, in := range input {
+		newInput := make([]byte, len(in[:]))
+		copy(newInput, in[:])
+		output = append(output, newInput)
+
+	}
+	return output
+}
diff --git a/consensus/bor/rest.go b/consensus/bor/rest.go
index 9c525d6df6c5b355e6a403845adbb0cb748f6d17..43a4439fde659a19125d471748768b3d17954d77 100644
--- a/consensus/bor/rest.go
+++ b/consensus/bor/rest.go
@@ -6,12 +6,16 @@ import (
 	"io/ioutil"
 	"net/http"
 	"net/url"
-	"path"
+	"sort"
 	"time"
 
 	"github.com/maticnetwork/bor/log"
 )
 
+var (
+	stateFetchLimit = 50
+)
+
 // ResponseWithHeight defines a response object type that wraps an original
 // response with a height.
 type ResponseWithHeight struct {
@@ -20,8 +24,9 @@ type ResponseWithHeight struct {
 }
 
 type IHeimdallClient interface {
-	Fetch(paths ...string) (*ResponseWithHeight, error)
-	FetchWithRetry(paths ...string) (*ResponseWithHeight, error)
+	Fetch(path string, query string) (*ResponseWithHeight, error)
+	FetchWithRetry(path string, query string) (*ResponseWithHeight, error)
+	FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error)
 }
 
 type HeimdallClient struct {
@@ -39,33 +44,57 @@ func NewHeimdallClient(urlString string) (*HeimdallClient, error) {
 	return h, nil
 }
 
-func (h *HeimdallClient) Fetch(paths ...string) (*ResponseWithHeight, error) {
+func (h *HeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error) {
+	eventRecords := make([]*EventRecordWithTime, 0)
+	for {
+		queryParams := fmt.Sprintf("from-id=%d&to-time=%d&limit=%d", fromID, to, stateFetchLimit)
+		log.Info("Fetching state sync events", "queryParams", queryParams)
+		response, err := h.FetchWithRetry("clerk/event-record/list", queryParams)
+		if err != nil {
+			return nil, err
+		}
+		var _eventRecords []*EventRecordWithTime
+		if response.Result == nil { // status 204
+			break
+		}
+		if err := json.Unmarshal(response.Result, &_eventRecords); err != nil {
+			return nil, err
+		}
+		eventRecords = append(eventRecords, _eventRecords...)
+		if len(_eventRecords) < stateFetchLimit {
+			break
+		}
+		fromID += uint64(stateFetchLimit)
+	}
+
+	sort.SliceStable(eventRecords, func(i, j int) bool {
+		return eventRecords[i].ID < eventRecords[j].ID
+	})
+	return eventRecords, nil
+}
+
+// Fetch fetches response from heimdall
+func (h *HeimdallClient) Fetch(rawPath string, rawQuery string) (*ResponseWithHeight, error) {
 	u, err := url.Parse(h.urlString)
 	if err != nil {
 		return nil, err
 	}
 
-	for _, e := range paths {
-		if e != "" {
-			u.Path = path.Join(u.Path, e)
-		}
-	}
+	u.Path = rawPath
+	u.RawQuery = rawQuery
 
 	return h.internalFetch(u)
 }
 
 // FetchWithRetry returns data from heimdall with retry
-func (h *HeimdallClient) FetchWithRetry(paths ...string) (*ResponseWithHeight, error) {
+func (h *HeimdallClient) FetchWithRetry(rawPath string, rawQuery string) (*ResponseWithHeight, error) {
 	u, err := url.Parse(h.urlString)
 	if err != nil {
 		return nil, err
 	}
 
-	for _, e := range paths {
-		if e != "" {
-			u.Path = path.Join(u.Path, e)
-		}
-	}
+	u.Path = rawPath
+	u.RawQuery = rawQuery
 
 	for {
 		res, err := h.internalFetch(u)
@@ -86,18 +115,22 @@ func (h *HeimdallClient) internalFetch(u *url.URL) (*ResponseWithHeight, error)
 	defer res.Body.Close()
 
 	// check status code
-	if res.StatusCode != 200 {
+	if res.StatusCode != 200 && res.StatusCode != 204 {
 		return nil, fmt.Errorf("Error while fetching data from Heimdall")
 	}
 
+	// unmarshall data from buffer
+	var response ResponseWithHeight
+	if res.StatusCode == 204 {
+		return &response, nil
+	}
+
 	// get response
 	body, err := ioutil.ReadAll(res.Body)
 	if err != nil {
 		return nil, err
 	}
 
-	// unmarshall data from buffer
-	var response ResponseWithHeight
 	if err := json.Unmarshal(body, &response); err != nil {
 		return nil, err
 	}
diff --git a/consensus/bor/snapshot.go b/consensus/bor/snapshot.go
index d2f0e82ff49c047cede16743d2d4cfdae2d33250..2ff7dec0cea12f83140de60e764097d7fbeed35f 100644
--- a/consensus/bor/snapshot.go
+++ b/consensus/bor/snapshot.go
@@ -26,7 +26,6 @@ import (
 	"github.com/maticnetwork/bor/core/types"
 	"github.com/maticnetwork/bor/ethdb"
 	"github.com/maticnetwork/bor/internal/ethapi"
-	"github.com/maticnetwork/bor/log"
 	"github.com/maticnetwork/bor/params"
 )
 
@@ -87,7 +86,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
 }
@@ -153,31 +154,11 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
 
 		// check if signer is in validator set
 		if !snap.ValidatorSet.HasAddress(signer.Bytes()) {
-			return nil, errUnauthorizedSigner
+			return nil, &UnauthorizedSignerError{number, signer.Bytes()}
 		}
 
-		//
-		// 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 +166,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 +184,28 @@ 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, &UnauthorizedProposerError{s.Number, proposer.Bytes()}
+	}
+	signerIndex, _ := s.ValidatorSet.GetByAddress(signer)
+	if signerIndex == -1 {
+		return -1, &UnauthorizedSignerError{s.Number, signer.Bytes()}
+	}
+
+	tempIndex := signerIndex
+	if proposerIndex != tempIndex {
+		if tempIndex < proposerIndex {
+			tempIndex = tempIndex + len(validators)
+		}
+	}
+	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))
@@ -209,8 +215,8 @@ func (s *Snapshot) signers() []common.Address {
 	return sigs
 }
 
-// inturn returns if a signer at a given block height is in-turn or not.
-func (s *Snapshot) inturn(number uint64, signer common.Address, epoch uint64) uint64 {
+// Difficulty returns the difficulty for a particular signer at the current snapshot number
+func (s *Snapshot) Difficulty(signer common.Address) uint64 {
 	// if signer is empty
 	if bytes.Compare(signer.Bytes(), common.Address{}.Bytes()) == 0 {
 		return 1
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/errors.go b/consensus/errors.go
index a005c5f63de802cbb2bf54203257d23fe16a3109..04342bea8a7c8a6e9ef9959b4d215fa7a04955ad 100644
--- a/consensus/errors.go
+++ b/consensus/errors.go
@@ -31,6 +31,9 @@ var (
 	// to the current node.
 	ErrFutureBlock = errors.New("block in the future")
 
+	// ErrBlockTooSoon is returned when the period / producerDelay values in the genesis were not respected
+	ErrBlockTooSoon = errors.New("block was produced sooner than expected")
+
 	// ErrInvalidNumber is returned if a block's number doesn't equal it's parent's
 	// plus one.
 	ErrInvalidNumber = errors.New("invalid block number")
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/core/tx_pool.go b/core/tx_pool.go
index 02011586c3443c766fb571fa8d02f6208d9ab185..a1822ec54a033436857155cc3400dc649b4d61d9 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -117,12 +117,6 @@ const (
 	TxStatusIncluded
 )
 
-// bor acts as a way to be able to type cast consensus.Engine;
-// since importing "github.com/maticnetwork/bor/consensus/bor" results in a cyclic dependency
-type bor interface {
-	IsValidatorAction(chain consensus.ChainReader, from common.Address, tx *types.Transaction) bool
-}
-
 // blockChain provides the state of blockchain and current gas limit to do
 // some pre checks in tx pool and event subscribers.
 type blockChain interface {
@@ -537,7 +531,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
 	// Drop non-local transactions under our own minimal accepted gas price
 	local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network
 	if !local &&
-		!pool.chain.Engine().(bor).IsValidatorAction(pool.chain.(consensus.ChainReader), from, tx) &&
 		pool.gasPrice.Cmp(tx.GasPrice()) > 0 {
 		return ErrUnderpriced
 	}
diff --git a/dashboard/assets/yarn.lock b/dashboard/assets/yarn.lock
index 0fdf5593cddf3f8b8803452a6fcc5b5196800af1..a1b03f483bcd7b1b4c5d17face001eeb279df9df 100644
--- a/dashboard/assets/yarn.lock
+++ b/dashboard/assets/yarn.lock
@@ -1075,7 +1075,7 @@ after@0.8.2:
   resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
   integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
 
-agent-base@4, agent-base@^4.1.0:
+agent-base@4, agent-base@^4.3.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
   integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
@@ -3650,11 +3650,11 @@ https-browserify@^1.0.0:
   integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
 
 https-proxy-agent@^2.2.0:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
-  integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
+  integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
   dependencies:
-    agent-base "^4.1.0"
+    agent-base "^4.3.0"
     debug "^3.1.0"
 
 humps@^2.0.1:
diff --git a/eth/api_backend.go b/eth/api_backend.go
index ff03d1a91e0537368b4c8ad9f10c07e916ef819a..0be0376cf556b9b9916aa8da2a7dca9699c01b01 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -248,3 +248,17 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
 		go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
 	}
 }
+
+func (b *EthAPIBackend) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) {
+	var api *bor.API
+	for _, _api := range b.eth.Engine().APIs(b.eth.BlockChain()) {
+		if _api.Namespace == "bor" {
+			api = _api.Service.(*bor.API)
+		}
+	}
+	root, err := api.GetRootHash(starBlockNr, endBlockNr)
+	if err != nil {
+		return "", err
+	}
+	return root, nil
+}
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index 5d349a289b86f8875b4e59d4b38cdf22778a2f6f..7d44b0da034b1c5373fc2259308c637563c7e806 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -522,6 +522,15 @@ func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er
 	return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", common.ToHex(data))
 }
 
+// GetRootHash returns the merkle root of the block headers
+func (ec *Client) GetRootHash(ctx context.Context, startBlockNumber uint64, endBlockNumber uint64) (string, error) {
+	var rootHash string
+	if err := ec.c.CallContext(ctx, &rootHash, "eth_getRootHash", startBlockNumber, endBlockNumber); err != nil {
+		return "", err
+	}
+	return rootHash, nil
+}
+
 func toCallArg(msg ethereum.CallMsg) interface{} {
 	arg := map[string]interface{}{
 		"from": msg.From,
diff --git a/go.mod b/go.mod
index ca433a71c6e86be991aa6fc41768bd611f3d735e..efce11a0bf9f85afb93992b53e0a8f53161a7f88 100644
--- a/go.mod
+++ b/go.mod
@@ -60,6 +60,7 @@ require (
 	github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
 	github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
 	github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208
+	github.com/xsleonard/go-merkle v1.1.0
 	golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4
 	golang.org/x/net v0.0.0-20200301022130-244492dfa37a
 	golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
diff --git a/go.sum b/go.sum
index c51ed2d8e957a19c286f02059467ee6d93ff1938..c15b30bb97f700cbf66266ae02be6fb655867871 100644
--- a/go.sum
+++ b/go.sum
@@ -176,6 +176,8 @@ github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZ
 github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
 github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
 github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
+github.com/xsleonard/go-merkle v1.1.0 h1:fHe1fuhJjGH22ZzVTAH0jqHLhTGhOq3wQjJN+8P0jQg=
+github.com/xsleonard/go-merkle v1.1.0/go.mod h1:cW4z+UZ/4f2n9IJgIiyDCdYguchoDyDAPmpuOWGxdGg=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA=
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/internal/ethapi/api.go b/internal/ethapi/api.go
index 2a939ed2c463f6d81a3d249a6d45afffd50d95a9..cee5a575fb45cd30e27f4f2d9b4ed15c454e4875 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -716,6 +716,14 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A
 	return res[:], state.Error()
 }
 
+func (s *PublicBlockChainAPI) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) {
+	root, err := s.b.GetRootHash(ctx, starBlockNr, endBlockNr)
+	if err != nil {
+		return "", err
+	}
+	return root, nil
+}
+
 // CallArgs represents the arguments for a call.
 type CallArgs struct {
 	From     *common.Address `json:"from"`
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index e0deeab81fdb42e2c907b223fe1469d085b52866..595a69b0cc2ebd6579b298e4aa01c15a6b76bec5 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -62,6 +62,7 @@ type Backend interface {
 	SubscribeStateEvent(ch chan<- core.NewStateChangeEvent) event.Subscription
 	SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
 	SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
+	GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error)
 
 	// Transaction pool API
 	SendTx(ctx context.Context, signedTx *types.Transaction) error
diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go
index d3fea7b50cc52366df901f91d244f686f11e2841..9ee4b4f3a7a46ceaf19b8c8afc51eca8b0b2f5bb 100644
--- a/internal/web3ext/web3ext.go
+++ b/internal/web3ext/web3ext.go
@@ -149,6 +149,11 @@ web3._extend({
 			call: 'bor_getCurrentValidators',
 			params: 0
 		}),
+		new web3._extend.Method({
+			name: 'getRootHash',
+			call: 'bor_getRootHash',
+			params: 2,
+		}),
 	]
 });
 `
diff --git a/les/api_backend.go b/les/api_backend.go
index 5c8ec82d8812f6c828364e2d4a44334ebb163371..3b228e7374625e5a23c82ebb706372969ee8439c 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -223,3 +223,7 @@ func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
 		go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
 	}
 }
+
+func (b *LesApiBackend) GetRootHash(ctx context.Context, starBlockNr uint64, endBlockNr uint64) (string, error) {
+	return "", errors.New("Not implemented")
+}
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/mocks/IHeimdallClient.go b/mocks/IHeimdallClient.go
index cb09800c746d629e87e0cb52269b3be23be0c7ea..d6037d2162de114cfa0905e9fd7a79fe424de8cd 100644
--- a/mocks/IHeimdallClient.go
+++ b/mocks/IHeimdallClient.go
@@ -12,19 +12,13 @@ type IHeimdallClient struct {
 	mock.Mock
 }
 
-// Fetch provides a mock function with given fields: paths
-func (_m *IHeimdallClient) Fetch(paths ...string) (*bor.ResponseWithHeight, error) {
-	_va := make([]interface{}, len(paths))
-	for _i := range paths {
-		_va[_i] = paths[_i]
-	}
-	var _ca []interface{}
-	_ca = append(_ca, _va...)
-	ret := _m.Called(_ca...)
+// Fetch provides a mock function with given fields: path, query
+func (_m *IHeimdallClient) Fetch(path string, query string) (*bor.ResponseWithHeight, error) {
+	ret := _m.Called(path, query)
 
 	var r0 *bor.ResponseWithHeight
-	if rf, ok := ret.Get(0).(func(...string) *bor.ResponseWithHeight); ok {
-		r0 = rf(paths...)
+	if rf, ok := ret.Get(0).(func(string, string) *bor.ResponseWithHeight); ok {
+		r0 = rf(path, query)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*bor.ResponseWithHeight)
@@ -32,8 +26,8 @@ func (_m *IHeimdallClient) Fetch(paths ...string) (*bor.ResponseWithHeight, erro
 	}
 
 	var r1 error
-	if rf, ok := ret.Get(1).(func(...string) error); ok {
-		r1 = rf(paths...)
+	if rf, ok := ret.Get(1).(func(string, string) error); ok {
+		r1 = rf(path, query)
 	} else {
 		r1 = ret.Error(1)
 	}
@@ -41,19 +35,36 @@ func (_m *IHeimdallClient) Fetch(paths ...string) (*bor.ResponseWithHeight, erro
 	return r0, r1
 }
 
-// FetchWithRetry provides a mock function with given fields: paths
-func (_m *IHeimdallClient) FetchWithRetry(paths ...string) (*bor.ResponseWithHeight, error) {
-	_va := make([]interface{}, len(paths))
-	for _i := range paths {
-		_va[_i] = paths[_i]
+// FetchStateSyncEvents provides a mock function with given fields: fromID, to
+func (_m *IHeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*bor.EventRecordWithTime, error) {
+	ret := _m.Called(fromID, to)
+
+	var r0 []*bor.EventRecordWithTime
+	if rf, ok := ret.Get(0).(func(uint64, int64) []*bor.EventRecordWithTime); ok {
+		r0 = rf(fromID, to)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).([]*bor.EventRecordWithTime)
+		}
+	}
+
+	var r1 error
+	if rf, ok := ret.Get(1).(func(uint64, int64) error); ok {
+		r1 = rf(fromID, to)
+	} else {
+		r1 = ret.Error(1)
 	}
-	var _ca []interface{}
-	_ca = append(_ca, _va...)
-	ret := _m.Called(_ca...)
+
+	return r0, r1
+}
+
+// FetchWithRetry provides a mock function with given fields: path, query
+func (_m *IHeimdallClient) FetchWithRetry(path string, query string) (*bor.ResponseWithHeight, error) {
+	ret := _m.Called(path, query)
 
 	var r0 *bor.ResponseWithHeight
-	if rf, ok := ret.Get(0).(func(...string) *bor.ResponseWithHeight); ok {
-		r0 = rf(paths...)
+	if rf, ok := ret.Get(0).(func(string, string) *bor.ResponseWithHeight); ok {
+		r0 = rf(path, query)
 	} else {
 		if ret.Get(0) != nil {
 			r0 = ret.Get(0).(*bor.ResponseWithHeight)
@@ -61,8 +72,8 @@ func (_m *IHeimdallClient) FetchWithRetry(paths ...string) (*bor.ResponseWithHei
 	}
 
 	var r1 error
-	if rf, ok := ret.Get(1).(func(...string) error); ok {
-		r1 = rf(paths...)
+	if rf, ok := ret.Get(1).(func(string, string) error); ok {
+		r1 = rf(path, query)
 	} else {
 		r1 = ret.Error(1)
 	}
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"
 )
 
diff --git a/params/config.go b/params/config.go
index e56336fe2d5f6d01a12c247f6ca846817d6eb251..3af6bb064becce65bc2a228232bf740163c3ae3c 100644
--- a/params/config.go
+++ b/params/config.go
@@ -319,6 +319,7 @@ type BorConfig struct {
 	Period                uint64 `json:"period"`                // Number of seconds between blocks to enforce
 	ProducerDelay         uint64 `json:"producerDelay"`         // Number of seconds delay between two producer interval
 	Sprint                uint64 `json:"sprint"`                // Epoch length to proposer
+	BackupMultiplier      uint64 `json:"backupMultiplier"`      // Backup multiplier to determine the wiggle time
 	ValidatorContract     string `json:"validatorContract"`     // Validator set contract
 	StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract
 }