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
b06320cd
Commit
b06320cd
authored
Nov 06, 2023
by
Joshua Gutow
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-chain-ops: Canyon checker script
parent
55f603e4
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
280 additions
and
0 deletions
+280
-0
main.go
op-chain-ops/cmd/check-canyon/main.go
+280
-0
No files found.
op-chain-ops/cmd/check-canyon/main.go
0 → 100644
View file @
b06320cd
package
main
import
(
"bytes"
"context"
"errors"
"flag"
"fmt"
"math/big"
"os"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/client"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
)
func
CalcBaseFee
(
parent
eth
.
BlockInfo
,
elasticity
uint64
,
canyonActive
bool
)
*
big
.
Int
{
denomUint
:=
uint64
(
50
)
if
canyonActive
{
denomUint
=
uint64
(
250
)
}
parentGasTarget
:=
parent
.
GasLimit
()
/
elasticity
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
if
parent
.
GasUsed
()
==
parentGasTarget
{
return
new
(
big
.
Int
)
.
Set
(
parent
.
BaseFee
())
}
var
(
num
=
new
(
big
.
Int
)
denom
=
new
(
big
.
Int
)
)
if
parent
.
GasUsed
()
>
parentGasTarget
{
// If the parent block used more gas than its target, the baseFee should increase.
// max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
num
.
SetUint64
(
parent
.
GasUsed
()
-
parentGasTarget
)
num
.
Mul
(
num
,
parent
.
BaseFee
())
num
.
Div
(
num
,
denom
.
SetUint64
(
parentGasTarget
))
num
.
Div
(
num
,
denom
.
SetUint64
(
denomUint
))
baseFeeDelta
:=
math
.
BigMax
(
num
,
common
.
Big1
)
return
num
.
Add
(
parent
.
BaseFee
(),
baseFeeDelta
)
}
else
{
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
// max(0, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
num
.
SetUint64
(
parentGasTarget
-
parent
.
GasUsed
())
num
.
Mul
(
num
,
parent
.
BaseFee
())
num
.
Div
(
num
,
denom
.
SetUint64
(
parentGasTarget
))
num
.
Div
(
num
,
denom
.
SetUint64
(
denomUint
))
baseFee
:=
num
.
Sub
(
parent
.
BaseFee
(),
num
)
return
math
.
BigMax
(
baseFee
,
common
.
Big0
)
}
}
func
ManuallyEncodeReceipts
(
receipts
types
.
Receipts
,
canyonActive
bool
)
[][]
byte
{
v
:=
uint64
(
1
)
for
_
,
receipt
:=
range
receipts
{
if
receipt
.
Type
==
types
.
DepositTxType
{
if
canyonActive
{
receipt
.
DepositReceiptVersion
=
&
v
}
else
{
receipt
.
DepositReceiptVersion
=
nil
}
}
}
var
out
[][]
byte
for
i
:=
range
receipts
{
var
buf
bytes
.
Buffer
receipts
.
EncodeIndex
(
i
,
&
buf
)
out
=
append
(
out
,
buf
.
Bytes
())
}
return
out
}
type
rawReceipts
[][]
byte
func
(
s
rawReceipts
)
Len
()
int
{
return
len
(
s
)
}
func
(
s
rawReceipts
)
EncodeIndex
(
i
int
,
w
*
bytes
.
Buffer
)
{
w
.
Write
(
s
[
i
])
}
func
HashList
(
list
[][]
byte
)
common
.
Hash
{
hasher
:=
trie
.
NewStackTrie
(
nil
)
return
types
.
DeriveSha
(
rawReceipts
(
list
),
hasher
)
}
type
L2Client
interface
{
BlockByNumber
(
context
.
Context
,
*
big
.
Int
)
(
*
types
.
Block
,
error
)
CodeAt
(
context
.
Context
,
common
.
Address
,
*
big
.
Int
)
([]
byte
,
error
)
InfoByNumber
(
context
.
Context
,
uint64
)
(
eth
.
BlockInfo
,
error
)
FetchReceipts
(
context
.
Context
,
common
.
Hash
)
(
eth
.
BlockInfo
,
types
.
Receipts
,
error
)
}
type
Client
struct
{
*
ethclient
.
Client
*
sources
.
L1Client
}
type
Args
struct
{
Number
uint64
Elasticity
uint64
Client
L2Client
}
func
ValidateReceipts
(
ctx
Args
,
canyonActive
bool
)
error
{
block
,
err
:=
ctx
.
Client
.
InfoByNumber
(
context
.
Background
(),
ctx
.
Number
)
if
err
!=
nil
{
return
err
}
_
,
receipts
,
err
:=
ctx
.
Client
.
FetchReceipts
(
context
.
Background
(),
block
.
Hash
())
if
err
!=
nil
{
return
err
}
have
:=
block
.
ReceiptHash
()
want
:=
HashList
(
ManuallyEncodeReceipts
(
receipts
,
canyonActive
))
if
have
!=
want
{
return
fmt
.
Errorf
(
"Receipts do not look correct. canyonActive: %v. have: %v, want: %v"
,
canyonActive
,
have
,
want
)
}
return
nil
}
func
Validate1559Params
(
ctx
Args
,
canyonActive
bool
)
error
{
block
,
err
:=
ctx
.
Client
.
InfoByNumber
(
context
.
Background
(),
ctx
.
Number
)
if
err
!=
nil
{
return
err
}
if
block
.
BaseFee
()
.
Cmp
(
big
.
NewInt
(
1000
))
<
0
{
log
.
Info
(
"Basefee to low to properly validate"
,
"basefee"
,
block
.
BaseFee
())
return
nil
}
parent
,
err
:=
ctx
.
Client
.
InfoByNumber
(
context
.
Background
(),
ctx
.
Number
-
1
)
if
err
!=
nil
{
return
err
}
want
:=
CalcBaseFee
(
parent
,
ctx
.
Elasticity
,
canyonActive
)
have
:=
block
.
BaseFee
()
if
have
.
Cmp
(
want
)
!=
0
{
return
fmt
.
Errorf
(
"BaseFee does not match. canyonActive: %v. have: %v, want: %v"
,
canyonActive
,
have
,
want
)
}
return
nil
}
func
ValidateWithdrawals
(
ctx
Args
,
canyonActive
bool
)
error
{
block
,
err
:=
ctx
.
Client
.
BlockByNumber
(
context
.
Background
(),
new
(
big
.
Int
)
.
SetUint64
(
ctx
.
Number
))
if
err
!=
nil
{
return
err
}
if
canyonActive
&&
block
.
Withdrawals
()
==
nil
{
return
errors
.
New
(
"No nonwithdrawals in a canyon block"
)
}
else
if
canyonActive
&&
len
(
block
.
Withdrawals
())
>
0
{
return
errors
.
New
(
"Withdrawals length is not zero in a canyon block"
)
}
else
if
!
canyonActive
&&
block
.
Withdrawals
()
!=
nil
{
return
errors
.
New
(
"Withdrawals in a pre-canyon block"
)
}
return
nil
}
func
ValidateCreate2Deployer
(
ctx
Args
,
canyonActive
bool
)
error
{
addr
:=
common
.
HexToAddress
(
"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2"
)
code
,
err
:=
ctx
.
Client
.
CodeAt
(
context
.
Background
(),
addr
,
new
(
big
.
Int
)
.
SetUint64
(
ctx
.
Number
))
if
err
!=
nil
{
return
err
}
codeHash
:=
crypto
.
Keccak256Hash
(
code
)
expectedCodeHash
:=
common
.
HexToHash
(
"0xb0550b5b431e30d38000efb7107aaa0ade03d48a7198a140edda9d27134468b2"
)
if
canyonActive
&&
codeHash
!=
expectedCodeHash
{
return
fmt
.
Errorf
(
"Canyon active but code hash does not match. have: %v, want: %v"
,
codeHash
,
expectedCodeHash
)
}
else
if
!
canyonActive
&&
codeHash
==
expectedCodeHash
{
return
fmt
.
Errorf
(
"Canyon not active but code hashes do match. codeHash: %v"
,
codeHash
)
}
return
nil
}
// CheckActivation takes a function f which determines in a specific block follows the rules of a fork.
// forkActivated tells `f` if the fork is active or not. `f` is called twice: First to validate that
// there is no error when checking the new value and second to validate the it returns an error when
// attempting to validate the block against the opposite of what is is.
// If any error is encountered, valid is set to false.
func
CheckActivation
(
f
func
(
Args
,
bool
)
error
,
ctx
Args
,
forkActivated
bool
,
valid
*
bool
)
{
if
forkActivated
{
if
err
:=
f
(
ctx
,
true
);
err
!=
nil
{
log
.
Error
(
"Pre-state was invalid when it was expected to be valid"
,
"err"
,
err
)
*
valid
=
false
}
if
err
:=
f
(
ctx
,
false
);
err
==
nil
{
log
.
Error
(
"Post-state was valid when it was expected to be invalid"
)
*
valid
=
false
}
}
else
{
if
err
:=
f
(
ctx
,
true
);
err
==
nil
{
log
.
Error
(
"Pre-state was valid when it was expected to be invalid"
)
*
valid
=
false
}
if
err
:=
f
(
ctx
,
false
);
err
!=
nil
{
log
.
Error
(
"Post-state was invalid when it was expected to be valid"
,
"err"
,
err
)
*
valid
=
false
}
}
}
func
main
()
{
logger
:=
log
.
New
()
// Define the flag variables
var
(
canyonActive
bool
number
uint64
elasticity
uint64
rpcURL
string
)
valid
:=
true
// Define and parse the command-line flags
flag
.
BoolVar
(
&
canyonActive
,
"canyon"
,
false
,
"Set this flag to assert canyon behavior"
)
flag
.
Uint64Var
(
&
number
,
"number"
,
31
,
"Block number to check"
)
flag
.
Uint64Var
(
&
elasticity
,
"elasticity"
,
6
,
"Specify the EIP-1559 elasticity. 6 on mainnet/sepolia. 10 on goerli"
)
flag
.
StringVar
(
&
rpcURL
,
"rpc-url"
,
"http://localhost:8545"
,
"Specify the L2 ETH RPC URL"
)
// Parse the command-line arguments
flag
.
Parse
()
l2RPC
,
err
:=
client
.
NewRPC
(
context
.
Background
(),
logger
,
rpcURL
,
client
.
WithDialBackoff
(
10
))
if
err
!=
nil
{
log
.
Crit
(
"Error creating RPC"
,
"err"
,
err
)
}
c
:=
&
rollup
.
Config
{
SeqWindowSize
:
10
}
l2Cfg
:=
sources
.
L1ClientDefaultConfig
(
c
,
true
,
sources
.
RPCKindBasic
)
sourceClient
,
err
:=
sources
.
NewL1Client
(
l2RPC
,
logger
,
nil
,
l2Cfg
)
if
err
!=
nil
{
log
.
Crit
(
"Error creating RPC"
,
"err"
,
err
)
}
ethClient
,
err
:=
ethclient
.
Dial
(
rpcURL
)
if
err
!=
nil
{
log
.
Crit
(
"Error creating RPC"
,
"err"
,
err
)
}
client
:=
Client
{
ethClient
,
sourceClient
}
ctx
:=
Args
{
Number
:
number
,
Elasticity
:
elasticity
,
Client
:
client
,
}
CheckActivation
(
ValidateReceipts
,
ctx
,
canyonActive
,
&
valid
)
CheckActivation
(
Validate1559Params
,
ctx
,
canyonActive
,
&
valid
)
CheckActivation
(
ValidateWithdrawals
,
ctx
,
canyonActive
,
&
valid
)
CheckActivation
(
ValidateCreate2Deployer
,
ctx
,
canyonActive
,
&
valid
)
if
!
valid
{
os
.
Exit
(
1
)
}
else
if
canyonActive
{
log
.
Info
(
fmt
.
Sprintf
(
"Successfully validated block %v as a Canyon block"
,
number
))
}
else
{
log
.
Info
(
fmt
.
Sprintf
(
"Successfully validated block %v as a Pre-Canyon block"
,
number
))
}
}
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