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
08481028
Unverified
Commit
08481028
authored
Dec 15, 2022
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core, les, params: add timestamp based fork compatibility checks
parent
a4e19c5c
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
272 additions
and
155 deletions
+272
-155
blockchain.go
core/blockchain.go
+5
-1
blockchain_test.go
core/blockchain_test.go
+1
-1
genesis.go
core/genesis.go
+5
-5
genesis_test.go
core/genesis_test.go
+4
-4
client.go
les/client.go
+5
-1
config.go
params/config.go
+189
-100
config_test.go
params/config_test.go
+63
-43
No files found.
core/blockchain.go
View file @
08481028
...
...
@@ -427,7 +427,11 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
// Rewind the chain in case of an incompatible config upgrade.
if
compat
,
ok
:=
genesisErr
.
(
*
params
.
ConfigCompatError
);
ok
{
log
.
Warn
(
"Rewinding chain to upgrade configuration"
,
"err"
,
compat
)
bc
.
SetHead
(
compat
.
RewindTo
)
if
compat
.
RewindToTime
>
0
{
log
.
Crit
(
"Timestamp based rewinds not implemented yet /sad"
)
}
else
{
bc
.
SetHead
(
compat
.
RewindToBlock
)
}
rawdb
.
WriteChainConfig
(
db
,
genesisHash
,
chainConfig
)
}
// Start tx indexer/unindexer if required.
...
...
core/blockchain_test.go
View file @
08481028
...
...
@@ -4275,7 +4275,7 @@ func TestEIP3651(t *testing.T) {
gspec
.
Config
.
BerlinBlock
=
common
.
Big0
gspec
.
Config
.
LondonBlock
=
common
.
Big0
gspec
.
Config
.
Shanghai
Block
=
common
.
Big0
gspec
.
Config
.
Shanghai
Time
=
common
.
Big0
signer
:=
types
.
LatestSigner
(
gspec
.
Config
)
_
,
blocks
,
_
:=
GenerateChainWithGenesis
(
gspec
,
engine
,
1
,
func
(
i
int
,
b
*
BlockGen
)
{
...
...
core/genesis.go
View file @
08481028
...
...
@@ -371,12 +371,12 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
}
// Check config compatibility and write the config. Compatibility errors
// are returned to the caller unless we're already at block zero.
he
ight
:=
rawdb
.
ReadHeaderNumber
(
db
,
rawdb
.
ReadHeadHeaderHash
(
db
)
)
if
he
ight
==
nil
{
return
newcfg
,
stored
,
fmt
.
Errorf
(
"missing
block number for head header hash
"
)
he
ad
:=
rawdb
.
ReadHeadHeader
(
db
)
if
he
ad
==
nil
{
return
newcfg
,
stored
,
fmt
.
Errorf
(
"missing
head header
"
)
}
compatErr
:=
storedcfg
.
CheckCompatible
(
newcfg
,
*
height
)
if
compatErr
!=
nil
&&
*
height
!=
0
&&
compatErr
.
RewindTo
!=
0
{
compatErr
:=
storedcfg
.
CheckCompatible
(
newcfg
,
head
.
Number
.
Uint64
(),
head
.
Time
)
if
compatErr
!=
nil
&&
((
head
.
Number
.
Uint64
()
!=
0
&&
compatErr
.
RewindToBlock
!=
0
)
||
(
head
.
Time
!=
0
&&
compatErr
.
RewindToTime
!=
0
))
{
return
newcfg
,
stored
,
compatErr
}
// Don't overwrite if the old is identical to the new
...
...
core/genesis_test.go
View file @
08481028
...
...
@@ -133,9 +133,9 @@ func TestSetupGenesis(t *testing.T) {
wantConfig
:
customg
.
Config
,
wantErr
:
&
params
.
ConfigCompatError
{
What
:
"Homestead fork block"
,
Stored
Config
:
big
.
NewInt
(
2
),
New
Config
:
big
.
NewInt
(
3
),
RewindTo
:
1
,
Stored
Block
:
big
.
NewInt
(
2
),
New
Block
:
big
.
NewInt
(
3
),
RewindTo
Block
:
1
,
},
},
}
...
...
les/client.go
View file @
08481028
...
...
@@ -179,7 +179,11 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
// Rewind the chain in case of an incompatible config upgrade.
if
compat
,
ok
:=
genesisErr
.
(
*
params
.
ConfigCompatError
);
ok
{
log
.
Warn
(
"Rewinding chain to upgrade configuration"
,
"err"
,
compat
)
leth
.
blockchain
.
SetHead
(
compat
.
RewindTo
)
if
compat
.
RewindToTime
>
0
{
log
.
Crit
(
"Timestamp based rewinds not implemented yet /sad"
)
}
else
{
leth
.
blockchain
.
SetHead
(
compat
.
RewindToBlock
)
}
rawdb
.
WriteChainConfig
(
chainDb
,
genesisHash
,
chainConfig
)
}
...
...
params/config.go
View file @
08481028
...
...
@@ -371,9 +371,12 @@ type ChainConfig struct {
ArrowGlacierBlock
*
big
.
Int
`json:"arrowGlacierBlock,omitempty"`
// Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated)
GrayGlacierBlock
*
big
.
Int
`json:"grayGlacierBlock,omitempty"`
// Eip-5133 (bomb delay) switch block (nil = no fork, 0 = already activated)
MergeNetsplitBlock
*
big
.
Int
`json:"mergeNetsplitBlock,omitempty"`
// Virtual fork after The Merge to use as a network splitter
ShanghaiTime
*
big
.
Int
`json:"shanghaiBlock,omitempty"`
// Shanghai switch time (nil = no fork, 0 = already on shanghai)
CancunBlock
*
big
.
Int
`json:"cancunBlock,omitempty"`
// Cancun switch block (nil = no fork, 0 = already on cancun)
// Fork scheduling was switched from blocks to timestamps here
ShanghaiTime
*
big
.
Int
`json:"shanghaiTime,omitempty"`
// Shanghai switch time (nil = no fork, 0 = already on shanghai)
// TerminalTotalDifficulty is the amount of total difficulty reached by
// the network that triggers the consensus upgrade.
TerminalTotalDifficulty
*
big
.
Int
`json:"terminalTotalDifficulty,omitempty"`
...
...
@@ -465,9 +468,7 @@ func (c *ChainConfig) Description() string {
if
c
.
GrayGlacierBlock
!=
nil
{
banner
+=
fmt
.
Sprintf
(
" - Gray Glacier: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md)
\n
"
,
c
.
GrayGlacierBlock
)
}
if
c
.
ShanghaiTime
!=
nil
{
banner
+=
fmt
.
Sprintf
(
" - Shanghai: %-8v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)
\n
"
,
c
.
ShanghaiTime
)
}
if
c
.
CancunBlock
!=
nil
{
banner
+=
fmt
.
Sprintf
(
" - Cancun: %-8v
\n
"
,
c
.
CancunBlock
)
}
...
...
@@ -489,74 +490,74 @@ func (c *ChainConfig) Description() string {
// IsHomestead returns whether num is either equal to the homestead block or greater.
func
(
c
*
ChainConfig
)
IsHomestead
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
HomesteadBlock
,
num
)
return
is
Block
Forked
(
c
.
HomesteadBlock
,
num
)
}
// IsDAOFork returns whether num is either equal to the DAO fork block or greater.
func
(
c
*
ChainConfig
)
IsDAOFork
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
DAOForkBlock
,
num
)
return
is
Block
Forked
(
c
.
DAOForkBlock
,
num
)
}
// IsEIP150 returns whether num is either equal to the EIP150 fork block or greater.
func
(
c
*
ChainConfig
)
IsEIP150
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
EIP150Block
,
num
)
return
is
Block
Forked
(
c
.
EIP150Block
,
num
)
}
// IsEIP155 returns whether num is either equal to the EIP155 fork block or greater.
func
(
c
*
ChainConfig
)
IsEIP155
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
EIP155Block
,
num
)
return
is
Block
Forked
(
c
.
EIP155Block
,
num
)
}
// IsEIP158 returns whether num is either equal to the EIP158 fork block or greater.
func
(
c
*
ChainConfig
)
IsEIP158
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
EIP158Block
,
num
)
return
is
Block
Forked
(
c
.
EIP158Block
,
num
)
}
// IsByzantium returns whether num is either equal to the Byzantium fork block or greater.
func
(
c
*
ChainConfig
)
IsByzantium
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
ByzantiumBlock
,
num
)
return
is
Block
Forked
(
c
.
ByzantiumBlock
,
num
)
}
// IsConstantinople returns whether num is either equal to the Constantinople fork block or greater.
func
(
c
*
ChainConfig
)
IsConstantinople
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
ConstantinopleBlock
,
num
)
return
is
Block
Forked
(
c
.
ConstantinopleBlock
,
num
)
}
// IsMuirGlacier returns whether num is either equal to the Muir Glacier (EIP-2384) fork block or greater.
func
(
c
*
ChainConfig
)
IsMuirGlacier
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
MuirGlacierBlock
,
num
)
return
is
Block
Forked
(
c
.
MuirGlacierBlock
,
num
)
}
// IsPetersburg returns whether num is either
// - equal to or greater than the PetersburgBlock fork block,
// - OR is nil, and Constantinople is active
func
(
c
*
ChainConfig
)
IsPetersburg
(
num
*
big
.
Int
)
bool
{
return
is
Forked
(
c
.
PetersburgBlock
,
num
)
||
c
.
PetersburgBlock
==
nil
&&
is
Forked
(
c
.
ConstantinopleBlock
,
num
)
return
is
BlockForked
(
c
.
PetersburgBlock
,
num
)
||
c
.
PetersburgBlock
==
nil
&&
isBlock
Forked
(
c
.
ConstantinopleBlock
,
num
)
}
// IsIstanbul returns whether num is either equal to the Istanbul fork block or greater.
func
(
c
*
ChainConfig
)
IsIstanbul
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
IstanbulBlock
,
num
)
return
is
Block
Forked
(
c
.
IstanbulBlock
,
num
)
}
// IsBerlin returns whether num is either equal to the Berlin fork block or greater.
func
(
c
*
ChainConfig
)
IsBerlin
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
BerlinBlock
,
num
)
return
is
Block
Forked
(
c
.
BerlinBlock
,
num
)
}
// IsLondon returns whether num is either equal to the London fork block or greater.
func
(
c
*
ChainConfig
)
IsLondon
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
LondonBlock
,
num
)
return
is
Block
Forked
(
c
.
LondonBlock
,
num
)
}
// IsArrowGlacier returns whether num is either equal to the Arrow Glacier (EIP-4345) fork block or greater.
func
(
c
*
ChainConfig
)
IsArrowGlacier
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
ArrowGlacierBlock
,
num
)
return
is
Block
Forked
(
c
.
ArrowGlacierBlock
,
num
)
}
// IsGrayGlacier returns whether num is either equal to the Gray Glacier (EIP-5133) fork block or greater.
func
(
c
*
ChainConfig
)
IsGrayGlacier
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
GrayGlacierBlock
,
num
)
return
is
Block
Forked
(
c
.
GrayGlacierBlock
,
num
)
}
// IsTerminalPoWBlock returns whether the given block is the last block of PoW stage.
...
...
@@ -567,30 +568,37 @@ func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *bi
return
parentTotalDiff
.
Cmp
(
c
.
TerminalTotalDifficulty
)
<
0
&&
totalDiff
.
Cmp
(
c
.
TerminalTotalDifficulty
)
>=
0
}
// IsShanghai returns whether time is either equal to the Shanghai fork time or greater.
func
(
c
*
ChainConfig
)
IsShanghai
(
time
*
big
.
Int
)
bool
{
return
isForked
(
c
.
ShanghaiTime
,
time
)
}
// IsCancun returns whether num is either equal to the Cancun fork block or greater.
func
(
c
*
ChainConfig
)
IsCancun
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
CancunBlock
,
num
)
return
isBlockForked
(
c
.
CancunBlock
,
num
)
}
// IsShanghai returns whether time is either equal to the Shanghai fork time or greater.
func
(
c
*
ChainConfig
)
IsShanghai
(
time
*
big
.
Int
)
bool
{
return
isTimestampForked
(
c
.
ShanghaiTime
,
time
)
}
// CheckCompatible checks whether scheduled fork transitions have been imported
// with a mismatching chain configuration.
func
(
c
*
ChainConfig
)
CheckCompatible
(
newcfg
*
ChainConfig
,
height
uint64
)
*
ConfigCompatError
{
bhead
:=
new
(
big
.
Int
)
.
SetUint64
(
height
)
func
(
c
*
ChainConfig
)
CheckCompatible
(
newcfg
*
ChainConfig
,
height
uint64
,
time
uint64
)
*
ConfigCompatError
{
var
(
bhead
=
new
(
big
.
Int
)
.
SetUint64
(
height
)
btime
=
new
(
big
.
Int
)
.
SetUint64
(
time
)
)
// Iterate checkCompatible to find the lowest conflict.
var
lasterr
*
ConfigCompatError
for
{
err
:=
c
.
checkCompatible
(
newcfg
,
bhead
)
if
err
==
nil
||
(
lasterr
!=
nil
&&
err
.
RewindTo
==
lasterr
.
RewindTo
)
{
err
:=
c
.
checkCompatible
(
newcfg
,
bhead
,
btime
)
if
err
==
nil
||
(
lasterr
!=
nil
&&
err
.
RewindTo
Block
==
lasterr
.
RewindToBlock
&&
err
.
RewindToTime
==
lasterr
.
RewindToTime
)
{
break
}
lasterr
=
err
bhead
.
SetUint64
(
err
.
RewindTo
)
if
err
.
RewindToTime
>
0
{
btime
.
SetUint64
(
err
.
RewindToTime
)
}
else
{
bhead
.
SetUint64
(
err
.
RewindToBlock
)
}
}
return
lasterr
}
...
...
@@ -600,7 +608,8 @@ func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *Confi
func
(
c
*
ChainConfig
)
CheckConfigForkOrder
()
error
{
type
fork
struct
{
name
string
block
*
big
.
Int
block
*
big
.
Int
// forks up to - and including the merge - were defined with block numbers
timestamp
*
big
.
Int
// forks after the merge are scheduled using timestamps
optional
bool
// if true, the fork may be nil and next fork is still allowed
}
var
lastFork
fork
...
...
@@ -620,93 +629,107 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
{
name
:
"arrowGlacierBlock"
,
block
:
c
.
ArrowGlacierBlock
,
optional
:
true
},
{
name
:
"grayGlacierBlock"
,
block
:
c
.
GrayGlacierBlock
,
optional
:
true
},
{
name
:
"mergeNetsplitBlock"
,
block
:
c
.
MergeNetsplitBlock
,
optional
:
true
},
//{name: "shanghaiBlock", block: c.ShanghaiBlock, optional: true},
{
name
:
"cancunBlock"
,
block
:
c
.
CancunBlock
,
optional
:
true
},
{
name
:
"shanghaiTime"
,
timestamp
:
c
.
ShanghaiTime
},
}
{
if
lastFork
.
name
!=
""
{
// Next one must be higher number
if
lastFork
.
block
==
nil
&&
cur
.
block
!=
nil
{
return
fmt
.
Errorf
(
"unsupported fork ordering: %v not enabled, but %v enabled at %v"
,
switch
{
// Non-optional forks must all be present in the chain config up to the last defined fork
case
lastFork
.
block
==
nil
&&
lastFork
.
timestamp
==
nil
&&
(
cur
.
block
!=
nil
||
cur
.
timestamp
!=
nil
)
:
if
cur
.
block
!=
nil
{
return
fmt
.
Errorf
(
"unsupported fork ordering: %v not enabled, but %v enabled at block %v"
,
lastFork
.
name
,
cur
.
name
,
cur
.
block
)
}
else
{
return
fmt
.
Errorf
(
"unsupported fork ordering: %v not enabled, but %v enabled at timestamp %v"
,
lastFork
.
name
,
cur
.
name
,
cur
.
timestamp
)
}
if
lastFork
.
block
!=
nil
&&
cur
.
block
!=
nil
{
if
lastFork
.
block
.
Cmp
(
cur
.
block
)
>
0
{
return
fmt
.
Errorf
(
"unsupported fork ordering: %v enabled at %v, but %v enabled at %v"
,
// Fork (whether defined by block or timestamp) must follow the fork definition sequence
case
(
lastFork
.
block
!=
nil
&&
cur
.
block
!=
nil
)
||
(
lastFork
.
timestamp
!=
nil
&&
cur
.
timestamp
!=
nil
)
:
if
lastFork
.
block
!=
nil
&&
lastFork
.
block
.
Cmp
(
cur
.
block
)
>
0
{
return
fmt
.
Errorf
(
"unsupported fork ordering: %v enabled at block %v, but %v enabled at block %v"
,
lastFork
.
name
,
lastFork
.
block
,
cur
.
name
,
cur
.
block
)
}
else
if
lastFork
.
timestamp
!=
nil
&&
lastFork
.
timestamp
.
Cmp
(
cur
.
timestamp
)
>
0
{
return
fmt
.
Errorf
(
"unsupported fork ordering: %v enabled at timestamp %v, but %v enabled at timestamp %v"
,
lastFork
.
name
,
lastFork
.
timestamp
,
cur
.
name
,
cur
.
timestamp
)
}
// Timestamp based forks can follow block based ones, but not the other way around
if
lastFork
.
timestamp
!=
nil
&&
cur
.
block
!=
nil
{
return
fmt
.
Errorf
(
"unsupported fork ordering: %v used timestamp ordering, but %v reverted to block ordering"
,
lastFork
.
name
,
cur
.
name
)
}
}
}
// If it was optional and not set, then ignore it
if
!
cur
.
optional
||
cur
.
block
!=
nil
{
if
!
cur
.
optional
||
(
cur
.
block
!=
nil
||
cur
.
timestamp
!=
nil
)
{
lastFork
=
cur
}
}
return
nil
}
func
(
c
*
ChainConfig
)
checkCompatible
(
newcfg
*
ChainConfig
,
head
*
big
.
Int
)
*
ConfigCompatError
{
if
isFork
Incompatible
(
c
.
HomesteadBlock
,
newcfg
.
HomesteadBlock
,
head
)
{
return
newCompatError
(
"Homestead fork block"
,
c
.
HomesteadBlock
,
newcfg
.
HomesteadBlock
)
func
(
c
*
ChainConfig
)
checkCompatible
(
newcfg
*
ChainConfig
,
head
Number
*
big
.
Int
,
headTimestamp
*
big
.
Int
)
*
ConfigCompatError
{
if
isFork
BlockIncompatible
(
c
.
HomesteadBlock
,
newcfg
.
HomesteadBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"Homestead fork block"
,
c
.
HomesteadBlock
,
newcfg
.
HomesteadBlock
)
}
if
isFork
Incompatible
(
c
.
DAOForkBlock
,
newcfg
.
DAOForkBlock
,
head
)
{
return
newCompatError
(
"DAO fork block"
,
c
.
DAOForkBlock
,
newcfg
.
DAOForkBlock
)
if
isFork
BlockIncompatible
(
c
.
DAOForkBlock
,
newcfg
.
DAOForkBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"DAO fork block"
,
c
.
DAOForkBlock
,
newcfg
.
DAOForkBlock
)
}
if
c
.
IsDAOFork
(
head
)
&&
c
.
DAOForkSupport
!=
newcfg
.
DAOForkSupport
{
return
newCompatError
(
"DAO fork support flag"
,
c
.
DAOForkBlock
,
newcfg
.
DAOForkBlock
)
if
c
.
IsDAOFork
(
head
Number
)
&&
c
.
DAOForkSupport
!=
newcfg
.
DAOForkSupport
{
return
new
Block
CompatError
(
"DAO fork support flag"
,
c
.
DAOForkBlock
,
newcfg
.
DAOForkBlock
)
}
if
isFork
Incompatible
(
c
.
EIP150Block
,
newcfg
.
EIP150Block
,
head
)
{
return
newCompatError
(
"EIP150 fork block"
,
c
.
EIP150Block
,
newcfg
.
EIP150Block
)
if
isFork
BlockIncompatible
(
c
.
EIP150Block
,
newcfg
.
EIP150Block
,
headNumber
)
{
return
new
Block
CompatError
(
"EIP150 fork block"
,
c
.
EIP150Block
,
newcfg
.
EIP150Block
)
}
if
isFork
Incompatible
(
c
.
EIP155Block
,
newcfg
.
EIP155Block
,
head
)
{
return
newCompatError
(
"EIP155 fork block"
,
c
.
EIP155Block
,
newcfg
.
EIP155Block
)
if
isFork
BlockIncompatible
(
c
.
EIP155Block
,
newcfg
.
EIP155Block
,
headNumber
)
{
return
new
Block
CompatError
(
"EIP155 fork block"
,
c
.
EIP155Block
,
newcfg
.
EIP155Block
)
}
if
isFork
Incompatible
(
c
.
EIP158Block
,
newcfg
.
EIP158Block
,
head
)
{
return
newCompatError
(
"EIP158 fork block"
,
c
.
EIP158Block
,
newcfg
.
EIP158Block
)
if
isFork
BlockIncompatible
(
c
.
EIP158Block
,
newcfg
.
EIP158Block
,
headNumber
)
{
return
new
Block
CompatError
(
"EIP158 fork block"
,
c
.
EIP158Block
,
newcfg
.
EIP158Block
)
}
if
c
.
IsEIP158
(
head
)
&&
!
configNum
Equal
(
c
.
ChainID
,
newcfg
.
ChainID
)
{
return
newCompatError
(
"EIP158 chain ID"
,
c
.
EIP158Block
,
newcfg
.
EIP158Block
)
if
c
.
IsEIP158
(
head
Number
)
&&
!
configBlock
Equal
(
c
.
ChainID
,
newcfg
.
ChainID
)
{
return
new
Block
CompatError
(
"EIP158 chain ID"
,
c
.
EIP158Block
,
newcfg
.
EIP158Block
)
}
if
isFork
Incompatible
(
c
.
ByzantiumBlock
,
newcfg
.
ByzantiumBlock
,
head
)
{
return
newCompatError
(
"Byzantium fork block"
,
c
.
ByzantiumBlock
,
newcfg
.
ByzantiumBlock
)
if
isFork
BlockIncompatible
(
c
.
ByzantiumBlock
,
newcfg
.
ByzantiumBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"Byzantium fork block"
,
c
.
ByzantiumBlock
,
newcfg
.
ByzantiumBlock
)
}
if
isFork
Incompatible
(
c
.
ConstantinopleBlock
,
newcfg
.
ConstantinopleBlock
,
head
)
{
return
newCompatError
(
"Constantinople fork block"
,
c
.
ConstantinopleBlock
,
newcfg
.
ConstantinopleBlock
)
if
isFork
BlockIncompatible
(
c
.
ConstantinopleBlock
,
newcfg
.
ConstantinopleBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"Constantinople fork block"
,
c
.
ConstantinopleBlock
,
newcfg
.
ConstantinopleBlock
)
}
if
isFork
Incompatible
(
c
.
PetersburgBlock
,
newcfg
.
PetersburgBlock
,
head
)
{
if
isFork
BlockIncompatible
(
c
.
PetersburgBlock
,
newcfg
.
PetersburgBlock
,
headNumber
)
{
// the only case where we allow Petersburg to be set in the past is if it is equal to Constantinople
// mainly to satisfy fork ordering requirements which state that Petersburg fork be set if Constantinople fork is set
if
isFork
Incompatible
(
c
.
ConstantinopleBlock
,
newcfg
.
PetersburgBlock
,
head
)
{
return
newCompatError
(
"Petersburg fork block"
,
c
.
PetersburgBlock
,
newcfg
.
PetersburgBlock
)
if
isFork
BlockIncompatible
(
c
.
ConstantinopleBlock
,
newcfg
.
PetersburgBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"Petersburg fork block"
,
c
.
PetersburgBlock
,
newcfg
.
PetersburgBlock
)
}
}
if
isFork
Incompatible
(
c
.
IstanbulBlock
,
newcfg
.
IstanbulBlock
,
head
)
{
return
newCompatError
(
"Istanbul fork block"
,
c
.
IstanbulBlock
,
newcfg
.
IstanbulBlock
)
if
isFork
BlockIncompatible
(
c
.
IstanbulBlock
,
newcfg
.
IstanbulBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"Istanbul fork block"
,
c
.
IstanbulBlock
,
newcfg
.
IstanbulBlock
)
}
if
isFork
Incompatible
(
c
.
MuirGlacierBlock
,
newcfg
.
MuirGlacierBlock
,
head
)
{
return
newCompatError
(
"Muir Glacier fork block"
,
c
.
MuirGlacierBlock
,
newcfg
.
MuirGlacierBlock
)
if
isFork
BlockIncompatible
(
c
.
MuirGlacierBlock
,
newcfg
.
MuirGlacierBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"Muir Glacier fork block"
,
c
.
MuirGlacierBlock
,
newcfg
.
MuirGlacierBlock
)
}
if
isFork
Incompatible
(
c
.
BerlinBlock
,
newcfg
.
BerlinBlock
,
head
)
{
return
newCompatError
(
"Berlin fork block"
,
c
.
BerlinBlock
,
newcfg
.
BerlinBlock
)
if
isFork
BlockIncompatible
(
c
.
BerlinBlock
,
newcfg
.
BerlinBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"Berlin fork block"
,
c
.
BerlinBlock
,
newcfg
.
BerlinBlock
)
}
if
isFork
Incompatible
(
c
.
LondonBlock
,
newcfg
.
LondonBlock
,
head
)
{
return
newCompatError
(
"London fork block"
,
c
.
LondonBlock
,
newcfg
.
LondonBlock
)
if
isFork
BlockIncompatible
(
c
.
LondonBlock
,
newcfg
.
LondonBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"London fork block"
,
c
.
LondonBlock
,
newcfg
.
LondonBlock
)
}
if
isFork
Incompatible
(
c
.
ArrowGlacierBlock
,
newcfg
.
ArrowGlacierBlock
,
head
)
{
return
newCompatError
(
"Arrow Glacier fork block"
,
c
.
ArrowGlacierBlock
,
newcfg
.
ArrowGlacierBlock
)
if
isFork
BlockIncompatible
(
c
.
ArrowGlacierBlock
,
newcfg
.
ArrowGlacierBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"Arrow Glacier fork block"
,
c
.
ArrowGlacierBlock
,
newcfg
.
ArrowGlacierBlock
)
}
if
isFork
Incompatible
(
c
.
GrayGlacierBlock
,
newcfg
.
GrayGlacierBlock
,
head
)
{
return
newCompatError
(
"Gray Glacier fork block"
,
c
.
GrayGlacierBlock
,
newcfg
.
GrayGlacierBlock
)
if
isFork
BlockIncompatible
(
c
.
GrayGlacierBlock
,
newcfg
.
GrayGlacierBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"Gray Glacier fork block"
,
c
.
GrayGlacierBlock
,
newcfg
.
GrayGlacierBlock
)
}
if
isFork
Incompatible
(
c
.
MergeNetsplitBlock
,
newcfg
.
MergeNetsplitBlock
,
head
)
{
return
newCompatError
(
"Merge netsplit fork block"
,
c
.
MergeNetsplitBlock
,
newcfg
.
MergeNetsplitBlock
)
if
isFork
BlockIncompatible
(
c
.
MergeNetsplitBlock
,
newcfg
.
MergeNetsplitBlock
,
headNumber
)
{
return
new
Block
CompatError
(
"Merge netsplit fork block"
,
c
.
MergeNetsplitBlock
,
newcfg
.
MergeNetsplitBlock
)
}
/*
if isForkIncompatible(c.ShanghaiBlock, newcfg.ShanghaiBlock, head) {
return newCompatError("Shanghai fork block", c.ShanghaiBlock, newcfg.ShanghaiBlock)
if
isForkBlockIncompatible
(
c
.
CancunBlock
,
newcfg
.
CancunBlock
,
headNumber
)
{
return
newBlockCompatError
(
"Cancun fork block"
,
c
.
CancunBlock
,
newcfg
.
CancunBlock
)
}
*/
if
isForkIncompatible
(
c
.
CancunBlock
,
newcfg
.
CancunBlock
,
head
)
{
return
newCompatError
(
"Cancun fork block"
,
c
.
CancunBlock
,
newcfg
.
CancunBlock
)
if
isForkTimestampIncompatible
(
c
.
ShanghaiTime
,
newcfg
.
ShanghaiTime
,
headTimestamp
)
{
return
newTimestampCompatError
(
"Shanghai fork timestamp"
,
c
.
ShanghaiTime
,
newcfg
.
ShanghaiTime
)
}
return
nil
}
...
...
@@ -721,21 +744,49 @@ func (c *ChainConfig) ElasticityMultiplier() uint64 {
return
DefaultElasticityMultiplier
}
// isFork
Incompatible returns true if a fork scheduled at s1 cannot be rescheduled to
// block s2 because head is already past the fork.
func
isForkIncompatible
(
s1
,
s2
,
head
*
big
.
Int
)
bool
{
return
(
is
Forked
(
s1
,
head
)
||
isForked
(
s2
,
head
))
&&
!
configNum
Equal
(
s1
,
s2
)
// isFork
BlockIncompatible returns true if a fork scheduled at block s1 cannot be
//
rescheduled to
block s2 because head is already past the fork.
func
isFork
Block
Incompatible
(
s1
,
s2
,
head
*
big
.
Int
)
bool
{
return
(
is
BlockForked
(
s1
,
head
)
||
isBlockForked
(
s2
,
head
))
&&
!
configBlock
Equal
(
s1
,
s2
)
}
// isForked returns whether a fork scheduled at block s is active at the given head block.
func
isForked
(
s
,
head
*
big
.
Int
)
bool
{
// isBlockForked returns whether a fork scheduled at block s is active at the
// given head block. Whilst this method is the same as isTimestampForked, they
// are explicitly separate for clearer reading.
func
isBlockForked
(
s
,
head
*
big
.
Int
)
bool
{
if
s
==
nil
||
head
==
nil
{
return
false
}
return
s
.
Cmp
(
head
)
<=
0
}
func
configNumEqual
(
x
,
y
*
big
.
Int
)
bool
{
func
configBlockEqual
(
x
,
y
*
big
.
Int
)
bool
{
if
x
==
nil
{
return
y
==
nil
}
if
y
==
nil
{
return
x
==
nil
}
return
x
.
Cmp
(
y
)
==
0
}
// isForkTimestampIncompatible returns true if a fork scheduled at timestamp s1
// cannot be rescheduled to timestamp s2 because head is already past the fork.
func
isForkTimestampIncompatible
(
s1
,
s2
,
head
*
big
.
Int
)
bool
{
return
(
isTimestampForked
(
s1
,
head
)
||
isTimestampForked
(
s2
,
head
))
&&
!
configTimestampEqual
(
s1
,
s2
)
}
// isTimestampForked returns whether a fork scheduled at timestamp s is active
// at the given head timestamp. Whilst this method is the same as isBlockForked,
// they are explicitly separate for clearer reading.
func
isTimestampForked
(
s
,
head
*
big
.
Int
)
bool
{
if
s
==
nil
||
head
==
nil
{
return
false
}
return
s
.
Cmp
(
head
)
<=
0
}
func
configTimestampEqual
(
x
,
y
*
big
.
Int
)
bool
{
if
x
==
nil
{
return
y
==
nil
}
...
...
@@ -749,13 +800,21 @@ func configNumEqual(x, y *big.Int) bool {
// ChainConfig that would alter the past.
type
ConfigCompatError
struct
{
What
string
// block numbers of the stored and new configurations
StoredConfig
,
NewConfig
*
big
.
Int
// block numbers of the stored and new configurations if block based forking
StoredBlock
,
NewBlock
*
big
.
Int
// timestamps of the stored and new configurations if time based forking
StoredTime
,
NewTime
*
big
.
Int
// the block number to which the local chain must be rewound to correct the error
RewindTo
uint64
RewindToBlock
uint64
// the timestamp to which the local chain must be rewound to correct the error
RewindToTime
uint64
}
func
newCompatError
(
what
string
,
storedblock
,
newblock
*
big
.
Int
)
*
ConfigCompatError
{
func
new
Block
CompatError
(
what
string
,
storedblock
,
newblock
*
big
.
Int
)
*
ConfigCompatError
{
var
rew
*
big
.
Int
switch
{
case
storedblock
==
nil
:
...
...
@@ -765,15 +824,45 @@ func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatEr
default
:
rew
=
newblock
}
err
:=
&
ConfigCompatError
{
what
,
storedblock
,
newblock
,
0
}
err
:=
&
ConfigCompatError
{
What
:
what
,
StoredBlock
:
storedblock
,
NewBlock
:
newblock
,
RewindToBlock
:
0
,
}
if
rew
!=
nil
&&
rew
.
Sign
()
>
0
{
err
.
RewindTo
=
rew
.
Uint64
()
-
1
err
.
RewindToBlock
=
rew
.
Uint64
()
-
1
}
return
err
}
func
newTimestampCompatError
(
what
string
,
storedtime
,
newtime
*
big
.
Int
)
*
ConfigCompatError
{
var
rew
*
big
.
Int
switch
{
case
storedtime
==
nil
:
rew
=
newtime
case
newtime
==
nil
||
storedtime
.
Cmp
(
newtime
)
<
0
:
rew
=
storedtime
default
:
rew
=
newtime
}
err
:=
&
ConfigCompatError
{
What
:
what
,
StoredTime
:
storedtime
,
NewTime
:
newtime
,
RewindToTime
:
0
,
}
if
rew
!=
nil
&&
rew
.
Sign
()
>
0
{
err
.
RewindToTime
=
rew
.
Uint64
()
-
1
}
return
err
}
func
(
err
*
ConfigCompatError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"mismatching %s in database (have %d, want %d, rewindto %d)"
,
err
.
What
,
err
.
StoredConfig
,
err
.
NewConfig
,
err
.
RewindTo
)
if
err
.
StoredBlock
!=
nil
{
return
fmt
.
Sprintf
(
"mismatching %s in database (have block %d, want block %d, rewindto block %d)"
,
err
.
What
,
err
.
StoredBlock
,
err
.
NewBlock
,
err
.
RewindToBlock
)
}
return
fmt
.
Sprintf
(
"mismatching %s in database (have timestamp %d, want timestamp %d, rewindto timestamp %d)"
,
err
.
What
,
err
.
StoredTime
,
err
.
NewTime
,
err
.
RewindToTime
)
}
// Rules wraps ChainConfig and is merely syntactic sugar or can be used for functions
...
...
params/config_test.go
View file @
08481028
...
...
@@ -20,79 +20,99 @@ import (
"math/big"
"reflect"
"testing"
"time"
)
func
TestCheckCompatible
(
t
*
testing
.
T
)
{
type
test
struct
{
stored
,
new
*
ChainConfig
head
uint64
headBlock
uint64
headTimestamp
uint64
wantErr
*
ConfigCompatError
}
tests
:=
[]
test
{
{
stored
:
AllEthashProtocolChanges
,
new
:
AllEthashProtocolChanges
,
head
:
0
,
wantErr
:
nil
},
{
stored
:
AllEthashProtocolChanges
,
new
:
AllEthashProtocolChanges
,
head
:
100
,
wantErr
:
nil
},
{
stored
:
AllEthashProtocolChanges
,
new
:
AllEthashProtocolChanges
,
headBlock
:
0
,
headTimestamp
:
0
,
wantErr
:
nil
},
{
stored
:
AllEthashProtocolChanges
,
new
:
AllEthashProtocolChanges
,
headBlock
:
0
,
headTimestamp
:
uint64
(
time
.
Now
()
.
Unix
()),
wantErr
:
nil
},
{
stored
:
AllEthashProtocolChanges
,
new
:
AllEthashProtocolChanges
,
headBlock
:
100
,
wantErr
:
nil
},
{
stored
:
&
ChainConfig
{
EIP150Block
:
big
.
NewInt
(
10
)},
new
:
&
ChainConfig
{
EIP150Block
:
big
.
NewInt
(
20
)},
head
:
9
,
head
Block
:
9
,
wantErr
:
nil
,
},
{
stored
:
AllEthashProtocolChanges
,
new
:
&
ChainConfig
{
HomesteadBlock
:
nil
},
head
:
3
,
head
Block
:
3
,
wantErr
:
&
ConfigCompatError
{
What
:
"Homestead fork block"
,
Stored
Config
:
big
.
NewInt
(
0
),
New
Config
:
nil
,
RewindTo
:
0
,
Stored
Block
:
big
.
NewInt
(
0
),
New
Block
:
nil
,
RewindTo
Block
:
0
,
},
},
{
stored
:
AllEthashProtocolChanges
,
new
:
&
ChainConfig
{
HomesteadBlock
:
big
.
NewInt
(
1
)},
head
:
3
,
head
Block
:
3
,
wantErr
:
&
ConfigCompatError
{
What
:
"Homestead fork block"
,
Stored
Config
:
big
.
NewInt
(
0
),
New
Config
:
big
.
NewInt
(
1
),
RewindTo
:
0
,
Stored
Block
:
big
.
NewInt
(
0
),
New
Block
:
big
.
NewInt
(
1
),
RewindTo
Block
:
0
,
},
},
{
stored
:
&
ChainConfig
{
HomesteadBlock
:
big
.
NewInt
(
30
),
EIP150Block
:
big
.
NewInt
(
10
)},
new
:
&
ChainConfig
{
HomesteadBlock
:
big
.
NewInt
(
25
),
EIP150Block
:
big
.
NewInt
(
20
)},
head
:
25
,
head
Block
:
25
,
wantErr
:
&
ConfigCompatError
{
What
:
"EIP150 fork block"
,
Stored
Config
:
big
.
NewInt
(
10
),
New
Config
:
big
.
NewInt
(
20
),
RewindTo
:
9
,
Stored
Block
:
big
.
NewInt
(
10
),
New
Block
:
big
.
NewInt
(
20
),
RewindTo
Block
:
9
,
},
},
{
stored
:
&
ChainConfig
{
ConstantinopleBlock
:
big
.
NewInt
(
30
)},
new
:
&
ChainConfig
{
ConstantinopleBlock
:
big
.
NewInt
(
30
),
PetersburgBlock
:
big
.
NewInt
(
30
)},
head
:
40
,
head
Block
:
40
,
wantErr
:
nil
,
},
{
stored
:
&
ChainConfig
{
ConstantinopleBlock
:
big
.
NewInt
(
30
)},
new
:
&
ChainConfig
{
ConstantinopleBlock
:
big
.
NewInt
(
30
),
PetersburgBlock
:
big
.
NewInt
(
31
)},
head
:
40
,
head
Block
:
40
,
wantErr
:
&
ConfigCompatError
{
What
:
"Petersburg fork block"
,
StoredConfig
:
nil
,
NewConfig
:
big
.
NewInt
(
31
),
RewindTo
:
30
,
StoredBlock
:
nil
,
NewBlock
:
big
.
NewInt
(
31
),
RewindToBlock
:
30
,
},
},
{
stored
:
&
ChainConfig
{
ShanghaiTime
:
big
.
NewInt
(
10
)},
new
:
&
ChainConfig
{
ShanghaiTime
:
big
.
NewInt
(
20
)},
headTimestamp
:
9
,
wantErr
:
nil
,
},
{
stored
:
&
ChainConfig
{
ShanghaiTime
:
big
.
NewInt
(
10
)},
new
:
&
ChainConfig
{
ShanghaiTime
:
big
.
NewInt
(
20
)},
headTimestamp
:
25
,
wantErr
:
&
ConfigCompatError
{
What
:
"Shanghai fork timestamp"
,
StoredTime
:
big
.
NewInt
(
10
),
NewTime
:
big
.
NewInt
(
20
),
RewindToTime
:
9
,
},
},
}
for
_
,
test
:=
range
tests
{
err
:=
test
.
stored
.
CheckCompatible
(
test
.
new
,
test
.
head
)
err
:=
test
.
stored
.
CheckCompatible
(
test
.
new
,
test
.
head
Block
,
test
.
headTimestamp
)
if
!
reflect
.
DeepEqual
(
err
,
test
.
wantErr
)
{
t
.
Errorf
(
"error mismatch:
\n
stored: %v
\n
new: %v
\n
head
: %v
\n
err: %v
\n
want: %v"
,
test
.
stored
,
test
.
new
,
test
.
head
,
err
,
test
.
wantErr
)
t
.
Errorf
(
"error mismatch:
\n
stored: %v
\n
new: %v
\n
head
Block: %v
\n
headTimestamp: %v
\n
err: %v
\n
want: %v"
,
test
.
stored
,
test
.
new
,
test
.
headBlock
,
test
.
headTimestamp
,
err
,
test
.
wantErr
)
}
}
}
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