diff --git a/test/foundry/CacheManager.t.sol b/test/foundry/CacheManager.t.sol index 686a75b2..d0b8a807 100644 --- a/test/foundry/CacheManager.t.sol +++ b/test/foundry/CacheManager.t.sol @@ -3,6 +3,8 @@ pragma solidity ^0.8.4; import "forge-std/Test.sol"; import "../../src/chain/CacheManager.sol"; +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; contract CacheManagerTest is Test { CacheManager public cacheManager; @@ -26,8 +28,8 @@ contract CacheManagerTest is Test { ) ); uint64 cacheSize = 1_000_000; - uint64 decay = 0.1 ether; - cacheManager = new CacheManager(cacheSize, decay); + uint64 decay = 100; + cacheManager.initialize(cacheSize, decay); require(cacheManager.cacheSize() == cacheSize, "wrong cache size"); require(cacheManager.decay() == decay, "wrong decay rate"); @@ -68,15 +70,31 @@ contract CacheManagerTest is Test { address program = programs[uint256(keccak256(abi.encodePacked("code", epoch, round))) % programs.length]; bytes32 codehash = program.codehash; - // roll a random bid - uint256 pay = uint256(keccak256(abi.encodePacked("value", epoch, round))) % MAX_PAY; + vm.warp(block.timestamp + 1); // move time forward to test decay and make bid unique + uint256 pay; + bool mustCache; + if (round < 512) { + // for the first half of the round, we use a random bid + pay = uint256(keccak256(abi.encodePacked("value", epoch, round))) % MAX_PAY; + } else { + // for the second half of the round, we use the minimum bid + pay = cacheManager.getMinBid(program); + mustCache = true; + if (pay > 0) { + vm.expectRevert(); + cacheManager.placeBid{value: pay}(program); + } + } uint256 bid = pay + block.timestamp * uint256(cacheManager.decay()); // determine the expected insertion index on success and the bid needed uint256 index; uint256 asmSize = ARB_WASM.codehashAsmSize(codehash); + asmSize = asmSize > 4096 ? asmSize : 4096; uint256 cumulativeCacheSize = asmSize; uint256 neededBid; + // this algo does not replicate the exact logic of CacheManager if bid size are not unique + // because if new bid equals to the minimum bid, a random entry with minimum bid will be evicted for (; index < expectedCache.length; index++) { if (bid >= expectedCache[index].bid) { break; @@ -136,15 +154,19 @@ contract CacheManagerTest is Test { ); } - if (round == 768) { - uint256 newCacheSize = 500_000 + - (uint256(keccak256(abi.encodePacked("cacheSize", epoch))) % 1_000_000); - cacheManager.setCacheSize(uint64(newCacheSize)); + if (round == 700) { + // increase cache size + cacheManager.setCacheSize(uint64(1_200_000)); + } + if (round == 900) { + // reduce cache size + cacheManager.setCacheSize(uint64(200_000)); } } cacheManager.evictAll(); require(ARB_WASM_CACHE.numCached() == 0, "cached items after evictAll"); + require(cacheManager.getMinBid(uint64(0)) == 0, "min bid after evictAll"); delete expectedCache; } require(ARB_WASM_CACHE.uselessCalls() == 0, "useless ArbWasmCache calls"); @@ -171,11 +193,7 @@ contract ArbOwnerPublicMock { contract ArbWasmMock { // returns a non-uniform distribution of mock code sizes function codehashAsmSize(bytes32 codehash) external pure returns (uint64) { - uint256 size; - for (uint256 i = 0; i < 3; i++) { - size += uint256(keccak256(abi.encodePacked(codehash, i))) % 65536; - } - return uint64(size); + return uint64(uint256(keccak256(abi.encodePacked(codehash))) % 65_536); } } @@ -184,7 +202,8 @@ contract ArbWasmCacheMock { uint256 public numCached; uint256 public uselessCalls; - function cacheCodehash(bytes32 codehash) external { + function cacheProgram(address addr) external { + bytes32 codehash = addr.codehash; if (codehashIsCached[codehash]) { uselessCalls++; return; @@ -201,4 +220,4 @@ contract ArbWasmCacheMock { codehashIsCached[codehash] = false; numCached--; } -} +} \ No newline at end of file