Commit fa4c743f authored by Liam Horne's avatar Liam Horne

Merge branch 'develop'

parents 3807f38d 376ce7bd
---
'@eth-optimism/integration-tests': patch
---
Add various stress tests
......@@ -91,7 +91,7 @@ jobs:
context: .
file: ./ops/docker/Dockerfile.geth
push: true
tags: ethereumoptimism/l2geth:${{ needs.release.outputs.l2geth }}
tags: ethereumoptimism/l2geth:${{ needs.release.outputs.l2geth }},ethereumoptimism/l2geth:latest
- name: Publish op_exporter
uses: docker/build-push-action@v2
......@@ -107,7 +107,7 @@ jobs:
context: .
file: ./ops/docker/Dockerfile.rpc-proxy
push: true
tags: ethereumoptimism/rpc-proxy:${{ needs.release.outputs.l2geth }}
tags: ethereumoptimism/rpc-proxy:${{ needs.release.outputs.l2geth }},ethereumoptimism/rpc-proxy:latest
gas-oracle:
name: Publish Gas Oracle Version ${{ needs.release.outputs.gas-oracle }}
......@@ -193,7 +193,7 @@ jobs:
context: .
file: ./ops/docker/Dockerfile.message-relayer
push: true
tags: ethereumoptimism/message-relayer:${{ needs.builder.outputs.message-relayer }}
tags: ethereumoptimism/message-relayer:${{ needs.builder.outputs.message-relayer }},ethereumoptimism/message-relayer:latest
batch-submitter:
name: Publish Batch Submitter Version ${{ needs.builder.outputs.batch-submitter }}
......@@ -219,7 +219,7 @@ jobs:
context: .
file: ./ops/docker/Dockerfile.batch-submitter
push: true
tags: ethereumoptimism/batch-submitter:${{ needs.builder.outputs.batch-submitter }}
tags: ethereumoptimism/batch-submitter:${{ needs.builder.outputs.batch-submitter }},ethereumoptimism/batch-submitter:latest
data-transport-layer:
name: Publish Data Transport Layer Version ${{ needs.builder.outputs.data-transport-layer }}
......@@ -245,7 +245,7 @@ jobs:
context: .
file: ./ops/docker/Dockerfile.data-transport-layer
push: true
tags: ethereumoptimism/data-transport-layer:${{ needs.builder.outputs.data-transport-layer }}
tags: ethereumoptimism/data-transport-layer:${{ needs.builder.outputs.data-transport-layer }},ethereumoptimism/data-transport-layer:latest
contracts:
name: Publish Deployer Version ${{ needs.builder.outputs.contracts }}
......@@ -271,7 +271,7 @@ jobs:
context: .
file: ./ops/docker/Dockerfile.deployer
push: true
tags: ethereumoptimism/deployer:${{ needs.builder.outputs.contracts }}
tags: ethereumoptimism/deployer:${{ needs.builder.outputs.contracts }},ethereumoptimism/deployer:latest
integration_tests:
name: Publish Integration tests ${{ needs.builder.outputs.integration-tests }}
......@@ -297,4 +297,4 @@ jobs:
context: .
file: ./ops/docker/Dockerfile.integration-tests
push: true
tags: ethereumoptimism/integration-tests:${{ needs.builder.outputs.integration-tests }}
tags: ethereumoptimism/integration-tests:${{ needs.builder.outputs.integration-tests }},ethereumoptimism/integration-tests:latest
......@@ -18,6 +18,12 @@ contract SimpleStorage {
totalCount++;
}
function setValueNotXDomain(bytes32 newValue) public {
msgSender = msg.sender;
value = newValue;
totalCount++;
}
function dumbSetValue(bytes32 newValue) public {
value = newValue;
}
......
......@@ -170,6 +170,8 @@ export class OptimismEnv {
} catch (err) {
if (err.message.includes('execution failed due to an exception')) {
await sleep(5000)
} else if (err.message.includes('Nonce too low')) {
await sleep(5000)
} else if (
err.message.includes('message has already been received')
) {
......
/* Imports: External */
import { ethers } from 'ethers'
/* Imports: Internal */
import { OptimismEnv } from './env'
import { Direction } from './watcher-utils'
interface TransactionParams {
contract: ethers.Contract
functionName: string
functionParams: any[]
}
// Arbitrary big amount of gas for the L1<>L2 messages.
const MESSAGE_GAS = 8_000_000
export const executeL1ToL2Transactions = async (
env: OptimismEnv,
txs: TransactionParams[]
) => {
for (const tx of txs) {
const signer = ethers.Wallet.createRandom().connect(env.l1Wallet.provider)
const receipt = await env.l1Messenger
.connect(signer)
.sendMessage(
tx.contract.address,
tx.contract.interface.encodeFunctionData(
tx.functionName,
tx.functionParams
),
MESSAGE_GAS,
{
gasPrice: 0,
}
)
await env.waitForXDomainTransaction(receipt, Direction.L1ToL2)
}
}
export const executeL2ToL1Transactions = async (
env: OptimismEnv,
txs: TransactionParams[]
) => {
for (const tx of txs) {
const signer = ethers.Wallet.createRandom().connect(env.l2Wallet.provider)
const receipt = await env.l2Messenger
.connect(signer)
.sendMessage(
tx.contract.address,
tx.contract.interface.encodeFunctionData(
tx.functionName,
tx.functionParams
),
MESSAGE_GAS,
{
gasPrice: 0,
}
)
await env.relayXDomainMessages(receipt)
await env.waitForXDomainTransaction(receipt, Direction.L2ToL1)
}
}
export const executeL2Transactions = async (
env: OptimismEnv,
txs: TransactionParams[]
) => {
for (const tx of txs) {
const signer = ethers.Wallet.createRandom().connect(env.l2Wallet.provider)
const result = await tx.contract
.connect(signer)
.functions[tx.functionName](...tx.functionParams, {
gasPrice: 0,
})
await result.wait()
}
}
export const executeRepeatedL1ToL2Transactions = async (
env: OptimismEnv,
tx: TransactionParams,
count: number
) => {
await executeL1ToL2Transactions(
env,
[...Array(count).keys()].map(() => tx)
)
}
export const executeRepeatedL2ToL1Transactions = async (
env: OptimismEnv,
tx: TransactionParams,
count: number
) => {
await executeL2ToL1Transactions(
env,
[...Array(count).keys()].map(() => tx)
)
}
export const executeRepeatedL2Transactions = async (
env: OptimismEnv,
tx: TransactionParams,
count: number
) => {
await executeL2Transactions(
env,
[...Array(count).keys()].map(() => tx)
)
}
export const executeL1ToL2TransactionsParallel = async (
env: OptimismEnv,
txs: TransactionParams[]
) => {
await Promise.all(
txs.map(async (tx) => {
const signer = ethers.Wallet.createRandom().connect(env.l1Wallet.provider)
const receipt = await env.l1Messenger
.connect(signer)
.sendMessage(
tx.contract.address,
tx.contract.interface.encodeFunctionData(
tx.functionName,
tx.functionParams
),
MESSAGE_GAS,
{
gasPrice: 0,
}
)
await env.waitForXDomainTransaction(receipt, Direction.L1ToL2)
})
)
}
export const executeL2ToL1TransactionsParallel = async (
env: OptimismEnv,
txs: TransactionParams[]
) => {
await Promise.all(
txs.map(async (tx) => {
const signer = ethers.Wallet.createRandom().connect(env.l2Wallet.provider)
const receipt = await env.l2Messenger
.connect(signer)
.sendMessage(
tx.contract.address,
tx.contract.interface.encodeFunctionData(
tx.functionName,
tx.functionParams
),
MESSAGE_GAS,
{
gasPrice: 0,
}
)
await env.relayXDomainMessages(receipt)
await env.waitForXDomainTransaction(receipt, Direction.L2ToL1)
})
)
}
export const executeL2TransactionsParallel = async (
env: OptimismEnv,
txs: TransactionParams[]
) => {
await Promise.all(
txs.map(async (tx) => {
const signer = ethers.Wallet.createRandom().connect(env.l2Wallet.provider)
const result = await tx.contract
.connect(signer)
.functions[tx.functionName](...tx.functionParams, {
gasPrice: 0,
})
await result.wait()
})
)
}
export const executeRepeatedL1ToL2TransactionsParallel = async (
env: OptimismEnv,
tx: TransactionParams,
count: number
) => {
await executeL1ToL2TransactionsParallel(
env,
[...Array(count).keys()].map(() => tx)
)
}
export const executeRepeatedL2ToL1TransactionsParallel = async (
env: OptimismEnv,
tx: TransactionParams,
count: number
) => {
await executeL2ToL1TransactionsParallel(
env,
[...Array(count).keys()].map(() => tx)
)
}
export const executeRepeatedL2TransactionsParallel = async (
env: OptimismEnv,
tx: TransactionParams,
count: number
) => {
await executeL2TransactionsParallel(
env,
[...Array(count).keys()].map(() => tx)
)
}
import { expect } from 'chai'
/* Imports: External */
import { Contract, ContractFactory } from 'ethers'
/* Imports: Internal */
import { OptimismEnv } from './shared/env'
import {
executeRepeatedL1ToL2Transactions,
executeRepeatedL2ToL1Transactions,
executeRepeatedL2Transactions,
executeRepeatedL1ToL2TransactionsParallel,
executeRepeatedL2ToL1TransactionsParallel,
executeRepeatedL2TransactionsParallel,
} from './shared/stress-test-helpers'
/* Imports: Artifacts */
import l1SimpleStorageJson from '../artifacts/contracts/SimpleStorage.sol/SimpleStorage.json'
import l2SimpleStorageJson from '../artifacts-ovm/contracts/SimpleStorage.sol/SimpleStorage.json'
// Need a big timeout to allow for all transactions to be processed.
// For some reason I can't figure out how to set the timeout on a per-suite basis
// so I'm instead setting it for every test.
const STRESS_TEST_TIMEOUT = 300_000
describe('stress tests', () => {
let env: OptimismEnv
before(async () => {
env = await OptimismEnv.new()
})
let L2SimpleStorage: Contract
let L1SimpleStorage: Contract
beforeEach(async () => {
const factory__L1SimpleStorage = new ContractFactory(
l1SimpleStorageJson.abi,
l1SimpleStorageJson.bytecode,
env.l1Wallet
)
const factory__L2SimpleStorage = new ContractFactory(
l2SimpleStorageJson.abi,
l2SimpleStorageJson.bytecode,
env.l2Wallet
)
L1SimpleStorage = await factory__L1SimpleStorage.deploy()
await L1SimpleStorage.deployTransaction.wait()
L2SimpleStorage = await factory__L2SimpleStorage.deploy()
await L2SimpleStorage.deployTransaction.wait()
})
describe('L1 => L2 stress tests', () => {
const numTransactions = 10
it(`${numTransactions} L1 => L2 transactions (serial)`, async () => {
await executeRepeatedL1ToL2Transactions(
env,
{
contract: L2SimpleStorage,
functionName: 'setValue',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
)
expect((await L2SimpleStorage.totalCount()).toNumber()).to.equal(
numTransactions
)
}).timeout(STRESS_TEST_TIMEOUT)
it(`${numTransactions} L1 => L2 transactions (parallel)`, async () => {
await executeRepeatedL1ToL2TransactionsParallel(
env,
{
contract: L2SimpleStorage,
functionName: 'setValue',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
)
expect((await L2SimpleStorage.totalCount()).toNumber()).to.equal(
numTransactions
)
}).timeout(STRESS_TEST_TIMEOUT)
})
describe('L2 => L1 stress tests', () => {
const numTransactions = 10
it(`${numTransactions} L2 => L1 transactions (serial)`, async () => {
await executeRepeatedL2ToL1Transactions(
env,
{
contract: L1SimpleStorage,
functionName: 'setValue',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
)
expect((await L1SimpleStorage.totalCount()).toNumber()).to.equal(
numTransactions
)
}).timeout(STRESS_TEST_TIMEOUT)
it(`${numTransactions} L2 => L1 transactions (parallel)`, async () => {
await executeRepeatedL2ToL1TransactionsParallel(
env,
{
contract: L1SimpleStorage,
functionName: 'setValue',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
)
expect((await L1SimpleStorage.totalCount()).toNumber()).to.equal(
numTransactions
)
}).timeout(STRESS_TEST_TIMEOUT)
})
describe('L2 transaction stress tests', () => {
const numTransactions = 10
it(`${numTransactions} L2 transactions (serial)`, async () => {
await executeRepeatedL2Transactions(
env,
{
contract: L2SimpleStorage,
functionName: 'setValueNotXDomain',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
)
expect((await L2SimpleStorage.totalCount()).toNumber()).to.equal(
numTransactions
)
}).timeout(STRESS_TEST_TIMEOUT)
it(`${numTransactions} L2 transactions (parallel)`, async () => {
await executeRepeatedL2TransactionsParallel(
env,
{
contract: L2SimpleStorage,
functionName: 'setValueNotXDomain',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
)
expect((await L2SimpleStorage.totalCount()).toNumber()).to.equal(
numTransactions
)
}).timeout(STRESS_TEST_TIMEOUT)
})
describe('C-C-C-Combo breakers', () => {
const numTransactions = 10
it(`${numTransactions} L2 transactions, L1 => L2 transactions, L2 => L1 transactions (txs serial, suites parallel)`, async () => {
await Promise.all([
executeRepeatedL1ToL2Transactions(
env,
{
contract: L2SimpleStorage,
functionName: 'setValue',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
),
executeRepeatedL2ToL1Transactions(
env,
{
contract: L1SimpleStorage,
functionName: 'setValue',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
),
executeRepeatedL2Transactions(
env,
{
contract: L2SimpleStorage,
functionName: 'setValueNotXDomain',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
),
])
expect((await L2SimpleStorage.totalCount()).toNumber()).to.equal(
numTransactions * 2
)
expect((await L1SimpleStorage.totalCount()).toNumber()).to.equal(
numTransactions
)
}).timeout(STRESS_TEST_TIMEOUT)
it(`${numTransactions} L2 transactions, L1 => L2 transactions, L2 => L1 transactions (all parallel)`, async () => {
await Promise.all([
executeRepeatedL1ToL2TransactionsParallel(
env,
{
contract: L2SimpleStorage,
functionName: 'setValue',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
),
executeRepeatedL2ToL1TransactionsParallel(
env,
{
contract: L1SimpleStorage,
functionName: 'setValue',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
),
executeRepeatedL2TransactionsParallel(
env,
{
contract: L2SimpleStorage,
functionName: 'setValueNotXDomain',
functionParams: [`0x${'42'.repeat(32)}`],
},
numTransactions
),
])
expect((await L2SimpleStorage.totalCount()).toNumber()).to.equal(
numTransactions * 2
)
expect((await L1SimpleStorage.totalCount()).toNumber()).to.equal(
numTransactions
)
}).timeout(STRESS_TEST_TIMEOUT)
})
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment