github.com/ledgerwatch/erigon-lib@v1.0.0/chain/chain_config.go (about)

     1  /*
     2     Copyright 2021 Erigon contributors
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package chain
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  	"sort"
    23  	"strconv"
    24  
    25  	"github.com/ledgerwatch/erigon-lib/common"
    26  )
    27  
    28  // Config is the core config which determines the blockchain settings.
    29  //
    30  // Config is stored in the database on a per block basis. This means
    31  // that any network, identified by its genesis block, can have its own
    32  // set of configuration options.
    33  type Config struct {
    34  	ChainName string
    35  	ChainID   *big.Int `json:"chainId"` // chainId identifies the current chain and is used for replay protection
    36  
    37  	Consensus ConsensusName `json:"consensus,omitempty"` // aura, ethash or clique
    38  
    39  	// *Block fields activate the corresponding hard fork at a certain block number,
    40  	// while *Time fields do so based on the block's time stamp.
    41  	// nil means that the hard-fork is not scheduled,
    42  	// while 0 means that it's already activated from genesis.
    43  
    44  	// ETH mainnet upgrades
    45  	// See https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades
    46  	HomesteadBlock        *big.Int `json:"homesteadBlock,omitempty"`
    47  	DAOForkBlock          *big.Int `json:"daoForkBlock,omitempty"`
    48  	TangerineWhistleBlock *big.Int `json:"eip150Block,omitempty"`
    49  	SpuriousDragonBlock   *big.Int `json:"eip155Block,omitempty"`
    50  	ByzantiumBlock        *big.Int `json:"byzantiumBlock,omitempty"`
    51  	ConstantinopleBlock   *big.Int `json:"constantinopleBlock,omitempty"`
    52  	PetersburgBlock       *big.Int `json:"petersburgBlock,omitempty"`
    53  	IstanbulBlock         *big.Int `json:"istanbulBlock,omitempty"`
    54  	MuirGlacierBlock      *big.Int `json:"muirGlacierBlock,omitempty"`
    55  	BerlinBlock           *big.Int `json:"berlinBlock,omitempty"`
    56  	LondonBlock           *big.Int `json:"londonBlock,omitempty"`
    57  	ArrowGlacierBlock     *big.Int `json:"arrowGlacierBlock,omitempty"`
    58  	GrayGlacierBlock      *big.Int `json:"grayGlacierBlock,omitempty"`
    59  
    60  	// EIP-3675: Upgrade consensus to Proof-of-Stake (a.k.a. "Paris", "The Merge")
    61  	TerminalTotalDifficulty       *big.Int `json:"terminalTotalDifficulty,omitempty"`       // The merge happens when terminal total difficulty is reached
    62  	TerminalTotalDifficultyPassed bool     `json:"terminalTotalDifficultyPassed,omitempty"` // Disable PoW sync for networks that have already passed through the Merge
    63  	MergeNetsplitBlock            *big.Int `json:"mergeNetsplitBlock,omitempty"`            // Virtual fork after The Merge to use as a network splitter; see FORK_NEXT_VALUE in EIP-3675
    64  
    65  	// Mainnet fork scheduling switched from block numbers to timestamps after The Merge
    66  	ShanghaiTime *big.Int `json:"shanghaiTime,omitempty"`
    67  	CancunTime   *big.Int `json:"cancunTime,omitempty"`
    68  	PragueTime   *big.Int `json:"pragueTime,omitempty"`
    69  
    70  	Eip1559FeeCollector           *common.Address `json:"eip1559FeeCollector,omitempty"`           // (Optional) Address where burnt EIP-1559 fees go to
    71  	Eip1559FeeCollectorTransition *big.Int        `json:"eip1559FeeCollectorTransition,omitempty"` // (Optional) Block from which burnt EIP-1559 fees go to the Eip1559FeeCollector
    72  
    73  	// Various consensus engines
    74  	Ethash *EthashConfig `json:"ethash,omitempty"`
    75  	Clique *CliqueConfig `json:"clique,omitempty"`
    76  	Aura   *AuRaConfig   `json:"aura,omitempty"`
    77  	Bor    *BorConfig    `json:"bor,omitempty"`
    78  }
    79  
    80  func (c *Config) String() string {
    81  	engine := c.getEngine()
    82  
    83  	return fmt.Sprintf("{ChainID: %v, Homestead: %v, DAO: %v, Tangerine Whistle: %v, Spurious Dragon: %v, Byzantium: %v, Constantinople: %v, Petersburg: %v, Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, Gray Glacier: %v, Terminal Total Difficulty: %v, Merge Netsplit: %v, Shanghai: %v, Cancun: %v, Prague: %v, Engine: %v}",
    84  		c.ChainID,
    85  		c.HomesteadBlock,
    86  		c.DAOForkBlock,
    87  		c.TangerineWhistleBlock,
    88  		c.SpuriousDragonBlock,
    89  		c.ByzantiumBlock,
    90  		c.ConstantinopleBlock,
    91  		c.PetersburgBlock,
    92  		c.IstanbulBlock,
    93  		c.MuirGlacierBlock,
    94  		c.BerlinBlock,
    95  		c.LondonBlock,
    96  		c.ArrowGlacierBlock,
    97  		c.GrayGlacierBlock,
    98  		c.TerminalTotalDifficulty,
    99  		c.MergeNetsplitBlock,
   100  		c.ShanghaiTime,
   101  		c.CancunTime,
   102  		c.PragueTime,
   103  		engine,
   104  	)
   105  }
   106  
   107  func (c *Config) getEngine() string {
   108  	switch {
   109  	case c.Ethash != nil:
   110  		return c.Ethash.String()
   111  	case c.Clique != nil:
   112  		return c.Clique.String()
   113  	case c.Bor != nil:
   114  		return c.Bor.String()
   115  	case c.Aura != nil:
   116  		return c.Aura.String()
   117  	default:
   118  		return "unknown"
   119  	}
   120  }
   121  
   122  // IsHomestead returns whether num is either equal to the homestead block or greater.
   123  func (c *Config) IsHomestead(num uint64) bool {
   124  	return isForked(c.HomesteadBlock, num)
   125  }
   126  
   127  // IsDAOFork returns whether num is either equal to the DAO fork block or greater.
   128  func (c *Config) IsDAOFork(num uint64) bool {
   129  	return isForked(c.DAOForkBlock, num)
   130  }
   131  
   132  // IsTangerineWhistle returns whether num is either equal to the Tangerine Whistle (EIP150) fork block or greater.
   133  func (c *Config) IsTangerineWhistle(num uint64) bool {
   134  	return isForked(c.TangerineWhistleBlock, num)
   135  }
   136  
   137  // IsSpuriousDragon returns whether num is either equal to the Spurious Dragon fork block or greater.
   138  func (c *Config) IsSpuriousDragon(num uint64) bool {
   139  	return isForked(c.SpuriousDragonBlock, num)
   140  }
   141  
   142  // IsByzantium returns whether num is either equal to the Byzantium fork block or greater.
   143  func (c *Config) IsByzantium(num uint64) bool {
   144  	return isForked(c.ByzantiumBlock, num)
   145  }
   146  
   147  // IsConstantinople returns whether num is either equal to the Constantinople fork block or greater.
   148  func (c *Config) IsConstantinople(num uint64) bool {
   149  	return isForked(c.ConstantinopleBlock, num)
   150  }
   151  
   152  // IsMuirGlacier returns whether num is either equal to the Muir Glacier (EIP-2384) fork block or greater.
   153  func (c *Config) IsMuirGlacier(num uint64) bool {
   154  	return isForked(c.MuirGlacierBlock, num)
   155  }
   156  
   157  // IsPetersburg returns whether num is either
   158  // - equal to or greater than the PetersburgBlock fork block,
   159  // - OR is nil, and Constantinople is active
   160  func (c *Config) IsPetersburg(num uint64) bool {
   161  	return isForked(c.PetersburgBlock, num) || c.PetersburgBlock == nil && isForked(c.ConstantinopleBlock, num)
   162  }
   163  
   164  // IsIstanbul returns whether num is either equal to the Istanbul fork block or greater.
   165  func (c *Config) IsIstanbul(num uint64) bool {
   166  	return isForked(c.IstanbulBlock, num)
   167  }
   168  
   169  // IsBerlin returns whether num is either equal to the Berlin fork block or greater.
   170  func (c *Config) IsBerlin(num uint64) bool {
   171  	return isForked(c.BerlinBlock, num)
   172  }
   173  
   174  // IsLondon returns whether num is either equal to the London fork block or greater.
   175  func (c *Config) IsLondon(num uint64) bool {
   176  	return isForked(c.LondonBlock, num)
   177  }
   178  
   179  // IsArrowGlacier returns whether num is either equal to the Arrow Glacier (EIP-4345) fork block or greater.
   180  func (c *Config) IsArrowGlacier(num uint64) bool {
   181  	return isForked(c.ArrowGlacierBlock, num)
   182  }
   183  
   184  // IsGrayGlacier returns whether num is either equal to the Gray Glacier (EIP-5133) fork block or greater.
   185  func (c *Config) IsGrayGlacier(num uint64) bool {
   186  	return isForked(c.GrayGlacierBlock, num)
   187  }
   188  
   189  // IsShanghai returns whether time is either equal to the Shanghai fork time or greater.
   190  func (c *Config) IsShanghai(time uint64) bool {
   191  	return isForked(c.ShanghaiTime, time)
   192  }
   193  
   194  // IsCancun returns whether time is either equal to the Cancun fork time or greater.
   195  func (c *Config) IsCancun(time uint64) bool {
   196  	return isForked(c.CancunTime, time)
   197  }
   198  
   199  // IsPrague returns whether time is either equal to the Prague fork time or greater.
   200  func (c *Config) IsPrague(time uint64) bool {
   201  	return isForked(c.PragueTime, time)
   202  }
   203  
   204  func (c *Config) IsEip1559FeeCollector(num uint64) bool {
   205  	return c.Eip1559FeeCollector != nil && isForked(c.Eip1559FeeCollectorTransition, num)
   206  }
   207  
   208  // CheckCompatible checks whether scheduled fork transitions have been imported
   209  // with a mismatching chain configuration.
   210  func (c *Config) CheckCompatible(newcfg *Config, height uint64) *ConfigCompatError {
   211  	bhead := height
   212  
   213  	// Iterate checkCompatible to find the lowest conflict.
   214  	var lasterr *ConfigCompatError
   215  	for {
   216  		err := c.checkCompatible(newcfg, bhead)
   217  		if err == nil || (lasterr != nil && err.RewindTo == lasterr.RewindTo) {
   218  			break
   219  		}
   220  		lasterr = err
   221  		bhead = err.RewindTo
   222  	}
   223  	return lasterr
   224  }
   225  
   226  type forkBlockNumber struct {
   227  	name        string
   228  	blockNumber *big.Int
   229  	optional    bool // if true, the fork may be nil and next fork is still allowed
   230  }
   231  
   232  func (c *Config) forkBlockNumbers() []forkBlockNumber {
   233  	return []forkBlockNumber{
   234  		{name: "homesteadBlock", blockNumber: c.HomesteadBlock},
   235  		{name: "daoForkBlock", blockNumber: c.DAOForkBlock, optional: true},
   236  		{name: "eip150Block", blockNumber: c.TangerineWhistleBlock},
   237  		{name: "eip155Block", blockNumber: c.SpuriousDragonBlock},
   238  		{name: "byzantiumBlock", blockNumber: c.ByzantiumBlock},
   239  		{name: "constantinopleBlock", blockNumber: c.ConstantinopleBlock},
   240  		{name: "petersburgBlock", blockNumber: c.PetersburgBlock},
   241  		{name: "istanbulBlock", blockNumber: c.IstanbulBlock},
   242  		{name: "muirGlacierBlock", blockNumber: c.MuirGlacierBlock, optional: true},
   243  		{name: "berlinBlock", blockNumber: c.BerlinBlock},
   244  		{name: "londonBlock", blockNumber: c.LondonBlock},
   245  		{name: "arrowGlacierBlock", blockNumber: c.ArrowGlacierBlock, optional: true},
   246  		{name: "grayGlacierBlock", blockNumber: c.GrayGlacierBlock, optional: true},
   247  		{name: "mergeNetsplitBlock", blockNumber: c.MergeNetsplitBlock, optional: true},
   248  	}
   249  }
   250  
   251  // CheckConfigForkOrder checks that we don't "skip" any forks
   252  func (c *Config) CheckConfigForkOrder() error {
   253  	if c != nil && c.ChainID != nil && c.ChainID.Uint64() == 77 {
   254  		return nil
   255  	}
   256  
   257  	var lastFork forkBlockNumber
   258  
   259  	for _, fork := range c.forkBlockNumbers() {
   260  		if lastFork.name != "" {
   261  			// Next one must be higher number
   262  			if lastFork.blockNumber == nil && fork.blockNumber != nil {
   263  				return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at %v",
   264  					lastFork.name, fork.name, fork.blockNumber)
   265  			}
   266  			if lastFork.blockNumber != nil && fork.blockNumber != nil {
   267  				if lastFork.blockNumber.Cmp(fork.blockNumber) > 0 {
   268  					return fmt.Errorf("unsupported fork ordering: %v enabled at %v, but %v enabled at %v",
   269  						lastFork.name, lastFork.blockNumber, fork.name, fork.blockNumber)
   270  				}
   271  			}
   272  			// If it was optional and not set, then ignore it
   273  		}
   274  		if !fork.optional || fork.blockNumber != nil {
   275  			lastFork = fork
   276  		}
   277  	}
   278  	return nil
   279  }
   280  
   281  func (c *Config) checkCompatible(newcfg *Config, head uint64) *ConfigCompatError {
   282  	// returns true if a fork scheduled at s1 cannot be rescheduled to block s2 because head is already past the fork.
   283  	incompatible := func(s1, s2 *big.Int, head uint64) bool {
   284  		return (isForked(s1, head) || isForked(s2, head)) && !numEqual(s1, s2)
   285  	}
   286  
   287  	// Ethereum mainnet forks
   288  	if incompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
   289  		return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
   290  	}
   291  	if incompatible(c.DAOForkBlock, newcfg.DAOForkBlock, head) {
   292  		return newCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock)
   293  	}
   294  	if incompatible(c.TangerineWhistleBlock, newcfg.TangerineWhistleBlock, head) {
   295  		return newCompatError("Tangerine Whistle fork block", c.TangerineWhistleBlock, newcfg.TangerineWhistleBlock)
   296  	}
   297  	if incompatible(c.SpuriousDragonBlock, newcfg.SpuriousDragonBlock, head) {
   298  		return newCompatError("Spurious Dragon fork block", c.SpuriousDragonBlock, newcfg.SpuriousDragonBlock)
   299  	}
   300  	if c.IsSpuriousDragon(head) && !numEqual(c.ChainID, newcfg.ChainID) {
   301  		return newCompatError("EIP155 chain ID", c.SpuriousDragonBlock, newcfg.SpuriousDragonBlock)
   302  	}
   303  	if incompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, head) {
   304  		return newCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock)
   305  	}
   306  	if incompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) {
   307  		return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock)
   308  	}
   309  	if incompatible(c.PetersburgBlock, newcfg.PetersburgBlock, head) {
   310  		// the only case where we allow Petersburg to be set in the past is if it is equal to Constantinople
   311  		// mainly to satisfy fork ordering requirements which state that Petersburg fork be set if Constantinople fork is set
   312  		if incompatible(c.ConstantinopleBlock, newcfg.PetersburgBlock, head) {
   313  			return newCompatError("Petersburg fork block", c.PetersburgBlock, newcfg.PetersburgBlock)
   314  		}
   315  	}
   316  	if incompatible(c.IstanbulBlock, newcfg.IstanbulBlock, head) {
   317  		return newCompatError("Istanbul fork block", c.IstanbulBlock, newcfg.IstanbulBlock)
   318  	}
   319  	if incompatible(c.MuirGlacierBlock, newcfg.MuirGlacierBlock, head) {
   320  		return newCompatError("Muir Glacier fork block", c.MuirGlacierBlock, newcfg.MuirGlacierBlock)
   321  	}
   322  	if incompatible(c.BerlinBlock, newcfg.BerlinBlock, head) {
   323  		return newCompatError("Berlin fork block", c.BerlinBlock, newcfg.BerlinBlock)
   324  	}
   325  	if incompatible(c.LondonBlock, newcfg.LondonBlock, head) {
   326  		return newCompatError("London fork block", c.LondonBlock, newcfg.LondonBlock)
   327  	}
   328  	if incompatible(c.ArrowGlacierBlock, newcfg.ArrowGlacierBlock, head) {
   329  		return newCompatError("Arrow Glacier fork block", c.ArrowGlacierBlock, newcfg.ArrowGlacierBlock)
   330  	}
   331  	if incompatible(c.GrayGlacierBlock, newcfg.GrayGlacierBlock, head) {
   332  		return newCompatError("Gray Glacier fork block", c.GrayGlacierBlock, newcfg.GrayGlacierBlock)
   333  	}
   334  	if incompatible(c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock, head) {
   335  		return newCompatError("Merge netsplit block", c.MergeNetsplitBlock, newcfg.MergeNetsplitBlock)
   336  	}
   337  
   338  	return nil
   339  }
   340  
   341  func numEqual(x, y *big.Int) bool {
   342  	if x == nil {
   343  		return y == nil
   344  	}
   345  	if y == nil {
   346  		return x == nil
   347  	}
   348  	return x.Cmp(y) == 0
   349  }
   350  
   351  // ConfigCompatError is raised if the locally-stored blockchain is initialised with a
   352  // ChainConfig that would alter the past.
   353  type ConfigCompatError struct {
   354  	What string
   355  	// block numbers of the stored and new configurations
   356  	StoredConfig, NewConfig *big.Int
   357  	// the block number to which the local chain must be rewound to correct the error
   358  	RewindTo uint64
   359  }
   360  
   361  func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError {
   362  	var rew *big.Int
   363  	switch {
   364  	case storedblock == nil:
   365  		rew = newblock
   366  	case newblock == nil || storedblock.Cmp(newblock) < 0:
   367  		rew = storedblock
   368  	default:
   369  		rew = newblock
   370  	}
   371  	err := &ConfigCompatError{what, storedblock, newblock, 0}
   372  	if rew != nil && rew.Sign() > 0 {
   373  		err.RewindTo = rew.Uint64() - 1
   374  	}
   375  	return err
   376  }
   377  
   378  func (err *ConfigCompatError) Error() string {
   379  	return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo)
   380  }
   381  
   382  // EthashConfig is the consensus engine configs for proof-of-work based sealing.
   383  type EthashConfig struct{}
   384  
   385  // String implements the stringer interface, returning the consensus engine details.
   386  func (c *EthashConfig) String() string {
   387  	return "ethash"
   388  }
   389  
   390  // CliqueConfig is the consensus engine configs for proof-of-authority based sealing.
   391  type CliqueConfig struct {
   392  	Period uint64 `json:"period"` // Number of seconds between blocks to enforce
   393  	Epoch  uint64 `json:"epoch"`  // Epoch length to reset votes and checkpoint
   394  }
   395  
   396  // String implements the stringer interface, returning the consensus engine details.
   397  func (c *CliqueConfig) String() string {
   398  	return "clique"
   399  }
   400  
   401  // BorConfig is the consensus engine configs for Matic bor based sealing.
   402  type BorConfig struct {
   403  	Period                map[string]uint64 `json:"period"`                // Number of seconds between blocks to enforce
   404  	ProducerDelay         map[string]uint64 `json:"producerDelay"`         // Number of seconds delay between two producer interval
   405  	Sprint                map[string]uint64 `json:"sprint"`                // Epoch length to proposer
   406  	BackupMultiplier      map[string]uint64 `json:"backupMultiplier"`      // Backup multiplier to determine the wiggle time
   407  	ValidatorContract     string            `json:"validatorContract"`     // Validator set contract
   408  	StateReceiverContract string            `json:"stateReceiverContract"` // State receiver contract
   409  
   410  	OverrideStateSyncRecords map[string]int         `json:"overrideStateSyncRecords"` // override state records count
   411  	BlockAlloc               map[string]interface{} `json:"blockAlloc"`
   412  
   413  	CalcuttaBlock *big.Int `json:"calcuttaBlock"` // Calcutta switch block (nil = no fork, 0 = already on calcutta)
   414  	JaipurBlock   *big.Int `json:"jaipurBlock"`   // Jaipur switch block (nil = no fork, 0 = already on jaipur)
   415  	DelhiBlock    *big.Int `json:"delhiBlock"`    // Delhi switch block (nil = no fork, 0 = already on delhi)
   416  
   417  	IndoreBlock                *big.Int          `json:"indoreBlock"`                // Indore switch block (nil = no fork, 0 = already on indore)
   418  	StateSyncConfirmationDelay map[string]uint64 `json:"stateSyncConfirmationDelay"` // StateSync Confirmation Delay, in seconds, to calculate `to`
   419  
   420  	sprints sprints
   421  }
   422  
   423  // String implements the stringer interface, returning the consensus engine details.
   424  func (b *BorConfig) String() string {
   425  	return "bor"
   426  }
   427  
   428  func (c *BorConfig) CalculateProducerDelay(number uint64) uint64 {
   429  	return borKeyValueConfigHelper(c.ProducerDelay, number)
   430  }
   431  
   432  func (c *BorConfig) CalculateSprint(number uint64) uint64 {
   433  	if c.sprints == nil {
   434  		c.sprints = asSprints(c.Sprint)
   435  	}
   436  
   437  	for i := 0; i < len(c.sprints)-1; i++ {
   438  		if number >= c.sprints[i].from && number < c.sprints[i+1].from {
   439  			return c.sprints[i].size
   440  		}
   441  	}
   442  
   443  	return c.sprints[len(c.sprints)-1].size
   444  }
   445  
   446  func (c *BorConfig) CalculateSprintCount(from, to uint64) int {
   447  	switch {
   448  	case from > to:
   449  		return 0
   450  	case from < to:
   451  		to--
   452  	}
   453  
   454  	if c.sprints == nil {
   455  		c.sprints = asSprints(c.Sprint)
   456  	}
   457  
   458  	count := uint64(0)
   459  	startCalc := from
   460  
   461  	zeroth := func(boundary uint64, size uint64) uint64 {
   462  		if boundary%size == 0 {
   463  			return 1
   464  		}
   465  
   466  		return 0
   467  	}
   468  
   469  	for i := 0; i < len(c.sprints)-1; i++ {
   470  		if startCalc >= c.sprints[i].from && startCalc < c.sprints[i+1].from {
   471  			if to >= c.sprints[i].from && to < c.sprints[i+1].from {
   472  				if startCalc == to {
   473  					return int(count + zeroth(startCalc, c.sprints[i].size))
   474  				}
   475  				return int(count + zeroth(startCalc, c.sprints[i].size) + (to-startCalc)/c.sprints[i].size)
   476  			} else {
   477  				endCalc := c.sprints[i+1].from - 1
   478  				count += zeroth(startCalc, c.sprints[i].size) + (endCalc-startCalc)/c.sprints[i].size
   479  				startCalc = endCalc + 1
   480  			}
   481  		}
   482  	}
   483  
   484  	if startCalc == to {
   485  		return int(count + zeroth(startCalc, c.sprints[len(c.sprints)-1].size))
   486  	}
   487  
   488  	return int(count + zeroth(startCalc, c.sprints[len(c.sprints)-1].size) + (to-startCalc)/c.sprints[len(c.sprints)-1].size)
   489  }
   490  
   491  func (c *BorConfig) CalculateBackupMultiplier(number uint64) uint64 {
   492  	return c.calcConfig(c.BackupMultiplier, number)
   493  }
   494  
   495  func (c *BorConfig) CalculatePeriod(number uint64) uint64 {
   496  	return c.calcConfig(c.Period, number)
   497  }
   498  
   499  func (c *BorConfig) IsJaipur(number uint64) bool {
   500  	return isForked(c.JaipurBlock, number)
   501  }
   502  
   503  func (c *BorConfig) IsDelhi(number uint64) bool {
   504  	return isForked(c.DelhiBlock, number)
   505  }
   506  
   507  func (c *BorConfig) IsCalcutta(number uint64) bool {
   508  	return isForked(c.CalcuttaBlock, number)
   509  }
   510  
   511  func (c *BorConfig) IsOnCalcutta(number *big.Int) bool {
   512  	return numEqual(c.CalcuttaBlock, number)
   513  }
   514  
   515  func (c *BorConfig) IsIndore(number uint64) bool {
   516  	return isForked(c.IndoreBlock, number)
   517  }
   518  
   519  func (c *BorConfig) CalculateStateSyncDelay(number uint64) uint64 {
   520  	return borKeyValueConfigHelper(c.StateSyncConfirmationDelay, number)
   521  }
   522  
   523  func (c *BorConfig) calcConfig(field map[string]uint64, number uint64) uint64 {
   524  	keys := sortMapKeys(field)
   525  	for i := 0; i < len(keys)-1; i++ {
   526  		valUint, _ := strconv.ParseUint(keys[i], 10, 64)
   527  		valUintNext, _ := strconv.ParseUint(keys[i+1], 10, 64)
   528  		if number > valUint && number < valUintNext {
   529  			return field[keys[i]]
   530  		}
   531  	}
   532  	return field[keys[len(keys)-1]]
   533  }
   534  
   535  func borKeyValueConfigHelper(field map[string]uint64, number uint64) uint64 {
   536  	keys := sortMapKeys(field)
   537  	for i := 0; i < len(keys)-1; i++ {
   538  		valUint, _ := strconv.ParseUint(keys[i], 10, 64)
   539  		valUintNext, _ := strconv.ParseUint(keys[i+1], 10, 64)
   540  
   541  		if number >= valUint && number < valUintNext {
   542  			return field[keys[i]]
   543  		}
   544  	}
   545  
   546  	return field[keys[len(keys)-1]]
   547  }
   548  
   549  func sortMapKeys(m map[string]uint64) []string {
   550  	keys := make([]string, 0, len(m))
   551  	for k := range m {
   552  		keys = append(keys, k)
   553  	}
   554  	sort.Strings(keys)
   555  
   556  	return keys
   557  }
   558  
   559  type sprint struct {
   560  	from, size uint64
   561  }
   562  
   563  type sprints []sprint
   564  
   565  func (s sprints) Len() int {
   566  	return len(s)
   567  }
   568  
   569  func (s sprints) Swap(i, j int) {
   570  	s[i], s[j] = s[j], s[i]
   571  }
   572  
   573  func (s sprints) Less(i, j int) bool {
   574  	return s[i].from < s[j].from
   575  }
   576  
   577  func asSprints(configSprints map[string]uint64) sprints {
   578  	sprints := make(sprints, len(configSprints))
   579  
   580  	i := 0
   581  	for key, value := range configSprints {
   582  		sprints[i].from, _ = strconv.ParseUint(key, 10, 64)
   583  		sprints[i].size = value
   584  		i++
   585  	}
   586  
   587  	sort.Sort(sprints)
   588  
   589  	return sprints
   590  }
   591  
   592  // Rules is syntactic sugar over Config. It can be used for functions
   593  // that do not have or require information about the block.
   594  //
   595  // Rules is a one time interface meaning that it shouldn't be used in between transition
   596  // phases.
   597  type Rules struct {
   598  	ChainID                                                 *big.Int
   599  	IsHomestead, IsTangerineWhistle, IsSpuriousDragon       bool
   600  	IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
   601  	IsBerlin, IsLondon, IsShanghai, IsCancun, IsPrague      bool
   602  	IsEip1559FeeCollector, IsAura                           bool
   603  }
   604  
   605  // Rules ensures c's ChainID is not nil and returns a new Rules instance
   606  func (c *Config) Rules(num uint64, time uint64) *Rules {
   607  	chainID := c.ChainID
   608  	if chainID == nil {
   609  		chainID = new(big.Int)
   610  	}
   611  
   612  	return &Rules{
   613  		ChainID:               new(big.Int).Set(chainID),
   614  		IsHomestead:           c.IsHomestead(num),
   615  		IsTangerineWhistle:    c.IsTangerineWhistle(num),
   616  		IsSpuriousDragon:      c.IsSpuriousDragon(num),
   617  		IsByzantium:           c.IsByzantium(num),
   618  		IsConstantinople:      c.IsConstantinople(num),
   619  		IsPetersburg:          c.IsPetersburg(num),
   620  		IsIstanbul:            c.IsIstanbul(num),
   621  		IsBerlin:              c.IsBerlin(num),
   622  		IsLondon:              c.IsLondon(num),
   623  		IsShanghai:            c.IsShanghai(time),
   624  		IsCancun:              c.IsCancun(time),
   625  		IsPrague:              c.IsPrague(time),
   626  		IsEip1559FeeCollector: c.IsEip1559FeeCollector(num),
   627  		IsAura:                c.Aura != nil,
   628  	}
   629  }
   630  
   631  // isForked returns whether a fork scheduled at block s is active at the given head block.
   632  func isForked(s *big.Int, head uint64) bool {
   633  	if s == nil {
   634  		return false
   635  	}
   636  	return s.Uint64() <= head
   637  }