Skip to content

feat: add debug.setSyncTarget console command (#31375) #31665

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/ethdb"
Expand Down Expand Up @@ -456,3 +457,7 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
}

func (b *EthAPIBackend) Downloader() *downloader.Downloader {
return b.eth.Downloader()
}
10 changes: 8 additions & 2 deletions eth/catalyst/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,14 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
// that should be fixed, not papered over.
header := api.remoteBlocks.get(update.HeadBlockHash)
if header == nil {
log.Warn("Forkchoice requested unknown head", "hash", update.HeadBlockHash)
return engine.STATUS_SYNCING, nil
log.Warn("Forkchoice requested unknown head, trying to retrive it from a random peer", "hash", update.HeadBlockHash)
retrievedHead, err := api.eth.Downloader().GetHeader(update.HeadBlockHash)
if err != nil {
log.Warn("Could not retrieve unknown head from peers")
return engine.STATUS_SYNCING, nil
}
api.remoteBlocks.put(retrievedHead.Hash(), retrievedHead)
header = retrievedHead
}
// If the finalized hash is known, we can direct the downloader to move
// potentially more data to the freezer from the get go.
Expand Down
61 changes: 35 additions & 26 deletions eth/downloader/beacondevsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)

Expand Down Expand Up @@ -48,34 +49,42 @@ func (d *Downloader) BeaconDevSync(mode SyncMode, hash common.Hash, stop chan st
return errors.New("stop requested")
default:
}
// Pick a random peer to sync from and keep retrying if none are yet
// available due to fresh startup
d.peers.lock.RLock()
var peer *peerConnection
for _, peer = range d.peers.peers {
break
}
d.peers.lock.RUnlock()

if peer == nil {
time.Sleep(time.Second)
continue
}
// Found a peer, attempt to retrieve the header whilst blocking and
// retry if it fails for whatever reason
log.Info("Attempting to retrieve sync target", "peer", peer.id)
headers, metas, err := d.fetchHeadersByHash(peer, hash, 1, 0, false)
if err != nil || len(headers) != 1 {
log.Warn("Failed to fetch sync target", "headers", len(headers), "err", err)
time.Sleep(time.Second)
continue
}
// Head header retrieved, if the hash matches, start the actual sync
if metas[0] != hash {
log.Error("Received invalid sync target", "want", hash, "have", metas[0])
header, err := d.GetHeader(hash)
if err != nil {
time.Sleep(time.Second)
continue
}
return d.BeaconSync(mode, headers[0], headers[0])

return d.BeaconSync(mode, header, header)
}
}

// GetHeader tries to retrieve the header with a given hash from a random peer.
func (d *Downloader) GetHeader(hash common.Hash) (*types.Header, error) {
// Pick a random peer to sync from and keep retrying if none are yet
// available due to fresh startup
d.peers.lock.RLock()
var peer *peerConnection
for _, peer = range d.peers.peers {
break
}
d.peers.lock.RUnlock()

if peer == nil {
return nil, errors.New("could not find peer")
}
// Found a peer, attempt to retrieve the header whilst blocking and
// retry if it fails for whatever reason
log.Info("Attempting to retrieve sync target", "peer", peer.id)
headers, metas, err := d.fetchHeadersByHash(peer, hash, 1, 0, false)
if err != nil || len(headers) != 1 {
log.Warn("Failed to fetch sync target", "headers", len(headers), "err", err)
return nil, errors.New("failed to fetch sync target")
}
// Head header retrieved, if the hash matches, start the actual sync
if metas[0] != hash {
log.Error("Received invalid sync target", "want", hash, "have", metas[0])
return nil, errors.New("received invalid sync target")
}
return headers[0], nil
}
38 changes: 37 additions & 1 deletion internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/eth/gasestimator"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/internal/ethapi/override"
Expand Down Expand Up @@ -1701,11 +1703,45 @@ type DebugAPI struct {
b Backend
}

// NewDebugAPI creates a new instance of DebugAPI.
// NewDebugAPI creates a new DebugAPI instance.
func NewDebugAPI(b Backend) *DebugAPI {
return &DebugAPI{b: b}
}

// SetSyncTarget manually sets the target hash for full sync.
// This is primarily intended for debugging and testing purposes, allowing
// simulation of syncing to specific forks or targets without restarting the node.
func (api *DebugAPI) SetSyncTarget(ctx context.Context, target common.Hash) error {
// Note: BeaconDevSync might block; running in a goroutine to avoid blocking RPC/console.
// Also, passing nil for the cancel channel as we don't provide a way to cancel via API.
type Downloader interface {
Downloader() *downloader.Downloader
}
backend, ok := api.b.(Downloader)
if !ok {
log.Error("Could not get downloader")
}
// retry 20 times to retrieve the header from random peers
for range 20 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big fan of this tbh, open for suggestions here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need the complete change here, please do let me know I am more than happy to work on it, Thanks for the reply .

header, err := backend.Downloader().GetHeader(target)
if err != nil {
continue
}
if err := backend.Downloader().BeaconSync(ethconfig.FullSync, header, header); err != nil {
return err
} else {
// Sync target set successfully, return
return nil
}
}
return errors.New("could not set sync target")
}

// ChainConfig returns the active chain configuration.
func (api *DebugAPI) ChainConfig() *params.ChainConfig {
return api.b.ChainConfig()
}

// GetRawHeader retrieves the RLP encoding for a single header.
func (api *DebugAPI) GetRawHeader(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
var hash common.Hash
Expand Down
5 changes: 5 additions & 0 deletions internal/web3ext/web3ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ web3._extend({
call: 'debug_setHead',
params: 1
}),
new web3._extend.Method({
name: 'setSyncTarget',
call: 'debug_setSyncTarget',
params: 1
}),
new web3._extend.Method({
name: 'seedHash',
call: 'debug_seedHash',
Expand Down