Skip to content

Commit

Permalink
Merge pull request matter-labs#164 from matter-labs/dev
Browse files Browse the repository at this point in the history
Syncing main with dev (tests only)
  • Loading branch information
StanislavBreadless authored Jan 12, 2024
2 parents 1831009 + 2e65523 commit 4287161
Show file tree
Hide file tree
Showing 24 changed files with 964 additions and 833 deletions.
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

0 comments on commit 4287161

Please sign in to comment.