Browse Source

core, eth/downloader: expose the bad hashes, check in downloader

Péter Szilágyi 10 years ago
parent
commit
29b0480cfb
5 changed files with 22 additions and 12 deletions
  1. 4 3
      core/blocks.go
  2. 1 1
      core/chain_manager.go
  3. 0 6
      core/manager.go
  4. 16 0
      eth/downloader/downloader.go
  5. 1 2
      eth/sync.go

+ 4 - 3
core/blocks.go

@@ -2,7 +2,8 @@ package core
 
 import "github.com/ethereum/go-ethereum/common"
 
-var badHashes = []common.Hash{
-	common.HexToHash("f269c503aed286caaa0d114d6a5320e70abbc2febe37953207e76a2873f2ba79"),
-	common.HexToHash("38f5bbbffd74804820ffa4bab0cd540e9de229725afb98c1a7e57936f4a714bc"),
+// Set of manually tracked bad hashes (usually hard forks)
+var BadHashes = map[common.Hash]bool{
+	common.HexToHash("f269c503aed286caaa0d114d6a5320e70abbc2febe37953207e76a2873f2ba79"): true,
+	common.HexToHash("38f5bbbffd74804820ffa4bab0cd540e9de229725afb98c1a7e57936f4a714bc"): true,
 }

+ 1 - 1
core/chain_manager.go

@@ -121,7 +121,7 @@ func NewChainManager(blockDb, stateDb common.Database, pow pow.PoW, mux *event.T
 	bc.setLastState()
 
 	// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
-	for _, hash := range badHashes {
+	for hash, _ := range BadHashes {
 		if block := bc.GetBlock(hash); block != nil {
 			glog.V(logger.Error).Infof("Found bad hash. Reorganising chain to state %x\n", block.ParentHash().Bytes()[:4])
 			block = bc.GetBlock(block.ParentHash())

+ 0 - 6
core/manager.go

@@ -3,9 +3,7 @@ package core
 import (
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
-	"github.com/ethereum/go-ethereum/eth/downloader"
 	"github.com/ethereum/go-ethereum/event"
-	"github.com/ethereum/go-ethereum/p2p"
 )
 
 // TODO move this to types?
@@ -14,11 +12,7 @@ type Backend interface {
 	BlockProcessor() *BlockProcessor
 	ChainManager() *ChainManager
 	TxPool() *TxPool
-	PeerCount() int
-	IsListening() bool
-	Peers() []*p2p.Peer
 	BlockDb() common.Database
 	StateDb() common.Database
 	EventMux() *event.TypeMux
-	Downloader() *downloader.Downloader
 }

+ 16 - 0
eth/downloader/downloader.go

@@ -7,7 +7,10 @@ import (
 	"sync/atomic"
 	"time"
 
+	"gopkg.in/fatih/set.v0"
+
 	"github.com/ethereum/go-ethereum/common"
+	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/event"
 	"github.com/ethereum/go-ethereum/logger"
@@ -75,6 +78,7 @@ type Downloader struct {
 	queue  *queue                      // Scheduler for selecting the hashes to download
 	peers  *peerSet                    // Set of active peers from which download can proceed
 	checks map[common.Hash]*crossCheck // Pending cross checks to verify a hash chain
+	banned *set.SetNonTS               // Set of hashes we've received and banned
 
 	// Callbacks
 	hasBlock hashCheckFn
@@ -100,6 +104,7 @@ type Block struct {
 }
 
 func New(mux *event.TypeMux, hasBlock hashCheckFn, getBlock getBlockFn) *Downloader {
+	// Create the base downloader
 	downloader := &Downloader{
 		mux:       mux,
 		queue:     newQueue(),
@@ -110,6 +115,11 @@ func New(mux *event.TypeMux, hasBlock hashCheckFn, getBlock getBlockFn) *Downloa
 		hashCh:    make(chan hashPack, 1),
 		blockCh:   make(chan blockPack, 1),
 	}
+	// Inject all the known bad hashes
+	downloader.banned = set.NewNonTS()
+	for hash, _ := range core.BadHashes {
+		downloader.banned.Add(hash)
+	}
 	return downloader
 }
 
@@ -280,6 +290,12 @@ func (d *Downloader) fetchHashes(p *peer, h common.Hash) error {
 				glog.V(logger.Debug).Infof("Peer (%s) responded with empty hash set\n", active.id)
 				return errEmptyHashSet
 			}
+			for _, hash := range hashPack.hashes {
+				if d.banned.Has(hash) {
+					glog.V(logger.Debug).Infof("Peer (%s) sent a known invalid chain\n", active.id)
+					return ErrInvalidChain
+				}
+			}
 			// Determine if we're done fetching hashes (queue up all pending), and continue if not done
 			done, index := false, 0
 			for index, head = range hashPack.hashes {

+ 1 - 2
eth/sync.go

@@ -70,6 +70,7 @@ func (pm *ProtocolManager) processBlocks() error {
 		// Try to inset the blocks, drop the originating peer if there's an error
 		index, err := pm.chainman.InsertChain(raw)
 		if err != nil {
+			glog.V(logger.Debug).Infoln("Downloaded block import failed:", err)
 			pm.removePeer(blocks[index].OriginPeer)
 			pm.downloader.Cancel()
 			return err
@@ -84,12 +85,10 @@ func (pm *ProtocolManager) processBlocks() error {
 func (pm *ProtocolManager) synchronise(peer *peer) {
 	// Short circuit if no peers are available
 	if peer == nil {
-		glog.V(logger.Debug).Infoln("Synchronisation canceled: no peers available")
 		return
 	}
 	// Make sure the peer's TD is higher than our own. If not drop.
 	if peer.td.Cmp(pm.chainman.Td()) <= 0 {
-		glog.V(logger.Debug).Infoln("Synchronisation canceled: peer's total difficulty is too small")
 		return
 	}
 	// FIXME if we have the hash in our chain and the TD of the peer is