aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2018-12-10 21:10:35 +0800
committerGitHub <noreply@github.com>2018-12-10 21:10:35 +0800
commit9fe5d200117bab0b2adbcf1d09629879366bcc54 (patch)
tree7449a43a27c17627540ffde7eb78a8a13ffbe1f7
parentdd98d1da9464c9ae6e1da69d7a41d4551f20bd8d (diff)
parent31b33349227715e8d1f8753d913892c1e35439d7 (diff)
downloadgo-tangerine-9fe5d200117bab0b2adbcf1d09629879366bcc54.tar
go-tangerine-9fe5d200117bab0b2adbcf1d09629879366bcc54.tar.gz
go-tangerine-9fe5d200117bab0b2adbcf1d09629879366bcc54.tar.bz2
go-tangerine-9fe5d200117bab0b2adbcf1d09629879366bcc54.tar.lz
go-tangerine-9fe5d200117bab0b2adbcf1d09629879366bcc54.tar.xz
go-tangerine-9fe5d200117bab0b2adbcf1d09629879366bcc54.tar.zst
go-tangerine-9fe5d200117bab0b2adbcf1d09629879366bcc54.zip
Merge pull request #18028 from ryanschneider/blockhash-whitelist
cmd, eth: add support for `--whitelist <blocknum>=<hash>`
-rw-r--r--cmd/geth/main.go1
-rw-r--r--cmd/geth/usage.go1
-rw-r--r--cmd/utils/flags.go28
-rw-r--r--eth/backend.go2
-rw-r--r--eth/config.go3
-rw-r--r--eth/handler.go21
-rw-r--r--eth/handler_test.go4
-rw-r--r--eth/helper_test.go2
8 files changed, 56 insertions, 6 deletions
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 69802a48a..fc1bf461f 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -87,6 +87,7 @@ var (
utils.LightServFlag,
utils.LightPeersFlag,
utils.LightKDFFlag,
+ utils.WhitelistFlag,
utils.CacheFlag,
utils.CacheDatabaseFlag,
utils.CacheTrieFlag,
diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go
index 82f17e0ee..25a702dd7 100644
--- a/cmd/geth/usage.go
+++ b/cmd/geth/usage.go
@@ -81,6 +81,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.LightServFlag,
utils.LightPeersFlag,
utils.LightKDFFlag,
+ utils.WhitelistFlag,
},
},
{
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 6a285fcb3..c9115d7a3 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -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)
diff --git a/eth/backend.go b/eth/backend.go
index 472140842..3f538d5f5 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -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
}
diff --git a/eth/config.go b/eth/config.go
index 601f4735e..a5c209512 100644
--- a/eth/config.go
+++ b/eth/config.go
@@ -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
diff --git a/eth/handler.go b/eth/handler.go
index 741fc9d5a..b42612a56 100644
--- a/eth/handler.go
+++ b/eth/handler.go
@@ -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())
}
diff --git a/eth/handler_test.go b/eth/handler_test.go
index 44824fd0b..9fffd9581 100644
--- a/eth/handler_test.go
+++ b/eth/handler_test.go
@@ -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)
}
diff --git a/eth/helper_test.go b/eth/helper_test.go
index 4e38a129e..b18a02baf 100644
--- a/eth/helper_test.go
+++ b/eth/helper_test.go
@@ -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
}