[Feat] 191 improve documentation (#316)

* initial changes for the contract readme

* testing guidelines wip

* add contract documentation

* add note on future deprecation

* add memory and CPU requirements for docker

* add audit references to documentation

* use tokenbridge make commands in documentation

* add additional comments to testing guidelines

* define contract style guide and link it

* address PR comments with better documentation

* document tweaks and traffic generation script

* catch error on failure of main()

* add precompute script and readme documentation

* use ethers address generation

---------

Co-authored-by: count-sum <andrei.alexandru@consensys.net>
This commit is contained in:
The Dark Jester
2024-11-22 17:53:15 +00:00
committed by GitHub
parent 86616e6136
commit 98291b5c4b
8 changed files with 431 additions and 40 deletions

View File

@@ -163,10 +163,6 @@ restart-shomei:
rm -rf tmp/local/shomei/*
docker compose -f docker/compose.yml -f docker/compose-local-dev.overrides.yml up zkbesu-shomei shomei -d
fresh-start-all-smc-v4:
make clean-environment
make start-all-smc-v4
fresh-start-all:
make clean-environment
make start-all
@@ -182,6 +178,7 @@ start-all:
start-all-traces-v2:
L1_GENESIS_TIME=$(get_future_time) make start-whole-environment-traces-v2
make deploy-contracts
deploy-contracts:
cd contracts/; \
export L1_NONCE=$$(npx ts-node local-deployments-artifacts/get-wallet-nonce.ts --wallet-priv-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --rpc-url http://localhost:8445) && \

View File

@@ -1,66 +1,154 @@
Readme.md
# Smart Contracts
# Smart Contract
Contains Ethereum smart contract code for the Linea Rollup and Message Service.
Contains Ethereum smart contract code for ConsenSys Rollups.
## LineaRollup (L1MessageService)
The Linea Rollup, which contains the L1MessageService, is the smart contract that is responsible for:
- Submitting messages to be sent to Linea (L2) for later claiming.
- Anchoring of L2 message Merkle roots to allow later claiming.
- Claiming of messages sent from L2 to Ethereum mainnet (L1).
- Submission of L2 compressed data using EIP-4844 blobs or via calldata.
- Finalization of L2 state on L1 using a Zero Knowledge Proof.
## L2MessageService
The L2MessageService is the L2 smart contract that is responsible for:
- Submitting messages to be sent to L1 for later claiming.
- Anchoring of L1 to L2 Message hashes for later claiming.
- Claiming of messages sent from L1 to L2.
## Linea Canonical Token Bridge
The Canonical Token Bridge (TokenBridge) is a canonical ERC20 token brige between Ethereum and Linea networks.
The TokenBridge utilises the L1MessageService and the L2MessageService for the transmission of messages between each layer's TokenBridge.
Documentation: [Token Bridge](./docs/linea-token-bridge.md)
# Style Guide
Please see the [Smart Contract Style Guide](./docs/contract-style-guide.md) for in depth smart contract layout and styling.
# Audit reports
Please see [Audits](./docs/audits.md) for a historical list of all the smart contract audits.
# Development & Testing
This project uses following libraries
Please see [Testing guidelines](./test/README.md) for in depth testing layout and styling.
This project uses the following libraries
- [PNPM](https://pnpm.io/) as the Package Manager
- [Ethers](https://github.com/ethers-io/ethers.js/) as Ethereum library
- [Hardhat](https://hardhat.org/getting-started/) as development environment
- [Chai](https://www.chaijs.com/) for assertions
- [GoLang](https://go.dev/) for the compilation of code to autogenerate data for L2 data and proofs (not strictly required)
- [Docker](https://www.docker.com/) for the local stack to run in
If you already have an understanding of the tech stack, use our [Get Started](../docs/get-started.md) guide.
To run the tests:
```bash
make test
```
# Useful scripts
Most of the scripts need to know address of Ethereum RPC. This is controlled via `BLOCKCHAIN_NODE` environment variable,
for example run this before all the scripts in the same terminal:
## Testing without coverage
```bash
export BLOCKCHAIN_NODE=http://localhost:5000
cd contracts # from the root folder
pnpm install
npx hardhat test
```
## Balance of ERC 20 token
## Testing with coverage
```bash
cd contracts # from the root folder
pnpm install
npx hardhat coverage
```
## Deploying the contracts to the local stack
Prerequisites:
- Be sure Docker is running.
Some caveats:
- The L2 chain will not produce empty blocks if there are no transactions, so it would be useful to execute a script to keep the chain "moving".
- The following script can be run with the expectation the local stack is running: [generateL2Traffic.ts](../e2e/src/common/generateL2Traffic.ts)
- To execute it run the following from the `e2e` folder: `npx ts-node src/common/generateL2Traffic.ts`
- For blob submission and finalization, there needs to be sufficient blocks to trigger it. Keeping the chain moving on L2 is vital for this to take place.
From the root of the repository:
Please read the MakeFile: [MakeFile](../Makefile)
```
export BLOCKCHAIN_NODE="http://localhost:8545"
ts-node scripts/balanceOf.ts \
data/rollup.json \
../node-data/test/keys/eth_account_3.acc \
1 \
../node-data/test/keys/eth_account_3.acc \
../node-data/test/keys/eth_account_4.acc \
../node-data/test/keys/eth_account_5.acc
# This will deploy all the relevant services and smart contracts
make fresh-start-all-traces-v2
```
### To deploy ZkEvm to local docker compose
### To deploy all the contracts
Run in ./contracts with running docker-compose stack.
If the stack is *already running*, to redeploy the contracts, the following commands can be used:
```shell
sed "s/BLOCKCHAIN_NODE=.*/BLOCKCHAIN_NODE=http:\/\/localhost:8445/" .env.template > .env
npx hardhat run ./scripts/deployment/deployZkEVM.ts --network zkevm_dev
Note: The addresses change per deployment due to nonce increments, so be sure to validate the correct ones are being used.
**NB:** The end to end tests run against a fresh stack and deploy with predetermined addresses.
If there is a need to get predetermined addresses for contract deployments, the following script can be used [precomputeDeployedAddresses.ts](./scripts/operational/precomputeDeployedAddress.ts).
This can be used by altering the values in the script file and running the script (from the `/contracts` folder) with: `npx ts-node scripts/operational/precomputeDeployedAddress.ts`
*Note the following nonce values for a fresh stack deploy:*
The LineaRollup deploy uses nonce 3 as the following are deployed beforehand:
- The verifier contract
- The implementation LineaRollup.sol contract
- The proxy admin contract
The L2MessageService deploy uses nonce 2 as the following are deployed beforehand:
- The implementation L2MessageService.sol contract
- The proxy admin contract
**Deploying the L1 contracts**
```
# This will deploy the Linea Rollup that is currently deployed on Mainnet - the current version is the LineaRollupV5.
# Some end to end tests will test future upgrades to validate the stack remains functional.
# Note: By default a test/placeholder verifier contract is used `IntegrationTestTrueVerifier` if you wish to use a proper verifier, adjust the
# PLONKVERIFIER_NAME=IntegrationTestTrueVerifier in the make command to be something like PLONKVERIFIER_NAME=PlonkVerifierForDataAggregation .
# Be sure to check the parameter values in the Makefile before executing the command.
# Deploy v5
make deploy-linea-rollup-v5
# Or deploy v6
make deploy-linea-rollup-v6
make deploy-token-bridge-l1
```
### To deploy ZkEvm to local docker compose
**Deploying the L2 contracts**
```
# This will deploy the current L2 Message Service.
# Some end to end tests will test future upgrades to validate the stack remains functional.
Run in ./contracts with running docker-compose stack.
make deploy-l2messageservice
```shell
sed "s/BLOCKCHAIN_NODE=.*/BLOCKCHAIN_NODE=http:\/\/localhost:8445/" .env.template > .env
npx hardhat run ./scripts/deployment/deployZkEVM.ts --network zkevm_dev
make deploy-token-bridge-l2
```
## Linea Token Bridge
**Deploying L1 and L2 together**
```
make deploy-contracts
```
Token Bridge is a canonical brige between Ethereum and Linea networks.
The above command will trigger the following commands to deploy:
Documentation: [./docs/linea-token-bridge.md](./docs/linea-token-bridge.md)
- deploy-linea-rollup-v5
- deploy-token-bridge-l1
- deploy-l1-test-erc20
- deploy-l2messageservice
- deploy-token-bridge-l2
- deploy-l2-test-erc20
Note: the deploy-l1-test-erc20 and deploy-l1-test-erc20 commands are executed for use in the end to end tests.

56
contracts/docs/audits.md Normal file
View File

@@ -0,0 +1,56 @@
# Audits
## Fourth Audit Round (Latest)
**Diligence**
- Differential audit since second audit round: https://consensys.io/diligence/audits/2024/07/linea-rollup-update/
**Open Zeppelin**
- Gas optimization audit: https://blog.openzeppelin.com/linea-gas-optimizations-audit
**Cyfrin**
- Full codebase audit including gas optimizations and TokenBridge updates: https://github.com/Cyfrin/cyfrin-audit-reports/blob/main/reports/2024-05-24-cyfrin-linea-v2.0.pdf
## Third Audit Round
**Open Zeppelin**
- Blob submission audit: https://blog.openzeppelin.com/linea-blob-submission-audit
## Second Audit Round
**Diligence**
- Proof aggregation, data compression and message service updates Audit: https://consensys.io/diligence/audits/2024/01/linea-contracts-update/
**Open Zeppelin**
- Proof aggregation, data compression and message service updates Audit: https://blog.openzeppelin.com/linea-v2-audit
## First Audit Round
**Diligence**
- Plonk Verifier: https://consensys.io/diligence/audits/2023/06/linea-plonk-verifier/
- Message Service & Rollup: https://consensys.io/diligence/audits/2023/06/linea-message-service/
- Canonical Token Bridge: https://consensys.io/diligence/audits/2023/06/linea-canonical-token-bridge/
**Open Zeppelin**
- Linea Bridge Audit: https://blog.openzeppelin.com/linea-bridge-audit-1
- Linea Verifier Audit: https://blog.openzeppelin.com/linea-verifier-audit-1
---
## Installation and testing
To run the solution's tests, coverage and gas reporting, be sure to install pnpm and then
```
# Install all the dependencies
pnpm install
pnpm run test
pnpm run test:reportgas
pnpm run coverage
```

View File

@@ -0,0 +1,110 @@
# Smart Contract Style Guide
The following document serves as the expected style guide for the Linea smart contracts:
## Licenses
- All interfaces will use `// SPDX-License-Identifier: Apache-2.0` for others to potentially consume
- All contracts other than specific ones will use `// SPDX-License-Identifier: AGPL-3.0`
## Imports
All imports should be in the format of:
```
import { ImportType } from "../ImportType.sol";
```
## NatSpec
Contracts and interfaces will use the [NatSpec](https://docs.soliditylang.org/en/develop/natspec-format.html) formatting.
**Note:** Interfaces and their implementations have duplicated NatSpec because consumers might just use the interface, and block explorers might use either the interface or implementation for the documentation. The documentation should always be available.
- use `DEPRECATED` in the NatSpec for deprecated variables, errors, events and functions if they need to remain
## Visibility
- CONSTANTS should be internal unless there is an explicit reason for it to be public
- External and public functions should be limited
- If there is a function calling itself using `this.` or a function is made public to do this, reconsider the design and refactor.
## Naming
- Public state variables are `camelCase`
- Internal and private state variables are `_camelCase` starting with the `_`
- Mappings contain key and value descriptors e.g. `mapping(uint256 id=>bytes32 messageHash)`
- CONSTANTS are all in upper case separated by `_` e.g. `DEFAULT_MESSAGE_STATUS`
- Public and External function names are `camelCase` - e.g. `function hashMessage(uint256 _messageNumber) external {}`
- Internal and Private function names are `_camelCase` starting with the `_` - e.g. `function _calculateY() internal`
- All function parameters start with an `_` e.g. `function hashMessage(uint256 _messageNumber) external {}`
- Return variables should be named and are `camelCase`
- Inherited contract initialization functions should be named `__ContractName_init`. e.g. `__PauseManager_init`
## General
- Avoid magic numbers by using constants
- Name variables so that their intent is easy to understand
- In assembly memory mappings use hexidecimal values for memory offsets - e.g `mstore(add(mPtr, 0x20), _varName)`
## Linting
Be sure to run `pnpm run lint:fix` in the contracts folder or `pnpm run -F contracts lint:fix` from the repository root.
## File layout
### Interface Structure
All interfaces should be laid out in the following format from top to bottom:
```
// SPDX-License-Identifier: Apache-2.0
pragma solidity >=0.8.19 <=0.8.26;
// imports here
import { ImportType } from "../ImportType.sol";
/**
* @title Title explaining interface contents.
* @author Author here.
* @custom:security-contact security-report@linea.build
*/
interface ISampleContract {
// All items have NatSpec
// 1. Structs
// 2. Enums
// 3. Events with NatSpec (including parameters)
// 4. Errors with NatSpec explaining when thrown
// 5. External Functions
}
```
### Library Structure
All libraries should be laid out in the following format from top to bottom:
```
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.19 <=0.8.26;
// imports here
import { ImportType } from "../ImportType.sol";
library SampleLibrary {
// All items have NatSpec
// 1. CONSTANTS (Public, internal and then private)
// 2. Structs
// 3. Enums
// 4. Events with NatSpec (including parameters)
// 5. Errors with NatSpec explaining when thrown
// 6. Modifiers
// 7. Functions (Public, external, internal and then private)
}
```
### Contract Structure
All contracts should be laid out in the following format from top to bottom:
```
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.19 <=0.8.26;
contract SampleContract {
// All items have NatSpec
// 1. CONSTANTS (Public, internal and then private)
// 2. Structs
// 3. Enums
// 4. Events with NatSpec (including parameters)
// 5. Errors with NatSpec explaining when thrown
// 6. Modifiers
// 7. Functions (Public, external, internal and then private)
}
```

View File

@@ -0,0 +1,7 @@
import { ethers } from "ethers";
const from = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; // Replace with your deployer address
const nonce = 3; // Replace with the actual nonce
const computedAddress = ethers.getCreateAddress({ from, nonce });
console.log("Computed Address:", computedAddress);

99
contracts/test/README.md Normal file
View File

@@ -0,0 +1,99 @@
# Smart Contract Testing Guidelines
The following document serves to be a guide on the best practices for the Linea smart contract testing codebase.
**Note:** some areas might not conform to the practices - feel free to open a PR to have them comply. Work is constantly being done to improve.
The current supported framework is Hardhat and TypeScript testing. Future improvements will include Foundry.
## Folder Structure and Naming Conventions
In order to make it easy to navigate between the smart contracts themselves and the tests, please keep to the following:
### Folders
- Maintain a 1:1 structure with the contract directory for ease of reference.
- Folder names are camelCase unless they are the contract name or contract behavior which is TitleCase.
```
# Contracts
/contracts/contracts/messageService
# Tests
/contracts/test/messageService
/contracts/test/LineaRollup/Finalization.ts
```
- All common or shared utilities and helpers that are test specific should be placed in `/contracts/test/common/`.
- All common or shared utilities and helpers that are specific across the contracts (e.g. deployment scripts) should be placed in `/contracts/common/`.
### Test Files
- Maintain a 1:1 structure with the contract directory for ease of reference.
Example:
```plaintext
./messageService/l1/L1MessageManager.ts
```
- If a contract is complex and requires multiple files to simplify, create a subfolder with individual test files representing behavior.
Example:
```plaintext
./LineaRollup/Finalization.ts
./LineaRollup/BlobSubmission.ts
./LineaRollup/CalldataDataSubmission.ts
./LineaRollup/PermissionsOrOtherThings.ts
```
- Contract-specific or feature-specific helper or utility functions should be in a separate file within a child folder named `helpers/contractName.ts`.
Example:
```plaintext
./LineaRollup/Finalization.ts
./LineaRollup/helpers/finalization.ts
./LineaRollup/helpers/blobSubmission.ts
```
### Utilities
- Common functions and helper files should be defined by functionality that is not specific to any given contract.
- Example: test assertions, hashing, and general framework behavior.
- Each helper file should contain functionality with a single reason to change (e.g. hashing, timing, encoding).
- File naming convention should describe the whole functionality using adverbial language (e.g. hashing).
## Test Layout
Within the test file itself, organize tests by contract name, external calls, behavior, starting with initialization/deployments, upgrades, failure tests followed by success tests. Following this order provides the following benefits:
1. Splitting by external call shows the exact contract entry points and makes permission checks easier to isolate.
2. It is easy to easily read the expected contract behavior.
3. Finding missing cases should be simpler.
4. Knowing where you expect reverts or expected permissions coming first helps to not miss/forget those scenarios.
### Describe
- Contract name (e.g., `Rate Limiter`).
- External call (e.g., `When initializing`).
- Expected behavior (if there are a few subcategories of behavior, this could be broken down further as well).
- Failure tests first. (e.g., `Should revert if limit is zero`).
- Tests should follow the order of code paths (failure ordering for ease of code reading).
- Success tests last. (e.g., `Should have values set`).
## Additional Guidelines
### Ethers Wrapping/Abstractions
- Ensure proper wrapping and abstraction using Ethers.js. Ideally Ethers should be in the common helpers/constants files and
### Solidity Test Contracts
- Use Solidity test contracts where necessary to set required state to simplify testing.
### Event Testing
- Test events, including expected arguments.
- Use the wrapped helper functions e.g. `expectEvent`
### Error Testing
- Test errors, including expected arguments.
- Use the wrapped helper functions e.g. `expectRevertWithCustomError`
### Scenario Building Pre-Testing
- Ideally build the scenarios in the test files without actual tests to ensure comprehensive coverage and ease of reading.
### Coverage
- Ensure high test coverage for all contracts. (ideally 100% - only some impossible test cases are allowed)
### Storage Layout and Upgrade Automated Testing
- Implement automated testing for storage layout and upgrades.

View File

@@ -4,6 +4,7 @@
- Node.js v20 or higher
- Docker v24 or higher
- Docker should ideally have ~16GB of Memory and 4+ CPUs to run the entire stack.
- Docker Compose version v2.19+
- Make v3.81+
- Pnpm >=v9.12.2 (https://pnpm.io/installation)

View File

@@ -0,0 +1,33 @@
import { config } from "./../config/tests-config";
import { etherToWei, sendTransactionsToGenerateTrafficWithInterval } from "./utils";
import * as dotenv from "dotenv";
dotenv.config();
async function main() {
console.log("Generating L2 traffic...");
const pollingAccount = await config.getL2AccountManager().generateAccount(etherToWei("200"));
const stopPolling = await sendTransactionsToGenerateTrafficWithInterval(pollingAccount, 2_500);
process.on("SIGINT", () => {
console.log("Caught interrupt signal.");
cleanup();
});
process.on("SIGTERM", () => {
console.log("Caught termination signal.");
cleanup();
});
function cleanup() {
stopPolling();
console.log("Terminated L2 traffic...");
process.exit(0);
}
}
main().catch((error) => {
console.error(error);
process.exit(1);
});