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
cee2a464
Unverified
Commit
cee2a464
authored
Oct 28, 2021
by
Matthew Slipper
Committed by
Kelvin Fichter
Nov 10, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: integration-tests core-utils Kovan integration tests
parent
499d8736
Changes
25
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
529 additions
and
449 deletions
+529
-449
few-gifts-hope.md
.changeset/few-gifts-hope.md
+5
-0
README.md
integration-tests/README.md
+9
-5
hardhat.config.ts
integration-tests/hardhat.config.ts
+2
-1
package.json
integration-tests/package.json
+1
-1
basic-l1-l2-communication.spec.ts
integration-tests/test/basic-l1-l2-communication.spec.ts
+12
-7
fee-payment.spec.ts
integration-tests/test/fee-payment.spec.ts
+23
-21
native-eth-ovm-calls.spec.ts
integration-tests/test/native-eth-ovm-calls.spec.ts
+48
-26
native-eth.spec.ts
integration-tests/test/native-eth.spec.ts
+3
-9
queue-ingestion.spec.ts
integration-tests/test/queue-ingestion.spec.ts
+2
-1
rpc.spec.ts
integration-tests/test/rpc.spec.ts
+23
-14
env.ts
integration-tests/test/shared/env.ts
+10
-0
stress-test-helpers.ts
integration-tests/test/shared/stress-test-helpers.ts
+90
-130
utils.ts
integration-tests/test/shared/utils.ts
+55
-7
watcher-utils.ts
integration-tests/test/shared/watcher-utils.ts
+5
-0
stress-tests.spec.ts
integration-tests/test/stress-tests.spec.ts
+98
-130
000-hardhat-setup.ts
packages/contracts/deploy/000-hardhat-setup.ts
+19
-11
007-OVM_L1CrossDomainMessenger.deploy.ts
...contracts/deploy/007-OVM_L1CrossDomainMessenger.deploy.ts
+11
-8
008-Proxy__OVM_L1CrossDomainMessenger.deploy.ts
...ts/deploy/008-Proxy__OVM_L1CrossDomainMessenger.deploy.ts
+0
-1
011-set-addresses.ts
packages/contracts/deploy/011-set-addresses.ts
+13
-14
012-initialize-Proxy__L1CrossDomainMessenger.ts
...ts/deploy/012-initialize-Proxy__L1CrossDomainMessenger.ts
+12
-11
014-OVM_L1StandardBridge.deploy.ts
packages/contracts/deploy/014-OVM_L1StandardBridge.deploy.ts
+18
-18
015-finalize.ts
packages/contracts/deploy/015-finalize.ts
+9
-8
hardhat-deploy-ethers.ts
packages/contracts/src/hardhat-deploy-ethers.ts
+13
-25
test-utils.ts
packages/core-utils/src/common/test-utils.ts
+18
-0
test-utils.spec.ts
packages/core-utils/test/common/test-utils.spec.ts
+30
-1
No files found.
.changeset/few-gifts-hope.md
0 → 100644
View file @
cee2a464
---
'
@eth-optimism/core-utils'
:
patch
---
Add awaitCondition to core utils
integration-tests/README.md
View file @
cee2a464
...
...
@@ -13,19 +13,23 @@ yarn build
### Testing a live network
Create an
`.env`
file and fill it out.
Look at
`.env.example`
to know which variables to include.
Testing on a live network is a bit more complicated than testing locally. You'll need the following in order to do so:
Once you have your environment set up, run:
1.
A pre-funded wallet with at least 40 ETH.
2.
URLs to an L1 and L2 node.
3.
The address of the address manager contract.
4.
The chain ID of the L2.
Once you have all the necessary info, create a
`.env`
file like the one in
`.env.example`
and fill it in with the values above. Then, run:
```
bash
yarn
test
:integration:live
```
This will take quite a long time. Kovan, for example, takes about 30 minutes to complete.
You can also set environment variables on the command line instead of inside
`.env`
if you want:
```
bash
L1_URL
=
whatever
L2_URL
=
whatever yarn
test
:integration:live
```
Note that this can take an extremely long time (~1hr).
integration-tests/hardhat.config.ts
View file @
cee2a464
...
...
@@ -4,6 +4,7 @@ import { HardhatUserConfig } from 'hardhat/types'
import
'
@nomiclabs/hardhat-ethers
'
import
'
@nomiclabs/hardhat-waffle
'
import
'
hardhat-gas-reporter
'
import
{
isLiveNetwork
}
from
'
./test/shared/utils
'
const
enableGasReport
=
!!
process
.
env
.
ENABLE_GAS_REPORT
...
...
@@ -14,7 +15,7 @@ const config: HardhatUserConfig = {
},
},
mocha
:
{
timeout
:
75
_000
,
timeout
:
isLiveNetwork
()
?
300
_000
:
75
_000
,
},
solidity
:
{
version
:
'
0.8.9
'
,
...
...
integration-tests/package.json
View file @
cee2a464
...
...
@@ -11,7 +11,7 @@
"lint:check"
:
"eslint ."
,
"build"
:
"hardhat compile"
,
"test:integration"
:
"hardhat --network optimism test"
,
"test:integration:live"
:
"IS_LIVE_NETWORK=true hardhat --network optimism test"
,
"test:integration:live"
:
"
NO_NETWORK=true
IS_LIVE_NETWORK=true hardhat --network optimism test"
,
"test:sync"
:
"hardhat --network optimism test sync-tests/*.spec.ts --no-compile"
,
"clean"
:
"rimraf cache artifacts"
},
...
...
integration-tests/test/basic-l1-l2-communication.spec.ts
View file @
cee2a464
...
...
@@ -2,13 +2,14 @@ import { expect } from 'chai'
/* Imports: External */
import
{
Contract
,
ContractFactory
}
from
'
ethers
'
import
{
applyL1ToL2Alias
,
sleep
}
from
'
@eth-optimism/core-utils
'
import
{
applyL1ToL2Alias
}
from
'
@eth-optimism/core-utils
'
/* Imports: Internal */
import
simpleStorageJson
from
'
../artifacts/contracts/SimpleStorage.sol/SimpleStorage.json
'
import
l2ReverterJson
from
'
../artifacts/contracts/Reverter.sol/Reverter.json
'
import
{
Direction
}
from
'
./shared/watcher-utils
'
import
{
OptimismEnv
,
useDynamicTimeoutForWithdrawals
}
from
'
./shared/env
'
import
{
OptimismEnv
}
from
'
./shared/env
'
import
{
awaitCondition
}
from
'
@eth-optimism/core-utils
'
describe
(
'
Basic L1<>L2 Communication
'
,
async
()
=>
{
let
Factory__L1SimpleStorage
:
ContractFactory
...
...
@@ -48,9 +49,7 @@ describe('Basic L1<>L2 Communication', async () => {
})
describe
(
'
L2 => L1
'
,
()
=>
{
it
(
'
should be able to perform a withdrawal from L2 -> L1
'
,
async
function
()
{
await
useDynamicTimeoutForWithdrawals
(
this
,
env
)
it
(
'
should be able to perform a withdrawal from L2 -> L1
'
,
async
()
=>
{
const
value
=
`0x
${
'
77
'
.
repeat
(
32
)}
`
// Send L2 -> L1 message.
...
...
@@ -114,8 +113,14 @@ describe('Basic L1<>L2 Communication', async () => {
])
)
// TODO: We need to have a function that can wait for enqueued txs.
await
sleep
(
10000
)
await
awaitCondition
(
async
()
=>
{
const
sender
=
await
L2SimpleStorage
.
msgSender
()
return
sender
===
env
.
l1Wallet
.
address
},
2000
,
60
)
// No aliasing when an EOA goes directly to L2.
expect
(
await
L2SimpleStorage
.
msgSender
()).
to
.
equal
(
env
.
l1Wallet
.
address
)
...
...
integration-tests/test/fee-payment.spec.ts
View file @
cee2a464
...
...
@@ -13,11 +13,14 @@ import {
}
from
'
@eth-optimism/contracts
'
/* Imports: Internal */
import
{
IS_LIVE_NETWORK
}
from
'
./shared/utils
'
import
{
isLiveNetwork
}
from
'
./shared/utils
'
import
{
OptimismEnv
}
from
'
./shared/env
'
import
{
Direction
}
from
'
./shared/watcher-utils
'
const
setPrices
=
async
(
env
:
OptimismEnv
,
value
:
number
|
BigNumber
)
=>
{
if
(
isLiveNetwork
())
{
return
}
const
gasPrice
=
await
env
.
gasPriceOracle
.
setGasPrice
(
value
)
await
gasPrice
.
wait
()
const
baseFee
=
await
env
.
gasPriceOracle
.
setL1BaseFee
(
value
)
...
...
@@ -32,20 +35,22 @@ describe('Fee Payment Integration Tests', async () => {
env
=
await
OptimismEnv
.
new
()
})
it
(
`should return eth_gasPrice equal to OVM_GasPriceOracle.gasPrice`
,
async
()
=>
{
const
assertGasPrice
=
async
()
=>
{
const
gasPrice
=
await
env
.
l2Wallet
.
getGasPrice
()
const
oracleGasPrice
=
await
env
.
gasPriceOracle
.
gasPrice
()
expect
(
gasPrice
).
to
.
deep
.
equal
(
oracleGasPrice
)
}
if
(
!
isLiveNetwork
())
{
it
(
`should return eth_gasPrice equal to OVM_GasPriceOracle.gasPrice`
,
async
()
=>
{
const
assertGasPrice
=
async
()
=>
{
const
gasPrice
=
await
env
.
l2Wallet
.
getGasPrice
()
const
oracleGasPrice
=
await
env
.
gasPriceOracle
.
gasPrice
()
expect
(
gasPrice
).
to
.
deep
.
equal
(
oracleGasPrice
)
}
assertGasPrice
()
// update the gas price
const
tx
=
await
env
.
gasPriceOracle
.
setGasPrice
(
1000
)
await
tx
.
wait
()
assertGasPrice
()
// update the gas price
const
tx
=
await
env
.
gasPriceOracle
.
setGasPrice
(
1000
)
await
tx
.
wait
()
assertGasPrice
()
})
assertGasPrice
()
})
}
it
(
'
Paying a nonzero but acceptable gasPrice fee
'
,
async
()
=>
{
await
setPrices
(
env
,
1000
)
...
...
@@ -152,19 +157,16 @@ describe('Fee Payment Integration Tests', async () => {
})
it
(
'
should be able to withdraw fees back to L1 once the minimum is met
'
,
async
function
()
{
if
(
isLiveNetwork
())
{
this
.
skip
()
return
}
const
l1FeeWallet
=
await
env
.
sequencerFeeVault
.
l1FeeWallet
()
const
balanceBefore
=
await
env
.
l1Wallet
.
provider
.
getBalance
(
l1FeeWallet
)
const
withdrawalAmount
=
await
env
.
sequencerFeeVault
.
MIN_WITHDRAWAL_AMOUNT
()
const
l2WalletBalance
=
await
env
.
l2Wallet
.
getBalance
()
if
(
IS_LIVE_NETWORK
&&
l2WalletBalance
.
lt
(
withdrawalAmount
))
{
console
.
log
(
`NOTICE: must have at least
${
ethers
.
utils
.
formatEther
(
withdrawalAmount
)}
ETH on L2 to execute this test, skipping`
)
this
.
skip
()
}
// Transfer the minimum required to withdraw.
const
tx
=
await
env
.
l2Wallet
.
sendTransaction
({
...
...
integration-tests/test/native-eth-ovm-calls.spec.ts
View file @
cee2a464
import
{
BigNumber
,
Contract
,
ContractFactory
,
Wallet
}
from
'
ethers
'
import
{
BigNumber
,
BigNumberish
,
Contract
,
ContractFactory
,
Wallet
,
}
from
'
ethers
'
import
{
ethers
}
from
'
hardhat
'
import
chai
,
{
expect
}
from
'
chai
'
import
{
GWEI
,
fundUser
,
encodeSolidityRevertMessage
}
from
'
./shared/utils
'
import
{
fundUser
,
encodeSolidityRevertMessage
,
gasPriceForL2
,
}
from
'
./shared/utils
'
import
{
OptimismEnv
}
from
'
./shared/env
'
import
{
solidity
}
from
'
ethereum-waffle
'
import
{
sleep
}
from
'
../../packages/core-utils/dist
'
import
{
getContractFactory
,
getContractInterface
,
}
from
'
../../packages/contracts/dist
'
import
{
Interface
}
from
'
ethers/lib/utils
'
chai
.
use
(
solidity
)
...
...
@@ -32,15 +36,16 @@ describe('Native ETH value integration tests', () => {
]
}
const
checkBalances
=
async
(
expectedBalances
:
BigNumber
[]
):
Promise
<
void
>
=>
{
const
realBalances
=
await
getBalances
()
expect
(
realBalances
[
0
]).
to
.
deep
.
eq
(
expectedBalances
[
0
])
expect
(
realBalances
[
1
]).
to
.
deep
.
eq
(
expectedBalances
[
1
])
const
expectBalancesWithinRange
=
(
bal
:
BigNumber
,
lte
:
BigNumber
,
gte
:
BigNumber
)
=>
{
expect
(
bal
.
lte
(
lte
)).
to
.
be
.
true
expect
(
bal
.
gte
(
gte
)).
to
.
be
.
true
}
const
value
=
10
const
value
=
ethers
.
utils
.
parseEther
(
'
0.01
'
)
await
fundUser
(
env
.
watcher
,
env
.
l1Bridge
,
value
,
wallet
.
address
)
const
initialBalances
=
await
getBalances
()
...
...
@@ -48,23 +53,40 @@ describe('Native ETH value integration tests', () => {
const
there
=
await
wallet
.
sendTransaction
({
to
:
other
.
address
,
value
,
gasPrice
:
0
,
gasPrice
:
await
gasPriceForL2
()
,
})
await
there
.
wait
()
const
thereReceipt
=
await
there
.
wait
()
const
thereGas
=
thereReceipt
.
gasUsed
.
mul
(
there
.
gasPrice
)
await
checkBalances
([
const
thereBalances
=
await
getBalances
()
const
thereWithGas
=
initialBalances
[
0
].
sub
(
value
).
sub
(
thereGas
).
sub
(
100000
)
expectBalancesWithinRange
(
thereBalances
[
0
],
initialBalances
[
0
].
sub
(
value
),
initialBalances
[
1
].
add
(
value
),
])
thereWithGas
)
expect
(
initialBalances
[
1
].
add
(
value
).
eq
(
thereBalances
[
1
]))
const
backVal
=
ethers
.
utils
.
parseEther
(
'
0.005
'
)
const
backAgain
=
await
other
.
sendTransaction
({
to
:
wallet
.
address
,
value
,
gasPrice
:
0
,
value
:
backVal
,
gasPrice
:
await
gasPriceForL2
()
,
})
await
backAgain
.
wait
()
await
checkBalances
(
initialBalances
)
const
backReceipt
=
await
backAgain
.
wait
()
const
backGas
=
backReceipt
.
gasUsed
.
mul
(
backAgain
.
gasPrice
)
const
backBalances
=
await
getBalances
()
expectBalancesWithinRange
(
backBalances
[
0
],
initialBalances
[
0
].
sub
(
thereGas
).
sub
(
backVal
),
initialBalances
[
0
].
sub
(
thereGas
).
sub
(
backVal
).
sub
(
200000
)
)
expectBalancesWithinRange
(
backBalances
[
1
],
initialBalances
[
1
].
add
(
backVal
).
sub
(
backGas
),
initialBalances
[
1
].
add
(
backVal
).
sub
(
backGas
).
sub
(
200000
)
)
})
describe
(
`calls between OVM contracts with native ETH value and relevant opcodes`
,
async
()
=>
{
...
...
@@ -155,7 +177,7 @@ describe('Native ETH value integration tests', () => {
it
(
'
should allow ETH to be sent
'
,
async
()
=>
{
const
sendAmount
=
15
const
tx
=
await
ValueCalls0
.
simpleSend
(
ValueCalls1
.
address
,
sendAmount
,
{
gasPrice
:
0
,
gasPrice
:
await
gasPriceForL2
()
,
})
await
tx
.
wait
()
...
...
integration-tests/test/native-eth.spec.ts
View file @
cee2a464
...
...
@@ -183,9 +183,7 @@ describe('Native ETH Integration Tests', async () => {
).
to
.
be
.
reverted
})
it
(
'
withdraw
'
,
async
function
()
{
await
useDynamicTimeoutForWithdrawals
(
this
,
env
)
it
(
'
withdraw
'
,
async
()
=>
{
const
withdrawAmount
=
BigNumber
.
from
(
3
)
const
preBalances
=
await
getBalances
(
env
)
expect
(
...
...
@@ -227,9 +225,7 @@ describe('Native ETH Integration Tests', async () => {
)
})
it
(
'
withdrawTo
'
,
async
function
()
{
await
useDynamicTimeoutForWithdrawals
(
this
,
env
)
it
(
'
withdrawTo
'
,
async
()
=>
{
const
withdrawAmount
=
BigNumber
.
from
(
3
)
const
preBalances
=
await
getBalances
(
env
)
...
...
@@ -287,9 +283,7 @@ describe('Native ETH Integration Tests', async () => {
)
})
it
(
'
deposit, transfer, withdraw
'
,
async
function
()
{
await
useDynamicTimeoutForWithdrawals
(
this
,
env
)
it
(
'
deposit, transfer, withdraw
'
,
async
()
=>
{
// 1. deposit
const
amount
=
utils
.
parseEther
(
'
1
'
)
await
env
.
waitForXDomainTransaction
(
...
...
integration-tests/test/queue-ingestion.spec.ts
View file @
cee2a464
...
...
@@ -7,6 +7,7 @@ import { injectL2Context, applyL1ToL2Alias } from '@eth-optimism/core-utils'
/* Imports: External */
import
{
OptimismEnv
}
from
'
./shared/env
'
import
{
Direction
}
from
'
./shared/watcher-utils
'
import
{
isLiveNetwork
}
from
'
./shared/utils
'
describe
(
'
Queue Ingestion
'
,
()
=>
{
let
env
:
OptimismEnv
...
...
@@ -61,5 +62,5 @@ describe('Queue Ingestion', () => {
)
expect
(
l2Tx
.
l1BlockNumber
).
to
.
equal
(
l1TxReceipt
.
blockNumber
)
}
}).
timeout
(
100
_000
)
}).
timeout
(
isLiveNetwork
()
?
300
_000
:
100
_000
)
})
integration-tests/test/rpc.spec.ts
View file @
cee2a464
...
...
@@ -6,10 +6,12 @@ import chai, { expect } from 'chai'
import
{
sleep
,
l2Provider
,
DEFAULT_TRANSACTION
,
defaultTransactionFactory
,
fundUser
,
L2_CHAINID
,
IS_LIVE_NETWORK
,
isLiveNetwork
,
gasPriceForL2
,
}
from
'
./shared/utils
'
import
chaiAsPromised
from
'
chai-as-promised
'
import
{
OptimismEnv
}
from
'
./shared/env
'
...
...
@@ -57,7 +59,8 @@ describe('Basic RPC tests', () => {
describe
(
'
eth_sendRawTransaction
'
,
()
=>
{
it
(
'
should correctly process a valid transaction
'
,
async
()
=>
{
const
tx
=
DEFAULT_TRANSACTION
const
tx
=
defaultTransactionFactory
()
tx
.
gasPrice
=
await
gasPriceForL2
()
const
nonce
=
await
wallet
.
getTransactionCount
()
const
result
=
await
wallet
.
sendTransaction
(
tx
)
...
...
@@ -70,7 +73,8 @@ describe('Basic RPC tests', () => {
it
(
'
should not accept a transaction with the wrong chain ID
'
,
async
()
=>
{
const
tx
=
{
...
DEFAULT_TRANSACTION
,
...
defaultTransactionFactory
(),
gasPrice
:
await
gasPriceForL2
(),
chainId
:
(
await
wallet
.
getChainId
())
+
1
,
}
...
...
@@ -81,7 +85,8 @@ describe('Basic RPC tests', () => {
it
(
'
should not accept a transaction without a chain ID
'
,
async
()
=>
{
const
tx
=
{
...
DEFAULT_TRANSACTION
,
...
defaultTransactionFactory
(),
gasPrice
:
await
gasPriceForL2
(),
chainId
:
null
,
// Disables EIP155 transaction signing.
}
...
...
@@ -92,7 +97,8 @@ describe('Basic RPC tests', () => {
it
(
'
should accept a transaction with a value
'
,
async
()
=>
{
const
tx
=
{
...
DEFAULT_TRANSACTION
,
...
defaultTransactionFactory
(),
gasPrice
:
await
gasPriceForL2
(),
chainId
:
await
env
.
l2Wallet
.
getChainId
(),
data
:
'
0x
'
,
value
:
ethers
.
utils
.
parseEther
(
'
0.1
'
),
...
...
@@ -103,15 +109,16 @@ describe('Basic RPC tests', () => {
const
receipt
=
await
result
.
wait
()
expect
(
receipt
.
status
).
to
.
deep
.
equal
(
1
)
expect
(
await
provider
.
getBalance
(
env
.
l2Wallet
.
address
)).
to
.
deep
.
equal
(
balanceBefore
.
sub
(
ethers
.
utils
.
parseEther
(
'
0.1
'
))
)
const
balAfter
=
await
provider
.
getBalance
(
env
.
l2Wallet
.
address
)
expect
(
balAfter
.
lte
(
balanceBefore
.
sub
(
ethers
.
utils
.
parseEther
(
'
0.1
'
)))).
to
.
be
.
true
})
it
(
'
should reject a transaction with higher value than user balance
'
,
async
()
=>
{
const
balance
=
await
env
.
l2Wallet
.
getBalance
()
const
tx
=
{
...
DEFAULT_TRANSACTION
,
...
defaultTransactionFactory
(),
gasPrice
:
await
gasPriceForL2
(),
chainId
:
await
env
.
l2Wallet
.
getChainId
(),
data
:
'
0x
'
,
value
:
balance
.
add
(
ethers
.
utils
.
parseEther
(
'
1
'
)),
...
...
@@ -240,7 +247,7 @@ describe('Basic RPC tests', () => {
it
(
'
includes L1 gas price and L1 gas used
'
,
async
()
=>
{
const
tx
=
await
env
.
l2Wallet
.
populateTransaction
({
to
:
env
.
l2Wallet
.
address
,
gasPrice
:
1
,
gasPrice
:
isLiveNetwork
()
?
10000
:
1
,
})
const
raw
=
serialize
({
...
...
@@ -274,7 +281,8 @@ describe('Basic RPC tests', () => {
describe
(
'
eth_getTransactionByHash
'
,
()
=>
{
it
(
'
should be able to get all relevant l1/l2 transaction data
'
,
async
()
=>
{
const
tx
=
DEFAULT_TRANSACTION
const
tx
=
defaultTransactionFactory
()
tx
.
gasPrice
=
await
gasPriceForL2
()
const
result
=
await
wallet
.
sendTransaction
(
tx
)
await
result
.
wait
()
...
...
@@ -288,7 +296,8 @@ describe('Basic RPC tests', () => {
describe
(
'
eth_getBlockByHash
'
,
()
=>
{
it
(
'
should return the block and all included transactions
'
,
async
()
=>
{
// Send a transaction and wait for it to be mined.
const
tx
=
DEFAULT_TRANSACTION
const
tx
=
defaultTransactionFactory
()
tx
.
gasPrice
=
await
gasPriceForL2
()
const
result
=
await
wallet
.
sendTransaction
(
tx
)
const
receipt
=
await
result
.
wait
()
...
...
@@ -362,7 +371,7 @@ describe('Basic RPC tests', () => {
let
lastEstimate
:
BigNumber
for
(
let
i
=
0
;
i
<
10
;
i
++
)
{
const
estimate
=
await
l2Provider
.
estimateGas
({
to
:
DEFAULT_TRANSACTION
.
to
,
to
:
defaultTransactionFactory
()
.
to
,
value
:
0
,
})
...
...
@@ -376,7 +385,7 @@ describe('Basic RPC tests', () => {
it
(
'
should return a gas estimate for txs with empty data
'
,
async
()
=>
{
const
estimate
=
await
l2Provider
.
estimateGas
({
to
:
DEFAULT_TRANSACTION
.
to
,
to
:
defaultTransactionFactory
()
.
to
,
value
:
0
,
})
// Expect gas to be less than or equal to the target plus 1%
...
...
integration-tests/test/shared/env.ts
View file @
cee2a464
...
...
@@ -185,6 +185,16 @@ export class OptimismEnv {
await
sleep
(
5000
)
}
else
if
(
err
.
message
.
includes
(
'
Nonce too low
'
))
{
await
sleep
(
5000
)
}
else
if
(
err
.
message
.
includes
(
'
transaction was replaced
'
))
{
// this happens when we run tests in parallel
await
sleep
(
5000
)
}
else
if
(
err
.
message
.
includes
(
'
another transaction with same nonce in the queue
'
)
)
{
// this happens when we run tests in parallel
await
sleep
(
5000
)
}
else
if
(
err
.
message
.
includes
(
'
message has already been received
'
)
)
{
...
...
integration-tests/test/shared/stress-test-helpers.ts
View file @
cee2a464
...
...
@@ -4,6 +4,7 @@ import { ethers } from 'ethers'
/* Imports: Internal */
import
{
OptimismEnv
}
from
'
./env
'
import
{
Direction
}
from
'
./watcher-utils
'
import
{
gasPriceForL1
,
gasPriceForL2
,
sleep
}
from
'
./utils
'
interface
TransactionParams
{
contract
:
ethers
.
Contract
...
...
@@ -14,13 +15,29 @@ interface TransactionParams {
// Arbitrary big amount of gas for the L1<>L2 messages.
const
MESSAGE_GAS
=
8
_000_000
export
const
executeL1ToL2Transactions
=
async
(
export
const
fundRandomWallet
=
async
(
env
:
OptimismEnv
,
txs
:
TransactionParams
[]
wallet
:
ethers
.
Wallet
,
value
:
ethers
.
BigNumber
):
Promise
<
ethers
.
Wallet
>
=>
{
const
fundTx
=
await
env
.
l1Wallet
.
sendTransaction
({
gasLimit
:
25
_000
,
to
:
wallet
.
address
,
gasPrice
:
await
gasPriceForL1
(
env
),
value
,
})
await
fundTx
.
wait
()
return
wallet
}
export
const
executeL1ToL2Transaction
=
async
(
env
:
OptimismEnv
,
wallet
:
ethers
.
Wallet
,
tx
:
TransactionParams
)
=>
{
for
(
const
tx
of
txs
)
{
const
signer
=
ethers
.
Wallet
.
createRandom
().
connect
(
env
.
l1Wallet
.
provider
)
const
receipt
=
await
env
.
l1Messenger
const
signer
=
wallet
.
connect
(
env
.
l1Wallet
.
provider
)
const
receipt
=
await
retryOnNonceError
(
async
()
=>
env
.
l1Messenger
.
connect
(
signer
)
.
sendMessage
(
tx
.
contract
.
address
,
...
...
@@ -30,21 +47,21 @@ export const executeL1ToL2Transactions = async (
),
MESSAGE_GAS
,
{
gasPrice
:
0
,
gasPrice
:
await
gasPriceForL1
(
env
)
,
}
)
await
env
.
waitForXDomainTransaction
(
receipt
,
Direction
.
L1ToL2
)
}
)
await
env
.
waitForXDomainTransaction
(
receipt
,
Direction
.
L1ToL2
)
}
export
const
executeL2ToL1Transaction
s
=
async
(
export
const
executeL2ToL1Transaction
=
async
(
env
:
OptimismEnv
,
txs
:
TransactionParams
[]
wallet
:
ethers
.
Wallet
,
tx
:
TransactionParams
)
=>
{
for
(
const
tx
of
txs
)
{
const
signer
=
ethers
.
Wallet
.
createRandom
().
connect
(
env
.
l2Wallet
.
provider
)
const
receipt
=
await
env
.
l2Messenger
const
signer
=
wallet
.
connect
(
env
.
l2Wallet
.
provider
)
const
receipt
=
await
retryOnNonceError
(()
=>
env
.
l2Messenger
.
connect
(
signer
)
.
sendMessage
(
tx
.
contract
.
address
,
...
...
@@ -54,162 +71,105 @@ export const executeL2ToL1Transactions = async (
),
MESSAGE_GAS
,
{
gasPrice
:
0
,
gasPrice
:
gasPriceForL2
()
,
}
)
)
await
env
.
relayXDomainMessages
(
receipt
)
await
env
.
waitForXDomainTransaction
(
receipt
,
Direction
.
L2ToL1
)
}
await
env
.
relayXDomainMessages
(
receipt
)
await
env
.
waitForXDomainTransaction
(
receipt
,
Direction
.
L2ToL1
)
}
export
const
executeL2Transaction
s
=
async
(
export
const
executeL2Transaction
=
async
(
env
:
OptimismEnv
,
txs
:
TransactionParams
[]
wallet
:
ethers
.
Wallet
,
tx
:
TransactionParams
)
=>
{
for
(
const
tx
of
txs
)
{
const
signer
=
ethers
.
Wallet
.
createRandom
().
connect
(
env
.
l2Wallet
.
provider
)
const
result
=
await
tx
.
contract
const
signer
=
wallet
.
connect
(
env
.
l2Wallet
.
provider
)
const
result
=
await
retryOnNonceError
(()
=>
tx
.
contract
.
connect
(
signer
)
.
functions
[
tx
.
functionName
](...
tx
.
functionParams
,
{
gasPrice
:
0
,
gasPrice
:
gasPriceForL2
()
,
})
await
result
.
wait
(
)
}
)
await
result
.
wait
()
}
export
const
executeRepeatedL1ToL2Transactions
=
async
(
env
:
OptimismEnv
,
tx
:
TransactionParams
,
count
:
number
wallets
:
ethers
.
Wallet
[]
,
tx
:
TransactionParams
)
=>
{
await
executeL1ToL2Transactions
(
env
,
[...
Array
(
count
).
keys
()].
map
(()
=>
tx
)
)
for
(
const
wallet
of
wallets
)
{
await
executeL1ToL2Transaction
(
env
,
wallet
,
tx
)
}
}
export
const
executeRepeatedL2ToL1Transactions
=
async
(
env
:
OptimismEnv
,
tx
:
TransactionParams
,
count
:
number
wallets
:
ethers
.
Wallet
[]
,
tx
:
TransactionParams
)
=>
{
await
executeL2ToL1Transactions
(
env
,
[...
Array
(
count
).
keys
()].
map
(()
=>
tx
)
)
for
(
const
wallet
of
wallets
)
{
await
executeL2ToL1Transaction
(
env
,
wallet
,
tx
)
}
}
export
const
executeRepeatedL2Transactions
=
async
(
env
:
OptimismEnv
,
tx
:
TransactionParams
,
count
:
number
wallets
:
ethers
.
Wallet
[]
,
tx
:
TransactionParams
)
=>
{
await
executeL2Transactions
(
env
,
[...
Array
(
count
).
keys
()].
map
(()
=>
tx
)
)
for
(
const
wallet
of
wallets
)
{
await
executeL2Transaction
(
env
,
wallet
,
tx
)
}
}
export
const
executeL1ToL2TransactionsParallel
=
async
(
env
:
OptimismEnv
,
txs
:
TransactionParams
[]
wallets
:
ethers
.
Wallet
[],
tx
:
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
)
})
)
await
Promise
.
all
(
wallets
.
map
((
w
)
=>
executeL1ToL2Transaction
(
env
,
w
,
tx
)))
}
export
const
executeL2ToL1TransactionsParallel
=
async
(
env
:
OptimismEnv
,
txs
:
TransactionParams
[]
wallets
:
ethers
.
Wallet
[],
tx
:
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
)
})
)
await
Promise
.
all
(
wallets
.
map
((
w
)
=>
executeL2ToL1Transaction
(
env
,
w
,
tx
)))
}
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
wallets
:
ethers
.
Wallet
[],
tx
:
TransactionParams
)
=>
{
await
executeL2ToL1TransactionsParallel
(
env
,
[...
Array
(
count
).
keys
()].
map
(()
=>
tx
)
)
await
Promise
.
all
(
wallets
.
map
((
w
)
=>
executeL2Transaction
(
env
,
w
,
tx
)))
}
export
const
executeRepeatedL2TransactionsParallel
=
async
(
env
:
OptimismEnv
,
tx
:
TransactionParams
,
count
:
number
)
=>
{
await
executeL2TransactionsParallel
(
env
,
[...
Array
(
count
).
keys
()].
map
(()
=>
tx
)
)
const
retryOnNonceError
=
async
(
cb
:
()
=>
Promise
<
any
>
):
Promise
<
any
>
=>
{
while
(
true
)
{
try
{
return
await
cb
()
}
catch
(
err
)
{
const
msg
=
err
.
message
.
toLowerCase
()
if
(
msg
.
includes
(
'
nonce too low
'
)
||
msg
.
includes
(
'
nonce has already been used
'
)
||
msg
.
includes
(
'
transaction was replaced
'
)
||
msg
.
includes
(
'
another transaction with same nonce in the queue
'
)
||
msg
.
includes
(
'
reverted without a reason
'
)
)
{
console
.
warn
(
'
Retrying transaction after nonce error.
'
)
await
sleep
(
5000
)
continue
}
throw
err
}
}
}
integration-tests/test/shared/utils.ts
View file @
cee2a464
...
...
@@ -19,10 +19,15 @@ import dotenv from 'dotenv'
/* Imports: Internal */
import
{
Direction
,
waitForXDomainTransaction
}
from
'
./watcher-utils
'
import
{
OptimismEnv
}
from
'
./env
'
export
const
GWEI
=
BigNumber
.
from
(
1
e9
)
if
(
process
.
env
.
IS_LIVE_NETWORK
===
'
true
'
)
{
export
const
isLiveNetwork
=
()
=>
{
return
process
.
env
.
IS_LIVE_NETWORK
===
'
true
'
}
if
(
isLiveNetwork
())
{
dotenv
.
config
()
}
...
...
@@ -144,12 +149,14 @@ export const encodeSolidityRevertMessage = (_reason: string): string => {
return
'
0x08c379a0
'
+
remove0x
(
abiCoder
.
encode
([
'
string
'
],
[
_reason
]))
}
export
const
DEFAULT_TRANSACTION
=
{
to
:
'
0x
'
+
'
1234
'
.
repeat
(
10
),
gasLimit
:
8
_000_000
,
gasPrice
:
0
,
data
:
'
0x
'
,
value
:
0
,
export
const
defaultTransactionFactory
=
()
=>
{
return
{
to
:
'
0x
'
+
'
1234
'
.
repeat
(
10
),
gasLimit
:
8
_000_000
,
gasPrice
:
BigNumber
.
from
(
0
),
data
:
'
0x
'
,
value
:
0
,
}
}
export
const
waitForL2Geth
=
async
(
...
...
@@ -166,3 +173,44 @@ export const waitForL2Geth = async (
}
return
injectL2Context
(
provider
)
}
export
const
awaitCondition
=
async
(
cond
:
()
=>
Promise
<
boolean
>
,
rate
=
1000
,
attempts
=
10
)
=>
{
for
(
let
i
=
0
;
i
<
attempts
;
i
++
)
{
const
ok
=
await
cond
()
if
(
ok
)
{
return
}
await
sleep
(
rate
)
}
throw
new
Error
(
'
Timed out.
'
)
}
export
const
gasPriceForL2
=
async
()
=>
{
if
(
isLiveNetwork
())
{
return
Promise
.
resolve
(
BigNumber
.
from
(
10000
))
}
return
Promise
.
resolve
(
BigNumber
.
from
(
0
))
}
// eslint-disable-next-line @typescript-eslint/no-shadow
export
const
gasPriceForL1
=
async
(
env
:
OptimismEnv
)
=>
{
const
chainId
=
await
env
.
l1Wallet
.
getChainId
()
switch
(
chainId
)
{
case
1
:
return
env
.
l1Wallet
.
getGasPrice
()
case
3
:
case
42
:
return
utils
.
parseUnits
(
'
10
'
,
'
gwei
'
)
case
5
:
return
utils
.
parseUnits
(
'
2
'
,
'
gwei
'
)
default
:
return
BigNumber
.
from
(
0
)
}
}
integration-tests/test/shared/watcher-utils.ts
View file @
cee2a464
...
...
@@ -60,6 +60,11 @@ export const waitForXDomainTransaction = async (
// get the message hash which was created on the SentMessage
const
[
xDomainMsgHash
]
=
await
watcher
.
getMessageHashesFromTx
(
src
,
tx
.
hash
)
if
(
!
xDomainMsgHash
)
{
throw
new
Error
(
`No x-domain message hash for tx hash
${
tx
.
hash
}
, bailing.`
)
}
// Get the transaction and receipt on the remote layer
const
remoteReceipt
=
await
watcher
.
getTransactionReceipt
(
dest
,
...
...
integration-tests/test/stress-tests.spec.ts
View file @
cee2a464
import
{
expect
}
from
'
chai
'
/* Imports: External */
import
{
Contract
,
ContractFactory
}
from
'
ethers
'
import
{
Contract
,
ContractFactory
,
Wallet
,
utils
}
from
'
ethers
'
/* Imports: Internal */
import
{
OptimismEnv
}
from
'
./shared/env
'
import
{
executeL1ToL2TransactionsParallel
,
executeL2ToL1TransactionsParallel
,
executeL2TransactionsParallel
,
executeRepeatedL1ToL2Transactions
,
executeRepeatedL2ToL1Transactions
,
executeRepeatedL2Transactions
,
executeRepeatedL1ToL2TransactionsParallel
,
executeRepeatedL2ToL1TransactionsParallel
,
executeRepeatedL2TransactionsParallel
,
fundRandomWallet
,
}
from
'
./shared/stress-test-helpers
'
/* Imports: Artifacts */
import
simpleStorageJson
from
'
../artifacts/contracts/SimpleStorage.sol/SimpleStorage.json
'
import
{
fundUser
,
isLiveNetwork
}
from
'
./shared/utils
'
// 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
=
5
00
_000
const
STRESS_TEST_TIMEOUT
=
isLiveNetwork
()
?
500
_000
:
1
_2
00_000
describe
(
'
stress tests
'
,
()
=>
{
const
numTransactions
=
3
let
env
:
OptimismEnv
const
wallets
:
Wallet
[]
=
[]
before
(
async
()
=>
{
env
=
await
OptimismEnv
.
new
()
for
(
let
i
=
0
;
i
<
numTransactions
;
i
++
)
{
wallets
.
push
(
Wallet
.
createRandom
())
}
for
(
const
wallet
of
wallets
)
{
await
fundRandomWallet
(
env
,
wallet
,
utils
.
parseEther
(
'
0.1
'
))
}
for
(
const
wallet
of
wallets
)
{
await
fundUser
(
env
.
watcher
,
env
.
l1Bridge
,
utils
.
parseEther
(
'
0.1
'
),
wallet
.
address
)
}
})
let
L2SimpleStorage
:
Contract
...
...
@@ -48,106 +72,76 @@ describe('stress tests', () => {
})
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
)
await
executeRepeatedL1ToL2Transactions
(
env
,
wallets
,
{
contract
:
L2SimpleStorage
,
functionName
:
'
setValue
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
})
expect
((
await
L2SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
numTransactions
wallets
.
length
)
}).
timeout
(
STRESS_TEST_TIMEOUT
)
it
(
`
${
numTransactions
}
L1 => L2 transactions (parallel)`
,
async
()
=>
{
await
executeRepeatedL1ToL2TransactionsParallel
(
env
,
{
contract
:
L2SimpleStorage
,
functionName
:
'
setValue
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
},
numTransactions
)
await
executeL1ToL2TransactionsParallel
(
env
,
wallets
,
{
contract
:
L2SimpleStorage
,
functionName
:
'
setValue
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
})
expect
((
await
L2SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
numTransactions
wallets
.
length
)
}).
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
)
await
executeRepeatedL2ToL1Transactions
(
env
,
wallets
,
{
contract
:
L1SimpleStorage
,
functionName
:
'
setValue
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
})
expect
((
await
L1SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
numTransactions
wallets
.
length
)
}).
timeout
(
STRESS_TEST_TIMEOUT
)
it
(
`
${
numTransactions
}
L2 => L1 transactions (parallel)`
,
async
()
=>
{
await
executeRepeatedL2ToL1TransactionsParallel
(
env
,
{
contract
:
L1SimpleStorage
,
functionName
:
'
setValue
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
},
numTransactions
)
await
executeL2ToL1TransactionsParallel
(
env
,
wallets
,
{
contract
:
L1SimpleStorage
,
functionName
:
'
setValue
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
})
expect
((
await
L1SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
numTransactions
wallets
.
length
)
}).
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
)
await
executeRepeatedL2Transactions
(
env
,
wallets
,
{
contract
:
L2SimpleStorage
,
functionName
:
'
setValueNotXDomain
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
})
expect
((
await
L2SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
numTransactions
wallets
.
length
)
}).
timeout
(
STRESS_TEST_TIMEOUT
)
it
(
`
${
numTransactions
}
L2 transactions (parallel)`
,
async
()
=>
{
await
executeRepeatedL2TransactionsParallel
(
env
,
{
contract
:
L2SimpleStorage
,
functionName
:
'
setValueNotXDomain
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
},
numTransactions
)
await
executeL2TransactionsParallel
(
env
,
wallets
,
{
contract
:
L2SimpleStorage
,
functionName
:
'
setValueNotXDomain
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
})
expect
((
await
L2SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
numTransactions
...
...
@@ -156,85 +150,59 @@ describe('stress tests', () => {
})
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
),
executeRepeatedL1ToL2Transactions
(
env
,
wallets
,
{
contract
:
L2SimpleStorage
,
functionName
:
'
setValue
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
}),
executeRepeatedL2ToL1Transactions
(
env
,
wallets
,
{
contract
:
L1SimpleStorage
,
functionName
:
'
setValue
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
}),
executeRepeatedL2Transactions
(
env
,
wallets
,
{
contract
:
L2SimpleStorage
,
functionName
:
'
setValueNotXDomain
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
}),
])
expect
((
await
L2SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
numTransactions
*
2
wallets
.
length
*
2
)
expect
((
await
L1SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
numTransactions
wallets
.
length
)
}).
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
),
executeL1ToL2TransactionsParallel
(
env
,
wallets
,
{
contract
:
L2SimpleStorage
,
functionName
:
'
setValue
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
}),
executeL2ToL1TransactionsParallel
(
env
,
wallets
,
{
contract
:
L1SimpleStorage
,
functionName
:
'
setValue
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
}),
executeL2TransactionsParallel
(
env
,
wallets
,
{
contract
:
L2SimpleStorage
,
functionName
:
'
setValueNotXDomain
'
,
functionParams
:
[
`0x
${
'
42
'
.
repeat
(
32
)}
`
],
}),
])
expect
((
await
L2SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
numTransactions
*
2
wallets
.
length
*
2
)
expect
((
await
L1SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
numTransactions
wallets
.
length
)
}).
timeout
(
STRESS_TEST_TIMEOUT
)
})
...
...
packages/contracts/deploy/000-hardhat-setup.ts
View file @
cee2a464
...
...
@@ -5,9 +5,9 @@ import {
getContractFromArtifact
,
fundAccount
,
sendImpersonatedTx
,
waitUntilTrue
,
BIG_BALANCE
,
}
from
'
../src/hardhat-deploy-ethers
'
import
{
awaitCondition
}
from
'
@eth-optimism/core-utils
'
const
deployFn
:
DeployFunction
=
async
(
hre
)
=>
{
if
((
hre
as
any
).
deployConfig
.
forked
!==
'
true
'
)
{
...
...
@@ -39,9 +39,13 @@ const deployFn: DeployFunction = async (hre) => {
})
console
.
log
(
`Waiting for owner to be correctly set...`
)
await
waitUntilTrue
(
async
()
=>
{
return
(
await
Lib_AddressManager
.
owner
())
===
deployer
})
await
awaitCondition
(
async
()
=>
{
return
(
await
Lib_AddressManager
.
owner
())
===
deployer
},
5000
,
100
)
// Get a reference to the L1StandardBridge contract.
const
Proxy__OVM_L1StandardBridge
=
await
getContractFromArtifact
(
...
...
@@ -63,13 +67,17 @@ const deployFn: DeployFunction = async (hre) => {
})
console
.
log
(
`Waiting for owner to be correctly set...`
)
await
waitUntilTrue
(
async
()
=>
{
return
(
(
await
Proxy__OVM_L1StandardBridge
.
callStatic
.
getOwner
({
from
:
hre
.
ethers
.
constants
.
AddressZero
,
}))
===
deployer
)
})
await
awaitCondition
(
async
()
=>
{
return
(
(
await
Proxy__OVM_L1StandardBridge
.
callStatic
.
getOwner
({
from
:
hre
.
ethers
.
constants
.
AddressZero
,
}))
===
deployer
)
},
5000
,
100
)
}
deployFn
.
tags
=
[
'
hardhat
'
,
'
upgrade
'
]
...
...
packages/contracts/deploy/007-OVM_L1CrossDomainMessenger.deploy.ts
View file @
cee2a464
/* Imports: External */
import
{
DeployFunction
}
from
'
hardhat-deploy/dist/types
'
import
{
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
import
{
hexStringEquals
,
awaitCondition
}
from
'
@eth-optimism/core-utils
'
/* Imports: Internal */
import
{
deployAndPostDeploy
,
getContractFromArtifact
,
waitUntilTrue
,
}
from
'
../src/hardhat-deploy-ethers
'
const
deployFn
:
DeployFunction
=
async
(
hre
)
=>
{
...
...
@@ -29,12 +28,16 @@ const deployFn: DeployFunction = async (hre) => {
await
contract
.
initialize
(
Lib_AddressManager
.
address
)
console
.
log
(
`Checking that contract was correctly initialized...`
)
await
waitUntilTrue
(
async
()
=>
{
return
hexStringEquals
(
await
contract
.
libAddressManager
(),
Lib_AddressManager
.
address
)
})
await
awaitCondition
(
async
()
=>
{
return
hexStringEquals
(
await
contract
.
libAddressManager
(),
Lib_AddressManager
.
address
)
},
5000
,
100
)
},
})
}
...
...
packages/contracts/deploy/008-Proxy__OVM_L1CrossDomainMessenger.deploy.ts
View file @
cee2a464
...
...
@@ -6,7 +6,6 @@ import { hexStringEquals } from '@eth-optimism/core-utils'
import
{
deployAndPostDeploy
,
getContractFromArtifact
,
waitUntilTrue
,
}
from
'
../src/hardhat-deploy-ethers
'
const
deployFn
:
DeployFunction
=
async
(
hre
)
=>
{
...
...
packages/contracts/deploy/011-set-addresses.ts
View file @
cee2a464
/* Imports: External */
import
{
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
import
{
hexStringEquals
,
awaitCondition
}
from
'
@eth-optimism/core-utils
'
import
{
ethers
}
from
'
hardhat
'
import
{
DeployFunction
}
from
'
hardhat-deploy/dist/types
'
/* Imports: Internal */
import
{
getContractFromArtifact
,
waitUntilTrue
,
}
from
'
../src/hardhat-deploy-ethers
'
import
{
getContractFromArtifact
}
from
'
../src/hardhat-deploy-ethers
'
const
deployFn
:
DeployFunction
=
async
(
hre
)
=>
{
const
{
deployer
}
=
await
hre
.
getNamedAccounts
()
...
...
@@ -92,18 +89,16 @@ const deployFn: DeployFunction = async (hre) => {
}
// Wait for ownership to be transferred to the AddressDictator contract.
await
waitUntilTrue
(
await
awaitCondition
(
async
()
=>
{
return
hexStringEquals
(
await
Lib_AddressManager
.
owner
(),
AddressDictator
.
address
)
},
{
// Try every 30 seconds for 500 minutes.
delay
:
30
_000
,
retries
:
1000
,
}
// Try every 30 seconds for 500 minutes.
30000
,
1000
)
// Set the addresses!
...
...
@@ -112,9 +107,13 @@ const deployFn: DeployFunction = async (hre) => {
// Make sure ownership has been correctly sent back to the original owner.
console
.
log
(
'
Verifying final ownership of Lib_AddressManager...
'
)
await
waitUntilTrue
(
async
()
=>
{
return
hexStringEquals
(
await
Lib_AddressManager
.
owner
(),
finalOwner
)
})
await
awaitCondition
(
async
()
=>
{
return
hexStringEquals
(
await
Lib_AddressManager
.
owner
(),
finalOwner
)
},
500
,
1000
)
}
deployFn
.
tags
=
[
'
set-addresses
'
,
'
upgrade
'
]
...
...
packages/contracts/deploy/012-initialize-Proxy__L1CrossDomainMessenger.ts
View file @
cee2a464
/* Imports: External */
import
{
DeployFunction
}
from
'
hardhat-deploy/dist/types
'
import
{
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
import
{
hexStringEquals
,
awaitCondition
}
from
'
@eth-optimism/core-utils
'
/* Imports: Internal */
import
{
getContractFromArtifact
,
waitUntilTrue
,
}
from
'
../src/hardhat-deploy-ethers
'
import
{
getContractFromArtifact
}
from
'
../src/hardhat-deploy-ethers
'
const
deployFn
:
DeployFunction
=
async
(
hre
)
=>
{
const
{
deployer
}
=
await
hre
.
getNamedAccounts
()
...
...
@@ -34,12 +31,16 @@ const deployFn: DeployFunction = async (hre) => {
await
Proxy__OVM_L1CrossDomainMessenger
.
initialize
(
Lib_AddressManager
.
address
)
console
.
log
(
`Checking that contract was correctly initialized...`
)
await
waitUntilTrue
(
async
()
=>
{
return
hexStringEquals
(
await
Proxy__OVM_L1CrossDomainMessenger
.
libAddressManager
(),
Lib_AddressManager
.
address
)
})
await
awaitCondition
(
async
()
=>
{
return
hexStringEquals
(
await
Proxy__OVM_L1CrossDomainMessenger
.
libAddressManager
(),
Lib_AddressManager
.
address
)
},
5000
,
100
)
}
deployFn
.
tags
=
[
'
finalize
'
]
...
...
packages/contracts/deploy/014-OVM_L1StandardBridge.deploy.ts
View file @
cee2a464
/* Imports: External */
import
{
DeployFunction
}
from
'
hardhat-deploy/dist/types
'
import
{
ethers
}
from
'
ethers
'
import
{
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
import
{
hexStringEquals
,
awaitCondition
}
from
'
@eth-optimism/core-utils
'
/* Imports: Internal */
import
{
getContractDefinition
}
from
'
../src/contract-defs
'
import
{
getContractFromArtifact
,
waitUntilTrue
,
deployAndPostDeploy
,
}
from
'
../src/hardhat-deploy-ethers
'
...
...
@@ -100,7 +99,7 @@ const deployFn: DeployFunction = async (hre) => {
}
// Wait for ownership to be transferred to the AddressDictator contract.
await
waitUntilTrue
(
await
awaitCondition
(
async
()
=>
{
return
hexStringEquals
(
await
Proxy__OVM_L1StandardBridge
.
connect
(
...
...
@@ -111,11 +110,8 @@ const deployFn: DeployFunction = async (hre) => {
ChugSplashDictator
.
address
)
},
{
// Try every 30 seconds for 500 minutes.
delay
:
30
_000
,
retries
:
1000
,
}
30000
,
1000
)
// Set the addresses!
...
...
@@ -123,16 +119,20 @@ const deployFn: DeployFunction = async (hre) => {
await
ChugSplashDictator
.
doActions
(
bridgeCode
)
console
.
log
(
`Confirming that owner address was correctly set...`
)
await
waitUntilTrue
(
async
()
=>
{
return
hexStringEquals
(
await
Proxy__OVM_L1StandardBridge
.
connect
(
Proxy__OVM_L1StandardBridge
.
signer
.
provider
).
callStatic
.
getOwner
({
from
:
ethers
.
constants
.
AddressZero
,
}),
finalOwner
)
})
await
awaitCondition
(
async
()
=>
{
return
hexStringEquals
(
await
Proxy__OVM_L1StandardBridge
.
connect
(
Proxy__OVM_L1StandardBridge
.
signer
.
provider
).
callStatic
.
getOwner
({
from
:
ethers
.
constants
.
AddressZero
,
}),
finalOwner
)
},
5000
,
100
)
// Deploy a copy of the implementation so it can be successfully verified on Etherscan.
console
.
log
(
`Deploying a copy of the bridge for Etherscan verification...`
)
...
...
packages/contracts/deploy/015-finalize.ts
View file @
cee2a464
/* Imports: External */
import
{
DeployFunction
}
from
'
hardhat-deploy/dist/types
'
import
{
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
import
{
hexStringEquals
,
awaitCondition
}
from
'
@eth-optimism/core-utils
'
/* Imports: Internal */
import
{
getContractFromArtifact
,
waitUntilTrue
,
}
from
'
../src/hardhat-deploy-ethers
'
import
{
getContractFromArtifact
}
from
'
../src/hardhat-deploy-ethers
'
const
deployFn
:
DeployFunction
=
async
(
hre
)
=>
{
const
{
deployer
}
=
await
hre
.
getNamedAccounts
()
...
...
@@ -31,9 +28,13 @@ const deployFn: DeployFunction = async (hre) => {
await
Lib_AddressManager
.
transferOwnership
(
owner
)
console
.
log
(
`Confirming transfer was successful...`
)
await
waitUntilTrue
(
async
()
=>
{
return
hexStringEquals
(
await
Lib_AddressManager
.
owner
(),
owner
)
})
await
awaitCondition
(
async
()
=>
{
return
hexStringEquals
(
await
Lib_AddressManager
.
owner
(),
owner
)
},
5000
,
100
)
console
.
log
(
`✓ Set owner of Lib_AddressManager to:
${
owner
}
`
)
}
...
...
packages/contracts/src/hardhat-deploy-ethers.ts
View file @
cee2a464
...
...
@@ -2,29 +2,13 @@
import
{
ethers
,
Contract
}
from
'
ethers
'
import
{
Provider
}
from
'
@ethersproject/abstract-provider
'
import
{
Signer
}
from
'
@ethersproject/abstract-signer
'
import
{
sleep
,
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
import
{
sleep
,
hexStringEquals
,
awaitCondition
,
}
from
'
@eth-optimism/core-utils
'
import
{
HttpNetworkConfig
}
from
'
hardhat/types
'
export
const
waitUntilTrue
=
async
(
check
:
()
=>
Promise
<
boolean
>
,
opts
:
{
retries
?:
number
delay
?:
number
}
=
{}
)
=>
{
opts
.
retries
=
opts
.
retries
||
100
opts
.
delay
=
opts
.
delay
||
5000
let
retries
=
0
while
(
!
(
await
check
()))
{
if
(
retries
>
opts
.
retries
)
{
throw
new
Error
(
`check failed after
${
opts
.
retries
}
attempts`
)
}
retries
++
await
sleep
(
opts
.
delay
)
}
}
export
const
deployAndPostDeploy
=
async
({
hre
,
name
,
...
...
@@ -152,10 +136,14 @@ export const fundAccount = async (
])
console
.
log
(
`Waiting for balance to reflect...`
)
await
waitUntilTrue
(
async
()
=>
{
const
balance
=
await
hre
.
ethers
.
provider
.
getBalance
(
address
)
return
balance
.
gte
(
amount
)
})
await
awaitCondition
(
async
()
=>
{
const
balance
=
await
hre
.
ethers
.
provider
.
getBalance
(
address
)
return
balance
.
gte
(
amount
)
},
5000
,
100
)
console
.
log
(
`Account successfully funded.`
)
}
...
...
packages/core-utils/src/common/test-utils.ts
View file @
cee2a464
import
{
expect
}
from
'
chai
'
import
{
BigNumber
}
from
'
ethers
'
import
{
sleep
}
from
'
./misc
'
interface
deviationRanges
{
percentUpperDeviation
?:
number
...
...
@@ -8,6 +9,23 @@ interface deviationRanges {
absoluteLowerDeviation
?:
number
}
export
const
awaitCondition
=
async
(
cond
:
()
=>
Promise
<
boolean
>
,
rate
=
1000
,
attempts
=
10
)
=>
{
for
(
let
i
=
0
;
i
<
attempts
;
i
++
)
{
const
ok
=
await
cond
()
if
(
ok
)
{
return
}
await
sleep
(
rate
)
}
throw
new
Error
(
'
Timed out.
'
)
}
/**
* Assert that a number lies within a custom defined range of the target.
*/
...
...
packages/core-utils/test/common/test-utils.spec.ts
View file @
cee2a464
import
{
expect
}
from
'
../setup
'
/* Imports: Internal */
import
{
expectApprox
}
from
'
../../src
'
import
{
expectApprox
,
awaitCondition
}
from
'
../../src
'
import
{
assert
}
from
'
chai
'
describe
(
'
awaitCondition
'
,
()
=>
{
it
(
'
should try the condition fn until it returns true
'
,
async
()
=>
{
let
i
=
0
const
condFn
=
async
()
=>
{
i
++
return
Promise
.
resolve
(
i
===
2
)
}
await
awaitCondition
(
condFn
,
50
,
3
);
expect
(
i
).
to
.
equal
(
2
)
})
it
(
'
should only try the configured number of attempts
'
,
async
()
=>
{
let
i
=
0
const
condFn
=
async
()
=>
{
i
++
return
Promise
.
resolve
(
i
===
2
)
}
try
{
await
awaitCondition
(
condFn
,
50
,
1
);
}
catch
(
e
)
{
return
;
}
assert
.
fail
(
'
Condition never failed, but it should have.
'
);
})
})
describe
(
'
expectApprox
'
,
()
=>
{
it
(
'
should pass when the actual number is higher, but within the expected range of the target
'
,
async
()
=>
{
expectApprox
(
119
,
100
,
{
...
...
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