Skip to content

Commit

Permalink
l2geth: Add berlin hardfork
Browse files Browse the repository at this point in the history
  • Loading branch information
tynes authored and mslipper committed Jan 28, 2022
1 parent cdc4ddd commit e631c39
Show file tree
Hide file tree
Showing 45 changed files with 1,800 additions and 140 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-baboons-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/integration-tests': patch
---

Add in berlin hardfork tests
5 changes: 5 additions & 0 deletions .changeset/many-cougars-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/l2geth': patch
---

Implement berlin hardfork
5 changes: 5 additions & 0 deletions .changeset/smooth-points-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/contracts': patch
---

Add berlin hardfork config to genesis creation
23 changes: 23 additions & 0 deletions integration-tests/contracts/Precompiles.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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)
}
}
}
15 changes: 15 additions & 0 deletions integration-tests/contracts/SelfDestruction.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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);
}
}
1 change: 1 addition & 0 deletions integration-tests/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { HardhatUserConfig } from 'hardhat/types'
import '@nomiclabs/hardhat-ethers'
import '@nomiclabs/hardhat-waffle'
import 'hardhat-gas-reporter'
import './tasks/check-block-hashes'
import { envConfig } from './test/shared/utils'

const enableGasReport = !!process.env.ENABLE_GAS_REPORT
Expand Down
58 changes: 58 additions & 0 deletions integration-tests/tasks/check-block-hashes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { task } from 'hardhat/config'
import { providers } from 'ethers'

import { die, logStderr } from '../test/shared/utils'

task(
'check-block-hashes',
'Compares the block hashes of two different replicas.'
)
.addPositionalParam('replicaA', 'The first replica')
.addPositionalParam('replicaB', 'The second replica')
.setAction(async ({ replicaA, replicaB }) => {
const providerA = new providers.JsonRpcProvider(replicaA)
const providerB = new providers.JsonRpcProvider(replicaB)

let netA
let netB
try {
netA = await providerA.getNetwork()
} catch (e) {
console.error(`Error getting network from ${replicaA}:`)
die(e)
}
try {
netB = await providerA.getNetwork()
} catch (e) {
console.error(`Error getting network from ${replicaB}:`)
die(e)
}

if (netA.chainId !== netB.chainId) {
die('Chain IDs do not match')
return
}

logStderr('Getting block height.')
const heightA = await providerA.getBlockNumber()
const heightB = await providerB.getBlockNumber()
const endHeight = Math.min(heightA, heightB)
logStderr(`Chose block height: ${endHeight}`)

for (let n = endHeight; n >= 1; n--) {
const blocks = await Promise.all([
providerA.getBlock(n),
providerB.getBlock(n),
])

const hashA = blocks[0].hash
const hashB = blocks[1].hash
if (hashA !== hashB) {
console.log(`HASH MISMATCH! block=${n} a=${hashA} b=${hashB}`)
continue
}

console.log(`HASHES OK! block=${n} hash=${hashA}`)
return
}
})
109 changes: 109 additions & 0 deletions integration-tests/test/env-specific/nightly.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { Contract } from 'ethers'
import { ethers } from 'hardhat'

import { OptimismEnv } from '../shared/env'
import { expect } from '../shared/setup'
import { traceToGasByOpcode } from '../hardfork.spec'
import { envConfig } from '../shared/utils'

describe('Nightly', () => {
before(async function () {
if (!envConfig.RUN_NIGHTLY_TESTS) {
this.skip()
}
})

describe('Berlin Hardfork', () => {
let env: OptimismEnv
let SimpleStorage: Contract
let Precompiles: Contract

before(async () => {
env = await OptimismEnv.new()
SimpleStorage = await ethers.getContractAt(
'SimpleStorage',
'0xE08fFE40748367ddc29B5A154331C73B7FCC13bD',
env.l2Wallet
)

Precompiles = await ethers.getContractAt(
'Precompiles',
'0x32E8Fbfd0C0bd1117112b249e997C27b0EC7cba2',
env.l2Wallet
)
})

describe('EIP-2929', () => {
it('should update the gas schedule', async () => {
const tx = await SimpleStorage.setValueNotXDomain(
`0x${'77'.repeat(32)}`
)
await tx.wait()

const berlinTrace = await env.l2Provider.send(
'debug_traceTransaction',
[tx.hash]
)
const preBerlinTrace = await env.l2Provider.send(
'debug_traceTransaction',
['0x2bb346f53544c5711502fbcbd1d78dc4fb61ca5f9390b9d6d67f1a3a77de7c39']
)

const berlinSstoreCosts = traceToGasByOpcode(
berlinTrace.structLogs,
'SSTORE'
)
const preBerlinSstoreCosts = traceToGasByOpcode(
preBerlinTrace.structLogs,
'SSTORE'
)
expect(preBerlinSstoreCosts).to.eq(80000)
expect(berlinSstoreCosts).to.eq(5300)
})
})

describe('EIP-2565', () => {
it('should become cheaper', async () => {
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',
['0x7ba7d273449b0062448fe5e7426bb169a032ce189d0e3781eb21079e85c2d7d5']
)
expect(berlinTrace.gas).to.be.lt(preBerlinTrace.gas)
})
})

describe('Berlin Additional (L1 London)', () => {
describe('EIP-3529', () => {
it('should remove the refund for selfdestruct', async () => {
const Factory__SelfDestruction = await ethers.getContractFactory(
'SelfDestruction',
env.l2Wallet
)

const SelfDestruction = await Factory__SelfDestruction.deploy()
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',
[
'0x948667349f00e996d9267e5c30d72fe7202a0ecdb88bab191e9a022bba6e4cb3',
]
)
expect(berlinTrace.gas).to.be.gt(preBerlinTrace.gas)
})
})
})
})
})
Loading

0 comments on commit e631c39

Please sign in to comment.