From 83d9589f49eb32848d02d9f1383638ce1a6ad9a0 Mon Sep 17 00:00:00 2001 From: dk1a Date: Mon, 14 Aug 2023 19:54:02 +0300 Subject: [PATCH] test(store): add more gas tests for table methods (#1300) --- packages/store/gas-report.json | 86 +++++++++++++++--- packages/store/test/tables/Callbacks.t.sol | 6 +- packages/store/test/tables/Hooks.t.sol | 47 +++++++++- .../store/test/tables/HooksColdLoad.t.sol | 88 +++++++++++++++++++ 4 files changed, 210 insertions(+), 17 deletions(-) create mode 100644 packages/store/test/tables/HooksColdLoad.t.sol diff --git a/packages/store/gas-report.json b/packages/store/gas-report.json index 840bf79565..65cd41e534 100644 --- a/packages/store/gas-report.json +++ b/packages/store/gas-report.json @@ -788,38 +788,104 @@ { "file": "test/tables/Callbacks.t.sol", "test": "testSetAndGet", - "name": "set field in Callbacks", + "name": "Callbacks: set field", "gasUsed": 61383 }, { "file": "test/tables/Callbacks.t.sol", "test": "testSetAndGet", - "name": "get field from Callbacks (warm)", + "name": "Callbacks: get field (warm)", "gasUsed": 5051 }, { "file": "test/tables/Callbacks.t.sol", "test": "testSetAndGet", - "name": "push field to Callbacks", + "name": "Callbacks: push 1 element", "gasUsed": 39268 }, { "file": "test/tables/Hooks.t.sol", - "test": "testSetAndGet", - "name": "set field in Hooks", + "test": "testTable", + "name": "Hooks: set field (cold)", "gasUsed": 63374 }, { "file": "test/tables/Hooks.t.sol", - "test": "testSetAndGet", - "name": "get field from Hooks (warm)", + "test": "testTable", + "name": "Hooks: get field (warm)", "gasUsed": 5035 }, { "file": "test/tables/Hooks.t.sol", - "test": "testSetAndGet", - "name": "push field to Hooks", - "gasUsed": 39259 + "test": "testTable", + "name": "Hooks: push 1 element (cold)", + "gasUsed": 39262 + }, + { + "file": "test/tables/Hooks.t.sol", + "test": "testTable", + "name": "Hooks: pop 1 element (warm)", + "gasUsed": 15741 + }, + { + "file": "test/tables/Hooks.t.sol", + "test": "testTable", + "name": "Hooks: push 1 element (warm)", + "gasUsed": 17449 + }, + { + "file": "test/tables/Hooks.t.sol", + "test": "testTable", + "name": "Hooks: update 1 element (warm)", + "gasUsed": 17242 + }, + { + "file": "test/tables/Hooks.t.sol", + "test": "testTable", + "name": "Hooks: delete record (warm)", + "gasUsed": 10501 + }, + { + "file": "test/tables/Hooks.t.sol", + "test": "testTable", + "name": "Hooks: set field (warm)", + "gasUsed": 33677 + }, + { + "file": "test/tables/HooksColdLoad.t.sol", + "test": "testDelete", + "name": "Hooks: delete record (cold)", + "gasUsed": 21230 + }, + { + "file": "test/tables/HooksColdLoad.t.sol", + "test": "testGet", + "name": "Hooks: get field (cold)", + "gasUsed": 13020 + }, + { + "file": "test/tables/HooksColdLoad.t.sol", + "test": "testGetItem", + "name": "Hooks: get 1 element (cold)", + "gasUsed": 7786 + }, + { + "file": "test/tables/HooksColdLoad.t.sol", + "test": "testLength", + "name": "Hooks: get length (cold)", + "gasUsed": 7536 + }, + { + "file": "test/tables/HooksColdLoad.t.sol", + "test": "testPop", + "name": "Hooks: pop 1 element (cold)", + "gasUsed": 27833 + }, + { + "file": "test/tables/HooksColdLoad.t.sol", + "test": "testUpdate", + "name": "Hooks: update 1 element (cold)", + "gasUsed": 28755 }, { "file": "test/tightcoder/DecodeSlice.t.sol", diff --git a/packages/store/test/tables/Callbacks.t.sol b/packages/store/test/tables/Callbacks.t.sol index 8916fd98c1..d96e1ffe9e 100644 --- a/packages/store/test/tables/Callbacks.t.sol +++ b/packages/store/test/tables/Callbacks.t.sol @@ -14,18 +14,18 @@ contract CallbacksTest is Test, GasReporter, StoreReadWithStubs { bytes24[] memory callbacks = new bytes24[](1); callbacks[0] = bytes24(abi.encode(this.testSetAndGet)); - startGasReport("set field in Callbacks"); + startGasReport("Callbacks: set field"); Callbacks.set(key, callbacks); endGasReport(); - startGasReport("get field from Callbacks (warm)"); + startGasReport("Callbacks: get field (warm)"); bytes24[] memory returnedCallbacks = Callbacks.get(key); endGasReport(); assertEq(returnedCallbacks.length, callbacks.length); assertEq(returnedCallbacks[0], callbacks[0]); - startGasReport("push field to Callbacks"); + startGasReport("Callbacks: push 1 element"); Callbacks.push(key, callbacks[0]); endGasReport(); diff --git a/packages/store/test/tables/Hooks.t.sol b/packages/store/test/tables/Hooks.t.sol index 5e2a62a237..2c7a1e2f8d 100644 --- a/packages/store/test/tables/Hooks.t.sol +++ b/packages/store/test/tables/Hooks.t.sol @@ -7,25 +7,25 @@ import { StoreReadWithStubs } from "../../src/StoreReadWithStubs.sol"; import { Hooks } from "../../src/codegen/Tables.sol"; contract HooksTest is Test, GasReporter, StoreReadWithStubs { - function testSetAndGet() public { + function testTable() public { // Hooks schema is already registered by StoreCore bytes32 key = keccak256("somekey"); address[] memory addresses = new address[](1); addresses[0] = address(this); - startGasReport("set field in Hooks"); + startGasReport("Hooks: set field (cold)"); Hooks.set(key, addresses); endGasReport(); - startGasReport("get field from Hooks (warm)"); + startGasReport("Hooks: get field (warm)"); address[] memory returnedAddresses = Hooks.get(key); endGasReport(); assertEq(returnedAddresses.length, addresses.length); assertEq(returnedAddresses[0], addresses[0]); - startGasReport("push field to Hooks"); + startGasReport("Hooks: push 1 element (cold)"); Hooks.push(key, addresses[0]); endGasReport(); @@ -33,5 +33,44 @@ contract HooksTest is Test, GasReporter, StoreReadWithStubs { assertEq(returnedAddresses.length, 2); assertEq(returnedAddresses[1], addresses[0]); + + startGasReport("Hooks: pop 1 element (warm)"); + Hooks.pop(key); + endGasReport(); + + returnedAddresses = Hooks.get(key); + + assertEq(returnedAddresses.length, 1); + assertEq(returnedAddresses[0], addresses[0]); + + startGasReport("Hooks: push 1 element (warm)"); + Hooks.push(key, addresses[0]); + endGasReport(); + + returnedAddresses = Hooks.get(key); + + assertEq(returnedAddresses.length, 2); + assertEq(returnedAddresses[1], addresses[0]); + + address newAddress = address(bytes20(keccak256("alice"))); + startGasReport("Hooks: update 1 element (warm)"); + Hooks.update(key, 1, newAddress); + endGasReport(); + + returnedAddresses = Hooks.get(key); + assertEq(returnedAddresses.length, 2); + assertEq(returnedAddresses[0], addresses[0]); + assertEq(returnedAddresses[1], newAddress); + + startGasReport("Hooks: delete record (warm)"); + Hooks.deleteRecord(key); + endGasReport(); + + returnedAddresses = Hooks.get(key); + assertEq(returnedAddresses.length, 0); + + startGasReport("Hooks: set field (warm)"); + Hooks.set(key, addresses); + endGasReport(); } } diff --git a/packages/store/test/tables/HooksColdLoad.t.sol b/packages/store/test/tables/HooksColdLoad.t.sol new file mode 100644 index 0000000000..30b2c6c644 --- /dev/null +++ b/packages/store/test/tables/HooksColdLoad.t.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import { Test } from "forge-std/Test.sol"; +import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; +import { StoreReadWithStubs } from "../../src/StoreReadWithStubs.sol"; +import { Hooks } from "../../src/codegen/Tables.sol"; + +contract HooksColdLoadTest is Test, GasReporter, StoreReadWithStubs { + address[] addresses; + + function setUp() public { + // Hooks schema is already registered by StoreCore + bytes32 key = keccak256("somekey"); + + addresses = new address[](1); + addresses[0] = address(this); + + Hooks.set(key, addresses); + } + + function testGet() public { + bytes32 key = keccak256("somekey"); + + startGasReport("Hooks: get field (cold)"); + address[] memory returnedAddresses = Hooks.get(key); + endGasReport(); + + assertEq(returnedAddresses.length, addresses.length); + assertEq(returnedAddresses[0], addresses[0]); + } + + function testLength() public { + bytes32 key = keccak256("somekey"); + + startGasReport("Hooks: get length (cold)"); + uint256 length = Hooks.length(key); + endGasReport(); + + assertEq(length, addresses.length); + } + + function testGetItem() public { + bytes32 key = keccak256("somekey"); + + startGasReport("Hooks: get 1 element (cold)"); + address returnedAddress = Hooks.getItem(key, 0); + endGasReport(); + + assertEq(returnedAddress, addresses[0]); + } + + function testPop() public { + bytes32 key = keccak256("somekey"); + + startGasReport("Hooks: pop 1 element (cold)"); + Hooks.pop(key); + endGasReport(); + + uint256 length = Hooks.length(key); + + assertEq(length, addresses.length - 1); + } + + function testUpdate() public { + bytes32 key = keccak256("somekey"); + + address newAddress = address(bytes20(keccak256("alice"))); + startGasReport("Hooks: update 1 element (cold)"); + Hooks.update(key, 0, newAddress); + endGasReport(); + + address[] memory returnedAddresses = Hooks.get(key); + assertEq(returnedAddresses.length, 1); + assertEq(returnedAddresses[0], newAddress); + } + + function testDelete() public { + bytes32 key = keccak256("somekey"); + + startGasReport("Hooks: delete record (cold)"); + Hooks.deleteRecord(key); + endGasReport(); + + address[] memory returnedAddresses = Hooks.get(key); + assertEq(returnedAddresses.length, 0); + } +}