diff --git a/.golangci.yml b/.golangci.yml index 3260c0f987..aea7a35b66 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -50,3 +50,6 @@ issues: - path: cmd/faucet/ linters: - deadcode + - path: core/blockchain_af.go + linters: + - deadcode diff --git a/cmd/echainspec/main.go b/cmd/echainspec/main.go index 8a3ef13cd5..855081a455 100644 --- a/cmd/echainspec/main.go +++ b/cmd/echainspec/main.go @@ -57,6 +57,7 @@ var defaultChainspecValues = map[string]ctypes.Configurator{ "rinkeby": params.DefaultRinkebyGenesisBlock(), "goerli": params.DefaultGoerliGenesisBlock(), "yolov1": params.DefaultYoloV1GenesisBlock(), + "messnet": params.DefaultMessNetGenesisBlock(), "social": params.DefaultSocialGenesisBlock(), "ethersocial": params.DefaultEthersocialGenesisBlock(), diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 05b0192c56..8829854007 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -167,6 +167,7 @@ The export-preimages command export hash preimages to an RLP encoded stream`, utils.SyncModeFlag, utils.FakePoWFlag, utils.ClassicFlag, + utils.MessNetFlag, utils.MordorFlag, utils.KottiFlag, utils.SocialFlag, @@ -221,6 +222,7 @@ Use "ethereum dump 0" to dump the genesis block.`, utils.AncientFlag, utils.CacheFlag, utils.ClassicFlag, + utils.MessNetFlag, utils.MordorFlag, utils.KottiFlag, utils.SocialFlag, diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go index 22974df0ec..8e936ab5dc 100644 --- a/cmd/geth/consolecmd.go +++ b/cmd/geth/consolecmd.go @@ -138,6 +138,8 @@ func remoteConsole(ctx *cli.Context) error { path = filepath.Join(path, "kotti") } else if ctx.GlobalBool(utils.ClassicFlag.Name) { path = filepath.Join(path, "classic") + } else if ctx.GlobalBool(utils.MessNetFlag.Name) { + path = filepath.Join(path, "messnet") } else if ctx.GlobalBool(utils.MordorFlag.Name) { path = filepath.Join(path, "mordor") } else if ctx.GlobalBool(utils.SocialFlag.Name) { diff --git a/cmd/geth/consolecmd_test.go b/cmd/geth/consolecmd_test.go index 4631e4812a..d4570b9196 100644 --- a/cmd/geth/consolecmd_test.go +++ b/cmd/geth/consolecmd_test.go @@ -65,6 +65,7 @@ func TestConsoleCmdNetworkIdentities(t *testing.T) { {[]string{"--social"}, 28, 28, params.SocialGenesisHash.Hex()}, {[]string{"--ethersocial"}, 1, 31102, params.EthersocialGenesisHash.Hex()}, {[]string{"--yolov1"}, 133519467574833, 133519467574833, params.YoloV1GenesisHash.Hex()}, + {[]string{"--messnet"}, 6161, 6161, "0xb2957ab683ae69176b2eb7858f2baedb93752cb7cb45284529d543eebe20652e"}, } for i, p := range chainIdentityCases { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index ca7afafced..94bb4f3f6a 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -145,6 +145,7 @@ var ( utils.DeveloperFlag, utils.DeveloperPeriodFlag, utils.ClassicFlag, + utils.MessNetFlag, utils.MordorFlag, utils.SocialFlag, utils.MixFlag, @@ -166,6 +167,7 @@ var ( utils.LegacyGpoPercentileFlag, utils.EWASMInterpreterFlag, utils.EVMInterpreterFlag, + utils.ECBP1100Flag, configFileFlag, } @@ -313,6 +315,9 @@ func checkMainnet(ctx *cli.Context) bool { case ctx.GlobalIsSet(utils.ClassicFlag.Name): log.Info("Starting Geth on Ethereum Classic...") + case ctx.GlobalIsSet(utils.MessNetFlag.Name): + log.Info("Starting Geth on MessNet...") + case ctx.GlobalIsSet(utils.MordorFlag.Name): log.Info("Starting Geth on Mordor testnet...") diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 4e87fcb515..37aadc884a 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -52,6 +52,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.RinkebyFlag, utils.YoloV1Flag, utils.RopstenFlag, + utils.MessNetFlag, utils.SyncModeFlag, utils.ExitWhenSyncedFlag, utils.GCModeFlag, @@ -60,6 +61,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.IdentityFlag, utils.LightKDFFlag, utils.WhitelistFlag, + utils.ECBP1100Flag, }, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 90a67a01f6..2d747d2bf7 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -136,7 +136,7 @@ var ( } NetworkIdFlag = cli.Uint64Flag{ Name: "networkid", - Usage: "Network identifier (integer, 1=Mainnet, 2=Morden (disused), 3=Ropsten, 4=Rinkeby, 5=Goerli, 6=Kotti, YoloV1=133519467574833, developer=1337)", + Usage: "Network identifier (integer, 1=Mainnet, 2=Morden (disused), 3=Ropsten, 4=Rinkeby, 5=Goerli, 6=Kotti, YoloV1=133519467574833, 6161=MessNet, developer=1337)", Value: eth.DefaultConfig.NetworkId, } ClassicFlag = cli.BoolFlag{ @@ -179,6 +179,10 @@ var ( Name: "goerli", Usage: "Görli network: pre-configured proof-of-authority test network", } + MessNetFlag = cli.BoolFlag{ + Name: "messnet", + Usage: "MESS network: temporary dedicated test network for MESS testing", + } DeveloperFlag = cli.BoolFlag{ Name: "dev", Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled", @@ -749,6 +753,10 @@ var ( Usage: "External EVM configuration (default = built-in interpreter)", Value: "", } + ECBP1100Flag = cli.Uint64Flag{ + Name: "ecbp1100", + Usage: "Configure ECBP-1100 (MESS) block activation number", + } ) // MakeDataDir retrieves the currently requested data directory, terminating @@ -1295,6 +1303,8 @@ func dataDirPathForCtxChainConfig(ctx *cli.Context, baseDataDirPath string) stri return filepath.Join(baseDataDirPath, "ropsten") case ctx.GlobalBool(ClassicFlag.Name): return filepath.Join(baseDataDirPath, "classic") + case ctx.GlobalBool(MessNetFlag.Name): + return filepath.Join(baseDataDirPath, "messnet") case ctx.GlobalBool(MordorFlag.Name): return filepath.Join(baseDataDirPath, "mordor") case ctx.GlobalBool(SocialFlag.Name): @@ -1411,6 +1421,9 @@ func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { } func setEthash(ctx *cli.Context, cfg *eth.Config) { + if ctx.GlobalBool(FakePoWFlag.Name) { + cfg.Ethash.PowMode = ethash.ModeFake + } if ctx.GlobalIsSet(EthashCacheDirFlag.Name) { cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name) } @@ -1553,7 +1566,7 @@ func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) { // 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, LegacyTestnetFlag, RopstenFlag, RinkebyFlag, GoerliFlag, YoloV1Flag, ClassicFlag, KottiFlag, MordorFlag, EthersocialFlag, SocialFlag, MessNetFlag) CheckExclusive(ctx, LegacyLightServFlag, LightServeFlag, SyncModeFlag, "light") CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer CheckExclusive(ctx, GCModeFlag, "archive", TxLookupLimitFlag) @@ -1664,6 +1677,13 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { if gen := genesisForCtxChainConfig(ctx); gen != nil { cfg.Genesis = gen } + // Handle temporary chain configuration override cases. + if ctx.GlobalIsSet(ECBP1100Flag.Name) { + n := ctx.GlobalUint64(ECBP1100Flag.Name) + if err := cfg.Genesis.Config.SetECBP1100Transition(&n); err != nil { + Fatalf("Failed to set ECBP-1100 activation number: %v", err) + } + } // Establish NetworkID. // If dev-mode is used, then NetworkID will be overridden. @@ -1894,6 +1914,8 @@ func genesisForCtxChainConfig(ctx *cli.Context) *genesisT.Genesis { switch { case ctx.GlobalBool(ClassicFlag.Name): genesis = params.DefaultClassicGenesisBlock() + case ctx.GlobalBool(MessNetFlag.Name): + genesis = params.DefaultMessNetGenesisBlock() case ctx.GlobalBool(MordorFlag.Name): genesis = params.DefaultMordorGenesisBlock() case ctx.GlobalBool(SocialFlag.Name): diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index aa3f002c0d..35eda36e1d 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -399,6 +399,22 @@ const ( ModeFullFake ) +func (m Mode) String() string { + switch m { + case ModeNormal: + return "Normal" + case ModeShared: + return "Shared" + case ModeTest: + return "Test" + case ModeFake: + return "Fake" + case ModeFullFake: + return "FullFake" + } + return "unknown" +} + // Config are the configuration parameters of the ethash. type Config struct { CacheDir string diff --git a/consensus/ethash/sealer.go b/consensus/ethash/sealer.go index 2053534028..655ca2d28f 100644 --- a/consensus/ethash/sealer.go +++ b/consensus/ethash/sealer.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/types" + "gonum.org/v1/gonum/stat/distuv" ) const ( @@ -46,18 +47,53 @@ var ( errInvalidSealResult = errors.New("invalid or stale proof-of-work solution") ) +// makeFakeDelay uses the ethash.threads value as a mean time (lambda) +// for a Poisson distribution, returning a random value from +// that discrete function. I think a Poisson distribution probably +// fairly accurately models real world block times. +// Note that this is a hacky way to use ethash.threads since +// lower values will yield faster blocks, but it saves having +// to add or modify any more code than necessary. +func (ethash *Ethash) makeFakeDelay() float64 { + p := distuv.Poisson{ + Lambda: float64(ethash.Threads()), + } + return p.Rand() +} + // Seal implements consensus.Engine, attempting to find a nonce that satisfies // the block's difficulty requirements. func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { // If we're running a fake PoW, simply return a 0 nonce immediately - if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake { - header := block.Header() - header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{} - select { - case results <- block.WithSeal(header): - default: - ethash.config.Log.Warn("Sealing result is not read by miner", "mode", "fake", "sealhash", ethash.SealHash(block.Header())) - } + faking := ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake + if faking { + go func(header *types.Header) { + // Assign random (but non-zero) values to header nonce and mix. + header.Nonce = types.EncodeNonce(uint64(rand.Int63n(math.MaxInt64))) + b, _ := header.Nonce.MarshalText() + header.MixDigest = common.BytesToHash(b) + + // Wait some amount of time. + timeout := time.NewTimer(time.Duration(ethash.makeFakeDelay()) * time.Second) + defer timeout.Stop() + + select { + case <-stop: + return + case <-ethash.update: + timeout.Stop() + if err := ethash.Seal(chain, block, results, stop); err != nil { + ethash.config.Log.Error("Failed to restart sealing after update", "err", err) + } + case <-timeout.C: + // Send the results when the timeout expires. + select { + case results <- block.WithSeal(header): + default: + ethash.config.Log.Warn("Sealing result is not read by miner", "mode", "fake", "sealhash", ethash.SealHash(block.Header())) + } + } + }(block.Header()) return nil } // If we're running a shared PoW, delegate sealing to it diff --git a/consensus/ethash/sealer_test.go b/consensus/ethash/sealer_test.go index 20ed2a4184..7d5369f643 100644 --- a/consensus/ethash/sealer_test.go +++ b/consensus/ethash/sealer_test.go @@ -22,6 +22,7 @@ import ( "math/big" "net/http" "net/http/httptest" + "sort" "testing" "time" @@ -31,6 +32,24 @@ import ( "github.com/ethereum/go-ethereum/log" ) +func TestSealFakeDelay(t *testing.T) { + cases := []int{ + 3, 10, 19, 33, + } + for _, c := range cases { + e := &Ethash{threads: c} // "threads" is actually the desired MEAN (lambda) of the Poisson distribution + got := []float64{} + for i := 0; i < 20; i++ { + d := e.makeFakeDelay() + got = append(got, d) + } + sort.Slice(got, func(i, j int) bool { + return got[i] < got[j] + }) + t.Logf("ethash.threads,lamda=%2d %v", c, got) + } +} + // Tests whether remote HTTP servers are correctly notified of new work. func TestRemoteNotify(t *testing.T) { // Start a simple web server to capture notifications. diff --git a/core/blockchain.go b/core/blockchain.go index 4e03dd4580..1571840be4 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -210,6 +210,8 @@ type BlockChain struct { badBlocks *lru.Cache // Bad block cache shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. terminateInsert func(common.Hash, uint64) bool // Testing hook used to terminate ancient receipt chain insertion. + + artificialFinalityEnabled int32 // toggles artificial finality features } // NewBlockChain returns a fully initialised block chain using information @@ -1419,7 +1421,8 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error { current := bc.CurrentBlock() if block.ParentHash() != current.Hash() { - if err := bc.reorg(current, block); err != nil { + d := bc.getReorgData(current, block) + if err := bc.reorg(d); err != nil { return err } } @@ -1540,17 +1543,29 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. reorg = !currentPreserve && (blockPreserve || mrand.Float64() < 0.5) } } + if reorg { - // Reorganise the chain if the parent is not the head block if block.ParentHash() != currentBlock.Hash() { - if err := bc.reorg(currentBlock, block); err != nil { + // Reorganise the chain if the parent is not the head block + d := bc.getReorgData(currentBlock, block) + if d.err == nil { + // Reorg data error was nil. + // Proceed with further reorg arbitration. + if bc.IsArtificialFinalityEnabled() && bc.chainConfig.IsEnabled(bc.chainConfig.GetECBP1100Transition, currentBlock.Number()) { + d.err = bc.ecbp1100(d.commonBlock.Header(), currentBlock.Header(), block.Header()) + } + } + // We leave the error to the reorg method to handle, if it wants to wrap it or log it or whatever. + if err := bc.reorg(d); err != nil { return NonStatTy, err } } + // Status is canon; reorg succeeded. status = CanonStatTy } else { status = SideStatTy } + // Set new head. if status == CanonStatTy { bc.writeHeadBlock(block) @@ -1647,7 +1662,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er senderCacher.recoverFromBlocks(types.MakeSigner(bc.chainConfig, chain[0].Number()), chain) var ( - stats = insertStats{startTime: mclock.Now()} + stats = insertStats{ + startTime: mclock.Now(), + artificialFinality: bc.IsArtificialFinalityEnabled() && + bc.chainConfig.IsEnabled(bc.chainConfig.GetECBP1100Transition, bc.CurrentBlock().Number()), + } lastCanon *types.Block ) // Fire a single chain head event if we've progressed the chain @@ -2045,17 +2064,44 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i return 0, nil } -// reorg takes two blocks, an old chain and a new chain and will reconstruct the -// blocks and inserts them to be part of the new canonical chain and accumulates -// potential missing transactions and post an event about them. -func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { +// errReorgImpossible denotes impossible reorgs. +// And yet, there is an error for if, and when they occur. +// Ah, sweet mystery of life. +var errReorgImpossible = errors.New("impossible reorg") + +// errReorgNewChain denotes an attempted reorg to an invalid incoming chain. +var errReorgNewChain = errors.New("invalid new chain") + +// errReorgNewChain denotes an attempted reorg to an invalid existing chain. +var errReorgOldChain = errors.New("invalid old chain") + +// reorgData is consumed by the reorg method. +type reorgData struct { + oldBlock *types.Block + newBlock *types.Block + + newChain types.Blocks + oldChain types.Blocks + commonBlock *types.Block + + deletedTxs types.Transactions + + deletedLogs [][]*types.Log + rebirthLogs [][]*types.Log + + err error +} + +// getReorgData gets the data required by the chain reorg method. +// This data is aggregated separately to facilitate the modularization of reorg acceptance +// arbitration logic. +func (bc *BlockChain) getReorgData(oldBlock, newBlock *types.Block) *reorgData { var ( newChain types.Blocks oldChain types.Blocks commonBlock *types.Block deletedTxs types.Transactions - addedTxs types.Transactions deletedLogs [][]*types.Log rebirthLogs [][]*types.Log @@ -2089,20 +2135,6 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } } } - // mergeLogs returns a merged log slice with specified sort order. - mergeLogs = func(logs [][]*types.Log, reverse bool) []*types.Log { - var ret []*types.Log - if reverse { - for i := len(logs) - 1; i >= 0; i-- { - ret = append(ret, logs[i]...) - } - } else { - for i := 0; i < len(logs); i++ { - ret = append(ret, logs[i]...) - } - } - return ret - } ) // Reduce the longer chain to the same number as the shorter one if oldBlock.NumberU64() > newBlock.NumberU64() { @@ -2119,10 +2151,10 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } } if oldBlock == nil { - return fmt.Errorf("invalid old chain") + return &reorgData{err: errReorgOldChain} } if newBlock == nil { - return fmt.Errorf("invalid new chain") + return &reorgData{err: errReorgNewChain} } // Both sides of the reorg are at the same number, reduce both until the common // ancestor is found @@ -2142,46 +2174,120 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // Step back with both chains oldBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1) if oldBlock == nil { - return fmt.Errorf("invalid old chain") + return &reorgData{err: errReorgOldChain} } newBlock = bc.GetBlock(newBlock.ParentHash(), newBlock.NumberU64()-1) if newBlock == nil { - return fmt.Errorf("invalid new chain") + return &reorgData{err: errReorgNewChain} } } - // Ensure the user sees large reorgs - if len(oldChain) > 0 && len(newChain) > 0 { - logFn := log.Info - msg := "Chain reorg detected" - if len(oldChain) > 63 { - msg = "Large chain reorg detected" - logFn = log.Warn - } - logFn(msg, "number", commonBlock.Number(), "hash", commonBlock.Hash(), - "drop", len(oldChain), "dropfrom", oldChain[0].Hash(), "add", len(newChain), "addfrom", newChain[0].Hash()) - blockReorgAddMeter.Mark(int64(len(newChain))) - blockReorgDropMeter.Mark(int64(len(oldChain))) - blockReorgMeter.Mark(1) - } else { - log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "newnum", newBlock.Number(), "newhash", newBlock.Hash()) - return fmt.Errorf("impossible reorg") + + if len(oldChain) == 0 || len(newChain) == 0 { + return &reorgData{err: errReorgImpossible} + } + return &reorgData{ + oldBlock: oldBlock, + newBlock: newBlock, + newChain: newChain, + oldChain: oldChain, + commonBlock: commonBlock, + deletedTxs: deletedTxs, + deletedLogs: deletedLogs, + rebirthLogs: rebirthLogs, } +} + +// reorg takes two blocks, an old chain and a new chain and will reconstruct the +// blocks and inserts them to be part of the new canonical chain and accumulates +// potential missing transactions and post an event about them. +// If reorgData passed contains an a non-nil error, the method is expect to return it immediately. +// reorgData is NOT expected to ever return an error of its own, since reorg arbitration +// should happen externally. +// This kind-of-strange pattern is in place to allow the function to issue "special case" warning logs +// consistent with its behavior prior to refactoring. +func (bc *BlockChain) reorg(data *reorgData) error { + if data.err != nil { + if data.err == errReorgImpossible { + log.Error("Impossible reorg, please file an issue", "oldnum", data.oldBlock.Number(), "oldhash", data.oldBlock.Hash(), "newnum", data.newBlock.Number(), "newhash", data.newBlock.Hash()) + } + return data.err + } + var ( + addedTxs types.Transactions + // mergeLogs returns a merged log slice with specified sort order. + mergeLogs = func(logs [][]*types.Log, reverse bool) []*types.Log { + var ret []*types.Log + if reverse { + for i := len(logs) - 1; i >= 0; i-- { + ret = append(ret, logs[i]...) + } + } else { + for i := 0; i < len(logs); i++ { + ret = append(ret, logs[i]...) + } + } + return ret + } + // collectLogs collects the logs that were generated or removed during + // the processing of the block that corresponds with the given hash. + // These logs are later announced as deleted or reborn + collectLogs = func(hash common.Hash, removed bool) { + number := bc.hc.GetBlockNumber(hash) + if number == nil { + return + } + receipts := rawdb.ReadReceipts(bc.db, hash, *number, bc.chainConfig) + + var logs []*types.Log + for _, receipt := range receipts { + for _, log := range receipt.Logs { + l := *log + if removed { + l.Removed = true + } else { + } + logs = append(logs, &l) + } + } + if len(logs) > 0 { + if removed { + data.deletedLogs = append(data.deletedLogs, logs) + } else { + data.rebirthLogs = append(data.rebirthLogs, logs) + } + } + } + ) + + // Ensure the user sees large reorgs + logFn := log.Info + msg := "Chain reorg detected" + if len(data.oldChain) > 63 { + msg = "Large chain reorg detected" + logFn = log.Warn + } + logFn(msg, "number", data.commonBlock.Number(), "hash", data.commonBlock.Hash(), + "drop", len(data.oldChain), "dropfrom", data.oldChain[0].Hash(), "add", len(data.newChain), "addfrom", data.newChain[0].Hash()) + blockReorgAddMeter.Mark(int64(len(data.newChain))) + blockReorgDropMeter.Mark(int64(len(data.oldChain))) + blockReorgMeter.Mark(1) + // Insert the new chain(except the head block(reverse order)), // taking care of the proper incremental order. - for i := len(newChain) - 1; i >= 1; i-- { + for i := len(data.newChain) - 1; i >= 1; i-- { // Insert the block in the canonical way, re-writing history - bc.writeHeadBlock(newChain[i]) + bc.writeHeadBlock(data.newChain[i]) // Collect reborn logs due to chain reorg - collectLogs(newChain[i].Hash(), false) + collectLogs(data.newChain[i].Hash(), false) // Collect the new added transactions. - addedTxs = append(addedTxs, newChain[i].Transactions()...) + addedTxs = append(addedTxs, data.newChain[i].Transactions()...) } // Delete useless indexes right now which includes the non-canonical // transaction indexes, canonical chain indexes which above the head. indexesBatch := bc.db.NewBatch() - for _, tx := range types.TxDifference(deletedTxs, addedTxs) { + for _, tx := range types.TxDifference(data.deletedTxs, addedTxs) { rawdb.DeleteTxLookupEntry(indexesBatch, tx.Hash()) } // Delete any canonical number assignments above the new head @@ -2200,15 +2306,15 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // this goroutine if there are no events to fire, but realistcally that only // ever happens if we're reorging empty blocks, which will only happen on idle // networks where performance is not an issue either way. - if len(deletedLogs) > 0 { - bc.rmLogsFeed.Send(RemovedLogsEvent{mergeLogs(deletedLogs, true)}) + if len(data.deletedLogs) > 0 { + bc.rmLogsFeed.Send(RemovedLogsEvent{mergeLogs(data.deletedLogs, true)}) } - if len(rebirthLogs) > 0 { - bc.logsFeed.Send(mergeLogs(rebirthLogs, false)) + if len(data.rebirthLogs) > 0 { + bc.logsFeed.Send(mergeLogs(data.rebirthLogs, false)) } - if len(oldChain) > 0 { - for i := len(oldChain) - 1; i >= 0; i-- { - bc.chainSideFeed.Send(ChainSideEvent{Block: oldChain[i]}) + if len(data.oldChain) > 0 { + for i := len(data.oldChain) - 1; i >= 0; i-- { + bc.chainSideFeed.Send(ChainSideEvent{Block: data.oldChain[i]}) } } return nil diff --git a/core/blockchain_af.go b/core/blockchain_af.go new file mode 100644 index 0000000000..7531b48cbf --- /dev/null +++ b/core/blockchain_af.go @@ -0,0 +1,157 @@ +package core + +import ( + "errors" + "fmt" + "math" + "math/big" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" +) + +// errReorgFinality represents an error caused by artificial finality mechanisms. +var errReorgFinality = errors.New("finality-enforced invalid new chain") + +// EnableArtificialFinality enables and disable artificial finality features for the blockchain. +// Currently toggled features include: +// - ECBP1100-MESS: modified exponential subject scoring +// +// This level of activation works BELOW the chain configuration for any of the +// potential features. eg. If ECBP1100 is not activated at the chain config x block number, +// then calling bc.EnableArtificialFinality(true) will be a noop. +// The method is idempotent. +func (bc *BlockChain) EnableArtificialFinality(enable bool, logValues ...interface{}) { + // Store enable/disable value regardless of config activation. + var statusLog string + if enable { + statusLog = "Enabled" + atomic.StoreInt32(&bc.artificialFinalityEnabled, 1) + } else { + statusLog = "Disabled" + atomic.StoreInt32(&bc.artificialFinalityEnabled, 0) + } + if !bc.chainConfig.IsEnabled(bc.chainConfig.GetECBP1100Transition, bc.CurrentHeader().Number) { + // Don't log anything if the config hasn't enabled it yet. + return + } + logFn := log.Warn // Deactivated and enabled + if enable { + logFn = log.Info // Activated and enabled + } + logFn(fmt.Sprintf("%s artificial finality features", statusLog), logValues...) +} + +// IsArtificialFinalityEnabled returns the status of the blockchain's artificial +// finality feature setting. +// This status is agnostic of feature activation by chain configuration. +func (bc *BlockChain) IsArtificialFinalityEnabled() bool { + return atomic.LoadInt32(&bc.artificialFinalityEnabled) == 1 +} + +// getTDRatio is a helper function returning the total difficulty ratio of +// proposed over current chain segments. +func (bc *BlockChain) getTDRatio(commonAncestor, current, proposed *types.Header) float64 { + // Get the total difficulty ratio of the proposed chain segment over the existing one. + commonAncestorTD := bc.GetTd(commonAncestor.Hash(), commonAncestor.Number.Uint64()) + + proposedParentTD := bc.GetTd(proposed.ParentHash, proposed.Number.Uint64()-1) + proposedTD := new(big.Int).Add(proposed.Difficulty, proposedParentTD) + + localTD := bc.GetTd(current.Hash(), current.Number.Uint64()) + + tdRatio, _ := new(big.Float).Quo( + new(big.Float).SetInt(new(big.Int).Sub(proposedTD, commonAncestorTD)), + new(big.Float).SetInt(new(big.Int).Sub(localTD, commonAncestorTD)), + ).Float64() + return tdRatio +} + +// ecbp1100 implements the "MESS" artificial finality mechanism +// "Modified Exponential Subjective Scoring" used to prefer known chain segments +// over later-to-come counterparts, especially proposed segments stretching far into the past. +func (bc *BlockChain) ecbp1100(commonAncestor, current, proposed *types.Header) error { + + tdRatio := bc.getTDRatio(commonAncestor, current, proposed) + + // Time span diff. + // The minimum value is 1. + x := float64(proposed.Time - commonAncestor.Time) + + // Commented now is a potential way to "soften" the acceptance while + // still avoiding discrete acceptance boundaries. In the case that ecbp1100 introduces + // unacceptable network inefficiency, this (or something similar) may be an option. + // // Accept with diminishing probability in the case of equivalent total difficulty. + // // Remember that the equivalent total difficulty case has ALREADY + // // passed one coin toss. + // if tdRatio == 1 && rand.Float64() < (1/x) { + // return nil + // } + + antiGravity := ecbp1100AGSinusoidalA(x) + + if tdRatio < antiGravity { + // Using "b/a" here as "'B' chain vs. 'A' chain", where A is original (current), and B is proposed (new). + return fmt.Errorf(`%w: ECBP1100-MESS 🔒 status=rejected age=%v blocks=%d td.B/A=%0.6f < antigravity=%0.6f`, + errReorgFinality, + common.PrettyAge(time.Unix(int64(commonAncestor.Time), 0)), proposed.Number.Uint64()-commonAncestor.Number.Uint64(), + tdRatio, antiGravity, + ) + } + log.Info("ECBP1100-MESS 🔓", + "status", "accepted", + "age", common.PrettyAge(time.Unix(int64(commonAncestor.Time), 0)), + "blocks", proposed.Number.Uint64()-commonAncestor.Number.Uint64(), + "td.B/A", tdRatio, + "antigravity", antiGravity, + ) + return nil +} + +/* +ecbp1100AGSinusoidalA is a sinusoidal function. + +OPTION 3: Yet slower takeoff, yet steeper eventual ascent. Has a differentiable ceiling transition. +h(x)=15 sin((x+12000 π)/(8000))+15+1 + +*/ +func ecbp1100AGSinusoidalA(x float64) (antiGravity float64) { + ampl := float64(15) // amplitude + pDiv := float64(8000) // period divisor + phaseShift := math.Pi * (pDiv * 1.5) + peakX := math.Pi * pDiv // x value of first sin peak where x > 0 + if x > peakX { + // Cause the x value to limit to the x value of the first peak of the sin wave (ceiling). + x = peakX + } + return (ampl * math.Sin((x+phaseShift)/pDiv)) + ampl + 1 +} + +/* +ecbp1100AGExpB is an exponential function with x as a base (and rationalized exponent). + +OPTION 2: Slightly slower takeoff, steeper eventual ascent +g(x)=x^(x*0.00002) +*/ +func ecbp1100AGExpB(x float64) (antiGravity float64) { + return math.Pow(x, x*0.00002) +} + +/* +ecbp1100AGExpA is an exponential function with x as exponent. + +This was (one of?) Vitalik's "original" specs: +> 1.0001 ** (number of seconds between when S1 was received and when S2 was received) +- https://bitcointalk.org/index.php?topic=865169.msg16349234#msg16349234 +> gravity(B') = gravity(B) * 0.99 ^ n +- https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/ + +OPTION 1 (Original ESS) +f(x)=1.0001^(x) +*/ +func ecbp1100AGExpA(x float64) (antiGravity float64) { + return math.Pow(1.0001, x) +} diff --git a/core/blockchain_af_test.go b/core/blockchain_af_test.go new file mode 100644 index 0000000000..436ec1a9eb --- /dev/null +++ b/core/blockchain_af_test.go @@ -0,0 +1,329 @@ +package core + +import ( + "fmt" + "image/color" + "log" + "math" + "math/rand" + "testing" + + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" + "gonum.org/v1/plot" + "gonum.org/v1/plot/plotter" + "gonum.org/v1/plot/vg" + "gonum.org/v1/plot/vg/draw" +) + +var yuckyGlobalTestEnableMess = false + +func runMESSTest(t *testing.T, easyL, hardL, caN int, easyT, hardT int64) (hardHead bool, err error) { + // Generate the original common chain segment and the two competing forks + engine := ethash.NewFaker() + + db := rawdb.NewMemoryDatabase() + genesis := params.DefaultMessNetGenesisBlock() + genesisB := MustCommitGenesis(db, genesis) + + chain, err := NewBlockChain(db, nil, genesis.Config, engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatal(err) + } + defer chain.Stop() + chain.EnableArtificialFinality(yuckyGlobalTestEnableMess) + + easy, _ := GenerateChain(genesis.Config, genesisB, engine, db, easyL, func(i int, b *BlockGen) { + b.SetNonce(types.EncodeNonce(uint64(rand.Int63n(math.MaxInt64)))) + b.OffsetTime(easyT) + }) + commonAncestor := easy[caN-1] + hard, _ := GenerateChain(genesis.Config, commonAncestor, engine, db, hardL, func(i int, b *BlockGen) { + b.SetNonce(types.EncodeNonce(uint64(rand.Int63n(math.MaxInt64)))) + b.OffsetTime(hardT) + }) + + if _, err := chain.InsertChain(easy); err != nil { + t.Fatal(err) + } + _, err = chain.InsertChain(hard) + hardHead = chain.CurrentBlock().Hash() == hard[len(hard)-1].Hash() + return +} + +func TestBlockChain_AF_ECBP1100(t *testing.T) { + yuckyGlobalTestEnableMess = true + defer func() { + yuckyGlobalTestEnableMess = false + }() + + cases := []struct { + easyLen, hardLen, commonAncestorN int + easyOffset, hardOffset int64 + hardGetsHead, accepted bool + }{ + // Hard has insufficient total difficulty / length and is rejected. + { + 5000, 7500, 2500, + 50, -9, + false, false, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 1000, 7, 995, + 60, 0, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 1000, 7, 995, + 60, 7, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 1000, 1, 999, + 30, 1, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 3, 497, + 0, -8, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 4, 496, + 0, -9, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 5, 495, + 0, -9, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 6, 494, + 0, -9, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 7, 493, + 0, -9, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 8, 492, + 0, -9, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 9, 491, + 0, -9, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 12, 488, + 0, -9, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 20, 480, + 0, -9, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 40, 460, + 0, -9, + true, true, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 60, 440, + 0, -9, + true, true, + }, + // Hard has insufficient total difficulty / length and is rejected. + { + 500, 200, 300, + 0, -9, + false, false, + }, + // Hard has insufficient total difficulty / length and is rejected. + { + 500, 200, 300, + 7, -9, + false, false, + }, + // Hard has insufficient total difficulty / length and is rejected. + { + 500, 200, 300, + 17, -9, + false, false, + }, + // Hard has sufficient total difficulty / length and is accepted. + { + 500, 200, 300, + 47, -9, + true, true, + }, + // Hard has insufficient total difficulty / length and is rejected. + { + 500, 200, 300, + 47, -8, + false, false, + }, + // Hard has insufficient total difficulty / length and is rejected. + { + 500, 200, 300, + 17, -8, + false, false, + }, + // Hard has insufficient total difficulty / length and is rejected. + { + 500, 200, 300, + 7, -8, + false, false, + }, + // Hard has insufficient total difficulty / length and is rejected. + { + 500, 200, 300, + 0, -8, + false, false, + }, + // Hard has insufficient total difficulty / length and is rejected. + { + 500, 100, 400, + 0, -7, + false, false, + }, + // Hard is accepted, but does not have greater total difficulty, + // and is not set as the chain head. + { + 1000, 1, 900, + 60, -9, + false, true, + }, + // Hard is shorter, but sufficiently heavier chain, is accepted. + { + 500, 100, 390, + 60, -9, + true, true, + }, + } + + for i, c := range cases { + hardHead, err := runMESSTest(t, c.easyLen, c.hardLen, c.commonAncestorN, c.easyOffset, c.hardOffset) + if (err != nil && c.accepted) || (err == nil && !c.accepted) || (hardHead != c.hardGetsHead) { + t.Errorf("case=%d [easy=%d hard=%d ca=%d eo=%d ho=%d] want.accepted=%v want.hardHead=%v got.hardHead=%v err=%v", + i, + c.easyLen, c.hardLen, c.commonAncestorN, c.easyOffset, c.hardOffset, + c.accepted, c.hardGetsHead, hardHead, err) + } + } +} + +func TestBlockChain_GenerateMESSPlot(t *testing.T) { + t.Skip("This test plots graph of chain acceptance for visualization.") + + easyLen := 200 + maxHardLen := 100 + + generatePlot := func(title, fileName string) { + p, err := plot.New() + if err != nil { + log.Panic(err) + } + p.Title.Text = title + p.X.Label.Text = "Block Depth" + p.Y.Label.Text = "Relative Block Time Delta (10 seconds + y)" + + accepteds := plotter.XYs{} + rejecteds := plotter.XYs{} + sides := plotter.XYs{} + + for i := 1; i <= maxHardLen; i++ { + for j := -9; j <= 8; j++ { + fmt.Println("running", i, j) + hardHead, err := runMESSTest(t, easyLen, i, easyLen-i, 0, int64(j)) + point := plotter.XY{X: float64(i), Y: float64(j)} + if err == nil && hardHead { + accepteds = append(accepteds, point) + } else if err == nil && !hardHead { + sides = append(sides, point) + } else if err != nil { + rejecteds = append(rejecteds, point) + } + + if err != nil { + t.Log(err) + } + } + } + + scatterAccept, _ := plotter.NewScatter(accepteds) + scatterReject, _ := plotter.NewScatter(rejecteds) + scatterSide, _ := plotter.NewScatter(sides) + + pixelWidth := vg.Length(1000) + + scatterAccept.Color = color.RGBA{R: 152, G: 236, B: 161, A: 255} + scatterAccept.Shape = draw.BoxGlyph{} + scatterAccept.Radius = vg.Length((float64(pixelWidth) / float64(maxHardLen)) * 2 / 3) + scatterReject.Color = color.RGBA{R: 236, G: 106, B: 94, A: 255} + scatterReject.Shape = draw.BoxGlyph{} + scatterReject.Radius = vg.Length((float64(pixelWidth) / float64(maxHardLen)) * 2 / 3) + scatterSide.Color = color.RGBA{R: 190, G: 197, B: 236, A: 255} + scatterSide.Shape = draw.BoxGlyph{} + scatterSide.Radius = vg.Length((float64(pixelWidth) / float64(maxHardLen)) * 2 / 3) + + p.Add(scatterAccept) + p.Legend.Add("Accepted", scatterAccept) + p.Add(scatterReject) + p.Legend.Add("Rejected", scatterReject) + p.Add(scatterSide) + p.Legend.Add("Sidechained", scatterSide) + + p.Legend.YOffs = -30 + + err = p.Save(pixelWidth, 300, fileName) + if err != nil { + log.Panic(err) + } + } + yuckyGlobalTestEnableMess = true + defer func() { + yuckyGlobalTestEnableMess = false + }() + baseTitle := fmt.Sprintf("Accept/Reject Reorgs: Relative Time (Difficulty) over Proposed Segment Length (%d-block original chain)", easyLen) + generatePlot(baseTitle, "reorgs-MESS.png") + yuckyGlobalTestEnableMess = false + generatePlot("WITHOUT MESS: "+baseTitle, "reorgs-noMESS.png") +} + +func TestEcbp1100AGSinusoidalA(t *testing.T) { + cases := []struct { + in, out float64 + }{ + {0, 1}, + {25132, 31}, + } + tolerance := 0.0000001 + for i, c := range cases { + if got := ecbp1100AGSinusoidalA(c.in); got < c.out-tolerance || got > c.out+tolerance { + t.Fatalf("%d: in: %0.6f want: %0.6f got: %0.6f", i, c.in, c.out, got) + } + } +} diff --git a/core/blockchain_insert.go b/core/blockchain_insert.go index 5685b0a4bd..af36cd81cf 100644 --- a/core/blockchain_insert.go +++ b/core/blockchain_insert.go @@ -31,6 +31,7 @@ type insertStats struct { usedGas uint64 lastIndex int startTime mclock.AbsTime + artificialFinality bool } // statsReportLimit is the time limit during import and export after which we @@ -71,6 +72,10 @@ func (st *insertStats) report(chain []*types.Block, index int, dirty common.Stor if st.ignored > 0 { context = append(context, []interface{}{"ignored", st.ignored}...) } + if st.artificialFinality { + context = append(context, []interface{}{"af", st.artificialFinality}...) + } + log.Info("Imported new chain segment", context...) // Bump the stats reported to the next section diff --git a/eth/api.go b/eth/api.go index 6103ed4a04..689ce315f8 100644 --- a/eth/api.go +++ b/eth/api.go @@ -264,6 +264,30 @@ func (api *PrivateAdminAPI) ImportChain(file string) (bool, error) { return true, nil } +func (api *PrivateAdminAPI) Ecbp1100(blockNr rpc.BlockNumber) (bool, error) { + i := uint64(blockNr.Int64()) + err := api.eth.blockchain.Config().SetECBP1100Transition(&i) + return api.eth.blockchain.IsArtificialFinalityEnabled() && + api.eth.blockchain.Config().IsEnabled( + api.eth.blockchain.Config().GetECBP1100Transition, + api.eth.blockchain.CurrentBlock().Number()), err +} + +// MaxPeers sets the maximum peer limit for the protocol manager and the p2p server. +func (api *PrivateAdminAPI) MaxPeers(n int) (bool, error) { + api.eth.protocolManager.maxPeers = n + api.eth.p2pServer.MaxPeers = n + + for i := api.eth.protocolManager.peers.Len(); i > n; i = api.eth.protocolManager.peers.Len() { + p := api.eth.protocolManager.peers.WorstPeer() + if p == nil { + break + } + api.eth.protocolManager.removePeer(p.id) + } + return true, nil +} + // PublicDebugAPI is the collection of Ethereum full node APIs exposed // over the public debugging endpoint. type PublicDebugAPI struct { diff --git a/eth/handler.go b/eth/handler.go index 0b300f5d9a..6e8a0ed8cb 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -267,6 +267,10 @@ func (pm *ProtocolManager) Start(maxPeers int) { pm.wg.Add(2) go pm.chainSync.loop() go pm.txsyncLoop64() // TODO(karalabe): Legacy initial tx echange, drop with eth/64. + + // start artificial finality safety loop + pm.wg.Add(1) + go pm.artificialFinalitySafetyLoop() } func (pm *ProtocolManager) Stop() { diff --git a/eth/peer.go b/eth/peer.go index 21b82a19c5..b78208778c 100644 --- a/eth/peer.go +++ b/eth/peer.go @@ -809,6 +809,22 @@ func (ps *peerSet) BestPeer() *peer { return bestPeer } +func (ps *peerSet) WorstPeer() *peer { + ps.lock.RLock() + defer ps.lock.RUnlock() + + var ( + worstPeer *peer + worstTD *big.Int + ) + for _, p := range ps.peers { + if _, td := p.Head(); worstPeer == nil || td.Cmp(worstTD) < 0 { + worstPeer, worstTD = p, td + } + } + return worstPeer +} + // Close disconnects all peers. // No new peers can be registered after Close has returned. func (ps *peerSet) Close() { diff --git a/eth/sync.go b/eth/sync.go index 26badd1e21..da9456d8c9 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/params/vars" ) const ( @@ -39,11 +40,60 @@ const ( txsyncPackSize = 100 * 1024 ) +var ( + // minArtificialFinalityPeers defines the minimum number of peers our node must be connected + // to in order to enable artificial finality features. + // A minimum number of peer connections mitigates the risk of lower-powered eclipse attacks. + minArtificialFinalityPeers = defaultMinSyncPeers * 2 + + // artificialFinalitySafetyInterval defines the interval at which the local head is checked for staleness. + // If the head is found to be stale across this interval, artificial finality features are disabled. + // This prevents an abandoned victim of an eclipse attack from being forever destitute. + artificialFinalitySafetyInterval = time.Second * time.Duration(10*vars.DurationLimit.Uint64()) +) + type txsync struct { p *peer txs []*types.Transaction } +// artificialFinalitySafetyLoop compares our local head across timer intervals. +// If it changes, assuming the interval is sufficiently long, +// it means we're syncing ok: there has been a steady flow of blocks. +// If it doesn't change, it means that we've stalled syncing for some reason, +// and should disable the permapoint feature in case that's keeping +// us on a dead chain. +func (pm *ProtocolManager) artificialFinalitySafetyLoop() { + defer pm.wg.Done() + + t := time.NewTicker(artificialFinalitySafetyInterval) + defer t.Stop() + + var lastHead uint64 + + for { + select { + case <-t.C: + if pm.blockchain.IsArtificialFinalityEnabled() { + // Get the latest header we have. + n := pm.blockchain.CurrentHeader().Number.Uint64() + // If it has changed, we haven't gone stale or dark. + if lastHead != n { + lastHead = n + continue + } + // Else, it hasn't changed, which means we've been at the same + // header for the whole timer interval time. + pm.blockchain.EnableArtificialFinality(false, "reason", "stale safety interval", "interval", artificialFinalitySafetyInterval) + } else { + lastHead = 0 // reset + } + case <-pm.quitSync: + return + } + } +} + // syncTransactions starts sending all currently pending transactions to the given peer. func (pm *ProtocolManager) syncTransactions(p *peer) { // Assemble the set of transaction to broadcast or announce to the remote @@ -248,6 +298,11 @@ func (cs *chainSyncer) nextSyncOp() *chainSyncOp { } else if minPeers > cs.pm.maxPeers { minPeers = cs.pm.maxPeers } + if cs.pm.peers.Len() < minArtificialFinalityPeers { + if cs.pm.blockchain.IsArtificialFinalityEnabled() { + cs.pm.blockchain.EnableArtificialFinality(false, "reason", "low peers", "peers", cs.pm.peers.Len()) + } + } if cs.pm.peers.Len() < minPeers { return nil } @@ -260,6 +315,12 @@ func (cs *chainSyncer) nextSyncOp() *chainSyncOp { mode, ourTD := cs.modeAndLocalHead() op := peerToSyncOp(mode, peer) if op.td.Cmp(ourTD) <= 0 { + // Enable artificial finality if parameters if should. + if op.mode == downloader.FullSync && + cs.pm.peers.Len() >= minArtificialFinalityPeers && + !cs.pm.blockchain.IsArtificialFinalityEnabled() { + cs.pm.blockchain.EnableArtificialFinality(true, "reason", "synced", "peers", cs.pm.peers.Len()) + } return nil // We're in sync. } return op diff --git a/go.mod b/go.mod index 92ddfbb6e5..2ad05faa3a 100755 --- a/go.mod +++ b/go.mod @@ -69,6 +69,8 @@ require ( golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 golang.org/x/text v0.3.3 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 + gonum.org/v1/plot v0.8.0 + gonum.org/v1/gonum v0.8.1 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 gopkg.in/urfave/cli.v1 v1.20.0 diff --git a/go.sum b/go.sum index 4de62984bd..dd5a97ad3c 100755 --- a/go.sum +++ b/go.sum @@ -11,6 +11,7 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +gioui.org v0.0.0-20200628203458-851255f7a67b/go.mod h1:jiUwifN9cRl/zmco43aAqh0aV+s9GbhG13KcD+gEpkU= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= @@ -41,9 +42,10 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrU github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw= github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af h1:wVe6/Ea46ZMeNkQjjBW6xcqyQA/j5e0D6GytH95g0gQ= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A= github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= @@ -57,6 +59,7 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= @@ -90,7 +93,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= @@ -105,18 +107,21 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc h1:jtW8jbpkO4YirRSyepBOH8E+2HEw6/hKkBvFPwhUN8c= github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-latex/latex v0.0.0-20200518072620-0806b477ea35 h1:uroDDLmuCK5Pz5J/Ef5vCL6F0sJmAtZFTm0/cF027F4= +github.com/go-latex/latex v0.0.0-20200518072620-0806b477ea35/go.mod h1:PNI+CcWytn/2Z/9f1SGOOYn0eILruVyp0v2/iAs8asQ= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= @@ -127,8 +132,9 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-test/deep v1.0.5 h1:AKODKU3pDH1RzZzm6YZu77YWtEAq6uh1rLIAQlay2qc= github.com/go-test/deep v1.0.5/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -152,7 +158,6 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -160,7 +165,6 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -214,24 +218,23 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22 github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5PtRc= +github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= @@ -267,7 +270,6 @@ github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hz github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= @@ -276,11 +278,9 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -291,6 +291,7 @@ github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -316,15 +317,14 @@ github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9Ac github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521 h1:3hxavr+IHMsQBrYUPQM5v0CgENFktkkbg1sfpgM3h20= github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shirou/gopsutil v2.20.5+incompatible h1:tYH07UPoQt0OCQdgWWMgYHy3/a9bcxNpBIysykNIP7I= github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -386,13 +386,23 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 h1:A1gGSx58LAGVHUUsOf7IiR0u8Xb6W51gRwfDBhkdcaw= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519 h1:1e2ufUJNM3lCHEY5jIgac/7UTjd6cgJNdatjPdFWf34= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -452,6 +462,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -466,8 +477,10 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -480,12 +493,19 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.1 h1:wGtP3yGpc5mCLOLeTeBdjeui9oZSz5De0eOjMLC/QuQ= +gonum.org/v1/gonum v0.8.1/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.8.0 h1:dNgubmltsMoehfn6XgbutHpicbUfbkcGSxkICy1bC4o= +gonum.org/v1/plot v0.8.0/go.mod h1:3GH8dTfoceRTELDnv+4HNwbvM/eMfdDUGHFG2bo3NeE= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -517,7 +537,6 @@ google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyz google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -528,7 +547,6 @@ gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHN gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= @@ -538,10 +556,10 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index c6057f66d2..872ec40e88 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -181,6 +181,16 @@ web3._extend({ call: 'admin_importChain', params: 1 }), + new web3._extend.Method({ + name: 'ecbp1100', + call: 'admin_ecbp1100', + params: 1 + }), + new web3._extend.Method({ + name: 'maxPeers', + call: 'admin_maxPeers', + params: 1 + }), new web3._extend.Method({ name: 'sleepBlocks', call: 'admin_sleepBlocks', diff --git a/params/config_classic.go b/params/config_classic.go index 33cc1c356b..d3ca6d8efa 100644 --- a/params/config_classic.go +++ b/params/config_classic.go @@ -19,8 +19,10 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/params/types/coregeth" "github.com/ethereum/go-ethereum/params/types/ctypes" + "github.com/ethereum/go-ethereum/params/types/genesisT" ) var ( @@ -73,6 +75,7 @@ var ( ECIP1017EraRounds: big.NewInt(5000000), ECIP1010PauseBlock: big.NewInt(3000000), ECIP1010Length: big.NewInt(2000000), + ECBP1100FBlock: nil, // big.NewInt(11295300), // Tentative: ETA 28 Sept 2020, ~1500 UTC RequireBlockHashes: map[uint64]common.Hash{ 1920000: common.HexToHash("0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f"), 2500000: common.HexToHash("0xca12c63534f565899681965528d536c52cb05b7c48e269c2a6cb77ad864d878a"), @@ -82,4 +85,75 @@ var ( DisinflationRateQuotient = big.NewInt(4) // Disinflation rate quotient for ECIP1017 DisinflationRateDivisor = big.NewInt(5) // Disinflation rate divisor for ECIP1017 ExpDiffPeriod = big.NewInt(100000) // Exponential diff period for diff bomb & ECIP1010 + + MessNetConfig = &coregeth.CoreGethChainConfig{ + NetworkID: 6161, + Ethash: new(ctypes.EthashConfig), + ChainID: big.NewInt(6161), + + EIP2FBlock: big.NewInt(1), + EIP7FBlock: big.NewInt(1), + + DAOForkBlock: nil, + + EIP150Block: big.NewInt(2), + + EIP155Block: big.NewInt(3), + EIP160FBlock: big.NewInt(3), + + // EIP158~ + EIP161FBlock: big.NewInt(8), + EIP170FBlock: big.NewInt(8), + + // Byzantium eq + EIP100FBlock: big.NewInt(8), + EIP140FBlock: big.NewInt(8), + EIP198FBlock: big.NewInt(8), + EIP211FBlock: big.NewInt(8), + EIP212FBlock: big.NewInt(8), + EIP213FBlock: big.NewInt(8), + EIP214FBlock: big.NewInt(8), + EIP658FBlock: big.NewInt(8), + + // Constantinople eq, aka Agharta + EIP145FBlock: big.NewInt(9), + EIP1014FBlock: big.NewInt(9), + EIP1052FBlock: big.NewInt(9), + + // Istanbul eq, aka Phoenix + // ECIP-1088 + EIP152FBlock: big.NewInt(10), + EIP1108FBlock: big.NewInt(10), + EIP1344FBlock: big.NewInt(10), + EIP1884FBlock: big.NewInt(10), + EIP2028FBlock: big.NewInt(10), + EIP2200FBlock: big.NewInt(10), // RePetersburg (=~ re-1283) + + DisposalBlock: big.NewInt(5), + ECIP1017FBlock: big.NewInt(5), + ECIP1017EraRounds: big.NewInt(5000), + ECIP1010PauseBlock: big.NewInt(3), + ECIP1010Length: big.NewInt(2), + ECBP1100FBlock: big.NewInt(11), + } ) + +func DefaultMessNetGenesisBlock() *genesisT.Genesis { + return &genesisT.Genesis{ + Config: MessNetConfig, + Timestamp: 1598650845, + ExtraData: hexutil.MustDecode("0x4235353535353535353535353535353535353535353535353535353535353535"), + GasLimit: 10485760, + Difficulty: big.NewInt(37103392657464), + 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 + }, + } +} diff --git a/params/config_mordor.go b/params/config_mordor.go index 623a0cb0f8..1198de55ac 100644 --- a/params/config_mordor.go +++ b/params/config_mordor.go @@ -71,6 +71,7 @@ var ( ECIP1017EraRounds: big.NewInt(2000000), ECIP1010PauseBlock: nil, ECIP1010Length: nil, + ECBP1100FBlock: big.NewInt(2290740), // ETA 15 Sept 2020, ~1500 UTC RequireBlockHashes: map[uint64]common.Hash{ 840013: common.HexToHash("0x2ceada2b191879b71a5bcf2241dd9bc50d6d953f1640e62f9c2cee941dc61c9d"), 840014: common.HexToHash("0x8ec29dd692c8985b82410817bac232fc82805b746538d17bc924624fe74a0fcf"), diff --git a/params/confp/configurator.go b/params/confp/configurator.go index 6266caea3b..942d154be0 100644 --- a/params/confp/configurator.go +++ b/params/confp/configurator.go @@ -21,12 +21,31 @@ import ( "math" "math/big" "reflect" + "regexp" "sort" "strings" "github.com/ethereum/go-ethereum/params/types/ctypes" ) +var ( + // compatibleProtocolNameSchemes define matchable naming schemes used by configuration methods + // that are not incompatible with configuration either having or lacking them. + compatibleProtocolNameSchemes = []string{ + "ECBP", // "Ethereum Classic Best Practice" + "EBP", // "Ethereum Best Practice" + } +) + +func nameSignalsCompatibility(name string) bool { + for _, s := range compatibleProtocolNameSchemes { + if regexp.MustCompile(s).MatchString(name) { + return true + } + } + return false +} + // ConfigCompatError is raised if the locally-stored blockchain is initialised with a // ChainConfig that would alter the past. type ConfigCompatError struct { @@ -133,6 +152,11 @@ func compatible(head *uint64, a, b ctypes.ChainConfigurator) *ConfigCompatError aFns, aNames := Transitions(a) bFns, _ := Transitions(b) for i, afn := range aFns { + // Skip cross-compatible namespaced transition names, assuming + // these will not be enforced as hardforks. + if nameSignalsCompatibility(aNames[i]) { + continue + } if err := func(c1, c2, head *uint64) *ConfigCompatError { if isForkIncompatible(c1, c2, head) { return NewCompatError("incompatible fork value: "+aNames[i], c1, c2) @@ -252,8 +276,13 @@ func Forks(conf ctypes.ChainConfigurator) []uint64 { var forks []uint64 var forksM = make(map[uint64]struct{}) // Will key for uniqueness as fork numbers are appended to slice. - transitions, _ := Transitions(conf) - for _, tr := range transitions { + transitions, names := Transitions(conf) + for i, tr := range transitions { + // Skip cross-compatible namespaced transition names, assuming + // these will not be enforced as hardforks. + if nameSignalsCompatibility(names[i]) { + continue + } // Extract the fork rule block number and aggregate it response := tr() if response == nil || diff --git a/params/types/coregeth/chain_config.go b/params/types/coregeth/chain_config.go index 9ff554b1a5..4f934c7745 100644 --- a/params/types/coregeth/chain_config.go +++ b/params/types/coregeth/chain_config.go @@ -173,6 +173,8 @@ type CoreGethChainConfig struct { ECIP1017EraRounds *big.Int `json:"ecip1017EraRounds,omitempty"` // ECIP1017 era rounds ECIP1080FBlock *big.Int `json:"ecip1080FBlock,omitempty"` + ECBP1100FBlock *big.Int `json:"ecbp1100FBlock,omitempty"` // ECBP1100:MESS artificial finality + DisposalBlock *big.Int `json:"disposalBlock,omitempty"` // Bomb disposal HF block SocialBlock *big.Int `json:"socialBlock,omitempty"` // Ethereum Social Reward block EthersocialBlock *big.Int `json:"ethersocialBlock,omitempty"` // Ethersocial Reward block diff --git a/params/types/coregeth/chain_config_configurator.go b/params/types/coregeth/chain_config_configurator.go index cd20e5da2f..af4ea10f55 100644 --- a/params/types/coregeth/chain_config_configurator.go +++ b/params/types/coregeth/chain_config_configurator.go @@ -381,6 +381,15 @@ func (c *CoreGethChainConfig) SetEIP2537Transition(n *uint64) error { return nil } +func (c *CoreGethChainConfig) GetECBP1100Transition() *uint64 { + return bigNewU64(c.ECBP1100FBlock) +} + +func (c *CoreGethChainConfig) SetECBP1100Transition(n *uint64) error { + c.ECBP1100FBlock = setBig(c.ECBP1100FBlock, n) + return nil +} + func (c *CoreGethChainConfig) IsEnabled(fn func() *uint64, n *big.Int) bool { f := fn() if f == nil || n == nil { diff --git a/params/types/ctypes/configurator_iface.go b/params/types/ctypes/configurator_iface.go index e3ff71a2b1..2abb0e56c5 100644 --- a/params/types/ctypes/configurator_iface.go +++ b/params/types/ctypes/configurator_iface.go @@ -130,6 +130,8 @@ type ProtocolSpecifier interface { SetEIP1706Transition(n *uint64) error GetEIP2537Transition() *uint64 SetEIP2537Transition(n *uint64) error + GetECBP1100Transition() *uint64 + SetECBP1100Transition(n *uint64) error } type Forker interface { diff --git a/params/types/genesisT/genesis.go b/params/types/genesisT/genesis.go index ee5b1096ac..9c97f454a2 100644 --- a/params/types/genesisT/genesis.go +++ b/params/types/genesisT/genesis.go @@ -528,22 +528,30 @@ func (g *Genesis) SetECIP1080Transition(n *uint64) error { return g.Config.SetECIP1080Transition(n) } -func (g Genesis) GetEIP1706Transition() *uint64 { +func (g *Genesis) GetEIP1706Transition() *uint64 { return g.Config.GetEIP1706Transition() } -func (g Genesis) SetEIP1706Transition(n *uint64) error { +func (g *Genesis) SetEIP1706Transition(n *uint64) error { return g.Config.SetEIP1706Transition(n) } -func (g Genesis) GetEIP2537Transition() *uint64 { +func (g *Genesis) GetEIP2537Transition() *uint64 { return g.Config.GetEIP2537Transition() } -func (g Genesis) SetEIP2537Transition(n *uint64) error { +func (g *Genesis) SetEIP2537Transition(n *uint64) error { return g.Config.SetEIP2537Transition(n) } +func (g *Genesis) GetECBP1100Transition() *uint64 { + return g.Config.GetECBP1100Transition() +} + +func (g *Genesis) SetECBP1100Transition(n *uint64) error { + return g.Config.SetECBP1100Transition(n) +} + func (g *Genesis) IsEnabled(fn func() *uint64, n *big.Int) bool { return g.Config.IsEnabled(fn, n) } diff --git a/params/types/goethereum/goethereum_configurator.go b/params/types/goethereum/goethereum_configurator.go index 2ae8c64a98..7a526b1ade 100644 --- a/params/types/goethereum/goethereum_configurator.go +++ b/params/types/goethereum/goethereum_configurator.go @@ -391,6 +391,17 @@ func (c *ChainConfig) SetEIP2537Transition(n *uint64) error { return nil } +func (c *ChainConfig) GetECBP1100Transition() *uint64 { + return nil +} + +func (c *ChainConfig) SetECBP1100Transition(n *uint64) error { + if n == nil { + return nil + } + return ctypes.ErrUnsupportedConfigFatal +} + func (c *ChainConfig) IsEnabled(fn func() *uint64, n *big.Int) bool { f := fn() if f == nil || n == nil { diff --git a/params/types/multigeth/multigethv0_chain_config_configurator.go b/params/types/multigeth/multigethv0_chain_config_configurator.go index 46e02e63e7..bf3ed07972 100644 --- a/params/types/multigeth/multigethv0_chain_config_configurator.go +++ b/params/types/multigeth/multigethv0_chain_config_configurator.go @@ -416,6 +416,17 @@ func (c *ChainConfig) SetEIP2537Transition(n *uint64) error { return ctypes.ErrUnsupportedConfigFatal } +func (c *ChainConfig) GetECBP1100Transition() *uint64 { + return nil +} + +func (c *ChainConfig) SetECBP1100Transition(n *uint64) error { + if n == nil { + return nil + } + return ctypes.ErrUnsupportedConfigFatal +} + func (c *ChainConfig) IsEnabled(fn func() *uint64, n *big.Int) bool { f := fn() if f == nil || n == nil { diff --git a/params/types/parity/parity_configurator.go b/params/types/parity/parity_configurator.go index 2b135a5b1b..673e1b0be7 100644 --- a/params/types/parity/parity_configurator.go +++ b/params/types/parity/parity_configurator.go @@ -624,6 +624,17 @@ func (spec *ParityChainSpec) SetEIP2537Transition(n *uint64) error { return nil } +func (spec *ParityChainSpec) GetECBP1100Transition() *uint64 { + return nil +} + +func (spec *ParityChainSpec) SetECBP1100Transition(n *uint64) error { + if n == nil { + return nil + } + return ctypes.ErrUnsupportedConfigFatal +} + func (spec *ParityChainSpec) IsEnabled(fn func() *uint64, n *big.Int) bool { f := fn() if f == nil || n == nil { diff --git a/params/version.go b/params/version.go index a5ad6b8ebe..7adb7c6c68 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 11 // Minor version component of the current release - VersionPatch = 14 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 11 // Minor version component of the current release + VersionPatch = 14 // Patch version component of the current release + VersionMeta = "rc-messnet-2+" // Version metadata to append to the version string VersionName = "CoreGeth" )