Skip to content

Commit

Permalink
update to use new test contract
Browse files Browse the repository at this point in the history
  • Loading branch information
0age committed Mar 27, 2024
1 parent 9eef2e4 commit 8050091
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 88 deletions.
30 changes: 0 additions & 30 deletions src/Counter.sol

This file was deleted.

146 changes: 129 additions & 17 deletions src/Tstorish.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,100 @@
pragma solidity ^0.8.24;

contract Tstorish {
// Declare a storage variable indicating if TSTORE support has been activated
// post-deployment.
bool private _tstoreSupport;

/*
*
* --------------------------------------------------------------------------+
* Opcode | Mnemonic | Stack | Memory |
* --------------------------------------------------------------------------|
* 60 0x02 | PUSH1 0x02 | 0x02 | |
* 60 0x1e | PUSH1 0x1e | 0x1e 0x02 | |
* 61 0x3d5c | PUSH2 0x3d5c | 0x3d5c 0x1e 0x02 | |
* 3d | RETURNDATASIZE | 0 0x3d5c 0x1e 0x02 | |
* |
* ::: store deployed bytecode in memory: (3d) RETURNDATASIZE (5c) TLOAD ::: |
* 52 | MSTORE | 0x1e 0x02 | [0..0x20): 0x3d5c |
* f3 | RETURN | | [0..0x20): 0x3d5c |
* --------------------------------------------------------------------------+
*/
uint256 constant _TLOAD_TEST_PAYLOAD = 0x6002_601e_613d5c_3d_52_f3;
uint256 constant _TLOAD_TEST_PAYLOAD_LENGTH = 0x0a;
uint256 constant _TLOAD_TEST_PAYLOAD_OFFSET = 0x16;

// Declare an immutable variable to store the initial TSTORE support status.
bool private immutable _tstoreInitialSupport;

bool private _tstoreSupport;
// Declare an immutable variable to store the tstore test contract address.
address private immutable _tloadTestContract;

// Declare a few custom revert error types.
error TStoreAlreadyActivated();
error TStoreNotSupported();
error TloadTestContractDeploymentFailed();

/**
* @dev Determine TSTORE availability during deployment. This involves
* attempting to deploy a contract that utilizes TLOAD as part of the
* contract construction bytecode, and configuring initial support for
* using TSTORE in place of SSTORE based on the result.
*/
constructor() {
try new TstoreTest() returns (TstoreTest) {
_tstoreInitialSupport = true;
} catch {
_tstoreInitialSupport = false;
// Deploy the contract testing TLOAD support and store the address.
address tloadTestContract = _prepareTloadTest();

// Ensure the deployment was successful.
if (tloadTestContract == address(0)) {
revert TloadTestContractDeploymentFailed();
}

// Determine if TSTORE is supported.
bool tstoreInitialSupport = _testTload(tloadTestContract);

// Store the result as an immutable.
_tstoreInitialSupport = tstoreInitialSupport;

// Set the address of the deployed TLOAD test contract as an immutable.
_tloadTestContract = tloadTestContract;
}

function __activateTstore() public {
/**
* @dev External function to activate TSTORE usage. Does not need to be
* called if TSTORE is supported from deployment, and only needs to be
* called once. Reverts if TSTORE has already been activated or if the
* opcode is not available. Note that this may be vulnerable to various
* reentrancy issues; if this is a concern, place this function behind
* the reentrancy guard to ensure that it is not triggered inflight.
*/
function __activateTstore() external {
// Determine if TSTORE can potentially be activated.
if (_tstoreInitialSupport || _tstoreSupport) {
revert TStoreAlreadyActivated();
}

try new TstoreTest() returns (TstoreTest) {
_tstoreSupport = true;
} catch {
// Determine if TSTORE can be activated and revert if not.
if (!_testTload(_tloadTestContract)) {
revert TStoreNotSupported();
}

// Mark TSTORE as activated.
_tstoreSupport = true;
}

/**
* @dev Internal function to set a TSTORISH value.
*
* @param storageSlot The slot to write the TSTORISH value to.
* @param value The value to write to the given storage slot.
*/
function _setTstorish(uint256 storageSlot, uint256 value) internal {
if (_tstoreInitialSupport || _tstoreSupport) {
if (_tstoreInitialSupport) {
assembly {
tstore(storageSlot, value)
}
} else if (_tstoreSupport) {
assembly {
tstore(storageSlot, value)
}
Expand All @@ -41,8 +106,21 @@ contract Tstorish {
}
}

function _getTstorish(uint256 storageSlot) internal view returns (uint256 value) {
if (_tstoreInitialSupport || _tstoreSupport) {
/**
* @dev Internal function to read a TSTORISH value.
*
* @param storageSlot The slot to read the TSTORISH value from.
*
* @return value The TSTORISH value at the given storage slot.
*/
function _getTstorish(
uint256 storageSlot
) internal view returns (uint256 value) {
if (_tstoreInitialSupport) {
assembly {
value := tload(storageSlot)
}
} else if (_tstoreSupport) {
assembly {
value := tload(storageSlot)
}
Expand All @@ -53,8 +131,17 @@ contract Tstorish {
}
}

/**
* @dev Internal function to clear a TSTORISH value.
*
* @param storageSlot The slot to clear the TSTORISH value for.
*/
function _clearTstorish(uint256 storageSlot) internal {
if (_tstoreInitialSupport || _tstoreSupport) {
if (_tstoreInitialSupport) {
assembly {
tstore(storageSlot, 0)
}
} else if (_tstoreSupport) {
assembly {
tstore(storageSlot, 0)
}
Expand All @@ -64,12 +151,37 @@ contract Tstorish {
}
}
}
}

contract TstoreTest {
constructor() {
/**
* @dev Private function to deploy a test contract that utilizes TLOAD as
* part of its fallback logic.
*/
function _prepareTloadTest() private returns (address contractAddress) {
// Utilize assembly to deploy a contract testing TLOAD support.
assembly {
pop(tload(0))
// Write the contract deployment code payload to scratch space.
mstore(0, _TLOAD_TEST_PAYLOAD)

// Deploy the contract.
contractAddress := create(
0,
_TLOAD_TEST_PAYLOAD_OFFSET,
_TLOAD_TEST_PAYLOAD_LENGTH
)
}
}

/**
* @dev Private view function to determine if TSTORE/TLOAD are supported by
* the current EVM implementation by attempting to call the test
* contract, which utilizes TLOAD as part of its fallback logic.
*/
function _testTload(
address tloadTestContract
) private view returns (bool ok) {
// Call the test contract, which will perform a TLOAD test. If the call
// does not revert, then TLOAD/TSTORE is supported. Do not forward all
// available gas, as all forwarded gas will be consumed on revert.
(ok, ) = tloadTestContract.staticcall{ gas: gasleft() / 10 }("");
}
}
41 changes: 0 additions & 41 deletions test/Counter.t.sol

This file was deleted.

0 comments on commit 8050091

Please sign in to comment.