Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(l2): don't recompute transaction senders when building blocks #2097

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.PHONY: build lint test clean run-image build-image clean-vectors \
setup-hive test-pattern-default run-hive run-hive-debug clean-hive-logs loc-detailed \
loc-compare-detailed
loc-compare-detailed load-test-fibonacci load-test-io

help: ## 📚 Show help for each of the Makefile recipes
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
Expand Down Expand Up @@ -193,16 +193,14 @@ start-node-with-flamegraph: rm-test-db ## 🚀🔥 Starts an ethrex client used
--dev \
--datadir test_ethrex

load-node: install-cli ## 🚧 Runs a load-test. Run make start-node-with-flamegraph and in a new terminal make load-node
@if [ -z "$$C" ]; then \
CONTRACT_INTERACTION=""; \
echo "Running the load-test without contract interaction"; \
echo "If you want to interact with contracts to load the evm, run the target with a C at the end: make <target> C=1"; \
else \
CONTRACT_INTERACTION="-c"; \
echo "Running the load-test with contract interaction"; \
fi; \
ethrex_l2 test load --path test_data/private_keys.txt -i 1000 -v --value 100000 $$CONTRACT_INTERACTION
load-test: install-cli ## 🚧 Runs a load-test. Run make start-node-with-flamegraph and in a new terminal make load-node
ethrex_l2 test load --path test_data/private_keys.txt -i 1000 -v --value 100000

load-test-fibonacci:
ethrex_l2 test load --path test_data/private_keys.txt -i 1000 -v --value 100000 --fibonacci

load-test-io:
ethrex_l2 test load --path test_data/private_keys.txt -i 1000 -v --value 100000 --io

rm-test-db: ## 🛑 Removes the DB used by the ethrex client used for testing
sudo cargo run --release --bin ethrex -- removedb --datadir test_ethrex
Expand Down
34 changes: 27 additions & 7 deletions cmd/ethrex_l2/src/commands/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,13 @@ pub(crate) enum Command {
)]
verbose: bool,
#[clap(
short = 'c',
long = "contract",
long = "fibonacci",
default_value = "false",
help = "send value to address with contract"
help = "Run fibonacci load test"
)]
contract: bool,
fibonacci: bool,
#[clap(long = "io", default_value = "false", help = "Run I/O-heavy load test")]
i_o_heavy: bool,
},
}

Expand Down Expand Up @@ -116,7 +117,7 @@ async fn transfer_from(
},
max_fee_per_gas: Some(3121115334),
max_priority_fee_per_gas: Some(3000000000),
gas_limit: Some(TX_GAS_COST * 5),
gas_limit: Some(TX_GAS_COST * 100),
..Default::default()
},
10,
Expand Down Expand Up @@ -163,7 +164,8 @@ impl Command {
value,
iterations,
verbose,
contract,
fibonacci,
i_o_heavy,
} => {
let Ok(lines) = read_lines(path) else {
return Ok(());
Expand All @@ -178,7 +180,7 @@ impl Command {
None => Address::random(),
};

let calldata: Bytes = if contract {
let calldata: Bytes = if fibonacci {
// This is the bytecode for the contract with the following functions
// version() -> always returns 2
// function fibonacci(uint n) public pure returns (uint) -> returns the nth fib number
Expand All @@ -201,6 +203,24 @@ impl Command {
&[Value::Uint(100000000000000_u64.into())],
)?
.into()
} else if i_o_heavy {
// Contract with a function that touches 100 storage slots on every transaction.
// See `test_data/IOHeavyContract.sol` for the code.
let init_code = hex::decode("6080604052348015600e575f5ffd5b505f5f90505b6064811015603e57805f8260648110602d57602c6043565b5b018190555080806001019150506014565b506070565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6102728061007d5f395ff3fe608060405234801561000f575f5ffd5b506004361061003f575f3560e01c8063431aabc21461004357806358faa02f1461007357806362f8e72a1461007d575b5f5ffd5b61005d6004803603810190610058919061015c565b61009b565b60405161006a9190610196565b60405180910390f35b61007b6100b3565b005b61008561010a565b6040516100929190610196565b60405180910390f35b5f81606481106100a9575f80fd5b015f915090505481565b5f5f90505b60648110156101075760015f82606481106100d6576100d56101af565b5b01546100e29190610209565b5f82606481106100f5576100f46101af565b5b018190555080806001019150506100b8565b50565b5f5f5f6064811061011e5761011d6101af565b5b0154905090565b5f5ffd5b5f819050919050565b61013b81610129565b8114610145575f5ffd5b50565b5f8135905061015681610132565b92915050565b5f6020828403121561017157610170610125565b5b5f61017e84828501610148565b91505092915050565b61019081610129565b82525050565b5f6020820190506101a95f830184610187565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61021382610129565b915061021e83610129565b9250828201905080821115610236576102356101dc565b5b9291505056fea264697066735822122055f6d7149afdb56c745a203d432710eaa25a8ccdb030503fb970bf1c964ac03264736f6c634300081b0033")?;
let client = EthClient::new(&cfg.network.l2_rpc_url);

let (_, contract_address) = client
.deploy(
cfg.wallet.address,
cfg.wallet.private_key,
init_code.into(),
Overrides::default(),
)
.await?;

to_address = contract_address;

calldata::encode_calldata("incrementNumbers()", &[])?.into()
} else {
Bytes::new()
};
Expand Down
9 changes: 6 additions & 3 deletions crates/blockchain/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ impl Blockchain {
metrics!(METRICS_TX.inc_tx());

// Execute tx
let receipt = match self.apply_transaction(&head_tx, context) {
let receipt = match self.apply_transaction(&head_tx, context, head_tx.tx.sender()) {
Ok(receipt) => {
txs.shift()?;
// Pull transaction from the mempool
Expand Down Expand Up @@ -455,10 +455,11 @@ impl Blockchain {
&self,
head: &HeadTransaction,
context: &mut PayloadBuildContext,
sender: Address
) -> Result<Receipt, ChainError> {
match **head {
Transaction::EIP4844Transaction(_) => self.apply_blob_transaction(head, context),
_ => self.apply_plain_transaction(head, context),
_ => self.apply_plain_transaction(head, context, sender),
}
}

Expand Down Expand Up @@ -491,7 +492,7 @@ impl Blockchain {
return Err(EvmError::Custom("max data blobs reached".to_string()).into());
};
// Apply transaction
let receipt = self.apply_plain_transaction(head, context)?;
let receipt = self.apply_plain_transaction(head, context, head.tx.sender())?;
// Update context with blob data
let prev_blob_gas = context.payload.header.blob_gas_used.unwrap_or_default();
context.payload.header.blob_gas_used =
Expand All @@ -505,6 +506,7 @@ impl Blockchain {
&self,
head: &HeadTransaction,
context: &mut PayloadBuildContext,
sender: Address,
) -> Result<Receipt, ChainError> {
let chain_config = context.chain_config()?;
let (report, gas_used) = self.vm.execute_tx(
Expand All @@ -514,6 +516,7 @@ impl Blockchain {
&mut context.block_cache,
&chain_config,
&mut context.remaining_gas,
sender
)?;
context.block_value += U256::from(gas_used) * head.tip;
Ok(report)
Expand Down
20 changes: 19 additions & 1 deletion crates/l2/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,25 @@ Configuration is done through env vars. A detailed list is available in each par

## Testing

Load tests are available via L2 CLI. The test take a list of private keys and send a bunch of transactions from each of them to some address.
Load tests are available via L2 CLI and Makefile targets.

### Makefile

There are currently three different load tests you can run:

```
make load-test
make load-test-fibonacci
make load-test-io
```

The first one sends regular transfers between accounts, the second runs an EVM-heavy contract that computes fibonacci numbers, the third a heavy IO contract that writes to 100 storage slots per transaction.

### CLI

To have more control over the load tests and its parameters, you can use the CLI (the Makefile targets use the CLI underneath).

The tests take a list of private keys and send a bunch of transactions from each of them to some address (either the address of some account to send eth to or the address of the contract that we're interacting with).

The CLI can be installed with the `cli` target:

Expand Down
2 changes: 2 additions & 0 deletions crates/vm/backends/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ impl EVM {
block_cache: &mut CacheDB,
chain_config: &ChainConfig,
remaining_gas: &mut u64,
sender: Address
) -> Result<(Receipt, u64), EvmError> {
match self {
EVM::REVM => {
Expand All @@ -75,6 +76,7 @@ impl EVM {
block_header,
state,
spec_id(chain_config, block_header.timestamp),
sender
)?;

*remaining_gas = remaining_gas.saturating_sub(execution_result.gas_used());
Expand Down
9 changes: 5 additions & 4 deletions crates/vm/backends/revm_b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl REVM {
let mut cumulative_gas_used = 0;

for tx in block.body.transactions.iter() {
let result = Self::execute_tx(tx, block_header, state, spec_id)?;
let result = Self::execute_tx(tx, block_header, state, spec_id, tx.sender())?;
cumulative_gas_used += result.gas_used();
let receipt = Receipt::new(
tx.tx_type(),
Expand Down Expand Up @@ -105,9 +105,10 @@ impl REVM {
header: &BlockHeader,
state: &mut EvmState,
spec_id: SpecId,
sender: Address
) -> Result<ExecutionResult, EvmError> {
let block_env = block_env(header, spec_id);
let tx_env = tx_env(tx);
let tx_env = tx_env(tx, sender);
run_evm(tx_env, block_env, state, spec_id)
}

Expand Down Expand Up @@ -374,14 +375,14 @@ pub fn block_env(header: &BlockHeader, spec_id: SpecId) -> BlockEnv {

// Used for the L2
pub const DEPOSIT_MAGIC_DATA: &[u8] = b"mint";
pub fn tx_env(tx: &Transaction) -> TxEnv {
pub fn tx_env(tx: &Transaction, sender: Address) -> TxEnv {
let max_fee_per_blob_gas = tx
.max_fee_per_blob_gas()
.map(|x| RevmU256::from_be_bytes(x.to_big_endian()));
TxEnv {
caller: match tx {
Transaction::PrivilegedL2Transaction(_tx) => RevmAddress::ZERO,
_ => RevmAddress(tx.sender().0.into()),
_ => RevmAddress(sender.0.into()),
},
gas_limit: tx.gas_limit(),
gas_price: RevmU256::from(tx.gas_price()),
Expand Down
2 changes: 1 addition & 1 deletion crates/vm/execution_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl ExecutionDB {
let block_env = block_env(&block.header, spec_id);

for transaction in &block.body.transactions {
let tx_env = tx_env(transaction);
let tx_env = tx_env(transaction, transaction.sender());

// execute tx
let evm_builder = Evm::builder()
Expand Down
25 changes: 25 additions & 0 deletions test_data/load_test/IOHeavyContract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

// Contract used in the `load-test-io` Makefile target. The test sends transactions calling
// the `incrementNumbers()` function, which writes to 100 storage slots.

contract Counter {
uint256[100] public number;

constructor() {
for(uint i = 0; i < 100; i++) {
number[i] = i;
}
}

function incrementNumbers() public {
for(uint i = 0; i < 100; i++) {
number[i] = number[i] + 1;
}
}

function getFirstNumber() public view returns(uint256) {
return number[0];
}
}
Loading