From 7f00e8c0331bf13739e749bab88bf9006ca02f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 8 Jul 2016 20:59:11 +0300 Subject: core, eth: enforce network split post DAO hard-fork --- eth/handler.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) (limited to 'eth/handler.go') 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 { -- cgit v1.2.3 From 2c2e389b778b490fcaf14d9cc45a750647ca5c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 14 Jul 2016 11:22:58 +0300 Subject: cmd, core, eth, miner, params, tests: finalize the DAO fork --- eth/handler.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'eth/handler.go') diff --git a/eth/handler.go b/eth/handler.go index 946d5930f..01550e6c2 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -513,7 +513,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { } // 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) + glog.V(logger.Debug).Infof("%v: seems to be on the same side of the DAO fork", p) p.forkDrop.Stop() p.forkDrop = nil return nil @@ -529,11 +529,11 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { 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) + if err := core.ValidateDAOHeaderExtraData(pm.chainconfig, headers[0]); err != nil { + glog.V(logger.Debug).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) + glog.V(logger.Debug).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()) -- cgit v1.2.3