cmd, consensus, core, miner: instatx clique for --dev (#15323)

* cmd, consensus, core, miner: instatx clique for --dev

* cmd, consensus, clique: support configurable --dev block times

* cmd, core: allow --dev to use persistent storage too
This commit is contained in:
Péter Szilágyi 2017-10-24 13:40:42 +03:00 committed by GitHub
parent ea5f2da39a
commit 6d6a5a9337
16 changed files with 115 additions and 58 deletions

@ -59,7 +59,7 @@ type SimulatedBackend struct {
// for testing purposes. // for testing purposes.
func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend { func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
database, _ := ethdb.NewMemDatabase() database, _ := ethdb.NewMemDatabase()
genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc} genesis := core.Genesis{Config: params.AllEthashProtocolChanges, Alloc: alloc}
genesis.MustCommit(database) genesis.MustCommit(database)
blockchain, _ := core.NewBlockChain(database, genesis.Config, ethash.NewFaker(), vm.Config{}) blockchain, _ := core.NewBlockChain(database, genesis.Config, ethash.NewFaker(), vm.Config{})
backend := &SimulatedBackend{database: database, blockchain: blockchain, config: genesis.Config} backend := &SimulatedBackend{database: database, blockchain: blockchain, config: genesis.Config}

@ -134,7 +134,7 @@ Fatal: could not decrypt key with given passphrase
func TestUnlockFlag(t *testing.T) { func TestUnlockFlag(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, geth := runGeth(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--dev", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"js", "testdata/empty.js") "js", "testdata/empty.js")
geth.Expect(` geth.Expect(`
@ -158,7 +158,7 @@ Passphrase: {{.InputLine "foobar"}}
func TestUnlockFlagWrongPassword(t *testing.T) { func TestUnlockFlagWrongPassword(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, geth := runGeth(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--dev", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a") "--unlock", "f466859ead1932d743d622cb74fc058882e8648a")
defer geth.ExpectExit() defer geth.ExpectExit()
geth.Expect(` geth.Expect(`
@ -177,7 +177,7 @@ Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could
func TestUnlockFlagMultiIndex(t *testing.T) { func TestUnlockFlagMultiIndex(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, geth := runGeth(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--dev", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "0,2", "--unlock", "0,2",
"js", "testdata/empty.js") "js", "testdata/empty.js")
geth.Expect(` geth.Expect(`
@ -204,7 +204,7 @@ Passphrase: {{.InputLine "foobar"}}
func TestUnlockFlagPasswordFile(t *testing.T) { func TestUnlockFlagPasswordFile(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, geth := runGeth(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--dev", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--password", "testdata/passwords.txt", "--unlock", "0,2", "--password", "testdata/passwords.txt", "--unlock", "0,2",
"js", "testdata/empty.js") "js", "testdata/empty.js")
geth.ExpectExit() geth.ExpectExit()
@ -224,7 +224,7 @@ func TestUnlockFlagPasswordFile(t *testing.T) {
func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) { func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) {
datadir := tmpDatadirWithKeystore(t) datadir := tmpDatadirWithKeystore(t)
geth := runGeth(t, geth := runGeth(t,
"--datadir", datadir, "--nat", "none", "--nodiscover", "--dev", "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--password", "testdata/wrong-passwords.txt", "--unlock", "0,2") "--password", "testdata/wrong-passwords.txt", "--unlock", "0,2")
defer geth.ExpectExit() defer geth.ExpectExit()
geth.Expect(` geth.Expect(`
@ -235,7 +235,7 @@ Fatal: Failed to unlock account 0 (could not decrypt key with given passphrase)
func TestUnlockFlagAmbiguous(t *testing.T) { func TestUnlockFlagAmbiguous(t *testing.T) {
store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes") store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes")
geth := runGeth(t, geth := runGeth(t,
"--keystore", store, "--nat", "none", "--nodiscover", "--dev", "--keystore", store, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a", "--unlock", "f466859ead1932d743d622cb74fc058882e8648a",
"js", "testdata/empty.js") "js", "testdata/empty.js")
defer geth.ExpectExit() defer geth.ExpectExit()
@ -273,7 +273,7 @@ In order to avoid this warning, you need to remove the following duplicate key f
func TestUnlockFlagAmbiguousWrongPassword(t *testing.T) { func TestUnlockFlagAmbiguousWrongPassword(t *testing.T) {
store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes") store := filepath.Join("..", "..", "accounts", "keystore", "testdata", "dupes")
geth := runGeth(t, geth := runGeth(t,
"--keystore", store, "--nat", "none", "--nodiscover", "--dev", "--keystore", store, "--nat", "none", "--nodiscover", "--maxpeers", "0", "--port", "0",
"--unlock", "f466859ead1932d743d622cb74fc058882e8648a") "--unlock", "f466859ead1932d743d622cb74fc058882e8648a")
defer geth.ExpectExit() defer geth.ExpectExit()

@ -155,7 +155,7 @@ func makeFullNode(ctx *cli.Context) *node.Node {
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode // Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
shhEnabled := enableWhisper(ctx) shhEnabled := enableWhisper(ctx)
shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DevModeFlag.Name) shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DeveloperFlag.Name)
if shhEnabled || shhAutoEnabled { if shhEnabled || shhAutoEnabled {
if ctx.GlobalIsSet(utils.WhisperMaxMessageSizeFlag.Name) { if ctx.GlobalIsSet(utils.WhisperMaxMessageSizeFlag.Name) {
cfg.Shh.MaxMessageSize = uint32(ctx.Int(utils.WhisperMaxMessageSizeFlag.Name)) cfg.Shh.MaxMessageSize = uint32(ctx.Int(utils.WhisperMaxMessageSizeFlag.Name))

@ -99,7 +99,8 @@ var (
utils.NetrestrictFlag, utils.NetrestrictFlag,
utils.NodeKeyFileFlag, utils.NodeKeyFileFlag,
utils.NodeKeyHexFlag, utils.NodeKeyHexFlag,
utils.DevModeFlag, utils.DeveloperFlag,
utils.DeveloperPeriodFlag,
utils.TestnetFlag, utils.TestnetFlag,
utils.RinkebyFlag, utils.RinkebyFlag,
utils.VMEnableDebugFlag, utils.VMEnableDebugFlag,
@ -270,7 +271,7 @@ func startNode(ctx *cli.Context, stack *node.Node) {
} }
}() }()
// Start auxiliary services if enabled // Start auxiliary services if enabled
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
// Mining only makes sense if a full Ethereum node is running // Mining only makes sense if a full Ethereum node is running
var ethereum *eth.Ethereum var ethereum *eth.Ethereum
if err := stack.Service(&ethereum); err != nil { if err := stack.Service(&ethereum); err != nil {

@ -72,7 +72,6 @@ var AppHelpFlagGroups = []flagGroup{
utils.NetworkIdFlag, utils.NetworkIdFlag,
utils.TestnetFlag, utils.TestnetFlag,
utils.RinkebyFlag, utils.RinkebyFlag,
utils.DevModeFlag,
utils.SyncModeFlag, utils.SyncModeFlag,
utils.EthStatsURLFlag, utils.EthStatsURLFlag,
utils.IdentityFlag, utils.IdentityFlag,
@ -81,6 +80,12 @@ var AppHelpFlagGroups = []flagGroup{
utils.LightKDFFlag, utils.LightKDFFlag,
}, },
}, },
{Name: "DEVELOPER CHAIN",
Flags: []cli.Flag{
utils.DeveloperFlag,
utils.DeveloperPeriodFlag,
},
},
{ {
Name: "ETHASH", Name: "ETHASH",
Flags: []cli.Flag{ Flags: []cli.Flag{

@ -137,9 +137,13 @@ var (
Name: "rinkeby", Name: "rinkeby",
Usage: "Rinkeby network: pre-configured proof-of-authority test network", Usage: "Rinkeby network: pre-configured proof-of-authority test network",
} }
DevModeFlag = cli.BoolFlag{ DeveloperFlag = cli.BoolFlag{
Name: "dev", Name: "dev",
Usage: "Developer mode: pre-configured private network with several debugging flags", Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
}
DeveloperPeriodFlag = cli.IntFlag{
Name: "dev.period",
Usage: "Block period to use in developer mode (0 = mine only if transaction pending)",
} }
IdentityFlag = cli.StringFlag{ IdentityFlag = cli.StringFlag{
Name: "identity", Name: "identity",
@ -796,7 +800,7 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
cfg.NetRestrict = list cfg.NetRestrict = list
} }
if ctx.GlobalBool(DevModeFlag.Name) { if ctx.GlobalBool(DeveloperFlag.Name) {
// --dev mode can't use p2p networking. // --dev mode can't use p2p networking.
cfg.MaxPeers = 0 cfg.MaxPeers = 0
cfg.ListenAddr = ":0" cfg.ListenAddr = ":0"
@ -817,8 +821,8 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
switch { switch {
case ctx.GlobalIsSet(DataDirFlag.Name): case ctx.GlobalIsSet(DataDirFlag.Name):
cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) cfg.DataDir = ctx.GlobalString(DataDirFlag.Name)
case ctx.GlobalBool(DevModeFlag.Name): case ctx.GlobalBool(DeveloperFlag.Name):
cfg.DataDir = filepath.Join(os.TempDir(), "ethereum_dev_mode") cfg.DataDir = "" // unless explicitly requested, use memory databases
case ctx.GlobalBool(TestnetFlag.Name): case ctx.GlobalBool(TestnetFlag.Name):
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet") cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet")
case ctx.GlobalBool(RinkebyFlag.Name): case ctx.GlobalBool(RinkebyFlag.Name):
@ -924,7 +928,7 @@ func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
// SetEthConfig applies eth-related command line flags to the config. // SetEthConfig applies eth-related command line flags to the config.
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
// Avoid conflicting network flags // Avoid conflicting network flags
checkExclusive(ctx, DevModeFlag, TestnetFlag, RinkebyFlag) checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag)
checkExclusive(ctx, FastSyncFlag, LightModeFlag, SyncModeFlag) checkExclusive(ctx, FastSyncFlag, LightModeFlag, SyncModeFlag)
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
@ -985,14 +989,30 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
cfg.NetworkId = 4 cfg.NetworkId = 4
} }
cfg.Genesis = core.DefaultRinkebyGenesisBlock() cfg.Genesis = core.DefaultRinkebyGenesisBlock()
case ctx.GlobalBool(DevModeFlag.Name): case ctx.GlobalBool(DeveloperFlag.Name):
cfg.Genesis = core.DevGenesisBlock() // Create new developer account or reuse existing one
if !ctx.GlobalIsSet(GasPriceFlag.Name) { var (
cfg.GasPrice = new(big.Int) developer accounts.Account
err error
)
if accs := ks.Accounts(); len(accs) > 0 {
developer = ks.Accounts()[0]
} else {
developer, err = ks.NewAccount("")
if err != nil {
Fatalf("Failed to create developer account: %v", err)
}
} }
cfg.PowTest = true if err := ks.Unlock(developer, ""); err != nil {
} Fatalf("Failed to unlock developer account: %v", err)
}
log.Info("Using developer account", "address", developer.Address)
cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address)
if !ctx.GlobalIsSet(GasPriceFlag.Name) {
cfg.GasPrice = big.NewInt(1)
}
}
// TODO(fjl): move trie cache generations into config // TODO(fjl): move trie cache generations into config
if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 { if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 {
state.MaxTrieCacheGen = uint16(gen) state.MaxTrieCacheGen = uint16(gen)
@ -1077,8 +1097,8 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
genesis = core.DefaultTestnetGenesisBlock() genesis = core.DefaultTestnetGenesisBlock()
case ctx.GlobalBool(RinkebyFlag.Name): case ctx.GlobalBool(RinkebyFlag.Name):
genesis = core.DefaultRinkebyGenesisBlock() genesis = core.DefaultRinkebyGenesisBlock()
case ctx.GlobalBool(DevModeFlag.Name): case ctx.GlobalBool(DeveloperFlag.Name):
genesis = core.DevGenesisBlock() Fatalf("Developer chains are ephemeral")
} }
return genesis return genesis
} }

@ -125,6 +125,11 @@ var (
// errUnauthorized is returned if a header is signed by a non-authorized entity. // errUnauthorized is returned if a header is signed by a non-authorized entity.
errUnauthorized = errors.New("unauthorized") errUnauthorized = errors.New("unauthorized")
// errWaitTransactions is returned if an empty block is attempted to be sealed
// on an instant chain (0 second period). It's important to refuse these as the
// block reward is zero, so an empty block just bloats the chain... fast.
errWaitTransactions = errors.New("waiting for transactions")
) )
// SignerFn is a signer callback function to request a hash to be signed by a // SignerFn is a signer callback function to request a hash to be signed by a
@ -211,9 +216,6 @@ func New(config *params.CliqueConfig, db ethdb.Database) *Clique {
if conf.Epoch == 0 { if conf.Epoch == 0 {
conf.Epoch = epochLength conf.Epoch = epochLength
} }
if conf.Period == 0 {
conf.Period = blockPeriod
}
// Allocate the snapshot caches and create the engine // Allocate the snapshot caches and create the engine
recents, _ := lru.NewARC(inmemorySnapshots) recents, _ := lru.NewARC(inmemorySnapshots)
signatures, _ := lru.NewARC(inmemorySignatures) signatures, _ := lru.NewARC(inmemorySignatures)
@ -599,6 +601,10 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, stop <-ch
if number == 0 { if number == 0 {
return nil, errUnknownBlock return nil, errUnknownBlock
} }
// For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing)
if c.config.Period == 0 && len(block.Transactions()) == 0 {
return nil, errWaitTransactions
}
// Don't hold the signer fields for the entire sealing procedure // Don't hold the signer fields for the entire sealing procedure
c.lock.RLock() c.lock.RLock()
signer, signFn := c.signer, c.signFn signer, signFn := c.signer, c.signFn

@ -74,7 +74,7 @@ type testerChainReader struct {
db ethdb.Database db ethdb.Database
} }
func (r *testerChainReader) Config() *params.ChainConfig { return params.AllProtocolChanges } func (r *testerChainReader) Config() *params.ChainConfig { return params.AllCliqueProtocolChanges }
func (r *testerChainReader) CurrentHeader() *types.Header { panic("not supported") } func (r *testerChainReader) CurrentHeader() *types.Header { panic("not supported") }
func (r *testerChainReader) GetHeader(common.Hash, uint64) *types.Header { panic("not supported") } func (r *testerChainReader) GetHeader(common.Hash, uint64) *types.Header { panic("not supported") }
func (r *testerChainReader) GetBlock(common.Hash, uint64) *types.Block { panic("not supported") } func (r *testerChainReader) GetBlock(common.Hash, uint64) *types.Block { panic("not supported") }

@ -94,7 +94,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
t.Fatalf("failed to create node: %v", err) t.Fatalf("failed to create node: %v", err)
} }
ethConf := &eth.Config{ ethConf := &eth.Config{
Genesis: core.DevGenesisBlock(), Genesis: core.DeveloperGenesisBlock(15, common.Address{}),
Etherbase: common.HexToAddress(testAddress), Etherbase: common.HexToAddress(testAddress),
PowTest: true, PowTest: true,
} }

@ -235,7 +235,7 @@ func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
genesis := gspec.MustCommit(db) genesis := gspec.MustCommit(db)
blockchain, _ := NewBlockChain(db, params.AllProtocolChanges, ethash.NewFaker(), vm.Config{}) blockchain, _ := NewBlockChain(db, params.AllEthashProtocolChanges, ethash.NewFaker(), vm.Config{})
// Create and inject the requested chain // Create and inject the requested chain
if n == 0 { if n == 0 {
return db, blockchain, nil return db, blockchain, nil

@ -151,7 +151,7 @@ func (e *GenesisMismatchError) Error() string {
// The returned chain configuration is never nil. // The returned chain configuration is never nil.
func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
if genesis != nil && genesis.Config == nil { if genesis != nil && genesis.Config == nil {
return params.AllProtocolChanges, common.Hash{}, errGenesisNoConfig return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
} }
// Just commit the new block if there is no stored genesis block. // Just commit the new block if there is no stored genesis block.
@ -216,7 +216,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
case ghash == params.TestnetGenesisHash: case ghash == params.TestnetGenesisHash:
return params.TestnetChainConfig return params.TestnetChainConfig
default: default:
return params.AllProtocolChanges return params.AllEthashProtocolChanges
} }
} }
@ -285,7 +285,7 @@ func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
} }
config := g.Config config := g.Config
if config == nil { if config == nil {
config = params.AllProtocolChanges config = params.AllEthashProtocolChanges
} }
return block, WriteChainConfig(db, block.Hash(), config) return block, WriteChainConfig(db, block.Hash(), config)
} }
@ -342,14 +342,30 @@ func DefaultRinkebyGenesisBlock() *Genesis {
} }
} }
// DevGenesisBlock returns the 'geth --dev' genesis block. // DeveloperGenesisBlock returns the 'geth --dev' genesis block. Note, this must
func DevGenesisBlock() *Genesis { // be seeded with the
func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis {
// Override the default period to the user requested one
config := *params.AllCliqueProtocolChanges
config.Clique.Period = period
// Assemble and return the genesis with the precompiles and faucet pre-funded
return &Genesis{ return &Genesis{
Config: params.AllProtocolChanges, Config: &config,
Nonce: 42, ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, 65)...),
GasLimit: 4712388, GasLimit: 6283185,
Difficulty: big.NewInt(131072), Difficulty: big.NewInt(1),
Alloc: decodePrealloc(devAllocData), Alloc: map[common.Address]GenesisAccount{
common.BytesToAddress([]byte{1}): GenesisAccount{Balance: big.NewInt(1)}, // ECRecover
common.BytesToAddress([]byte{2}): GenesisAccount{Balance: big.NewInt(1)}, // SHA256
common.BytesToAddress([]byte{3}): GenesisAccount{Balance: big.NewInt(1)}, // RIPEMD
common.BytesToAddress([]byte{4}): GenesisAccount{Balance: big.NewInt(1)}, // Identity
common.BytesToAddress([]byte{5}): GenesisAccount{Balance: big.NewInt(1)}, // ModExp
common.BytesToAddress([]byte{6}): GenesisAccount{Balance: big.NewInt(1)}, // ECAdd
common.BytesToAddress([]byte{7}): GenesisAccount{Balance: big.NewInt(1)}, // ECScalarMul
common.BytesToAddress([]byte{8}): GenesisAccount{Balance: big.NewInt(1)}, // ECPairing
faucet: GenesisAccount{Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))},
},
} }
} }

File diff suppressed because one or more lines are too long

@ -65,7 +65,7 @@ func TestSetupGenesis(t *testing.T) {
return SetupGenesisBlock(db, new(Genesis)) return SetupGenesisBlock(db, new(Genesis))
}, },
wantErr: errGenesisNoConfig, wantErr: errGenesisNoConfig,
wantConfig: params.AllProtocolChanges, wantConfig: params.AllEthashProtocolChanges,
}, },
{ {
name: "no block in DB, genesis == nil", name: "no block in DB, genesis == nil",

@ -269,6 +269,11 @@ func (self *worker) update() {
self.current.commitTransactions(self.mux, txset, self.chain, self.coinbase) self.current.commitTransactions(self.mux, txset, self.chain, self.coinbase)
self.currentMu.Unlock() self.currentMu.Unlock()
} else {
// If we're mining, but nothing is being processed, wake on new transactions
if self.config.Clique != nil && self.config.Clique.Period == 0 {
self.commitNewWork()
}
} }
// System stopped // System stopped

@ -77,17 +77,22 @@ var (
}, },
} }
// AllProtocolChanges contains every protocol change (EIPs) // AllEthashProtocolChanges contains every protocol change (EIPs) introduced
// introduced and accepted by the Ethereum core developers. // and accepted by the Ethereum core developers into the Ethash consensus.
// //
// This configuration is intentionally not using keyed fields. // This configuration is intentionally not using keyed fields to force anyone
// This configuration must *always* have all forks enabled, which // adding flags to the config to also have to set these fields.
// means that all fields must be set at all times. This forces AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil}
// anyone adding flags to the config to also have to set these
// fields. // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil} // and accepted by the Ethereum core developers into the Clique consensus.
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil} //
TestRules = TestChainConfig.Rules(new(big.Int)) // This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, &CliqueConfig{Period: 0, Epoch: 30000}}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil}
TestRules = TestChainConfig.Rules(new(big.Int))
) )
// ChainConfig is the core config which determines the blockchain settings. // ChainConfig is the core config which determines the blockchain settings.

@ -29,8 +29,8 @@ func TestCheckCompatible(t *testing.T) {
wantErr *ConfigCompatError wantErr *ConfigCompatError
} }
tests := []test{ tests := []test{
{stored: AllProtocolChanges, new: AllProtocolChanges, head: 0, wantErr: nil}, {stored: AllEthashProtocolChanges, new: AllEthashProtocolChanges, head: 0, wantErr: nil},
{stored: AllProtocolChanges, new: AllProtocolChanges, head: 100, wantErr: nil}, {stored: AllEthashProtocolChanges, new: AllEthashProtocolChanges, head: 100, wantErr: nil},
{ {
stored: &ChainConfig{EIP150Block: big.NewInt(10)}, stored: &ChainConfig{EIP150Block: big.NewInt(10)},
new: &ChainConfig{EIP150Block: big.NewInt(20)}, new: &ChainConfig{EIP150Block: big.NewInt(20)},
@ -38,7 +38,7 @@ func TestCheckCompatible(t *testing.T) {
wantErr: nil, wantErr: nil,
}, },
{ {
stored: AllProtocolChanges, stored: AllEthashProtocolChanges,
new: &ChainConfig{HomesteadBlock: nil}, new: &ChainConfig{HomesteadBlock: nil},
head: 3, head: 3,
wantErr: &ConfigCompatError{ wantErr: &ConfigCompatError{
@ -49,7 +49,7 @@ func TestCheckCompatible(t *testing.T) {
}, },
}, },
{ {
stored: AllProtocolChanges, stored: AllEthashProtocolChanges,
new: &ChainConfig{HomesteadBlock: big.NewInt(1)}, new: &ChainConfig{HomesteadBlock: big.NewInt(1)},
head: 3, head: 3,
wantErr: &ConfigCompatError{ wantErr: &ConfigCompatError{