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
d0211578
Unverified
Commit
d0211578
authored
Dec 16, 2022
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core, les, light: implement timestamp based sethead and genesis rewinds
parent
08481028
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
74 additions
and
21 deletions
+74
-21
blockchain.go
core/blockchain.go
+38
-14
headerchain.go
core/headerchain.go
+24
-6
client.go
les/client.go
+1
-1
lightchain.go
light/lightchain.go
+11
-0
No files found.
core/blockchain.go
View file @
d0211578
...
...
@@ -318,7 +318,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
if
diskRoot
!=
(
common
.
Hash
{})
{
log
.
Warn
(
"Head state missing, repairing"
,
"number"
,
head
.
Number
(),
"hash"
,
head
.
Hash
(),
"snaproot"
,
diskRoot
)
snapDisk
,
err
:=
bc
.
setHeadBeyondRoot
(
head
.
NumberU64
(),
diskRoot
,
true
)
snapDisk
,
err
:=
bc
.
setHeadBeyondRoot
(
head
.
NumberU64
(),
0
,
diskRoot
,
true
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -328,7 +328,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
}
}
else
{
log
.
Warn
(
"Head state missing, repairing"
,
"number"
,
head
.
Number
(),
"hash"
,
head
.
Hash
())
if
_
,
err
:=
bc
.
setHeadBeyondRoot
(
head
.
NumberU64
(),
common
.
Hash
{},
true
);
err
!=
nil
{
if
_
,
err
:=
bc
.
setHeadBeyondRoot
(
head
.
NumberU64
(),
0
,
common
.
Hash
{},
true
);
err
!=
nil
{
return
nil
,
err
}
}
...
...
@@ -428,7 +428,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
if
compat
,
ok
:=
genesisErr
.
(
*
params
.
ConfigCompatError
);
ok
{
log
.
Warn
(
"Rewinding chain to upgrade configuration"
,
"err"
,
compat
)
if
compat
.
RewindToTime
>
0
{
log
.
Crit
(
"Timestamp based rewinds not implemented yet /sad"
)
bc
.
SetHeadWithTimestamp
(
compat
.
RewindToTime
)
}
else
{
bc
.
SetHead
(
compat
.
RewindToBlock
)
}
...
...
@@ -536,7 +536,20 @@ func (bc *BlockChain) loadLastState() error {
// was fast synced or full synced and in which state, the method will try to
// delete minimal data from disk whilst retaining chain consistency.
func
(
bc
*
BlockChain
)
SetHead
(
head
uint64
)
error
{
if
_
,
err
:=
bc
.
setHeadBeyondRoot
(
head
,
common
.
Hash
{},
false
);
err
!=
nil
{
if
_
,
err
:=
bc
.
setHeadBeyondRoot
(
head
,
0
,
common
.
Hash
{},
false
);
err
!=
nil
{
return
err
}
// Send chain head event to update the transaction pool
bc
.
chainHeadFeed
.
Send
(
ChainHeadEvent
{
Block
:
bc
.
CurrentBlock
()})
return
nil
}
// SetHeadWithTimestamp rewinds the local chain to a new head that has at max
// the given timestamp. Depending on whether the node was fast synced or full
// synced and in which state, the method will try to delete minimal data from
// disk whilst retaining chain consistency.
func
(
bc
*
BlockChain
)
SetHeadWithTimestamp
(
timestamp
uint64
)
error
{
if
_
,
err
:=
bc
.
setHeadBeyondRoot
(
0
,
timestamp
,
common
.
Hash
{},
false
);
err
!=
nil
{
return
err
}
// Send chain head event to update the transaction pool
...
...
@@ -573,8 +586,12 @@ func (bc *BlockChain) SetSafe(block *types.Block) {
// in which state, the method will try to delete minimal data from disk whilst
// retaining chain consistency.
//
// The method also works in timestamp mode if `head == 0` but `time != 0`. In that
// case blocks are rolled back until the new head becomes older or equal to the
// requested time. If both `head` and `time` is 0, the chain is rewound to genesis.
//
// The method returns the block number where the requested root cap was found.
func
(
bc
*
BlockChain
)
setHeadBeyondRoot
(
head
uint64
,
root
common
.
Hash
,
repair
bool
)
(
uint64
,
error
)
{
func
(
bc
*
BlockChain
)
setHeadBeyondRoot
(
head
uint64
,
time
uint64
,
root
common
.
Hash
,
repair
bool
)
(
uint64
,
error
)
{
if
!
bc
.
chainmu
.
TryLock
()
{
return
0
,
errChainStopped
}
...
...
@@ -588,7 +605,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo
pivot
:=
rawdb
.
ReadLastPivotNumber
(
bc
.
db
)
frozen
,
_
:=
bc
.
db
.
Ancients
()
updateFn
:=
func
(
db
ethdb
.
KeyValueWriter
,
header
*
types
.
Header
)
(
uint64
,
bool
)
{
updateFn
:=
func
(
db
ethdb
.
KeyValueWriter
,
header
*
types
.
Header
)
(
*
types
.
Header
,
bool
)
{
// Rewind the blockchain, ensuring we don't end up with a stateless head
// block. Note, depth equality is permitted to allow using SetHead as a
// chain reparation mechanism without deleting any data!
...
...
@@ -669,16 +686,18 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo
bc
.
currentFastBlock
.
Store
(
newHeadFastBlock
)
headFastBlockGauge
.
Update
(
int64
(
newHeadFastBlock
.
NumberU64
()))
}
head
:=
bc
.
CurrentBlock
()
.
NumberU64
()
var
(
headHeader
=
bc
.
CurrentBlock
()
.
Header
()
headNumber
=
headHeader
.
Number
.
Uint64
()
)
// If setHead underflown the freezer threshold and the block processing
// intent afterwards is full block importing, delete the chain segment
// between the stateful-block and the sethead target.
var
wipe
bool
if
head
+
1
<
frozen
{
wipe
=
pivot
==
nil
||
head
>=
*
pivot
if
head
Number
+
1
<
frozen
{
wipe
=
pivot
==
nil
||
head
Number
>=
*
pivot
}
return
head
,
wipe
// Only force wipe if full synced
return
head
Header
,
wipe
// Only force wipe if full synced
}
// Rewind the header chain, deleting all block bodies until then
delFn
:=
func
(
db
ethdb
.
KeyValueWriter
,
hash
common
.
Hash
,
num
uint64
)
{
...
...
@@ -705,13 +724,18 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo
// touching the header chain altogether, unless the freezer is broken
if
repair
{
if
target
,
force
:=
updateFn
(
bc
.
db
,
bc
.
CurrentBlock
()
.
Header
());
force
{
bc
.
hc
.
SetHead
(
target
,
updateFn
,
delFn
)
bc
.
hc
.
SetHead
(
target
.
Number
.
Uint64
()
,
updateFn
,
delFn
)
}
}
else
{
// Rewind the chain to the requested head and keep going backwards until a
// block with a state is found or fast sync pivot is passed
log
.
Warn
(
"Rewinding blockchain"
,
"target"
,
head
)
bc
.
hc
.
SetHead
(
head
,
updateFn
,
delFn
)
if
time
>
0
{
log
.
Warn
(
"Rewinding blockchain to timestamp"
,
"target"
,
time
)
bc
.
hc
.
SetHeadWithTimestamp
(
time
,
updateFn
,
delFn
)
}
else
{
log
.
Warn
(
"Rewinding blockchain to block"
,
"target"
,
head
)
bc
.
hc
.
SetHead
(
head
,
updateFn
,
delFn
)
}
}
// Clear out any stale content from the caches
bc
.
bodyCache
.
Purge
()
...
...
core/headerchain.go
View file @
d0211578
...
...
@@ -556,7 +556,7 @@ type (
// before head header is updated. The method will return the actual block it
// updated the head to (missing state) and a flag if setHead should continue
// rewinding till that forcefully (exceeded ancient limits)
UpdateHeadBlocksCallback
func
(
ethdb
.
KeyValueWriter
,
*
types
.
Header
)
(
uint64
,
bool
)
UpdateHeadBlocksCallback
func
(
ethdb
.
KeyValueWriter
,
*
types
.
Header
)
(
*
types
.
Header
,
bool
)
// DeleteBlockContentCallback is a callback function that is called by SetHead
// before each header is deleted.
...
...
@@ -566,15 +566,33 @@ type (
// SetHead rewinds the local chain to a new head. Everything above the new head
// will be deleted and the new one set.
func
(
hc
*
HeaderChain
)
SetHead
(
head
uint64
,
updateFn
UpdateHeadBlocksCallback
,
delFn
DeleteBlockContentCallback
)
{
hc
.
setHead
(
head
,
0
,
updateFn
,
delFn
)
}
// SetHeadWithTimestamp rewinds the local chain to a new head timestamp. Everything
// above the new head will be deleted and the new one set.
func
(
hc
*
HeaderChain
)
SetHeadWithTimestamp
(
time
uint64
,
updateFn
UpdateHeadBlocksCallback
,
delFn
DeleteBlockContentCallback
)
{
hc
.
setHead
(
0
,
time
,
updateFn
,
delFn
)
}
// setHead rewinds the local chain to a new head block or a head timestamp.
// Everything above the new head will be deleted and the new one set.
func
(
hc
*
HeaderChain
)
setHead
(
headBlock
uint64
,
headTime
uint64
,
updateFn
UpdateHeadBlocksCallback
,
delFn
DeleteBlockContentCallback
)
{
var
(
parentHash
common
.
Hash
batch
=
hc
.
chainDb
.
NewBatch
()
origin
=
true
)
for
hdr
:=
hc
.
CurrentHeader
();
hdr
!=
nil
&&
hdr
.
Number
.
Uint64
()
>
head
;
hdr
=
hc
.
CurrentHeader
()
{
done
:=
func
(
header
*
types
.
Header
)
bool
{
if
headBlock
!=
0
||
headTime
==
0
{
return
header
.
Number
.
Uint64
()
<=
headBlock
}
return
header
.
Time
<=
headTime
}
for
hdr
:=
hc
.
CurrentHeader
();
hdr
!=
nil
&&
!
done
(
hdr
);
hdr
=
hc
.
CurrentHeader
()
{
num
:=
hdr
.
Number
.
Uint64
()
// Rewind
block chain to new head.
// Rewind
chain to new head
parent
:=
hc
.
GetHeader
(
hdr
.
ParentHash
,
num
-
1
)
if
parent
==
nil
{
parent
=
hc
.
genesisHeader
...
...
@@ -591,9 +609,9 @@ func (hc *HeaderChain) SetHead(head uint64, updateFn UpdateHeadBlocksCallback, d
markerBatch
:=
hc
.
chainDb
.
NewBatch
()
if
updateFn
!=
nil
{
newHead
,
force
:=
updateFn
(
markerBatch
,
parent
)
if
force
&&
newHead
<
head
{
log
.
Warn
(
"Force rewinding till ancient limit"
,
"head"
,
newHead
)
head
=
newHead
if
force
&&
((
headTime
>
0
&&
newHead
.
Time
<
headTime
)
||
(
headTime
==
0
&&
newHead
.
Number
.
Uint64
()
<
headBlock
))
{
log
.
Warn
(
"Force rewinding till ancient limit"
,
"head"
,
newHead
.
Number
.
Uint64
()
)
head
Block
,
headTime
=
newHead
.
Number
.
Uint64
(),
0
}
}
// Update head header then.
...
...
les/client.go
View file @
d0211578
...
...
@@ -180,7 +180,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
if
compat
,
ok
:=
genesisErr
.
(
*
params
.
ConfigCompatError
);
ok
{
log
.
Warn
(
"Rewinding chain to upgrade configuration"
,
"err"
,
compat
)
if
compat
.
RewindToTime
>
0
{
l
og
.
Crit
(
"Timestamp based rewinds not implemented yet /sad"
)
l
eth
.
blockchain
.
SetHeadWithTimestamp
(
compat
.
RewindToTime
)
}
else
{
leth
.
blockchain
.
SetHead
(
compat
.
RewindToBlock
)
}
...
...
light/lightchain.go
View file @
d0211578
...
...
@@ -178,6 +178,17 @@ func (lc *LightChain) SetHead(head uint64) error {
return
lc
.
loadLastState
()
}
// SetHeadWithTimestamp rewinds the local chain to a new head that has at max
// the given timestamp. Everything above the new head will be deleted and the
// new one set.
func
(
lc
*
LightChain
)
SetHeadWithTimestamp
(
timestamp
uint64
)
error
{
lc
.
chainmu
.
Lock
()
defer
lc
.
chainmu
.
Unlock
()
lc
.
hc
.
SetHeadWithTimestamp
(
timestamp
,
nil
,
nil
)
return
lc
.
loadLastState
()
}
// GasLimit returns the gas limit of the current HEAD block.
func
(
lc
*
LightChain
)
GasLimit
()
uint64
{
return
lc
.
hc
.
CurrentHeader
()
.
GasLimit
...
...
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