[release/1.4.10] core, eth: enforce network split post DAO hard-fork
(cherry picked from commit 7f00e8c033
)
This commit is contained in:
@ -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 {
|
||||
@ -479,9 +497,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 {
|
||||
|
Reference in New Issue
Block a user