params: check fork ordering when initializing new genesis, fixes #20136 (#20169)

prevent users from misconfiguring their nodes so that fork ordering is not preserved.
This commit is contained in:
Martin Holst Swende 2019-10-16 13:23:14 +02:00 committed by GitHub
parent 028af3457d
commit c476460cb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 7 deletions

View File

@ -1318,7 +1318,7 @@ func TestEIP155Transition(t *testing.T) {
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
deleteAddr = common.Address{1} deleteAddr = common.Address{1}
gspec = &Genesis{ gspec = &Genesis{
Config: &params.ChainConfig{ChainID: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}, Config: &params.ChainConfig{ChainID: big.NewInt(1), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}},
} }
genesis = gspec.MustCommit(db) genesis = gspec.MustCommit(db)
@ -1389,7 +1389,7 @@ func TestEIP155Transition(t *testing.T) {
} }
// generate an invalid chain id transaction // generate an invalid chain id transaction
config := &params.ChainConfig{ChainID: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)} config := &params.ChainConfig{ChainID: big.NewInt(2), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
var ( var (
tx *types.Transaction tx *types.Transaction
@ -1425,6 +1425,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
ChainID: big.NewInt(1), ChainID: big.NewInt(1),
HomesteadBlock: new(big.Int), HomesteadBlock: new(big.Int),
EIP155Block: new(big.Int), EIP155Block: new(big.Int),
EIP150Block: new(big.Int),
EIP158Block: big.NewInt(2), EIP158Block: big.NewInt(2),
}, },
Alloc: GenesisAlloc{address: {Balance: funds}}, Alloc: GenesisAlloc{address: {Balance: funds}},

View File

@ -207,6 +207,9 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override
if overrideIstanbul != nil { if overrideIstanbul != nil {
newcfg.IstanbulBlock = overrideIstanbul newcfg.IstanbulBlock = overrideIstanbul
} }
if err := newcfg.CheckConfigForkOrder(); err != nil {
return newcfg, common.Hash{}, err
}
storedcfg := rawdb.ReadChainConfig(db, stored) storedcfg := rawdb.ReadChainConfig(db, stored)
if storedcfg == nil { if storedcfg == nil {
log.Warn("Found genesis block without chain config") log.Warn("Found genesis block without chain config")
@ -295,6 +298,13 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
if block.Number().Sign() != 0 { if block.Number().Sign() != 0 {
return nil, fmt.Errorf("can't commit genesis block with number > 0") return nil, fmt.Errorf("can't commit genesis block with number > 0")
} }
config := g.Config
if config == nil {
config = params.AllEthashProtocolChanges
}
if err := config.CheckConfigForkOrder(); err != nil {
return nil, err
}
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty) rawdb.WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty)
rawdb.WriteBlock(db, block) rawdb.WriteBlock(db, block)
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil) rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
@ -302,11 +312,6 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
rawdb.WriteHeadBlockHash(db, block.Hash()) rawdb.WriteHeadBlockHash(db, block.Hash())
rawdb.WriteHeadFastBlockHash(db, block.Hash()) rawdb.WriteHeadFastBlockHash(db, block.Hash())
rawdb.WriteHeadHeaderHash(db, block.Hash()) rawdb.WriteHeadHeaderHash(db, block.Hash())
config := g.Config
if config == nil {
config = params.AllEthashProtocolChanges
}
rawdb.WriteChainConfig(db, block.Hash(), config) rawdb.WriteChainConfig(db, block.Hash(), config)
return block, nil return block, nil
} }

View File

@ -415,6 +415,42 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *Confi
return lasterr return lasterr
} }
// CheckConfigForkOrder checks that we don't "skip" any forks, geth isn't pluggable enough
// to guarantee that forks
func (c *ChainConfig) CheckConfigForkOrder() error {
type fork struct {
name string
block *big.Int
}
var lastFork fork
for _, cur := range []fork{
{"homesteadBlock", c.HomesteadBlock},
{"eip150Block", c.EIP150Block},
{"eip155Block", c.EIP155Block},
{"eip158Block", c.EIP158Block},
{"byzantiumBlock", c.ByzantiumBlock},
{"constantinopleBlock", c.ConstantinopleBlock},
{"petersburgBlock", c.PetersburgBlock},
{"istanbulBlock", c.IstanbulBlock},
} {
if lastFork.name != "" {
// Next one must be higher number
if lastFork.block == nil && cur.block != nil {
return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at %v",
lastFork.name, cur.name, cur.block)
}
if lastFork.block != nil && cur.block != nil {
if lastFork.block.Cmp(cur.block) > 0 {
return fmt.Errorf("unsupported fork ordering: %v enabled at %v, but %v enabled at %v",
lastFork.name, lastFork.block, cur.name, cur.block)
}
}
}
lastFork = cur
}
return nil
}
func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError { func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError {
if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) { if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock) return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)