@hyperlane-xyz/core
Version:
Core solidity contracts for Hyperlane
212 lines (183 loc) • 6.94 kB
text/typescript
/* Imports: External */
import { Contract, BigNumber } from 'ethers'
import { ethers } from 'hardhat'
/* Imports: Internal */
import { expect } from './shared/setup'
import { OptimismEnv } from './shared/env'
export 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',
[]
)
const preBerlinTrace = await env.l2Provider.send(
'debug_traceTransaction',
[]
)
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',
[]
)
const preBerlinTrace = await env.l2Provider.send(
'debug_traceTransaction',
[]
)
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',
[]
)
const preBerlinTrace = await env.l2Provider.send(
'debug_traceTransaction',
[]
)
// 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',
[]
)
const preBerlinTrace = await env.l2Provider.send(
'debug_traceTransaction',
[]
)
// 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',
[]
)
const preBerlinTrace = await env.l2Provider.send(
'debug_traceTransaction',
[]
)
// 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',
[]
)
const preBerlinTrace = await env.l2Provider.send(
'debug_traceTransaction',
[]
)
// 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)
})
})
})
})