Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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