diff options
Diffstat (limited to 'params/config.go')
-rw-r--r-- | params/config.go | 259 |
1 files changed, 183 insertions, 76 deletions
diff --git a/params/config.go b/params/config.go index ee993fe4a..c5a2afb5b 100644 --- a/params/config.go +++ b/params/config.go @@ -23,39 +23,45 @@ import ( "github.com/ethereum/go-ethereum/common" ) -// MainnetChainConfig is the chain parameters to run a node on the main network. -var MainnetChainConfig = &ChainConfig{ - ChainId: MainNetChainID, - HomesteadBlock: MainNetHomesteadBlock, - DAOForkBlock: MainNetDAOForkBlock, - DAOForkSupport: true, - EIP150Block: MainNetHomesteadGasRepriceBlock, - EIP150Hash: MainNetHomesteadGasRepriceHash, - EIP155Block: MainNetSpuriousDragon, - EIP158Block: MainNetSpuriousDragon, -} - -// TestnetChainConfig is the chain parameters to run a node on the test network. -var TestnetChainConfig = &ChainConfig{ - ChainId: big.NewInt(3), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), - EIP155Block: big.NewInt(10), - EIP158Block: big.NewInt(10), -} - -// AllProtocolChanges contains every protocol change (EIPs) -// introduced and accepted by the Ethereum core developers. -// -// This configuration is intentionally not using keyed fields. -// This configuration must *always* have all forks enabled, which -// means that all fields must be set at all times. This forces -// anyone adding flags to the config to also have to set these -// fields. -var AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)} +var ( + // MainnetChainConfig is the chain parameters to run a node on the main network. + MainnetChainConfig = &ChainConfig{ + ChainId: MainNetChainID, + HomesteadBlock: MainNetHomesteadBlock, + DAOForkBlock: MainNetDAOForkBlock, + DAOForkSupport: true, + EIP150Block: MainNetHomesteadGasRepriceBlock, + EIP150Hash: MainNetHomesteadGasRepriceHash, + EIP155Block: MainNetSpuriousDragon, + EIP158Block: MainNetSpuriousDragon, + Ethash: new(EthashConfig), + } + + // TestnetChainConfig contains the chain parameters to run a node on the ropsten test network. + TestnetChainConfig = &ChainConfig{ + ChainId: big.NewInt(3), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), + EIP155Block: big.NewInt(10), + EIP158Block: big.NewInt(10), + Ethash: new(EthashConfig), + } + + // AllProtocolChanges contains every protocol change (EIPs) + // introduced and accepted by the Ethereum core developers. + // TestChainConfig is like AllProtocolChanges but has chain ID 1. + // + // This configuration is intentionally not using keyed fields. + // This configuration must *always* have all forks enabled, which + // means that all fields must be set at all times. This forces + // anyone adding flags to the config to also have to set these + // fields. + AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), new(EthashConfig), nil} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), new(EthashConfig), nil} +) // ChainConfig is the core config which determines the blockchain settings. // @@ -65,21 +71,53 @@ var AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, fals type ChainConfig struct { ChainId *big.Int `json:"chainId"` // Chain id identifies the current chain and is used for replay protection - HomesteadBlock *big.Int `json:"homesteadBlock"` // Homestead switch block (nil = no fork, 0 = already homestead) - DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork) - DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork + HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead) + DAOForkBlock *big.Int `json:"daoForkBlock,omitempty"` // TheDAO hard-fork switch block (nil = no fork) + DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) - EIP150Block *big.Int `json:"eip150Block"` // EIP150 HF block (nil = no fork) - EIP150Hash common.Hash `json:"eip150Hash"` // EIP150 HF hash (fast sync aid) + EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) + EIP150Hash common.Hash `json:"eip150Hash,omitempty"` // EIP150 HF hash (fast sync aid) + + EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block + EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block + + // Various consensus engines + Ethash *EthashConfig `json:"ethash,omitempty"` + Clique *CliqueConfig `json:"clique,omitempty"` +} + +// EthashConfig is the consensus engine configs for proof-of-work based sealing. +type EthashConfig struct{} + +// String implements the stringer interface, returning the consensus engine details. +func (c *EthashConfig) String() string { + return "ethash" +} + +// CliqueConfig is the consensus engine configs for proof-of-authority based sealing. +type CliqueConfig struct { + Period uint64 `json:"period"` // Number of seconds between blocks to enforce + Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint +} - EIP155Block *big.Int `json:"eip155Block"` // EIP155 HF block - EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block +// String implements the stringer interface, returning the consensus engine details. +func (c *CliqueConfig) String() string { + return "clique" } -// String implements the Stringer interface. +// String implements the fmt.Stringer interface. func (c *ChainConfig) String() string { - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v}", + var engine interface{} + switch { + case c.Ethash != nil: + engine = c.Ethash + case c.Clique != nil: + engine = c.Clique + default: + engine = "unknown" + } + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Engine: %v}", c.ChainId, c.HomesteadBlock, c.DAOForkBlock, @@ -87,20 +125,30 @@ func (c *ChainConfig) String() string { c.EIP150Block, c.EIP155Block, c.EIP158Block, + engine, ) } -var ( - TestChainConfig = &ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int), new(big.Int)} - TestRules = TestChainConfig.Rules(new(big.Int)) -) - // IsHomestead returns whether num is either equal to the homestead block or greater. func (c *ChainConfig) IsHomestead(num *big.Int) bool { - if c.HomesteadBlock == nil || num == nil { - return false - } - return num.Cmp(c.HomesteadBlock) >= 0 + return isForked(c.HomesteadBlock, num) +} + +// IsDAO returns whether num is either equal to the DAO fork block or greater. +func (c *ChainConfig) IsDAOFork(num *big.Int) bool { + return isForked(c.DAOForkBlock, num) +} + +func (c *ChainConfig) IsEIP150(num *big.Int) bool { + return isForked(c.EIP150Block, num) +} + +func (c *ChainConfig) IsEIP155(num *big.Int) bool { + return isForked(c.EIP155Block, num) +} + +func (c *ChainConfig) IsEIP158(num *big.Int) bool { + return isForked(c.EIP158Block, num) } // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice). @@ -110,51 +158,110 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable { if num == nil { return GasTableHomestead } - switch { - case c.EIP158Block != nil && num.Cmp(c.EIP158Block) >= 0: + case c.IsEIP158(num): return GasTableEIP158 - case c.EIP150Block != nil && num.Cmp(c.EIP150Block) >= 0: + case c.IsEIP150(num): return GasTableHomesteadGasRepriceFork default: return GasTableHomestead } } -func (c *ChainConfig) IsEIP150(num *big.Int) bool { - if c.EIP150Block == nil || num == nil { - return false - } - return num.Cmp(c.EIP150Block) >= 0 +// CheckCompatible checks whether scheduled fork transitions have been imported +// with a mismatching chain configuration. +func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError { + bhead := new(big.Int).SetUint64(height) + // Iterate checkCompatible to find the lowest conflict. + var lasterr *ConfigCompatError + for { + err := c.checkCompatible(newcfg, bhead) + if err == nil || (lasterr != nil && err.RewindTo == lasterr.RewindTo) { + break + } + lasterr = err + bhead.SetUint64(err.RewindTo) + } + return lasterr } -func (c *ChainConfig) IsEIP155(num *big.Int) bool { - if c.EIP155Block == nil || num == nil { - return false +func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError { + if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) { + return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock) + } + if isForkIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, head) { + return newCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock) + } + if c.IsDAOFork(head) && c.DAOForkSupport != newcfg.DAOForkSupport { + return newCompatError("DAO fork support flag", c.DAOForkBlock, newcfg.DAOForkBlock) + } + if isForkIncompatible(c.EIP150Block, newcfg.EIP150Block, head) { + return newCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block) + } + if isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) { + return newCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block) } - return num.Cmp(c.EIP155Block) >= 0 + if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) { + return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block) + } + if c.IsEIP158(head) && !configNumEqual(c.ChainId, newcfg.ChainId) { + return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block) + } + return nil +} +// isForkIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to +// block s2 because head is already past the fork. +func isForkIncompatible(s1, s2, head *big.Int) bool { + return (isForked(s1, head) || isForked(s2, head)) && !configNumEqual(s1, s2) } -func (c *ChainConfig) IsEIP158(num *big.Int) bool { - if c.EIP158Block == nil || num == nil { +// isForked returns whether a fork scheduled at block s is active at the given head block. +func isForked(s, head *big.Int) bool { + if s == nil || head == nil { return false } - return num.Cmp(c.EIP158Block) >= 0 + return s.Cmp(head) <= 0 +} + +func configNumEqual(x, y *big.Int) bool { + if x == nil { + return y == nil + } + if y == nil { + return x == nil + } + return x.Cmp(y) == 0 +} +// ConfigCompatError is raised if the locally-stored blockchain is initialised with a +// ChainConfig that would alter the past. +type ConfigCompatError struct { + What string + // block numbers of the stored and new configurations + StoredConfig, NewConfig *big.Int + // the block number to which the local chain must be rewound to correct the error + RewindTo uint64 } -// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions -// that do not have or require information about the block. -// -// Rules is a one time interface meaning that it shouldn't be used in between transition -// phases. -type Rules struct { - ChainId *big.Int - IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool +func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError { + var rew *big.Int + switch { + case storedblock == nil: + rew = newblock + case newblock == nil || storedblock.Cmp(newblock) < 0: + rew = storedblock + default: + rew = newblock + } + err := &ConfigCompatError{what, storedblock, newblock, 0} + if rew != nil && rew.Sign() > 0 { + err.RewindTo = rew.Uint64() - 1 + } + return err } -func (c *ChainConfig) Rules(num *big.Int) Rules { - return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num)} +func (err *ConfigCompatError) Error() string { + return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo) } |