闽公网安备 35020302035485号


// 堆代码 www.duidaima.com
function addSequencerL2Batch(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder,
uint256 prevMessageCount,
uint256 newMessageCount
) external override refundsGas(gasRefunder) {
if (
!isBatchPoster[msg.sender]
&& msg.sender != address(rollup)
) revert NotBatchPoster();
[...]
addSequencerL2BatchImpl(
dataHash_,
afterDelayedMessagesRead_,
0,
prevMessageCount_,
newMessageCount_
);
[...]
}
然后在addSequencerL2BatchImpl[9]里面调用桥接(bridge),将信息排队到收件箱。bridge.enqueueSequencerMessage(
dataHash,
afterDelayedMessagesRead,
prevMessageCount,
newMessageCount
);
然后在桥接中调用 enqueueSequencerMessage[10],它只是向收件箱数组添加一个新的哈希值。bytes32[] public sequencerInboxAccs;
function enqueueSequencerMessage(
bytes32 dataHash,
uint256 afterDelayedMessagesRead,
uint256 prevMessageCount,
uint256 newMessageCount
)
external
onlySequencerInbox
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 acc
)
{
[...]
acc = keccak256(abi.encodePacked(beforeAcc, dataHash, delayedAcc));
sequencerInboxAccs.push(acc);
}
bytes32[] public delayedInboxAccs;
function enqueueDelayedMessage(
uint8 kind,
address sender,
bytes32 messageDataHash
) external payable returns (uint256) {
[...]
delayedInboxAccs.push(
Messages.accumulateInboxMessage(
prevAcc,
messageHash
)
);
[...]
}
function deliverToBridge(
uint8 kind,
address sender,
bytes32 messageDataHash
) internal returns (uint256) {
return
bridge.enqueueDelayedMessage{value: msg.value}(
kind,
AddressAliasHelper.applyL1ToL2Alias(sender),
messageDataHash
);
}
// 堆代码 www.duidaima.com
function forceInclusion(
uint256 _totalDelayedMessagesRead,
uint8 kind,
uint64[2] calldata l1BlockAndTime,
uint256 baseFeeL1,
address sender,
bytes32 messageDataHash
) external {
[...]
if (l1BlockAndTime[0] + maxTimeVariation.delayBlocks >= block.number)
revert ForceIncludeBlockTooSoon();
if (l1BlockAndTime[1] + maxTimeVariation.delaySeconds >= block.timestamp)
revert ForceIncludeTimeTooSoon();
[...]
addSequencerL2BatchImpl(
dataHash,
__totalDelayedMessagesRead,
0,
prevSeqMsgCount,
newSeqMsgCount
);
[...]
}

struct Machine {
MachineStatus status;
ValueStack valueStack;
ValueStack internalStack;
StackFrameWindow frameStack;
bytes32 globalStateHash;
uint32 moduleIdx;
uint32 functionIdx;
uint32 functionPc;
bytes32 modulesRoot;
}
挑战者将用所有的数据初始化这个机器 Machine。在合约中,我们只需要再次检查这些数据是否代表了存储的 Merkle 根哈希值。require(mach.hash() == beforeHash, "MACHINE_BEFORE_HASH")现在我们可以信任 Module(模块)根,用它来验证模块的数据。
struct Module {
bytes32 globalsMerkleRoot;
ModuleMemory moduleMemory;
bytes32 tablesMerkleRoot;
bytes32 functionsMerkleRoot;
uint32 internalsOffset;
}
这里面持有的数据是 WAVM 机器数据的进一步 Merkle 根哈希值的形式。而挑战者也初始化了这些数据。(mod, offset) = Deserialize.module(proof, offset);
(modProof, offset) = Deserialize.merkleProof(proof, offset);
require(
modProof.computeRootFromModule(mach.moduleIdx, mod) == mach.modulesRoot,
"MODULES_ROOT"
);
最后我们再对Instruction(指令)[19]数据做同样的处理。struct Instruction {
uint16 opcode;
uint256 argumentData;
}
并且将通过函数 MerkleRoot 进行验证:MerkleProof memory instProof;
MerkleProof memory funcProof;
(inst, offset) = Deserialize.instruction(proof, offset);
(instProof, offset) = Deserialize.merkleProof(proof, offset);
(funcProof, offset) = Deserialize.merkleProof(proof, offset);
bytes32 codeHash = instProof.computeRootFromInstruction(mach.functionPc, inst);
bytes32 recomputedRoot = funcProof.computeRootFromFunction(
mach.functionIdx,
codeHash
);
require(recomputedRoot == mod.functionsMerkleRoot, "BAD_FUNCTIONS_ROOT");
所以现在我们有一个初始化的 WAVM 机器,剩下的就是执行某个有分歧的的操作。现在这取决于我们需要运行的确切指令。uint32 b = mach.valueStack.pop().assumeI32(); uint32 a = mach.valueStack.pop().assumeI32(); [...] return (a + b, false);

// 堆代码 www.duidaima.com
function executeLocalGet(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata proof
) internal pure {
StackFrame memory frame = mach.frameStack.peek();
Value memory val = merkleProveGetValue(frame.localsMerkleRoot, inst.argumentData, proof);
mach.valueStack.push(val);
}
这个StackFrame[22]来自 WAVM 的初始化,在这里我们可以找到 localsMerkleRoot。struct StackFrame {
Value returnPc;
bytes32 localsMerkleRoot;
uint32 callerModule;
uint32 callerModuleInternals;
}
并通过 Merkle 证明,我们可以检索到该值并将其推送到堆栈。最后,我们检查[23]这个计算步骤产生的最终哈希值是否等于存储的哈希值。require(
afterHash != selection.oldSegments[selection.challengePosition + 1],
"SAME_OSP_END"
);
只有当它不匹配时,证明才有效,我们继续。现在挑战者赢了,一个新的后状态将被接受。5.msg.sender的工作方式与以太坊上正常的 L2 到 L2 交易相同;对于 L1 到 L2 的 “retryable ticket(可重试票据) ”交易,它将返回触发消息的 L1 合约的 L2 地址别名。更多内容见可重试票据地址别名[25]。
const params = [{
"chainId": "42161", // testnet: "421611"
"chainName": "Arbitrum",
"rpcUrls": [
"https://arb1.arbitrum.io/rpc"
// rinkeby: "https://rinkeby.arbitrum.io/rpc"
// goerli: "https://goerli-rollup.arbitrum.io/rpc"
],
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"blockExplorerUrls": [
"https://explorer.arbitrum.io"
// rinkeby: "https://rinkeby-explorer.arbitrum.io"
// goerli: "https://goerli-rollup-explorer.arbitrum.io"
]
}]
try {
await ethereum.request({
method: 'wallet_addEthereumChain',
params,
})
} catch (error) {
// something failed, e.g., user denied request
}
要在 Arbitrum 获得资金,可使用 https://bridge.arbitrum.io/ 提供的桥。{
arbitrum_mainnet: {
provider: function () {
return new HDWalletProvider(
mnemonic,
"https://arbitrum-mainnet.infura.io/v3/"
+ infuraKey,
0,
1
);
},
},
arbitrum_rinkeby: {
provider: function () {
return new HDWalletProvider(
mnemonic,
"https://rinkeby.arbitrum.io/rpc",
0,
1
);
},
},
arbitrum_goerli: {
provider: function () {
return new HDWalletProvider(
mnemonic,
"https://goerli-rollup.arbitrum.io/rpc",
0,
1
);
}
}
}
推荐的一个好的做法是用 Hardhat 编写测试,用常规的本地配置,这样你可以快速运行测试,并有 console.log/stacktraces 功能可用。如果需要,可以在Infura[30]设置中激活 Arbitrum。
参考资料
[1]登链翻译计划: https://github.com/lbc-team/Pioneer
[2]翻译小组: https://learnblockchain.cn/people/412
[3]Tiny 熊: https://learnblockchain.cn/people/15
[4]最成功的: https://twitter.com/JackNiewold/status/1564374766441611266
[5]Merkle 树指南: https://learnblockchain.cn/article/5297
[6]UTXO: https://www.investopedia.com/terms/u/utxo.asp
[7]这里: https://www.learnplasma.org/en/learn/mvp.html#plasma-mvp
[8]addSequencerL2Batch: https://github.com/OffchainLabs/nitro/blob/2678e0b57abfbcda8f21e844a94368eea5389348/contracts/src/bridge/SequencerInbox.sol#L235
[9]addSequencerL2BatchImpl: https://github.com/OffchainLabs/nitro/blob/2678e0b57abfbcda8f21e844a94368eea5389348/contracts/src/bridge/SequencerInbox.sol#L338-L383
[10]enqueueSequencerMessage: https://github.com/OffchainLabs/nitro/blob/2678e0b57abfbcda8f21e844a94368eea5389348/contracts/src/bridge/Bridge.sol#L100-L132
[11]deliverToBridge: https://github.com/OffchainLabs/nitro/blob/2678e0b57abfbcda8f21e844a94368eea5389348/contracts/src/bridge/Inbox.sol#L419-L430
[12]enqueueDelayedMessage: https://github.com/OffchainLabs/nitro/blob/2678e0b57abfbcda8f21e844a94368eea5389348/contracts/src/bridge/Bridge.sol#L152-L167
[13]forceInclusion(强制包含): https://github.com/OffchainLabs/nitro/blob/2678e0b57abfbcda8f21e844a94368eea5389348/contracts/src/bridge/SequencerInbox.sol#L89-L152
[14]这里: https://developer.offchainlabs.com/inside-arbitrum-nitro#dissection-protocol-simplified-version
[15]源代码: https://github.com/OffchainLabs/nitro/blob/c191708c7847bf9e92c3c0a5263d31e4876d9e18/contracts/src/challenge/ChallengeManager.sol#L171
[16]WAVM 机器(Machine): https://github.com/OffchainLabs/nitro/blob/c191708c7847bf9e92c3c0a5263d31e4876d9e18/contracts/src/state/Machine.sol#L18-L28
[17]模块: https://github.com/OffchainLabs/nitro/blob/c191708c7847bf9e92c3c0a5263d31e4876d9e18/contracts/src/state/Module.sol#L9
[18]验证它: https://github.com/OffchainLabs/nitro/blob/c191708c7847bf9e92c3c0a5263d31e4876d9e18/contracts/src/osp/OneStepProofEntry.sol#L60
[19]Instruction(指令): https://github.com/OffchainLabs/nitro/blob/c191708c7847bf9e92c3c0a5263d31e4876d9e18/contracts/src/state/Instructions.sol#L7
[20]简单加法: https://github.com/OffchainLabs/nitro/blob/c191708c7847bf9e92c3c0a5263d31e4876d9e18/contracts/src/osp/OneStepProverMath.sol#L217
[21]本地获取: https://github.com/OffchainLabs/nitro/blob/c191708c7847bf9e92c3c0a5263d31e4876d9e18/contracts/src/osp/OneStepProver0.sol#L334
[22]StackFrame: https://github.com/OffchainLabs/nitro/blob/c191708c7847bf9e92c3c0a5263d31e4876d9e18/contracts/src/state/StackFrame.sol#L9
[23]检查: https://github.com/OffchainLabs/nitro/blob/c191708c7847bf9e92c3c0a5263d31e4876d9e18/contracts/src/challenge/ChallengeManager.sol#L262
[24]支持Solidity: https://developer.offchainlabs.com/solidity-support
[25]可重试票据地址别名: https://developer.offchainlabs.com/arbos/l1-to-l2-messaging#address-aliasing
[26]wallet_addEthereumChain: https://docs.metamask.io/guide/rpc-api.html#wallet-addethereumchain
[27]点击这里连接到 Arbitrum One: https://chainlist.org/chain/42161
[28]点击这里连接到 Arbitrrum Nitro Rinkeby: https://chainlist.org/chain/421611
[29]点击这里连接到 Aribitrum Nitro Goerli: https://chainlist.org/chain/421613
[30]Infura: https://infura.io