github.com/codingfuture/orig-energi3@v0.8.4/params/config.go (about)

     1  // Copyright 2018 The Energi Core Authors
     2  // Copyright 2016 The go-ethereum Authors
     3  // This file is part of the Energi Core library.
     4  //
     5  // The Energi Core library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The Energi Core library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package params
    19  
    20  import (
    21  	"fmt"
    22  	"math/big"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  )
    26  
    27  // Genesis hashes to enforce below configs on.
    28  var (
    29  	MainnetGenesisHash = common.HexToHash("0x20ce7692e14be55a26793cbc0a5edd187e680a465025a89092691b72b3f13050")
    30  	TestnetGenesisHash = common.HexToHash("0x4d5513e2cd959af850591de3e38f6cc7a2f9775f8159da0159788a95ef4e85ac")
    31  
    32  	MainnetMigrationSigner = common.HexToAddress("0xac34a2555de08384cd7960f35d3ab048fcf9f83a")
    33  	TestnetMigrationSigner = common.HexToAddress("0xb1372ea07f6a92bc86fd5f8cdf468528f79f87ca")
    34  
    35  	MainnetEBISigner = common.HexToAddress("0xf7ec1411b51eebd813f71545ec6b5dc8a7ab71bc")
    36  	TestnetEBISigner = common.HexToAddress("0x25bbaaaf27ab1966c3ab9faf31277a1db7601f3f")
    37  
    38  	MainnetCPPSigner = common.HexToAddress("0xa7acab32c9b29c116825b85d61e1e5587d7db7e4")
    39  	TestnetCPPSigner = common.HexToAddress("0xb1372ea07f6a92bc86fd5f8cdf468528f79f87ca")
    40  
    41  	MainnetBackbone = common.HexToAddress("0x4d11f979cc5813f85436bdd4ab530a3768d34ae3")
    42  	TestnetBackbone = common.HexToAddress("0x5143c57fcde025f05a19d0de9a7dac852e553624")
    43  )
    44  
    45  // TrustedCheckpoints associates each known checkpoint with the genesis hash of
    46  // the chain it belongs to.
    47  var TrustedCheckpoints = map[common.Hash]*TrustedCheckpoint{
    48  	//MainnetGenesisHash: MainnetTrustedCheckpoint,
    49  	//TestnetGenesisHash: TestnetTrustedCheckpoint,
    50  }
    51  
    52  var (
    53  	EnergiMainnetChainConfig = &ChainConfig{
    54  		ChainID:             big.NewInt(39797),
    55  		HomesteadBlock:      big.NewInt(0),
    56  		EIP150Block:         big.NewInt(0),
    57  		EIP150Hash:          common.Hash{},
    58  		EIP155Block:         big.NewInt(0),
    59  		EIP158Block:         big.NewInt(0),
    60  		ByzantiumBlock:      big.NewInt(0),
    61  		ConstantinopleBlock: big.NewInt(0),
    62  		PetersburgBlock:     big.NewInt(0),
    63  		Energi: &EnergiConfig{
    64  			BackboneAddress: MainnetBackbone,
    65  			MigrationSigner: MainnetMigrationSigner,
    66  			EBISigner:       MainnetEBISigner,
    67  			CPPSigner:       MainnetCPPSigner,
    68  		},
    69  		SuperblockCycle:     big.NewInt(60 * 24 * 14),
    70  		MNRequireValidation: big.NewInt(10),
    71  		MNValidationPeriod:  big.NewInt(5),
    72  		MNCleanupPeriod:     big.NewInt(60 * 60 * 24 * 14),
    73  		MNEverCollateral:    new(big.Int).Mul(big.NewInt(3000000), big.NewInt(Ether)),
    74  		MNRewardsPerBlock:   big.NewInt(10),
    75  	}
    76  
    77  	EnergiTestnetChainConfig = &ChainConfig{
    78  		ChainID:             big.NewInt(49797),
    79  		HomesteadBlock:      big.NewInt(0),
    80  		EIP150Block:         big.NewInt(0),
    81  		EIP150Hash:          common.Hash{},
    82  		EIP155Block:         big.NewInt(0),
    83  		EIP158Block:         big.NewInt(0),
    84  		ByzantiumBlock:      big.NewInt(0),
    85  		ConstantinopleBlock: big.NewInt(0),
    86  		PetersburgBlock:     big.NewInt(0),
    87  		Energi: &EnergiConfig{
    88  			BackboneAddress: TestnetBackbone,
    89  			MigrationSigner: TestnetMigrationSigner,
    90  			EBISigner:       TestnetEBISigner,
    91  			CPPSigner:       TestnetCPPSigner,
    92  		},
    93  		SuperblockCycle:     big.NewInt(60 * 24),
    94  		MNRequireValidation: big.NewInt(5),
    95  		MNValidationPeriod:  big.NewInt(5),
    96  		MNCleanupPeriod:     big.NewInt(60 * 60 * 3),
    97  		MNEverCollateral:    new(big.Int).Mul(big.NewInt(30000), big.NewInt(Ether)),
    98  		MNRewardsPerBlock:   big.NewInt(10),
    99  	}
   100  
   101  	// MainnetChainConfig is the chain parameters to run a node on the main network.
   102  	MainnetChainConfig = &ChainConfig{
   103  		ChainID:             big.NewInt(39797),
   104  		HomesteadBlock:      big.NewInt(0),
   105  		EIP150Block:         big.NewInt(0),
   106  		EIP150Hash:          common.Hash{},
   107  		EIP155Block:         big.NewInt(0),
   108  		EIP158Block:         big.NewInt(0),
   109  		ByzantiumBlock:      big.NewInt(0),
   110  		ConstantinopleBlock: big.NewInt(0),
   111  		PetersburgBlock:     big.NewInt(0),
   112  		Ethash:              new(EthashConfig),
   113  	}
   114  
   115  	// MainnetTrustedCheckpoint contains the light client trusted checkpoint for the main network.
   116  	MainnetTrustedCheckpoint = &TrustedCheckpoint{
   117  		Name:         "mainnet",
   118  		SectionIndex: 1,
   119  		SectionHead:  common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
   120  		CHTRoot:      common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
   121  		BloomRoot:    common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
   122  	}
   123  
   124  	// TestnetChainConfig contains the chain parameters to run a node on the Ropsten test network.
   125  	TestnetChainConfig = &ChainConfig{
   126  		ChainID:             big.NewInt(49797),
   127  		HomesteadBlock:      big.NewInt(0),
   128  		EIP150Block:         big.NewInt(0),
   129  		EIP150Hash:          common.Hash{},
   130  		EIP155Block:         big.NewInt(0),
   131  		EIP158Block:         big.NewInt(0),
   132  		ByzantiumBlock:      big.NewInt(0),
   133  		ConstantinopleBlock: big.NewInt(0),
   134  		PetersburgBlock:     big.NewInt(0),
   135  		Ethash:              new(EthashConfig),
   136  	}
   137  
   138  	// TestnetTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network.
   139  	TestnetTrustedCheckpoint = &TrustedCheckpoint{
   140  		Name:         "testnet",
   141  		SectionIndex: 1,
   142  		SectionHead:  common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
   143  		CHTRoot:      common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
   144  		BloomRoot:    common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
   145  	}
   146  
   147  	// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
   148  	// and accepted by the Ethereum core developers into the Ethash consensus.
   149  	//
   150  	// This configuration is intentionally not using keyed fields to force anyone
   151  	// adding flags to the config to also have to set these fields.
   152  	AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0)}
   153  
   154  	// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
   155  	// and accepted by the Ethereum core developers into the Clique consensus.
   156  	//
   157  	// This configuration is intentionally not using keyed fields to force anyone
   158  	// adding flags to the config to also have to set these fields.
   159  	AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0)}
   160  
   161  	TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0)}
   162  	TestRules       = TestChainConfig.Rules(new(big.Int))
   163  )
   164  
   165  // TrustedCheckpoint represents a set of post-processed trie roots (CHT and
   166  // BloomTrie) associated with the appropriate section index and head hash. It is
   167  // used to start light syncing from this checkpoint and avoid downloading the
   168  // entire header chain while still being able to securely access old headers/logs.
   169  type TrustedCheckpoint struct {
   170  	Name         string      `json:"-"`
   171  	SectionIndex uint64      `json:"sectionIndex"`
   172  	SectionHead  common.Hash `json:"sectionHead"`
   173  	CHTRoot      common.Hash `json:"chtRoot"`
   174  	BloomRoot    common.Hash `json:"bloomRoot"`
   175  }
   176  
   177  // ChainConfig is the core config which determines the blockchain settings.
   178  //
   179  // ChainConfig is stored in the database on a per block basis. This means
   180  // that any network, identified by its genesis block, can have its own
   181  // set of configuration options.
   182  type ChainConfig struct {
   183  	ChainID *big.Int `json:"chainId"` // chainId identifies the current chain and is used for replay protection
   184  
   185  	HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead)
   186  
   187  	// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
   188  	EIP150Block *big.Int    `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork)
   189  	EIP150Hash  common.Hash `json:"eip150Hash,omitempty"`  // EIP150 HF hash (needed for header only clients as only gas pricing changed)
   190  
   191  	EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block
   192  	EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block
   193  
   194  	ByzantiumBlock      *big.Int `json:"byzantiumBlock,omitempty"`      // Byzantium switch block (nil = no fork, 0 = already on byzantium)
   195  	ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated)
   196  	PetersburgBlock     *big.Int `json:"petersburgBlock,omitempty"`     // Petersburg switch block (nil = same as Constantinople)
   197  	EWASMBlock          *big.Int `json:"ewasmBlock,omitempty"`          // EWASM switch block (nil = no fork, 0 = already activated)
   198  
   199  	// Various consensus engines
   200  	Ethash *EthashConfig `json:"ethash,omitempty"`
   201  	Clique *CliqueConfig `json:"clique,omitempty"`
   202  	Energi *EnergiConfig `json:"energi,omitempty"`
   203  
   204  	// This parameters are not part of hardcoded consensus!
   205  	SuperblockCycle     *big.Int `json:"superblockCycle"`
   206  	MNRequireValidation *big.Int `json:"mnRequireValidation"`
   207  	MNValidationPeriod  *big.Int `json:"mnValidationPeriod"`
   208  	MNCleanupPeriod     *big.Int `json:"mnCleanupPeriod"`
   209  	MNEverCollateral    *big.Int `json:"mnEverCollateral"`
   210  	MNRewardsPerBlock   *big.Int `json:"mnRewardsPerBlock"`
   211  }
   212  
   213  // EthashConfig is the consensus engine configs for proof-of-work based sealing.
   214  type EthashConfig struct{}
   215  
   216  // String implements the stringer interface, returning the consensus engine details.
   217  func (c *EthashConfig) String() string {
   218  	return "ethash"
   219  }
   220  
   221  // CliqueConfig is the consensus engine configs for proof-of-authority based sealing.
   222  type CliqueConfig struct {
   223  	Period uint64 `json:"period"` // Number of seconds between blocks to enforce
   224  	Epoch  uint64 `json:"epoch"`  // Epoch length to reset votes and checkpoint
   225  }
   226  
   227  // String implements the stringer interface, returning the consensus engine details.
   228  func (c *CliqueConfig) String() string {
   229  	return "clique"
   230  }
   231  
   232  // EnergiConfig is the consensus engine config for proof-of-stake based sealing.
   233  type EnergiConfig struct {
   234  	BackboneAddress common.Address `json:"backboneAddress"`
   235  	MigrationSigner common.Address `json:"migrationSigner"`
   236  	EBISigner       common.Address `json:"ebiSigner"`
   237  	CPPSigner       common.Address `json:"cppSigner"`
   238  }
   239  
   240  // String implements the stringer interface, returning the consensus engine details.
   241  func (*EnergiConfig) String() string {
   242  	return "energi"
   243  }
   244  
   245  // String implements the fmt.Stringer interface.
   246  func (c *ChainConfig) String() string {
   247  	var engine interface{}
   248  	switch {
   249  	case c.Energi != nil:
   250  		engine = c.Energi
   251  	case c.Ethash != nil:
   252  		engine = c.Ethash
   253  	case c.Clique != nil:
   254  		engine = c.Clique
   255  	default:
   256  		engine = "unknown"
   257  	}
   258  	return fmt.Sprintf("{ChainID: %v Homestead: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v  ConstantinopleFix: %v Engine: %v}",
   259  		c.ChainID,
   260  		c.HomesteadBlock,
   261  		c.EIP150Block,
   262  		c.EIP155Block,
   263  		c.EIP158Block,
   264  		c.ByzantiumBlock,
   265  		c.ConstantinopleBlock,
   266  		c.PetersburgBlock,
   267  		engine,
   268  	)
   269  }
   270  
   271  // IsHomestead returns whether num is either equal to the homestead block or greater.
   272  func (c *ChainConfig) IsHomestead(num *big.Int) bool {
   273  	return isForked(c.HomesteadBlock, num)
   274  }
   275  
   276  // IsEIP150 returns whether num is either equal to the EIP150 fork block or greater.
   277  func (c *ChainConfig) IsEIP150(num *big.Int) bool {
   278  	return isForked(c.EIP150Block, num)
   279  }
   280  
   281  // IsEIP155 returns whether num is either equal to the EIP155 fork block or greater.
   282  func (c *ChainConfig) IsEIP155(num *big.Int) bool {
   283  	return isForked(c.EIP155Block, num)
   284  }
   285  
   286  // IsEIP158 returns whether num is either equal to the EIP158 fork block or greater.
   287  func (c *ChainConfig) IsEIP158(num *big.Int) bool {
   288  	return isForked(c.EIP158Block, num)
   289  }
   290  
   291  // IsByzantium returns whether num is either equal to the Byzantium fork block or greater.
   292  func (c *ChainConfig) IsByzantium(num *big.Int) bool {
   293  	return isForked(c.ByzantiumBlock, num)
   294  }
   295  
   296  // IsConstantinople returns whether num is either equal to the Constantinople fork block or greater.
   297  func (c *ChainConfig) IsConstantinople(num *big.Int) bool {
   298  	return isForked(c.ConstantinopleBlock, num)
   299  }
   300  
   301  // IsPetersburg returns whether num is either
   302  // - equal to or greater than the PetersburgBlock fork block,
   303  // - OR is nil, and Constantinople is active
   304  func (c *ChainConfig) IsPetersburg(num *big.Int) bool {
   305  	return isForked(c.PetersburgBlock, num) || c.PetersburgBlock == nil && isForked(c.ConstantinopleBlock, num)
   306  }
   307  
   308  // IsEWASM returns whether num represents a block number after the EWASM fork
   309  func (c *ChainConfig) IsEWASM(num *big.Int) bool {
   310  	return isForked(c.EWASMBlock, num)
   311  }
   312  
   313  // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
   314  //
   315  // The returned GasTable's fields shouldn't, under any circumstances, be changed.
   316  func (c *ChainConfig) GasTable(num *big.Int) GasTable {
   317  	if num == nil {
   318  		return GasTableHomestead
   319  	}
   320  	switch {
   321  	case c.IsConstantinople(num):
   322  		return GasTableConstantinople
   323  	case c.IsEIP158(num):
   324  		return GasTableEIP158
   325  	case c.IsEIP150(num):
   326  		return GasTableEIP150
   327  	default:
   328  		return GasTableHomestead
   329  	}
   330  }
   331  
   332  // CheckCompatible checks whether scheduled fork transitions have been imported
   333  // with a mismatching chain configuration.
   334  func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError {
   335  	bhead := new(big.Int).SetUint64(height)
   336  
   337  	// Iterate checkCompatible to find the lowest conflict.
   338  	var lasterr *ConfigCompatError
   339  	for {
   340  		err := c.checkCompatible(newcfg, bhead)
   341  		if err == nil || (lasterr != nil && err.RewindTo == lasterr.RewindTo) {
   342  			break
   343  		}
   344  		lasterr = err
   345  		bhead.SetUint64(err.RewindTo)
   346  	}
   347  	return lasterr
   348  }
   349  
   350  func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError {
   351  	if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
   352  		return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
   353  	}
   354  	if isForkIncompatible(c.EIP150Block, newcfg.EIP150Block, head) {
   355  		return newCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block)
   356  	}
   357  	if isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) {
   358  		return newCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block)
   359  	}
   360  	if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) {
   361  		return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block)
   362  	}
   363  	if c.IsEIP158(head) && !configNumEqual(c.ChainID, newcfg.ChainID) {
   364  		return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block)
   365  	}
   366  	if isForkIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, head) {
   367  		return newCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock)
   368  	}
   369  	if isForkIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) {
   370  		return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock)
   371  	}
   372  	if isForkIncompatible(c.PetersburgBlock, newcfg.PetersburgBlock, head) {
   373  		return newCompatError("ConstantinopleFix fork block", c.PetersburgBlock, newcfg.PetersburgBlock)
   374  	}
   375  	if isForkIncompatible(c.EWASMBlock, newcfg.EWASMBlock, head) {
   376  		return newCompatError("ewasm fork block", c.EWASMBlock, newcfg.EWASMBlock)
   377  	}
   378  	return nil
   379  }
   380  
   381  // isForkIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to
   382  // block s2 because head is already past the fork.
   383  func isForkIncompatible(s1, s2, head *big.Int) bool {
   384  	return (isForked(s1, head) || isForked(s2, head)) && !configNumEqual(s1, s2)
   385  }
   386  
   387  // isForked returns whether a fork scheduled at block s is active at the given head block.
   388  func isForked(s, head *big.Int) bool {
   389  	if s == nil || head == nil {
   390  		return false
   391  	}
   392  	return s.Cmp(head) <= 0
   393  }
   394  
   395  func configNumEqual(x, y *big.Int) bool {
   396  	if x == nil {
   397  		return y == nil
   398  	}
   399  	if y == nil {
   400  		return x == nil
   401  	}
   402  	return x.Cmp(y) == 0
   403  }
   404  
   405  // ConfigCompatError is raised if the locally-stored blockchain is initialised with a
   406  // ChainConfig that would alter the past.
   407  type ConfigCompatError struct {
   408  	What string
   409  	// block numbers of the stored and new configurations
   410  	StoredConfig, NewConfig *big.Int
   411  	// the block number to which the local chain must be rewound to correct the error
   412  	RewindTo uint64
   413  }
   414  
   415  func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError {
   416  	var rew *big.Int
   417  	switch {
   418  	case storedblock == nil:
   419  		rew = newblock
   420  	case newblock == nil || storedblock.Cmp(newblock) < 0:
   421  		rew = storedblock
   422  	default:
   423  		rew = newblock
   424  	}
   425  	err := &ConfigCompatError{what, storedblock, newblock, 0}
   426  	if rew != nil && rew.Sign() > 0 {
   427  		err.RewindTo = rew.Uint64() - 1
   428  	}
   429  	return err
   430  }
   431  
   432  func (err *ConfigCompatError) Error() string {
   433  	return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo)
   434  }
   435  
   436  // Rules wraps ChainConfig and is merely syntactic sugar or can be used for functions
   437  // that do not have or require information about the block.
   438  //
   439  // Rules is a one time interface meaning that it shouldn't be used in between transition
   440  // phases.
   441  type Rules struct {
   442  	ChainID                                     *big.Int
   443  	IsHomestead, IsEIP150, IsEIP155, IsEIP158   bool
   444  	IsByzantium, IsConstantinople, IsPetersburg bool
   445  }
   446  
   447  // Rules ensures c's ChainID is not nil.
   448  func (c *ChainConfig) Rules(num *big.Int) Rules {
   449  	chainID := c.ChainID
   450  	if chainID == nil {
   451  		chainID = new(big.Int)
   452  	}
   453  	return Rules{
   454  		ChainID:          new(big.Int).Set(chainID),
   455  		IsHomestead:      c.IsHomestead(num),
   456  		IsEIP150:         c.IsEIP150(num),
   457  		IsEIP155:         c.IsEIP155(num),
   458  		IsEIP158:         c.IsEIP158(num),
   459  		IsByzantium:      c.IsByzantium(num),
   460  		IsConstantinople: c.IsConstantinople(num),
   461  		IsPetersburg:     c.IsPetersburg(num),
   462  	}
   463  }