Skip to content

Commit 9fe5d20

Browse files
authored
Merge pull request #18028 from ryanschneider/blockhash-whitelist
cmd, eth: add support for `--whitelist <blocknum>=<hash>`
2 parents dd98d1d + 31b3334 commit 9fe5d20

File tree

8 files changed

+56
-6
lines changed

8 files changed

+56
-6
lines changed

cmd/geth/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ var (
8787
utils.LightServFlag,
8888
utils.LightPeersFlag,
8989
utils.LightKDFFlag,
90+
utils.WhitelistFlag,
9091
utils.CacheFlag,
9192
utils.CacheDatabaseFlag,
9293
utils.CacheTrieFlag,

cmd/geth/usage.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ var AppHelpFlagGroups = []flagGroup{
8181
utils.LightServFlag,
8282
utils.LightPeersFlag,
8383
utils.LightKDFFlag,
84+
utils.WhitelistFlag,
8485
},
8586
},
8687
{

cmd/utils/flags.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ var (
182182
Name: "lightkdf",
183183
Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
184184
}
185+
WhitelistFlag = cli.StringFlag{
186+
Name: "whitelist",
187+
Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)",
188+
}
185189
// Dashboard settings
186190
DashboardEnabledFlag = cli.BoolFlag{
187191
Name: metrics.DashboardEnabledFlag,
@@ -1072,6 +1076,29 @@ func setEthash(ctx *cli.Context, cfg *eth.Config) {
10721076
}
10731077
}
10741078

1079+
func setWhitelist(ctx *cli.Context, cfg *eth.Config) {
1080+
whitelist := ctx.GlobalString(WhitelistFlag.Name)
1081+
if whitelist == "" {
1082+
return
1083+
}
1084+
cfg.Whitelist = make(map[uint64]common.Hash)
1085+
for _, entry := range strings.Split(whitelist, ",") {
1086+
parts := strings.Split(entry, "=")
1087+
if len(parts) != 2 {
1088+
Fatalf("Invalid whitelist entry: %s", entry)
1089+
}
1090+
number, err := strconv.ParseUint(parts[0], 0, 64)
1091+
if err != nil {
1092+
Fatalf("Invalid whitelist block number %s: %v", parts[0], err)
1093+
}
1094+
var hash common.Hash
1095+
if err = hash.UnmarshalText([]byte(parts[1])); err != nil {
1096+
Fatalf("Invalid whitelist hash %s: %v", parts[1], err)
1097+
}
1098+
cfg.Whitelist[number] = hash
1099+
}
1100+
}
1101+
10751102
// checkExclusive verifies that only a single instance of the provided flags was
10761103
// set by the user. Each flag might optionally be followed by a string type to
10771104
// specialize it further.
@@ -1137,6 +1164,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
11371164
setGPO(ctx, &cfg.GPO)
11381165
setTxPool(ctx, &cfg.TxPool)
11391166
setEthash(ctx, cfg)
1167+
setWhitelist(ctx, cfg)
11401168

11411169
if ctx.GlobalIsSet(SyncModeFlag.Name) {
11421170
cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)

eth/backend.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
173173
}
174174
eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain)
175175

176-
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil {
176+
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, config.Whitelist); err != nil {
177177
return nil, err
178178
}
179179

eth/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ type Config struct {
8787
SyncMode downloader.SyncMode
8888
NoPruning bool
8989

90+
// Whitelist of required block number -> hash values to accept
91+
Whitelist map[uint64]common.Hash `toml:"-"`
92+
9093
// Light client options
9194
LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests
9295
LightPeers int `toml:",omitempty"` // Maximum number of LES client peers

eth/handler.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ type ProtocolManager struct {
8888
txsSub event.Subscription
8989
minedBlockSub *event.TypeMuxSubscription
9090

91+
whitelist map[uint64]common.Hash
92+
9193
// channels for fetcher, syncer, txsyncLoop
9294
newPeerCh chan *peer
9395
txsyncCh chan *txsync
@@ -101,7 +103,7 @@ type ProtocolManager struct {
101103

102104
// NewProtocolManager returns a new Ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
103105
// with the Ethereum network.
104-
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) {
106+
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) {
105107
// Create the protocol manager with the base fields
106108
manager := &ProtocolManager{
107109
networkID: networkID,
@@ -110,6 +112,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
110112
blockchain: blockchain,
111113
chainconfig: config,
112114
peers: newPeerSet(),
115+
whitelist: whitelist,
113116
newPeerCh: make(chan *peer),
114117
noMorePeers: make(chan struct{}),
115118
txsyncCh: make(chan *txsync),
@@ -307,7 +310,13 @@ func (pm *ProtocolManager) handle(p *peer) error {
307310
}
308311
}()
309312
}
310-
// main loop. handle incoming messages.
313+
// If we have any explicit whitelist block hashes, request them
314+
for number := range pm.whitelist {
315+
if err := p.RequestHeadersByNumber(number, 1, 0, false); err != nil {
316+
return err
317+
}
318+
}
319+
// Handle incoming messages until the connection is torn down
311320
for {
312321
if err := pm.handleMsg(p); err != nil {
313322
p.Log().Debug("Ethereum message handling failed", "err", err)
@@ -466,6 +475,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
466475
p.Log().Debug("Verified to be on the same side of the DAO fork")
467476
return nil
468477
}
478+
// Otherwise if it's a whitelisted block, validate against the set
479+
if want, ok := pm.whitelist[headers[0].Number.Uint64()]; ok {
480+
if hash := headers[0].Hash(); want != hash {
481+
p.Log().Info("Whitelist mismatch, dropping peer", "number", headers[0].Number.Uint64(), "hash", hash, "want", want)
482+
return errors.New("whitelist block mismatch")
483+
}
484+
p.Log().Debug("Whitelist block verified", "number", headers[0].Number.Uint64(), "hash", want)
485+
}
469486
// Irrelevant of the fork checks, send the header to the fetcher just in case
470487
headers = pm.fetcher.FilterHeaders(p.id, headers, time.Now())
471488
}

eth/handler_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
478478
if err != nil {
479479
t.Fatalf("failed to create new blockchain: %v", err)
480480
}
481-
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db)
481+
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil)
482482
if err != nil {
483483
t.Fatalf("failed to start test protocol manager: %v", err)
484484
}
@@ -559,7 +559,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
559559
if err != nil {
560560
t.Fatalf("failed to create new blockchain: %v", err)
561561
}
562-
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db)
562+
pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil)
563563
if err != nil {
564564
t.Fatalf("failed to start test protocol manager: %v", err)
565565
}

eth/helper_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func
6666
panic(err)
6767
}
6868

69-
pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db)
69+
pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db, nil)
7070
if err != nil {
7171
return nil, nil, err
7272
}

0 commit comments

Comments
 (0)