github.com/ethereum/go-ethereum@v1.16.1/eth/downloader/beacondevsync.go (about)

     1  // Copyright 2023 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package downloader
    18  
    19  import (
    20  	"errors"
    21  	"time"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/core/types"
    25  	"github.com/ethereum/go-ethereum/log"
    26  )
    27  
    28  // BeaconDevSync is a development helper to test synchronization by providing
    29  // a block hash instead of header to run the beacon sync against.
    30  //
    31  // The method will reach out to the network to retrieve the header of the sync
    32  // target instead of receiving it from the consensus node.
    33  //
    34  // Note, this must not be used in live code. If the forkchcoice endpoint where
    35  // to use this instead of giving us the payload first, then essentially nobody
    36  // in the network would have the block yet that we'd attempt to retrieve.
    37  func (d *Downloader) BeaconDevSync(mode SyncMode, hash common.Hash, stop chan struct{}) error {
    38  	// Be very loud that this code should not be used in a live node
    39  	log.Warn("----------------------------------")
    40  	log.Warn("Beacon syncing with hash as target", "hash", hash)
    41  	log.Warn("This is unhealthy for a live node!")
    42  	log.Warn("----------------------------------")
    43  
    44  	log.Info("Waiting for peers to retrieve sync target")
    45  	for {
    46  		// If the node is going down, unblock
    47  		select {
    48  		case <-stop:
    49  			return errors.New("stop requested")
    50  		default:
    51  		}
    52  		header, err := d.GetHeader(hash)
    53  		if err != nil {
    54  			time.Sleep(time.Second)
    55  			continue
    56  		}
    57  		return d.BeaconSync(mode, header, header)
    58  	}
    59  }
    60  
    61  // GetHeader tries to retrieve the header with a given hash from a random peer.
    62  func (d *Downloader) GetHeader(hash common.Hash) (*types.Header, error) {
    63  	// Pick a random peer to sync from and keep retrying if none are yet
    64  	// available due to fresh startup
    65  	d.peers.lock.RLock()
    66  	defer d.peers.lock.RUnlock()
    67  
    68  	for _, peer := range d.peers.peers {
    69  		if peer == nil {
    70  			return nil, errors.New("could not find peer")
    71  		}
    72  		// Found a peer, attempt to retrieve the header whilst blocking and
    73  		// retry if it fails for whatever reason
    74  		log.Debug("Attempting to retrieve sync target", "peer", peer.id, "hash", hash)
    75  		headers, metas, err := d.fetchHeadersByHash(peer, hash, 1, 0, false)
    76  		if err != nil || len(headers) != 1 {
    77  			continue
    78  		}
    79  		// Head header retrieved, if the hash matches, start the actual sync
    80  		if metas[0] != hash {
    81  			log.Warn("Received invalid sync target", "peer", peer.id, "want", hash, "have", metas[0])
    82  			continue
    83  		}
    84  		return headers[0], nil
    85  	}
    86  	return nil, errors.New("failed to fetch sync target")
    87  }