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

Specify address when caching Stylus program #194

Merged
merged 6 commits into from
Jul 1, 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
22 changes: 15 additions & 7 deletions src/chain/CacheManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
error BidsArePaused();
error MakeSpaceTooLarge(uint64 size, uint64 limit);

event InsertBid(bytes32 indexed codehash, uint192 bid, uint64 size);
event InsertBid(bytes32 indexed codehash, address program, uint192 bid, uint64 size);
gzeoneth marked this conversation as resolved.
Show resolved Hide resolved
event DeleteBid(bytes32 indexed codehash, uint192 bid, uint64 size);
event SetCacheSize(uint64 size);
event SetDecayRate(uint64 decay);
Expand Down Expand Up @@ -151,10 +151,16 @@

/// @notice Returns the minimum bid required to cache the program with given codehash.
/// Value returned here is the minimum bid that you can send with msg.value
function getMinBid(bytes32 codehash) external view returns (uint192 min) {
function getMinBid(bytes32 codehash) public view returns (uint192 min) {
return getMinBid(_asmSize(codehash));
}

/// @notice Returns the minimum bid required to cache the program at given address.
/// Value returned here is the minimum bid that you can send with msg.value
function getMinBid(address program) external view returns (uint192 min) {
return getMinBid(program.codehash);
}

/// @notice Sends all revenue to the network fee account.
function sweepFunds() external {
(bool success, bytes memory data) = ARB_OWNER_PUBLIC.getNetworkFeeAccount().call{
Expand All @@ -167,19 +173,20 @@
}
}

/// @notice Places a bid, reverting if payment is insufficient.
function placeBid(bytes32 codehash) external payable {
/// Places a bid, reverting if payment is insufficient.
function placeBid(address program) external payable {
if (isPaused) {
revert BidsArePaused();
}
bytes32 codehash = program.codehash;
gzeoneth marked this conversation as resolved.
Show resolved Hide resolved
if (_isCached(codehash)) {
revert AlreadyCached(codehash);
}

uint64 asm = _asmSize(codehash);
(uint192 bid, uint64 index) = _makeSpace(asm);
return _addBid(bid, codehash, asm, index);
return _addBid(bid, program, codehash, asm, index);
}

/// @notice Evicts entries until enough space exists in the cache, reverting if payment is insufficient.
/// Returns the new amount of space available on success.
Expand Down Expand Up @@ -230,6 +237,7 @@
/// @dev Adds a bid
function _addBid(
uint192 bid,
address program,
bytes32 code,
uint64 size,
uint64 index
Expand All @@ -239,15 +247,15 @@
}

Entry memory entry = Entry({size: size, code: code, bid: bid});
ARB_WASM_CACHE.cacheCodehash(code);
ARB_WASM_CACHE.cacheProgram(program);
bids.push(_packBid(bid, index));
queueSize += size;
if (index == entries.length) {
entries.push(entry);
} else {
entries[index] = entry;
}
emit InsertBid(code, bid, size);
emit InsertBid(code, program, bid, size);
}

/// @dev Clears the entry at the given index
Expand Down
2 changes: 1 addition & 1 deletion src/mocks/SimpleCacheManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "../precompiles/ArbWasmCache.sol";

contract SimpleCacheManager {
function cacheProgram(address program) external {
ArbWasmCache(address(0x72)).cacheCodehash(codehash(program));
ArbWasmCache(address(0x72)).cacheProgram(program);
}

function evictProgram(address program) external {
Expand Down
7 changes: 5 additions & 2 deletions src/precompiles/ArbWasmCache.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ interface ArbWasmCache {
/// @return managers the list of managers.
function allCacheManagers() external view returns (address[] memory managers);

/// @notice Caches all programs with the given codehash.
/// @dev Deprecated, replaced with cacheProgram
function cacheCodehash(bytes32 codehash) external;
PlasmaPower marked this conversation as resolved.
Show resolved Hide resolved

/// @notice Caches all programs with a codehash equal to the given address.
/// @notice Reverts if the programs have expired.
/// @notice Caller must be a cache manager or chain owner.
/// @notice If you're looking for how to bid for position, interact with the chain's cache manager contract.
function cacheCodehash(bytes32 codehash) external;
function cacheProgram(address addr) external;

/// @notice Evicts all programs with the given codehash.
/// @notice Caller must be a cache manager or chain owner.
Expand Down
36 changes: 28 additions & 8 deletions test/foundry/CacheManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,30 @@ contract CacheManagerTest is Test {
}

function test_randomBids() external {
address[] memory programs = new address[](256);
for (uint256 i = 0; i < programs.length; i++) {
// Deploy bytes(bytes32(i)) as code to a sample program
// PUSH32 i PUSH1 0 MSTORE PUSH1 32 PUSH1 0 RETURN
// at the time of writing this our forge version or config doesn't have PUSH0 support
bytes memory bytecode = bytes.concat(hex"7F", abi.encodePacked(i), hex"60005260206000F3");
address program;
assembly {
program := create(0, add(bytecode, 32), mload(bytecode))
}
if (program == address(0)) {
revert("zero");
}
if (program.codehash != keccak256(abi.encodePacked(i))) {
revert("failed to deploy sample code");
}
programs[i] = program;
}

for (uint256 epoch = 0; epoch < 4; epoch++) {
for (uint256 round = 0; round < 1024; round++) {
// roll one of 256 random codehashes
bytes32 codehash = keccak256(abi.encodePacked("code", epoch, round));
codehash = keccak256(abi.encodePacked(uint256(codehash) % 256));
for (uint256 round = 0; round < 512; round++) {
// roll one of 256 random programs
address program = programs[uint256(keccak256(abi.encodePacked("code", epoch, round))) % programs.length];
bytes32 codehash = program.codehash;

vm.warp(block.timestamp + 1); // move time forward to test decay and make bid unique
uint256 pay;
Expand All @@ -46,11 +65,11 @@ contract CacheManagerTest is Test {
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(codehash);
pay = cacheManager.getMinBid(program);
mustCache = true;
if (pay > 0) {
vm.expectRevert();
cacheManager.placeBid{value: pay - 1}(codehash);
cacheManager.placeBid{value: pay}(program);
}
}
uint256 bid = pay + block.timestamp * uint256(cacheManager.decay());
Expand Down Expand Up @@ -102,7 +121,7 @@ contract CacheManagerTest is Test {
}
}

cacheManager.placeBid{value: pay}(codehash);
cacheManager.placeBid{value: pay}(program);

if(mustCache) {
require(
Expand Down Expand Up @@ -170,7 +189,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;
Expand Down
Loading