aboutsummaryrefslogtreecommitdiffstats
path: root/eth/handler.go
diff options
context:
space:
mode:
Diffstat (limited to 'eth/handler.go')
-rw-r--r--eth/handler.go77
1 files changed, 38 insertions, 39 deletions
diff --git a/eth/handler.go b/eth/handler.go
index b42612a56..2c0ea1eb1 100644
--- a/eth/handler.go
+++ b/eth/handler.go
@@ -28,7 +28,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
- "github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader"
@@ -55,7 +54,7 @@ const (
)
var (
- daoChallengeTimeout = 15 * time.Second // Time allowance for a node to reply to the DAO handshake challenge
+ syncChallengeTimeout = 15 * time.Second // Time allowance for a node to reply to the sync progress challenge
)
// errIncompatibleConfig is returned if the requested protocols and configs are
@@ -72,6 +71,9 @@ type ProtocolManager struct {
fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks)
acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing)
+ checkpointNumber uint64 // Block number for the sync progress validator to cross reference
+ checkpointHash common.Hash // Block hash for the sync progress validator to cross reference
+
txpool txPool
blockchain *core.BlockChain
chainconfig *params.ChainConfig
@@ -126,6 +128,11 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
if mode == downloader.FastSync {
manager.fastSync = uint32(1)
}
+ // If we have trusted checkpoints, enforce them on the chain
+ if checkpoint, ok := params.TrustedCheckpoints[blockchain.Genesis().Hash()]; ok {
+ manager.checkpointNumber = (checkpoint.SectionIndex+1)*params.CHTFrequencyClient - 1
+ manager.checkpointHash = checkpoint.SectionHead
+ }
// Initiate a sub-protocol for every implemented version we can handle
manager.SubProtocols = make([]p2p.Protocol, 0, len(ProtocolVersions))
for i, version := range ProtocolVersions {
@@ -165,7 +172,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
return nil, errIncompatibleConfig
}
// Construct the different synchronisation mechanisms
- manager.downloader = downloader.New(mode, chaindb, manager.eventMux, blockchain, nil, manager.removePeer)
+ manager.downloader = downloader.New(mode, manager.checkpointNumber, chaindb, manager.eventMux, blockchain, nil, manager.removePeer)
validator := func(header *types.Header) error {
return engine.VerifyHeader(blockchain, header, true)
@@ -291,22 +298,22 @@ func (pm *ProtocolManager) handle(p *peer) error {
// after this will be sent via broadcasts.
pm.syncTransactions(p)
- // If we're DAO hard-fork aware, validate any remote peer with regard to the hard-fork
- if daoBlock := pm.chainconfig.DAOForkBlock; daoBlock != nil {
- // Request the peer's DAO fork header for extra-data validation
- if err := p.RequestHeadersByNumber(daoBlock.Uint64(), 1, 0, false); err != nil {
+ // If we have a trusted CHT, reject all peers below that (avoid fast sync eclipse)
+ if pm.checkpointHash != (common.Hash{}) {
+ // Request the peer's checkpoint header for chain height/weight validation
+ if err := p.RequestHeadersByNumber(pm.checkpointNumber, 1, 0, false); err != nil {
return err
}
// Start a timer to disconnect if the peer doesn't reply in time
- p.forkDrop = time.AfterFunc(daoChallengeTimeout, func() {
- p.Log().Debug("Timed out DAO fork-check, dropping")
+ p.syncDrop = time.AfterFunc(syncChallengeTimeout, func() {
+ p.Log().Warn("Checkpoint challenge timed out, dropping", "addr", p.RemoteAddr(), "type", p.Name())
pm.removePeer(p.id)
})
// Make sure it's cleaned up if the peer dies off
defer func() {
- if p.forkDrop != nil {
- p.forkDrop.Stop()
- p.forkDrop = nil
+ if p.syncDrop != nil {
+ p.syncDrop.Stop()
+ p.syncDrop = nil
}
}()
}
@@ -438,41 +445,33 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
if err := msg.Decode(&headers); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err)
}
- // If no headers were received, but we're expending a DAO fork check, maybe it's that
- if len(headers) == 0 && p.forkDrop != nil {
- // Possibly an empty reply to the fork header checks, sanity check TDs
- verifyDAO := true
-
- // If we already have a DAO header, we can check the peer's TD against it. If
- // the peer's ahead of this, it too must have a reply to the DAO check
- if daoHeader := pm.blockchain.GetHeaderByNumber(pm.chainconfig.DAOForkBlock.Uint64()); daoHeader != nil {
- if _, td := p.Head(); td.Cmp(pm.blockchain.GetTd(daoHeader.Hash(), daoHeader.Number.Uint64())) >= 0 {
- verifyDAO = false
- }
- }
- // If we're seemingly on the same chain, disable the drop timer
- if verifyDAO {
- p.Log().Debug("Seems to be on the same side of the DAO fork")
- p.forkDrop.Stop()
- p.forkDrop = nil
- return nil
+ // If no headers were received, but we're expencting a checkpoint header, consider it that
+ if len(headers) == 0 && p.syncDrop != nil {
+ // Stop the timer either way, decide later to drop or not
+ p.syncDrop.Stop()
+ p.syncDrop = nil
+
+ // If we're doing a fast sync, we must enforce the checkpoint block to avoid
+ // eclipse attacks. Unsynced nodes are welcome to connect after we're done
+ // joining the network
+ if atomic.LoadUint32(&pm.fastSync) == 1 {
+ p.Log().Warn("Dropping unsynced node during fast sync", "addr", p.RemoteAddr(), "type", p.Name())
+ return errors.New("unsynced node cannot serve fast sync")
}
}
// Filter out any explicitly requested headers, deliver the rest to the downloader
filter := len(headers) == 1
if filter {
- // If it's a potential DAO fork check, validate against the rules
- if p.forkDrop != nil && pm.chainconfig.DAOForkBlock.Cmp(headers[0].Number) == 0 {
- // Disable the fork drop timer
- p.forkDrop.Stop()
- p.forkDrop = nil
+ // If it's a potential sync progress check, validate the content and advertised chain weight
+ if p.syncDrop != nil && headers[0].Number.Uint64() == pm.checkpointNumber {
+ // Disable the sync drop timer
+ p.syncDrop.Stop()
+ p.syncDrop = nil
// Validate the header and either drop the peer or continue
- if err := misc.VerifyDAOHeaderExtraData(pm.chainconfig, headers[0]); err != nil {
- p.Log().Debug("Verified to be on the other side of the DAO fork, dropping")
- return err
+ if headers[0].Hash() != pm.checkpointHash {
+ return errors.New("checkpoint hash mismatch")
}
- 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