Skip to content

Commit 13f553d

Browse files
authored
fix(l2): race conditions in ERC20 integration tests (#6138)
**Motivation** The L2 integration test workflow failed in [this run](https://github.com/lambdaclass/ethrex/actions/runs/21723329010/job/62659573593) with `l2_balance == 0` instead of the expected `100`. This may be caused by two possible race conditions. **Description** **Fix 1: Nonce race condition in `create_deploy`** (`crates/l2/sdk/src/sdk.rs`) The contract address was computed from a nonce fetched *after* sending the deploy transaction. If the transaction was mined before the nonce query returned, `get_nonce` would return N+1 instead of N, resulting in an incorrect contract address. The test would then use the wrong address for the ERC20 deposit, causing the bridge's `mintERC20` to silently fail (it uses `call()` and falls back to `_withdraw` instead of reverting). Fix: Use `receipt.tx_info.contract_address` from the transaction receipt instead of computing it from the nonce. **Fix 2: Compile race condition in integration tests** (`test/tests/l2/integration_tests.rs`) Both ERC20 tests compile `L2ERC20.sol` to the same output file (`solc_out/TestTokenL2.bin`). When running concurrently via `JoinSet`, one test could read partially written bytecode from the other test's compilation. Fix: Each test now compiles to its own output directory (`test_erc20_roundtrip/` and `test_erc20_mismatch/`). **Checklist** - [ ] Updated `STORE_SCHEMA_VERSION` (crates/storage/lib.rs) if the PR includes breaking changes to the `Store` requiring a re-sync.
1 parent f9eea3b commit 13f553d

2 files changed

Lines changed: 10 additions & 15 deletions

File tree

crates/l2/sdk/src/sdk.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -444,18 +444,11 @@ pub async fn create_deploy(
444444
.await?;
445445
let deploy_tx_hash = send_generic_transaction(client, deploy_tx, deployer).await?;
446446

447-
let nonce = client
448-
.get_nonce(deployer.address(), BlockIdentifier::Tag(BlockTag::Latest))
449-
.await?;
450-
let mut encode = vec![];
451-
(deployer.address(), nonce).encode(&mut encode);
452-
453-
//Taking the last 20bytes so it matches an H160 == Address length
454-
let deployed_address = Address::from_slice(keccak(encode).as_fixed_bytes().get(12..).ok_or(
455-
EthClientError::Custom("Failed to get deployed_address".to_owned()),
456-
)?);
447+
let receipt = wait_for_transaction_receipt(deploy_tx_hash, client, 1000).await?;
457448

458-
wait_for_transaction_receipt(deploy_tx_hash, client, 1000).await?;
449+
let deployed_address = receipt.tx_info.contract_address.ok_or_else(|| {
450+
EthClientError::Custom("Deploy transaction did not create a contract".to_owned())
451+
})?;
459452

460453
Ok((deploy_tx_hash, deployed_address))
461454
}

test/tests/l2/integration_tests.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ async fn test_erc20_roundtrip(
562562
let token_l1 = test_deploy_l1(&l1_client, &init_code_l1, &rich_wallet_private_key).await?;
563563

564564
let contracts_path = workspace_root().join("crates/l2/contracts");
565+
let compile_output_path = contracts_path.join("test_erc20_roundtrip");
565566

566567
get_contract_dependencies(&contracts_path);
567568
let remappings = [(
@@ -570,7 +571,7 @@ async fn test_erc20_roundtrip(
570571
.join("lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts"),
571572
)];
572573
compile_contract(
573-
&contracts_path,
574+
&compile_output_path,
574575
&contracts_path.join("src/example/L2ERC20.sol"),
575576
false,
576577
false,
@@ -579,7 +580,7 @@ async fn test_erc20_roundtrip(
579580
None,
580581
)?;
581582
let init_code_l2_inner = hex::decode(String::from_utf8(std::fs::read(
582-
contracts_path.join("solc_out/TestTokenL2.bin"),
583+
compile_output_path.join("solc_out/TestTokenL2.bin"),
583584
)?)?)?;
584585
let init_code_l2 = [
585586
init_code_l2_inner,
@@ -783,6 +784,7 @@ async fn test_erc20_withdraw_l1_address_mismatch(
783784
let token_l1 = test_deploy_l1(&l1_client, &init_code_l1, &rich_wallet_private_key).await?;
784785

785786
let contracts_path = workspace_root().join("crates/l2/contracts");
787+
let compile_output_path = contracts_path.join("test_erc20_mismatch");
786788

787789
get_contract_dependencies(&contracts_path);
788790
let remappings = [(
@@ -791,7 +793,7 @@ async fn test_erc20_withdraw_l1_address_mismatch(
791793
.join("lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts"),
792794
)];
793795
compile_contract(
794-
&contracts_path,
796+
&compile_output_path,
795797
&contracts_path.join("src/example/L2ERC20.sol"),
796798
false,
797799
false,
@@ -800,7 +802,7 @@ async fn test_erc20_withdraw_l1_address_mismatch(
800802
None,
801803
)?;
802804
let init_code_l2_inner = hex::decode(String::from_utf8(std::fs::read(
803-
contracts_path.join("solc_out/TestTokenL2.bin"),
805+
compile_output_path.join("solc_out/TestTokenL2.bin"),
804806
)?)?)?;
805807
let init_code_l2 = [
806808
init_code_l2_inner,

0 commit comments

Comments
 (0)