From c4b3cceaf38b391dd4d6340631cf499ec9c8072c Mon Sep 17 00:00:00 2001 From: dk1a Date: Tue, 22 Aug 2023 11:04:42 +0300 Subject: [PATCH] test(store): add gas tests for AccessControl (#1323) --- packages/world/gas-report.json | 36 +++++++++++++++++ packages/world/test/AccessControl.t.sol | 53 +++++++++++++++++++++---- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/packages/world/gas-report.json b/packages/world/gas-report.json index dff4daad5e..e9516bb4cf 100644 --- a/packages/world/gas-report.json +++ b/packages/world/gas-report.json @@ -1,4 +1,40 @@ [ + { + "file": "test/AccessControl.t.sol", + "test": "testAccessControl", + "name": "AccessControl: hasAccess (cold)", + "gasUsed": 14088 + }, + { + "file": "test/AccessControl.t.sol", + "test": "testAccessControl", + "name": "AccessControl: hasAccess (warm, namespace only)", + "gasUsed": 4122 + }, + { + "file": "test/AccessControl.t.sol", + "test": "testAccessControl", + "name": "AccessControl: hasAccess (warm)", + "gasUsed": 8121 + }, + { + "file": "test/AccessControl.t.sol", + "test": "testRequireAccess", + "name": "AccessControl: requireAccess (cold)", + "gasUsed": 14131 + }, + { + "file": "test/AccessControl.t.sol", + "test": "testRequireAccess", + "name": "AccessControl: requireAccess (warm)", + "gasUsed": 8137 + }, + { + "file": "test/AccessControl.t.sol", + "test": "testRequireAccess", + "name": "AccessControl: requireAccess (this address)", + "gasUsed": 153 + }, { "file": "test/KeysInTableModule.t.sol", "test": "testInstallComposite", diff --git a/packages/world/test/AccessControl.t.sol b/packages/world/test/AccessControl.t.sol index 39092d375c..b9f571cd39 100644 --- a/packages/world/test/AccessControl.t.sol +++ b/packages/world/test/AccessControl.t.sol @@ -2,8 +2,10 @@ pragma solidity >=0.8.0; import "forge-std/Test.sol"; +import { GasReporter } from "@latticexyz/gas-report/src/GasReporter.sol"; import { StoreReadWithStubs } from "@latticexyz/store/src/StoreReadWithStubs.sol"; +import { IWorldErrors } from "../src/interfaces/IWorldErrors.sol"; import { World } from "../src/World.sol"; import { AccessControl } from "../src/AccessControl.sol"; import { ResourceSelector } from "../src/ResourceSelector.sol"; @@ -11,34 +13,46 @@ import { ResourceSelector } from "../src/ResourceSelector.sol"; import { ResourceAccess } from "../src/tables/ResourceAccess.sol"; import { NamespaceOwner } from "../src/tables/NamespaceOwner.sol"; -contract AccessControlTest is Test, StoreReadWithStubs { - bytes16 namespace = "namespace"; - bytes16 name = "name"; - address caller = address(0x01); +contract AccessControlTest is Test, GasReporter, StoreReadWithStubs { + bytes16 constant namespace = "namespace"; + bytes16 constant name = "name"; + address constant presetCaller = address(0x0123); + address constant caller = address(0x01); function setUp() public { ResourceAccess.register(); NamespaceOwner.register(); NamespaceOwner.set(namespace, address(this)); - ResourceAccess.set(ResourceSelector.from(namespace), address(this), true); + ResourceAccess.set(ResourceSelector.from(namespace, name), presetCaller, true); } function testAccessControl() public { + bool hasAccess; + // Check that the caller has no access to the namespace or name - assertFalse(AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller)); + startGasReport("AccessControl: hasAccess (cold)"); + hasAccess = AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller); + endGasReport(); + assertFalse(hasAccess); // Grant access to the namespace ResourceAccess.set(ResourceSelector.from(namespace, 0), caller, true); // Check that the caller has access to the namespace or name - assertTrue(AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller)); + startGasReport("AccessControl: hasAccess (warm, namespace only)"); + hasAccess = AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller); + endGasReport(); + assertTrue(hasAccess); // Revoke access to the namespace ResourceAccess.set(ResourceSelector.from(namespace, 0), caller, false); // Check that the caller has no access to the namespace or name - assertFalse(AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller)); + startGasReport("AccessControl: hasAccess (warm)"); + hasAccess = AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller); + endGasReport(); + assertFalse(hasAccess); // Grant access to the name ResourceAccess.set(ResourceSelector.from(namespace, name), caller, true); @@ -52,4 +66,27 @@ contract AccessControlTest is Test, StoreReadWithStubs { // Check that the caller has no access to the namespace or name assertFalse(AccessControl.hasAccess(ResourceSelector.from(namespace, name), caller)); } + + function testRequireAccess() public { + bytes32 resourceSelector = ResourceSelector.from(namespace, name); + startGasReport("AccessControl: requireAccess (cold)"); + AccessControl.requireAccess(resourceSelector, presetCaller); + endGasReport(); + + startGasReport("AccessControl: requireAccess (warm)"); + AccessControl.requireAccess(resourceSelector, presetCaller); + endGasReport(); + + startGasReport("AccessControl: requireAccess (this address)"); + AccessControl.requireAccess(resourceSelector, address(this)); + endGasReport(); + } + + function testRequireAccessRevert() public { + bytes32 resourceSelector = ResourceSelector.from(namespace, name); + vm.expectRevert( + abi.encodeWithSelector(IWorldErrors.AccessDenied.selector, ResourceSelector.toString(resourceSelector), caller) + ); + AccessControl.requireAccess(resourceSelector, caller); + } }