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

Syncing main with dev (tests only) #164

Merged
merged 8 commits into from
Jan 12, 2024
Merged
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
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@
"import/namespace": "off",
"import/no-unresolved": "off",
"import/order": "off"
}
},
"ignorePatterns": [
"**/lib/*"
]
}
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "l1-contracts/lib/forge-std"]
path = l1-contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "l1-contracts/lib/murky"]
path = l1-contracts/lib/murky
url = https://github.com/dmfxyz/murky

This file was deleted.

1 change: 1 addition & 0 deletions l1-contracts/lib/murky
Submodule murky added at 40de6e
3 changes: 2 additions & 1 deletion l1-contracts/remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ ds-test/=lib/forge-std/lib/ds-test/src/
eth-gas-reporter/=node_modules/eth-gas-reporter/
forge-std/=lib/forge-std/src/
hardhat/=node_modules/hardhat/
solpp/=cache/solpp-generated-contracts/
solpp/=cache/solpp-generated-contracts/
murky/=lib/murky/src/
66 changes: 66 additions & 0 deletions l1-contracts/test/foundry/unit/concrete/Merkle/Merkle.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {Test} from "forge-std/Test.sol";
import {MerkleTest} from "solpp/dev-contracts/test/MerkleTest.sol";
import {MerkleTreeNoSort} from "./MerkleTreeNoSort.sol";

contract MerkleTestTest is Test {
MerkleTreeNoSort merkleTree;
MerkleTest merkleTest;
bytes32[] elements;
bytes32 root;

function setUp() public {
merkleTree = new MerkleTreeNoSort();
merkleTest = new MerkleTest();

for (uint256 i = 0; i < 65; i++) {
elements.push(keccak256(abi.encodePacked(i)));
}

root = merkleTree.getRoot(elements);
}

function testElements(uint256 i) public {
vm.assume(i < elements.length);
bytes32 leaf = elements[i];
bytes32[] memory proof = merkleTree.getProof(elements, i);

bytes32 rootFromContract = merkleTest.calculateRoot(proof, i, leaf);

assertEq(rootFromContract, root);
}

function testFirstElement() public {
testElements(0);
}

function testLastElement() public {
testElements(elements.length - 1);
}

function testEmptyProof_shouldRevert() public {
bytes32 leaf = elements[0];
bytes32[] memory proof;

vm.expectRevert(bytes("xc"));
merkleTest.calculateRoot(proof, 0, leaf);
}

function testLeafIndexTooBig_shouldRevert() public {
bytes32 leaf = elements[0];
bytes32[] memory proof = merkleTree.getProof(elements, 0);

vm.expectRevert(bytes("px"));
merkleTest.calculateRoot(proof, 2 ** 255, leaf);
}

function testProofLengthTooLarge_shouldRevert() public {
bytes32 leaf = elements[0];
bytes32[] memory proof = new bytes32[](256);

vm.expectRevert(bytes("bt"));
merkleTest.calculateRoot(proof, 0, leaf);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import "murky/common/MurkyBase.sol";

contract MerkleTreeNoSort is MurkyBase {
/********************
* HASHING FUNCTION *
********************/

/// The original Merkle tree contains the ascending sort and concat prior to hashing, so we need to override it
function hashLeafPairs(bytes32 left, bytes32 right) public pure override returns (bytes32 _hash) {
assembly {
mstore(0x0, left)
mstore(0x20, right)
_hash := keccak256(0x0, 0x40)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
pragma solidity 0.8.20;

import {PriorityQueueSharedTest} from "./_PriorityQueue_Shared.t.sol";

contract OnEmptyQueueTest is PriorityQueueSharedTest {
function test_gets() public {
assertEq(0, priorityQueue.getSize());
assertEq(0, priorityQueue.getFirstUnprocessedPriorityTx());
assertEq(0, priorityQueue.getTotalPriorityTxs());
assertTrue(priorityQueue.isEmpty());
}

function test_failGetFront() public {
vm.expectRevert(bytes("D"));
priorityQueue.front();
}

function test_failPopFront() public {
vm.expectRevert(bytes("s"));
priorityQueue.popFront();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
pragma solidity 0.8.20;

import {PriorityQueueSharedTest} from "./_PriorityQueue_Shared.t.sol";
import {PriorityOperation} from "../../../../../cache/solpp-generated-contracts/dev-contracts/test/PriorityQueueTest.sol";

contract PopOperationsTest is PriorityQueueSharedTest {
uint public constant NUMBER_OPERATIONS = 10;

function setUp() public {
push_mock_entries(NUMBER_OPERATIONS);
}

function test_after_pop() public {
assertEq(NUMBER_OPERATIONS, priorityQueue.getSize());

PriorityOperation memory front = priorityQueue.popFront();
assertEq(keccak256(abi.encode(0)), front.canonicalTxHash);
assertEq(uint64(0), front.expirationTimestamp);
assertEq(uint192(0), front.layer2Tip);

assertEq(NUMBER_OPERATIONS - 1, priorityQueue.getSize());
assertEq(1, priorityQueue.getFirstUnprocessedPriorityTx());
assertEq(NUMBER_OPERATIONS, priorityQueue.getTotalPriorityTxs());
assertFalse(priorityQueue.isEmpty());

// Ok - one more pop
PriorityOperation memory front2 = priorityQueue.popFront();
assertEq(keccak256(abi.encode(1)), front2.canonicalTxHash);
assertEq(uint64(1), front2.expirationTimestamp);
assertEq(uint192(1), front2.layer2Tip);

assertEq(NUMBER_OPERATIONS - 2, priorityQueue.getSize());
assertEq(2, priorityQueue.getFirstUnprocessedPriorityTx());
assertEq(NUMBER_OPERATIONS, priorityQueue.getTotalPriorityTxs());
assertFalse(priorityQueue.isEmpty());
}

function test_pop_until_limit() public {
for (uint i = 0; i < NUMBER_OPERATIONS; ++i) {
PriorityOperation memory front = priorityQueue.popFront();
assertEq(keccak256(abi.encode(i)), front.canonicalTxHash);
}

assertEq(0, priorityQueue.getSize());
assertEq(NUMBER_OPERATIONS, priorityQueue.getFirstUnprocessedPriorityTx());
assertEq(NUMBER_OPERATIONS, priorityQueue.getTotalPriorityTxs());
assertTrue(priorityQueue.isEmpty());

// And now let's push something.

PriorityOperation memory dummyOp = PriorityOperation({
canonicalTxHash: keccak256(abi.encode(300)),
expirationTimestamp: uint64(300),
layer2Tip: uint192(300)
});
priorityQueue.pushBack(dummyOp);

assertEq(1, priorityQueue.getSize());
assertEq(NUMBER_OPERATIONS, priorityQueue.getFirstUnprocessedPriorityTx());
assertEq(NUMBER_OPERATIONS + 1, priorityQueue.getTotalPriorityTxs());
assertFalse(priorityQueue.isEmpty());

PriorityOperation memory front_end = priorityQueue.popFront();
assertEq(keccak256(abi.encode(300)), front_end.canonicalTxHash);
assertTrue(priorityQueue.isEmpty());

// And now let's go over the limit and fail.
vm.expectRevert(bytes.concat("s"));
priorityQueue.popFront();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
pragma solidity 0.8.20;

import {PriorityQueueSharedTest} from "./_PriorityQueue_Shared.t.sol";
import {PriorityOperation} from "../../../../../cache/solpp-generated-contracts/dev-contracts/test/PriorityQueueTest.sol";

contract PushOperationsTest is PriorityQueueSharedTest {
uint public constant NUMBER_OPERATIONS = 10;

function setUp() public {
push_mock_entries(NUMBER_OPERATIONS);
}

function test_front() public {
assertEq(NUMBER_OPERATIONS, priorityQueue.getSize());
PriorityOperation memory front = priorityQueue.front();
assertEq(keccak256(abi.encode(0)), front.canonicalTxHash);
assertEq(uint64(0), front.expirationTimestamp);
assertEq(uint192(0), front.layer2Tip);
// This is 'front' and not popFront, so the amount should not change.
assertEq(NUMBER_OPERATIONS, priorityQueue.getSize());
assertEq(0, priorityQueue.getFirstUnprocessedPriorityTx());
assertEq(NUMBER_OPERATIONS, priorityQueue.getTotalPriorityTxs());
assertFalse(priorityQueue.isEmpty());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

import {Test} from "forge-std/Test.sol";
import {PriorityQueueTest, PriorityOperation} from "solpp/dev-contracts/test/PriorityQueueTest.sol";

contract PriorityQueueSharedTest is Test {
PriorityQueueTest internal priorityQueue;

constructor() {
priorityQueue = new PriorityQueueTest();
}

// Pushes 'count' entries into the priority queue.
function push_mock_entries(uint count) public {
for (uint i = 0; i < count; ++i) {
PriorityOperation memory dummyOp = PriorityOperation({
canonicalTxHash: keccak256(abi.encode(i)),
expirationTimestamp: uint64(i),
layer2Tip: uint192(i)
});
priorityQueue.pushBack(dummyOp);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
pragma solidity 0.8.20;

import {TransactionValidatorSharedTest} from "./_TransactionValidator_Shared.t.sol";
import {IMailbox} from "solpp/zksync/interfaces/IMailbox.sol";
import {TransactionValidator} from "solpp/zksync/libraries/TransactionValidator.sol";

contract ValidateL1L2TxTest is TransactionValidatorSharedTest {
function test_BasicRequestL1L2() public pure {
IMailbox.L2CanonicalTransaction memory testTx = createTestTransaction();
testTx.gasLimit = 500000;
validateL1ToL2Transaction(testTx, 500000);
}

function test_RevertWhen_GasLimitDoesntCoverOverhead() public {
IMailbox.L2CanonicalTransaction memory testTx = createTestTransaction();
// The limit is so low, that it doesn't even cover the overhead
testTx.gasLimit = 0;
vm.expectRevert(bytes("my"));
validateL1ToL2Transaction(testTx, 500000);
}

function test_RevertWhen_GasLimitHigherThanMax() public {
IMailbox.L2CanonicalTransaction memory testTx = createTestTransaction();
// We should fail, if user asks for too much gas.
// Notice, that we subtract the transaction overhead costs from the user's gas limit
// before checking that it is below the max gas limit.
uint256 priorityTxMaxGasLimit = 500000;
testTx.gasLimit = priorityTxMaxGasLimit + 1000000;
vm.expectRevert(bytes("ui"));
validateL1ToL2Transaction(testTx, priorityTxMaxGasLimit);
}

function test_RevertWhen_TooMuchPubdata() public {
IMailbox.L2CanonicalTransaction memory testTx = createTestTransaction();
// We should fail, if user's transaction could output too much pubdata.
// We can allow only 99k of pubdata (otherwise we'd exceed the ethereum calldata limits).

uint256 priorityTxMaxGasLimit = 500000;
testTx.gasLimit = priorityTxMaxGasLimit;
// So if the pubdata costs per byte is 1 - then this transaction could produce 500k of pubdata.
// (hypothetically, assuming all the gas was spent on writing).
testTx.gasPerPubdataByteLimit = 1;
vm.expectRevert(bytes("uk"));
validateL1ToL2Transaction(testTx, priorityTxMaxGasLimit);
}

function test_RevertWhen_BelowMinimumCost() public {
IMailbox.L2CanonicalTransaction memory testTx = createTestTransaction();
uint256 priorityTxMaxGasLimit = 500000;
testTx.gasLimit = 200000;
vm.expectRevert(bytes("up"));
validateL1ToL2Transaction(testTx, priorityTxMaxGasLimit);
}

function test_RevertWhen_HugePubdata() public {
IMailbox.L2CanonicalTransaction memory testTx = createTestTransaction();
uint256 priorityTxMaxGasLimit = 500000;
testTx.gasLimit = 400000;
// Setting huge pubdata limit should cause the panic.
testTx.gasPerPubdataByteLimit = type(uint256).max;
vm.expectRevert();
validateL1ToL2Transaction(testTx, priorityTxMaxGasLimit);
}
}
Loading
Loading