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
9343f33e
Commit
9343f33e
authored
Jan 14, 2022
by
Mark Tyneway
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
integration-tests: add berlin hardfork tests
Add integration tests to test the hardfork logic
parent
c201aeba
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
276 additions
and
19 deletions
+276
-19
early-baboons-look.md
.changeset/early-baboons-look.md
+5
-0
Precompiles.sol
integration-tests/contracts/Precompiles.sol
+23
-0
SelfDestruction.sol
integration-tests/contracts/SelfDestruction.sol
+15
-0
hardfork.spec.ts
integration-tests/test/hardfork.spec.ts
+207
-0
rpc.spec.ts
integration-tests/test/rpc.spec.ts
+26
-19
No files found.
.changeset/early-baboons-look.md
0 → 100644
View file @
9343f33e
---
'
@eth-optimism/integration-tests'
:
patch
---
Add in berlin hardfork tests
integration-tests/contracts/Precompiles.sol
0 → 100644
View file @
9343f33e
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract Precompiles {
function expmod(uint256 base, uint256 e, uint256 m) public returns (uint256 o) {
assembly {
// define pointer
let p := mload(0x40)
// store data assembly-favouring ways
mstore(p, 0x20) // Length of Base
mstore(add(p, 0x20), 0x20) // Length of Exponent
mstore(add(p, 0x40), 0x20) // Length of Modulus
mstore(add(p, 0x60), base) // Base
mstore(add(p, 0x80), e) // Exponent
mstore(add(p, 0xa0), m) // Modulus
if iszero(staticcall(sub(gas(), 2000), 0x05, p, 0xc0, p, 0x20)) {
revert(0, 0)
}
// data
o := mload(p)
}
}
}
integration-tests/contracts/SelfDestruction.sol
0 → 100644
View file @
9343f33e
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract SelfDestruction {
bytes32 public data = 0x0000000000000000000000000000000000000000000000000000000061626364;
function setData(bytes32 _data) public {
data = _data;
}
function destruct() public {
address payable self = payable(address(this));
selfdestruct(self);
}
}
integration-tests/test/hardfork.spec.ts
0 → 100644
View file @
9343f33e
import
{
expect
}
from
'
./shared/setup
'
import
{
Contract
,
BigNumber
}
from
'
ethers
'
import
{
ethers
}
from
'
hardhat
'
import
{
OptimismEnv
}
from
'
./shared/env
'
const
traceToGasByOpcode
=
(
structLogs
,
opcode
)
=>
{
let
gas
=
0
const
opcodes
=
[]
for
(
const
log
of
structLogs
)
{
if
(
log
.
op
===
opcode
)
{
opcodes
.
push
(
opcode
)
gas
+=
log
.
gasCost
}
}
return
gas
}
describe
(
'
Hard forks
'
,
()
=>
{
let
env
:
OptimismEnv
let
SimpleStorage
:
Contract
let
SelfDestruction
:
Contract
let
Precompiles
:
Contract
before
(
async
()
=>
{
env
=
await
OptimismEnv
.
new
()
const
Factory__SimpleStorage
=
await
ethers
.
getContractFactory
(
'
SimpleStorage
'
,
env
.
l2Wallet
)
SimpleStorage
=
await
Factory__SimpleStorage
.
deploy
()
const
Factory__SelfDestruction
=
await
ethers
.
getContractFactory
(
'
SelfDestruction
'
,
env
.
l2Wallet
)
SelfDestruction
=
await
Factory__SelfDestruction
.
deploy
()
const
Factory__Precompiles
=
await
ethers
.
getContractFactory
(
'
Precompiles
'
,
env
.
l2Wallet
)
Precompiles
=
await
Factory__Precompiles
.
deploy
()
})
describe
(
'
Berlin
'
,
()
=>
{
// https://eips.ethereum.org/EIPS/eip-2929
describe
(
'
EIP-2929
'
,
()
=>
{
it
(
'
should update the gas schedule
'
,
async
()
=>
{
// Get the tip height
const
tip
=
await
env
.
l2Provider
.
getBlock
(
'
latest
'
)
// send a transaction to be able to trace
const
tx
=
await
SimpleStorage
.
setValueNotXDomain
(
`0x
${
'
77
'
.
repeat
(
32
)}
`
)
await
tx
.
wait
()
// Collect the traces
const
berlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
]
)
const
preBerlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
,
{
overrides
:
{
berlinBlock
:
tip
.
number
+
10
}
}]
)
expect
(
berlinTrace
.
gas
).
to
.
not
.
eq
(
preBerlinTrace
.
gas
)
const
berlinSstoreCosts
=
traceToGasByOpcode
(
berlinTrace
.
structLogs
,
'
SSTORE
'
)
const
preBerlinSstoreCosts
=
traceToGasByOpcode
(
preBerlinTrace
.
structLogs
,
'
SSTORE
'
)
expect
(
berlinSstoreCosts
).
to
.
not
.
eq
(
preBerlinSstoreCosts
)
})
})
// https://eips.ethereum.org/EIPS/eip-2565
describe
(
'
EIP-2565
'
,
async
()
=>
{
it
(
'
should become cheaper
'
,
async
()
=>
{
const
tip
=
await
env
.
l2Provider
.
getBlock
(
'
latest
'
)
const
tx
=
await
Precompiles
.
expmod
(
64
,
1
,
64
,
{
gasLimit
:
5
_000_000
})
await
tx
.
wait
()
const
berlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
]
)
const
preBerlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
,
{
overrides
:
{
berlinBlock
:
tip
.
number
+
10
}
}]
)
expect
(
berlinTrace
.
gas
).
to
.
be
.
lt
(
preBerlinTrace
.
gas
)
})
})
})
// Optimism includes EIP-3529 as part of its Berlin hardfork. It is part
// of the London hardfork on L1. Since it is coupled to the Berlin
// hardfork, some of its functionality cannot be directly tests via
// integration tests since we can currently only turn on all of the Berlin
// EIPs or none of the Berlin EIPs
describe
(
'
Berlin Additional (L1 London)
'
,
()
=>
{
// https://eips.ethereum.org/EIPS/eip-3529
describe
(
'
EIP-3529
'
,
async
()
=>
{
const
bytes32Zero
=
'
0x
'
+
'
00
'
.
repeat
(
32
)
const
bytes32NonZero
=
'
0x
'
+
'
ff
'
.
repeat
(
32
)
it
(
'
should lower the refund for storage clear
'
,
async
()
=>
{
const
tip
=
await
env
.
l2Provider
.
getBlock
(
'
latest
'
)
const
value
=
await
SelfDestruction
.
callStatic
.
data
()
// It should be non zero
expect
(
BigNumber
.
from
(
value
).
toNumber
()).
to
.
not
.
eq
(
0
)
{
// Set the value to another non zero value
// Going from non zero to non zero
const
tx
=
await
SelfDestruction
.
setData
(
bytes32NonZero
,
{
gasLimit
:
5
_000_000
,
})
await
tx
.
wait
()
const
berlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
]
)
const
preBerlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
,
{
overrides
:
{
berlinBlock
:
tip
.
number
+
10
}
}]
)
// Updating a non zero value to another non zero value should not change
expect
(
berlinTrace
.
gas
).
to
.
deep
.
eq
(
preBerlinTrace
.
gas
)
}
{
// Set the value to the zero value
// Going from non zero to zero
const
tx
=
await
SelfDestruction
.
setData
(
bytes32Zero
,
{
gasLimit
:
5
_000_000
,
})
await
tx
.
wait
()
const
berlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
]
)
const
preBerlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
,
{
overrides
:
{
berlinBlock
:
tip
.
number
+
10
}
}]
)
// Updating to a zero value from a non zero value should becomes
// more expensive due to this change being coupled with EIP-2929
expect
(
berlinTrace
.
gas
).
to
.
be
.
gt
(
preBerlinTrace
.
gas
)
}
{
// Set the value to a non zero value
// Going from zero to non zero
const
tx
=
await
SelfDestruction
.
setData
(
bytes32NonZero
,
{
gasLimit
:
5
_000_000
,
})
await
tx
.
wait
()
const
berlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
]
)
const
preBerlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
,
{
overrides
:
{
berlinBlock
:
tip
.
number
+
10
}
}]
)
// Updating to a zero value from a non zero value should becomes
// more expensive due to this change being coupled with EIP-2929
expect
(
berlinTrace
.
gas
).
to
.
be
.
gt
(
preBerlinTrace
.
gas
)
}
})
it
(
'
should remove the refund for selfdestruct
'
,
async
()
=>
{
const
tip
=
await
env
.
l2Provider
.
getBlock
(
'
latest
'
)
// Send transaction with a large gas limit
const
tx
=
await
SelfDestruction
.
destruct
({
gasLimit
:
5
_000_000
})
await
tx
.
wait
()
const
berlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
]
)
const
preBerlinTrace
=
await
env
.
l2Provider
.
send
(
'
debug_traceTransaction
'
,
[
tx
.
hash
,
{
overrides
:
{
berlinBlock
:
tip
.
number
+
10
}
}]
)
// The berlin execution should use more gas than the pre Berlin
// execution because there is no longer a selfdestruct gas
// refund
expect
(
berlinTrace
.
gas
).
to
.
be
.
gt
(
preBerlinTrace
.
gas
)
})
})
})
})
integration-tests/test/rpc.spec.ts
View file @
9343f33e
...
@@ -27,6 +27,7 @@ describe('Basic RPC tests', () => {
...
@@ -27,6 +27,7 @@ describe('Basic RPC tests', () => {
const
provider
=
injectL2Context
(
l2Provider
)
const
provider
=
injectL2Context
(
l2Provider
)
let
Reverter
:
Contract
let
Reverter
:
Contract
let
ValueContext
:
Contract
let
revertMessage
:
string
let
revertMessage
:
string
let
revertingTx
:
TransactionRequest
let
revertingTx
:
TransactionRequest
let
revertingDeployTx
:
TransactionRequest
let
revertingDeployTx
:
TransactionRequest
...
@@ -52,6 +53,12 @@ describe('Basic RPC tests', () => {
...
@@ -52,6 +53,12 @@ describe('Basic RPC tests', () => {
revertingDeployTx
=
{
revertingDeployTx
=
{
data
:
Factory__ConstructorReverter
.
bytecode
,
data
:
Factory__ConstructorReverter
.
bytecode
,
}
}
// Deploy a contract to check msg.value of the call
const
Factory__ValueContext
:
ContractFactory
=
await
ethers
.
getContractFactory
(
'
ValueContext
'
,
wallet
)
ValueContext
=
await
Factory__ValueContext
.
deploy
()
await
ValueContext
.
deployTransaction
.
wait
()
})
})
describe
(
'
eth_sendRawTransaction
'
,
()
=>
{
describe
(
'
eth_sendRawTransaction
'
,
()
=>
{
...
@@ -211,12 +218,6 @@ describe('Basic RPC tests', () => {
...
@@ -211,12 +218,6 @@ describe('Basic RPC tests', () => {
})
})
it
(
'
should allow eth_calls with nonzero value
'
,
async
()
=>
{
it
(
'
should allow eth_calls with nonzero value
'
,
async
()
=>
{
// Deploy a contract to check msg.value of the call
const
Factory__ValueContext
:
ContractFactory
=
await
ethers
.
getContractFactory
(
'
ValueContext
'
,
wallet
)
const
ValueContext
:
Contract
=
await
Factory__ValueContext
.
deploy
()
await
ValueContext
.
deployTransaction
.
wait
()
// Fund account to call from
// Fund account to call from
const
from
=
wallet
.
address
const
from
=
wallet
.
address
const
value
=
15
const
value
=
15
...
@@ -236,12 +237,6 @@ describe('Basic RPC tests', () => {
...
@@ -236,12 +237,6 @@ describe('Basic RPC tests', () => {
// https://github.com/ethereum-optimism/optimism/issues/1998
// https://github.com/ethereum-optimism/optimism/issues/1998
it
(
'
should use address(0) as the default "from" value
'
,
async
()
=>
{
it
(
'
should use address(0) as the default "from" value
'
,
async
()
=>
{
// Deploy a contract to check msg.caller
const
Factory__ValueContext
:
ContractFactory
=
await
ethers
.
getContractFactory
(
'
ValueContext
'
,
wallet
)
const
ValueContext
:
Contract
=
await
Factory__ValueContext
.
deploy
()
await
ValueContext
.
deployTransaction
.
wait
()
// Do the call and check msg.sender
// Do the call and check msg.sender
const
data
=
ValueContext
.
interface
.
encodeFunctionData
(
'
getCaller
'
)
const
data
=
ValueContext
.
interface
.
encodeFunctionData
(
'
getCaller
'
)
const
res
=
await
provider
.
call
({
const
res
=
await
provider
.
call
({
...
@@ -258,12 +253,6 @@ describe('Basic RPC tests', () => {
...
@@ -258,12 +253,6 @@ describe('Basic RPC tests', () => {
})
})
it
(
'
should correctly use the "from" value
'
,
async
()
=>
{
it
(
'
should correctly use the "from" value
'
,
async
()
=>
{
// Deploy a contract to check msg.caller
const
Factory__ValueContext
:
ContractFactory
=
await
ethers
.
getContractFactory
(
'
ValueContext
'
,
wallet
)
const
ValueContext
:
Contract
=
await
Factory__ValueContext
.
deploy
()
await
ValueContext
.
deployTransaction
.
wait
()
const
from
=
wallet
.
address
const
from
=
wallet
.
address
// Do the call and check msg.sender
// Do the call and check msg.sender
...
@@ -280,6 +269,15 @@ describe('Basic RPC tests', () => {
...
@@ -280,6 +269,15 @@ describe('Basic RPC tests', () => {
)
)
expect
(
paddedRes
).
to
.
eq
(
from
)
expect
(
paddedRes
).
to
.
eq
(
from
)
})
})
it
(
'
should be deterministic
'
,
async
()
=>
{
let
res
=
await
ValueContext
.
callStatic
.
getSelfBalance
()
for
(
let
i
=
0
;
i
<
10
;
i
++
)
{
const
next
=
await
ValueContext
.
callStatic
.
getSelfBalance
()
expect
(
res
.
toNumber
()).
to
.
deep
.
eq
(
next
.
toNumber
())
res
=
next
}
})
})
})
describe
(
'
eth_getTransactionReceipt
'
,
()
=>
{
describe
(
'
eth_getTransactionReceipt
'
,
()
=>
{
...
@@ -453,7 +451,7 @@ describe('Basic RPC tests', () => {
...
@@ -453,7 +451,7 @@ describe('Basic RPC tests', () => {
})
})
describe
(
'
eth_estimateGas
'
,
()
=>
{
describe
(
'
eth_estimateGas
'
,
()
=>
{
it
(
'
gas estimation is deterministic
'
,
async
()
=>
{
it
(
'
simple send
gas estimation is deterministic
'
,
async
()
=>
{
let
lastEstimate
:
BigNumber
let
lastEstimate
:
BigNumber
for
(
let
i
=
0
;
i
<
10
;
i
++
)
{
for
(
let
i
=
0
;
i
<
10
;
i
++
)
{
const
estimate
=
await
l2Provider
.
estimateGas
({
const
estimate
=
await
l2Provider
.
estimateGas
({
...
@@ -469,6 +467,15 @@ describe('Basic RPC tests', () => {
...
@@ -469,6 +467,15 @@ describe('Basic RPC tests', () => {
}
}
})
})
it
(
'
deterministic gas estimation for evm execution
'
,
async
()
=>
{
let
res
=
await
ValueContext
.
estimateGas
.
getSelfBalance
()
for
(
let
i
=
0
;
i
<
10
;
i
++
)
{
const
next
=
await
ValueContext
.
estimateGas
.
getSelfBalance
()
expect
(
res
.
toNumber
()).
to
.
deep
.
eq
(
next
.
toNumber
())
res
=
next
}
})
it
(
'
should return a gas estimate for txs with empty data
'
,
async
()
=>
{
it
(
'
should return a gas estimate for txs with empty data
'
,
async
()
=>
{
const
estimate
=
await
l2Provider
.
estimateGas
({
const
estimate
=
await
l2Provider
.
estimateGas
({
to
:
defaultTransactionFactory
().
to
,
to
:
defaultTransactionFactory
().
to
,
...
...
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