diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 3cecd61d11..8d45cb76eb 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -145,6 +145,7 @@ var ( utils.EthProtocolsFlag, utils.DeveloperFlag, utils.DeveloperPeriodFlag, + utils.DeveloperPoWFlag, utils.ClassicFlag, utils.MordorFlag, utils.SocialFlag, @@ -160,6 +161,7 @@ var ( utils.NetworkIdFlag, utils.EthStatsURLFlag, utils.FakePoWFlag, + utils.FakePoWPoissonFlag, utils.NoCompactionFlag, utils.GpoBlocksFlag, utils.LegacyGpoBlocksFlag, @@ -311,7 +313,10 @@ func checkMainnet(ctx *cli.Context) bool { log.Info("Starting Geth on Görli testnet...") case ctx.GlobalIsSet(utils.DeveloperFlag.Name): - log.Info("Starting Geth in ephemeral dev mode...") + log.Info("Starting Geth in ephemeral proof-of-authority network dev mode...") + + case ctx.GlobalIsSet(utils.DeveloperPoWFlag.Name): + log.Info("Starting Geth in ephemeral proof-of-work network dev mode...") case ctx.GlobalIsSet(utils.ClassicFlag.Name): log.Info("Starting Geth on Ethereum Classic...") @@ -488,7 +493,8 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) { } // Start auxiliary services if enabled - if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) { + isDeveloperMode := ctx.GlobalBool(utils.DeveloperFlag.Name) || ctx.GlobalBool(utils.DeveloperPoWFlag.Name) + if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || isDeveloperMode { // Mining only makes sense if a full Ethereum node is running if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { utils.Fatalf("Light clients do not support mining") @@ -510,6 +516,9 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) { threads = ctx.GlobalInt(utils.LegacyMinerThreadsFlag.Name) log.Warn("The flag --minerthreads is deprecated and will be removed in the future, please use --miner.threads") } + if isDeveloperMode && !ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) && !ctx.GlobalIsSet(utils.LegacyMinerThreadsFlag.Name) { + threads = 1 + } if err := ethBackend.StartMining(threads); err != nil { utils.Fatalf("Failed to start mining: %v", err) } diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 6506b6e30c..a6cd695736 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -81,6 +81,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ Flags: []cli.Flag{ utils.DeveloperFlag, utils.DeveloperPeriodFlag, + utils.DeveloperPoWFlag, }, }, { @@ -214,6 +215,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ Name: "LOGGING AND DEBUGGING", Flags: append([]cli.Flag{ utils.FakePoWFlag, + utils.FakePoWPoissonFlag, utils.NoCompactionFlag, }, debug.Flags...), }, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 98996fd7fe..c09a2f28e2 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -192,7 +192,11 @@ var ( } DeveloperPeriodFlag = cli.IntFlag{ Name: "dev.period", - Usage: "Block period to use in developer mode (0 = mine only if transaction pending)", + Usage: "Block period for proof-of-authority network to use in developer mode (0 = mine only if transaction pending)", + } + DeveloperPoWFlag = cli.BoolFlag{ + Name: "dev.pow", + Usage: "Ephemeral proof-of-work network with a pre-funded developer account, mining enabled", } IdentityFlag = cli.StringFlag{ Name: "identity", @@ -517,6 +521,10 @@ var ( Name: "fakepow", Usage: "Disables proof-of-work verification", } + FakePoWPoissonFlag = cli.BoolFlag{ + Name: "fakepow.poisson", + Usage: "Disables proof-of-work verification and adds mining delay (Poisson) based on --miner.threads", + } NoCompactionFlag = cli.BoolFlag{ Name: "nocompaction", Usage: "Disables db compaction after import", @@ -1252,7 +1260,7 @@ func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { cfg.NetRestrict = list } - if ctx.GlobalBool(DeveloperFlag.Name) { + if ctx.GlobalBool(DeveloperFlag.Name) || ctx.GlobalBool(DeveloperPoWFlag.Name) { // --dev mode can't use p2p networking. cfg.MaxPeers = 0 cfg.ListenAddr = ":0" @@ -1341,7 +1349,7 @@ func setDataDir(ctx *cli.Context, cfg *node.Config) { case ctx.GlobalIsSet(DataDirFlag.Name): cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) - case ctx.GlobalBool(DeveloperFlag.Name): + case ctx.GlobalBool(DeveloperFlag.Name) || ctx.GlobalBool(DeveloperPoWFlag.Name): cfg.DataDir = "" // unless explicitly requested, use memory databases case (ctx.GlobalBool(LegacyTestnetFlag.Name) || ctx.GlobalBool(RopstenFlag.Name)) && cfg.DataDir == node.DefaultDataDir(): @@ -1478,6 +1486,9 @@ func setEthash(ctx *cli.Context, cfg *eth.Config) { setEthashCacheDir(ctx, cfg) setEthashDatasetDir(ctx, cfg) + if ctx.GlobalBool(FakePoWPoissonFlag.Name) { + cfg.Ethash.PowMode = ethash.ModePoissonFake + } if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) { cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name) } @@ -1611,9 +1622,9 @@ func SetShhConfig(ctx *cli.Context, stack *node.Node) { // SetEthConfig applies eth-related command line flags to the config. func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { // Avoid conflicting network flags - CheckExclusive(ctx, DeveloperFlag, LegacyTestnetFlag, RopstenFlag, RinkebyFlag, GoerliFlag, YoloV1Flag, ClassicFlag, KottiFlag, MordorFlag, EthersocialFlag, SocialFlag) + CheckExclusive(ctx, DeveloperFlag, DeveloperPoWFlag, LegacyTestnetFlag, RopstenFlag, RinkebyFlag, GoerliFlag, YoloV1Flag, ClassicFlag, KottiFlag, MordorFlag, EthersocialFlag, SocialFlag) CheckExclusive(ctx, LegacyLightServFlag, LightServeFlag, SyncModeFlag, "light") - CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer + CheckExclusive(ctx, DeveloperFlag, DeveloperPoWFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer CheckExclusive(ctx, GCModeFlag, "archive", TxLookupLimitFlag) // todo(rjl493456442) make it available for les server // Ancient tx indices pruning is not available for les server now @@ -1621,6 +1632,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { CheckExclusive(ctx, LegacyLightServFlag, LightServeFlag, TxLookupLimitFlag) CheckExclusive(ctx, AncientFlag, AncientRPCFlag) + CheckExclusive(ctx, DeveloperPoWFlag, DeveloperPeriodFlag, FakePoWFlag) + CheckExclusive(ctx, FakePoWFlag, FakePoWPoissonFlag) var ks *keystore.KeyStore if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { @@ -1790,7 +1803,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { } } - if ctx.GlobalBool(DeveloperFlag.Name) { + if ctx.GlobalBool(DeveloperFlag.Name) || ctx.GlobalBool(DeveloperPoWFlag.Name) { if !ctx.GlobalIsSet(NetworkIdFlag.Name) { cfg.NetworkId = 1337 } @@ -1824,7 +1837,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { log.Info("Using developer account", "address", developer.Address) // Create a new developer genesis block or reuse existing one - cfg.Genesis = params.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address) + cfg.Genesis = params.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address, ctx.GlobalBool(DeveloperPoWFlag.Name)) if ctx.GlobalIsSet(DataDirFlag.Name) { // Check if we have an already initialized chain and fall back to // that if so. Otherwise we need to generate a new genesis spec. @@ -2007,7 +2020,7 @@ func genesisForCtxChainConfig(ctx *cli.Context) *genesisT.Genesis { } func MakeGenesis(ctx *cli.Context) *genesisT.Genesis { - if ctx.GlobalBool(DeveloperFlag.Name) { + if ctx.GlobalBool(DeveloperFlag.Name) || ctx.GlobalBool(DeveloperPoWFlag.Name) { Fatalf("Developer chains are ephemeral") } return genesisForCtxChainConfig(ctx) @@ -2029,7 +2042,9 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readOnly bool) (chain *core.B }, chainDb) } else { engine = ethash.NewFaker() - if !ctx.GlobalBool(FakePoWFlag.Name) { + if ctx.GlobalBool(FakePoWPoissonFlag.Name) { + engine = ethash.NewPoissonFaker() + } else if !ctx.GlobalBool(FakePoWFlag.Name) { engine = ethash.New(ethash.Config{ CacheDir: stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir), CachesInMem: eth.DefaultConfig.Ethash.CachesInMem, diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index fe0c61d96a..f5e6778237 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -642,6 +642,18 @@ func NewFakeDelayer(delay time.Duration) *Ethash { } } +// NewPoissonFaker creates a ethash consensus engine with a fake PoW scheme that +// accepts all blocks as valid, but delays mining by some time based on miner.threads, though +// they still have to conform to the Ethereum consensus rules. +func NewPoissonFaker() *Ethash { + return &Ethash{ + config: Config{ + PowMode: ModePoissonFake, + Log: log.Root(), + }, + } +} + // NewFullFaker creates an ethash consensus engine with a full fake scheme that // accepts all blocks as valid, without checking any consensus rules whatsoever. func NewFullFaker() *Ethash { diff --git a/console/console_test.go b/console/console_test.go index 7293d2d761..c0515929c2 100644 --- a/console/console_test.go +++ b/console/console_test.go @@ -98,7 +98,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester { t.Fatalf("failed to create node: %v", err) } ethConf := ð.Config{ - Genesis: params.DeveloperGenesisBlock(15, common.Address{}), + Genesis: params.DeveloperGenesisBlock(15, common.Address{}, false), Miner: miner.Config{ Etherbase: common.HexToAddress(testAddress), }, diff --git a/eth/backend.go b/eth/backend.go index 284f938565..e8238137f7 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -270,6 +270,9 @@ func CreateConsensusEngine(stack *node.Node, chainConfig ctypes.ChainConfigurato case ethash.ModeFake: log.Warn("Ethash used in fake mode") return ethash.NewFaker() + case ethash.ModePoissonFake: + log.Warn("Ethash used in fake Poisson mode") + return ethash.NewPoissonFaker() case ethash.ModeTest: log.Warn("Ethash used in test mode") return ethash.NewTester(nil, noverify) diff --git a/miner/miner_test.go b/miner/miner_test.go index aceca7b3e6..76f32220bb 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -238,7 +238,7 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux) { // Create chainConfig memdb := memorydb.New() chainDB := rawdb.NewDatabase(memdb) - genesis := params.DeveloperGenesisBlock(15, common.HexToAddress("12345")) + genesis := params.DeveloperGenesisBlock(15, common.HexToAddress("12345"), false) chainConfig, _, err := core.SetupGenesisBlock(chainDB, genesis) if err != nil { t.Fatalf("can't create new chain config: %v", err) diff --git a/params/genesis.go b/params/genesis.go index 0b6adb6f82..8a1c68df71 100644 --- a/params/genesis.go +++ b/params/genesis.go @@ -22,7 +22,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params/types/coregeth" + "github.com/ethereum/go-ethereum/params/types/ctypes" "github.com/ethereum/go-ethereum/params/types/genesisT" + "github.com/ethereum/go-ethereum/params/types/goethereum" + "github.com/ethereum/go-ethereum/params/vars" ) // DefaultGenesisBlock returns the Ethereum main net genesis block. @@ -86,17 +90,85 @@ func DefaultYoloV1GenesisBlock() *genesisT.Genesis { // DeveloperGenesisBlock returns the 'geth --dev' genesis block. Note, this must // be seeded with the -func DeveloperGenesisBlock(period uint64, faucet common.Address) *genesisT.Genesis { - // Override the default period to the user requested one - config := *AllCliqueProtocolChanges - config.Clique.Period = period +func DeveloperGenesisBlock(period uint64, faucet common.Address, useEthash bool) *genesisT.Genesis { + if !useEthash { + // Make a copy to avoid unpredicted contamination. + config := &goethereum.ChainConfig{} + *config = *AllCliqueProtocolChanges + + // Override the default period to the user requested one + config.Clique.Period = period + // Assemble and return the genesis with the precompiles and faucet pre-funded + return &genesisT.Genesis{ + Config: config, + ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, crypto.SignatureLength)...), + GasLimit: 6283185, + Difficulty: big.NewInt(1), + Alloc: map[common.Address]genesisT.GenesisAccount{ + common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover + common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256 + common.BytesToAddress([]byte{3}): {Balance: big.NewInt(1)}, // RIPEMD + common.BytesToAddress([]byte{4}): {Balance: big.NewInt(1)}, // Identity + common.BytesToAddress([]byte{5}): {Balance: big.NewInt(1)}, // ModExp + common.BytesToAddress([]byte{6}): {Balance: big.NewInt(1)}, // ECAdd + common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul + common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing + faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(9))}, + }, + } + } + + // Use an ETC equivalent of AllEthashProtocolChanges. + // This will allow initial permanent disposal of the difficulty bomb, + // and we'll override the monetary policy block reward schedule to be a non-occurring. + // + // This was originally intended to be as follows, but import cycles prevent it. + // Leaving here to show provenance of initial configuration value. + // config := &coregeth.CoreGethChainConfig{} + // *config = *tests.Forks["ETC_Phoenix"].(*coregeth.CoreGethChainConfig) + config := &coregeth.CoreGethChainConfig{ + NetworkID: AllCliqueProtocolChanges.GetChainID().Uint64(), // Use network and chain IDs equivalent to Clique configuration, ie 1337. + Ethash: new(ctypes.EthashConfig), + ChainID: AllCliqueProtocolChanges.GetChainID(), + EIP2FBlock: big.NewInt(0), + EIP7FBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP160FBlock: big.NewInt(0), + EIP161FBlock: big.NewInt(0), + EIP170FBlock: big.NewInt(0), + EIP100FBlock: big.NewInt(0), + EIP140FBlock: big.NewInt(0), + EIP198FBlock: big.NewInt(0), + EIP211FBlock: big.NewInt(0), + EIP212FBlock: big.NewInt(0), + EIP213FBlock: big.NewInt(0), + EIP214FBlock: big.NewInt(0), + EIP658FBlock: big.NewInt(0), + EIP145FBlock: big.NewInt(0), + EIP1014FBlock: big.NewInt(0), + EIP1052FBlock: big.NewInt(0), + EIP1283FBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + EIP152FBlock: big.NewInt(0), + EIP1108FBlock: big.NewInt(0), + EIP1344FBlock: big.NewInt(0), + EIP1884FBlock: big.NewInt(0), + EIP2028FBlock: big.NewInt(0), + EIP2200FBlock: big.NewInt(0), + DisposalBlock: big.NewInt(0), + ECIP1017FBlock: nil, // disable block reward disinflation + ECIP1017EraRounds: nil, // ^ + ECIP1010PauseBlock: nil, // no need for difficulty bomb delay (see disposal block) + ECIP1010Length: nil, // ^ + } // Assemble and return the genesis with the precompiles and faucet pre-funded return &genesisT.Genesis{ - Config: &config, + Config: config, ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, crypto.SignatureLength)...), GasLimit: 6283185, - Difficulty: big.NewInt(1), + Difficulty: vars.MinimumDifficulty, Alloc: map[common.Address]genesisT.GenesisAccount{ common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256