diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 15122f2982a8d..499f320f64327 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -27,17 +27,10 @@ import ( "net/http" "os" "path/filepath" - "strings" "time" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/contracts/registrar/contract" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/core/vm/runtime" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) @@ -140,65 +133,6 @@ func (w *wizard) makeGenesis() { fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)") genesis.Config.ChainID = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536)))) - // Query the user for checkpoint contract config - fmt.Println() - fmt.Println("Should a checkpoint contract be deployed (y/n)? (default = no)") - if w.readDefaultYesNo(false) { - // Read the addresses of the trusted signers - fmt.Println("Which accounts should be trusted signers? (mandatory at least one)") - var ( - signers []common.Address - threshold uint64 - ) - // Get trusted signer addresses - for { - if address := w.readAddress(); address != nil { - signers = append(signers, *address) - continue - } - if len(signers) == 0 { - continue - } - break - } - // Read the checkpoint signature threshold - for { - fmt.Printf("What is the minimal approval threshold (maximum %d)?\n", len(signers)) - threshold = uint64(w.readInt()) - if threshold <= 0 || threshold > uint64(len(signers)) { - log.Error(fmt.Sprintf("Invalid approval threshold, please enter in range [1, %d]\n", len(signers))) - continue - } - break - } - parsed, err := abi.JSON(strings.NewReader(contract.ContractABI)) - if err != nil { - log.Crit("Parse contract ABI failed", "err", err) - } - input, err := parsed.Pack("", signers, big.NewInt(params.CheckpointFrequency), big.NewInt(params.CheckpointProcessConfirmations), new(big.Int).SetUint64(threshold)) - if err != nil { - log.Crit("Pack contract constructor arguments failed", "err", err) - } - config := &runtime.Config{GasLimit: math.MaxInt64} - config.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) - code, address, _, err := runtime.Create(append(common.FromHex(contract.ContractBin), input...), config) - if err != nil { - log.Crit("Execute contract constructor failed", "err", err) - } - config.State.Commit(true) - genesis.Alloc[address] = core.GenesisAccount{Code: code, Storage: make(map[common.Hash]common.Hash), Balance: big.NewInt(1)} - if err = config.State.ForEachStorage(address, func(key, value common.Hash) bool { - genesis.Alloc[address].Storage[key] = value - return true - }); err != nil { - log.Crit("Failed to iterate contract storage", "err", err) - } - genesis.Config.CheckpointConfig = ¶ms.CheckpointContractConfig{ - Address: address, - Signers: signers, - Threshold: threshold, - } - } // All done, store the genesis and flush to disk log.Info("Configured new genesis block") @@ -296,77 +230,6 @@ func (w *wizard) manageGenesis() { fmt.Printf("Which block should Petersburg come into effect? (default = %v)\n", w.conf.Genesis.Config.PetersburgBlock) w.conf.Genesis.Config.PetersburgBlock = w.readDefaultBigInt(w.conf.Genesis.Config.PetersburgBlock) - // The registrar contract might have been deployed - fmt.Println() - fmt.Printf("Should a checkpoint contract be active (y/n)? (default = %v)\n", w.conf.Genesis.Config.CheckpointConfig != nil) - if !w.readDefaultYesNo(w.conf.Genesis.Config.CheckpointConfig != nil) { - w.conf.Genesis.Config.CheckpointConfig = nil - } else { - // Make sure we have a checkpoint config to fill out - checkpoint := w.conf.Genesis.Config.CheckpointConfig - if checkpoint == nil { - checkpoint = new(params.CheckpointContractConfig) - } - // Read the Ethereum address of the deployed contract - fmt.Println() - if checkpoint.Address == (common.Address{}) { - fmt.Printf("Which address does the checkpoint contract reside at?\n") - for checkpoint.Address == (common.Address{}) { - if address := w.readAddress(); address != nil { - checkpoint.Address = *address - } - } - } else { - fmt.Printf("Which address does the checkpoint contract reside at? (default = %s)\n", checkpoint.Address.Hex()) - checkpoint.Address = w.readDefaultAddress(checkpoint.Address) - } - // Read the addresses of the trusted signers - if len(checkpoint.Signers) > 0 { - signers := make([]string, len(checkpoint.Signers)) - for i, signer := range checkpoint.Signers { - signers[i] = signer.Hex() - } - fmt.Println() - fmt.Printf("Keep existing list of authorized signers %s? (default = yes)\n", strings.Join(signers, ",")) - if !w.readDefaultYesNo(true) { - checkpoint.Signers = nil - } - } - if len(checkpoint.Signers) == 0 { - fmt.Println() - fmt.Println("Which accounts should be trusted signers? (mandatory at least one)") - for { - if address := w.readAddress(); address != nil { - checkpoint.Signers = append(checkpoint.Signers, *address) - continue - } - if len(checkpoint.Signers) == 0 { - continue - } - break - } - } - // Read the checkpoint signature threshold - fmt.Println() - if checkpoint.Threshold == 0 { - fmt.Printf("What is the minimal approval threshold (maximum %d)?\n", len(checkpoint.Signers)) - } else { - fmt.Printf("What is the minimal approval threshold (maximum %d)? (default = %d)\n", len(checkpoint.Signers), checkpoint.Threshold) - } - for { - if checkpoint.Threshold == 0 { - checkpoint.Threshold = uint64(w.readInt()) - } else { - checkpoint.Threshold = uint64(w.readDefaultInt(int(checkpoint.Threshold))) - } - if checkpoint.Threshold <= 0 || checkpoint.Threshold > uint64(len(checkpoint.Signers)) { - log.Error(fmt.Sprintf("Invalid approval threshold, please enter in range [1, %d]\n", len(checkpoint.Signers))) - continue - } - break - } - w.conf.Genesis.Config.CheckpointConfig = checkpoint - } out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", " ") fmt.Printf("Chain configuration updated:\n\n%s\n", out) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 973e47ea0cc57..fc8f222b33f22 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1451,16 +1451,28 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { cfg.NetworkId = 3 } cfg.Genesis = core.DefaultTestnetGenesisBlock() + if cfg.Checkpoint == nil { + cfg.Checkpoint = params.TestnetTrustedCheckpoint + } case ctx.GlobalBool(RinkebyFlag.Name): if !ctx.GlobalIsSet(NetworkIdFlag.Name) { cfg.NetworkId = 4 } cfg.Genesis = core.DefaultRinkebyGenesisBlock() + if cfg.Checkpoint == nil { + cfg.Checkpoint = params.RinkebyTrustedCheckpoint + } + if cfg.CheckpointConfig == nil { + cfg.CheckpointConfig = params.RinkebyCheckpointConfig // Enable checkpoint contract for rinkeby testnet. + } case ctx.GlobalBool(GoerliFlag.Name): if !ctx.GlobalIsSet(NetworkIdFlag.Name) { cfg.NetworkId = 5 } cfg.Genesis = core.DefaultGoerliGenesisBlock() + if cfg.Checkpoint == nil { + cfg.Checkpoint = params.GoerliTrustedCheckpoint + } case ctx.GlobalBool(DeveloperFlag.Name): if !ctx.GlobalIsSet(NetworkIdFlag.Name) { cfg.NetworkId = 1337 diff --git a/eth/backend.go b/eth/backend.go index 3b8b4853383c9..8a4e1fc4e3203 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -202,7 +202,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { // Permit the downloader to use the trie cache allowance during fast sync cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit - if eth.protocolManager, err = NewProtocolManager(chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, cacheLimit, config.Whitelist); err != nil { + if eth.protocolManager, err = NewProtocolManager(chainConfig, config.Checkpoint, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, cacheLimit, config.Whitelist); err != nil { return nil, err } eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock) diff --git a/eth/config.go b/eth/config.go index ccd5674a74bc2..144638c9f25f1 100644 --- a/eth/config.go +++ b/eth/config.go @@ -60,6 +60,7 @@ var DefaultConfig = Config{ Blocks: 20, Percentile: 60, }, + Checkpoint: params.MainnetTrustedCheckpoint, } func init() { @@ -149,4 +150,10 @@ type Config struct { // RPCGasCap is the global gas cap for eth-call variants. RPCGasCap *big.Int `toml:",omitempty"` + + // Checkpoint is a hardcoded checkpoint which can be nil. + Checkpoint *params.TrustedCheckpoint + + // CheckpointConfig is a set of checkpoint contract configs. + CheckpointConfig *params.CheckpointContractConfig } diff --git a/eth/gen_config.go b/eth/gen_config.go index 178faf7cb7942..2d1dd2483c6f9 100644 --- a/eth/gen_config.go +++ b/eth/gen_config.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/miner" + "github.com/ethereum/go-ethereum/params" ) // MarshalTOML marshals as TOML. @@ -32,6 +33,7 @@ func (c Config) MarshalTOML() (interface{}, error) { SkipBcVersionCheck bool `toml:"-"` DatabaseHandles int `toml:"-"` DatabaseCache int + DatabaseFreezer string TrieCleanCache int TrieDirtyCache int TrieTimeout time.Duration @@ -45,6 +47,8 @@ func (c Config) MarshalTOML() (interface{}, error) { EVMInterpreter string ConstantinopleOverride *big.Int RPCGasCap *big.Int `toml:",omitempty"` + Checkpoint *params.TrustedCheckpoint + CheckpointConfig *params.CheckpointContractConfig } var enc Config enc.Genesis = c.Genesis @@ -62,6 +66,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.SkipBcVersionCheck = c.SkipBcVersionCheck enc.DatabaseHandles = c.DatabaseHandles enc.DatabaseCache = c.DatabaseCache + enc.DatabaseFreezer = c.DatabaseFreezer enc.TrieCleanCache = c.TrieCleanCache enc.TrieDirtyCache = c.TrieDirtyCache enc.TrieTimeout = c.TrieTimeout @@ -75,6 +80,8 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.EVMInterpreter = c.EVMInterpreter enc.ConstantinopleOverride = c.ConstantinopleOverride enc.RPCGasCap = c.RPCGasCap + enc.Checkpoint = c.Checkpoint + enc.CheckpointConfig = c.CheckpointConfig return &enc, nil } @@ -96,6 +103,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { SkipBcVersionCheck *bool `toml:"-"` DatabaseHandles *int `toml:"-"` DatabaseCache *int + DatabaseFreezer *string TrieCleanCache *int TrieDirtyCache *int TrieTimeout *time.Duration @@ -109,6 +117,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { EVMInterpreter *string ConstantinopleOverride *big.Int RPCGasCap *big.Int `toml:",omitempty"` + Checkpoint *params.TrustedCheckpoint + CheckpointConfig *params.CheckpointContractConfig } var dec Config if err := unmarshal(&dec); err != nil { @@ -159,6 +169,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.DatabaseCache != nil { c.DatabaseCache = *dec.DatabaseCache } + if dec.DatabaseFreezer != nil { + c.DatabaseFreezer = *dec.DatabaseFreezer + } if dec.TrieCleanCache != nil { c.TrieCleanCache = *dec.TrieCleanCache } @@ -198,5 +211,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.RPCGasCap != nil { c.RPCGasCap = dec.RPCGasCap } + if dec.Checkpoint != nil { + c.Checkpoint = dec.Checkpoint + } + if dec.CheckpointConfig != nil { + c.CheckpointConfig = dec.CheckpointConfig + } return nil } diff --git a/eth/handler.go b/eth/handler.go index 58add2eafcb70..8e295a83680ac 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -106,7 +106,7 @@ type ProtocolManager struct { // NewProtocolManager returns a new Ethereum sub protocol manager. The Ethereum sub protocol manages peers capable // with the Ethereum network. -func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database, cacheLimit int, whitelist map[uint64]common.Hash) (*ProtocolManager, error) { +func NewProtocolManager(config *params.ChainConfig, checkpoint *params.TrustedCheckpoint, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database, cacheLimit int, whitelist map[uint64]common.Hash) (*ProtocolManager, error) { // Create the protocol manager with the base fields manager := &ProtocolManager{ networkID: networkID, @@ -126,7 +126,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne manager.fastSync = uint32(1) } // If we have trusted checkpoints, enforce them on the chain - if checkpoint, ok := params.TrustedCheckpoints[blockchain.Genesis().Hash()]; ok { + if checkpoint != nil { manager.checkpointNumber = (checkpoint.SectionIndex+1)*params.CHTFrequency - 1 manager.checkpointHash = checkpoint.SectionHead } diff --git a/eth/handler_test.go b/eth/handler_test.go index 04831e4dc6597..cfda0b43b0aa2 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -504,31 +504,30 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo // Initialize a chain and generate a fake CHT if checkpointing is enabled var ( - db = rawdb.NewMemoryDatabase() - config = new(params.ChainConfig) - genesis = (&core.Genesis{Config: config}).MustCommit(db) + db = rawdb.NewMemoryDatabase() + config = new(params.ChainConfig) ) + (&core.Genesis{Config: config}).MustCommit(db) // Commit genesis block // If checkpointing is enabled, create and inject a fake CHT and the corresponding // chllenge response. var response *types.Header + var cht *params.TrustedCheckpoint if checkpoint { index := uint64(rand.Intn(500)) number := (index+1)*params.CHTFrequency - 1 response = &types.Header{Number: big.NewInt(int64(number)), Extra: []byte("valid")} - cht := ¶ms.TrustedCheckpoint{ + cht = ¶ms.TrustedCheckpoint{ SectionIndex: index, SectionHead: response.Hash(), } - params.TrustedCheckpoints[genesis.Hash()] = cht - defer delete(params.TrustedCheckpoints, genesis.Hash()) } // Create a checkpoint aware protocol manager blockchain, err := core.NewBlockChain(db, nil, config, ethash.NewFaker(), vm.Config{}, nil) if err != nil { t.Fatalf("failed to create new blockchain: %v", err) } - pm, err := NewProtocolManager(config, syncmode, DefaultConfig.NetworkId, new(event.TypeMux), new(testTxPool), ethash.NewFaker(), blockchain, db, 1, nil) + pm, err := NewProtocolManager(config, cht, syncmode, DefaultConfig.NetworkId, new(event.TypeMux), new(testTxPool), ethash.NewFaker(), blockchain, db, 1, nil) if err != nil { t.Fatalf("failed to start test protocol manager: %v", err) } @@ -615,7 +614,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) { if err != nil { t.Fatalf("failed to create new blockchain: %v", err) } - pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, 1, nil) + pm, err := NewProtocolManager(config, nil, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, 1, nil) if err != nil { t.Fatalf("failed to start test protocol manager: %v", err) } diff --git a/eth/helper_test.go b/eth/helper_test.go index 27e7189ed9ffe..1482e99c4e107 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -66,7 +66,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func if _, err := blockchain.InsertChain(chain); err != nil { panic(err) } - pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db, 1, nil) + pm, err := NewProtocolManager(gspec.Config, nil, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db, 1, nil) if err != nil { return nil, nil, err } diff --git a/les/backend.go b/les/backend.go index 71a42f814ea60..6867ff11812ec 100644 --- a/les/backend.go +++ b/les/backend.go @@ -126,7 +126,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { // Note: NewLightChain adds the trusted checkpoint so it needs an ODR with // indexers already set but not started yet - if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine); err != nil { + if leth.blockchain, err = light.NewLightChain(leth.odr, leth.chainConfig, leth.engine, config.Checkpoint); err != nil { return nil, err } // Note: AddChildIndexer starts the update process for the child @@ -150,8 +150,8 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { } leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams) - registrar := newCheckpointRegistrar(chainConfig.CheckpointConfig, leth.getLocalCheckpoint) - if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, light.DefaultClientIndexerConfig, config.ULC, true, config.NetworkId, leth.eventMux, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.serverPool, registrar, quitSync, &leth.wg, nil); err != nil { + registrar := newCheckpointRegistrar(config.CheckpointConfig, leth.getLocalCheckpoint) + if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, config.Checkpoint, light.DefaultClientIndexerConfig, config.ULC, true, config.NetworkId, leth.eventMux, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.serverPool, registrar, quitSync, &leth.wg, nil); err != nil { return nil, err } if leth.protocolManager.isULCEnabled() { diff --git a/les/handler.go b/les/handler.go index eb3674abe8fa2..40838aa6b2956 100644 --- a/les/handler.go +++ b/les/handler.go @@ -110,6 +110,7 @@ type ProtocolManager struct { fetcher *lightFetcher ulc *ulc peers *peerSet + checkpoint *params.TrustedCheckpoint reg *checkpointRegistrar // If reg == nil, it means the checkpoint registrar is not activated // channels for fetcher, syncer, txsyncLoop @@ -127,7 +128,7 @@ type ProtocolManager struct { // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable // with the ethereum network. -func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.IndexerConfig, ulcConfig *eth.ULCConfig, client bool, networkId uint64, mux *event.TypeMux, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, serverPool *serverPool, registrar *checkpointRegistrar, quitSync chan struct{}, wg *sync.WaitGroup, synced func() bool) (*ProtocolManager, error) { +func NewProtocolManager(chainConfig *params.ChainConfig, checkpoint *params.TrustedCheckpoint, indexerConfig *light.IndexerConfig, ulcConfig *eth.ULCConfig, client bool, networkId uint64, mux *event.TypeMux, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, serverPool *serverPool, registrar *checkpointRegistrar, quitSync chan struct{}, wg *sync.WaitGroup, synced func() bool) (*ProtocolManager, error) { // Create the protocol manager with the base fields manager := &ProtocolManager{ client: client, @@ -146,6 +147,7 @@ func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.In quitSync: quitSync, wg: wg, noMorePeers: make(chan struct{}), + checkpoint: checkpoint, synced: synced, } if odr != nil { @@ -162,11 +164,11 @@ func NewProtocolManager(chainConfig *params.ChainConfig, indexerConfig *light.In removePeer = func(id string) {} } if client { - var checkpoint uint64 - if cht, ok := params.TrustedCheckpoints[blockchain.Genesis().Hash()]; ok { - checkpoint = (cht.SectionIndex+1)*params.CHTFrequency - 1 + var checkpointNumber uint64 + if checkpoint != nil { + checkpointNumber = (checkpoint.SectionIndex+1)*params.CHTFrequency - 1 } - manager.downloader = downloader.New(checkpoint, chainDb, nil, manager.eventMux, nil, blockchain, removePeer) + manager.downloader = downloader.New(checkpointNumber, chainDb, nil, manager.eventMux, nil, blockchain, removePeer) manager.peers.notify((*downloaderPeerNotify)(manager)) manager.fetcher = newLightFetcher(manager) } diff --git a/les/helper_test.go b/les/helper_test.go index 7da213dbfa058..0332b41003d06 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -189,7 +189,7 @@ func newTestProtocolManager(lightSync bool, blocks int, odr *LesOdr, indexers [] // initialize empty chain for light client or pre-committed chain for server. if lightSync { - chain, _ = light.NewLightChain(odr, gspec.Config, engine) + chain, _ = light.NewLightChain(odr, gspec.Config, engine, nil) } else { chain = simulation.Blockchain() pool = core.NewTxPool(core.DefaultTxPoolConfig, gspec.Config, simulation.Blockchain()) @@ -201,7 +201,6 @@ func newTestProtocolManager(lightSync bool, blocks int, odr *LesOdr, indexers [] indexConfig = light.TestClientIndexerConfig } config := ¶ms.CheckpointContractConfig{ - Name: "test", Address: crypto.CreateAddress(bankAddr, 0), Signers: []common.Address{signerAddr}, Threshold: 1, @@ -220,7 +219,7 @@ func newTestProtocolManager(lightSync bool, blocks int, odr *LesOdr, indexers [] } reg = newCheckpointRegistrar(config, getLocal) } - pm, err := NewProtocolManager(gspec.Config, indexConfig, ulcConfig, lightSync, NetworkId, evmux, peers, chain, pool, db, odr, nil, reg, exitCh, new(sync.WaitGroup), func() bool { return true }) + pm, err := NewProtocolManager(gspec.Config, nil, indexConfig, ulcConfig, lightSync, NetworkId, evmux, peers, chain, pool, db, odr, nil, reg, exitCh, new(sync.WaitGroup), func() bool { return true }) if err != nil { return nil, nil, err } diff --git a/les/peer.go b/les/peer.go index ae1aceb676b37..3e520c2c5ed75 100644 --- a/les/peer.go +++ b/les/peer.go @@ -79,9 +79,8 @@ type peer struct { announceType uint64 // Checkpoint relative fields - advertisedCheckpoint params.TrustedCheckpoint - registeredHeight uint64 - hardcodedCheckpoint bool // Indicator whether the checkpoint is hardcoded + checkpoint params.TrustedCheckpoint + checkpointNumber uint64 id string @@ -684,24 +683,8 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis p.fcServer = flowcontrol.NewServerNode(sParams, &mclock.System{}) p.fcCosts = MRC.decode(ProtocolLengths[uint(p.version)]) - // Recap the checkpoint. - // - // The light client may be connected to several different versions of the server. - // (1) Old version server which can not provide stable checkpoint in the handshake packet. - // => Use hardcoded checkpoint or empty checkpoint - // (2) New version server but simple checkpoint syncing is not enabled(e.g. mainnet, new testnet or private network) - // => Use hardcoded checkpoint or empty checkpoint - // (3) New version server but the provided stable checkpoint is even lower than the hardcoded one. - // => Use hardcoded checkpoint - // (4) New version server with valid and higher stable checkpoint - // => Use provided checkpoint - hardcoded := params.TrustedCheckpoints[genesis] - if err := recv.get("checkpoint/value", &p.advertisedCheckpoint); hardcoded != nil && - (err != nil || p.advertisedCheckpoint.SectionIndex < hardcoded.SectionIndex) { - p.advertisedCheckpoint = *hardcoded - p.hardcodedCheckpoint = true - } - recv.get("checkpoint/registerHeight", &p.registeredHeight) + recv.get("checkpoint/value", &p.checkpoint) + recv.get("checkpoint/registerHeight", &p.checkpointNumber) if !p.isOnlyAnnounce { for msgCode := range reqAvgTimeCost { diff --git a/les/server.go b/les/server.go index 2e125e2f2784e..7b7dc4097526d 100644 --- a/les/server.go +++ b/les/server.go @@ -120,8 +120,8 @@ func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) { srv.chtIndexer.Start(e.BlockChain()) - registrar := newCheckpointRegistrar(e.BlockChain().Config().CheckpointConfig, srv.getLocalCheckpoint) - pm, err := NewProtocolManager(e.BlockChain().Config(), light.DefaultServerIndexerConfig, config.ULC, false, config.NetworkId, e.EventMux(), newPeerSet(), e.BlockChain(), e.TxPool(), e.ChainDb(), nil, nil, registrar, quitSync, new(sync.WaitGroup), e.Synced) + registrar := newCheckpointRegistrar(config.CheckpointConfig, srv.getLocalCheckpoint) + pm, err := NewProtocolManager(e.BlockChain().Config(), config.Checkpoint, light.DefaultServerIndexerConfig, config.ULC, false, config.NetworkId, e.EventMux(), newPeerSet(), e.BlockChain(), e.TxPool(), e.ChainDb(), nil, nil, registrar, quitSync, new(sync.WaitGroup), e.Synced) if err != nil { return nil, err } diff --git a/les/sync.go b/les/sync.go index 54160b585e258..6c2ce5eefc791 100644 --- a/les/sync.go +++ b/les/sync.go @@ -26,7 +26,6 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/light" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" ) var errInvalidCheckpoint = errors.New("invalid advertised checkpoint") @@ -86,8 +85,8 @@ func (pm *ProtocolManager) validateCheckpoint(peer *peer) error { defer cancel() // Fetch the block header corresponding to the checkpoint registration. - cp := peer.advertisedCheckpoint - header, err := light.GetUntrustedHeaderByNumber(ctx, pm.odr, peer.registeredHeight, peer.id) + cp := peer.checkpoint + header, err := light.GetUntrustedHeaderByNumber(ctx, pm.odr, peer.checkpointNumber, peer.id) if err != nil { return err } @@ -128,6 +127,23 @@ func (pm *ProtocolManager) synchronise(peer *peer) { if currentTd != nil && peer.headBlockInfo().Td.Cmp(currentTd) < 0 { return } + // Recap the checkpoint. + // + // The light client may be connected to several different versions of the server. + // (1) Old version server which can not provide stable checkpoint in the handshake packet. + // => Use hardcoded checkpoint or empty checkpoint + // (2) New version server but simple checkpoint syncing is not enabled(e.g. mainnet, new testnet or private network) + // => Use hardcoded checkpoint or empty checkpoint + // (3) New version server but the provided stable checkpoint is even lower than the hardcoded one. + // => Use hardcoded checkpoint + // (4) New version server with valid and higher stable checkpoint + // => Use provided checkpoint + var checkpoint = &peer.checkpoint + var hardcoded bool + if pm.checkpoint != nil && pm.checkpoint.SectionIndex > peer.checkpoint.SectionIndex { + checkpoint = pm.checkpoint // Use the hardcoded one. + hardcoded = true + } // Determine whether we should run checkpoint syncing or normal light syncing. // // Here has four situations that we will disable the checkpoint syncing: @@ -136,16 +152,15 @@ func (pm *ProtocolManager) synchronise(peer *peer) { // 2. The latest head block of the local chain is above the checkpoint. // 3. The checkpoint is hardcoded(recap with local hardcoded checkpoint) // 4. For some networks the checkpoint syncing is not activated. - cp := &peer.advertisedCheckpoint mode := checkpointSync switch { - case cp.Empty(): + case checkpoint.Empty(): mode = lightSync log.Debug("Disable checkpoint syncing", "reason", "empty checkpoint") - case latest.Number.Uint64() >= (cp.SectionIndex+1)*pm.iConfig.ChtSize-1: + case latest.Number.Uint64() >= (checkpoint.SectionIndex+1)*pm.iConfig.ChtSize-1: mode = lightSync - log.Debug("Disable checkpoint syncing", "reason", "local chain beyond the checkpoint") - case peer.hardcodedCheckpoint: + log.Debug("Disable checkpoint syncing", "reason", "local chain beyonds the checkpoint") + case hardcoded: mode = legacyCheckpointSync log.Debug("Disable checkpoint syncing", "reason", "checkpoint is hardcoded") case pm.reg == nil || !pm.reg.isRunning(): @@ -162,16 +177,16 @@ func (pm *ProtocolManager) synchronise(peer *peer) { if mode == checkpointSync || mode == legacyCheckpointSync { // Validate the advertised checkpoint if mode == legacyCheckpointSync { - cp = params.TrustedCheckpoints[pm.blockchain.Genesis().Hash()] + checkpoint = pm.checkpoint } else if mode == checkpointSync { if err := pm.validateCheckpoint(peer); err != nil { log.Debug("Failed to validate checkpoint", "reason", err) pm.removePeer(peer.id) return } - pm.blockchain.(*light.LightChain).AddTrustedCheckpoint(cp) + pm.blockchain.(*light.LightChain).AddTrustedCheckpoint(checkpoint) } - log.Debug("Checkpoint syncing start", "peer", peer.id, "checkpoint", cp.SectionIndex) + log.Debug("Checkpoint syncing start", "peer", peer.id, "checkpoint", checkpoint.SectionIndex) // Fetch the start point block header. // @@ -182,7 +197,7 @@ func (pm *ProtocolManager) synchronise(peer *peer) { // of the latest epoch covered by checkpoint. ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - if !cp.Empty() && !pm.blockchain.(*light.LightChain).SyncCheckpoint(ctx, cp) { + if !checkpoint.Empty() && !pm.blockchain.(*light.LightChain).SyncCheckpoint(ctx, checkpoint) { log.Debug("Sync checkpoint failed") pm.removePeer(peer.id) return diff --git a/light/lightchain.go b/light/lightchain.go index 8b787dc7e4026..7f64d1c28bbe4 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -77,7 +77,7 @@ type LightChain struct { // NewLightChain returns a fully initialised light chain using information // available in the database. It initialises the default Ethereum header // validator. -func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine) (*LightChain, error) { +func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine, checkpoint *params.TrustedCheckpoint) (*LightChain, error) { bodyCache, _ := lru.New(bodyCacheLimit) bodyRLPCache, _ := lru.New(bodyCacheLimit) blockCache, _ := lru.New(blockCacheLimit) @@ -101,8 +101,8 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus. if bc.genesisBlock == nil { return nil, core.ErrNoGenesis } - if cp, ok := params.TrustedCheckpoints[bc.genesisBlock.Hash()]; ok { - bc.AddTrustedCheckpoint(cp) + if checkpoint != nil { + bc.AddTrustedCheckpoint(checkpoint) } if err := bc.loadLastState(); err != nil { return nil, err diff --git a/light/lightchain_test.go b/light/lightchain_test.go index 58ea93044a4dd..70d2e70c189d0 100644 --- a/light/lightchain_test.go +++ b/light/lightchain_test.go @@ -55,7 +55,7 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) { db := rawdb.NewMemoryDatabase() gspec := core.Genesis{Config: params.TestChainConfig} genesis := gspec.MustCommit(db) - blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker()) + blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker(), nil) // Create and inject the requested chain if n == 0 { @@ -75,7 +75,7 @@ func newTestLightChain() *LightChain { Config: params.TestChainConfig, } gspec.MustCommit(db) - lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker()) + lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), nil) if err != nil { panic(err) } @@ -344,7 +344,7 @@ func TestReorgBadHeaderHashes(t *testing.T) { defer func() { delete(core.BadHashes, headers[3].Hash()) }() // Create a new LightChain and check that it rolled back the state. - ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker()) + ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } diff --git a/light/odr_test.go b/light/odr_test.go index 912a0cbdd8e8a..debd5544c3122 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -264,7 +264,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) { } odr := &testOdr{sdb: sdb, ldb: ldb, indexerConfig: TestClientIndexerConfig} - lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker()) + lightchain, err := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil) if err != nil { t.Fatal(err) } diff --git a/light/txpool_test.go b/light/txpool_test.go index 4f446c6ca2d6c..0996bd7c9cc04 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -100,7 +100,7 @@ func TestTxPool(t *testing.T) { discard: make(chan int, 1), mined: make(chan int, 1), } - lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker()) + lightchain, _ := NewLightChain(odr, params.TestChainConfig, ethash.NewFullFaker(), nil) txPermanent = 50 pool := NewTxPool(params.TestChainConfig, lightchain, relay) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) diff --git a/params/config.go b/params/config.go index a472a5c43a933..54f7234418101 100644 --- a/params/config.go +++ b/params/config.go @@ -33,15 +33,6 @@ var ( GoerliGenesisHash = common.HexToHash("0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a") ) -// TrustedCheckpoints associates each known checkpoint with the genesis hash of -// the chain it belongs to. -var TrustedCheckpoints = map[common.Hash]*TrustedCheckpoint{ - MainnetGenesisHash: MainnetTrustedCheckpoint, - TestnetGenesisHash: TestnetTrustedCheckpoint, - RinkebyGenesisHash: RinkebyTrustedCheckpoint, - GoerliGenesisHash: GoerliTrustedCheckpoint, -} - var ( // MainnetChainConfig is the chain parameters to run a node on the main network. MainnetChainConfig = &ChainConfig{ @@ -108,16 +99,6 @@ var ( Period: 15, Epoch: 30000, }, - CheckpointConfig: &CheckpointContractConfig{ - Address: common.HexToAddress("0x62652ed8e969ce7bd5e3dd13590efa1e569215f1"), - Signers: []common.Address{ - common.HexToAddress("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3"), // Peter - common.HexToAddress("0x78d1ad571a1a09d60d9bbf25894b44e4c8859595"), // Martin - common.HexToAddress("0x286834935f4A8Cfb4FF4C77D5770C2775aE2b0E7"), // Zsolt - common.HexToAddress("0xb86e2B0Ab5A4B1373e40c51A7C712c70Ba2f9f8E"), // Gary - }, - Threshold: 2, - }, } // RinkebyTrustedCheckpoint contains the light client trusted checkpoint for the Rinkeby test network. @@ -128,6 +109,18 @@ var ( BloomRoot: common.HexToHash("0xa3048fe8b7e30f77f11bc755a88478363d7d3e71c2bdfe4e8ab9e269cd804ba2"), } + // RinkebyCheckpointConfig contains a set of checkpoint contract configs for the Rinkeby test network. + RinkebyCheckpointConfig = &CheckpointContractConfig{ + Address: common.HexToAddress("0x62652ed8e969ce7bd5e3dd13590efa1e569215f1"), + Signers: []common.Address{ + common.HexToAddress("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3"), // Peter + common.HexToAddress("0x78d1ad571a1a09d60d9bbf25894b44e4c8859595"), // Martin + common.HexToAddress("0x286834935f4A8Cfb4FF4C77D5770C2775aE2b0E7"), // Zsolt + common.HexToAddress("0xb86e2B0Ab5A4B1373e40c51A7C712c70Ba2f9f8E"), // Gary + }, + Threshold: 2, + } + // GoerliChainConfig contains the chain parameters to run a node on the Görli test network. GoerliChainConfig = &ChainConfig{ ChainID: big.NewInt(5), @@ -159,16 +152,16 @@ var ( // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil} + AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil} // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil} + AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil} TestRules = TestChainConfig.Rules(new(big.Int)) ) @@ -242,9 +235,6 @@ type ChainConfig struct { // Various consensus engines Ethash *EthashConfig `json:"ethash,omitempty"` Clique *CliqueConfig `json:"clique,omitempty"` - - // Checkpoint contract configs - CheckpointConfig *CheckpointContractConfig `json:"checkpointContract,omitempty"` } // EthashConfig is the consensus engine configs for proof-of-work based sealing.