Merge pull request #18028 from ryanschneider/blockhash-whitelist
cmd, eth: add support for `--whitelist <blocknum>=<hash>`
This commit is contained in:
		
						commit
						9fe5d20011
					
				| @ -87,6 +87,7 @@ var ( | ||||
| 		utils.LightServFlag, | ||||
| 		utils.LightPeersFlag, | ||||
| 		utils.LightKDFFlag, | ||||
| 		utils.WhitelistFlag, | ||||
| 		utils.CacheFlag, | ||||
| 		utils.CacheDatabaseFlag, | ||||
| 		utils.CacheTrieFlag, | ||||
|  | ||||
| @ -81,6 +81,7 @@ var AppHelpFlagGroups = []flagGroup{ | ||||
| 			utils.LightServFlag, | ||||
| 			utils.LightPeersFlag, | ||||
| 			utils.LightKDFFlag, | ||||
| 			utils.WhitelistFlag, | ||||
| 		}, | ||||
| 	}, | ||||
| 	{ | ||||
|  | ||||
| @ -182,6 +182,10 @@ var ( | ||||
| 		Name:  "lightkdf", | ||||
| 		Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", | ||||
| 	} | ||||
| 	WhitelistFlag = cli.StringFlag{ | ||||
| 		Name:  "whitelist", | ||||
| 		Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)", | ||||
| 	} | ||||
| 	// Dashboard settings
 | ||||
| 	DashboardEnabledFlag = cli.BoolFlag{ | ||||
| 		Name:  metrics.DashboardEnabledFlag, | ||||
| @ -1072,6 +1076,29 @@ func setEthash(ctx *cli.Context, cfg *eth.Config) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func setWhitelist(ctx *cli.Context, cfg *eth.Config) { | ||||
| 	whitelist := ctx.GlobalString(WhitelistFlag.Name) | ||||
| 	if whitelist == "" { | ||||
| 		return | ||||
| 	} | ||||
| 	cfg.Whitelist = make(map[uint64]common.Hash) | ||||
| 	for _, entry := range strings.Split(whitelist, ",") { | ||||
| 		parts := strings.Split(entry, "=") | ||||
| 		if len(parts) != 2 { | ||||
| 			Fatalf("Invalid whitelist entry: %s", entry) | ||||
| 		} | ||||
| 		number, err := strconv.ParseUint(parts[0], 0, 64) | ||||
| 		if err != nil { | ||||
| 			Fatalf("Invalid whitelist block number %s: %v", parts[0], err) | ||||
| 		} | ||||
| 		var hash common.Hash | ||||
| 		if err = hash.UnmarshalText([]byte(parts[1])); err != nil { | ||||
| 			Fatalf("Invalid whitelist hash %s: %v", parts[1], err) | ||||
| 		} | ||||
| 		cfg.Whitelist[number] = hash | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // checkExclusive verifies that only a single instance of the provided flags was
 | ||||
| // set by the user. Each flag might optionally be followed by a string type to
 | ||||
| // specialize it further.
 | ||||
| @ -1137,6 +1164,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { | ||||
| 	setGPO(ctx, &cfg.GPO) | ||||
| 	setTxPool(ctx, &cfg.TxPool) | ||||
| 	setEthash(ctx, cfg) | ||||
| 	setWhitelist(ctx, cfg) | ||||
| 
 | ||||
| 	if ctx.GlobalIsSet(SyncModeFlag.Name) { | ||||
| 		cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) | ||||
|  | ||||
| @ -173,7 +173,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { | ||||
| 	} | ||||
| 	eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain) | ||||
| 
 | ||||
| 	if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil { | ||||
| 	if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, config.Whitelist); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -87,6 +87,9 @@ type Config struct { | ||||
| 	SyncMode  downloader.SyncMode | ||||
| 	NoPruning bool | ||||
| 
 | ||||
| 	// Whitelist of required block number -> hash values to accept
 | ||||
| 	Whitelist map[uint64]common.Hash `toml:"-"` | ||||
| 
 | ||||
| 	// Light client options
 | ||||
| 	LightServ  int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests
 | ||||
| 	LightPeers int `toml:",omitempty"` // Maximum number of LES client peers
 | ||||
|  | ||||
| @ -88,6 +88,8 @@ type ProtocolManager struct { | ||||
| 	txsSub        event.Subscription | ||||
| 	minedBlockSub *event.TypeMuxSubscription | ||||
| 
 | ||||
| 	whitelist map[uint64]common.Hash | ||||
| 
 | ||||
| 	// channels for fetcher, syncer, txsyncLoop
 | ||||
| 	newPeerCh   chan *peer | ||||
| 	txsyncCh    chan *txsync | ||||
| @ -101,7 +103,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) (*ProtocolManager, error) { | ||||
| func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database, whitelist map[uint64]common.Hash) (*ProtocolManager, error) { | ||||
| 	// Create the protocol manager with the base fields
 | ||||
| 	manager := &ProtocolManager{ | ||||
| 		networkID:   networkID, | ||||
| @ -110,6 +112,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne | ||||
| 		blockchain:  blockchain, | ||||
| 		chainconfig: config, | ||||
| 		peers:       newPeerSet(), | ||||
| 		whitelist:   whitelist, | ||||
| 		newPeerCh:   make(chan *peer), | ||||
| 		noMorePeers: make(chan struct{}), | ||||
| 		txsyncCh:    make(chan *txsync), | ||||
| @ -307,7 +310,13 @@ func (pm *ProtocolManager) handle(p *peer) error { | ||||
| 			} | ||||
| 		}() | ||||
| 	} | ||||
| 	// main loop. handle incoming messages.
 | ||||
| 	// If we have any explicit whitelist block hashes, request them
 | ||||
| 	for number := range pm.whitelist { | ||||
| 		if err := p.RequestHeadersByNumber(number, 1, 0, false); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	// Handle incoming messages until the connection is torn down
 | ||||
| 	for { | ||||
| 		if err := pm.handleMsg(p); err != nil { | ||||
| 			p.Log().Debug("Ethereum message handling failed", "err", err) | ||||
| @ -466,6 +475,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { | ||||
| 				p.Log().Debug("Verified to be on the same side of the DAO fork") | ||||
| 				return nil | ||||
| 			} | ||||
| 			// Otherwise if it's a whitelisted block, validate against the set
 | ||||
| 			if want, ok := pm.whitelist[headers[0].Number.Uint64()]; ok { | ||||
| 				if hash := headers[0].Hash(); want != hash { | ||||
| 					p.Log().Info("Whitelist mismatch, dropping peer", "number", headers[0].Number.Uint64(), "hash", hash, "want", want) | ||||
| 					return errors.New("whitelist block mismatch") | ||||
| 				} | ||||
| 				p.Log().Debug("Whitelist block verified", "number", headers[0].Number.Uint64(), "hash", want) | ||||
| 			} | ||||
| 			// Irrelevant of the fork checks, send the header to the fetcher just in case
 | ||||
| 			headers = pm.fetcher.FilterHeaders(p.id, headers, time.Now()) | ||||
| 		} | ||||
|  | ||||
| @ -478,7 +478,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool | ||||
| 	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) | ||||
| 	pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("failed to start test protocol manager: %v", err) | ||||
| 	} | ||||
| @ -559,7 +559,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) | ||||
| 	pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("failed to start test protocol manager: %v", err) | ||||
| 	} | ||||
|  | ||||
| @ -66,7 +66,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db) | ||||
| 	pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user