aboutsummaryrefslogtreecommitdiffstats
path: root/eth/handler.go
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2016-07-09 01:59:11 +0800
committerPéter Szilágyi <peterke@gmail.com>2016-07-15 21:52:55 +0800
commit7f00e8c0331bf13739e749bab88bf9006ca02f96 (patch)
tree80205e861b7c510a2d3d6e432bed09badfef57fa /eth/handler.go
parenta87089fd2dc08a69a4a4f1ef93db9a2871d819a3 (diff)
downloaddexon-7f00e8c0331bf13739e749bab88bf9006ca02f96.tar
dexon-7f00e8c0331bf13739e749bab88bf9006ca02f96.tar.gz
dexon-7f00e8c0331bf13739e749bab88bf9006ca02f96.tar.bz2
dexon-7f00e8c0331bf13739e749bab88bf9006ca02f96.tar.lz
dexon-7f00e8c0331bf13739e749bab88bf9006ca02f96.tar.xz
dexon-7f00e8c0331bf13739e749bab88bf9006ca02f96.tar.zst
dexon-7f00e8c0331bf13739e749bab88bf9006ca02f96.zip
core, eth: enforce network split post DAO hard-fork
Diffstat (limited to 'eth/handler.go')
-rw-r--r--eth/handler.go58
1 files changed, 55 insertions, 3 deletions
diff --git a/eth/handler.go b/eth/handler.go
index 47a36cc0b..946d5930f 100644
--- a/eth/handler.go
+++ b/eth/handler.go
@@ -45,6 +45,10 @@ const (
estHeaderRlpSize = 500 // Approximate size of an RLP encoded block header
)
+var (
+ daoChallengeTimeout = 15 * time.Second // Time allowance for a node to reply to the DAO handshake challenge
+)
+
// errIncompatibleConfig is returned if the requested protocols and configs are
// not compatible (low protocol version restrictions and high requirements).
var errIncompatibleConfig = errors.New("incompatible configuration")
@@ -62,9 +66,10 @@ type ProtocolManager struct {
fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks)
synced uint32 // Flag whether we're considered synchronised (enables transaction processing)
- txpool txPool
- blockchain *core.BlockChain
- chaindb ethdb.Database
+ txpool txPool
+ blockchain *core.BlockChain
+ chaindb ethdb.Database
+ chainconfig *core.ChainConfig
downloader *downloader.Downloader
fetcher *fetcher.Fetcher
@@ -99,6 +104,7 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int,
txpool: txpool,
blockchain: blockchain,
chaindb: chaindb,
+ chainconfig: config,
peers: newPeerSet(),
newPeerCh: make(chan *peer),
noMorePeers: make(chan struct{}),
@@ -278,6 +284,18 @@ 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 {
+ return err
+ }
+ // Start a timer to disconnect if the peer doesn't reply in time
+ p.forkDrop = time.AfterFunc(daoChallengeTimeout, func() {
+ glog.V(logger.Warn).Infof("%v: timed out DAO fork-check, dropping", p)
+ pm.removePeer(p.id)
+ })
+ }
// main loop. handle incoming messages.
for {
if err := pm.handleMsg(p); err != nil {
@@ -481,9 +499,43 @@ 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 p.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 {
+ glog.V(logger.Info).Infof("%v: seems to be on the same side of the DAO fork", p)
+ p.forkDrop.Stop()
+ p.forkDrop = nil
+ return nil
+ }
+ }
// 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
+
+ // Validate the header and either drop the peer or continue
+ if err := core.ValidateHeaderExtraData(pm.chainconfig, headers[0]); err != nil {
+ glog.V(logger.Info).Infof("%v: verified to be on the other side of the DAO fork, dropping", p)
+ return err
+ }
+ glog.V(logger.Info).Infof("%v: verified to be on the same side of the DAO fork", p)
+ }
+ // Irrelevant of the fork checks, send the header to the fetcher just in case
headers = pm.fetcher.FilterHeaders(headers, time.Now())
}
if len(headers) > 0 || !filter {