存款
存入交易,也称为存款,是在L1上发起并在L2上执行的交易。本文件概述了一种新的存款交易类型。它还描述了如何在 L1 上发起存款,以及 L2 上的授权和验证条件。
词汇注释:存入交易特指L2交易,而 存款可以指各个阶段的交易(例如存入L1时)。
目录
- 充值交易类型
- 存款收据
- L1属性充值交易
- L2 上的特殊账户
- L1 属性存款人账户
- L1属性预部署合约
- 用户存入交易
- 存款合约
充值交易类型
存入交易与现有交易类型有以下显着区别:
- 它们源自第 1 层块,并且必须作为协议的一部分包含在内。
- 它们不包括签名验证(请参阅用户存入交易 了解原理)。
- 他们在 L1 上购买 L2 Gas,因此 L2 Gas 不可退还。
我们定义了一个新的EIP-2718兼容交易类型,其前缀0x7E代表存款交易。
存款具有以下字段(rlp 按照它们在此处出现的顺序进行编码):
-
bytes32 sourceHash:源哈希,唯一标识存款的来源。 -
address from:发件人帐户的地址。 -
address to:接收者帐户的地址,如果存入的交易是合约创建,则为空(零长度)地址。 -
uint256 mint:在 L2 上铸造的 ETH 价值。 -
uint256 value:发送到接收者账户的 ETH 值。 -
uint64 gas:L2 交易的 Gas 限制。 -
bool isSystemTx:如果为 true,则交易不会与 L2 区块气池交互。
false注意:从 Regolith 升级开始,布尔值被禁用(强制为)。
-
bytes data:通话数据。
与EIP-155交易相比,此交易类型:
-
不包括 a
nonce,因为它是由 标识的
sourceHash。API 响应仍然包含一个
nonce属性:
- 在风化层之前:
nonce始终是0 - 对于Regolith:
nonce设置为depositNonce相应交易收据的属性。
- 在风化层之前:
-
不包含签名信息,并
from明确地址。API 响应包含归零签名v,r,s值以实现向后兼容。 -
包括新的
sourceHash、from、mint和isSystemTx属性。API 响应包含这些作为附加字段。
我们选择是0x7E因为当前允许交易类型标识符达到0x7F。选择高标识符可以最大限度地降低该标识符将来被 L1 链上的另一种交易类型占用的风险。我们不会选择0x7F它自己,以防它被用于可变长度编码方案。
源哈希计算
存款交易的sourceHash是根据来源计算的:
- 用户存入:
keccak256(bytes32(uint256(0)), keccak256(l1BlockHash, bytes32(uint256(l1LogIndex)))). 其中l1BlockHash、 和l1LogIndexall 指的是L1上包含充值日志事件。l1LogIndex是该区块的日志事件组合列表中的存款事件日志的索引。 - 存入L1属性:
keccak256(bytes32(uint256(1)), keccak256(l1BlockHash, bytes32(uint256(seqNumber))))。其中l1BlockHash指的是存放信息属性的L1块哈希。且seqNumber = l2BlockNum - l2EpochStartBlockNum,其中l2BlockNum是存款 tx 包含在 L2 中的 L2 区块号,l2EpochStartBlockNum是该纪元中第一个 L2 区块的 L2 区块号。
如果没有sourceHash存款,两个不同的存款交易可能具有相同的哈希值。
外部keccak256对域中的实际唯一标识信息进行哈希处理,以避免不同类型的源之间的冲突。
我们不使用发送者的随机数来确保唯一性,因为这需要 在块派生期间从执行引擎读取额外的 L2 EVM 状态。
充值交易种类
虽然我们只定义了一种新的交易类型,但我们可以根据两种存入交易在 L2 区块中的定位来区分它们:
我们仅定义一个新的交易类型,以便最大限度地减少对 L1 客户端软件的修改以及总体复杂性。
存入交易的验证和授权
如上所述,存入的交易类型不包括用于验证的签名。相反,授权是由L2 链派生过程处理的,正确应用时,只会派生出具有L1 存款合约from日志证明的地址的交易。
执行
为了执行存入交易:
首先,账户余额from必须增加 的金额mint。这是无条件的,并且不会在存款失败时恢复。
然后,根据交易的属性初始化存入交易的执行环境,其方式与 EIP-155 交易完全相同。
存款交易的处理方式与类型 3 (EIP-1559) 交易完全相同,但以下情况除外:
- 没有验证任何费用字段:押金没有任何费用,因为它支付了 L1 上的 Gas 费用。
- 未验证任何
nonce字段:存款没有任何字段,它由其唯一标识sourceHash。 - 不处理访问列表:存款没有访问列表,因此会像访问列表为空一样进行处理。
- 不检查是否
from是外部所有者账户 (EOA):通过 L1 地址屏蔽确保存款不是 EAO,这可能会在未来的 L1 合约部署中发生变化,例如启用类似账户抽象的机制。 - 风化层升级前:
- 执行输出显示非标准气体使用情况:
- 如果
isSystemTx为 false:执行输出表明它使用了gasLimitgas。 - 如果
isSystemTx为真:执行输出表明它使用了0gas。
- 如果
- 执行输出显示非标准气体使用情况:
- 天然气不会以 ETH 形式退还。(要么不退还,要么利用押金的 Gas 价格为 的事实
0) - 不收取交易优先费。不向集体费用接收者支付任何费用。
- 不收取 L1 成本费用,因为押金来自 L1,无需作为数据提交回 L1。
- 不收取基本费用。基本费用总额核算不变。
请注意,这包括像常规交易一样的合约部署行为,并且 Gas 计量是相同的(除了上面与费用相关的更改之外),包括内在 Gas 的计量。
EVM 执行发出的任何非 EVM 状态转换错误都会以特殊方式处理:
- 它转化为EVM错误:即存款将始终被包含在内,但如果遇到非EVM状态转换错误,其收据将指示失败,例如由于帐户不足而无法转移指定数量的
valueETH -平衡。 - 在存款的铸造部分之后,世界状态将回滚到 EVM 处理开始时的状态。
nonce世界状态中的 of增加from1,使错误相当于本机 EVM 故障。请注意,之前的nonce增量可能在 EVM 处理期间发生,但这将首先回滚。
最后,经过上述处理后,执行后处理的运行方式相同:即气池和收据的处理与常规交易相同。然而,从 Regolith 升级开始,存款交易的接收会增加一个附加值 depositNonce,存储EVM 处理之前注册的发送者nonce的值。from
请注意,执行输出所述使用的 Gas 会从 Gas 池中减去,但此执行输出值在 Regolith 升级之前具有特殊的边缘情况。
应用程序开发人员请注意:因为CALLER和ORIGIN被设置为from,所以在存款交易期间使用检查的语义tx.origin == msg.sender将无法确定调用者是否是 EOA。相反,该支票只能用于识别 L2 存款交易中的第一次调用。然而,此检查仍然满足开发人员使用此检查来确保在CALLER调用之前和之后无法执行代码的常见情况。
随机数处理
尽管缺乏签名验证,我们仍然from在执行存款交易时增加帐户的随机数。在仅存款汇总的情况下,这对于交易排序或防止重放来说不是必需的,但它与合约创建期间随机数的使用保持了一致性。它还可以简化与下游工具(例如钱包和区块浏览器)的集成。
存款收据
交易收据使用符合EIP-2718的标准类型。存款交易收据类型与常规收据相同,但扩展了一个可选depositNonce字段。
RLP 编码的共识强制字段是:
-
postStateOrStatus(标准):这包含事务状态,请参阅EIP-658。 -
cumulativeGasUsed(标准):迄今为止区块中使用的天然气,包括本次交易。
CumulativeGasUsed实际使用的gas是根据与之前交易的差异得出的。- 从 Regolith 开始,这说明了存款的实际 Gas 使用量,就像常规交易一样。
-
bloom(标准):事务日志的布隆过滤器。 -
logs(标准):记录 EVM 处理发出的事件。 -
depositNonce(唯一扩展):可选字段。存款交易会保留执行期间使用的随机数。
- 在 Regolith 之前,
depositNonce必须始终忽略此字段。 - 对于风化层,
depositNonce必须始终包含该字段。
- 在 Regolith 之前,
从 Regolith 开始,收据 API 响应利用收据更改来获得更准确的响应数据:
- 包含
depositNonce在 API 响应中的收据 JSON 数据中 - 对于合约部署(当 时
to == null),depositNonce有助于导出正确的contractAddress元数据,而不是假设随机数为零。 - 这
cumulativeGasUsed说明了 EVM 处理中计量的实际气体使用量。
L1属性充值交易
L1属性押金交易是发送到L1属性预部署合约的押金交易。
该交易必须具有以下值:
from是( L1属性存款人账户0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001的地址 )to是( L1属性预部署合约0x4200000000000000000000000000000000000015的地址)。mint是0value是0gasLimit设置为 150,000,000。isSystemTx设置为true.data是对L1 属性预部署合约函数 的ABI编码调用,具有与相应 L1 块关联的正确值(参见 参考实现)。setL1BlockValues()
如果风化层升级处于活动状态,某些字段将被覆盖:
gasLimit设置为 1,000,000isSystemTx被设定为false
系统发起的 L1 属性交易不会为其分配的任何 ETH 收取费用gasLimit,因为它实际上是状态转换处理的一部分。
L2 上的特殊账户
L1属性存款交易涉及两个特殊目的账户:
- L1属性存款人账户
- L1属性预部署合约
L1 属性存款人账户
存款人账户是一个没有已知私钥的EOA 。它有地址 0xdeaddeaddeaddeaddeaddeaddeaddeaddead0001。 在执行 L1 属性存入交易期间,其值由CALLER和操作码返回。ORIGIN
L1属性预部署合约
L2 上地址 处的预部署合约0x4200000000000000000000000000000000000015,保存存储中相应 L1 区块中的某些区块变量,以便在执行后续存入交易时可以访问它们。
预部署存储以下值:
-
L1块属性:
number(uint64)timestamp(uint64)basefee(uint256)hash(bytes32)
-
sequenceNumber(uint64):这等于相对于纪元开始的 L2 区块编号,即 L1 属性上次更改的 L2 区块到 L2 区块高度的距离,并在新纪元开始时重置为 0。 -
与 L1 块相关的系统配置,请参阅
系统配置规范
:
batcherHash(bytes32):对当前正在运行的批次提交者的版本化承诺。overhead(uint256):应用于此 L2 区块中交易的 L1 成本计算的 L1 费用开销。scalar(uint256):应用于此 L2 区块中交易的 L1 成本计算的 L1 费用标量。
该合约实施授权方案,使其仅接受来自存款人账户的状态更改调用。
合约具有如下solidity接口,可以按照 合约ABI规范进行交互。
L1属性预部署合约:参考实现
L1 属性预部署合约的参考实现可以在L1Block.sol中找到。
pnpm build在目录中运行后packages/contracts,要添加到创世文件的字节码将位于deployedBytecode构建工件文件的字段 中,位置为/packages/contracts/artifacts/contracts/L2/L1Block.sol/L1Block.json.
用户存入交易
用户存入交易是由L2链衍生过程 生成的存入交易。每笔用户充值交易的内容由L1上的充值合约发出的 相应事件决定。TransactionDeposited
-
from与发出的值没有变化(尽管它可能已转换为OptimismPortal存款馈送合约中的别名)。 -
to是任意20字节地址(包括零地址)
- 如果创建合约(参见
isCreation),该地址设置为null。
- 如果创建合约(参见
-
mint设置为发射值。 -
value设置为发射值。 -
gaslimit与发射值相比没有变化。它必须至少为 21000。 -
isCreation``true如果交易是合约创建,则设置为,false否则。 -
data与发射值相比没有变化。根据它的值,isCreation它被处理为调用数据或合约初始化代码。 -
isSystemTx由汇总节点为某些具有不计量执行的事务设置。用于false用户存入交易
存款合约
存款合约部署到L1。存款交易源自TransactionDeposited存款合约发出的事件中的值。
保证金合约负责维护保证 Gas 市场,对 L2 上使用的 Gas 收取保证金,并保证单个 L1 区块的保证 Gas 总量不超过 L2 区块 Gas 限额。
存款合约处理两种特殊情况:
- 合约创建押金,通过将
isCreation标志设置为 来表示true。如果to地址非零,合约将恢复。 - 来自合约账户的调用,在这种情况下,该
from值将转换为其 L2 别名。
地址别名
如果调用者是合约,则地址将通过添加 0x1111000000000000000000000000000000001111来转换。数学是unchecked在 Solidity 上完成的uint160,因此该值会溢出。这可以防止 L1 上的合约与 L2 上的合约具有相同地址但代码不同的攻击。我们可以安全地忽略 EOA 的这一点,因为它们保证具有相同的“代码”(即根本没有代码)。这也使得用户即使在 Sequencer 关闭时也可以与 L2 上的合约进行交互。
存款合约实施:乐观门户
存款合约的参考实现可以在OptimismPortal.sol中找到。