3分钟Solidity: 4.2 Transient Storage瞬态存储

25 阅读1分钟

如需获取本内容的最新版本,请参见 Cyfrin.io 上的瞬态存储(代码示例)

transient torage瞬态存储(或者叫临时storage,交易storage)中的数据在交易完成后会被清除。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

// 确保EVM版本和虚拟机设置为Cancun

// storage - 数据存储在区块链上
// memory - 函数调用后数据被清除
// Transient storage - 交易完成后数据被清除

interface ITest {
    function val() external view returns (uint256);
    function test() external;
}

// 测试TestStorage和TestTransientStorage的合约
// 展示普通storage与临时存储之间的差异
contract Callback {
    uint256 public val;

    fallback() external {
        val = ITest(msg.sender).val();
    }

    function test(address target) external {
        ITest(target).test();
    }
}

contract TestStorage {
    uint256 public val;

    function test() public {
        val = 123;
        bytes memory b = "";
        msg.sender.call(b);
    }
}

contract TestTransientStorage {
    bytes32 constant SLOT = 0;

    function test() public {
        assembly {
            tstore(SLOT, 321)
        }
        bytes memory b = "";
        msg.sender.call(b);
    }

    function val() public view returns (uint256 v) {
        assembly {
            v := tload(SLOT)
        }
    }
}

// 测试重入保护的合约
contract MaliciousCallback {
    uint256 public count = 0;

    //尝试多次重新进入目标合约
    fallback() external {
        ITest(msg.sender).test();
    }

    // 测试发起重入攻击
    function attack(address _target) external {
        // First call to test()
        ITest(_target).test();
    }
}

contract ReentrancyGuard {
    bool private locked;

    modifier lock() {
        require(!locked);
        locked = true;
        _;
        locked = false;
    }

    // 27587 gas
    function test() public lock {
        // 忽略调用错误
        bytes memory b = "";
        msg.sender.call(b);
    }
}

contract ReentrancyGuardTransient {
    bytes32 constant SLOT = 0;

    modifier lock() {
        assembly {
            if tload(SLOT) { revert(0, 0) }
            tstore(SLOT, 1)
        }
        _;
        assembly {
            tstore(SLOT, 0)
        }
    }

    // 4909 gas
    function test() external lock {
        // 忽略调用错误
        bytes memory b = "";
        msg.sender.call(b);
    }
}

Remix Lite 尝试一下

solidity-transient_storage


END