Fix(133): Improve e2e tests performance (#234)

* fix: add mutex in account manager to avoid nonce issue

* fix: optimize global setup

* fix: update jest config to exit even if there are open handles

* feat: deploy smart contracts from artifacts + change e2e tests setup

* fix: update pnpm

* fix: remove compile contracts gradle task

* fix: remove compileContracts gradle task

* fix: refactor genesis generator dockerfile + downgrade l1-el-node besu version

* fix: move abi from e2e folder to contract folder + refactor contracts deployments scripts

* feat: add deployment script from artifacts for LineaRollupV6

* update pnpm version in get-started.md

* fix: update console log in deployment scripts

* fix: update besu version + fix deployment scripts

* fix: update submission finalization tests + rename variable
This commit is contained in:
Victorien Gauch
2024-10-30 14:10:24 +01:00
committed by GitHub
parent be62a1b1a0
commit 36959fb21b
49 changed files with 4601 additions and 4025 deletions

View File

@@ -8,10 +8,11 @@ const config: Config = {
verbose: true,
globalSetup: "./config/jest/global-setup.ts",
globalTeardown: "./config/jest/global-teardown.ts",
maxWorkers: "50%",
maxConcurrency: 5,
testTimeout: 3 * 60 * 1000,
maxConcurrency: 7,
maxWorkers: "75%",
workerThreads: true,
forceExit: true,
};
export default config;

View File

@@ -11,7 +11,7 @@
"test:e2e:local": "TEST_ENV=local npx jest",
"test:e2e:dev": "TEST_ENV=dev npx jest --config ./jest.testnet.config.ts --bail --runInBand --testPathIgnorePatterns=restart.spec.ts",
"test:e2e:sepolia": "TEST_ENV=sepolia npx jest --config ./jest.testnet.config.ts --bail --runInBand --testPathIgnorePatterns=restart.spec.ts",
"postinstall": "typechain --target ethers-v6 --out-dir ./src/typechain './src/abi/*.json'",
"postinstall": "typechain --target ethers-v6 --out-dir ./src/typechain '../contracts/local-deployments-artifacts/**/*.json'",
"lint:fix": "pnpm run lint:ts:fix && pnpm run prettier:fix",
"clean": "rimraf node_modules src/typechain"
},
@@ -22,6 +22,7 @@
"@openzeppelin/upgrades-core": "1.33.1",
"@typechain/ethers-v6": "0.5.1",
"@types/jest": "29.5.13",
"async-mutex": "^0.5.0",
"child_process": "1.0.2",
"dotenv": "16.4.5",
"ethers": "6.13.3",

View File

@@ -1,89 +0,0 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "DummyContract",
"sourceName": "contracts/messageService/DummyContract.sol",
"abi": [
{
"inputs": [],
"name": "age",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "payload",
"outputs": [
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_newAge",
"type": "uint256"
}
],
"name": "setAge",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "_newName",
"type": "string"
}
],
"name": "setName",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "_payload",
"type": "bytes"
}
],
"name": "setPayload",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x608060405234801561001057600080fd5b5061058d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806306fdde0314610067578063262a9dff14610085578063a878f8581461009c578063c47f0027146100a4578063d5dcf127146100b9578063deb3cdf2146100cc575b600080fd5b61006f6100df565b60405161007c91906101e2565b60405180910390f35b61008e60015481565b60405190815260200161007c565b61006f61016d565b6100b76100b2366004610212565b61017a565b005b6100b76100c73660046102c3565b600155565b6100b76100da3660046102dc565b61018a565b600080546100ec9061034e565b80601f01602080910402602001604051908101604052809291908181526020018280546101189061034e565b80156101655780601f1061013a57610100808354040283529160200191610165565b820191906000526020600020905b81548152906001019060200180831161014857829003601f168201915b505050505081565b600280546100ec9061034e565b600061018682826103d6565b5050565b6002610197828483610496565b505050565b6000815180845260005b818110156101c2576020818501810151868301820152016101a6565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006101f5602083018461019c565b9392505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561022457600080fd5b813567ffffffffffffffff8082111561023c57600080fd5b818401915084601f83011261025057600080fd5b813581811115610262576102626101fc565b604051601f8201601f19908116603f0116810190838211818310171561028a5761028a6101fc565b816040528281528760208487010111156102a357600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000602082840312156102d557600080fd5b5035919050565b600080602083850312156102ef57600080fd5b823567ffffffffffffffff8082111561030757600080fd5b818501915085601f83011261031b57600080fd5b81358181111561032a57600080fd5b86602082850101111561033c57600080fd5b60209290920196919550909350505050565b600181811c9082168061036257607f821691505b60208210810361038257634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561019757600081815260208120601f850160051c810160208610156103af5750805b601f850160051c820191505b818110156103ce578281556001016103bb565b505050505050565b815167ffffffffffffffff8111156103f0576103f06101fc565b610404816103fe845461034e565b84610388565b602080601f83116001811461043957600084156104215750858301515b600019600386901b1c1916600185901b1785556103ce565b600085815260208120601f198616915b8281101561046857888601518255948401946001909101908401610449565b50858210156104865787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b67ffffffffffffffff8311156104ae576104ae6101fc565b6104c2836104bc835461034e565b83610388565b6000601f8411600181146104f657600085156104de5750838201355b600019600387901b1c1916600186901b178355610550565b600083815260209020601f19861690835b828110156105275786850135825560209485019460019092019101610507565b50868210156105445760001960f88860031b161c19848701351681555b505060018560011b0183555b505050505056fea26469706673582212207e818de156c0521ea5a573908822840fd65862fb2f8510cd6d9ed8daa261d2c864736f6c63430008130033",
"deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c806306fdde0314610067578063262a9dff14610085578063a878f8581461009c578063c47f0027146100a4578063d5dcf127146100b9578063deb3cdf2146100cc575b600080fd5b61006f6100df565b60405161007c91906101e2565b60405180910390f35b61008e60015481565b60405190815260200161007c565b61006f61016d565b6100b76100b2366004610212565b61017a565b005b6100b76100c73660046102c3565b600155565b6100b76100da3660046102dc565b61018a565b600080546100ec9061034e565b80601f01602080910402602001604051908101604052809291908181526020018280546101189061034e565b80156101655780601f1061013a57610100808354040283529160200191610165565b820191906000526020600020905b81548152906001019060200180831161014857829003601f168201915b505050505081565b600280546100ec9061034e565b600061018682826103d6565b5050565b6002610197828483610496565b505050565b6000815180845260005b818110156101c2576020818501810151868301820152016101a6565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006101f5602083018461019c565b9392505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561022457600080fd5b813567ffffffffffffffff8082111561023c57600080fd5b818401915084601f83011261025057600080fd5b813581811115610262576102626101fc565b604051601f8201601f19908116603f0116810190838211818310171561028a5761028a6101fc565b816040528281528760208487010111156102a357600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000602082840312156102d557600080fd5b5035919050565b600080602083850312156102ef57600080fd5b823567ffffffffffffffff8082111561030757600080fd5b818501915085601f83011261031b57600080fd5b81358181111561032a57600080fd5b86602082850101111561033c57600080fd5b60209290920196919550909350505050565b600181811c9082168061036257607f821691505b60208210810361038257634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111561019757600081815260208120601f850160051c810160208610156103af5750805b601f850160051c820191505b818110156103ce578281556001016103bb565b505050505050565b815167ffffffffffffffff8111156103f0576103f06101fc565b610404816103fe845461034e565b84610388565b602080601f83116001811461043957600084156104215750858301515b600019600386901b1c1916600185901b1785556103ce565b600085815260208120601f198616915b8281101561046857888601518255948401946001909101908401610449565b50858210156104865787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b67ffffffffffffffff8311156104ae576104ae6101fc565b6104c2836104bc835461034e565b83610388565b6000601f8411600181146104f657600085156104de5750838201355b600019600387901b1c1916600186901b178355610550565b600083815260209020601f19861690835b828110156105275786850135825560209485019460019092019101610507565b50868210156105445760001960f88860031b161c19848701351681555b505060018560011b0183555b505050505056fea26469706673582212207e818de156c0521ea5a573908822840fd65862fb2f8510cd6d9ed8daa261d2c864736f6c63430008130033",
"linkReferences": {},
"deployedLinkReferences": {}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,28 +0,0 @@
[
{
"inputs": [
{
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "changeValue",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "testValue",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,158 +0,0 @@
{
"contractName": "ProxyAdmin",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [
{
"internalType": "contract ITransparentUpgradeableProxy",
"name": "proxy",
"type": "address"
},
{
"internalType": "address",
"name": "newAdmin",
"type": "address"
}
],
"name": "changeProxyAdmin",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ITransparentUpgradeableProxy",
"name": "proxy",
"type": "address"
}
],
"name": "getProxyAdmin",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ITransparentUpgradeableProxy",
"name": "proxy",
"type": "address"
}
],
"name": "getProxyImplementation",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ITransparentUpgradeableProxy",
"name": "proxy",
"type": "address"
},
{
"internalType": "address",
"name": "implementation",
"type": "address"
}
],
"name": "upgrade",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ITransparentUpgradeableProxy",
"name": "proxy",
"type": "address"
},
{
"internalType": "address",
"name": "implementation",
"type": "address"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "upgradeAndCall",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
],
"bytecode": "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61069a8061007e6000396000f3fe60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461011157806399a88ec414610124578063f2fde38b14610144578063f3b7dead1461016457600080fd5b8063204e1c7a14610080578063715018a6146100bc5780637eff275e146100d35780638da5cb5b146100f3575b600080fd5b34801561008c57600080fd5b506100a061009b366004610499565b610184565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c857600080fd5b506100d1610215565b005b3480156100df57600080fd5b506100d16100ee3660046104bd565b610229565b3480156100ff57600080fd5b506000546001600160a01b03166100a0565b6100d161011f36600461050c565b610291565b34801561013057600080fd5b506100d161013f3660046104bd565b610300565b34801561015057600080fd5b506100d161015f366004610499565b610336565b34801561017057600080fd5b506100a061017f366004610499565b6103b4565b6000806000836001600160a01b03166040516101aa90635c60da1b60e01b815260040190565b600060405180830381855afa9150503d80600081146101e5576040519150601f19603f3d011682016040523d82523d6000602084013e6101ea565b606091505b5091509150816101f957600080fd5b8080602001905181019061020d91906105e2565b949350505050565b61021d6103da565b6102276000610434565b565b6102316103da565b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b600060405180830381600087803b15801561027557600080fd5b505af1158015610289573d6000803e3d6000fd5b505050505050565b6102996103da565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906102c990869086906004016105ff565b6000604051808303818588803b1580156102e257600080fd5b505af11580156102f6573d6000803e3d6000fd5b5050505050505050565b6103086103da565b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe69060240161025b565b61033e6103da565b6001600160a01b0381166103a85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6103b181610434565b50565b6000806000836001600160a01b03166040516101aa906303e1469160e61b815260040190565b6000546001600160a01b031633146102275760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161039f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146103b157600080fd5b6000602082840312156104ab57600080fd5b81356104b681610484565b9392505050565b600080604083850312156104d057600080fd5b82356104db81610484565b915060208301356104eb81610484565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561052157600080fd5b833561052c81610484565b9250602084013561053c81610484565b9150604084013567ffffffffffffffff8082111561055957600080fd5b818601915086601f83011261056d57600080fd5b81358181111561057f5761057f6104f6565b604051601f8201601f19908116603f011681019083821181831017156105a7576105a76104f6565b816040528281528960208487010111156105c057600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156105f457600080fd5b81516104b681610484565b60018060a01b038316815260006020604081840152835180604085015260005b8181101561063b5785810183015185820160600152820161061f565b8181111561064d576000606083870101525b50601f01601f19169290920160600194935050505056fea26469706673582212207ad53e1008cce369999f6b5f2f77109510b404ff1de9b47b639981fd68e6239264736f6c63430008090033",
"deployedBytecode": "0x60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461011157806399a88ec414610124578063f2fde38b14610144578063f3b7dead1461016457600080fd5b8063204e1c7a14610080578063715018a6146100bc5780637eff275e146100d35780638da5cb5b146100f3575b600080fd5b34801561008c57600080fd5b506100a061009b366004610499565b610184565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c857600080fd5b506100d1610215565b005b3480156100df57600080fd5b506100d16100ee3660046104bd565b610229565b3480156100ff57600080fd5b506000546001600160a01b03166100a0565b6100d161011f36600461050c565b610291565b34801561013057600080fd5b506100d161013f3660046104bd565b610300565b34801561015057600080fd5b506100d161015f366004610499565b610336565b34801561017057600080fd5b506100a061017f366004610499565b6103b4565b6000806000836001600160a01b03166040516101aa90635c60da1b60e01b815260040190565b600060405180830381855afa9150503d80600081146101e5576040519150601f19603f3d011682016040523d82523d6000602084013e6101ea565b606091505b5091509150816101f957600080fd5b8080602001905181019061020d91906105e2565b949350505050565b61021d6103da565b6102276000610434565b565b6102316103da565b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b600060405180830381600087803b15801561027557600080fd5b505af1158015610289573d6000803e3d6000fd5b505050505050565b6102996103da565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906102c990869086906004016105ff565b6000604051808303818588803b1580156102e257600080fd5b505af11580156102f6573d6000803e3d6000fd5b5050505050505050565b6103086103da565b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe69060240161025b565b61033e6103da565b6001600160a01b0381166103a85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6103b181610434565b50565b6000806000836001600160a01b03166040516101aa906303e1469160e61b815260040190565b6000546001600160a01b031633146102275760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161039f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146103b157600080fd5b6000602082840312156104ab57600080fd5b81356104b681610484565b9392505050565b600080604083850312156104d057600080fd5b82356104db81610484565b915060208301356104eb81610484565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561052157600080fd5b833561052c81610484565b9250602084013561053c81610484565b9150604084013567ffffffffffffffff8082111561055957600080fd5b818601915086601f83011261056d57600080fd5b81358181111561057f5761057f6104f6565b604051601f8201601f19908116603f011681019083821181831017156105a7576105a76104f6565b816040528281528960208487010111156105c057600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156105f457600080fd5b81516104b681610484565b60018060a01b038316815260006020604081840152835180604085015260005b8181101561063b5785810183015185820160600152820161061f565b8181111561064d576000606083870101525b50601f01601f19169290920160600194935050505056fea26469706673582212207ad53e1008cce369999f6b5f2f77109510b404ff1de9b47b639981fd68e6239264736f6c63430008090033",
"linkReferences": {},
"deployedLinkReferences": {}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
import { AbiCoder, BaseContract, ContractFactory, Wallet, ethers } from "ethers";
import { AbiCoder, AbstractSigner, BaseContract, ContractFactory, Wallet, ethers } from "ethers";
import { ProxyAdmin__factory, TransparentUpgradeableProxy__factory, ProxyAdmin } from "../typechain";
export const encodeData = (types: string[], values: unknown[], packed?: boolean) => {
@@ -21,7 +21,7 @@ export const encodeLibraryName = (libraryName: string) => {
export const deployContract = async <T extends ContractFactory>(
contractFactory: T,
deployer: Wallet,
deployer: AbstractSigner,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
args?: any[],
): Promise<BaseContract> => {

View File

@@ -1,9 +1,9 @@
import * as fs from "fs";
import assert from "assert";
import { BaseContract, BlockTag, TransactionReceipt, TransactionRequest, Wallet, ethers } from "ethers";
import { AbstractSigner, BaseContract, BlockTag, TransactionReceipt, TransactionRequest, Wallet, ethers } from "ethers";
import path from "path";
import { exec } from "child_process";
import { L2MessageService, LineaRollup } from "../typechain";
import { L2MessageService, LineaRollupV5 } from "../typechain";
import { PayableOverrides, TypedContractEvent, TypedDeferredTopicFilter, TypedEventLog } from "../typechain/common";
import { MessageEvent, SendMessageArgs } from "./types";
@@ -79,7 +79,8 @@ export class TransactionExclusionClient {
this.endpoint = endpoint;
}
public async getTransactionExclusionStatusV1(txHash: String): Promise<any> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public async getTransactionExclusionStatusV1(txHash: string): Promise<any> {
const request = {
method: "post",
body: JSON.stringify({
@@ -94,13 +95,15 @@ export class TransactionExclusionClient {
}
public async saveRejectedTransactionV1(
txRejectionStage: String,
timestamp: String, // ISO-8601
blockNumber: Number | null,
transactionRLP: String,
reasonMessage: String,
overflows: { module: String; count: Number; limit: Number }[],
txRejectionStage: string,
timestamp: string, // ISO-8601
blockNumber: number | null,
transactionRLP: string,
reasonMessage: string,
overflows: { module: string; count: number; limit: number }[],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<any> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let params: any = {
txRejectionStage,
timestamp,
@@ -144,7 +147,7 @@ export async function getBlockByNumberOrBlockTag(rpcUrl: URL, blockTag: BlockTag
}
}
export async function getEvents<TContract extends LineaRollup | L2MessageService, TEvent extends TypedContractEvent>(
export async function getEvents<TContract extends LineaRollupV5 | L2MessageService, TEvent extends TypedContractEvent>(
contract: TContract,
eventFilter: TypedDeferredTopicFilter<TEvent>,
fromBlock?: BlockTag,
@@ -165,7 +168,7 @@ export async function getEvents<TContract extends LineaRollup | L2MessageService
}
export async function waitForEvents<
TContract extends LineaRollup | L2MessageService,
TContract extends LineaRollupV5 | L2MessageService,
TEvent extends TypedContractEvent,
>(
contract: TContract,
@@ -221,10 +224,13 @@ export async function waitForFile(
throw new Error("File check timed out");
}
export async function sendTransactionsToGenerateTrafficWithInterval(signer: Wallet, pollingInterval: number = 1_000) {
export async function sendTransactionsToGenerateTrafficWithInterval(
signer: AbstractSigner,
pollingInterval: number = 1_000,
) {
const { maxPriorityFeePerGas, maxFeePerGas } = await signer.provider!.getFeeData();
const transactionRequest = {
to: signer.address,
to: await signer.getAddress(),
value: etherToWei("0.000001"),
maxPriorityFeePerGas: maxPriorityFeePerGas,
maxFeePerGas: maxFeePerGas,
@@ -288,8 +294,8 @@ export function getMessageSentEventFromLogs<T extends BaseContract>(
});
}
export const sendMessage = async <T extends LineaRollup | L2MessageService>(
signer: Wallet,
export const sendMessage = async <T extends LineaRollupV5 | L2MessageService>(
signer: AbstractSigner,
contract: T,
args: SendMessageArgs,
overrides?: PayableOverrides,

View File

@@ -11,31 +11,41 @@ declare global {
export default async (): Promise<void> => {
const account = config.getL1AccountManager().whaleAccount(0);
const l2Account = config.getL2AccountManager().whaleAccount(0);
const [dummyContract, l2DummyContract] = await Promise.all([
deployContract(new DummyContract__factory(), account),
deployContract(new DummyContract__factory(), l2Account),
]);
console.log(`L1 Dummy contract deployed at address: ${await dummyContract.getAddress()}`);
console.log(`L2 Dummy contract deployed at address: ${await l2DummyContract.getAddress()}`);
const l2TestContract = await deployContract(new TestContract__factory(), l2Account);
console.log(`L2 Test contract deployed at address: ${await l2TestContract.getAddress()}`);
// Send ETH to the LineaRollup contract
const lineaRollup = config.getLineaRollupContract(account);
const l1JsonRpcProvider = config.getL1Provider();
const value = etherToWei("500");
const [l1AccountNonce, l2AccountNonce, { maxPriorityFeePerGas, maxFeePerGas }] = await Promise.all([
account.getNonce(),
l2Account.getNonce(),
l1JsonRpcProvider.getFeeData(),
]);
const fee = etherToWei("3");
const to = "0x8D97689C9818892B700e27F316cc3E41e17fBeb9";
const calldata = "0x";
const { maxPriorityFeePerGas, maxFeePerGas } = await l1JsonRpcProvider.getFeeData();
const tx = await lineaRollup.sendMessage(to, fee, calldata, { value, maxPriorityFeePerGas, maxFeePerGas });
await tx.wait();
const [dummyContract, l2DummyContract, l2TestContract] = await Promise.all([
deployContract(new DummyContract__factory(), account, [{ nonce: l1AccountNonce }]),
deployContract(new DummyContract__factory(), l2Account, [{ nonce: l2AccountNonce }]),
deployContract(new TestContract__factory(), l2Account, [{ nonce: l2AccountNonce + 1 }]),
// Send ETH to the LineaRollup contract
(
await lineaRollup.sendMessage(to, fee, calldata, {
value: etherToWei("500"),
maxPriorityFeePerGas,
maxFeePerGas,
nonce: l1AccountNonce + 1,
})
).wait(),
]);
console.log(`L1 Dummy contract deployed at address: ${await dummyContract.getAddress()}`);
console.log(`L2 Dummy contract deployed at address: ${await l2DummyContract.getAddress()}`);
console.log(`L2 Test contract deployed at address: ${await l2TestContract.getAddress()}`);
console.log("Generating L2 traffic...");
const stopPolling = await sendTransactionsToGenerateTrafficWithInterval(l2Account, 2_000);
const pollingAccount = await config.getL2AccountManager().generateAccount(etherToWei("200"));
const stopPolling = await sendTransactionsToGenerateTrafficWithInterval(pollingAccount, 2_000);
global.stopL2TrafficGeneration = stopPolling;
};

View File

@@ -1,9 +1,10 @@
import { ethers, Provider, Wallet } from "ethers";
import { ethers, NonceManager, Provider, TransactionResponse, Wallet } from "ethers";
import { Mutex } from "async-mutex";
import Account from "./account";
import { etherToWei } from "../../../common/utils";
interface IAccountManager {
whaleAccount(accIndex?: number): Wallet;
whaleAccount(accIndex?: number): NonceManager;
generateAccount(initialBalanceWei?: bigint): Promise<Wallet>;
generateAccounts(numberOfAccounts: number, initialBalanceWei?: bigint): Promise<Wallet[]>;
getWallet(account: Account): Wallet;
@@ -26,16 +27,20 @@ abstract class AccountManager implements IAccountManager {
protected readonly chainId: number;
protected readonly whaleAccounts: Account[];
protected provider: Provider;
protected accountWallets: Wallet[];
protected accountWallets: NonceManager[];
private whaleAccountMutex: Mutex;
constructor(provider: Provider, whaleAccounts: Account[], chainId: number) {
this.provider = provider;
this.whaleAccounts = whaleAccounts;
this.chainId = chainId;
this.accountWallets = this.whaleAccounts.map((account) => getWallet(this.provider, account.privateKey));
this.accountWallets = this.whaleAccounts.map(
(account) => new NonceManager(getWallet(this.provider, account.privateKey)),
);
this.whaleAccountMutex = new Mutex();
}
selectWhaleAccount(accIndex?: number): { account: Account; accountWallet: Wallet } {
selectWhaleAccount(accIndex?: number): { account: Account; accountWallet: NonceManager } {
if (accIndex) {
return { account: this.whaleAccounts[accIndex], accountWallet: this.accountWallets[accIndex] };
}
@@ -48,20 +53,16 @@ abstract class AccountManager implements IAccountManager {
return { account: whaleAccount, accountWallet: whaleTxManager };
}
whaleAccount(accIndex?: number): Wallet {
whaleAccount(accIndex?: number): NonceManager {
return this.selectWhaleAccount(accIndex).accountWallet;
}
async generateAccount(initialBalanceWei = etherToWei("10")): Promise<Wallet> {
const accounts = await this.generateAccounts(1, initialBalanceWei);
return this.getWallet(accounts[0]);
return accounts[0];
}
async generateAccounts(
numberOfAccounts: number,
initialBalanceWei = etherToWei("10"),
retryDelayMs = 1_000,
): Promise<Wallet[]> {
async generateAccounts(numberOfAccounts: number, initialBalanceWei = etherToWei("10")): Promise<Wallet[]> {
const { account: whaleAccount, accountWallet: whaleAccountWallet } = this.selectWhaleAccount();
console.log(
@@ -69,6 +70,7 @@ abstract class AccountManager implements IAccountManager {
);
const accounts: Account[] = [];
const transactionResponses: TransactionResponse[] = [];
for (let i = 0; i < numberOfAccounts; i++) {
const randomBytes = ethers.randomBytes(32);
@@ -76,44 +78,36 @@ abstract class AccountManager implements IAccountManager {
const newAccount = new Account(randomPrivKey, ethers.computeAddress(randomPrivKey));
accounts.push(newAccount);
let success = false;
while (!success) {
try {
const tx = {
to: newAccount.address,
value: initialBalanceWei,
gasPrice: ethers.parseUnits("300", "gwei"),
gasLimit: 21000n,
};
const transactionResponse = await whaleAccountWallet.sendTransaction(tx);
console.log(
`Waiting for account funding: newAccount=${newAccount.address} txHash=${transactionResponse.hash} whaleAccount=${whaleAccount.address}`,
);
const receipt = await transactionResponse.wait();
const tx = {
to: newAccount.address,
value: initialBalanceWei,
gasPrice: ethers.parseUnits("300", "gwei"),
gasLimit: 21000n,
};
if (!receipt) {
throw new Error(`Transaction failed to be mined`);
}
if (receipt.status !== 1) {
throw new Error(`Transaction failed with status ${receipt.status}`);
}
console.log(
`Account funded: newAccount=${newAccount.address} balance=${(
await this.provider.getBalance(newAccount.address)
).toString()} wei`,
);
success = true;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.log(
`Failed to send funds from accAddress=${whaleAccount.address}. Retrying funding in ${retryDelayMs}ms...`,
);
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
}
const release = await this.whaleAccountMutex.acquire();
try {
const transactionResponse = await whaleAccountWallet.sendTransaction(tx);
console.log(
`Transaction sent: newAccount=${newAccount.address} txHash=${transactionResponse.hash} whaleAccount=${whaleAccount.address}`,
);
transactionResponses.push(transactionResponse);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.error(`Failed to fund account ${newAccount.address}: ${error.message}`);
whaleAccountWallet.reset();
} finally {
release();
}
}
return accounts.map((account) => getWallet(this.provider, account.privateKey));
await Promise.all(transactionResponses.map((tx) => tx.wait()));
console.log(
`Accounts funded: newAccounts=${accounts.map((account) => account.address).join(",")} balance=${initialBalanceWei.toString()} wei`,
);
return accounts.map((account) => this.getWallet(account));
}
getWallet(account: Account): Wallet {

View File

@@ -37,6 +37,7 @@ const config: Config = {
rpcUrl: L2_RPC_URL,
chainId: L2_CHAIN_ID,
l2MessageServiceAddress: "0x33bf916373159A8c1b54b025202517BfDbB7863D",
l2TestContractAddress: "",
accountManager: new EnvironmentBasedAccountManager(
new ethers.JsonRpcProvider(L2_RPC_URL.toString()),
L2_WHALE_ACCOUNTS,

View File

@@ -36,6 +36,7 @@ const config: Config = {
rpcUrl: L2_RPC_URL,
chainId: L2_CHAIN_ID,
l2MessageServiceAddress: "0x971e727e956690b9957be6d51Ec16E73AcAC83A7",
l2TestContractAddress: "",
accountManager: new EnvironmentBasedAccountManager(
new ethers.JsonRpcProvider(L2_RPC_URL.toString()),
L2_WHALE_ACCOUNTS,

View File

@@ -1,12 +1,12 @@
import { JsonRpcProvider, Wallet } from "ethers";
import { Config } from "./types";
import { AbstractSigner, JsonRpcProvider, Wallet } from "ethers";
import { Config, L2Config, LocalL2Config } from "./types";
import {
DummyContract,
DummyContract__factory,
L2MessageService,
L2MessageService__factory,
LineaRollup,
LineaRollup__factory,
LineaRollupV5,
LineaRollupV5__factory,
TestContract,
TestContract__factory,
} from "../../typechain";
@@ -24,19 +24,17 @@ export default class TestSetup {
}
public getL2SequencerProvider(): JsonRpcProvider | undefined {
if (this.config.L2.sequencerEndpoint) {
return new JsonRpcProvider(this.config.L2.sequencerEndpoint.toString());
} else {
if (!this.isLocalL2Config(this.config.L2)) {
return undefined;
}
return new JsonRpcProvider(this.config.L2.sequencerEndpoint.toString());
}
public getL2BesuNodeProvider(): JsonRpcProvider | undefined {
if (this.config.L2.besuNodeRpcUrl) {
return new JsonRpcProvider(this.config.L2.besuNodeRpcUrl.toString());
} else {
if (!this.isLocalL2Config(this.config.L2)) {
return undefined;
}
return new JsonRpcProvider(this.config.L2.besuNodeRpcUrl.toString());
}
public getL1ChainId(): number {
@@ -48,23 +46,35 @@ export default class TestSetup {
}
public getShomeiEndpoint(): URL | undefined {
if (!this.isLocalL2Config(this.config.L2)) {
return undefined;
}
return this.config.L2.shomeiEndpoint;
}
public getShomeiFrontendEndpoint(): URL | undefined {
if (!this.isLocalL2Config(this.config.L2)) {
return undefined;
}
return this.config.L2.shomeiFrontendEndpoint;
}
public getSequencerEndpoint(): URL | undefined {
if (!this.isLocalL2Config(this.config.L2)) {
return undefined;
}
return this.config.L2.sequencerEndpoint;
}
public getTransactionExclusionEndpoint(): URL | undefined {
if (!this.isLocalL2Config(this.config.L2)) {
return undefined;
}
return this.config.L2.transactionExclusionEndpoint;
}
public getLineaRollupContract(signer?: Wallet): LineaRollup {
const lineaRollup: LineaRollup = LineaRollup__factory.connect(
public getLineaRollupContract(signer?: AbstractSigner): LineaRollupV5 {
const lineaRollup: LineaRollupV5 = LineaRollupV5__factory.connect(
this.config.L1.lineaRollupAddress,
this.getL1Provider(),
);
@@ -130,4 +140,14 @@ export default class TestSetup {
public getL2AccountManager(): AccountManager {
return this.config.L2.accountManager;
}
private isLocalL2Config(config: L2Config): config is LocalL2Config {
return (
(config as LocalL2Config).besuNodeRpcUrl !== undefined &&
(config as LocalL2Config).sequencerEndpoint !== undefined &&
(config as LocalL2Config).shomeiEndpoint !== undefined &&
(config as LocalL2Config).shomeiFrontendEndpoint !== undefined &&
(config as LocalL2Config).transactionExclusionEndpoint !== undefined
);
}
}

View File

@@ -11,16 +11,25 @@ export type L1Config = BaseConfig & {
lineaRollupAddress: string;
};
export type L2Config = BaseConfig & {
export type BaseL2Config = BaseConfig & {
l2MessageServiceAddress: string;
l2TestContractAddress?: string;
besuNodeRpcUrl?: URL;
shomeiEndpoint?: URL;
shomeiFrontendEndpoint?: URL;
sequencerEndpoint?: URL;
transactionExclusionEndpoint?: URL;
l2TestContractAddress: string;
};
export type LocalL2Config = BaseL2Config & {
besuNodeRpcUrl: URL;
shomeiEndpoint: URL;
shomeiFrontendEndpoint: URL;
sequencerEndpoint: URL;
transactionExclusionEndpoint: URL;
};
export type DevL2Config = BaseL2Config;
export type SepoliaL2Config = BaseL2Config;
export type L2Config = LocalL2Config | DevL2Config | SepoliaL2Config;
export type Config = {
L1: L1Config;
L2: L2Config;

View File

@@ -32,6 +32,8 @@ async function waitForCoordinatorRestart() {
}
}
const l1AccountManager = config.getL1AccountManager();
describe("Coordinator restart test suite", () => {
it.concurrent(
"When the coordinator restarts it should resume blob submission and finalization",
@@ -101,7 +103,7 @@ describe("Coordinator restart test suite", () => {
}
const l1Provider = config.getL1Provider();
const l1MessageSender = await config.getL1AccountManager().generateAccount();
const l1MessageSender = await l1AccountManager.generateAccount();
const lineaRollup = config.getLineaRollupContract();
const l2MessageService = config.getL2MessageServiceContract();

View File

@@ -1,4 +1,5 @@
import { describe, expect, it } from "@jest/globals";
import { NonceManager } from "ethers";
import {
getMessageSentEventFromLogs,
sendMessage,
@@ -8,7 +9,8 @@ import {
etherToWei,
} from "./common/utils";
import { config } from "./config/tests-config";
import { LineaRollup } from "./typechain";
const l1AccountManager = config.getL1AccountManager();
describe("Submission and finalization test suite", () => {
const sendMessages = async () => {
@@ -16,18 +18,13 @@ describe("Submission and finalization test suite", () => {
const messageValue = etherToWei("0.0051");
const destinationAddress = "0x8D97689C9818892B700e27F316cc3E41e17fBeb9";
const l1MessageSender = await config.getL1AccountManager().generateAccount();
const l1MessageSender = new NonceManager(await l1AccountManager.generateAccount());
const lineaRollup = config.getLineaRollupContract();
console.log("Sending messages on L1");
// Send L1 messages
const l1MessagesPromises = [];
// eslint-disable-next-line prefer-const
let [l1MessageSenderNonce, { maxPriorityFeePerGas, maxFeePerGas }] = await Promise.all([
config.getL1Provider().getTransactionCount(l1MessageSender.address),
config.getL1Provider().getFeeData(),
]);
for (let i = 0; i < 5; i++) {
l1MessagesPromises.push(
@@ -41,13 +38,9 @@ describe("Submission and finalization test suite", () => {
},
{
value: messageValue,
nonce: l1MessageSenderNonce,
maxPriorityFeePerGas,
maxFeePerGas,
},
),
);
l1MessageSenderNonce++;
}
const l1Receipts = await Promise.all(l1MessagesPromises);
@@ -60,22 +53,6 @@ describe("Submission and finalization test suite", () => {
return { l1Messages, l1Receipts };
};
async function getFinalizedL2BlockNumber(lineaRollup: LineaRollup) {
let blockNumber = null;
while (!blockNumber) {
try {
blockNumber = await lineaRollup.currentL2BlockNumber({ blockTag: "finalized" });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (error: any) {
console.log("No finalized block yet, retrying in 5 seconds...");
await new Promise((resolve) => setTimeout(resolve, 5_000));
}
}
return blockNumber;
}
it.concurrent(
"Check L2 anchoring",
async () => {
@@ -152,21 +129,20 @@ describe("Submission and finalization test suite", () => {
it.concurrent(
"Check L2 safe/finalized tag update on sequencer",
async () => {
const lineaRollup = config.getLineaRollupContract();
const sequencerEndpoint = config.getSequencerEndpoint();
if (!sequencerEndpoint) {
console.log('Skipped the "Check L2 safe/finalized tag update on sequencer" test');
return;
}
const lastFinalizedL2BlockNumberOnL1 = (await getFinalizedL2BlockNumber(lineaRollup)).toString();
const lastFinalizedL2BlockNumberOnL1 = 0;
console.log(`lastFinalizedL2BlockNumberOnL1=${lastFinalizedL2BlockNumberOnL1}`);
let safeL2BlockNumber = -1,
finalizedL2BlockNumber = -1;
while (
safeL2BlockNumber < parseInt(lastFinalizedL2BlockNumberOnL1) ||
finalizedL2BlockNumber < parseInt(lastFinalizedL2BlockNumberOnL1)
safeL2BlockNumber < lastFinalizedL2BlockNumberOnL1 ||
finalizedL2BlockNumber < lastFinalizedL2BlockNumberOnL1
) {
safeL2BlockNumber = (await getBlockByNumberOrBlockTag(sequencerEndpoint, "safe"))?.number || safeL2BlockNumber;
finalizedL2BlockNumber =
@@ -176,8 +152,8 @@ describe("Submission and finalization test suite", () => {
console.log(`safeL2BlockNumber=${safeL2BlockNumber} finalizedL2BlockNumber=${finalizedL2BlockNumber}`);
expect(safeL2BlockNumber).toBeGreaterThanOrEqual(parseInt(lastFinalizedL2BlockNumberOnL1));
expect(finalizedL2BlockNumber).toBeGreaterThanOrEqual(parseInt(lastFinalizedL2BlockNumberOnL1));
expect(safeL2BlockNumber).toBeGreaterThanOrEqual(lastFinalizedL2BlockNumberOnL1);
expect(finalizedL2BlockNumber).toBeGreaterThanOrEqual(lastFinalizedL2BlockNumberOnL1);
console.log("L2 safe/finalized tag update on sequencer done.");
},

View File

@@ -9,12 +9,13 @@ describe("Transaction exclusion test suite", () => {
it.concurrent(
"Should get the status of the rejected transaction reported from Besu RPC node",
async () => {
expect(config.getTransactionExclusionEndpoint()).toBeDefined();
const transactionExclusionEndpoint = config.getTransactionExclusionEndpoint();
expect(transactionExclusionEndpoint).toBeDefined();
const transactionExclusionClient = new TransactionExclusionClient(config.getTransactionExclusionEndpoint()!!);
const transactionExclusionClient = new TransactionExclusionClient(transactionExclusionEndpoint!);
const l2Account = await l2AccountManager.generateAccount();
const l2AccountLocal = getWallet(l2Account.privateKey, config.getL2BesuNodeProvider()!!);
const testContract = config.getL2TestContract(l2AccountLocal)!!;
const l2AccountLocal = getWallet(l2Account.privateKey, config.getL2BesuNodeProvider()!);
const testContract = config.getL2TestContract(l2AccountLocal)!;
// This shall be rejected by the Besu node due to traces module limit overflow
let rejectedTxHash;
@@ -51,13 +52,13 @@ describe("Transaction exclusion test suite", () => {
it.skip("Should get the status of the rejected transaction reported from Besu SEQUENCER node", async () => {
expect(config.getTransactionExclusionEndpoint()).toBeDefined();
const transactionExclusionClient = new TransactionExclusionClient(config.getTransactionExclusionEndpoint()!!);
const transactionExclusionClient = new TransactionExclusionClient(config.getTransactionExclusionEndpoint()!);
const l2Account = await l2AccountManager.generateAccount();
const l2AccountLocal = getWallet(l2Account.privateKey, config.getL2SequencerProvider()!!);
const l2AccountLocal = getWallet(l2Account.privateKey, config.getL2SequencerProvider()!);
const testContract = config.getL2TestContract(l2AccountLocal);
// This shall be rejected by sequencer due to traces module limit overflow
const tx = await testContract!!.connect(l2AccountLocal).testAddmod(13000, 31);
const tx = await testContract!.connect(l2AccountLocal).testAddmod(13000, 31);
const rejectedTxHash = tx.hash;
console.log(`rejectedTxHash (SEQUENCER): ${rejectedTxHash}`);