Solidity transient storage
한 트랜잭션 내에서만 유지되고, 트랜잭션이 끝나면 자동으로 초기화되는 임시 저장소이다. EIP-1153에서 소개되었다. TSTORE와 TLOAD opcode 로 접근할 수 있으며, EVM Cancun 버전부터 지원한다. Solidity 0.8.24 부터 지원된다. 재진입 락으로 주로 이용된다.
어셈블리를 이용하여 Transient 스토리지의 슬롯 번호를 지정하여 사용할 수 있다. 슬롯은 영구 스토리지와는 별도로 관리된다.
contract TransientAssembly {
// slot 번호
bytes32 constant SLOT = bytes32(uint256(1));
function tstore(uint256 value) external {
assembly {
tstore(SLOT, value)
}
}
function tload() external view returns (uint256 value) {
assembly {
value := tload(SLOT)
}
}
}하이레벨에서 접근하려면 다음과 같이 사용할 수 있다.
contract OverwriteStorage {
address transient _lock;
function guarded() external {
require(_lock == address(0), "locked");
_lock = msg.sender;
// ... protected logic ...
delete _lock;
}
}Transient storage clearing helper collision bug
Solidity 0.8.28 - 0.8.33 컴파일러에서 Transient 스토리지를 삭제할 때 스토리지가 잘못 삭제되는 버그가 존재한다. Solidity 0.8.34에서 이를 수정했다.
예를 들어 다음과 같은 코드가 있다. 영구 스토리지 슬롯 0번에 owner 변수가, transient 스토리지 슬롯 0번에 _lock이 저장되어 있다. guarded 함수에서 delete _lock; 으로 transient 스토리지를 클리어한다.
contract OverwriteStorage {
// ---- persistent storage ----
address public owner;
mapping(uint256 => address) public delegates;
// ---- transient storage ----
address transient _lock;
constructor() { owner = msg.sender; }
function clearDelegate(uint256 id) external {
delete delegates[id];
}
function guarded() external {
require(_lock == address(0), "locked");
_lock = msg.sender;
// ... protected logic ...
@> delete _lock;
}
}이때 transient 가 아니라 영구 스토리지인 owner 변수가 초기화 된다. transient 스토리지는 초기화되지 않았으므로 동일 트랜잭션에서 guarded 재호출 시 트랜잭션이 revert 된다.
OverwriteStorage target = new OverwriteStorage();
assert(target.owner() == address(this)); // owner is deployer
target.guarded();
assert(target.owner() == address(0)); // owner overwritten with zerotags: blockchain, smart contract, solidity, solidity storage