瞬态存储新引入的一种数据位置类型。它提供了一种在单个交易执行期间临时存储数据的机制,这些数据会在交易结束后自动清除。是对现有数据位置的补充。
瞬态存储(Transient Storage)是 Solidity 0.8.24 版本中新引入的一种数据位置类型。它提供了一种在单个交易执行期间临时存储数据的机制,这些数据会在交易结束后自动清除。该特性通过 EIP-1153 提案实现,是对现有数据位置(内存、存储、调用数据)的补充。
瞬态存储的需求主要源于以下几点:
高昂的 Gas 成本:在以太坊中,永久存储(Storage)的 SSTORE
操作成本极高,首次写入至少需要 20,000 gas。这使得处理临时数据变得不经济。
状态膨胀:永久存储的数据会不断累积,导致区块链状态的增长,增加了节点的存储负担。
清理成本:删除不再需要的存储数据需要额外支付 gas,这进一步增加了管理存储的复杂性和成本。
临时性需求:许多应用场景只需要临时存储数据。
瞬态存储填补了以太坊现有存储机制的空缺,为开发者提供了一个经济高效的临时数据存储方案,尤其适合那些数据只需在单个交易内有效且需要频繁读写的场景。
以下是关于瞬态存储(Transient Storage)、存储(Storage)、内存(Memory)和调用数据(Calldata)的比较:
特性 | 瞬态存储 | 存储 | 内存 | 调用数据 |
---|---|---|---|---|
存储位置 | 临时存储 | 永久存储 | 临时存储 | 只读存储 |
Gas 成本 | 较低(约 100 gas/操作) | 高昂(首次写入至少 20,000 gas) | 较低 | 较低 |
作用域 | 跨函数调用可用 | 跨交易可用 | 仅限于单个函数调用 | 仅限于函数参数 |
状态保持 | 可以保持状态 | 永久保持状态 | 不可保持状态 | 不可保持状态 |
清理成本 | 无需清理 | 需要额外支付 gas | 无需清理 | 无需清理 |
大小限制 | 无明显限制 | 受链上状态限制 | 有限的内存空间 | 有限的输入参数大小 |
适用场景 | 临时数据和计算 | 永久性数据存储 | 临时数据处理 | 函数参数传递 |
可以通过以下方式使用瞬态存储:
tstore
和 tload
汇编指令:contract TransientStorageExample {
function example() public {
assembly {
// 存储值
tstore(0x01, 100)
// 其它操作
// 读取值
let value := tload(0x01)
}
}
}
transient
关键字(在 Solidity 0.8.28 及之后的版本中):pragma solidity ^0.8.28;
contract TransientStorageExample {
uint transient tempValue;
function example() public {
tempValue = 100;
// 其它操作
return tempValue;
}
}
pragma solidity ^0.8.28;
contract TReentrant {
mapping(address => bool) claimed;
bool transient locked;
modifier nonReentrant {
require(!locked, "Reentrancy attempt");
locked = true;
_;
locked = false;
}
function claim() nonReentrant public {
require(!claimed[msg.sender], "Already claimed");
// 其它操作
claimed[msg.sender] = true;
}
}
pragma solidity ^0.8.28;
contract TMultiplier {
uint public transient multiplier;
function setMultiplier(uint mul) external {
multiplier = mul;
}
function multiply(uint value) external view returns (uint) {
return value * multiplier;
}
}
setMultiplier(100);
multiply(1); // 返回 0,而不是 100
multiply(2); // 返回 0,而不是 200
如果该示例使用内存或存储来存储乘数,它将是完全可组合的。无论是将交易拆分为单独的交易还是以某种方式将它们组合在一起,都没有关系。总是会得到相同的结果:在 multiplier
设置为 100
后,后续调用将分别返回 100
和 200
。这使得可以将来自多个交易的调用批量处理在一起以减少 gas 费用。
瞬态存储可能会破坏这样的用例,因为可组合性不再是理所当然的。在这个例子中,如果调用不是在同一交易中执行的,则 multiplier
将被重置,后续对函数 multiply
的调用将始终返回 0
。
瞬态存储的数据在当前交易执行期间有效,交易结束后会自动清除,从而确保其临时性。这种存储方式的写入和读取成本显著低于传统存储,能够有效节省交易的 Gas 消耗,特别适合处理临时数据。通过在合适的场景中应用瞬态存储,开发者能够显著提升合约的 Gas 效率,从而为用户节省成本并提高交易的整体性能。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!