Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
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
exchain
nebula
Commits
6d376644
Commit
6d376644
authored
Jan 19, 2022
by
Mark Tyneway
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
l2geth: implement hardforking logic
Be sure to switch to using the new rules at a specific height
parent
02c2a703
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
62 additions
and
11 deletions
+62
-11
state_transition.go
l2geth/core/state_transition.go
+6
-0
evm.go
l2geth/core/vm/evm.go
+11
-1
interpreter.go
l2geth/core/vm/interpreter.go
+5
-4
runtime.go
l2geth/core/vm/runtime/runtime.go
+11
-1
config.go
l2geth/params/config.go
+19
-5
state_test_util.go
l2geth/tests/state_test_util.go
+10
-0
No files found.
l2geth/core/state_transition.go
View file @
6d376644
...
...
@@ -79,6 +79,7 @@ type Message interface {
Nonce
()
uint64
CheckNonce
()
bool
Data
()
[]
byte
AccessList
()
types
.
AccessList
L1Timestamp
()
uint64
L1BlockNumber
()
*
big
.
Int
...
...
@@ -254,6 +255,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
vmerr
error
)
// The access list gets created here
if
rules
:=
st
.
evm
.
ChainConfig
()
.
Rules
(
st
.
evm
.
Context
.
BlockNumber
);
rules
.
IsBerlin
{
st
.
state
.
PrepareAccessList
(
msg
.
From
(),
msg
.
To
(),
vm
.
ActivePrecompiles
(
rules
),
msg
.
AccessList
())
}
if
contractCreation
{
ret
,
_
,
st
.
gas
,
vmerr
=
evm
.
Create
(
sender
,
st
.
data
,
st
.
gas
,
st
.
value
)
}
else
{
...
...
l2geth/core/vm/evm.go
View file @
6d376644
...
...
@@ -55,6 +55,9 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err
if
evm
.
chainRules
.
IsIstanbul
{
precompiles
=
PrecompiledContractsIstanbul
}
if
evm
.
chainRules
.
IsBerlin
{
precompiles
=
PrecompiledContractsBerlin
}
if
p
:=
precompiles
[
*
contract
.
CodeAddr
];
p
!=
nil
{
return
RunPrecompiledContract
(
p
,
input
,
contract
)
}
...
...
@@ -220,6 +223,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
if
evm
.
chainRules
.
IsIstanbul
{
precompiles
=
PrecompiledContractsIstanbul
}
if
evm
.
chainRules
.
IsBerlin
{
precompiles
=
PrecompiledContractsBerlin
}
if
precompiles
[
addr
]
==
nil
&&
evm
.
chainRules
.
IsEIP158
&&
value
.
Sign
()
==
0
{
// Calling a non existing account, don't do anything, but ping the tracer
if
evm
.
vmConfig
.
Debug
&&
evm
.
depth
==
0
{
...
...
@@ -413,7 +419,11 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
}
nonce
:=
evm
.
StateDB
.
GetNonce
(
caller
.
Address
())
evm
.
StateDB
.
SetNonce
(
caller
.
Address
(),
nonce
+
1
)
// We add this to the access list _before_ taking a snapshot. Even if the creation fails,
// the access-list change should not be rolled back
if
evm
.
chainRules
.
IsBerlin
{
evm
.
StateDB
.
AddAddressToAccessList
(
address
)
}
// Ensure there's no existing contract already at the designated address
contractHash
:=
evm
.
StateDB
.
GetCodeHash
(
address
)
if
evm
.
StateDB
.
GetNonce
(
address
)
!=
0
||
(
contractHash
!=
(
common
.
Hash
{})
&&
contractHash
!=
emptyCodeHash
)
{
...
...
l2geth/core/vm/interpreter.go
View file @
6d376644
...
...
@@ -94,8 +94,13 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
if
!
cfg
.
JumpTable
[
STOP
]
.
valid
{
var
jt
JumpTable
switch
{
case
evm
.
chainRules
.
IsBerlin
:
jt
=
berlinInstructionSet
case
evm
.
chainRules
.
IsIstanbul
:
jt
=
istanbulInstructionSet
if
rcfg
.
UsingOVM
{
enableMinimal2929
(
&
jt
)
}
case
evm
.
chainRules
.
IsConstantinople
:
jt
=
constantinopleInstructionSet
case
evm
.
chainRules
.
IsByzantium
:
...
...
@@ -116,10 +121,6 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
log
.
Error
(
"EIP activation failed"
,
"eip"
,
eip
,
"error"
,
err
)
}
}
// Enable minimal eip 2929
if
rcfg
.
UsingOVM
{
enableMinimal2929
(
&
jt
)
}
cfg
.
JumpTable
=
jt
}
...
...
l2geth/core/vm/runtime/runtime.go
View file @
6d376644
...
...
@@ -106,6 +106,9 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
vmenv
=
NewEnv
(
cfg
)
sender
=
vm
.
AccountRef
(
cfg
.
Origin
)
)
if
rules
:=
cfg
.
ChainConfig
.
Rules
(
vmenv
.
Context
.
BlockNumber
);
rules
.
IsBerlin
{
cfg
.
State
.
PrepareAccessList
(
cfg
.
Origin
,
&
address
,
vm
.
ActivePrecompiles
(
rules
),
nil
)
}
cfg
.
State
.
CreateAccount
(
address
)
// set the receiver's (the executing contract) code for execution.
cfg
.
State
.
SetCode
(
address
,
code
)
...
...
@@ -135,7 +138,9 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
vmenv
=
NewEnv
(
cfg
)
sender
=
vm
.
AccountRef
(
cfg
.
Origin
)
)
if
rules
:=
cfg
.
ChainConfig
.
Rules
(
vmenv
.
Context
.
BlockNumber
);
rules
.
IsBerlin
{
cfg
.
State
.
PrepareAccessList
(
cfg
.
Origin
,
nil
,
vm
.
ActivePrecompiles
(
rules
),
nil
)
}
// Call the code with the given configuration.
code
,
address
,
leftOverGas
,
err
:=
vmenv
.
Create
(
sender
,
...
...
@@ -157,6 +162,11 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
vmenv
:=
NewEnv
(
cfg
)
sender
:=
cfg
.
State
.
GetOrNewStateObject
(
cfg
.
Origin
)
statedb
:=
cfg
.
State
if
rules
:=
cfg
.
ChainConfig
.
Rules
(
vmenv
.
Context
.
BlockNumber
);
rules
.
IsBerlin
{
statedb
.
PrepareAccessList
(
cfg
.
Origin
,
&
address
,
vm
.
ActivePrecompiles
(
rules
),
nil
)
}
// Call the code with the given configuration.
ret
,
leftOverGas
,
err
:=
vmenv
.
Call
(
sender
,
...
...
l2geth/params/config.go
View file @
6d376644
...
...
@@ -215,16 +215,16 @@ var (
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllEthashProtocolChanges
=
&
ChainConfig
{
big
.
NewInt
(
108
),
big
.
NewInt
(
0
),
nil
,
false
,
big
.
NewInt
(
0
),
common
.
Hash
{},
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
nil
,
nil
,
new
(
EthashConfig
),
nil
}
AllEthashProtocolChanges
=
&
ChainConfig
{
big
.
NewInt
(
108
),
big
.
NewInt
(
0
),
nil
,
false
,
big
.
NewInt
(
0
),
common
.
Hash
{},
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
nil
,
nil
,
new
(
EthashConfig
),
nil
}
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the Clique consensus.
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllCliqueProtocolChanges
=
&
ChainConfig
{
big
.
NewInt
(
420
),
big
.
NewInt
(
0
),
nil
,
false
,
big
.
NewInt
(
0
),
common
.
Hash
{},
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
nil
,
nil
,
nil
,
&
CliqueConfig
{
Period
:
0
,
Epoch
:
30000
}}
AllCliqueProtocolChanges
=
&
ChainConfig
{
big
.
NewInt
(
420
),
big
.
NewInt
(
0
),
nil
,
false
,
big
.
NewInt
(
0
),
common
.
Hash
{},
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
nil
,
nil
,
nil
,
&
CliqueConfig
{
Period
:
0
,
Epoch
:
30000
}}
TestChainConfig
=
&
ChainConfig
{
big
.
NewInt
(
1
),
big
.
NewInt
(
0
),
nil
,
false
,
big
.
NewInt
(
0
),
common
.
Hash
{},
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
nil
,
nil
,
new
(
EthashConfig
),
nil
}
TestChainConfig
=
&
ChainConfig
{
big
.
NewInt
(
1
),
big
.
NewInt
(
0
),
nil
,
false
,
big
.
NewInt
(
0
),
common
.
Hash
{},
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
nil
,
nil
,
new
(
EthashConfig
),
nil
}
TestRules
=
TestChainConfig
.
Rules
(
new
(
big
.
Int
))
)
...
...
@@ -295,7 +295,9 @@ type ChainConfig struct {
PetersburgBlock
*
big
.
Int
`json:"petersburgBlock,omitempty"`
// Petersburg switch block (nil = same as Constantinople)
IstanbulBlock
*
big
.
Int
`json:"istanbulBlock,omitempty"`
// Istanbul switch block (nil = no fork, 0 = already on istanbul)
MuirGlacierBlock
*
big
.
Int
`json:"muirGlacierBlock,omitempty"`
// Eip-2384 (bomb delay) switch block (nil = no fork, 0 = already activated)
EWASMBlock
*
big
.
Int
`json:"ewasmBlock,omitempty"`
// EWASM switch block (nil = no fork, 0 = already activated)
BerlinBlock
*
big
.
Int
`json:"berlinBlock,omitempty"`
// Berlin switch block (nil = no fork, 0 = already on berlin)
EWASMBlock
*
big
.
Int
`json:"ewasmBlock,omitempty"`
// EWASM switch block (nil = no fork, 0 = already activated)
// Various consensus engines
Ethash
*
EthashConfig
`json:"ethash,omitempty"`
...
...
@@ -332,7 +334,7 @@ func (c *ChainConfig) String() string {
default
:
engine
=
"unknown"
}
return
fmt
.
Sprintf
(
"{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Engine: %v}"
,
return
fmt
.
Sprintf
(
"{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v,
Berlin: %v,
Engine: %v}"
,
c
.
ChainID
,
c
.
HomesteadBlock
,
c
.
DAOForkBlock
,
...
...
@@ -345,6 +347,7 @@ func (c *ChainConfig) String() string {
c
.
PetersburgBlock
,
c
.
IstanbulBlock
,
c
.
MuirGlacierBlock
,
c
.
BerlinBlock
,
engine
,
)
}
...
...
@@ -401,6 +404,11 @@ func (c *ChainConfig) IsIstanbul(num *big.Int) bool {
return
isForked
(
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
)
}
// IsEWASM returns whether num represents a block number after the EWASM fork
func
(
c
*
ChainConfig
)
IsEWASM
(
num
*
big
.
Int
)
bool
{
return
isForked
(
c
.
EWASMBlock
,
num
)
...
...
@@ -442,6 +450,7 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
{
"petersburgBlock"
,
c
.
PetersburgBlock
},
{
"istanbulBlock"
,
c
.
IstanbulBlock
},
{
"muirGlacierBlock"
,
c
.
MuirGlacierBlock
},
{
name
:
"berlinBlock"
,
block
:
c
.
BerlinBlock
},
}
{
if
lastFork
.
name
!=
""
{
// Next one must be higher number
...
...
@@ -498,6 +507,9 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi
if
isForkIncompatible
(
c
.
MuirGlacierBlock
,
newcfg
.
MuirGlacierBlock
,
head
)
{
return
newCompatError
(
"Muir Glacier fork block"
,
c
.
MuirGlacierBlock
,
newcfg
.
MuirGlacierBlock
)
}
if
isForkIncompatible
(
c
.
BerlinBlock
,
newcfg
.
BerlinBlock
,
head
)
{
return
newCompatError
(
"Berlin fork block"
,
c
.
BerlinBlock
,
newcfg
.
BerlinBlock
)
}
if
isForkIncompatible
(
c
.
EWASMBlock
,
newcfg
.
EWASMBlock
,
head
)
{
return
newCompatError
(
"ewasm fork block"
,
c
.
EWASMBlock
,
newcfg
.
EWASMBlock
)
}
...
...
@@ -568,6 +580,7 @@ type Rules struct {
ChainID
*
big
.
Int
IsHomestead
,
IsEIP150
,
IsEIP155
,
IsEIP158
bool
IsByzantium
,
IsConstantinople
,
IsPetersburg
,
IsIstanbul
bool
IsBerlin
bool
}
// Rules ensures c's ChainID is not nil.
...
...
@@ -586,5 +599,6 @@ func (c *ChainConfig) Rules(num *big.Int) Rules {
IsConstantinople
:
c
.
IsConstantinople
(
num
),
IsPetersburg
:
c
.
IsPetersburg
(
num
),
IsIstanbul
:
c
.
IsIstanbul
(
num
),
IsBerlin
:
c
.
IsBerlin
(
num
),
}
}
l2geth/tests/state_test_util.go
View file @
6d376644
...
...
@@ -181,6 +181,16 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config) (*stat
context
.
GetHash
=
vmTestBlockHash
evm
:=
vm
.
NewEVM
(
context
,
statedb
,
config
,
vmconfig
)
if
config
.
IsBerlin
(
context
.
BlockNumber
)
{
statedb
.
AddAddressToAccessList
(
msg
.
From
())
if
dst
:=
msg
.
To
();
dst
!=
nil
{
statedb
.
AddAddressToAccessList
(
*
dst
)
// If it's a create-tx, the destination will be added inside evm.create
}
for
_
,
addr
:=
range
vm
.
ActivePrecompiles
(
config
.
Rules
(
context
.
BlockNumber
))
{
statedb
.
AddAddressToAccessList
(
addr
)
}
}
gaspool
:=
new
(
core
.
GasPool
)
gaspool
.
AddGas
(
block
.
GasLimit
())
snapshot
:=
statedb
.
Snapshot
()
...
...
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