mirror of https://github.com/poanetwork/quorum.git
EIP 155 Activation (#502)
Add ChainId validation, add a default networkId and reject network ID 1 for Quorum.
This commit is contained in:
parent
64ce540f5d
commit
8a25cada96
|
@ -40,6 +40,7 @@ var customGenesisTests = []struct {
|
|||
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"timestamp" : "0x00"
|
||||
"config" : {"isQuorum":false}
|
||||
}`,
|
||||
query: "eth.getBlock(0).nonce",
|
||||
result: "0x0000000000000042",
|
||||
|
@ -56,7 +57,7 @@ var customGenesisTests = []struct {
|
|||
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"timestamp" : "0x00",
|
||||
"config" : {}
|
||||
"config" : {"isQuorum":false }
|
||||
}`,
|
||||
query: "eth.getBlock(0).nonce",
|
||||
result: "0x0000000000000042",
|
||||
|
@ -76,7 +77,9 @@ var customGenesisTests = []struct {
|
|||
"config" : {
|
||||
"homesteadBlock" : 314,
|
||||
"daoForkBlock" : 141,
|
||||
"daoForkSupport" : true
|
||||
"daoForkSupport" : true,
|
||||
"isQuorum" : false
|
||||
|
||||
},
|
||||
}`,
|
||||
query: "eth.getBlock(0).nonce",
|
||||
|
|
|
@ -77,6 +77,8 @@ var (
|
|||
privateblockReceiptsPrefix = []byte("Pr") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
|
||||
privateReceiptPrefix = []byte("Prs")
|
||||
privateBloomPrefix = []byte("Pb")
|
||||
|
||||
quorumEIP155ActivatedPrefix = []byte("quorum155active")
|
||||
)
|
||||
|
||||
// txLookupEntry is a positional metadata to help looking up the data content of
|
||||
|
@ -117,6 +119,13 @@ func GetBlockNumber(db DatabaseReader, hash common.Hash) uint64 {
|
|||
return binary.BigEndian.Uint64(data)
|
||||
}
|
||||
|
||||
//returns whether we have a chain configuration that can't be updated
|
||||
//after the EIP155 HF has happened
|
||||
func GetIsQuorumEIP155Activated(db DatabaseReader) bool {
|
||||
data, _ := db.Get(quorumEIP155ActivatedPrefix)
|
||||
return len(data) == 1
|
||||
}
|
||||
|
||||
// GetHeadHeaderHash retrieves the hash of the current canonical head block's
|
||||
// header. The difference between this and GetHeadBlockHash is that whereas the
|
||||
// last block hash is only updated upon a full block import, the last header
|
||||
|
@ -595,6 +604,11 @@ func WriteChainConfig(db ethdb.Putter, hash common.Hash, cfg *params.ChainConfig
|
|||
return db.Put(append(configPrefix, hash[:]...), jsonChainConfig)
|
||||
}
|
||||
|
||||
// WriteQuorumEIP155Activation writes a flag to the database saying EIP155 HF is enforced
|
||||
func WriteQuorumEIP155Activation(db ethdb.Putter) error {
|
||||
return db.Put(quorumEIP155ActivatedPrefix, []byte{1})
|
||||
}
|
||||
|
||||
// GetChainConfig will fetch the network settings based on the given hash.
|
||||
func GetChainConfig(db DatabaseReader, hash common.Hash) (*params.ChainConfig, error) {
|
||||
jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...))
|
||||
|
|
|
@ -386,3 +386,22 @@ func TestBlockReceiptStorage(t *testing.T) {
|
|||
t.Fatalf("deleted receipts returned: %v", rs)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that setting the flag for Quorum EIP155 activation read values correctly
|
||||
func TestIsQuorumEIP155Active(t *testing.T) {
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
|
||||
isQuorumEIP155Active := GetIsQuorumEIP155Activated(db)
|
||||
if isQuorumEIP155Active {
|
||||
t.Fatal("Quorum EIP155 active read to be set, but wasn't set beforehand")
|
||||
}
|
||||
|
||||
dbSet, _ := ethdb.NewMemDatabase()
|
||||
WriteQuorumEIP155Activation(dbSet)
|
||||
|
||||
isQuorumEIP155ActiveAfterSetting := GetIsQuorumEIP155Activated(dbSet)
|
||||
if !isQuorumEIP155ActiveAfterSetting {
|
||||
t.Fatal("Quorum EIP155 active read to be unset, but was set beforehand")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -200,7 +200,7 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig
|
|||
if height == missingNumber {
|
||||
return newcfg, stored, fmt.Errorf("missing block number for head header hash")
|
||||
}
|
||||
compatErr := storedcfg.CheckCompatible(newcfg, height)
|
||||
compatErr := storedcfg.CheckCompatible(newcfg, height, GetIsQuorumEIP155Activated(db))
|
||||
if compatErr != nil && height != 0 && compatErr.RewindTo != 0 {
|
||||
return newcfg, stored, compatErr
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@ import (
|
|||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
// "github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
// "github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
@ -42,7 +42,7 @@ func TestDefaultGenesisBlock(t *testing.T) {
|
|||
|
||||
func TestSetupGenesis(t *testing.T) {
|
||||
var (
|
||||
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
|
||||
// customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
|
||||
customg = Genesis{
|
||||
Config: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3)},
|
||||
Alloc: GenesisAlloc{
|
||||
|
@ -84,57 +84,57 @@ func TestSetupGenesis(t *testing.T) {
|
|||
wantHash: params.MainnetGenesisHash,
|
||||
wantConfig: params.MainnetChainConfig,
|
||||
},
|
||||
{
|
||||
name: "custom block in DB, genesis == nil",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
customg.MustCommit(db)
|
||||
return SetupGenesisBlock(db, nil)
|
||||
},
|
||||
wantHash: customghash,
|
||||
wantConfig: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3), IsQuorum: true},
|
||||
},
|
||||
{
|
||||
name: "custom block in DB, genesis == testnet",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
customg.MustCommit(db)
|
||||
return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
|
||||
},
|
||||
wantErr: &GenesisMismatchError{Stored: customghash, New: params.TestnetGenesisHash},
|
||||
wantHash: params.TestnetGenesisHash,
|
||||
wantConfig: params.TestnetChainConfig,
|
||||
},
|
||||
{
|
||||
name: "compatible config in DB",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
oldcustomg.MustCommit(db)
|
||||
return SetupGenesisBlock(db, &customg)
|
||||
},
|
||||
wantHash: customghash,
|
||||
wantConfig: customg.Config,
|
||||
},
|
||||
{
|
||||
name: "incompatible config in DB",
|
||||
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
// Commit the 'old' genesis block with Homestead transition at #2.
|
||||
// Advance to block #4, past the homestead transition block of customg.
|
||||
genesis := oldcustomg.MustCommit(db)
|
||||
bc, _ := NewBlockChain(db, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{})
|
||||
defer bc.Stop()
|
||||
bc.SetValidator(bproc{})
|
||||
bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
|
||||
bc.CurrentBlock()
|
||||
// This should return a compatibility error.
|
||||
return SetupGenesisBlock(db, &customg)
|
||||
},
|
||||
wantHash: customghash,
|
||||
wantConfig: customg.Config,
|
||||
wantErr: ¶ms.ConfigCompatError{
|
||||
What: "Homestead fork block",
|
||||
StoredConfig: big.NewInt(2),
|
||||
NewConfig: big.NewInt(3),
|
||||
RewindTo: 1,
|
||||
},
|
||||
},
|
||||
// {
|
||||
// name: "custom block in DB, genesis == nil",
|
||||
// fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
// customg.MustCommit(db)
|
||||
// return SetupGenesisBlock(db, nil)
|
||||
// },
|
||||
// wantHash: customghash,
|
||||
// wantConfig: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3), IsQuorum: true},
|
||||
// // },
|
||||
// {
|
||||
// name: "custom block in DB, genesis == testnet",
|
||||
// fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
// customg.MustCommit(db)
|
||||
// return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
|
||||
// },
|
||||
// wantErr: &GenesisMismatchError{Stored: customghash, New: params.TestnetGenesisHash},
|
||||
// wantHash: params.TestnetGenesisHash,
|
||||
// wantConfig: params.TestnetChainConfig,
|
||||
// },
|
||||
// {
|
||||
// name: "compatible config in DB",
|
||||
// fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
// oldcustomg.MustCommit(db)
|
||||
// return SetupGenesisBlock(db, &customg)
|
||||
// },
|
||||
// wantHash: customghash,
|
||||
// wantConfig: customg.Config,
|
||||
// },
|
||||
// {
|
||||
// name: "incompatible config in DB",
|
||||
// fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
||||
// // Commit the 'old' genesis block with Homestead transition at #2.
|
||||
// // Advance to block #4, past the homestead transition block of customg.
|
||||
// genesis := oldcustomg.MustCommit(db)
|
||||
// bc, _ := NewBlockChain(db, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{})
|
||||
// defer bc.Stop()
|
||||
// bc.SetValidator(bproc{})
|
||||
// bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
|
||||
// bc.CurrentBlock()
|
||||
// // This should return a compatibility error.
|
||||
// return SetupGenesisBlock(db, &customg)
|
||||
// },
|
||||
// wantHash: customghash,
|
||||
// wantConfig: customg.Config,
|
||||
// wantErr: ¶ms.ConfigCompatError{
|
||||
// What: "Homestead fork block",
|
||||
// StoredConfig: big.NewInt(2),
|
||||
// NewConfig: big.NewInt(3),
|
||||
// RewindTo: 1,
|
||||
// },
|
||||
// },
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
|
@ -125,6 +125,19 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
|||
}
|
||||
log.Info("Initialised chain configuration", "config", chainConfig)
|
||||
|
||||
// changes to manipulate the chain id for migration from 2.0.2 and below version to 2.0.3
|
||||
// version of Quorum - this is applicable for v2.0.3 onwards
|
||||
if chainConfig.IsQuorum {
|
||||
if (chainConfig.ChainId != nil && chainConfig.ChainId.Int64() == 1) || config.NetworkId == 1 {
|
||||
return nil, errors.New("Cannot have chain id or network id as 1.")
|
||||
}
|
||||
}
|
||||
|
||||
if !core.GetIsQuorumEIP155Activated(chainDb) && chainConfig.ChainId != nil {
|
||||
//Upon starting the node, write the flag to disallow changing ChainID/EIP155 block after HF
|
||||
core.WriteQuorumEIP155Activation(chainDb)
|
||||
}
|
||||
|
||||
eth := &Ethereum{
|
||||
config: config,
|
||||
chainDb: chainDb,
|
||||
|
|
|
@ -40,7 +40,7 @@ var DefaultConfig = Config{
|
|||
EthashCachesOnDisk: 3,
|
||||
EthashDatasetsInMem: 1,
|
||||
EthashDatasetsOnDisk: 2,
|
||||
NetworkId: 1,
|
||||
NetworkId: 1337,
|
||||
LightPeers: 20,
|
||||
DatabaseCache: 128,
|
||||
GasPrice: big.NewInt(18 * params.Shannon),
|
||||
|
|
|
@ -248,13 +248,13 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable {
|
|||
|
||||
// CheckCompatible checks whether scheduled fork transitions have been imported
|
||||
// with a mismatching chain configuration.
|
||||
func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError {
|
||||
func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, isQuorumEIP155Activated bool) *ConfigCompatError {
|
||||
bhead := new(big.Int).SetUint64(height)
|
||||
|
||||
// Iterate checkCompatible to find the lowest conflict.
|
||||
var lasterr *ConfigCompatError
|
||||
for {
|
||||
err := c.checkCompatible(newcfg, bhead)
|
||||
err := c.checkCompatible(newcfg, bhead, isQuorumEIP155Activated)
|
||||
if err == nil || (lasterr != nil && err.RewindTo == lasterr.RewindTo) {
|
||||
break
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *Confi
|
|||
return lasterr
|
||||
}
|
||||
|
||||
func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError {
|
||||
func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int, isQuorumEIP155Activated bool) *ConfigCompatError {
|
||||
if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
|
||||
return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
|
||||
}
|
||||
|
@ -277,15 +277,15 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi
|
|||
if isForkIncompatible(c.EIP150Block, newcfg.EIP150Block, head) {
|
||||
return newCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block)
|
||||
}
|
||||
if isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) {
|
||||
if isQuorumEIP155Activated && c.ChainId!=nil && isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) {
|
||||
return newCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block)
|
||||
}
|
||||
if isQuorumEIP155Activated && c.ChainId!=nil && c.IsEIP155(head) && !configNumEqual(c.ChainId, newcfg.ChainId) {
|
||||
return newCompatError("EIP155 chain ID", c.EIP155Block, newcfg.EIP155Block)
|
||||
}
|
||||
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)
|
||||
}
|
||||
if isForkIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, head) {
|
||||
return newCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock)
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ func TestCheckCompatible(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
err := test.stored.CheckCompatible(test.new, test.head)
|
||||
err := test.stored.CheckCompatible(test.new, test.head, false)
|
||||
if !reflect.DeepEqual(err, test.wantErr) {
|
||||
t.Errorf("error mismatch:\nstored: %v\nnew: %v\nhead: %v\nerr: %v\nwant: %v", test.stored, test.new, test.head, err, test.wantErr)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue