Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
b3ae0734
Unverified
Commit
b3ae0734
authored
Feb 23, 2023
by
Péter Szilágyi
Committed by
GitHub
Feb 23, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
eth: use the last announced finalized block as the sync ancient limit (#26685)
parent
09a9ccdb
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
104 additions
and
55 deletions
+104
-55
api.go
eth/catalyst/api.go
+14
-2
queue.go
eth/catalyst/queue.go
+6
-3
tester.go
eth/catalyst/tester.go
+1
-1
beaconsync.go
eth/downloader/beaconsync.go
+8
-8
downloader.go
eth/downloader/downloader.go
+37
-22
downloader_test.go
eth/downloader/downloader_test.go
+1
-1
skeleton.go
eth/downloader/skeleton.go
+32
-13
skeleton_test.go
eth/downloader/skeleton_test.go
+5
-5
No files found.
eth/catalyst/api.go
View file @
b3ae0734
...
@@ -237,6 +237,10 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
...
@@ -237,6 +237,10 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
log
.
Warn
(
"Forkchoice requested unknown head"
,
"hash"
,
update
.
HeadBlockHash
)
log
.
Warn
(
"Forkchoice requested unknown head"
,
"hash"
,
update
.
HeadBlockHash
)
return
engine
.
STATUS_SYNCING
,
nil
return
engine
.
STATUS_SYNCING
,
nil
}
}
// If the finalized hash is known, we can direct the downloader to move
// potentially more data to the freezer from the get go.
finalized
:=
api
.
remoteBlocks
.
get
(
update
.
FinalizedBlockHash
)
// Header advertised via a past newPayload request. Start syncing to it.
// Header advertised via a past newPayload request. Start syncing to it.
// Before we do however, make sure any legacy sync in switched off so we
// Before we do however, make sure any legacy sync in switched off so we
// don't accidentally have 2 cycles running.
// don't accidentally have 2 cycles running.
...
@@ -244,8 +248,16 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
...
@@ -244,8 +248,16 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
merger
.
ReachTTD
()
merger
.
ReachTTD
()
api
.
eth
.
Downloader
()
.
Cancel
()
api
.
eth
.
Downloader
()
.
Cancel
()
}
}
log
.
Info
(
"Forkchoice requested sync to new head"
,
"number"
,
header
.
Number
,
"hash"
,
header
.
Hash
())
context
:=
[]
interface
{}{
"number"
,
header
.
Number
,
"hash"
,
header
.
Hash
()}
if
err
:=
api
.
eth
.
Downloader
()
.
BeaconSync
(
api
.
eth
.
SyncMode
(),
header
);
err
!=
nil
{
if
update
.
FinalizedBlockHash
!=
(
common
.
Hash
{})
{
if
finalized
==
nil
{
context
=
append
(
context
,
[]
interface
{}{
"finalized"
,
"unknown"
}
...
)
}
else
{
context
=
append
(
context
,
[]
interface
{}{
"finalized"
,
finalized
.
Number
}
...
)
}
}
log
.
Info
(
"Forkchoice requested sync to new head"
,
context
...
)
if
err
:=
api
.
eth
.
Downloader
()
.
BeaconSync
(
api
.
eth
.
SyncMode
(),
header
,
finalized
);
err
!=
nil
{
return
engine
.
STATUS_SYNCING
,
err
return
engine
.
STATUS_SYNCING
,
err
}
}
return
engine
.
STATUS_SYNCING
,
nil
return
engine
.
STATUS_SYNCING
,
nil
...
...
eth/catalyst/queue.go
View file @
b3ae0734
...
@@ -31,9 +31,12 @@ import (
...
@@ -31,9 +31,12 @@ import (
const
maxTrackedPayloads
=
10
const
maxTrackedPayloads
=
10
// maxTrackedHeaders is the maximum number of executed payloads the execution
// maxTrackedHeaders is the maximum number of executed payloads the execution
// engine tracks before evicting old ones. Ideally we should only ever track the
// engine tracks before evicting old ones. These are tracked outside the chain
// latest one; but have a slight wiggle room for non-ideal conditions.
// during initial sync to allow ForkchoiceUpdate to reference past blocks via
const
maxTrackedHeaders
=
10
// hashes only. For the sync target it would be enough to track only the latest
// header, but snap sync also needs the latest finalized height for the ancient
// limit.
const
maxTrackedHeaders
=
96
// payloadQueueItem represents an id->payload tuple to store until it's retrieved
// payloadQueueItem represents an id->payload tuple to store until it's retrieved
// or evicted.
// or evicted.
...
...
eth/catalyst/tester.go
View file @
b3ae0734
...
@@ -75,7 +75,7 @@ func (tester *FullSyncTester) Start() error {
...
@@ -75,7 +75,7 @@ func (tester *FullSyncTester) Start() error {
}
}
// Trigger beacon sync with the provided block header as
// Trigger beacon sync with the provided block header as
// trusted chain head.
// trusted chain head.
err
:=
tester
.
api
.
eth
.
Downloader
()
.
BeaconSync
(
downloader
.
FullSync
,
tester
.
block
.
Header
())
err
:=
tester
.
api
.
eth
.
Downloader
()
.
BeaconSync
(
downloader
.
FullSync
,
tester
.
block
.
Header
()
,
nil
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Info
(
"Failed to beacon sync"
,
"err"
,
err
)
log
.
Info
(
"Failed to beacon sync"
,
"err"
,
err
)
}
}
...
...
eth/downloader/beaconsync.go
View file @
b3ae0734
...
@@ -151,8 +151,8 @@ func (d *Downloader) SetBadBlockCallback(onBadBlock badBlockFn) {
...
@@ -151,8 +151,8 @@ func (d *Downloader) SetBadBlockCallback(onBadBlock badBlockFn) {
//
//
// Internally backfilling and state sync is done the same way, but the header
// Internally backfilling and state sync is done the same way, but the header
// retrieval and scheduling is replaced.
// retrieval and scheduling is replaced.
func
(
d
*
Downloader
)
BeaconSync
(
mode
SyncMode
,
head
*
types
.
Header
)
error
{
func
(
d
*
Downloader
)
BeaconSync
(
mode
SyncMode
,
head
*
types
.
Header
,
final
*
types
.
Header
)
error
{
return
d
.
beaconSync
(
mode
,
head
,
true
)
return
d
.
beaconSync
(
mode
,
head
,
final
,
true
)
}
}
// BeaconExtend is an optimistic version of BeaconSync, where an attempt is made
// BeaconExtend is an optimistic version of BeaconSync, where an attempt is made
...
@@ -162,7 +162,7 @@ func (d *Downloader) BeaconSync(mode SyncMode, head *types.Header) error {
...
@@ -162,7 +162,7 @@ func (d *Downloader) BeaconSync(mode SyncMode, head *types.Header) error {
// This is useful if a beacon client is feeding us large chunks of payloads to run,
// This is useful if a beacon client is feeding us large chunks of payloads to run,
// but is not setting the head after each.
// but is not setting the head after each.
func
(
d
*
Downloader
)
BeaconExtend
(
mode
SyncMode
,
head
*
types
.
Header
)
error
{
func
(
d
*
Downloader
)
BeaconExtend
(
mode
SyncMode
,
head
*
types
.
Header
)
error
{
return
d
.
beaconSync
(
mode
,
head
,
false
)
return
d
.
beaconSync
(
mode
,
head
,
nil
,
false
)
}
}
// beaconSync is the post-merge version of the chain synchronization, where the
// beaconSync is the post-merge version of the chain synchronization, where the
...
@@ -171,7 +171,7 @@ func (d *Downloader) BeaconExtend(mode SyncMode, head *types.Header) error {
...
@@ -171,7 +171,7 @@ func (d *Downloader) BeaconExtend(mode SyncMode, head *types.Header) error {
//
//
// Internally backfilling and state sync is done the same way, but the header
// Internally backfilling and state sync is done the same way, but the header
// retrieval and scheduling is replaced.
// retrieval and scheduling is replaced.
func
(
d
*
Downloader
)
beaconSync
(
mode
SyncMode
,
head
*
types
.
Header
,
force
bool
)
error
{
func
(
d
*
Downloader
)
beaconSync
(
mode
SyncMode
,
head
*
types
.
Header
,
f
inal
*
types
.
Header
,
f
orce
bool
)
error
{
// When the downloader starts a sync cycle, it needs to be aware of the sync
// When the downloader starts a sync cycle, it needs to be aware of the sync
// mode to use (full, snap). To keep the skeleton chain oblivious, inject the
// mode to use (full, snap). To keep the skeleton chain oblivious, inject the
// mode into the backfiller directly.
// mode into the backfiller directly.
...
@@ -181,7 +181,7 @@ func (d *Downloader) beaconSync(mode SyncMode, head *types.Header, force bool) e
...
@@ -181,7 +181,7 @@ func (d *Downloader) beaconSync(mode SyncMode, head *types.Header, force bool) e
d
.
skeleton
.
filler
.
(
*
beaconBackfiller
)
.
setMode
(
mode
)
d
.
skeleton
.
filler
.
(
*
beaconBackfiller
)
.
setMode
(
mode
)
// Signal the skeleton sync to switch to a new head, however it wants
// Signal the skeleton sync to switch to a new head, however it wants
if
err
:=
d
.
skeleton
.
Sync
(
head
,
force
);
err
!=
nil
{
if
err
:=
d
.
skeleton
.
Sync
(
head
,
f
inal
,
f
orce
);
err
!=
nil
{
return
err
return
err
}
}
return
nil
return
nil
...
@@ -207,7 +207,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
...
@@ -207,7 +207,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
number
:=
chainHead
.
Number
.
Uint64
()
number
:=
chainHead
.
Number
.
Uint64
()
// Retrieve the skeleton bounds and ensure they are linked to the local chain
// Retrieve the skeleton bounds and ensure they are linked to the local chain
beaconHead
,
beaconTail
,
err
:=
d
.
skeleton
.
Bounds
()
beaconHead
,
beaconTail
,
_
,
err
:=
d
.
skeleton
.
Bounds
()
if
err
!=
nil
{
if
err
!=
nil
{
// This is a programming error. The chain backfiller was called with an
// This is a programming error. The chain backfiller was called with an
// invalid beacon sync state. Ideally we would panic here, but erroring
// invalid beacon sync state. Ideally we would panic here, but erroring
...
@@ -272,7 +272,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
...
@@ -272,7 +272,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
// until sync errors or is finished.
// until sync errors or is finished.
func
(
d
*
Downloader
)
fetchBeaconHeaders
(
from
uint64
)
error
{
func
(
d
*
Downloader
)
fetchBeaconHeaders
(
from
uint64
)
error
{
var
head
*
types
.
Header
var
head
*
types
.
Header
_
,
tail
,
err
:=
d
.
skeleton
.
Bounds
()
_
,
tail
,
_
,
err
:=
d
.
skeleton
.
Bounds
()
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -292,7 +292,7 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error {
...
@@ -292,7 +292,7 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error {
for
{
for
{
// Some beacon headers might have appeared since the last cycle, make
// Some beacon headers might have appeared since the last cycle, make
// sure we're always syncing to all available ones
// sure we're always syncing to all available ones
head
,
_
,
err
=
d
.
skeleton
.
Bounds
()
head
,
_
,
_
,
err
=
d
.
skeleton
.
Bounds
()
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
...
eth/downloader/downloader.go
View file @
b3ae0734
...
@@ -480,7 +480,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
...
@@ -480,7 +480,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
}(
time
.
Now
())
}(
time
.
Now
())
// Look up the sync boundaries: the common ancestor and the target block
// Look up the sync boundaries: the common ancestor and the target block
var
latest
,
pivot
*
types
.
Header
var
latest
,
pivot
,
final
*
types
.
Header
if
!
beaconMode
{
if
!
beaconMode
{
// In legacy mode, use the master peer to retrieve the headers from
// In legacy mode, use the master peer to retrieve the headers from
latest
,
pivot
,
err
=
d
.
fetchHead
(
p
)
latest
,
pivot
,
err
=
d
.
fetchHead
(
p
)
...
@@ -489,7 +489,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
...
@@ -489,7 +489,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
}
}
}
else
{
}
else
{
// In beacon mode, use the skeleton chain to retrieve the headers from
// In beacon mode, use the skeleton chain to retrieve the headers from
latest
,
_
,
err
=
d
.
skeleton
.
Bounds
()
latest
,
_
,
final
,
err
=
d
.
skeleton
.
Bounds
()
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -499,7 +499,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
...
@@ -499,7 +499,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
// Retrieve the pivot header from the skeleton chain segment but
// Retrieve the pivot header from the skeleton chain segment but
// fallback to local chain if it's not found in skeleton space.
// fallback to local chain if it's not found in skeleton space.
if
pivot
=
d
.
skeleton
.
Header
(
number
);
pivot
==
nil
{
if
pivot
=
d
.
skeleton
.
Header
(
number
);
pivot
==
nil
{
_
,
oldest
,
_
:=
d
.
skeleton
.
Bounds
()
// error is already checked
_
,
oldest
,
_
,
_
:=
d
.
skeleton
.
Bounds
()
// error is already checked
if
number
<
oldest
.
Number
.
Uint64
()
{
if
number
<
oldest
.
Number
.
Uint64
()
{
count
:=
int
(
oldest
.
Number
.
Uint64
()
-
number
)
// it's capped by fsMinFullBlocks
count
:=
int
(
oldest
.
Number
.
Uint64
()
-
number
)
// it's capped by fsMinFullBlocks
headers
:=
d
.
readHeaderRange
(
oldest
,
count
)
headers
:=
d
.
readHeaderRange
(
oldest
,
count
)
...
@@ -567,26 +567,41 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
...
@@ -567,26 +567,41 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
d
.
committed
=
0
d
.
committed
=
0
}
}
if
mode
==
SnapSync
{
if
mode
==
SnapSync
{
// Set the ancient data limitation.
// Set the ancient data limitation.
If we are running snap sync, all block
//
If we are running snap sync, all block data older than ancientLimit will b
e
//
data older than ancientLimit will be written to the ancient store. Mor
e
//
written to the ancient store. More recent data will be written to the activ
e
//
recent data will be written to the active database and will wait for th
e
//
database and will wait for the
freezer to migrate.
// freezer to migrate.
//
//
// If there is a checkpoint available, then calculate the ancientLimit through
// If the network is post-merge, use either the last announced finalized
// that. Otherwise calculate the ancient limit through the advertised height
// block as the ancient limit, or if we haven't yet received one, the head-
// of the remote peer.
// a max fork ancestry limit. One quirky case if we've already passed the
// finalized block, in which case the skeleton.Bounds will return nil and
// we'll revert to head - 90K. That's fine, we're finishing sync anyway.
//
//
// The reason for picking checkpoint first is that a malicious peer can give us
// For non-merged networks, if there is a checkpoint available, then calculate
// a fake (very high) height, forcing the ancient limit to also be very high.
// the ancientLimit through that. Otherwise calculate the ancient limit through
// The peer would start to feed us valid blocks until head, resulting in all of
// the advertised height of the remote peer. This most is mostly a fallback for
// the blocks might be written into the ancient store. A following mini-reorg
// legacy networks, but should eventually be droppped. TODO(karalabe).
// could cause issues.
if
beaconMode
{
if
d
.
checkpoint
!=
0
&&
d
.
checkpoint
>
fullMaxForkAncestry
+
1
{
// Beacon sync, use the latest finalized block as the ancient limit
d
.
ancientLimit
=
d
.
checkpoint
// or a reasonable height if no finalized block is yet announced.
}
else
if
height
>
fullMaxForkAncestry
+
1
{
if
final
!=
nil
{
d
.
ancientLimit
=
height
-
fullMaxForkAncestry
-
1
d
.
ancientLimit
=
final
.
Number
.
Uint64
()
}
else
if
height
>
fullMaxForkAncestry
+
1
{
d
.
ancientLimit
=
height
-
fullMaxForkAncestry
-
1
}
else
{
d
.
ancientLimit
=
0
}
}
else
{
}
else
{
d
.
ancientLimit
=
0
// Legacy sync, use any hardcoded checkpoints or the best announcement
// we have from the remote peer. TODO(karalabe): Drop this pathway.
if
d
.
checkpoint
!=
0
&&
d
.
checkpoint
>
fullMaxForkAncestry
+
1
{
d
.
ancientLimit
=
d
.
checkpoint
}
else
if
height
>
fullMaxForkAncestry
+
1
{
d
.
ancientLimit
=
height
-
fullMaxForkAncestry
-
1
}
else
{
d
.
ancientLimit
=
0
}
}
}
frozen
,
_
:=
d
.
stateDB
.
Ancients
()
// Ignore the error here since light client can also hit here.
frozen
,
_
:=
d
.
stateDB
.
Ancients
()
// Ignore the error here since light client can also hit here.
...
@@ -1566,7 +1581,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error {
...
@@ -1566,7 +1581,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error {
// In post-merge, notify the engine API of encountered bad chains
// In post-merge, notify the engine API of encountered bad chains
if
d
.
badBlock
!=
nil
{
if
d
.
badBlock
!=
nil
{
head
,
_
,
err
:=
d
.
skeleton
.
Bounds
()
head
,
_
,
_
,
err
:=
d
.
skeleton
.
Bounds
()
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Error
(
"Failed to retrieve beacon bounds for bad block reporting"
,
"err"
,
err
)
log
.
Error
(
"Failed to retrieve beacon bounds for bad block reporting"
,
"err"
,
err
)
}
else
{
}
else
{
...
@@ -1860,7 +1875,7 @@ func (d *Downloader) reportSnapSyncProgress(force bool) {
...
@@ -1860,7 +1875,7 @@ func (d *Downloader) reportSnapSyncProgress(force bool) {
return
return
}
}
// Retrieve the current chain head and calculate the ETA
// Retrieve the current chain head and calculate the ETA
latest
,
_
,
err
:=
d
.
skeleton
.
Bounds
()
latest
,
_
,
_
,
err
:=
d
.
skeleton
.
Bounds
()
if
err
!=
nil
{
if
err
!=
nil
{
// We're going to cheat for non-merged networks, but that's fine
// We're going to cheat for non-merged networks, but that's fine
latest
=
d
.
pivotHeader
latest
=
d
.
pivotHeader
...
...
eth/downloader/downloader_test.go
View file @
b3ae0734
...
@@ -1478,7 +1478,7 @@ func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) {
...
@@ -1478,7 +1478,7 @@ func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) {
if
c
.
local
>
0
{
if
c
.
local
>
0
{
tester
.
chain
.
InsertChain
(
chain
.
blocks
[
1
:
c
.
local
+
1
])
tester
.
chain
.
InsertChain
(
chain
.
blocks
[
1
:
c
.
local
+
1
])
}
}
if
err
:=
tester
.
downloader
.
BeaconSync
(
mode
,
chain
.
blocks
[
len
(
chain
.
blocks
)
-
1
]
.
Header
());
err
!=
nil
{
if
err
:=
tester
.
downloader
.
BeaconSync
(
mode
,
chain
.
blocks
[
len
(
chain
.
blocks
)
-
1
]
.
Header
()
,
nil
);
err
!=
nil
{
t
.
Fatalf
(
"Failed to beacon sync chain %v %v"
,
c
.
name
,
err
)
t
.
Fatalf
(
"Failed to beacon sync chain %v %v"
,
c
.
name
,
err
)
}
}
select
{
select
{
...
...
eth/downloader/skeleton.go
View file @
b3ae0734
...
@@ -102,6 +102,7 @@ type subchain struct {
...
@@ -102,6 +102,7 @@ type subchain struct {
// suspended skeleton sync without prior knowledge of all prior suspension points.
// suspended skeleton sync without prior knowledge of all prior suspension points.
type
skeletonProgress
struct
{
type
skeletonProgress
struct
{
Subchains
[]
*
subchain
// Disjoint subchains downloaded until now
Subchains
[]
*
subchain
// Disjoint subchains downloaded until now
Finalized
*
uint64
// Last known finalized block number
}
}
// headUpdate is a notification that the beacon sync should switch to a new target.
// headUpdate is a notification that the beacon sync should switch to a new target.
...
@@ -109,6 +110,7 @@ type skeletonProgress struct {
...
@@ -109,6 +110,7 @@ type skeletonProgress struct {
// extend it and fail if it's not possible.
// extend it and fail if it's not possible.
type
headUpdate
struct
{
type
headUpdate
struct
{
header
*
types
.
Header
// Header to update the sync target to
header
*
types
.
Header
// Header to update the sync target to
final
*
types
.
Header
// Finalized header to use as thresholds
force
bool
// Whether to force the update or only extend if possible
force
bool
// Whether to force the update or only extend if possible
errc
chan
error
// Channel to signal acceptance of the new head
errc
chan
error
// Channel to signal acceptance of the new head
}
}
...
@@ -321,12 +323,12 @@ func (s *skeleton) Terminate() error {
...
@@ -321,12 +323,12 @@ func (s *skeleton) Terminate() error {
//
//
// This method does not block, rather it just waits until the syncer receives the
// This method does not block, rather it just waits until the syncer receives the
// fed header. What the syncer does with it is the syncer's problem.
// fed header. What the syncer does with it is the syncer's problem.
func
(
s
*
skeleton
)
Sync
(
head
*
types
.
Header
,
force
bool
)
error
{
func
(
s
*
skeleton
)
Sync
(
head
*
types
.
Header
,
f
inal
*
types
.
Header
,
f
orce
bool
)
error
{
log
.
Trace
(
"New skeleton head announced"
,
"number"
,
head
.
Number
,
"hash"
,
head
.
Hash
(),
"force"
,
force
)
log
.
Trace
(
"New skeleton head announced"
,
"number"
,
head
.
Number
,
"hash"
,
head
.
Hash
(),
"force"
,
force
)
errc
:=
make
(
chan
error
)
errc
:=
make
(
chan
error
)
select
{
select
{
case
s
.
headEvents
<-
&
headUpdate
{
header
:
head
,
force
:
force
,
errc
:
errc
}
:
case
s
.
headEvents
<-
&
headUpdate
{
header
:
head
,
f
inal
:
final
,
f
orce
:
force
,
errc
:
errc
}
:
return
<-
errc
return
<-
errc
case
<-
s
.
terminated
:
case
<-
s
.
terminated
:
return
errTerminated
return
errTerminated
...
@@ -437,7 +439,7 @@ func (s *skeleton) sync(head *types.Header) (*types.Header, error) {
...
@@ -437,7 +439,7 @@ func (s *skeleton) sync(head *types.Header) (*types.Header, error) {
// we don't seamlessly integrate reorgs to keep things simple. If the
// we don't seamlessly integrate reorgs to keep things simple. If the
// network starts doing many mini reorgs, it might be worthwhile handling
// network starts doing many mini reorgs, it might be worthwhile handling
// a limited depth without an error.
// a limited depth without an error.
if
reorged
:=
s
.
processNewHead
(
event
.
header
,
event
.
force
);
reorged
{
if
reorged
:=
s
.
processNewHead
(
event
.
header
,
event
.
f
inal
,
event
.
f
orce
);
reorged
{
// If a reorg is needed, and we're forcing the new head, signal
// If a reorg is needed, and we're forcing the new head, signal
// the syncer to tear down and start over. Otherwise, drop the
// the syncer to tear down and start over. Otherwise, drop the
// non-force reorg.
// non-force reorg.
...
@@ -590,7 +592,17 @@ func (s *skeleton) saveSyncStatus(db ethdb.KeyValueWriter) {
...
@@ -590,7 +592,17 @@ func (s *skeleton) saveSyncStatus(db ethdb.KeyValueWriter) {
// accepts and integrates it into the skeleton or requests a reorg. Upon reorg,
// accepts and integrates it into the skeleton or requests a reorg. Upon reorg,
// the syncer will tear itself down and restart with a fresh head. It is simpler
// the syncer will tear itself down and restart with a fresh head. It is simpler
// to reconstruct the sync state than to mutate it and hope for the best.
// to reconstruct the sync state than to mutate it and hope for the best.
func
(
s
*
skeleton
)
processNewHead
(
head
*
types
.
Header
,
force
bool
)
bool
{
func
(
s
*
skeleton
)
processNewHead
(
head
*
types
.
Header
,
final
*
types
.
Header
,
force
bool
)
bool
{
// If a new finalized block was announced, update the sync process independent
// of what happens with the sync head below
if
final
!=
nil
{
if
number
:=
final
.
Number
.
Uint64
();
s
.
progress
.
Finalized
==
nil
||
*
s
.
progress
.
Finalized
!=
number
{
s
.
progress
.
Finalized
=
new
(
uint64
)
*
s
.
progress
.
Finalized
=
final
.
Number
.
Uint64
()
s
.
saveSyncStatus
(
s
.
db
)
}
}
// If the header cannot be inserted without interruption, return an error for
// If the header cannot be inserted without interruption, return an error for
// the outer loop to tear down the skeleton sync and restart it
// the outer loop to tear down the skeleton sync and restart it
number
:=
head
.
Number
.
Uint64
()
number
:=
head
.
Number
.
Uint64
()
...
@@ -1150,9 +1162,10 @@ func (s *skeleton) cleanStales(filled *types.Header) error {
...
@@ -1150,9 +1162,10 @@ func (s *skeleton) cleanStales(filled *types.Header) error {
return
nil
return
nil
}
}
// Bounds retrieves the current head and tail tracked by the skeleton syncer.
// Bounds retrieves the current head and tail tracked by the skeleton syncer
// This method is used by the backfiller, whose life cycle is controlled by the
// and optionally the last known finalized header if any was announced and if
// skeleton syncer.
// it is still in the sync range. This method is used by the backfiller, whose
// life cycle is controlled by the skeleton syncer.
//
//
// Note, the method will not use the internal state of the skeleton, but will
// Note, the method will not use the internal state of the skeleton, but will
// rather blindly pull stuff from the database. This is fine, because the back-
// rather blindly pull stuff from the database. This is fine, because the back-
...
@@ -1160,28 +1173,34 @@ func (s *skeleton) cleanStales(filled *types.Header) error {
...
@@ -1160,28 +1173,34 @@ func (s *skeleton) cleanStales(filled *types.Header) error {
// There might be new heads appended, but those are atomic from the perspective
// There might be new heads appended, but those are atomic from the perspective
// of this method. Any head reorg will first tear down the backfiller and only
// of this method. Any head reorg will first tear down the backfiller and only
// then make the modification.
// then make the modification.
func
(
s
*
skeleton
)
Bounds
()
(
head
*
types
.
Header
,
tail
*
types
.
Header
,
err
error
)
{
func
(
s
*
skeleton
)
Bounds
()
(
head
*
types
.
Header
,
tail
*
types
.
Header
,
final
*
types
.
Header
,
err
error
)
{
// Read the current sync progress from disk and figure out the current head.
// Read the current sync progress from disk and figure out the current head.
// Although there's a lot of error handling here, these are mostly as sanity
// Although there's a lot of error handling here, these are mostly as sanity
// checks to avoid crashing if a programming error happens. These should not
// checks to avoid crashing if a programming error happens. These should not
// happen in live code.
// happen in live code.
status
:=
rawdb
.
ReadSkeletonSyncStatus
(
s
.
db
)
status
:=
rawdb
.
ReadSkeletonSyncStatus
(
s
.
db
)
if
len
(
status
)
==
0
{
if
len
(
status
)
==
0
{
return
nil
,
nil
,
errors
.
New
(
"beacon sync not yet started"
)
return
nil
,
nil
,
nil
,
errors
.
New
(
"beacon sync not yet started"
)
}
}
progress
:=
new
(
skeletonProgress
)
progress
:=
new
(
skeletonProgress
)
if
err
:=
json
.
Unmarshal
(
status
,
progress
);
err
!=
nil
{
if
err
:=
json
.
Unmarshal
(
status
,
progress
);
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
nil
,
err
}
}
head
=
rawdb
.
ReadSkeletonHeader
(
s
.
db
,
progress
.
Subchains
[
0
]
.
Head
)
head
=
rawdb
.
ReadSkeletonHeader
(
s
.
db
,
progress
.
Subchains
[
0
]
.
Head
)
if
head
==
nil
{
if
head
==
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"head skeleton header %d is missing"
,
progress
.
Subchains
[
0
]
.
Head
)
return
nil
,
nil
,
nil
,
fmt
.
Errorf
(
"head skeleton header %d is missing"
,
progress
.
Subchains
[
0
]
.
Head
)
}
}
tail
=
rawdb
.
ReadSkeletonHeader
(
s
.
db
,
progress
.
Subchains
[
0
]
.
Tail
)
tail
=
rawdb
.
ReadSkeletonHeader
(
s
.
db
,
progress
.
Subchains
[
0
]
.
Tail
)
if
tail
==
nil
{
if
tail
==
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"tail skeleton header %d is missing"
,
progress
.
Subchains
[
0
]
.
Tail
)
return
nil
,
nil
,
nil
,
fmt
.
Errorf
(
"tail skeleton header %d is missing"
,
progress
.
Subchains
[
0
]
.
Tail
)
}
if
progress
.
Finalized
!=
nil
&&
tail
.
Number
.
Uint64
()
<=
*
progress
.
Finalized
&&
*
progress
.
Finalized
<=
head
.
Number
.
Uint64
()
{
final
=
rawdb
.
ReadSkeletonHeader
(
s
.
db
,
*
progress
.
Finalized
)
if
final
==
nil
{
return
nil
,
nil
,
nil
,
fmt
.
Errorf
(
"finalized skeleton header %d is missing"
,
*
progress
.
Finalized
)
}
}
}
return
head
,
tail
,
nil
return
head
,
tail
,
final
,
nil
}
}
// Header retrieves a specific header tracked by the skeleton syncer. This method
// Header retrieves a specific header tracked by the skeleton syncer. This method
...
...
eth/downloader/skeleton_test.go
View file @
b3ae0734
...
@@ -370,7 +370,7 @@ func TestSkeletonSyncInit(t *testing.T) {
...
@@ -370,7 +370,7 @@ func TestSkeletonSyncInit(t *testing.T) {
skeleton
:=
newSkeleton
(
db
,
newPeerSet
(),
nil
,
newHookedBackfiller
())
skeleton
:=
newSkeleton
(
db
,
newPeerSet
(),
nil
,
newHookedBackfiller
())
skeleton
.
syncStarting
=
func
()
{
close
(
wait
)
}
skeleton
.
syncStarting
=
func
()
{
close
(
wait
)
}
skeleton
.
Sync
(
tt
.
head
,
true
)
skeleton
.
Sync
(
tt
.
head
,
nil
,
true
)
<-
wait
<-
wait
skeleton
.
Terminate
()
skeleton
.
Terminate
()
...
@@ -484,10 +484,10 @@ func TestSkeletonSyncExtend(t *testing.T) {
...
@@ -484,10 +484,10 @@ func TestSkeletonSyncExtend(t *testing.T) {
skeleton
:=
newSkeleton
(
db
,
newPeerSet
(),
nil
,
newHookedBackfiller
())
skeleton
:=
newSkeleton
(
db
,
newPeerSet
(),
nil
,
newHookedBackfiller
())
skeleton
.
syncStarting
=
func
()
{
close
(
wait
)
}
skeleton
.
syncStarting
=
func
()
{
close
(
wait
)
}
skeleton
.
Sync
(
tt
.
head
,
true
)
skeleton
.
Sync
(
tt
.
head
,
nil
,
true
)
<-
wait
<-
wait
if
err
:=
skeleton
.
Sync
(
tt
.
extend
,
false
);
err
!=
tt
.
err
{
if
err
:=
skeleton
.
Sync
(
tt
.
extend
,
nil
,
false
);
err
!=
tt
.
err
{
t
.
Errorf
(
"test %d: extension failure mismatch: have %v, want %v"
,
i
,
err
,
tt
.
err
)
t
.
Errorf
(
"test %d: extension failure mismatch: have %v, want %v"
,
i
,
err
,
tt
.
err
)
}
}
skeleton
.
Terminate
()
skeleton
.
Terminate
()
...
@@ -859,7 +859,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
...
@@ -859,7 +859,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
}
}
// Create a skeleton sync and run a cycle
// Create a skeleton sync and run a cycle
skeleton
:=
newSkeleton
(
db
,
peerset
,
drop
,
filler
)
skeleton
:=
newSkeleton
(
db
,
peerset
,
drop
,
filler
)
skeleton
.
Sync
(
tt
.
head
,
true
)
skeleton
.
Sync
(
tt
.
head
,
nil
,
true
)
var
progress
skeletonProgress
var
progress
skeletonProgress
// Wait a bit (bleah) for the initial sync loop to go to idle. This might
// Wait a bit (bleah) for the initial sync loop to go to idle. This might
...
@@ -910,7 +910,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
...
@@ -910,7 +910,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
}
}
// Apply the post-init events if there's any
// Apply the post-init events if there's any
if
tt
.
newHead
!=
nil
{
if
tt
.
newHead
!=
nil
{
skeleton
.
Sync
(
tt
.
newHead
,
true
)
skeleton
.
Sync
(
tt
.
newHead
,
nil
,
true
)
}
}
if
tt
.
newPeer
!=
nil
{
if
tt
.
newPeer
!=
nil
{
if
err
:=
peerset
.
Register
(
newPeerConnection
(
tt
.
newPeer
.
id
,
eth
.
ETH66
,
tt
.
newPeer
,
log
.
New
(
"id"
,
tt
.
newPeer
.
id
)));
err
!=
nil
{
if
err
:=
peerset
.
Register
(
newPeerConnection
(
tt
.
newPeer
.
id
,
eth
.
ETH66
,
tt
.
newPeer
,
log
.
New
(
"id"
,
tt
.
newPeer
.
id
)));
err
!=
nil
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment