文件 1 的 88:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 88:AddressAliasHelper.sol
pragma solidity ^0.8.0;
library AddressAliasHelper {
uint160 internal constant OFFSET = uint160(0x1111000000000000000000000000000000001111);
function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
unchecked {
l2Address = address(uint160(l1Address) + OFFSET);
}
}
function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
unchecked {
l1Address = address(uint160(l2Address) - OFFSET);
}
}
}
文件 3 的 88:AddressUpgradeable.sol
pragma solidity ^0.8.1;
library AddressUpgradeable {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 4 的 88:AdminFallbackProxy.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/Proxy.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/StorageSlot.sol";
abstract contract DoubleLogicERC1967Upgrade is ERC1967Upgrade {
bytes32 internal constant _IMPLEMENTATION_SECONDARY_SLOT =
0x2b1dbce74324248c222f0ec2d5ed7bd323cfc425b336f0253c5ccfda7265546d;
bytes32 private constant _ROLLBACK_SECONDARY_SLOT =
0x49bd798cd84788856140a4cd5030756b4d08a9e4d55db725ec195f232d262a89;
event UpgradedSecondary(address indexed implementation);
function _getSecondaryImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SECONDARY_SLOT).value;
}
function _setSecondaryImplementation(address newImplementation) private {
require(
Address.isContract(newImplementation),
"ERC1967: new secondary implementation is not a contract"
);
StorageSlot.getAddressSlot(_IMPLEMENTATION_SECONDARY_SLOT).value = newImplementation;
}
function _upgradeSecondaryTo(address newImplementation) internal {
_setSecondaryImplementation(newImplementation);
emit UpgradedSecondary(newImplementation);
}
function _upgradeSecondaryToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeSecondaryTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
function _upgradeSecondaryToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
if (StorageSlot.getBooleanSlot(_ROLLBACK_SECONDARY_SLOT).value) {
_setSecondaryImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(
slot == _IMPLEMENTATION_SECONDARY_SLOT,
"ERC1967Upgrade: unsupported secondary proxiableUUID"
);
} catch {
revert("ERC1967Upgrade: new secondary implementation is not UUPS");
}
_upgradeSecondaryToAndCall(newImplementation, data, forceCall);
}
}
}
contract AdminFallbackProxy is Proxy, DoubleLogicERC1967Upgrade {
constructor(
address adminLogic,
bytes memory adminData,
address userLogic,
bytes memory userData,
address adminAddr
) payable {
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
assert(
_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)
);
assert(
_IMPLEMENTATION_SECONDARY_SLOT ==
bytes32(uint256(keccak256("eip1967.proxy.implementation.secondary")) - 1)
);
_changeAdmin(adminAddr);
_upgradeToAndCall(adminLogic, adminData, false);
_upgradeSecondaryToAndCall(userLogic, userData, false);
}
function _implementation() internal view override returns (address) {
require(msg.data.length >= 4, "NO_FUNC_SIG");
address target = _getAdmin() != msg.sender
? DoubleLogicERC1967Upgrade._getSecondaryImplementation()
: ERC1967Upgrade._getImplementation();
require(Address.isContract(target), "TARGET_NOT_CONTRACT");
return target;
}
function _beforeFallback() internal override {
super._beforeFallback();
}
}
文件 5 的 88:Bridge.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import {
NotContract,
NotRollupOrOwner,
NotDelayedInbox,
NotSequencerInbox,
NotOutbox,
InvalidOutboxSet
} from "../libraries/Error.sol";
import "./IBridge.sol";
import "./Messages.sol";
import "../libraries/DelegateCallAware.sol";
import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol";
contract Bridge is Initializable, DelegateCallAware, IBridge {
using AddressUpgradeable for address;
struct InOutInfo {
uint256 index;
bool allowed;
}
mapping(address => InOutInfo) private allowedDelayedInboxesMap;
mapping(address => InOutInfo) private allowedOutboxesMap;
address[] public allowedDelayedInboxList;
address[] public allowedOutboxList;
address private _activeOutbox;
bytes32[] public delayedInboxAccs;
bytes32[] public sequencerInboxAccs;
IOwnable public rollup;
address public sequencerInbox;
address private constant EMPTY_ACTIVEOUTBOX = address(type(uint160).max);
function initialize(IOwnable rollup_) external initializer onlyDelegated {
_activeOutbox = EMPTY_ACTIVEOUTBOX;
rollup = rollup_;
}
modifier onlyRollupOrOwner() {
if (msg.sender != address(rollup)) {
address rollupOwner = rollup.owner();
if (msg.sender != rollupOwner) {
revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
}
}
_;
}
function activeOutbox() public view returns (address) {
address outbox = _activeOutbox;
if (outbox == EMPTY_ACTIVEOUTBOX) return address(0);
return outbox;
}
function allowedDelayedInboxes(address inbox) external view returns (bool) {
return allowedDelayedInboxesMap[inbox].allowed;
}
function allowedOutboxes(address outbox) external view returns (bool) {
return allowedOutboxesMap[outbox].allowed;
}
modifier onlySequencerInbox() {
if (msg.sender != sequencerInbox) revert NotSequencerInbox(msg.sender);
_;
}
function enqueueSequencerMessage(bytes32 dataHash, uint256 afterDelayedMessagesRead)
external
onlySequencerInbox
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 acc
)
{
seqMessageIndex = sequencerInboxAccs.length;
if (sequencerInboxAccs.length > 0) {
beforeAcc = sequencerInboxAccs[sequencerInboxAccs.length - 1];
}
if (afterDelayedMessagesRead > 0) {
delayedAcc = delayedInboxAccs[afterDelayedMessagesRead - 1];
}
acc = keccak256(abi.encodePacked(beforeAcc, dataHash, delayedAcc));
sequencerInboxAccs.push(acc);
}
function submitBatchSpendingReport(address sender, bytes32 messageDataHash)
external
onlySequencerInbox
returns (uint256)
{
return
addMessageToDelayedAccumulator(
L1MessageType_batchPostingReport,
sender,
uint64(block.number),
uint64(block.timestamp),
block.basefee,
messageDataHash
);
}
function enqueueDelayedMessage(
uint8 kind,
address sender,
bytes32 messageDataHash
) external payable returns (uint256) {
if (!allowedDelayedInboxesMap[msg.sender].allowed) revert NotDelayedInbox(msg.sender);
return
addMessageToDelayedAccumulator(
kind,
sender,
uint64(block.number),
uint64(block.timestamp),
block.basefee,
messageDataHash
);
}
function addMessageToDelayedAccumulator(
uint8 kind,
address sender,
uint64 blockNumber,
uint64 blockTimestamp,
uint256 baseFeeL1,
bytes32 messageDataHash
) internal returns (uint256) {
uint256 count = delayedInboxAccs.length;
bytes32 messageHash = Messages.messageHash(
kind,
sender,
blockNumber,
blockTimestamp,
count,
baseFeeL1,
messageDataHash
);
bytes32 prevAcc = 0;
if (count > 0) {
prevAcc = delayedInboxAccs[count - 1];
}
delayedInboxAccs.push(Messages.accumulateInboxMessage(prevAcc, messageHash));
emit MessageDelivered(
count,
prevAcc,
msg.sender,
kind,
sender,
messageDataHash,
baseFeeL1,
blockTimestamp
);
return count;
}
function executeCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success, bytes memory returnData) {
if (!allowedOutboxesMap[msg.sender].allowed) revert NotOutbox(msg.sender);
if (data.length > 0 && !to.isContract()) revert NotContract(to);
address prevOutbox = _activeOutbox;
_activeOutbox = msg.sender;
(success, returnData) = to.call{value: value}(data);
_activeOutbox = prevOutbox;
emit BridgeCallTriggered(msg.sender, to, value, data);
}
function setSequencerInbox(address _sequencerInbox) external onlyRollupOrOwner {
sequencerInbox = _sequencerInbox;
emit SequencerInboxUpdated(_sequencerInbox);
}
function setDelayedInbox(address inbox, bool enabled) external onlyRollupOrOwner {
InOutInfo storage info = allowedDelayedInboxesMap[inbox];
bool alreadyEnabled = info.allowed;
emit InboxToggle(inbox, enabled);
if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
return;
}
if (enabled) {
allowedDelayedInboxesMap[inbox] = InOutInfo(allowedDelayedInboxList.length, true);
allowedDelayedInboxList.push(inbox);
} else {
allowedDelayedInboxList[info.index] = allowedDelayedInboxList[
allowedDelayedInboxList.length - 1
];
allowedDelayedInboxesMap[allowedDelayedInboxList[info.index]].index = info.index;
allowedDelayedInboxList.pop();
delete allowedDelayedInboxesMap[inbox];
}
}
function setOutbox(address outbox, bool enabled) external onlyRollupOrOwner {
if (outbox == EMPTY_ACTIVEOUTBOX) revert InvalidOutboxSet(outbox);
InOutInfo storage info = allowedOutboxesMap[outbox];
bool alreadyEnabled = info.allowed;
emit OutboxToggle(outbox, enabled);
if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
return;
}
if (enabled) {
allowedOutboxesMap[outbox] = InOutInfo(allowedOutboxList.length, true);
allowedOutboxList.push(outbox);
} else {
allowedOutboxList[info.index] = allowedOutboxList[allowedOutboxList.length - 1];
allowedOutboxesMap[allowedOutboxList[info.index]].index = info.index;
allowedOutboxList.pop();
delete allowedOutboxesMap[outbox];
}
}
function delayedMessageCount() external view returns (uint256) {
return delayedInboxAccs.length;
}
function sequencerMessageCount() external view returns (uint256) {
return sequencerInboxAccs.length;
}
function acceptFundsFromOldBridge() external payable {}
}
文件 6 的 88:BridgeCreator.sol
pragma solidity ^0.8.0;
import "../bridge/Bridge.sol";
import "../bridge/SequencerInbox.sol";
import "../bridge/ISequencerInbox.sol";
import "../bridge/Inbox.sol";
import "../bridge/Outbox.sol";
import "./RollupEventInbox.sol";
import "../bridge/IBridge.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
contract BridgeCreator is Ownable {
Bridge public bridgeTemplate;
SequencerInbox public sequencerInboxTemplate;
Inbox public inboxTemplate;
RollupEventInbox public rollupEventInboxTemplate;
Outbox public outboxTemplate;
event TemplatesUpdated();
constructor() Ownable() {
bridgeTemplate = new Bridge();
sequencerInboxTemplate = new SequencerInbox();
inboxTemplate = new Inbox();
rollupEventInboxTemplate = new RollupEventInbox();
outboxTemplate = new Outbox();
}
function updateTemplates(
address _bridgeTemplate,
address _sequencerInboxTemplate,
address _inboxTemplate,
address _rollupEventInboxTemplate,
address _outboxTemplate
) external onlyOwner {
bridgeTemplate = Bridge(_bridgeTemplate);
sequencerInboxTemplate = SequencerInbox(_sequencerInboxTemplate);
inboxTemplate = Inbox(_inboxTemplate);
rollupEventInboxTemplate = RollupEventInbox(_rollupEventInboxTemplate);
outboxTemplate = Outbox(_outboxTemplate);
emit TemplatesUpdated();
}
struct CreateBridgeFrame {
ProxyAdmin admin;
Bridge bridge;
SequencerInbox sequencerInbox;
Inbox inbox;
RollupEventInbox rollupEventInbox;
Outbox outbox;
}
function createBridge(
address adminProxy,
address rollup,
ISequencerInbox.MaxTimeVariation memory maxTimeVariation
)
external
returns (
Bridge,
SequencerInbox,
Inbox,
RollupEventInbox,
Outbox
)
{
CreateBridgeFrame memory frame;
{
frame.bridge = Bridge(
address(new TransparentUpgradeableProxy(address(bridgeTemplate), adminProxy, ""))
);
frame.sequencerInbox = SequencerInbox(
address(
new TransparentUpgradeableProxy(address(sequencerInboxTemplate), adminProxy, "")
)
);
frame.inbox = Inbox(
address(new TransparentUpgradeableProxy(address(inboxTemplate), adminProxy, ""))
);
frame.rollupEventInbox = RollupEventInbox(
address(
new TransparentUpgradeableProxy(
address(rollupEventInboxTemplate),
adminProxy,
""
)
)
);
frame.outbox = Outbox(
address(new TransparentUpgradeableProxy(address(outboxTemplate), adminProxy, ""))
);
}
frame.bridge.initialize(IOwnable(rollup));
frame.sequencerInbox.initialize(IBridge(frame.bridge), maxTimeVariation);
frame.inbox.initialize(IBridge(frame.bridge), ISequencerInbox(frame.sequencerInbox));
frame.rollupEventInbox.initialize(IBridge(frame.bridge));
frame.outbox.initialize(IBridge(frame.bridge));
return (
frame.bridge,
frame.sequencerInbox,
frame.inbox,
frame.rollupEventInbox,
frame.outbox
);
}
}
文件 7 的 88:BridgeStub.sol
pragma solidity ^0.8.0;
import "./InboxStub.sol";
import "../bridge/IBridge.sol";
contract BridgeStub is IBridge {
struct InOutInfo {
uint256 index;
bool allowed;
}
mapping(address => InOutInfo) private allowedDelayedInboxesMap;
address[] public allowedDelayedInboxList;
address[] public allowedOutboxList;
address public override activeOutbox;
bytes32[] public override delayedInboxAccs;
bytes32[] public override sequencerInboxAccs;
address public sequencerInbox;
function setSequencerInbox(address _sequencerInbox) external override {
sequencerInbox = _sequencerInbox;
emit SequencerInboxUpdated(_sequencerInbox);
}
function allowedDelayedInboxes(address inbox) external view override returns (bool) {
return allowedDelayedInboxesMap[inbox].allowed;
}
function allowedOutboxes(address) external pure override returns (bool) {
revert("NOT_IMPLEMENTED");
}
function enqueueDelayedMessage(
uint8 kind,
address sender,
bytes32 messageDataHash
) external payable override returns (uint256) {
require(allowedDelayedInboxesMap[msg.sender].allowed, "NOT_FROM_INBOX");
return
addMessageToDelayedAccumulator(
kind,
sender,
block.number,
block.timestamp,
block.basefee,
messageDataHash
);
}
function enqueueSequencerMessage(bytes32 dataHash, uint256 afterDelayedMessagesRead)
external
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 acc
)
{
seqMessageIndex = sequencerInboxAccs.length;
if (sequencerInboxAccs.length > 0) {
beforeAcc = sequencerInboxAccs[sequencerInboxAccs.length - 1];
}
if (afterDelayedMessagesRead > 0) {
delayedAcc = delayedInboxAccs[afterDelayedMessagesRead - 1];
}
acc = keccak256(abi.encodePacked(beforeAcc, dataHash, delayedAcc));
sequencerInboxAccs.push(acc);
}
function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
external
returns (uint256)
{
}
function addMessageToDelayedAccumulator(
uint8,
address,
uint256,
uint256,
uint256,
bytes32 messageDataHash
) internal returns (uint256) {
uint256 count = delayedInboxAccs.length;
bytes32 messageHash = Messages.messageHash(
0,
address(uint160(0)),
0,
0,
0,
0,
messageDataHash
);
bytes32 prevAcc = 0;
if (count > 0) {
prevAcc = delayedInboxAccs[count - 1];
}
delayedInboxAccs.push(Messages.accumulateInboxMessage(prevAcc, messageHash));
return count;
}
function executeCall(
address,
uint256,
bytes calldata
) external pure override returns (bool, bytes memory) {
revert("NOT_IMPLEMENTED");
}
function setDelayedInbox(address inbox, bool enabled) external override {
InOutInfo storage info = allowedDelayedInboxesMap[inbox];
bool alreadyEnabled = info.allowed;
emit InboxToggle(inbox, enabled);
if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
return;
}
if (enabled) {
allowedDelayedInboxesMap[inbox] = InOutInfo(allowedDelayedInboxList.length, true);
allowedDelayedInboxList.push(inbox);
} else {
allowedDelayedInboxList[info.index] = allowedDelayedInboxList[
allowedDelayedInboxList.length - 1
];
allowedDelayedInboxesMap[allowedDelayedInboxList[info.index]].index = info.index;
allowedDelayedInboxList.pop();
delete allowedDelayedInboxesMap[inbox];
}
}
function setOutbox(
address,
bool
) external pure override {
revert("NOT_IMPLEMENTED");
}
function delayedMessageCount() external view override returns (uint256) {
return delayedInboxAccs.length;
}
function sequencerMessageCount() external view override returns (uint256) {
return sequencerInboxAccs.length;
}
function rollup() external pure override returns (IOwnable) {
revert("NOT_IMPLEMENTED");
}
function acceptFundsFromOldBridge() external payable {}
function initialize(IOwnable) external pure {
revert("NOT_IMPLEMENTED");
}
}
文件 8 的 88:BridgeTester.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import {
NotContract,
NotRollupOrOwner,
NotDelayedInbox,
NotSequencerInbox,
NotOutbox,
InvalidOutboxSet
} from "../libraries/Error.sol";
import "../bridge/IBridge.sol";
import "../bridge/Messages.sol";
import "../libraries/DelegateCallAware.sol";
contract BridgeTester is Initializable, DelegateCallAware, IBridge {
using AddressUpgradeable for address;
struct InOutInfo {
uint256 index;
bool allowed;
}
mapping(address => InOutInfo) private allowedInboxesMap;
mapping(address => InOutInfo) private allowedOutboxesMap;
address[] public allowedDelayedInboxList;
address[] public allowedOutboxList;
address private _activeOutbox;
IOwnable public rollup;
address public sequencerInbox;
modifier onlyRollupOrOwner() {
if (msg.sender != address(rollup)) {
address rollupOwner = rollup.owner();
if (msg.sender != rollupOwner) {
revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
}
}
_;
}
function setSequencerInbox(address _sequencerInbox) external override onlyRollupOrOwner {
sequencerInbox = _sequencerInbox;
emit SequencerInboxUpdated(_sequencerInbox);
}
bytes32[] public override delayedInboxAccs;
bytes32[] public override sequencerInboxAccs;
address private constant EMPTY_ACTIVEOUTBOX = address(type(uint160).max);
function initialize(IOwnable rollup_) external initializer {
_activeOutbox = EMPTY_ACTIVEOUTBOX;
rollup = rollup_;
}
function activeOutbox() public view returns (address) {
if (_activeOutbox == EMPTY_ACTIVEOUTBOX) return address(uint160(0));
return _activeOutbox;
}
function allowedDelayedInboxes(address inbox) external view override returns (bool) {
return allowedInboxesMap[inbox].allowed;
}
function allowedOutboxes(address outbox) external view override returns (bool) {
return allowedOutboxesMap[outbox].allowed;
}
function enqueueSequencerMessage(bytes32 dataHash, uint256 afterDelayedMessagesRead)
external
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 acc
)
{
}
function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
external
returns (uint256)
{
}
function enqueueDelayedMessage(
uint8 kind,
address sender,
bytes32 messageDataHash
) external payable override returns (uint256) {
if (!allowedInboxesMap[msg.sender].allowed) revert NotDelayedInbox(msg.sender);
return
addMessageToDelayedAccumulator(
kind,
sender,
uint64(block.number),
uint64(block.timestamp),
block.basefee,
messageDataHash
);
}
function addMessageToDelayedAccumulator(
uint8 kind,
address sender,
uint64 blockNumber,
uint64 blockTimestamp,
uint256 baseFeeL1,
bytes32 messageDataHash
) internal returns (uint256) {
uint256 count = delayedInboxAccs.length;
bytes32 messageHash = Messages.messageHash(
kind,
sender,
blockNumber,
blockTimestamp,
count,
baseFeeL1,
messageDataHash
);
bytes32 prevAcc = 0;
if (count > 0) {
prevAcc = delayedInboxAccs[count - 1];
}
delayedInboxAccs.push(Messages.accumulateInboxMessage(prevAcc, messageHash));
emit MessageDelivered(
count,
prevAcc,
msg.sender,
kind,
sender,
messageDataHash,
baseFeeL1,
blockTimestamp
);
return count;
}
function executeCall(
address to,
uint256 value,
bytes calldata data
) external override returns (bool success, bytes memory returnData) {
if (!allowedOutboxesMap[msg.sender].allowed) revert NotOutbox(msg.sender);
if (data.length > 0 && !to.isContract()) revert NotContract(to);
address prevOutbox = _activeOutbox;
_activeOutbox = msg.sender;
(success, returnData) = to.call{value: value}(data);
_activeOutbox = prevOutbox;
emit BridgeCallTriggered(msg.sender, to, value, data);
}
function setDelayedInbox(address inbox, bool enabled) external override onlyRollupOrOwner {
InOutInfo storage info = allowedInboxesMap[inbox];
bool alreadyEnabled = info.allowed;
emit InboxToggle(inbox, enabled);
if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
return;
}
if (enabled) {
allowedInboxesMap[inbox] = InOutInfo(allowedDelayedInboxList.length, true);
allowedDelayedInboxList.push(inbox);
} else {
allowedDelayedInboxList[info.index] = allowedDelayedInboxList[
allowedDelayedInboxList.length - 1
];
allowedInboxesMap[allowedDelayedInboxList[info.index]].index = info.index;
allowedDelayedInboxList.pop();
delete allowedInboxesMap[inbox];
}
}
function setOutbox(address outbox, bool enabled) external override onlyRollupOrOwner {
InOutInfo storage info = allowedOutboxesMap[outbox];
bool alreadyEnabled = info.allowed;
emit OutboxToggle(outbox, enabled);
if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) {
return;
}
if (enabled) {
allowedOutboxesMap[outbox] = InOutInfo(allowedOutboxList.length, true);
allowedOutboxList.push(outbox);
} else {
allowedOutboxList[info.index] = allowedOutboxList[allowedOutboxList.length - 1];
allowedOutboxesMap[allowedOutboxList[info.index]].index = info.index;
allowedOutboxList.pop();
delete allowedOutboxesMap[outbox];
}
}
function delayedMessageCount() external view override returns (uint256) {
return delayedInboxAccs.length;
}
function sequencerMessageCount() external view override returns (uint256) {
return sequencerInboxAccs.length;
}
receive() external payable {}
function acceptFundsFromOldBridge() external payable {}
}
文件 9 的 88:ChallengeLib.sol
pragma solidity ^0.8.0;
import "../state/Machine.sol";
import "../state/GlobalState.sol";
library ChallengeLib {
using MachineLib for Machine;
using ChallengeLib for Challenge;
enum ChallengeMode {
NONE,
BLOCK,
EXECUTION
}
struct Participant {
address addr;
uint256 timeLeft;
}
struct Challenge {
Participant current;
Participant next;
uint256 lastMoveTimestamp;
bytes32 wasmModuleRoot;
bytes32 challengeStateHash;
uint64 maxInboxMessages;
ChallengeMode mode;
}
struct SegmentSelection {
uint256 oldSegmentsStart;
uint256 oldSegmentsLength;
bytes32[] oldSegments;
uint256 challengePosition;
}
function timeUsedSinceLastMove(Challenge storage challenge) internal view returns (uint256) {
return block.timestamp - challenge.lastMoveTimestamp;
}
function isTimedOut(Challenge storage challenge) internal view returns (bool) {
return challenge.timeUsedSinceLastMove() > challenge.current.timeLeft;
}
function getStartMachineHash(bytes32 globalStateHash, bytes32 wasmModuleRoot)
internal
pure
returns (bytes32)
{
Value[] memory startingValues = new Value[](3);
startingValues[0] = ValueLib.newRefNull();
startingValues[1] = ValueLib.newI32(0);
startingValues[2] = ValueLib.newI32(0);
ValueArray memory valuesArray = ValueArray({inner: startingValues});
ValueStack memory values = ValueStack({proved: valuesArray, remainingHash: 0});
ValueStack memory internalStack;
StackFrameWindow memory frameStack;
Machine memory mach = Machine({
status: MachineStatus.RUNNING,
valueStack: values,
internalStack: internalStack,
frameStack: frameStack,
globalStateHash: globalStateHash,
moduleIdx: 0,
functionIdx: 0,
functionPc: 0,
modulesRoot: wasmModuleRoot
});
return mach.hash();
}
function getEndMachineHash(MachineStatus status, bytes32 globalStateHash)
internal
pure
returns (bytes32)
{
if (status == MachineStatus.FINISHED) {
return keccak256(abi.encodePacked("Machine finished:", globalStateHash));
} else if (status == MachineStatus.ERRORED) {
return keccak256(abi.encodePacked("Machine errored:"));
} else if (status == MachineStatus.TOO_FAR) {
return keccak256(abi.encodePacked("Machine too far:"));
} else {
revert("BAD_BLOCK_STATUS");
}
}
function extractChallengeSegment(SegmentSelection calldata selection)
internal
pure
returns (uint256 segmentStart, uint256 segmentLength)
{
uint256 oldChallengeDegree = selection.oldSegments.length - 1;
segmentLength = selection.oldSegmentsLength / oldChallengeDegree;
segmentStart = selection.oldSegmentsStart + segmentLength * selection.challengePosition;
if (selection.challengePosition == selection.oldSegments.length - 2) {
segmentLength += selection.oldSegmentsLength % oldChallengeDegree;
}
}
function hashChallengeState(
uint256 segmentsStart,
uint256 segmentsLength,
bytes32[] memory segments
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(segmentsStart, segmentsLength, segments));
}
function blockStateHash(MachineStatus status, bytes32 globalStateHash)
internal
pure
returns (bytes32)
{
if (status == MachineStatus.FINISHED) {
return keccak256(abi.encodePacked("Block state:", globalStateHash));
} else if (status == MachineStatus.ERRORED) {
return keccak256(abi.encodePacked("Block state, errored:", globalStateHash));
} else if (status == MachineStatus.TOO_FAR) {
return keccak256(abi.encodePacked("Block state, too far:"));
} else {
revert("BAD_BLOCK_STATUS");
}
}
}
文件 10 的 88:ChallengeManager.sol
pragma solidity ^0.8.0;
import "../libraries/DelegateCallAware.sol";
import "../osp/IOneStepProofEntry.sol";
import "../state/GlobalState.sol";
import "./IChallengeResultReceiver.sol";
import "./ChallengeLib.sol";
import "./IChallengeManager.sol";
import {NO_CHAL_INDEX} from "../libraries/Constants.sol";
contract ChallengeManager is DelegateCallAware, IChallengeManager {
using GlobalStateLib for GlobalState;
using MachineLib for Machine;
using ChallengeLib for ChallengeLib.Challenge;
enum ChallengeModeRequirement {
ANY,
BLOCK,
EXECUTION
}
string private constant NO_CHAL = "NO_CHAL";
uint256 private constant MAX_CHALLENGE_DEGREE = 40;
uint64 public totalChallengesCreated;
mapping(uint256 => ChallengeLib.Challenge) public challenges;
IChallengeResultReceiver public resultReceiver;
ISequencerInbox public sequencerInbox;
IBridge public bridge;
IOneStepProofEntry public osp;
function challengeInfo(uint64 challengeIndex)
external
view
override
returns (ChallengeLib.Challenge memory)
{
return challenges[challengeIndex];
}
modifier takeTurn(
uint64 challengeIndex,
ChallengeLib.SegmentSelection calldata selection,
ChallengeModeRequirement expectedMode
) {
ChallengeLib.Challenge storage challenge = challenges[challengeIndex];
require(msg.sender == currentResponder(challengeIndex), "CHAL_SENDER");
require(!isTimedOut(challengeIndex), "CHAL_DEADLINE");
if (expectedMode == ChallengeModeRequirement.ANY) {
require(challenge.mode != ChallengeLib.ChallengeMode.NONE, NO_CHAL);
} else if (expectedMode == ChallengeModeRequirement.BLOCK) {
require(challenge.mode == ChallengeLib.ChallengeMode.BLOCK, "CHAL_NOT_BLOCK");
} else if (expectedMode == ChallengeModeRequirement.EXECUTION) {
require(challenge.mode == ChallengeLib.ChallengeMode.EXECUTION, "CHAL_NOT_EXECUTION");
} else {
assert(false);
}
require(
challenge.challengeStateHash ==
ChallengeLib.hashChallengeState(
selection.oldSegmentsStart,
selection.oldSegmentsLength,
selection.oldSegments
),
"BIS_STATE"
);
if (
selection.oldSegments.length < 2 ||
selection.challengePosition >= selection.oldSegments.length - 1
) {
revert("BAD_CHALLENGE_POS");
}
_;
if (challenge.mode == ChallengeLib.ChallengeMode.NONE) {
return;
}
ChallengeLib.Participant memory current = challenge.current;
current.timeLeft -= block.timestamp - challenge.lastMoveTimestamp;
challenge.current = challenge.next;
challenge.next = current;
challenge.lastMoveTimestamp = block.timestamp;
}
function initialize(
IChallengeResultReceiver resultReceiver_,
ISequencerInbox sequencerInbox_,
IBridge bridge_,
IOneStepProofEntry osp_
) external override onlyDelegated {
require(address(resultReceiver) == address(0), "ALREADY_INIT");
require(address(resultReceiver_) != address(0), "NO_RESULT_RECEIVER");
resultReceiver = resultReceiver_;
sequencerInbox = sequencerInbox_;
bridge = bridge_;
osp = osp_;
}
function createChallenge(
bytes32 wasmModuleRoot_,
MachineStatus[2] calldata startAndEndMachineStatuses_,
GlobalState[2] calldata startAndEndGlobalStates_,
uint64 numBlocks,
address asserter_,
address challenger_,
uint256 asserterTimeLeft_,
uint256 challengerTimeLeft_
) external override returns (uint64) {
require(msg.sender == address(resultReceiver), "ONLY_ROLLUP_CHAL");
bytes32[] memory segments = new bytes32[](2);
segments[0] = ChallengeLib.blockStateHash(
startAndEndMachineStatuses_[0],
startAndEndGlobalStates_[0].hash()
);
segments[1] = ChallengeLib.blockStateHash(
startAndEndMachineStatuses_[1],
startAndEndGlobalStates_[1].hash()
);
uint64 challengeIndex = ++totalChallengesCreated;
assert(challengeIndex != NO_CHAL_INDEX);
ChallengeLib.Challenge storage challenge = challenges[challengeIndex];
challenge.wasmModuleRoot = wasmModuleRoot_;
uint64 maxInboxMessagesRead = startAndEndGlobalStates_[1].getInboxPosition();
if (
startAndEndMachineStatuses_[1] == MachineStatus.ERRORED ||
startAndEndGlobalStates_[1].getPositionInMessage() > 0
) {
maxInboxMessagesRead++;
}
challenge.maxInboxMessages = maxInboxMessagesRead;
challenge.next = ChallengeLib.Participant({addr: asserter_, timeLeft: asserterTimeLeft_});
challenge.current = ChallengeLib.Participant({
addr: challenger_,
timeLeft: challengerTimeLeft_
});
challenge.lastMoveTimestamp = block.timestamp;
challenge.mode = ChallengeLib.ChallengeMode.BLOCK;
emit InitiatedChallenge(
challengeIndex,
startAndEndGlobalStates_[0],
startAndEndGlobalStates_[1]
);
completeBisection(challengeIndex, 0, numBlocks, segments);
return challengeIndex;
}
function bisectExecution(
uint64 challengeIndex,
ChallengeLib.SegmentSelection calldata selection,
bytes32[] calldata newSegments
) external takeTurn(challengeIndex, selection, ChallengeModeRequirement.ANY) {
(uint256 challengeStart, uint256 challengeLength) = ChallengeLib.extractChallengeSegment(
selection
);
require(challengeLength > 1, "TOO_SHORT");
{
uint256 expectedDegree = challengeLength;
if (expectedDegree > MAX_CHALLENGE_DEGREE) {
expectedDegree = MAX_CHALLENGE_DEGREE;
}
require(newSegments.length == expectedDegree + 1, "WRONG_DEGREE");
}
requireValidBisection(selection, newSegments[0], newSegments[newSegments.length - 1]);
completeBisection(challengeIndex, challengeStart, challengeLength, newSegments);
}
function challengeExecution(
uint64 challengeIndex,
ChallengeLib.SegmentSelection calldata selection,
MachineStatus[2] calldata machineStatuses,
bytes32[2] calldata globalStateHashes,
uint256 numSteps
) external takeTurn(challengeIndex, selection, ChallengeModeRequirement.BLOCK) {
require(numSteps >= 1, "CHALLENGE_TOO_SHORT");
require(numSteps <= OneStepProofEntryLib.MAX_STEPS, "CHALLENGE_TOO_LONG");
requireValidBisection(
selection,
ChallengeLib.blockStateHash(machineStatuses[0], globalStateHashes[0]),
ChallengeLib.blockStateHash(machineStatuses[1], globalStateHashes[1])
);
ChallengeLib.Challenge storage challenge = challenges[challengeIndex];
(uint256 executionChallengeAtSteps, uint256 challengeLength) = ChallengeLib
.extractChallengeSegment(selection);
require(challengeLength == 1, "TOO_LONG");
if (machineStatuses[0] != MachineStatus.FINISHED) {
require(
machineStatuses[0] == machineStatuses[1] &&
globalStateHashes[0] == globalStateHashes[1],
"HALTED_CHANGE"
);
_currentWin(challengeIndex, ChallengeTerminationType.BLOCK_PROOF);
return;
}
if (machineStatuses[1] == MachineStatus.ERRORED) {
require(globalStateHashes[0] == globalStateHashes[1], "ERROR_CHANGE");
}
bytes32[] memory segments = new bytes32[](2);
segments[0] = ChallengeLib.getStartMachineHash(
globalStateHashes[0],
challenge.wasmModuleRoot
);
segments[1] = ChallengeLib.getEndMachineHash(machineStatuses[1], globalStateHashes[1]);
challenge.mode = ChallengeLib.ChallengeMode.EXECUTION;
completeBisection(challengeIndex, 0, numSteps, segments);
emit ExecutionChallengeBegun(challengeIndex, executionChallengeAtSteps);
}
function oneStepProveExecution(
uint64 challengeIndex,
ChallengeLib.SegmentSelection calldata selection,
bytes calldata proof
) external takeTurn(challengeIndex, selection, ChallengeModeRequirement.EXECUTION) {
ChallengeLib.Challenge storage challenge = challenges[challengeIndex];
uint256 challengeStart;
{
uint256 challengeLength;
(challengeStart, challengeLength) = ChallengeLib.extractChallengeSegment(selection);
require(challengeLength == 1, "TOO_LONG");
}
bytes32 afterHash = osp.proveOneStep(
ExecutionContext({maxInboxMessagesRead: challenge.maxInboxMessages, bridge: bridge}),
challengeStart,
selection.oldSegments[selection.challengePosition],
proof
);
require(
afterHash != selection.oldSegments[selection.challengePosition + 1],
"SAME_OSP_END"
);
emit OneStepProofCompleted(challengeIndex);
_currentWin(challengeIndex, ChallengeTerminationType.EXECUTION_PROOF);
}
function timeout(uint64 challengeIndex) external override {
require(challenges[challengeIndex].mode != ChallengeLib.ChallengeMode.NONE, NO_CHAL);
require(isTimedOut(challengeIndex), "TIMEOUT_DEADLINE");
_nextWin(challengeIndex, ChallengeTerminationType.TIMEOUT);
}
function clearChallenge(uint64 challengeIndex) external override {
require(msg.sender == address(resultReceiver), "NOT_RES_RECEIVER");
require(challenges[challengeIndex].mode != ChallengeLib.ChallengeMode.NONE, NO_CHAL);
delete challenges[challengeIndex];
emit ChallengeEnded(challengeIndex, ChallengeTerminationType.CLEARED);
}
function currentResponder(uint64 challengeIndex) public view override returns (address) {
return challenges[challengeIndex].current.addr;
}
function currentResponderTimeLeft(uint64 challengeIndex)
public
view
override
returns (uint256)
{
return challenges[challengeIndex].current.timeLeft;
}
function isTimedOut(uint64 challengeIndex) public view override returns (bool) {
return challenges[challengeIndex].isTimedOut();
}
function requireValidBisection(
ChallengeLib.SegmentSelection calldata selection,
bytes32 startHash,
bytes32 endHash
) private pure {
require(selection.oldSegments[selection.challengePosition] == startHash, "WRONG_START");
require(selection.oldSegments[selection.challengePosition + 1] != endHash, "SAME_END");
}
function completeBisection(
uint64 challengeIndex,
uint256 challengeStart,
uint256 challengeLength,
bytes32[] memory newSegments
) private {
assert(challengeLength >= 1);
assert(newSegments.length >= 2);
bytes32 challengeStateHash = ChallengeLib.hashChallengeState(
challengeStart,
challengeLength,
newSegments
);
challenges[challengeIndex].challengeStateHash = challengeStateHash;
emit Bisected(
challengeIndex,
challengeStateHash,
challengeStart,
challengeLength,
newSegments
);
}
function _nextWin(uint64 challengeIndex, ChallengeTerminationType reason) private {
ChallengeLib.Challenge storage challenge = challenges[challengeIndex];
address next = challenge.next.addr;
address current = challenge.current.addr;
delete challenges[challengeIndex];
resultReceiver.completeChallenge(challengeIndex, next, current);
emit ChallengeEnded(challengeIndex, reason);
}
function _currentWin(
uint64 challengeIndex,
ChallengeTerminationType
) private {
ChallengeLib.Challenge storage challenge = challenges[challengeIndex];
challenge.challengeStateHash = bytes32(0);
}
}
文件 11 的 88:Constants.sol
pragma solidity ^0.8.4;
uint256 constant MAX_DATA_SIZE = 117964;
uint64 constant NO_CHAL_INDEX = 0;
文件 12 的 88:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 13 的 88:ContextUpgradeable.sol
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
uint256[50] private __gap;
}
文件 14 的 88:DelegateCallAware.sol
pragma solidity ^0.8.0;
import {NotOwner} from "./Error.sol";
abstract contract DelegateCallAware {
address private immutable __self = address(this);
modifier onlyDelegated() {
require(address(this) != __self, "Function must be called through delegatecall");
_;
}
modifier notDelegated() {
require(address(this) == __self, "Function must not be called through delegatecall");
_;
}
modifier onlyProxyOwner() {
bytes32 slot = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
address admin;
assembly {
admin := sload(slot)
}
if (msg.sender != admin) revert NotOwner(msg.sender, admin);
_;
}
}
文件 15 的 88:Deserialize.sol
pragma solidity ^0.8.0;
import "./Value.sol";
import "./ValueStack.sol";
import "./Machine.sol";
import "./Instructions.sol";
import "./StackFrame.sol";
import "./MerkleProof.sol";
import "./ModuleMemory.sol";
import "./Module.sol";
import "./GlobalState.sol";
library Deserialize {
function u8(bytes calldata proof, uint256 startOffset)
internal
pure
returns (uint8 ret, uint256 offset)
{
offset = startOffset;
ret = uint8(proof[offset]);
offset++;
}
function u16(bytes calldata proof, uint256 startOffset)
internal
pure
returns (uint16 ret, uint256 offset)
{
offset = startOffset;
for (uint256 i = 0; i < 16 / 8; i++) {
ret <<= 8;
ret |= uint8(proof[offset]);
offset++;
}
}
function u32(bytes calldata proof, uint256 startOffset)
internal
pure
returns (uint32 ret, uint256 offset)
{
offset = startOffset;
for (uint256 i = 0; i < 32 / 8; i++) {
ret <<= 8;
ret |= uint8(proof[offset]);
offset++;
}
}
function u64(bytes calldata proof, uint256 startOffset)
internal
pure
returns (uint64 ret, uint256 offset)
{
offset = startOffset;
for (uint256 i = 0; i < 64 / 8; i++) {
ret <<= 8;
ret |= uint8(proof[offset]);
offset++;
}
}
function u256(bytes calldata proof, uint256 startOffset)
internal
pure
returns (uint256 ret, uint256 offset)
{
offset = startOffset;
for (uint256 i = 0; i < 256 / 8; i++) {
ret <<= 8;
ret |= uint8(proof[offset]);
offset++;
}
}
function b32(bytes calldata proof, uint256 startOffset)
internal
pure
returns (bytes32 ret, uint256 offset)
{
offset = startOffset;
uint256 retInt;
(retInt, offset) = u256(proof, offset);
ret = bytes32(retInt);
}
function value(bytes calldata proof, uint256 startOffset)
internal
pure
returns (Value memory val, uint256 offset)
{
offset = startOffset;
uint8 typeInt = uint8(proof[offset]);
offset++;
require(typeInt <= uint8(ValueLib.maxValueType()), "BAD_VALUE_TYPE");
uint256 contents;
(contents, offset) = u256(proof, offset);
val = Value({valueType: ValueType(typeInt), contents: contents});
}
function valueStack(bytes calldata proof, uint256 startOffset)
internal
pure
returns (ValueStack memory stack, uint256 offset)
{
offset = startOffset;
bytes32 remainingHash;
(remainingHash, offset) = b32(proof, offset);
uint256 provedLength;
(provedLength, offset) = u256(proof, offset);
Value[] memory proved = new Value[](provedLength);
for (uint256 i = 0; i < proved.length; i++) {
(proved[i], offset) = value(proof, offset);
}
stack = ValueStack({proved: ValueArray(proved), remainingHash: remainingHash});
}
function instruction(bytes calldata proof, uint256 startOffset)
internal
pure
returns (Instruction memory inst, uint256 offset)
{
offset = startOffset;
uint16 opcode;
uint256 data;
(opcode, offset) = u16(proof, offset);
(data, offset) = u256(proof, offset);
inst = Instruction({opcode: opcode, argumentData: data});
}
function stackFrame(bytes calldata proof, uint256 startOffset)
internal
pure
returns (StackFrame memory window, uint256 offset)
{
offset = startOffset;
Value memory returnPc;
bytes32 localsMerkleRoot;
uint32 callerModule;
uint32 callerModuleInternals;
(returnPc, offset) = value(proof, offset);
(localsMerkleRoot, offset) = b32(proof, offset);
(callerModule, offset) = u32(proof, offset);
(callerModuleInternals, offset) = u32(proof, offset);
window = StackFrame({
returnPc: returnPc,
localsMerkleRoot: localsMerkleRoot,
callerModule: callerModule,
callerModuleInternals: callerModuleInternals
});
}
function stackFrameWindow(bytes calldata proof, uint256 startOffset)
internal
pure
returns (StackFrameWindow memory window, uint256 offset)
{
offset = startOffset;
bytes32 remainingHash;
(remainingHash, offset) = b32(proof, offset);
StackFrame[] memory proved;
if (proof[offset] != 0) {
offset++;
proved = new StackFrame[](1);
(proved[0], offset) = stackFrame(proof, offset);
} else {
offset++;
proved = new StackFrame[](0);
}
window = StackFrameWindow({proved: proved, remainingHash: remainingHash});
}
function moduleMemory(bytes calldata proof, uint256 startOffset)
internal
pure
returns (ModuleMemory memory mem, uint256 offset)
{
offset = startOffset;
uint64 size;
uint64 maxSize;
bytes32 root;
(size, offset) = u64(proof, offset);
(maxSize, offset) = u64(proof, offset);
(root, offset) = b32(proof, offset);
mem = ModuleMemory({size: size, maxSize: maxSize, merkleRoot: root});
}
function module(bytes calldata proof, uint256 startOffset)
internal
pure
returns (Module memory mod, uint256 offset)
{
offset = startOffset;
bytes32 globalsMerkleRoot;
ModuleMemory memory mem;
bytes32 tablesMerkleRoot;
bytes32 functionsMerkleRoot;
uint32 internalsOffset;
(globalsMerkleRoot, offset) = b32(proof, offset);
(mem, offset) = moduleMemory(proof, offset);
(tablesMerkleRoot, offset) = b32(proof, offset);
(functionsMerkleRoot, offset) = b32(proof, offset);
(internalsOffset, offset) = u32(proof, offset);
mod = Module({
globalsMerkleRoot: globalsMerkleRoot,
moduleMemory: mem,
tablesMerkleRoot: tablesMerkleRoot,
functionsMerkleRoot: functionsMerkleRoot,
internalsOffset: internalsOffset
});
}
function globalState(bytes calldata proof, uint256 startOffset)
internal
pure
returns (GlobalState memory state, uint256 offset)
{
offset = startOffset;
bytes32[2] memory bytes32Vals;
uint64[2] memory u64Vals;
for (uint8 i = 0; i < GlobalStateLib.BYTES32_VALS_NUM; i++) {
(bytes32Vals[i], offset) = b32(proof, offset);
}
for (uint8 i = 0; i < GlobalStateLib.U64_VALS_NUM; i++) {
(u64Vals[i], offset) = u64(proof, offset);
}
state = GlobalState({bytes32Vals: bytes32Vals, u64Vals: u64Vals});
}
function machine(bytes calldata proof, uint256 startOffset)
internal
pure
returns (Machine memory mach, uint256 offset)
{
offset = startOffset;
MachineStatus status;
{
uint8 statusU8;
(statusU8, offset) = u8(proof, offset);
if (statusU8 == 0) {
status = MachineStatus.RUNNING;
} else if (statusU8 == 1) {
status = MachineStatus.FINISHED;
} else if (statusU8 == 2) {
status = MachineStatus.ERRORED;
} else if (statusU8 == 3) {
status = MachineStatus.TOO_FAR;
} else {
revert("UNKNOWN_MACH_STATUS");
}
}
ValueStack memory values;
ValueStack memory internalStack;
bytes32 globalStateHash;
uint32 moduleIdx;
uint32 functionIdx;
uint32 functionPc;
StackFrameWindow memory frameStack;
bytes32 modulesRoot;
(values, offset) = valueStack(proof, offset);
(internalStack, offset) = valueStack(proof, offset);
(frameStack, offset) = stackFrameWindow(proof, offset);
(globalStateHash, offset) = b32(proof, offset);
(moduleIdx, offset) = u32(proof, offset);
(functionIdx, offset) = u32(proof, offset);
(functionPc, offset) = u32(proof, offset);
(modulesRoot, offset) = b32(proof, offset);
mach = Machine({
status: status,
valueStack: values,
internalStack: internalStack,
frameStack: frameStack,
globalStateHash: globalStateHash,
moduleIdx: moduleIdx,
functionIdx: functionIdx,
functionPc: functionPc,
modulesRoot: modulesRoot
});
}
function merkleProof(bytes calldata proof, uint256 startOffset)
internal
pure
returns (MerkleProof memory merkle, uint256 offset)
{
offset = startOffset;
uint8 length;
(length, offset) = u8(proof, offset);
bytes32[] memory counterparts = new bytes32[](length);
for (uint8 i = 0; i < length; i++) {
(counterparts[i], offset) = b32(proof, offset);
}
merkle = MerkleProof(counterparts);
}
}
文件 16 的 88:DoubleLogicUUPSUpgradeable.sol
pragma solidity ^0.8.0;
import {DoubleLogicERC1967Upgrade} from "./AdminFallbackProxy.sol";
import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
abstract contract DoubleLogicUUPSUpgradeable is UUPSUpgradeable, DoubleLogicERC1967Upgrade {
function proxiableUUID() external view override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
function _authorizeSecondaryUpgrade(address newImplementation) internal virtual;
function upgradeSecondaryTo(address newImplementation) external onlyProxy {
_authorizeSecondaryUpgrade(newImplementation);
_upgradeSecondaryToAndCallUUPS(newImplementation, new bytes(0), false);
}
function upgradeSecondaryToAndCall(address newImplementation, bytes memory data)
external
payable
onlyProxy
{
_authorizeSecondaryUpgrade(newImplementation);
_upgradeSecondaryToAndCallUUPS(newImplementation, data, true);
}
}
文件 17 的 88:ERC1967Proxy.sol
pragma solidity ^0.8.0;
import "../Proxy.sol";
import "./ERC1967Upgrade.sol";
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
constructor(address _logic, bytes memory _data) payable {
assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
_upgradeToAndCall(_logic, _data, false);
}
function _implementation() internal view virtual override returns (address impl) {
return ERC1967Upgrade._getImplementation();
}
}
文件 18 的 88:ERC1967Upgrade.sol
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
abstract contract ERC1967Upgrade {
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
event Upgraded(address indexed implementation);
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
event AdminChanged(address previousAdmin, address newAdmin);
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
event BeaconUpgraded(address indexed beacon);
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}
文件 19 的 88:Error.sol
pragma solidity ^0.8.4;
error AlreadyInit();
error HadZeroInit();
error NotOwner(address sender, address owner);
error NotRollup(address sender, address rollup);
error NotOrigin();
error DataTooLarge(uint256 dataLength, uint256 maxDataLength);
error NotContract(address addr);
error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength);
error NotRollupOrOwner(address sender, address rollup, address owner);
error NotDelayedInbox(address sender);
error NotSequencerInbox(address sender);
error NotOutbox(address sender);
error InvalidOutboxSet(address outbox);
error AlreadyPaused();
error AlreadyUnpaused();
error Paused();
error InsufficientValue(uint256 expected, uint256 actual);
error InsufficientSubmissionCost(uint256 expected, uint256 actual);
error NotAllowedOrigin(address origin);
error RetryableData(
address from,
address to,
uint256 l2CallValue,
uint256 deposit,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes data
);
error ProofTooLong(uint256 proofLength);
error PathNotMinimal(uint256 index, uint256 maxIndex);
error UnknownRoot(bytes32 root);
error AlreadySpent(uint256 index);
error BridgeCallFailed();
error DelayedBackwards();
error DelayedTooFar();
error ForceIncludeBlockTooSoon();
error ForceIncludeTimeTooSoon();
error IncorrectMessagePreimage();
error NotBatchPoster();
error BadSequencerNumber(uint256 stored, uint256 received);
error DataNotAuthenticated();
error AlreadyValidDASKeyset(bytes32);
error NoSuchKeyset(bytes32);
文件 20 的 88:ExecutionManager.sol
pragma solidity ^0.8.0;
import "../challenge/ChallengeManager.sol";
contract SingleExecutionChallenge is ChallengeManager {
constructor(
IOneStepProofEntry osp_,
IChallengeResultReceiver resultReceiver_,
uint64 maxInboxMessagesRead_,
bytes32[2] memory startAndEndHashes,
uint256 numSteps_,
address asserter_,
address challenger_,
uint256 asserterTimeLeft_,
uint256 challengerTimeLeft_
) {
osp = osp_;
resultReceiver = resultReceiver_;
uint64 challengeIndex = ++totalChallengesCreated;
ChallengeLib.Challenge storage challenge = challenges[challengeIndex];
challenge.maxInboxMessages = maxInboxMessagesRead_;
bytes32[] memory segments = new bytes32[](2);
segments[0] = startAndEndHashes[0];
segments[1] = startAndEndHashes[1];
bytes32 challengeStateHash = ChallengeLib.hashChallengeState(0, numSteps_, segments);
challenge.challengeStateHash = challengeStateHash;
challenge.next = ChallengeLib.Participant({addr: asserter_, timeLeft: asserterTimeLeft_});
challenge.current = ChallengeLib.Participant({
addr: challenger_,
timeLeft: challengerTimeLeft_
});
challenge.lastMoveTimestamp = block.timestamp;
challenge.mode = ChallengeLib.ChallengeMode.EXECUTION;
emit Bisected(challengeIndex, challengeStateHash, 0, numSteps_, segments);
}
}
文件 21 的 88:GlobalState.sol
pragma solidity ^0.8.0;
struct GlobalState {
bytes32[2] bytes32Vals;
uint64[2] u64Vals;
}
library GlobalStateLib {
uint16 internal constant BYTES32_VALS_NUM = 2;
uint16 internal constant U64_VALS_NUM = 2;
function hash(GlobalState memory state) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
"Global state:",
state.bytes32Vals[0],
state.bytes32Vals[1],
state.u64Vals[0],
state.u64Vals[1]
)
);
}
function getBlockHash(GlobalState memory state) internal pure returns (bytes32) {
return state.bytes32Vals[0];
}
function getSendRoot(GlobalState memory state) internal pure returns (bytes32) {
return state.bytes32Vals[1];
}
function getInboxPosition(GlobalState memory state) internal pure returns (uint64) {
return state.u64Vals[0];
}
function getPositionInMessage(GlobalState memory state) internal pure returns (uint64) {
return state.u64Vals[1];
}
function isEmpty(GlobalState calldata state) internal pure returns (bool) {
return (state.bytes32Vals[0] == bytes32(0) &&
state.bytes32Vals[1] == bytes32(0) &&
state.u64Vals[0] == 0 &&
state.u64Vals[1] == 0);
}
}
文件 22 的 88:IBeacon.sol
pragma solidity ^0.8.0;
interface IBeacon {
function implementation() external view returns (address);
}
文件 23 的 88:IBridge.sol
pragma solidity >=0.6.9 <0.9.0;
import "./IOwnable.sol";
interface IBridge {
event MessageDelivered(
uint256 indexed messageIndex,
bytes32 indexed beforeInboxAcc,
address inbox,
uint8 kind,
address sender,
bytes32 messageDataHash,
uint256 baseFeeL1,
uint64 timestamp
);
event BridgeCallTriggered(
address indexed outbox,
address indexed to,
uint256 value,
bytes data
);
event InboxToggle(address indexed inbox, bool enabled);
event OutboxToggle(address indexed outbox, bool enabled);
event SequencerInboxUpdated(address newSequencerInbox);
function allowedDelayedInboxList(uint256) external returns (address);
function allowedOutboxList(uint256) external returns (address);
function delayedInboxAccs(uint256) external view returns (bytes32);
function sequencerInboxAccs(uint256) external view returns (bytes32);
function rollup() external view returns (IOwnable);
function sequencerInbox() external view returns (address);
function activeOutbox() external view returns (address);
function allowedDelayedInboxes(address inbox) external view returns (bool);
function allowedOutboxes(address outbox) external view returns (bool);
function enqueueDelayedMessage(
uint8 kind,
address sender,
bytes32 messageDataHash
) external payable returns (uint256);
function executeCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success, bytes memory returnData);
function delayedMessageCount() external view returns (uint256);
function sequencerMessageCount() external view returns (uint256);
function enqueueSequencerMessage(bytes32 dataHash, uint256 afterDelayedMessagesRead)
external
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 acc
);
function submitBatchSpendingReport(address batchPoster, bytes32 dataHash)
external
returns (uint256 msgNum);
function setSequencerInbox(address _sequencerInbox) external;
function setDelayedInbox(address inbox, bool enabled) external;
function setOutbox(address inbox, bool enabled) external;
function initialize(IOwnable rollup_) external;
}
文件 24 的 88:IChallengeManager.sol
pragma solidity ^0.8.0;
import "../state/Machine.sol";
import "../bridge/IBridge.sol";
import "../bridge/ISequencerInbox.sol";
import "../osp/IOneStepProofEntry.sol";
import "./IChallengeResultReceiver.sol";
import "./ChallengeLib.sol";
interface IChallengeManager {
enum ChallengeTerminationType {
TIMEOUT,
BLOCK_PROOF,
EXECUTION_PROOF,
CLEARED
}
event InitiatedChallenge(
uint64 indexed challengeIndex,
GlobalState startState,
GlobalState endState
);
event Bisected(
uint64 indexed challengeIndex,
bytes32 indexed challengeRoot,
uint256 challengedSegmentStart,
uint256 challengedSegmentLength,
bytes32[] chainHashes
);
event ExecutionChallengeBegun(uint64 indexed challengeIndex, uint256 blockSteps);
event OneStepProofCompleted(uint64 indexed challengeIndex);
event ChallengeEnded(uint64 indexed challengeIndex, ChallengeTerminationType kind);
function initialize(
IChallengeResultReceiver resultReceiver_,
ISequencerInbox sequencerInbox_,
IBridge bridge_,
IOneStepProofEntry osp_
) external;
function createChallenge(
bytes32 wasmModuleRoot_,
MachineStatus[2] calldata startAndEndMachineStatuses_,
GlobalState[2] calldata startAndEndGlobalStates_,
uint64 numBlocks,
address asserter_,
address challenger_,
uint256 asserterTimeLeft_,
uint256 challengerTimeLeft_
) external returns (uint64);
function challengeInfo(uint64 challengeIndex_)
external
view
returns (ChallengeLib.Challenge memory);
function currentResponder(uint64 challengeIndex) external view returns (address);
function isTimedOut(uint64 challengeIndex) external view returns (bool);
function currentResponderTimeLeft(uint64 challengeIndex_) external view returns (uint256);
function clearChallenge(uint64 challengeIndex_) external;
function timeout(uint64 challengeIndex_) external;
}
文件 25 的 88:IChallengeResultReceiver.sol
pragma solidity ^0.8.0;
interface IChallengeResultReceiver {
function completeChallenge(
uint256 challengeIndex,
address winner,
address loser
) external;
}
文件 26 的 88:IDelayedMessageProvider.sol
pragma solidity >=0.6.9 <0.9.0;
interface IDelayedMessageProvider {
event InboxMessageDelivered(uint256 indexed messageNum, bytes data);
event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum);
}
文件 27 的 88:IERC20Upgradeable.sol
pragma solidity ^0.8.0;
interface IERC20Upgradeable {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 28 的 88:IGasRefunder.sol
pragma solidity >=0.6.9 <0.9.0;
interface IGasRefunder {
function onGasSpent(
address payable spender,
uint256 gasUsed,
uint256 calldataSize
) external returns (bool success);
}
abstract contract GasRefundEnabled {
modifier refundsGas(IGasRefunder gasRefunder) {
uint256 startGasLeft = gasleft();
_;
if (address(gasRefunder) != address(0)) {
uint256 calldataSize = 0;
if (msg.sender == tx.origin) {
assembly {
calldataSize := calldatasize()
}
}
gasRefunder.onGasSpent(payable(msg.sender), startGasLeft - gasleft(), calldataSize);
}
}
}
文件 29 的 88:IInbox.sol
pragma solidity >=0.6.9 <0.9.0;
import "./IBridge.sol";
import "./IDelayedMessageProvider.sol";
import "./ISequencerInbox.sol";
interface IInbox is IDelayedMessageProvider {
function bridge() external view returns (IBridge);
function sequencerInbox() external view returns (ISequencerInbox);
function sendL2MessageFromOrigin(bytes calldata messageData) external returns (uint256);
function sendL2Message(bytes calldata messageData) external returns (uint256);
function sendL1FundedUnsignedTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
address to,
bytes calldata data
) external payable returns (uint256);
function sendL1FundedContractTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
address to,
bytes calldata data
) external payable returns (uint256);
function sendUnsignedTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
address to,
uint256 value,
bytes calldata data
) external returns (uint256);
function sendContractTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
address to,
uint256 value,
bytes calldata data
) external returns (uint256);
function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
external
view
returns (uint256);
function depositEth() external payable returns (uint256);
function createRetryableTicket(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes calldata data
) external payable returns (uint256);
function unsafeCreateRetryableTicket(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes calldata data
) external payable returns (uint256);
function pause() external;
function unpause() external;
function postUpgradeInit(IBridge _bridge) external;
function initialize(IBridge _bridge, ISequencerInbox _sequencerInbox) external;
}
文件 30 的 88:IOneStepProofEntry.sol
pragma solidity ^0.8.0;
import "./IOneStepProver.sol";
library OneStepProofEntryLib {
uint256 internal constant MAX_STEPS = 1 << 43;
}
interface IOneStepProofEntry {
function proveOneStep(
ExecutionContext calldata execCtx,
uint256 machineStep,
bytes32 beforeHash,
bytes calldata proof
) external view returns (bytes32 afterHash);
}
文件 31 的 88:IOneStepProver.sol
pragma solidity ^0.8.0;
import "../state/Machine.sol";
import "../state/Module.sol";
import "../state/Instructions.sol";
import "../bridge/ISequencerInbox.sol";
import "../bridge/IBridge.sol";
struct ExecutionContext {
uint256 maxInboxMessagesRead;
IBridge bridge;
}
abstract contract IOneStepProver {
function executeOneStep(
ExecutionContext memory execCtx,
Machine calldata mach,
Module calldata mod,
Instruction calldata instruction,
bytes calldata proof
) external view virtual returns (Machine memory result, Module memory resultMod);
}
文件 32 的 88:IOutbox.sol
pragma solidity >=0.6.9 <0.9.0;
import "./IBridge.sol";
interface IOutbox {
event SendRootUpdated(bytes32 indexed blockHash, bytes32 indexed outputRoot);
event OutBoxTransactionExecuted(
address indexed to,
address indexed l2Sender,
uint256 indexed zero,
uint256 transactionIndex
);
function rollup() external view returns (address);
function bridge() external view returns (IBridge);
function spent(uint256) external view returns (bytes32);
function roots(bytes32) external view returns (bytes32);
function OUTBOX_VERSION() external view returns (uint128);
function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external;
function l2ToL1Sender() external view returns (address);
function l2ToL1Block() external view returns (uint256);
function l2ToL1EthBlock() external view returns (uint256);
function l2ToL1Timestamp() external view returns (uint256);
function l2ToL1OutputId() external view returns (bytes32);
function executeTransaction(
bytes32[] calldata proof,
uint256 index,
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) external;
function executeTransactionSimulation(
uint256 index,
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) external;
function isSpent(uint256 index) external view returns (bool);
function calculateItemHash(
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) external pure returns (bytes32);
function calculateMerkleRoot(
bytes32[] memory proof,
uint256 path,
bytes32 item
) external pure returns (bytes32);
}
文件 33 的 88:IOwnable.sol
pragma solidity >=0.4.21 <0.9.0;
interface IOwnable {
function owner() external view returns (address);
}
文件 34 的 88:IRollupCore.sol
pragma solidity ^0.8.0;
import "./Node.sol";
import "./RollupLib.sol";
interface IRollupCore {
struct Staker {
uint256 amountStaked;
uint64 index;
uint64 latestStakedNode;
uint64 currentChallenge;
bool isStaked;
}
event RollupInitialized(bytes32 machineHash, uint256 chainId);
event NodeCreated(
uint64 indexed nodeNum,
bytes32 indexed parentNodeHash,
bytes32 indexed nodeHash,
bytes32 executionHash,
RollupLib.Assertion assertion,
bytes32 afterInboxBatchAcc,
bytes32 wasmModuleRoot,
uint256 inboxMaxCount
);
event NodeConfirmed(uint64 indexed nodeNum, bytes32 blockHash, bytes32 sendRoot);
event NodeRejected(uint64 indexed nodeNum);
event RollupChallengeStarted(
uint64 indexed challengeIndex,
address asserter,
address challenger,
uint64 challengedNode
);
event UserStakeUpdated(address indexed user, uint256 initialBalance, uint256 finalBalance);
event UserWithdrawableFundsUpdated(
address indexed user,
uint256 initialBalance,
uint256 finalBalance
);
function confirmPeriodBlocks() external view returns (uint64);
function extraChallengeTimeBlocks() external view returns (uint64);
function chainId() external view returns (uint256);
function baseStake() external view returns (uint256);
function wasmModuleRoot() external view returns (bytes32);
function bridge() external view returns (IBridge);
function sequencerInbox() external view returns (ISequencerInbox);
function outbox() external view returns (IOutbox);
function rollupEventInbox() external view returns (IRollupEventInbox);
function challengeManager() external view returns (IChallengeManager);
function loserStakeEscrow() external view returns (address);
function stakeToken() external view returns (address);
function minimumAssertionPeriod() external view returns (uint256);
function isValidator(address) external view returns (bool);
function getNode(uint64 nodeNum) external view returns (Node memory);
function nodeHasStaker(uint64 nodeNum, address staker) external view returns (bool);
function getStakerAddress(uint64 stakerNum) external view returns (address);
function isStaked(address staker) external view returns (bool);
function latestStakedNode(address staker) external view returns (uint64);
function currentChallenge(address staker) external view returns (uint64);
function amountStaked(address staker) external view returns (uint256);
function getStaker(address staker) external view returns (Staker memory);
function zombieAddress(uint256 zombieNum) external view returns (address);
function zombieLatestStakedNode(uint256 zombieNum) external view returns (uint64);
function zombieCount() external view returns (uint256);
function isZombie(address staker) external view returns (bool);
function withdrawableFunds(address owner) external view returns (uint256);
function firstUnresolvedNode() external view returns (uint64);
function latestConfirmed() external view returns (uint64);
function latestNodeCreated() external view returns (uint64);
function lastStakeBlock() external view returns (uint64);
function stakerCount() external view returns (uint64);
}
文件 35 的 88:IRollupEventInbox.sol
pragma solidity ^0.8.0;
import "../bridge/IBridge.sol";
interface IRollupEventInbox {
function bridge() external view returns (IBridge);
function initialize(IBridge _bridge) external;
function rollup() external view returns (address);
function rollupInitialized(uint256 chainId) external;
}
文件 36 的 88:IRollupLogic.sol
pragma solidity ^0.8.0;
import "./RollupLib.sol";
import "./IRollupCore.sol";
import "../bridge/ISequencerInbox.sol";
import "../bridge/IOutbox.sol";
import "../bridge/IOwnable.sol";
interface IRollupUserAbs is IRollupCore, IOwnable {
function initialize(address stakeToken) external view;
function isERC20Enabled() external view returns (bool);
function rejectNextNode(address stakerAddress) external;
function confirmNextNode(bytes32 blockHash, bytes32 sendRoot) external;
function stakeOnExistingNode(uint64 nodeNum, bytes32 nodeHash) external;
function stakeOnNewNode(
RollupLib.Assertion memory assertion,
bytes32 expectedNodeHash,
uint256 prevNodeInboxMaxCount
) external;
function returnOldDeposit(address stakerAddress) external;
function reduceDeposit(uint256 target) external;
function removeZombie(uint256 zombieNum, uint256 maxNodes) external;
function removeOldZombies(uint256 startIndex) external;
function requiredStake(
uint256 blockNumber,
uint64 firstUnresolvedNodeNum,
uint64 latestCreatedNode
) external view returns (uint256);
function currentRequiredStake() external view returns (uint256);
function countStakedZombies(uint64 nodeNum) external view returns (uint256);
function countZombiesStakedOnChildren(uint64 nodeNum) external view returns (uint256);
function requireUnresolvedExists() external view;
function requireUnresolved(uint256 nodeNum) external view;
function withdrawStakerFunds() external returns (uint256);
function createChallenge(
address[2] calldata stakers,
uint64[2] calldata nodeNums,
MachineStatus[2] calldata machineStatuses,
GlobalState[2] calldata globalStates,
uint64 numBlocks,
bytes32 secondExecutionHash,
uint256[2] calldata proposedTimes,
bytes32[2] calldata wasmModuleRoots
) external;
}
interface IRollupUser is IRollupUserAbs {
function newStakeOnExistingNode(uint64 nodeNum, bytes32 nodeHash) external payable;
function newStakeOnNewNode(
RollupLib.Assertion calldata assertion,
bytes32 expectedNodeHash,
uint256 prevNodeInboxMaxCount
) external payable;
function addToDeposit(address stakerAddress) external payable;
}
interface IRollupUserERC20 is IRollupUserAbs {
function newStakeOnExistingNode(
uint256 tokenAmount,
uint64 nodeNum,
bytes32 nodeHash
) external;
function newStakeOnNewNode(
uint256 tokenAmount,
RollupLib.Assertion calldata assertion,
bytes32 expectedNodeHash,
uint256 prevNodeInboxMaxCount
) external;
function addToDeposit(address stakerAddress, uint256 tokenAmount) external;
}
interface IRollupAdmin {
event OwnerFunctionCalled(uint256 indexed id);
function initialize(Config calldata config, ContractDependencies calldata connectedContracts)
external;
function setOutbox(IOutbox _outbox) external;
function removeOldOutbox(address _outbox) external;
function setDelayedInbox(address _inbox, bool _enabled) external;
function pause() external;
function resume() external;
function setValidator(address[] memory _validator, bool[] memory _val) external;
function setOwner(address newOwner) external;
function setMinimumAssertionPeriod(uint256 newPeriod) external;
function setConfirmPeriodBlocks(uint64 newConfirmPeriod) external;
function setExtraChallengeTimeBlocks(uint64 newExtraTimeBlocks) external;
function setBaseStake(uint256 newBaseStake) external;
function setStakeToken(address newStakeToken) external;
function upgradeBeacon(address beacon, address newImplementation) external;
function forceResolveChallenge(address[] memory stackerA, address[] memory stackerB) external;
function forceRefundStaker(address[] memory stacker) external;
function forceCreateNode(
uint64 prevNode,
uint256 prevNodeInboxMaxCount,
RollupLib.Assertion memory assertion,
bytes32 expectedNodeHash
) external;
function forceConfirmNode(
uint64 nodeNum,
bytes32 blockHash,
bytes32 sendRoot
) external;
function setLoserStakeEscrow(address newLoserStakerEscrow) external;
function setWasmModuleRoot(bytes32 newWasmModuleRoot) external;
function setSequencerInbox(address _sequencerInbox) external;
}
文件 37 的 88:ISequencerInbox.sol
pragma solidity >=0.6.9 <0.9.0;
pragma experimental ABIEncoderV2;
import "../libraries/IGasRefunder.sol";
import "./IDelayedMessageProvider.sol";
import "./IBridge.sol";
interface ISequencerInbox is IDelayedMessageProvider {
struct MaxTimeVariation {
uint256 delayBlocks;
uint256 futureBlocks;
uint256 delaySeconds;
uint256 futureSeconds;
}
struct TimeBounds {
uint64 minTimestamp;
uint64 maxTimestamp;
uint64 minBlockNumber;
uint64 maxBlockNumber;
}
enum BatchDataLocation {
TxInput,
SeparateBatchEvent,
NoData
}
event SequencerBatchDelivered(
uint256 indexed batchSequenceNumber,
bytes32 indexed beforeAcc,
bytes32 indexed afterAcc,
bytes32 delayedAcc,
uint256 afterDelayedMessagesRead,
TimeBounds timeBounds,
BatchDataLocation dataLocation
);
event OwnerFunctionCalled(uint256 indexed id);
event SequencerBatchData(uint256 indexed batchSequenceNumber, bytes data);
event SetValidKeyset(bytes32 indexed keysetHash, bytes keysetBytes);
event InvalidateKeyset(bytes32 indexed keysetHash);
function totalDelayedMessagesRead() external view returns (uint256);
function bridge() external view returns (IBridge);
function HEADER_LENGTH() external view returns (uint256);
function DATA_AUTHENTICATED_FLAG() external view returns (bytes1);
function rollup() external view returns (IOwnable);
function isBatchPoster(address) external view returns (bool);
struct DasKeySetInfo {
bool isValidKeyset;
uint64 creationBlock;
}
function forceInclusion(
uint256 _totalDelayedMessagesRead,
uint8 kind,
uint64[2] calldata l1BlockAndTime,
uint256 baseFeeL1,
address sender,
bytes32 messageDataHash
) external;
function inboxAccs(uint256 index) external view returns (bytes32);
function batchCount() external view returns (uint256);
function isValidKeysetHash(bytes32 ksHash) external view returns (bool);
function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256);
function addSequencerL2BatchFromOrigin(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder
) external;
function addSequencerL2Batch(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder
) external;
function setMaxTimeVariation(MaxTimeVariation memory maxTimeVariation_) external;
function setIsBatchPoster(address addr, bool isBatchPoster_) external;
function setValidKeyset(bytes calldata keysetBytes) external;
function invalidateKeysetHash(bytes32 ksHash) external;
function initialize(IBridge bridge_, MaxTimeVariation calldata maxTimeVariation_) external;
}
文件 38 的 88:Inbox.sol
pragma solidity ^0.8.4;
import {
AlreadyInit,
NotOrigin,
DataTooLarge,
AlreadyPaused,
AlreadyUnpaused,
Paused,
InsufficientValue,
InsufficientSubmissionCost,
NotAllowedOrigin,
RetryableData,
NotRollupOrOwner
} from "../libraries/Error.sol";
import "./IInbox.sol";
import "./ISequencerInbox.sol";
import "./IBridge.sol";
import "./Messages.sol";
import "../libraries/AddressAliasHelper.sol";
import "../libraries/DelegateCallAware.sol";
import {
L2_MSG,
L1MessageType_L2FundedByL1,
L1MessageType_submitRetryableTx,
L1MessageType_ethDeposit,
L2MessageType_unsignedEOATx,
L2MessageType_unsignedContractTx
} from "../libraries/MessageTypes.sol";
import {MAX_DATA_SIZE} from "../libraries/Constants.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
IBridge public bridge;
ISequencerInbox public sequencerInbox;
bool public allowListEnabled;
mapping(address => bool) public isAllowed;
event AllowListAddressSet(address indexed user, bool val);
event AllowListEnabledUpdated(bool isEnabled);
function setAllowList(address[] memory user, bool[] memory val) external onlyRollupOrOwner {
require(user.length == val.length, "INVALID_INPUT");
for (uint256 i = 0; i < user.length; i++) {
isAllowed[user[i]] = val[i];
emit AllowListAddressSet(user[i], val[i]);
}
}
function setAllowListEnabled(bool _allowListEnabled) external onlyRollupOrOwner {
require(_allowListEnabled != allowListEnabled, "ALREADY_SET");
allowListEnabled = _allowListEnabled;
emit AllowListEnabledUpdated(_allowListEnabled);
}
modifier onlyAllowed() {
if (allowListEnabled && !isAllowed[tx.origin]) revert NotAllowedOrigin(tx.origin);
_;
}
modifier onlyRollupOrOwner() {
IOwnable rollup = bridge.rollup();
if (msg.sender != address(rollup)) {
address rollupOwner = rollup.owner();
if (msg.sender != rollupOwner) {
revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
}
}
_;
}
function pause() external onlyRollupOrOwner {
_pause();
}
function unpause() external onlyRollupOrOwner {
_unpause();
}
function initialize(IBridge _bridge, ISequencerInbox _sequencerInbox)
external
initializer
onlyDelegated
{
bridge = _bridge;
sequencerInbox = _sequencerInbox;
allowListEnabled = false;
__Pausable_init();
}
function postUpgradeInit(IBridge _bridge) external onlyDelegated onlyProxyOwner {
uint8 slotsToWipe = 3;
for (uint8 i = 0; i < slotsToWipe; i++) {
assembly {
sstore(i, 0)
}
}
allowListEnabled = false;
bridge = _bridge;
}
function sendL2MessageFromOrigin(bytes calldata messageData)
external
whenNotPaused
onlyAllowed
returns (uint256)
{
if (msg.sender != tx.origin) revert NotOrigin();
if (messageData.length > MAX_DATA_SIZE)
revert DataTooLarge(messageData.length, MAX_DATA_SIZE);
uint256 msgNum = deliverToBridge(L2_MSG, msg.sender, keccak256(messageData));
emit InboxMessageDeliveredFromOrigin(msgNum);
return msgNum;
}
function sendL2Message(bytes calldata messageData)
external
whenNotPaused
onlyAllowed
returns (uint256)
{
return _deliverMessage(L2_MSG, msg.sender, messageData);
}
function sendL1FundedUnsignedTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
address to,
bytes calldata data
) external payable whenNotPaused onlyAllowed returns (uint256) {
return
_deliverMessage(
L1MessageType_L2FundedByL1,
msg.sender,
abi.encodePacked(
L2MessageType_unsignedEOATx,
gasLimit,
maxFeePerGas,
nonce,
uint256(uint160(to)),
msg.value,
data
)
);
}
function sendL1FundedContractTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
address to,
bytes calldata data
) external payable whenNotPaused onlyAllowed returns (uint256) {
return
_deliverMessage(
L1MessageType_L2FundedByL1,
msg.sender,
abi.encodePacked(
L2MessageType_unsignedContractTx,
gasLimit,
maxFeePerGas,
uint256(uint160(to)),
msg.value,
data
)
);
}
function sendUnsignedTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
address to,
uint256 value,
bytes calldata data
) external whenNotPaused onlyAllowed returns (uint256) {
return
_deliverMessage(
L2_MSG,
msg.sender,
abi.encodePacked(
L2MessageType_unsignedEOATx,
gasLimit,
maxFeePerGas,
nonce,
uint256(uint160(to)),
value,
data
)
);
}
function sendContractTransaction(
uint256 gasLimit,
uint256 maxFeePerGas,
address to,
uint256 value,
bytes calldata data
) external whenNotPaused onlyAllowed returns (uint256) {
return
_deliverMessage(
L2_MSG,
msg.sender,
abi.encodePacked(
L2MessageType_unsignedContractTx,
gasLimit,
maxFeePerGas,
uint256(uint160(to)),
value,
data
)
);
}
function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
public
view
returns (uint256)
{
return (1400 + 6 * dataLength) * (baseFee == 0 ? block.basefee : baseFee);
}
function depositEth() public payable whenNotPaused onlyAllowed returns (uint256) {
address dest = msg.sender;
if (AddressUpgradeable.isContract(msg.sender) || tx.origin != msg.sender) {
dest = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
}
return
_deliverMessage(
L1MessageType_ethDeposit,
msg.sender,
abi.encodePacked(dest, msg.value)
);
}
function depositEth(uint256) external payable whenNotPaused onlyAllowed returns (uint256) {
return depositEth();
}
function createRetryableTicketNoRefundAliasRewrite(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes calldata data
) external payable whenNotPaused onlyAllowed returns (uint256) {
return
unsafeCreateRetryableTicket(
to,
l2CallValue,
maxSubmissionCost,
excessFeeRefundAddress,
callValueRefundAddress,
gasLimit,
maxFeePerGas,
data
);
}
function createRetryableTicket(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes calldata data
) external payable whenNotPaused onlyAllowed returns (uint256) {
if (msg.value < (maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas)) {
revert InsufficientValue(
maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas,
msg.value
);
}
if (AddressUpgradeable.isContract(excessFeeRefundAddress)) {
excessFeeRefundAddress = AddressAliasHelper.applyL1ToL2Alias(excessFeeRefundAddress);
}
if (AddressUpgradeable.isContract(callValueRefundAddress)) {
callValueRefundAddress = AddressAliasHelper.applyL1ToL2Alias(callValueRefundAddress);
}
return
unsafeCreateRetryableTicket(
to,
l2CallValue,
maxSubmissionCost,
excessFeeRefundAddress,
callValueRefundAddress,
gasLimit,
maxFeePerGas,
data
);
}
function unsafeCreateRetryableTicket(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes calldata data
) public payable whenNotPaused onlyAllowed returns (uint256) {
if (gasLimit == 1 || maxFeePerGas == 1)
revert RetryableData(
msg.sender,
to,
l2CallValue,
msg.value,
maxSubmissionCost,
excessFeeRefundAddress,
callValueRefundAddress,
gasLimit,
maxFeePerGas,
data
);
uint256 submissionFee = calculateRetryableSubmissionFee(data.length, block.basefee);
if (maxSubmissionCost < submissionFee)
revert InsufficientSubmissionCost(submissionFee, maxSubmissionCost);
return
_deliverMessage(
L1MessageType_submitRetryableTx,
msg.sender,
abi.encodePacked(
uint256(uint160(to)),
l2CallValue,
msg.value,
maxSubmissionCost,
uint256(uint160(excessFeeRefundAddress)),
uint256(uint160(callValueRefundAddress)),
gasLimit,
maxFeePerGas,
data.length,
data
)
);
}
function _deliverMessage(
uint8 _kind,
address _sender,
bytes memory _messageData
) internal returns (uint256) {
if (_messageData.length > MAX_DATA_SIZE)
revert DataTooLarge(_messageData.length, MAX_DATA_SIZE);
uint256 msgNum = deliverToBridge(_kind, _sender, keccak256(_messageData));
emit InboxMessageDelivered(msgNum, _messageData);
return msgNum;
}
function deliverToBridge(
uint8 kind,
address sender,
bytes32 messageDataHash
) internal returns (uint256) {
return
bridge.enqueueDelayedMessage{value: msg.value}(
kind,
AddressAliasHelper.applyL1ToL2Alias(sender),
messageDataHash
);
}
}
文件 39 的 88:InboxStub.sol
pragma solidity ^0.8.0;
import "../bridge/IInbox.sol";
import "../bridge/IBridge.sol";
import "../bridge/Messages.sol";
import "./BridgeStub.sol";
import {
L2_MSG,
L1MessageType_L2FundedByL1,
L1MessageType_submitRetryableTx,
L2MessageType_unsignedEOATx,
L2MessageType_unsignedContractTx
} from "../libraries/MessageTypes.sol";
contract InboxStub is IInbox {
IBridge public override bridge;
ISequencerInbox public override sequencerInbox;
bool public paused;
function pause() external pure {
revert("NOT IMPLEMENTED");
}
function unpause() external pure {
revert("NOT IMPLEMENTED");
}
function initialize(IBridge _bridge, ISequencerInbox) external {
require(address(bridge) == address(0), "ALREADY_INIT");
bridge = _bridge;
}
function sendL2MessageFromOrigin(bytes calldata messageData) external returns (uint256) {
require(msg.sender == tx.origin, "origin only");
uint256 msgNum = deliverToBridge(L2_MSG, msg.sender, keccak256(messageData));
emit InboxMessageDeliveredFromOrigin(msgNum);
return msgNum;
}
function sendL2Message(bytes calldata messageData) external override returns (uint256) {
uint256 msgNum = deliverToBridge(L2_MSG, msg.sender, keccak256(messageData));
emit InboxMessageDelivered(msgNum, messageData);
return msgNum;
}
function deliverToBridge(
uint8 kind,
address sender,
bytes32 messageDataHash
) internal returns (uint256) {
return bridge.enqueueDelayedMessage{value: msg.value}(kind, sender, messageDataHash);
}
function sendUnsignedTransaction(
uint256,
uint256,
uint256,
address,
uint256,
bytes calldata
) external pure override returns (uint256) {
revert("NOT_IMPLEMENTED");
}
function sendContractTransaction(
uint256,
uint256,
address,
uint256,
bytes calldata
) external pure override returns (uint256) {
revert("NOT_IMPLEMENTED");
}
function sendL1FundedUnsignedTransaction(
uint256,
uint256,
uint256,
address,
bytes calldata
) external payable override returns (uint256) {
revert("NOT_IMPLEMENTED");
}
function sendL1FundedContractTransaction(
uint256,
uint256,
address,
bytes calldata
) external payable override returns (uint256) {
revert("NOT_IMPLEMENTED");
}
function createRetryableTicket(
address,
uint256,
uint256,
address,
address,
uint256,
uint256,
bytes calldata
) external payable override returns (uint256) {
revert("NOT_IMPLEMENTED");
}
function unsafeCreateRetryableTicket(
address,
uint256,
uint256,
address,
address,
uint256,
uint256,
bytes calldata
) external payable override returns (uint256) {
revert("NOT_IMPLEMENTED");
}
function depositEth() external payable override returns (uint256) {
revert("NOT_IMPLEMENTED");
}
function postUpgradeInit(IBridge _bridge) external {}
function calculateRetryableSubmissionFee(uint256, uint256)
external
pure
override
returns (uint256)
{
revert("NOT_IMPLEMENTED");
}
}
文件 40 的 88:Initializable.sol
pragma solidity ^0.8.0;
import "../../utils/AddressUpgradeable.sol";
abstract contract Initializable {
bool private _initialized;
bool private _initializing;
modifier initializer() {
require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
function _isConstructor() private view returns (bool) {
return !AddressUpgradeable.isContract(address(this));
}
}
文件 41 的 88:Instructions.sol
pragma solidity ^0.8.0;
struct Instruction {
uint16 opcode;
uint256 argumentData;
}
library Instructions {
uint16 internal constant UNREACHABLE = 0x00;
uint16 internal constant NOP = 0x01;
uint16 internal constant RETURN = 0x0F;
uint16 internal constant CALL = 0x10;
uint16 internal constant CALL_INDIRECT = 0x11;
uint16 internal constant LOCAL_GET = 0x20;
uint16 internal constant LOCAL_SET = 0x21;
uint16 internal constant GLOBAL_GET = 0x23;
uint16 internal constant GLOBAL_SET = 0x24;
uint16 internal constant I32_LOAD = 0x28;
uint16 internal constant I64_LOAD = 0x29;
uint16 internal constant F32_LOAD = 0x2A;
uint16 internal constant F64_LOAD = 0x2B;
uint16 internal constant I32_LOAD8_S = 0x2C;
uint16 internal constant I32_LOAD8_U = 0x2D;
uint16 internal constant I32_LOAD16_S = 0x2E;
uint16 internal constant I32_LOAD16_U = 0x2F;
uint16 internal constant I64_LOAD8_S = 0x30;
uint16 internal constant I64_LOAD8_U = 0x31;
uint16 internal constant I64_LOAD16_S = 0x32;
uint16 internal constant I64_LOAD16_U = 0x33;
uint16 internal constant I64_LOAD32_S = 0x34;
uint16 internal constant I64_LOAD32_U = 0x35;
uint16 internal constant I32_STORE = 0x36;
uint16 internal constant I64_STORE = 0x37;
uint16 internal constant F32_STORE = 0x38;
uint16 internal constant F64_STORE = 0x39;
uint16 internal constant I32_STORE8 = 0x3A;
uint16 internal constant I32_STORE16 = 0x3B;
uint16 internal constant I64_STORE8 = 0x3C;
uint16 internal constant I64_STORE16 = 0x3D;
uint16 internal constant I64_STORE32 = 0x3E;
uint16 internal constant MEMORY_SIZE = 0x3F;
uint16 internal constant MEMORY_GROW = 0x40;
uint16 internal constant DROP = 0x1A;
uint16 internal constant SELECT = 0x1B;
uint16 internal constant I32_CONST = 0x41;
uint16 internal constant I64_CONST = 0x42;
uint16 internal constant F32_CONST = 0x43;
uint16 internal constant F64_CONST = 0x44;
uint16 internal constant I32_EQZ = 0x45;
uint16 internal constant I32_RELOP_BASE = 0x46;
uint16 internal constant IRELOP_EQ = 0;
uint16 internal constant IRELOP_NE = 1;
uint16 internal constant IRELOP_LT_S = 2;
uint16 internal constant IRELOP_LT_U = 3;
uint16 internal constant IRELOP_GT_S = 4;
uint16 internal constant IRELOP_GT_U = 5;
uint16 internal constant IRELOP_LE_S = 6;
uint16 internal constant IRELOP_LE_U = 7;
uint16 internal constant IRELOP_GE_S = 8;
uint16 internal constant IRELOP_GE_U = 9;
uint16 internal constant IRELOP_LAST = IRELOP_GE_U;
uint16 internal constant I64_EQZ = 0x50;
uint16 internal constant I64_RELOP_BASE = 0x51;
uint16 internal constant I32_UNOP_BASE = 0x67;
uint16 internal constant IUNOP_CLZ = 0;
uint16 internal constant IUNOP_CTZ = 1;
uint16 internal constant IUNOP_POPCNT = 2;
uint16 internal constant IUNOP_LAST = IUNOP_POPCNT;
uint16 internal constant I32_ADD = 0x6A;
uint16 internal constant I32_SUB = 0x6B;
uint16 internal constant I32_MUL = 0x6C;
uint16 internal constant I32_DIV_S = 0x6D;
uint16 internal constant I32_DIV_U = 0x6E;
uint16 internal constant I32_REM_S = 0x6F;
uint16 internal constant I32_REM_U = 0x70;
uint16 internal constant I32_AND = 0x71;
uint16 internal constant I32_OR = 0x72;
uint16 internal constant I32_XOR = 0x73;
uint16 internal constant I32_SHL = 0x74;
uint16 internal constant I32_SHR_S = 0x75;
uint16 internal constant I32_SHR_U = 0x76;
uint16 internal constant I32_ROTL = 0x77;
uint16 internal constant I32_ROTR = 0x78;
uint16 internal constant I64_UNOP_BASE = 0x79;
uint16 internal constant I64_ADD = 0x7C;
uint16 internal constant I64_SUB = 0x7D;
uint16 internal constant I64_MUL = 0x7E;
uint16 internal constant I64_DIV_S = 0x7F;
uint16 internal constant I64_DIV_U = 0x80;
uint16 internal constant I64_REM_S = 0x81;
uint16 internal constant I64_REM_U = 0x82;
uint16 internal constant I64_AND = 0x83;
uint16 internal constant I64_OR = 0x84;
uint16 internal constant I64_XOR = 0x85;
uint16 internal constant I64_SHL = 0x86;
uint16 internal constant I64_SHR_S = 0x87;
uint16 internal constant I64_SHR_U = 0x88;
uint16 internal constant I64_ROTL = 0x89;
uint16 internal constant I64_ROTR = 0x8A;
uint16 internal constant I32_WRAP_I64 = 0xA7;
uint16 internal constant I64_EXTEND_I32_S = 0xAC;
uint16 internal constant I64_EXTEND_I32_U = 0xAD;
uint16 internal constant I32_REINTERPRET_F32 = 0xBC;
uint16 internal constant I64_REINTERPRET_F64 = 0xBD;
uint16 internal constant F32_REINTERPRET_I32 = 0xBE;
uint16 internal constant F64_REINTERPRET_I64 = 0xBF;
uint16 internal constant I32_EXTEND_8S = 0xC0;
uint16 internal constant I32_EXTEND_16S = 0xC1;
uint16 internal constant I64_EXTEND_8S = 0xC2;
uint16 internal constant I64_EXTEND_16S = 0xC3;
uint16 internal constant I64_EXTEND_32S = 0xC4;
uint16 internal constant INIT_FRAME = 0x8002;
uint16 internal constant ARBITRARY_JUMP = 0x8003;
uint16 internal constant ARBITRARY_JUMP_IF = 0x8004;
uint16 internal constant MOVE_FROM_STACK_TO_INTERNAL = 0x8005;
uint16 internal constant MOVE_FROM_INTERNAL_TO_STACK = 0x8006;
uint16 internal constant DUP = 0x8008;
uint16 internal constant CROSS_MODULE_CALL = 0x8009;
uint16 internal constant CALLER_MODULE_INTERNAL_CALL = 0x800A;
uint16 internal constant GET_GLOBAL_STATE_BYTES32 = 0x8010;
uint16 internal constant SET_GLOBAL_STATE_BYTES32 = 0x8011;
uint16 internal constant GET_GLOBAL_STATE_U64 = 0x8012;
uint16 internal constant SET_GLOBAL_STATE_U64 = 0x8013;
uint16 internal constant READ_PRE_IMAGE = 0x8020;
uint16 internal constant READ_INBOX_MESSAGE = 0x8021;
uint16 internal constant HALT_AND_SET_FINISHED = 0x8022;
uint256 internal constant INBOX_INDEX_SEQUENCER = 0;
uint256 internal constant INBOX_INDEX_DELAYED = 1;
function hash(Instruction memory inst) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("Instruction:", inst.opcode, inst.argumentData));
}
}
文件 42 的 88:InterfaceCompatibilityTester.sol
pragma solidity >=0.6.9 <0.9.0;
import "../bridge/IBridge.sol";
import "../bridge/IOutbox.sol";
import "../bridge/IInbox.sol";
import "../bridge/ISequencerInbox.sol";
文件 43 的 88:Machine.sol
pragma solidity ^0.8.0;
import "./ValueStack.sol";
import "./Instructions.sol";
import "./StackFrame.sol";
enum MachineStatus {
RUNNING,
FINISHED,
ERRORED,
TOO_FAR
}
struct Machine {
MachineStatus status;
ValueStack valueStack;
ValueStack internalStack;
StackFrameWindow frameStack;
bytes32 globalStateHash;
uint32 moduleIdx;
uint32 functionIdx;
uint32 functionPc;
bytes32 modulesRoot;
}
library MachineLib {
using StackFrameLib for StackFrameWindow;
using ValueStackLib for ValueStack;
function hash(Machine memory mach) internal pure returns (bytes32) {
if (mach.status == MachineStatus.RUNNING) {
return
keccak256(
abi.encodePacked(
"Machine running:",
mach.valueStack.hash(),
mach.internalStack.hash(),
mach.frameStack.hash(),
mach.globalStateHash,
mach.moduleIdx,
mach.functionIdx,
mach.functionPc,
mach.modulesRoot
)
);
} else if (mach.status == MachineStatus.FINISHED) {
return keccak256(abi.encodePacked("Machine finished:", mach.globalStateHash));
} else if (mach.status == MachineStatus.ERRORED) {
return keccak256(abi.encodePacked("Machine errored:"));
} else if (mach.status == MachineStatus.TOO_FAR) {
return keccak256(abi.encodePacked("Machine too far:"));
} else {
revert("BAD_MACH_STATUS");
}
}
}
文件 44 的 88:MerkleLib.sol
pragma solidity ^0.8.4;
import {MerkleProofTooLong} from "./Error.sol";
library MerkleLib {
function generateRoot(bytes32[] memory _hashes) internal pure returns (bytes32) {
bytes32[] memory prevLayer = _hashes;
while (prevLayer.length > 1) {
bytes32[] memory nextLayer = new bytes32[]((prevLayer.length + 1) / 2);
for (uint256 i = 0; i < nextLayer.length; i++) {
if (2 * i + 1 < prevLayer.length) {
nextLayer[i] = keccak256(
abi.encodePacked(prevLayer[2 * i], prevLayer[2 * i + 1])
);
} else {
nextLayer[i] = prevLayer[2 * i];
}
}
prevLayer = nextLayer;
}
return prevLayer[0];
}
function calculateRoot(
bytes32[] memory nodes,
uint256 route,
bytes32 item
) internal pure returns (bytes32) {
uint256 proofItems = nodes.length;
if (proofItems > 256) revert MerkleProofTooLong(proofItems, 256);
bytes32 h = item;
for (uint256 i = 0; i < proofItems; ) {
bytes32 node = nodes[i];
if ((route & (1 << i)) == 0) {
assembly {
mstore(0x00, h)
mstore(0x20, node)
h := keccak256(0x00, 0x40)
}
} else {
assembly {
mstore(0x00, node)
mstore(0x20, h)
h := keccak256(0x00, 0x40)
}
}
unchecked {
++i;
}
}
return h;
}
}
文件 45 的 88:MerkleProof.sol
pragma solidity ^0.8.0;
import "./Value.sol";
import "./Instructions.sol";
import "./Module.sol";
struct MerkleProof {
bytes32[] counterparts;
}
library MerkleProofLib {
using ModuleLib for Module;
using ValueLib for Value;
function computeRootFromValue(
MerkleProof memory proof,
uint256 index,
Value memory leaf
) internal pure returns (bytes32) {
return computeRootUnsafe(proof, index, leaf.hash(), "Value merkle tree:");
}
function computeRootFromInstruction(
MerkleProof memory proof,
uint256 index,
Instruction memory inst
) internal pure returns (bytes32) {
return computeRootUnsafe(proof, index, Instructions.hash(inst), "Instruction merkle tree:");
}
function computeRootFromFunction(
MerkleProof memory proof,
uint256 index,
bytes32 codeRoot
) internal pure returns (bytes32) {
bytes32 h = keccak256(abi.encodePacked("Function:", codeRoot));
return computeRootUnsafe(proof, index, h, "Function merkle tree:");
}
function computeRootFromMemory(
MerkleProof memory proof,
uint256 index,
bytes32 contents
) internal pure returns (bytes32) {
bytes32 h = keccak256(abi.encodePacked("Memory leaf:", contents));
return computeRootUnsafe(proof, index, h, "Memory merkle tree:");
}
function computeRootFromElement(
MerkleProof memory proof,
uint256 index,
bytes32 funcTypeHash,
Value memory val
) internal pure returns (bytes32) {
bytes32 h = keccak256(abi.encodePacked("Table element:", funcTypeHash, val.hash()));
return computeRootUnsafe(proof, index, h, "Table element merkle tree:");
}
function computeRootFromTable(
MerkleProof memory proof,
uint256 index,
uint8 tableType,
uint64 tableSize,
bytes32 elementsRoot
) internal pure returns (bytes32) {
bytes32 h = keccak256(abi.encodePacked("Table:", tableType, tableSize, elementsRoot));
return computeRootUnsafe(proof, index, h, "Table merkle tree:");
}
function computeRootFromModule(
MerkleProof memory proof,
uint256 index,
Module memory mod
) internal pure returns (bytes32) {
return computeRootUnsafe(proof, index, mod.hash(), "Module merkle tree:");
}
function computeRootUnsafe(
MerkleProof memory proof,
uint256 index,
bytes32 leafHash,
string memory prefix
) internal pure returns (bytes32 h) {
h = leafHash;
for (uint256 layer = 0; layer < proof.counterparts.length; layer++) {
if (index & 1 == 0) {
h = keccak256(abi.encodePacked(prefix, h, proof.counterparts[layer]));
} else {
h = keccak256(abi.encodePacked(prefix, proof.counterparts[layer], h));
}
index >>= 1;
}
}
}
文件 46 的 88:MessageTester.sol
pragma solidity ^0.8.0;
import "../bridge/Messages.sol";
contract MessageTester {
function messageHash(
uint8 messageType,
address sender,
uint64 blockNumber,
uint64 timestamp,
uint256 inboxSeqNum,
uint256 gasPriceL1,
bytes32 messageDataHash
) public pure returns (bytes32) {
return
Messages.messageHash(
messageType,
sender,
blockNumber,
timestamp,
inboxSeqNum,
gasPriceL1,
messageDataHash
);
}
function accumulateInboxMessage(bytes32 inbox, bytes32 message) public pure returns (bytes32) {
return Messages.accumulateInboxMessage(inbox, message);
}
}
文件 47 的 88:MessageTypes.sol
pragma solidity ^0.8.4;
uint8 constant L2_MSG = 3;
uint8 constant L1MessageType_L2FundedByL1 = 7;
uint8 constant L1MessageType_submitRetryableTx = 9;
uint8 constant L1MessageType_ethDeposit = 12;
uint8 constant L1MessageType_batchPostingReport = 13;
uint8 constant L2MessageType_unsignedEOATx = 0;
uint8 constant L2MessageType_unsignedContractTx = 1;
uint8 constant ROLLUP_PROTOCOL_EVENT_TYPE = 8;
uint8 constant INITIALIZATION_MSG_TYPE = 11;
文件 48 的 88:Messages.sol
pragma solidity ^0.8.0;
library Messages {
function messageHash(
uint8 kind,
address sender,
uint64 blockNumber,
uint64 timestamp,
uint256 inboxSeqNum,
uint256 baseFeeL1,
bytes32 messageDataHash
) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
kind,
sender,
blockNumber,
timestamp,
inboxSeqNum,
baseFeeL1,
messageDataHash
)
);
}
function accumulateInboxMessage(bytes32 prevAcc, bytes32 message)
internal
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(prevAcc, message));
}
}
文件 49 的 88:MockResultReceiver.sol
pragma solidity ^0.8.0;
import "../challenge/IChallengeResultReceiver.sol";
import "../challenge/IChallengeManager.sol";
contract MockResultReceiver is IChallengeResultReceiver {
IChallengeManager public manager;
address public winner;
address public loser;
uint256 public challengeIndex;
event ChallengeCompleted(
uint256 indexed challengeIndex,
address indexed winner,
address indexed loser
);
constructor(IChallengeManager manager_) {
manager = manager_;
}
function createChallenge(
bytes32 wasmModuleRoot_,
MachineStatus[2] calldata startAndEndMachineStatuses_,
GlobalState[2] calldata startAndEndGlobalStates_,
uint64 numBlocks,
address asserter_,
address challenger_,
uint256 asserterTimeLeft_,
uint256 challengerTimeLeft_
) external returns (uint64) {
return
manager.createChallenge(
wasmModuleRoot_,
startAndEndMachineStatuses_,
startAndEndGlobalStates_,
numBlocks,
asserter_,
challenger_,
asserterTimeLeft_,
challengerTimeLeft_
);
}
function completeChallenge(
uint256 challengeIndex_,
address winner_,
address loser_
) external override {
winner = winner_;
loser = loser_;
challengeIndex = challengeIndex_;
emit ChallengeCompleted(challengeIndex, winner_, loser_);
}
}
文件 50 的 88:Module.sol
pragma solidity ^0.8.0;
import "./ModuleMemory.sol";
struct Module {
bytes32 globalsMerkleRoot;
ModuleMemory moduleMemory;
bytes32 tablesMerkleRoot;
bytes32 functionsMerkleRoot;
uint32 internalsOffset;
}
library ModuleLib {
using ModuleMemoryLib for ModuleMemory;
function hash(Module memory mod) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
"Module:",
mod.globalsMerkleRoot,
mod.moduleMemory.hash(),
mod.tablesMerkleRoot,
mod.functionsMerkleRoot,
mod.internalsOffset
)
);
}
}
文件 51 的 88:ModuleMemory.sol
pragma solidity ^0.8.0;
import "./MerkleProof.sol";
import "./Deserialize.sol";
struct ModuleMemory {
uint64 size;
uint64 maxSize;
bytes32 merkleRoot;
}
library ModuleMemoryLib {
using MerkleProofLib for MerkleProof;
function hash(ModuleMemory memory mem) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("Memory:", mem.size, mem.maxSize, mem.merkleRoot));
}
function proveLeaf(
ModuleMemory memory mem,
uint256 leafIdx,
bytes calldata proof,
uint256 startOffset
)
internal
pure
returns (
bytes32 contents,
uint256 offset,
MerkleProof memory merkle
)
{
offset = startOffset;
(contents, offset) = Deserialize.b32(proof, offset);
(merkle, offset) = Deserialize.merkleProof(proof, offset);
bytes32 recomputedRoot = merkle.computeRootFromMemory(leafIdx, contents);
require(recomputedRoot == mem.merkleRoot, "WRONG_MEM_ROOT");
}
}
文件 52 的 88:Node.sol
pragma solidity ^0.8.0;
struct Node {
bytes32 stateHash;
bytes32 challengeHash;
bytes32 confirmData;
uint64 prevNum;
uint64 deadlineBlock;
uint64 noChildConfirmedBeforeBlock;
uint64 stakerCount;
uint64 childStakerCount;
uint64 firstChildBlock;
uint64 latestChildNumber;
uint64 createdAtBlock;
bytes32 nodeHash;
}
library NodeLib {
function createNode(
bytes32 _stateHash,
bytes32 _challengeHash,
bytes32 _confirmData,
uint64 _prevNum,
uint64 _deadlineBlock,
bytes32 _nodeHash
) internal view returns (Node memory) {
Node memory node;
node.stateHash = _stateHash;
node.challengeHash = _challengeHash;
node.confirmData = _confirmData;
node.prevNum = _prevNum;
node.deadlineBlock = _deadlineBlock;
node.noChildConfirmedBeforeBlock = _deadlineBlock;
node.createdAtBlock = uint64(block.number);
node.nodeHash = _nodeHash;
return node;
}
function childCreated(Node storage self, uint64 number) internal {
if (self.firstChildBlock == 0) {
self.firstChildBlock = uint64(block.number);
}
self.latestChildNumber = number;
}
function newChildConfirmDeadline(Node storage self, uint64 deadline) internal {
self.noChildConfirmedBeforeBlock = deadline;
}
function requirePastDeadline(Node memory self) internal view {
require(block.number >= self.deadlineBlock, "BEFORE_DEADLINE");
}
function requirePastChildConfirmDeadline(Node memory self) internal view {
require(block.number >= self.noChildConfirmedBeforeBlock, "CHILD_TOO_RECENT");
}
}
文件 53 的 88:OneStepProofEntry.sol
pragma solidity ^0.8.0;
import "../state/Deserialize.sol";
import "../state/Machine.sol";
import "../state/MerkleProof.sol";
import "./IOneStepProver.sol";
import "./IOneStepProofEntry.sol";
contract OneStepProofEntry is IOneStepProofEntry {
using MerkleProofLib for MerkleProof;
using MachineLib for Machine;
IOneStepProver public prover0;
IOneStepProver public proverMem;
IOneStepProver public proverMath;
IOneStepProver public proverHostIo;
constructor(
IOneStepProver prover0_,
IOneStepProver proverMem_,
IOneStepProver proverMath_,
IOneStepProver proverHostIo_
) {
prover0 = prover0_;
proverMem = proverMem_;
proverMath = proverMath_;
proverHostIo = proverHostIo_;
}
function proveOneStep(
ExecutionContext calldata execCtx,
uint256 machineStep,
bytes32 beforeHash,
bytes calldata proof
) external view override returns (bytes32 afterHash) {
Machine memory mach;
Module memory mod;
MerkleProof memory modProof;
Instruction memory inst;
{
uint256 offset = 0;
(mach, offset) = Deserialize.machine(proof, offset);
require(mach.hash() == beforeHash, "MACHINE_BEFORE_HASH");
if (mach.status != MachineStatus.RUNNING) {
return mach.hash();
}
if (machineStep + 1 == OneStepProofEntryLib.MAX_STEPS) {
mach.status = MachineStatus.ERRORED;
return mach.hash();
}
(mod, offset) = Deserialize.module(proof, offset);
(modProof, offset) = Deserialize.merkleProof(proof, offset);
require(
modProof.computeRootFromModule(mach.moduleIdx, mod) == mach.modulesRoot,
"MODULES_ROOT"
);
{
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");
}
proof = proof[offset:];
}
uint256 oldModIdx = mach.moduleIdx;
mach.functionPc += 1;
uint16 opcode = inst.opcode;
IOneStepProver prover;
if (
(opcode >= Instructions.I32_LOAD && opcode <= Instructions.I64_LOAD32_U) ||
(opcode >= Instructions.I32_STORE && opcode <= Instructions.I64_STORE32) ||
opcode == Instructions.MEMORY_SIZE ||
opcode == Instructions.MEMORY_GROW
) {
prover = proverMem;
} else if (
(opcode == Instructions.I32_EQZ || opcode == Instructions.I64_EQZ) ||
(opcode >= Instructions.I32_RELOP_BASE &&
opcode <= Instructions.I32_RELOP_BASE + Instructions.IRELOP_LAST) ||
(opcode >= Instructions.I32_UNOP_BASE &&
opcode <= Instructions.I32_UNOP_BASE + Instructions.IUNOP_LAST) ||
(opcode >= Instructions.I32_ADD && opcode <= Instructions.I32_ROTR) ||
(opcode >= Instructions.I64_RELOP_BASE &&
opcode <= Instructions.I64_RELOP_BASE + Instructions.IRELOP_LAST) ||
(opcode >= Instructions.I64_UNOP_BASE &&
opcode <= Instructions.I64_UNOP_BASE + Instructions.IUNOP_LAST) ||
(opcode >= Instructions.I64_ADD && opcode <= Instructions.I64_ROTR) ||
(opcode == Instructions.I32_WRAP_I64) ||
(opcode == Instructions.I64_EXTEND_I32_S || opcode == Instructions.I64_EXTEND_I32_U) ||
(opcode >= Instructions.I32_EXTEND_8S && opcode <= Instructions.I64_EXTEND_32S) ||
(opcode >= Instructions.I32_REINTERPRET_F32 &&
opcode <= Instructions.F64_REINTERPRET_I64)
) {
prover = proverMath;
} else if (
(opcode >= Instructions.GET_GLOBAL_STATE_BYTES32 &&
opcode <= Instructions.SET_GLOBAL_STATE_U64) ||
(opcode >= Instructions.READ_PRE_IMAGE && opcode <= Instructions.HALT_AND_SET_FINISHED)
) {
prover = proverHostIo;
} else {
prover = prover0;
}
(mach, mod) = prover.executeOneStep(execCtx, mach, mod, inst, proof);
mach.modulesRoot = modProof.computeRootFromModule(oldModIdx, mod);
return mach.hash();
}
}
文件 54 的 88:OneStepProver0.sol
pragma solidity ^0.8.0;
import "../state/Value.sol";
import "../state/Machine.sol";
import "../state/Module.sol";
import "../state/Deserialize.sol";
import "./IOneStepProver.sol";
contract OneStepProver0 is IOneStepProver {
using MerkleProofLib for MerkleProof;
using StackFrameLib for StackFrameWindow;
using ValueLib for Value;
using ValueStackLib for ValueStack;
function executeUnreachable(
Machine memory mach,
Module memory,
Instruction calldata,
bytes calldata
) internal pure {
mach.status = MachineStatus.ERRORED;
}
function executeNop(
Machine memory mach,
Module memory,
Instruction calldata,
bytes calldata
) internal pure {
}
function executeConstPush(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
uint16 opcode = inst.opcode;
ValueType ty;
if (opcode == Instructions.I32_CONST) {
ty = ValueType.I32;
} else if (opcode == Instructions.I64_CONST) {
ty = ValueType.I64;
} else if (opcode == Instructions.F32_CONST) {
ty = ValueType.F32;
} else if (opcode == Instructions.F64_CONST) {
ty = ValueType.F64;
} else {
revert("CONST_PUSH_INVALID_OPCODE");
}
mach.valueStack.push(Value({valueType: ty, contents: uint64(inst.argumentData)}));
}
function executeDrop(
Machine memory mach,
Module memory,
Instruction calldata,
bytes calldata
) internal pure {
mach.valueStack.pop();
}
function executeSelect(
Machine memory mach,
Module memory,
Instruction calldata,
bytes calldata
) internal pure {
uint32 selector = mach.valueStack.pop().assumeI32();
Value memory b = mach.valueStack.pop();
Value memory a = mach.valueStack.pop();
if (selector != 0) {
mach.valueStack.push(a);
} else {
mach.valueStack.push(b);
}
}
function executeReturn(
Machine memory mach,
Module memory,
Instruction calldata,
bytes calldata
) internal pure {
StackFrame memory frame = mach.frameStack.pop();
if (frame.returnPc.valueType == ValueType.REF_NULL) {
mach.status = MachineStatus.ERRORED;
return;
} else if (frame.returnPc.valueType != ValueType.INTERNAL_REF) {
revert("INVALID_RETURN_PC_TYPE");
}
uint256 data = frame.returnPc.contents;
uint32 pc = uint32(data);
uint32 func = uint32(data >> 32);
uint32 mod = uint32(data >> 64);
require(data >> 96 == 0, "INVALID_RETURN_PC_DATA");
mach.functionPc = pc;
mach.functionIdx = func;
mach.moduleIdx = mod;
}
function createReturnValue(Machine memory mach) internal pure returns (Value memory) {
uint256 returnData = 0;
returnData |= mach.functionPc;
returnData |= uint256(mach.functionIdx) << 32;
returnData |= uint256(mach.moduleIdx) << 64;
return Value({valueType: ValueType.INTERNAL_REF, contents: returnData});
}
function executeCall(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
mach.valueStack.push(createReturnValue(mach));
StackFrame memory frame = mach.frameStack.peek();
mach.valueStack.push(ValueLib.newI32(frame.callerModule));
mach.valueStack.push(ValueLib.newI32(frame.callerModuleInternals));
uint32 idx = uint32(inst.argumentData);
require(idx == inst.argumentData, "BAD_CALL_DATA");
mach.functionIdx = idx;
mach.functionPc = 0;
}
function executeCrossModuleCall(
Machine memory mach,
Module memory mod,
Instruction calldata inst,
bytes calldata
) internal pure {
mach.valueStack.push(createReturnValue(mach));
mach.valueStack.push(ValueLib.newI32(mach.moduleIdx));
mach.valueStack.push(ValueLib.newI32(mod.internalsOffset));
uint32 func = uint32(inst.argumentData);
uint32 module = uint32(inst.argumentData >> 32);
require(inst.argumentData >> 64 == 0, "BAD_CROSS_MODULE_CALL_DATA");
mach.moduleIdx = module;
mach.functionIdx = func;
mach.functionPc = 0;
}
function executeCallerModuleInternalCall(
Machine memory mach,
Module memory mod,
Instruction calldata inst,
bytes calldata
) internal pure {
mach.valueStack.push(createReturnValue(mach));
mach.valueStack.push(ValueLib.newI32(mach.moduleIdx));
mach.valueStack.push(ValueLib.newI32(mod.internalsOffset));
StackFrame memory frame = mach.frameStack.peek();
if (frame.callerModuleInternals == 0) {
mach.status = MachineStatus.ERRORED;
return;
}
uint32 offset = uint32(inst.argumentData);
require(offset == inst.argumentData, "BAD_CALLER_INTERNAL_CALL_DATA");
mach.moduleIdx = frame.callerModule;
mach.functionIdx = frame.callerModuleInternals + offset;
mach.functionPc = 0;
}
function executeCallIndirect(
Machine memory mach,
Module memory mod,
Instruction calldata inst,
bytes calldata proof
) internal pure {
uint32 funcIdx;
{
uint32 elementIdx = mach.valueStack.pop().assumeI32();
bytes32 elemsRoot;
bytes32 wantedFuncTypeHash;
uint256 offset = 0;
{
uint64 tableIdx;
uint8 tableType;
uint64 tableSize;
MerkleProof memory tableMerkleProof;
(tableIdx, offset) = Deserialize.u64(proof, offset);
(wantedFuncTypeHash, offset) = Deserialize.b32(proof, offset);
(tableType, offset) = Deserialize.u8(proof, offset);
(tableSize, offset) = Deserialize.u64(proof, offset);
(elemsRoot, offset) = Deserialize.b32(proof, offset);
(tableMerkleProof, offset) = Deserialize.merkleProof(proof, offset);
bytes32 recomputed = keccak256(
abi.encodePacked("Call indirect:", tableIdx, wantedFuncTypeHash)
);
require(recomputed == bytes32(inst.argumentData), "BAD_CALL_INDIRECT_DATA");
recomputed = tableMerkleProof.computeRootFromTable(
tableIdx,
tableType,
tableSize,
elemsRoot
);
require(recomputed == mod.tablesMerkleRoot, "BAD_TABLES_ROOT");
if (elementIdx >= tableSize) {
mach.status = MachineStatus.ERRORED;
return;
}
}
bytes32 elemFuncTypeHash;
Value memory functionPointer;
MerkleProof memory elementMerkleProof;
(elemFuncTypeHash, offset) = Deserialize.b32(proof, offset);
(functionPointer, offset) = Deserialize.value(proof, offset);
(elementMerkleProof, offset) = Deserialize.merkleProof(proof, offset);
bytes32 recomputedElemRoot = elementMerkleProof.computeRootFromElement(
elementIdx,
elemFuncTypeHash,
functionPointer
);
require(recomputedElemRoot == elemsRoot, "BAD_ELEMENTS_ROOT");
if (elemFuncTypeHash != wantedFuncTypeHash) {
mach.status = MachineStatus.ERRORED;
return;
}
if (functionPointer.valueType == ValueType.REF_NULL) {
mach.status = MachineStatus.ERRORED;
return;
} else if (functionPointer.valueType == ValueType.FUNC_REF) {
funcIdx = uint32(functionPointer.contents);
require(funcIdx == functionPointer.contents, "BAD_FUNC_REF_CONTENTS");
} else {
revert("BAD_ELEM_TYPE");
}
}
mach.valueStack.push(createReturnValue(mach));
StackFrame memory frame = mach.frameStack.peek();
mach.valueStack.push(ValueLib.newI32(frame.callerModule));
mach.valueStack.push(ValueLib.newI32(frame.callerModuleInternals));
mach.functionIdx = funcIdx;
mach.functionPc = 0;
}
function executeArbitraryJump(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
uint32 pc = uint32(inst.argumentData);
require(pc == inst.argumentData, "BAD_CALL_DATA");
mach.functionPc = pc;
}
function executeArbitraryJumpIf(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
uint32 cond = mach.valueStack.pop().assumeI32();
if (cond != 0) {
uint32 pc = uint32(inst.argumentData);
require(pc == inst.argumentData, "BAD_CALL_DATA");
mach.functionPc = pc;
}
}
function merkleProveGetValue(
bytes32 merkleRoot,
uint256 index,
bytes calldata proof
) internal pure returns (Value memory) {
uint256 offset = 0;
Value memory proposedVal;
MerkleProof memory merkle;
(proposedVal, offset) = Deserialize.value(proof, offset);
(merkle, offset) = Deserialize.merkleProof(proof, offset);
bytes32 recomputedRoot = merkle.computeRootFromValue(index, proposedVal);
require(recomputedRoot == merkleRoot, "WRONG_MERKLE_ROOT");
return proposedVal;
}
function merkleProveSetValue(
bytes32 merkleRoot,
uint256 index,
Value memory newVal,
bytes calldata proof
) internal pure returns (bytes32) {
Value memory oldVal;
uint256 offset = 0;
MerkleProof memory merkle;
(oldVal, offset) = Deserialize.value(proof, offset);
(merkle, offset) = Deserialize.merkleProof(proof, offset);
bytes32 recomputedRoot = merkle.computeRootFromValue(index, oldVal);
require(recomputedRoot == merkleRoot, "WRONG_MERKLE_ROOT");
return merkle.computeRootFromValue(index, newVal);
}
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);
}
function executeLocalSet(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata proof
) internal pure {
Value memory newVal = mach.valueStack.pop();
StackFrame memory frame = mach.frameStack.peek();
frame.localsMerkleRoot = merkleProveSetValue(
frame.localsMerkleRoot,
inst.argumentData,
newVal,
proof
);
}
function executeGlobalGet(
Machine memory mach,
Module memory mod,
Instruction calldata inst,
bytes calldata proof
) internal pure {
Value memory val = merkleProveGetValue(mod.globalsMerkleRoot, inst.argumentData, proof);
mach.valueStack.push(val);
}
function executeGlobalSet(
Machine memory mach,
Module memory mod,
Instruction calldata inst,
bytes calldata proof
) internal pure {
Value memory newVal = mach.valueStack.pop();
mod.globalsMerkleRoot = merkleProveSetValue(
mod.globalsMerkleRoot,
inst.argumentData,
newVal,
proof
);
}
function executeInitFrame(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
Value memory callerModuleInternals = mach.valueStack.pop();
Value memory callerModule = mach.valueStack.pop();
Value memory returnPc = mach.valueStack.pop();
StackFrame memory newFrame = StackFrame({
returnPc: returnPc,
localsMerkleRoot: bytes32(inst.argumentData),
callerModule: callerModule.assumeI32(),
callerModuleInternals: callerModuleInternals.assumeI32()
});
mach.frameStack.push(newFrame);
}
function executeMoveInternal(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
Value memory val;
if (inst.opcode == Instructions.MOVE_FROM_STACK_TO_INTERNAL) {
val = mach.valueStack.pop();
mach.internalStack.push(val);
} else if (inst.opcode == Instructions.MOVE_FROM_INTERNAL_TO_STACK) {
val = mach.internalStack.pop();
mach.valueStack.push(val);
} else {
revert("MOVE_INTERNAL_INVALID_OPCODE");
}
}
function executeDup(
Machine memory mach,
Module memory,
Instruction calldata,
bytes calldata
) internal pure {
Value memory val = mach.valueStack.peek();
mach.valueStack.push(val);
}
function executeOneStep(
ExecutionContext calldata,
Machine calldata startMach,
Module calldata startMod,
Instruction calldata inst,
bytes calldata proof
) external pure override returns (Machine memory mach, Module memory mod) {
mach = startMach;
mod = startMod;
uint16 opcode = inst.opcode;
function(Machine memory, Module memory, Instruction calldata, bytes calldata)
internal
pure impl;
if (opcode == Instructions.UNREACHABLE) {
impl = executeUnreachable;
} else if (opcode == Instructions.NOP) {
impl = executeNop;
} else if (opcode == Instructions.RETURN) {
impl = executeReturn;
} else if (opcode == Instructions.CALL) {
impl = executeCall;
} else if (opcode == Instructions.CROSS_MODULE_CALL) {
impl = executeCrossModuleCall;
} else if (opcode == Instructions.CALLER_MODULE_INTERNAL_CALL) {
impl = executeCallerModuleInternalCall;
} else if (opcode == Instructions.CALL_INDIRECT) {
impl = executeCallIndirect;
} else if (opcode == Instructions.ARBITRARY_JUMP) {
impl = executeArbitraryJump;
} else if (opcode == Instructions.ARBITRARY_JUMP_IF) {
impl = executeArbitraryJumpIf;
} else if (opcode == Instructions.LOCAL_GET) {
impl = executeLocalGet;
} else if (opcode == Instructions.LOCAL_SET) {
impl = executeLocalSet;
} else if (opcode == Instructions.GLOBAL_GET) {
impl = executeGlobalGet;
} else if (opcode == Instructions.GLOBAL_SET) {
impl = executeGlobalSet;
} else if (opcode == Instructions.INIT_FRAME) {
impl = executeInitFrame;
} else if (opcode == Instructions.DROP) {
impl = executeDrop;
} else if (opcode == Instructions.SELECT) {
impl = executeSelect;
} else if (opcode >= Instructions.I32_CONST && opcode <= Instructions.F64_CONST) {
impl = executeConstPush;
} else if (
opcode == Instructions.MOVE_FROM_STACK_TO_INTERNAL ||
opcode == Instructions.MOVE_FROM_INTERNAL_TO_STACK
) {
impl = executeMoveInternal;
} else if (opcode == Instructions.DUP) {
impl = executeDup;
} else {
revert("INVALID_OPCODE");
}
impl(mach, mod, inst, proof);
}
}
文件 55 的 88:OneStepProverHostIo.sol
pragma solidity ^0.8.0;
import "../state/Value.sol";
import "../state/Machine.sol";
import "../state/Deserialize.sol";
import "./IOneStepProver.sol";
import "../bridge/Messages.sol";
import "../bridge/IBridge.sol";
contract OneStepProverHostIo is IOneStepProver {
using GlobalStateLib for GlobalState;
using MerkleProofLib for MerkleProof;
using ModuleMemoryLib for ModuleMemory;
using ValueLib for Value;
using ValueStackLib for ValueStack;
uint256 private constant LEAF_SIZE = 32;
uint256 private constant INBOX_NUM = 2;
uint64 private constant INBOX_HEADER_LEN = 40;
uint64 private constant DELAYED_HEADER_LEN = 112 + 1;
function setLeafByte(
bytes32 oldLeaf,
uint256 idx,
uint8 val
) internal pure returns (bytes32) {
require(idx < LEAF_SIZE, "BAD_SET_LEAF_BYTE_IDX");
uint256 leafShift = (LEAF_SIZE - 1 - idx) * 8;
uint256 newLeaf = uint256(oldLeaf);
newLeaf &= ~(0xFF << leafShift);
newLeaf |= uint256(val) << leafShift;
return bytes32(newLeaf);
}
function executeGetOrSetBytes32(
Machine memory mach,
Module memory mod,
GlobalState memory state,
Instruction calldata inst,
bytes calldata proof
) internal pure {
uint256 ptr = mach.valueStack.pop().assumeI32();
uint32 idx = mach.valueStack.pop().assumeI32();
if (idx >= GlobalStateLib.BYTES32_VALS_NUM) {
mach.status = MachineStatus.ERRORED;
return;
}
if (ptr + 32 > mod.moduleMemory.size || ptr % LEAF_SIZE != 0) {
mach.status = MachineStatus.ERRORED;
return;
}
uint256 leafIdx = ptr / LEAF_SIZE;
uint256 proofOffset = 0;
bytes32 startLeafContents;
MerkleProof memory merkleProof;
(startLeafContents, proofOffset, merkleProof) = mod.moduleMemory.proveLeaf(
leafIdx,
proof,
proofOffset
);
if (inst.opcode == Instructions.GET_GLOBAL_STATE_BYTES32) {
mod.moduleMemory.merkleRoot = merkleProof.computeRootFromMemory(
leafIdx,
state.bytes32Vals[idx]
);
} else if (inst.opcode == Instructions.SET_GLOBAL_STATE_BYTES32) {
state.bytes32Vals[idx] = startLeafContents;
} else {
revert("BAD_GLOBAL_STATE_OPCODE");
}
}
function executeGetU64(Machine memory mach, GlobalState memory state) internal pure {
uint32 idx = mach.valueStack.pop().assumeI32();
if (idx >= GlobalStateLib.U64_VALS_NUM) {
mach.status = MachineStatus.ERRORED;
return;
}
mach.valueStack.push(ValueLib.newI64(state.u64Vals[idx]));
}
function executeSetU64(Machine memory mach, GlobalState memory state) internal pure {
uint64 val = mach.valueStack.pop().assumeI64();
uint32 idx = mach.valueStack.pop().assumeI32();
if (idx >= GlobalStateLib.U64_VALS_NUM) {
mach.status = MachineStatus.ERRORED;
return;
}
state.u64Vals[idx] = val;
}
function executeReadPreImage(
ExecutionContext calldata,
Machine memory mach,
Module memory mod,
Instruction calldata,
bytes calldata proof
) internal pure {
uint256 preimageOffset = mach.valueStack.pop().assumeI32();
uint256 ptr = mach.valueStack.pop().assumeI32();
if (ptr + 32 > mod.moduleMemory.size || ptr % LEAF_SIZE != 0) {
mach.status = MachineStatus.ERRORED;
return;
}
uint256 leafIdx = ptr / LEAF_SIZE;
uint256 proofOffset = 0;
bytes32 leafContents;
MerkleProof memory merkleProof;
(leafContents, proofOffset, merkleProof) = mod.moduleMemory.proveLeaf(
leafIdx,
proof,
proofOffset
);
bytes memory extracted;
uint8 proofType = uint8(proof[proofOffset]);
proofOffset++;
if (proofType == 0) {
bytes calldata preimage = proof[proofOffset:];
require(keccak256(preimage) == leafContents, "BAD_PREIMAGE");
uint256 preimageEnd = preimageOffset + 32;
if (preimageEnd > preimage.length) {
preimageEnd = preimage.length;
}
extracted = preimage[preimageOffset:preimageEnd];
} else {
revert("UNKNOWN_PREIMAGE_PROOF");
}
for (uint256 i = 0; i < extracted.length; i++) {
leafContents = setLeafByte(leafContents, i, uint8(extracted[i]));
}
mod.moduleMemory.merkleRoot = merkleProof.computeRootFromMemory(leafIdx, leafContents);
mach.valueStack.push(ValueLib.newI32(uint32(extracted.length)));
}
function validateSequencerInbox(
ExecutionContext calldata execCtx,
uint64 msgIndex,
bytes calldata message
) internal view returns (bool) {
require(message.length >= INBOX_HEADER_LEN, "BAD_SEQINBOX_PROOF");
uint64 afterDelayedMsg;
(afterDelayedMsg, ) = Deserialize.u64(message, 32);
bytes32 messageHash = keccak256(message);
bytes32 beforeAcc;
bytes32 delayedAcc;
if (msgIndex > 0) {
beforeAcc = execCtx.bridge.sequencerInboxAccs(msgIndex - 1);
}
if (afterDelayedMsg > 0) {
delayedAcc = execCtx.bridge.delayedInboxAccs(afterDelayedMsg - 1);
}
bytes32 acc = keccak256(abi.encodePacked(beforeAcc, messageHash, delayedAcc));
require(acc == execCtx.bridge.sequencerInboxAccs(msgIndex), "BAD_SEQINBOX_MESSAGE");
return true;
}
function validateDelayedInbox(
ExecutionContext calldata execCtx,
uint64 msgIndex,
bytes calldata message
) internal view returns (bool) {
require(message.length >= DELAYED_HEADER_LEN, "BAD_DELAYED_PROOF");
bytes32 beforeAcc;
if (msgIndex > 0) {
beforeAcc = execCtx.bridge.delayedInboxAccs(msgIndex - 1);
}
bytes32 messageDataHash = keccak256(message[DELAYED_HEADER_LEN:]);
bytes1 kind = message[0];
uint256 sender;
(sender, ) = Deserialize.u256(message, 1);
bytes32 messageHash = keccak256(
abi.encodePacked(kind, uint160(sender), message[33:DELAYED_HEADER_LEN], messageDataHash)
);
bytes32 acc = Messages.accumulateInboxMessage(beforeAcc, messageHash);
require(acc == execCtx.bridge.delayedInboxAccs(msgIndex), "BAD_DELAYED_MESSAGE");
return true;
}
function executeReadInboxMessage(
ExecutionContext calldata execCtx,
Machine memory mach,
Module memory mod,
Instruction calldata inst,
bytes calldata proof
) internal view {
uint256 messageOffset = mach.valueStack.pop().assumeI32();
uint256 ptr = mach.valueStack.pop().assumeI32();
uint256 msgIndex = mach.valueStack.pop().assumeI64();
if (
inst.argumentData == Instructions.INBOX_INDEX_SEQUENCER &&
msgIndex >= execCtx.maxInboxMessagesRead
) {
mach.status = MachineStatus.TOO_FAR;
return;
}
if (ptr + 32 > mod.moduleMemory.size || ptr % LEAF_SIZE != 0) {
mach.status = MachineStatus.ERRORED;
return;
}
uint256 leafIdx = ptr / LEAF_SIZE;
uint256 proofOffset = 0;
bytes32 leafContents;
MerkleProof memory merkleProof;
(leafContents, proofOffset, merkleProof) = mod.moduleMemory.proveLeaf(
leafIdx,
proof,
proofOffset
);
{
require(proof[proofOffset] == 0, "UNKNOWN_INBOX_PROOF");
proofOffset++;
function(ExecutionContext calldata, uint64, bytes calldata)
internal
view
returns (bool) inboxValidate;
bool success;
if (inst.argumentData == Instructions.INBOX_INDEX_SEQUENCER) {
inboxValidate = validateSequencerInbox;
} else if (inst.argumentData == Instructions.INBOX_INDEX_DELAYED) {
inboxValidate = validateDelayedInbox;
} else {
mach.status = MachineStatus.ERRORED;
return;
}
success = inboxValidate(execCtx, uint64(msgIndex), proof[proofOffset:]);
if (!success) {
mach.status = MachineStatus.ERRORED;
return;
}
}
require(proof.length >= proofOffset, "BAD_MESSAGE_PROOF");
uint256 messageLength = proof.length - proofOffset;
uint32 i = 0;
for (; i < 32 && messageOffset + i < messageLength; i++) {
leafContents = setLeafByte(
leafContents,
i,
uint8(proof[proofOffset + messageOffset + i])
);
}
mod.moduleMemory.merkleRoot = merkleProof.computeRootFromMemory(leafIdx, leafContents);
mach.valueStack.push(ValueLib.newI32(i));
}
function executeHaltAndSetFinished(
ExecutionContext calldata,
Machine memory mach,
Module memory,
Instruction calldata,
bytes calldata
) internal pure {
mach.status = MachineStatus.FINISHED;
}
function executeGlobalStateAccess(
ExecutionContext calldata,
Machine memory mach,
Module memory mod,
Instruction calldata inst,
bytes calldata proof
) internal pure {
uint16 opcode = inst.opcode;
GlobalState memory state;
uint256 proofOffset = 0;
(state, proofOffset) = Deserialize.globalState(proof, proofOffset);
require(state.hash() == mach.globalStateHash, "BAD_GLOBAL_STATE");
if (
opcode == Instructions.GET_GLOBAL_STATE_BYTES32 ||
opcode == Instructions.SET_GLOBAL_STATE_BYTES32
) {
executeGetOrSetBytes32(mach, mod, state, inst, proof[proofOffset:]);
} else if (opcode == Instructions.GET_GLOBAL_STATE_U64) {
executeGetU64(mach, state);
} else if (opcode == Instructions.SET_GLOBAL_STATE_U64) {
executeSetU64(mach, state);
} else {
revert("INVALID_GLOBALSTATE_OPCODE");
}
mach.globalStateHash = state.hash();
}
function executeOneStep(
ExecutionContext calldata execCtx,
Machine calldata startMach,
Module calldata startMod,
Instruction calldata inst,
bytes calldata proof
) external view override returns (Machine memory mach, Module memory mod) {
mach = startMach;
mod = startMod;
uint16 opcode = inst.opcode;
function(
ExecutionContext calldata,
Machine memory,
Module memory,
Instruction calldata,
bytes calldata
) internal view impl;
if (
opcode >= Instructions.GET_GLOBAL_STATE_BYTES32 &&
opcode <= Instructions.SET_GLOBAL_STATE_U64
) {
impl = executeGlobalStateAccess;
} else if (opcode == Instructions.READ_PRE_IMAGE) {
impl = executeReadPreImage;
} else if (opcode == Instructions.READ_INBOX_MESSAGE) {
impl = executeReadInboxMessage;
} else if (opcode == Instructions.HALT_AND_SET_FINISHED) {
impl = executeHaltAndSetFinished;
} else {
revert("INVALID_MEMORY_OPCODE");
}
impl(execCtx, mach, mod, inst, proof);
}
}
文件 56 的 88:OneStepProverMath.sol
pragma solidity ^0.8.0;
import "../state/Value.sol";
import "../state/Machine.sol";
import "../state/Module.sol";
import "../state/Deserialize.sol";
import "./IOneStepProver.sol";
contract OneStepProverMath is IOneStepProver {
using ValueLib for Value;
using ValueStackLib for ValueStack;
function executeEqz(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
Value memory v = mach.valueStack.pop();
if (inst.opcode == Instructions.I32_EQZ) {
require(v.valueType == ValueType.I32, "NOT_I32");
} else if (inst.opcode == Instructions.I64_EQZ) {
require(v.valueType == ValueType.I64, "NOT_I64");
} else {
revert("BAD_EQZ");
}
uint32 output;
if (v.contents == 0) {
output = 1;
} else {
output = 0;
}
mach.valueStack.push(ValueLib.newI32(output));
}
function signExtend(uint32 a) internal pure returns (uint64) {
if (a & (1 << 31) != 0) {
return uint64(a) | uint64(0xffffffff00000000);
}
return uint64(a);
}
function i64RelOp(
uint64 a,
uint64 b,
uint16 relop
) internal pure returns (bool) {
if (relop == Instructions.IRELOP_EQ) {
return (a == b);
} else if (relop == Instructions.IRELOP_NE) {
return (a != b);
} else if (relop == Instructions.IRELOP_LT_S) {
return (int64(a) < int64(b));
} else if (relop == Instructions.IRELOP_LT_U) {
return (a < b);
} else if (relop == Instructions.IRELOP_GT_S) {
return (int64(a) > int64(b));
} else if (relop == Instructions.IRELOP_GT_U) {
return (a > b);
} else if (relop == Instructions.IRELOP_LE_S) {
return (int64(a) <= int64(b));
} else if (relop == Instructions.IRELOP_LE_U) {
return (a <= b);
} else if (relop == Instructions.IRELOP_GE_S) {
return (int64(a) >= int64(b));
} else if (relop == Instructions.IRELOP_GE_U) {
return (a >= b);
} else {
revert("BAD IRELOP");
}
}
function executeI32RelOp(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
uint32 b = mach.valueStack.pop().assumeI32();
uint32 a = mach.valueStack.pop().assumeI32();
uint16 relop = inst.opcode - Instructions.I32_RELOP_BASE;
uint64 a64;
uint64 b64;
if (
relop == Instructions.IRELOP_LT_S ||
relop == Instructions.IRELOP_GT_S ||
relop == Instructions.IRELOP_LE_S ||
relop == Instructions.IRELOP_GE_S
) {
a64 = signExtend(a);
b64 = signExtend(b);
} else {
a64 = uint64(a);
b64 = uint64(b);
}
bool res = i64RelOp(a64, b64, relop);
mach.valueStack.push(ValueLib.newBoolean(res));
}
function executeI64RelOp(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
uint64 b = mach.valueStack.pop().assumeI64();
uint64 a = mach.valueStack.pop().assumeI64();
uint16 relop = inst.opcode - Instructions.I64_RELOP_BASE;
bool res = i64RelOp(a, b, relop);
mach.valueStack.push(ValueLib.newBoolean(res));
}
function genericIUnOp(
uint64 a,
uint16 unop,
uint16 bits
) internal pure returns (uint32) {
require(bits == 32 || bits == 64, "WRONG USE OF genericUnOp");
if (unop == Instructions.IUNOP_CLZ) {
uint32 curbit = bits;
while (curbit > 0 && (a & (1 << (curbit - 1)) == 0)) {
curbit -= 1;
}
return (bits - curbit);
} else if (unop == Instructions.IUNOP_CTZ) {
uint32 curbit = 0;
while (curbit < bits && ((a & (1 << curbit)) == 0)) {
curbit += 1;
}
return curbit;
} else if (unop == Instructions.IUNOP_POPCNT) {
uint32 curbit = 0;
uint32 res = 0;
while (curbit < bits) {
if ((a & (1 << curbit)) != 0) {
res += 1;
}
curbit++;
}
return res;
}
revert("BAD IUnOp");
}
function executeI32UnOp(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
uint32 a = mach.valueStack.pop().assumeI32();
uint16 unop = inst.opcode - Instructions.I32_UNOP_BASE;
uint32 res = genericIUnOp(a, unop, 32);
mach.valueStack.push(ValueLib.newI32(res));
}
function executeI64UnOp(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
uint64 a = mach.valueStack.pop().assumeI64();
uint16 unop = inst.opcode - Instructions.I64_UNOP_BASE;
uint64 res = uint64(genericIUnOp(a, unop, 64));
mach.valueStack.push(ValueLib.newI64(res));
}
function rotl32(uint32 a, uint32 b) internal pure returns (uint32) {
b %= 32;
return (a << b) | (a >> (32 - b));
}
function rotl64(uint64 a, uint64 b) internal pure returns (uint64) {
b %= 64;
return (a << b) | (a >> (64 - b));
}
function rotr32(uint32 a, uint32 b) internal pure returns (uint32) {
b %= 32;
return (a >> b) | (a << (32 - b));
}
function rotr64(uint64 a, uint64 b) internal pure returns (uint64) {
b %= 64;
return (a >> b) | (a << (64 - b));
}
function genericBinOp(
uint64 a,
uint64 b,
uint16 opcodeOffset
) internal pure returns (uint64, bool) {
unchecked {
if (opcodeOffset == 0) {
return (a + b, false);
} else if (opcodeOffset == 1) {
return (a - b, false);
} else if (opcodeOffset == 2) {
return (a * b, false);
} else if (opcodeOffset == 4) {
if (b == 0) {
return (0, true);
}
return (a / b, false);
} else if (opcodeOffset == 6) {
if (b == 0) {
return (0, true);
}
return (a % b, false);
} else if (opcodeOffset == 7) {
return (a & b, false);
} else if (opcodeOffset == 8) {
return (a | b, false);
} else if (opcodeOffset == 9) {
return (a ^ b, false);
} else {
revert("INVALID_GENERIC_BIN_OP");
}
}
}
function executeI32BinOp(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
uint32 b = mach.valueStack.pop().assumeI32();
uint32 a = mach.valueStack.pop().assumeI32();
uint32 res;
uint16 opcodeOffset = inst.opcode - Instructions.I32_ADD;
unchecked {
if (opcodeOffset == 3) {
if (b == 0 || (int32(a) == -2147483648 && int32(b) == -1)) {
mach.status = MachineStatus.ERRORED;
return;
}
res = uint32(int32(a) / int32(b));
} else if (opcodeOffset == 5) {
if (b == 0) {
mach.status = MachineStatus.ERRORED;
return;
}
res = uint32(int32(a) % int32(b));
} else if (opcodeOffset == 10) {
res = a << (b % 32);
} else if (opcodeOffset == 12) {
res = a >> (b % 32);
} else if (opcodeOffset == 11) {
res = uint32(int32(a) >> (b % 32));
} else if (opcodeOffset == 13) {
res = rotl32(a, b);
} else if (opcodeOffset == 14) {
res = rotr32(a, b);
} else {
(uint64 computed, bool err) = genericBinOp(a, b, opcodeOffset);
if (err) {
mach.status = MachineStatus.ERRORED;
return;
}
res = uint32(computed);
}
}
mach.valueStack.push(ValueLib.newI32(res));
}
function executeI64BinOp(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
uint64 b = mach.valueStack.pop().assumeI64();
uint64 a = mach.valueStack.pop().assumeI64();
uint64 res;
uint16 opcodeOffset = inst.opcode - Instructions.I64_ADD;
unchecked {
if (opcodeOffset == 3) {
if (b == 0 || (int64(a) == -9223372036854775808 && int64(b) == -1)) {
mach.status = MachineStatus.ERRORED;
return;
}
res = uint64(int64(a) / int64(b));
} else if (opcodeOffset == 5) {
if (b == 0) {
mach.status = MachineStatus.ERRORED;
return;
}
res = uint64(int64(a) % int64(b));
} else if (opcodeOffset == 10) {
res = a << (b % 64);
} else if (opcodeOffset == 12) {
res = a >> (b % 64);
} else if (opcodeOffset == 11) {
res = uint64(int64(a) >> (b % 64));
} else if (opcodeOffset == 13) {
res = rotl64(a, b);
} else if (opcodeOffset == 14) {
res = rotr64(a, b);
} else {
bool err;
(res, err) = genericBinOp(a, b, opcodeOffset);
if (err) {
mach.status = MachineStatus.ERRORED;
return;
}
}
}
mach.valueStack.push(ValueLib.newI64(res));
}
function executeI32WrapI64(
Machine memory mach,
Module memory,
Instruction calldata,
bytes calldata
) internal pure {
uint64 a = mach.valueStack.pop().assumeI64();
uint32 a32 = uint32(a);
mach.valueStack.push(ValueLib.newI32(a32));
}
function executeI64ExtendI32(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
uint32 a = mach.valueStack.pop().assumeI32();
uint64 a64;
if (inst.opcode == Instructions.I64_EXTEND_I32_S) {
a64 = signExtend(a);
} else {
a64 = uint64(a);
}
mach.valueStack.push(ValueLib.newI64(a64));
}
function executeExtendSameType(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
ValueType ty;
uint8 sourceBits;
if (inst.opcode == Instructions.I32_EXTEND_8S) {
ty = ValueType.I32;
sourceBits = 8;
} else if (inst.opcode == Instructions.I32_EXTEND_16S) {
ty = ValueType.I32;
sourceBits = 16;
} else if (inst.opcode == Instructions.I64_EXTEND_8S) {
ty = ValueType.I64;
sourceBits = 8;
} else if (inst.opcode == Instructions.I64_EXTEND_16S) {
ty = ValueType.I64;
sourceBits = 16;
} else if (inst.opcode == Instructions.I64_EXTEND_32S) {
ty = ValueType.I64;
sourceBits = 32;
} else {
revert("INVALID_EXTEND_SAME_TYPE");
}
uint256 resultMask;
if (ty == ValueType.I32) {
resultMask = (1 << 32) - 1;
} else {
resultMask = (1 << 64) - 1;
}
Value memory val = mach.valueStack.pop();
require(val.valueType == ty, "BAD_EXTEND_SAME_TYPE_TYPE");
uint256 sourceMask = (1 << sourceBits) - 1;
val.contents &= sourceMask;
if (val.contents & (1 << (sourceBits - 1)) != 0) {
val.contents |= resultMask & ~sourceMask;
}
mach.valueStack.push(val);
}
function executeReinterpret(
Machine memory mach,
Module memory,
Instruction calldata inst,
bytes calldata
) internal pure {
ValueType destTy;
ValueType sourceTy;
if (inst.opcode == Instructions.I32_REINTERPRET_F32) {
destTy = ValueType.I32;
sourceTy = ValueType.F32;
} else if (inst.opcode == Instructions.I64_REINTERPRET_F64) {
destTy = ValueType.I64;
sourceTy = ValueType.F64;
} else if (inst.opcode == Instructions.F32_REINTERPRET_I32) {
destTy = ValueType.F32;
sourceTy = ValueType.I32;
} else if (inst.opcode == Instructions.F64_REINTERPRET_I64) {
destTy = ValueType.F64;
sourceTy = ValueType.I64;
} else {
revert("INVALID_REINTERPRET");
}
Value memory val = mach.valueStack.pop();
require(val.valueType == sourceTy, "INVALID_REINTERPRET_TYPE");
val.valueType = destTy;
mach.valueStack.push(val);
}
function executeOneStep(
ExecutionContext calldata,
Machine calldata startMach,
Module calldata startMod,
Instruction calldata inst,
bytes calldata proof
) external pure override returns (Machine memory mach, Module memory mod) {
mach = startMach;
mod = startMod;
uint16 opcode = inst.opcode;
function(Machine memory, Module memory, Instruction calldata, bytes calldata)
internal
pure impl;
if (opcode == Instructions.I32_EQZ || opcode == Instructions.I64_EQZ) {
impl = executeEqz;
} else if (
opcode >= Instructions.I32_RELOP_BASE &&
opcode <= Instructions.I32_RELOP_BASE + Instructions.IRELOP_LAST
) {
impl = executeI32RelOp;
} else if (
opcode >= Instructions.I32_UNOP_BASE &&
opcode <= Instructions.I32_UNOP_BASE + Instructions.IUNOP_LAST
) {
impl = executeI32UnOp;
} else if (opcode >= Instructions.I32_ADD && opcode <= Instructions.I32_ROTR) {
impl = executeI32BinOp;
} else if (
opcode >= Instructions.I64_RELOP_BASE &&
opcode <= Instructions.I64_RELOP_BASE + Instructions.IRELOP_LAST
) {
impl = executeI64RelOp;
} else if (
opcode >= Instructions.I64_UNOP_BASE &&
opcode <= Instructions.I64_UNOP_BASE + Instructions.IUNOP_LAST
) {
impl = executeI64UnOp;
} else if (opcode >= Instructions.I64_ADD && opcode <= Instructions.I64_ROTR) {
impl = executeI64BinOp;
} else if (opcode == Instructions.I32_WRAP_I64) {
impl = executeI32WrapI64;
} else if (
opcode == Instructions.I64_EXTEND_I32_S || opcode == Instructions.I64_EXTEND_I32_U
) {
impl = executeI64ExtendI32;
} else if (opcode >= Instructions.I32_EXTEND_8S && opcode <= Instructions.I64_EXTEND_32S) {
impl = executeExtendSameType;
} else if (
opcode >= Instructions.I32_REINTERPRET_F32 && opcode <= Instructions.F64_REINTERPRET_I64
) {
impl = executeReinterpret;
} else {
revert("INVALID_OPCODE");
}
impl(mach, mod, inst, proof);
}
}
文件 57 的 88:OneStepProverMemory.sol
pragma solidity ^0.8.0;
import "../state/Value.sol";
import "../state/Machine.sol";
import "../state/Deserialize.sol";
import "./IOneStepProver.sol";
contract OneStepProverMemory is IOneStepProver {
using MerkleProofLib for MerkleProof;
using ModuleMemoryLib for ModuleMemory;
using ValueLib for Value;
using ValueStackLib for ValueStack;
uint256 private constant LEAF_SIZE = 32;
uint64 private constant PAGE_SIZE = 65536;
function pullLeafByte(bytes32 leaf, uint256 idx) internal pure returns (uint8) {
require(idx < LEAF_SIZE, "BAD_PULL_LEAF_BYTE_IDX");
uint256 leafShift = (LEAF_SIZE - 1 - idx) * 8;
return uint8(uint256(leaf) >> leafShift);
}
function setLeafByte(
bytes32 oldLeaf,
uint256 idx,
uint8 val
) internal pure returns (bytes32) {
require(idx < LEAF_SIZE, "BAD_SET_LEAF_BYTE_IDX");
uint256 leafShift = (LEAF_SIZE - 1 - idx) * 8;
uint256 newLeaf = uint256(oldLeaf);
newLeaf &= ~(0xFF << leafShift);
newLeaf |= uint256(val) << leafShift;
return bytes32(newLeaf);
}
function executeMemoryLoad(
Machine memory mach,
Module memory mod,
Instruction calldata inst,
bytes calldata proof
) internal pure {
ValueType ty;
uint256 readBytes;
bool signed;
if (inst.opcode == Instructions.I32_LOAD) {
ty = ValueType.I32;
readBytes = 4;
signed = false;
} else if (inst.opcode == Instructions.I64_LOAD) {
ty = ValueType.I64;
readBytes = 8;
signed = false;
} else if (inst.opcode == Instructions.F32_LOAD) {
ty = ValueType.F32;
readBytes = 4;
signed = false;
} else if (inst.opcode == Instructions.F64_LOAD) {
ty = ValueType.F64;
readBytes = 8;
signed = false;
} else if (inst.opcode == Instructions.I32_LOAD8_S) {
ty = ValueType.I32;
readBytes = 1;
signed = true;
} else if (inst.opcode == Instructions.I32_LOAD8_U) {
ty = ValueType.I32;
readBytes = 1;
signed = false;
} else if (inst.opcode == Instructions.I32_LOAD16_S) {
ty = ValueType.I32;
readBytes = 2;
signed = true;
} else if (inst.opcode == Instructions.I32_LOAD16_U) {
ty = ValueType.I32;
readBytes = 2;
signed = false;
} else if (inst.opcode == Instructions.I64_LOAD8_S) {
ty = ValueType.I64;
readBytes = 1;
signed = true;
} else if (inst.opcode == Instructions.I64_LOAD8_U) {
ty = ValueType.I64;
readBytes = 1;
signed = false;
} else if (inst.opcode == Instructions.I64_LOAD16_S) {
ty = ValueType.I64;
readBytes = 2;
signed = true;
} else if (inst.opcode == Instructions.I64_LOAD16_U) {
ty = ValueType.I64;
readBytes = 2;
signed = false;
} else if (inst.opcode == Instructions.I64_LOAD32_S) {
ty = ValueType.I64;
readBytes = 4;
signed = true;
} else if (inst.opcode == Instructions.I64_LOAD32_U) {
ty = ValueType.I64;
readBytes = 4;
signed = false;
} else {
revert("INVALID_MEMORY_LOAD_OPCODE");
}
uint256 startIdx = inst.argumentData + mach.valueStack.pop().assumeI32();
if (startIdx + readBytes > mod.moduleMemory.size) {
mach.status = MachineStatus.ERRORED;
return;
}
uint256 proofOffset = 0;
uint256 lastProvedLeafIdx = ~uint256(0);
bytes32 lastProvedLeafContents;
uint64 readValue;
for (uint256 i = 0; i < readBytes; i++) {
uint256 idx = startIdx + i;
uint256 leafIdx = idx / LEAF_SIZE;
if (leafIdx != lastProvedLeafIdx) {
(lastProvedLeafContents, proofOffset, ) = ModuleMemoryLib.proveLeaf(
mod.moduleMemory,
leafIdx,
proof,
proofOffset
);
lastProvedLeafIdx = leafIdx;
}
uint256 indexWithinLeaf = idx % LEAF_SIZE;
readValue |=
uint64(pullLeafByte(lastProvedLeafContents, indexWithinLeaf)) <<
uint64(i * 8);
}
if (signed) {
if (readBytes == 1 && ty == ValueType.I32) {
readValue = uint32(int32(int8(uint8(readValue))));
} else if (readBytes == 1 && ty == ValueType.I64) {
readValue = uint64(int64(int8(uint8(readValue))));
} else if (readBytes == 2 && ty == ValueType.I32) {
readValue = uint32(int32(int16(uint16(readValue))));
} else if (readBytes == 2 && ty == ValueType.I64) {
readValue = uint64(int64(int16(uint16(readValue))));
} else if (readBytes == 4 && ty == ValueType.I64) {
readValue = uint64(int64(int32(uint32(readValue))));
} else {
revert("BAD_READ_BYTES_SIGNED");
}
}
mach.valueStack.push(Value({valueType: ty, contents: readValue}));
}
function executeMemoryStore(
Machine memory mach,
Module memory mod,
Instruction calldata inst,
bytes calldata proof
) internal pure {
uint64 writeBytes;
uint64 toWrite;
{
ValueType ty;
if (inst.opcode == Instructions.I32_STORE) {
ty = ValueType.I32;
writeBytes = 4;
} else if (inst.opcode == Instructions.I64_STORE) {
ty = ValueType.I64;
writeBytes = 8;
} else if (inst.opcode == Instructions.F32_STORE) {
ty = ValueType.F32;
writeBytes = 4;
} else if (inst.opcode == Instructions.F64_STORE) {
ty = ValueType.F64;
writeBytes = 8;
} else if (inst.opcode == Instructions.I32_STORE8) {
ty = ValueType.I32;
writeBytes = 1;
} else if (inst.opcode == Instructions.I32_STORE16) {
ty = ValueType.I32;
writeBytes = 2;
} else if (inst.opcode == Instructions.I64_STORE8) {
ty = ValueType.I64;
writeBytes = 1;
} else if (inst.opcode == Instructions.I64_STORE16) {
ty = ValueType.I64;
writeBytes = 2;
} else if (inst.opcode == Instructions.I64_STORE32) {
ty = ValueType.I64;
writeBytes = 4;
} else {
revert("INVALID_MEMORY_STORE_OPCODE");
}
Value memory writingVal = mach.valueStack.pop();
require(writingVal.valueType == ty, "BAD_STORE_TYPE");
toWrite = uint64(writingVal.contents);
if (writeBytes < 8) {
toWrite &= (uint64(1) << (writeBytes * 8)) - 1;
}
}
uint256 startIdx = inst.argumentData + mach.valueStack.pop().assumeI32();
if (startIdx + writeBytes > mod.moduleMemory.size) {
mach.status = MachineStatus.ERRORED;
return;
}
uint256 proofOffset = 0;
uint256 lastProvedLeafIdx = ~uint256(0);
MerkleProof memory lastProvedMerkle;
bytes32 lastProvedLeafContents;
for (uint256 i = 0; i < writeBytes; i++) {
uint256 idx = startIdx + i;
uint256 leafIdx = idx / LEAF_SIZE;
if (leafIdx != lastProvedLeafIdx) {
if (lastProvedLeafIdx != ~uint256(0)) {
mod.moduleMemory.merkleRoot = lastProvedMerkle.computeRootFromMemory(
lastProvedLeafIdx,
lastProvedLeafContents
);
}
(lastProvedLeafContents, proofOffset, lastProvedMerkle) = ModuleMemoryLib.proveLeaf(
mod.moduleMemory,
leafIdx,
proof,
proofOffset
);
lastProvedLeafIdx = leafIdx;
}
uint256 indexWithinLeaf = idx % LEAF_SIZE;
lastProvedLeafContents = setLeafByte(
lastProvedLeafContents,
indexWithinLeaf,
uint8(toWrite)
);
toWrite >>= 8;
}
mod.moduleMemory.merkleRoot = lastProvedMerkle.computeRootFromMemory(
lastProvedLeafIdx,
lastProvedLeafContents
);
}
function executeMemorySize(
Machine memory mach,
Module memory mod,
Instruction calldata,
bytes calldata
) internal pure {
uint32 pages = uint32(mod.moduleMemory.size / PAGE_SIZE);
mach.valueStack.push(ValueLib.newI32(pages));
}
function executeMemoryGrow(
Machine memory mach,
Module memory mod,
Instruction calldata,
bytes calldata
) internal pure {
uint32 oldPages = uint32(mod.moduleMemory.size / PAGE_SIZE);
uint32 growingPages = mach.valueStack.pop().assumeI32();
uint256 newSize = uint256(oldPages) + uint256(growingPages);
if (newSize <= mod.moduleMemory.maxSize) {
mod.moduleMemory.size = uint64(newSize * PAGE_SIZE);
mach.valueStack.push(ValueLib.newI32(oldPages));
} else {
mach.valueStack.push(ValueLib.newI32(~uint32(0)));
}
}
function executeOneStep(
ExecutionContext calldata,
Machine calldata startMach,
Module calldata startMod,
Instruction calldata inst,
bytes calldata proof
) external pure override returns (Machine memory mach, Module memory mod) {
mach = startMach;
mod = startMod;
uint16 opcode = inst.opcode;
function(Machine memory, Module memory, Instruction calldata, bytes calldata)
internal
pure impl;
if (opcode >= Instructions.I32_LOAD && opcode <= Instructions.I64_LOAD32_U) {
impl = executeMemoryLoad;
} else if (opcode >= Instructions.I32_STORE && opcode <= Instructions.I64_STORE32) {
impl = executeMemoryStore;
} else if (opcode == Instructions.MEMORY_SIZE) {
impl = executeMemorySize;
} else if (opcode == Instructions.MEMORY_GROW) {
impl = executeMemoryGrow;
} else {
revert("INVALID_MEMORY_OPCODE");
}
impl(mach, mod, inst, proof);
}
}
文件 58 的 88:Outbox.sol
pragma solidity ^0.8.4;
import {
AlreadyInit,
NotRollup,
ProofTooLong,
PathNotMinimal,
UnknownRoot,
AlreadySpent,
BridgeCallFailed,
HadZeroInit
} from "../libraries/Error.sol";
import "./IBridge.sol";
import "./IOutbox.sol";
import "../libraries/MerkleLib.sol";
import "../libraries/DelegateCallAware.sol";
error SimulationOnlyEntrypoint();
contract Outbox is DelegateCallAware, IOutbox {
address public rollup;
IBridge public bridge;
mapping(uint256 => bytes32) public spent;
mapping(bytes32 => bytes32) public roots;
struct L2ToL1Context {
uint128 l2Block;
uint128 l1Block;
uint128 timestamp;
bytes32 outputId;
address sender;
}
L2ToL1Context internal context;
uint128 private constant L2BLOCK_DEFAULT_CONTEXT = type(uint128).max;
uint128 private constant L1BLOCK_DEFAULT_CONTEXT = type(uint128).max;
uint128 private constant TIMESTAMP_DEFAULT_CONTEXT = type(uint128).max;
bytes32 private constant OUTPUTID_DEFAULT_CONTEXT = bytes32(type(uint256).max);
address private constant SENDER_DEFAULT_CONTEXT = address(type(uint160).max);
uint128 public constant OUTBOX_VERSION = 2;
function initialize(IBridge _bridge) external onlyDelegated {
if (address(_bridge) == address(0)) revert HadZeroInit();
if (address(bridge) != address(0)) revert AlreadyInit();
context = L2ToL1Context({
l2Block: L2BLOCK_DEFAULT_CONTEXT,
l1Block: L1BLOCK_DEFAULT_CONTEXT,
timestamp: TIMESTAMP_DEFAULT_CONTEXT,
outputId: OUTPUTID_DEFAULT_CONTEXT,
sender: SENDER_DEFAULT_CONTEXT
});
bridge = _bridge;
rollup = address(_bridge.rollup());
}
function updateSendRoot(bytes32 root, bytes32 l2BlockHash) external {
if (msg.sender != rollup) revert NotRollup(msg.sender, rollup);
roots[root] = l2BlockHash;
emit SendRootUpdated(root, l2BlockHash);
}
function l2ToL1Sender() external view returns (address) {
address sender = context.sender;
if (sender == SENDER_DEFAULT_CONTEXT) return address(0);
return sender;
}
function l2ToL1Block() external view returns (uint256) {
uint128 l2Block = context.l2Block;
if (l2Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0);
return uint256(l2Block);
}
function l2ToL1EthBlock() external view returns (uint256) {
uint128 l1Block = context.l1Block;
if (l1Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0);
return uint256(l1Block);
}
function l2ToL1Timestamp() external view returns (uint256) {
uint128 timestamp = context.timestamp;
if (timestamp == TIMESTAMP_DEFAULT_CONTEXT) return uint256(0);
return uint256(timestamp);
}
function l2ToL1BatchNum() external pure returns (uint256) {
return 0;
}
function l2ToL1OutputId() external view returns (bytes32) {
bytes32 outputId = context.outputId;
if (outputId == OUTPUTID_DEFAULT_CONTEXT) return bytes32(0);
return outputId;
}
function executeTransaction(
bytes32[] calldata proof,
uint256 index,
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) external {
bytes32 userTx = calculateItemHash(
l2Sender,
to,
l2Block,
l1Block,
l2Timestamp,
value,
data
);
recordOutputAsSpent(proof, index, userTx);
executeTransactionImpl(index, l2Sender, to, l2Block, l1Block, l2Timestamp, value, data);
}
function executeTransactionSimulation(
uint256 index,
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) external {
if (msg.sender != address(0)) revert SimulationOnlyEntrypoint();
executeTransactionImpl(index, l2Sender, to, l2Block, l1Block, l2Timestamp, value, data);
}
function executeTransactionImpl(
uint256 outputId,
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) internal {
emit OutBoxTransactionExecuted(to, l2Sender, 0, outputId);
L2ToL1Context memory prevContext = context;
context = L2ToL1Context({
sender: l2Sender,
l2Block: uint128(l2Block),
l1Block: uint128(l1Block),
timestamp: uint128(l2Timestamp),
outputId: bytes32(outputId)
});
executeBridgeCall(to, value, data);
context = prevContext;
}
function _calcSpentIndexOffset(uint256 index)
internal
view
returns (
uint256,
uint256,
bytes32
)
{
uint256 spentIndex = index / 255;
uint256 bitOffset = index % 255;
bytes32 replay = spent[spentIndex];
return (spentIndex, bitOffset, replay);
}
function _isSpent(uint256 bitOffset, bytes32 replay) internal pure returns (bool) {
return ((replay >> bitOffset) & bytes32(uint256(1))) != bytes32(0);
}
function isSpent(uint256 index) external view returns (bool) {
(, uint256 bitOffset, bytes32 replay) = _calcSpentIndexOffset(index);
return _isSpent(bitOffset, replay);
}
function recordOutputAsSpent(
bytes32[] memory proof,
uint256 index,
bytes32 item
) internal {
if (proof.length >= 256) revert ProofTooLong(proof.length);
if (index >= 2**proof.length) revert PathNotMinimal(index, 2**proof.length);
bytes32 calcRoot = calculateMerkleRoot(proof, index, item);
if (roots[calcRoot] == bytes32(0)) revert UnknownRoot(calcRoot);
(uint256 spentIndex, uint256 bitOffset, bytes32 replay) = _calcSpentIndexOffset(index);
if (_isSpent(bitOffset, replay)) revert AlreadySpent(index);
spent[spentIndex] = (replay | bytes32(1 << bitOffset));
}
function executeBridgeCall(
address to,
uint256 value,
bytes memory data
) internal {
(bool success, bytes memory returndata) = bridge.executeCall(to, value, data);
if (!success) {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert BridgeCallFailed();
}
}
}
function calculateItemHash(
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) public pure returns (bytes32) {
return
keccak256(abi.encodePacked(l2Sender, to, l2Block, l1Block, l2Timestamp, value, data));
}
function calculateMerkleRoot(
bytes32[] memory proof,
uint256 path,
bytes32 item
) public pure returns (bytes32) {
return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item)));
}
}
文件 59 的 88:OutboxWithoutOptTester.sol
pragma solidity ^0.8.4;
import {
AlreadyInit,
NotRollup,
ProofTooLong,
PathNotMinimal,
UnknownRoot,
AlreadySpent,
BridgeCallFailed
} from "../libraries/Error.sol";
import "../bridge/IBridge.sol";
import "../bridge/IOutbox.sol";
import "../libraries/MerkleLib.sol";
import "../libraries/DelegateCallAware.sol";
contract OutboxWithoutOptTester is DelegateCallAware, IOutbox {
address public rollup;
IBridge public bridge;
function spent(uint256) external pure override returns (bytes32) {
revert("NOT_IMPLEMETED");
}
mapping(uint256 => bool) public isSpent;
mapping(bytes32 => bytes32) public roots;
struct L2ToL1Context {
uint128 l2Block;
uint128 l1Block;
uint128 timestamp;
bytes32 outputId;
address sender;
}
L2ToL1Context internal context;
uint128 public constant OUTBOX_VERSION = 2;
function initialize(IBridge _bridge) external {
if (address(bridge) != address(0)) revert AlreadyInit();
bridge = _bridge;
rollup = address(_bridge.rollup());
}
function updateSendRoot(bytes32 root, bytes32 l2BlockHash) external override {
roots[root] = l2BlockHash;
emit SendRootUpdated(root, l2BlockHash);
}
function l2ToL1Sender() external view override returns (address) {
return context.sender;
}
function l2ToL1Block() external view override returns (uint256) {
return uint256(context.l2Block);
}
function l2ToL1EthBlock() external view override returns (uint256) {
return uint256(context.l1Block);
}
function l2ToL1Timestamp() external view override returns (uint256) {
return uint256(context.timestamp);
}
function l2ToL1BatchNum() external pure returns (uint256) {
return 0;
}
function l2ToL1OutputId() external view override returns (bytes32) {
return context.outputId;
}
function executeTransaction(
bytes32[] calldata proof,
uint256 index,
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) external virtual override {
bytes32 outputId;
{
bytes32 userTx = calculateItemHash(
l2Sender,
to,
l2Block,
l1Block,
l2Timestamp,
value,
data
);
outputId = recordOutputAsSpent(proof, index, userTx);
emit OutBoxTransactionExecuted(to, l2Sender, 0, index);
}
L2ToL1Context memory prevContext = context;
context = L2ToL1Context({
sender: l2Sender,
l2Block: uint128(l2Block),
l1Block: uint128(l1Block),
timestamp: uint128(l2Timestamp),
outputId: outputId
});
executeBridgeCall(to, value, data);
context = prevContext;
}
function executeTransactionSimulation(
uint256,
address,
address,
uint256,
uint256,
uint256,
uint256,
bytes calldata
) external pure override {
revert("Not implemented");
}
function recordOutputAsSpent(
bytes32[] memory proof,
uint256 index,
bytes32 item
) internal returns (bytes32) {
if (proof.length >= 256) revert ProofTooLong(proof.length);
if (index >= 2**proof.length) revert PathNotMinimal(index, 2**proof.length);
bytes32 calcRoot = calculateMerkleRoot(proof, index, item);
if (roots[calcRoot] == bytes32(0)) revert UnknownRoot(calcRoot);
if (isSpent[index]) revert AlreadySpent(index);
isSpent[index] = true;
return bytes32(index);
}
function executeBridgeCall(
address to,
uint256 value,
bytes memory data
) internal {
(bool success, bytes memory returndata) = bridge.executeCall(to, value, data);
if (!success) {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert BridgeCallFailed();
}
}
}
function calculateItemHash(
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) public pure override returns (bytes32) {
return
keccak256(abi.encodePacked(l2Sender, to, l2Block, l1Block, l2Timestamp, value, data));
}
function calculateMerkleRoot(
bytes32[] memory proof,
uint256 path,
bytes32 item
) public pure override returns (bytes32) {
return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item)));
}
}
文件 60 的 88:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 61 的 88:OwnableUpgradeable.sol
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
uint256[49] private __gap;
}
文件 62 的 88:PausableUpgradeable.sol
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
uint256[49] private __gap;
}
文件 63 的 88:Proxy.sol
pragma solidity ^0.8.0;
abstract contract Proxy {
function _delegate(address implementation) internal virtual {
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
function _implementation() internal view virtual returns (address);
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
fallback() external payable virtual {
_fallback();
}
receive() external payable virtual {
_fallback();
}
function _beforeFallback() internal virtual {}
}
文件 64 的 88:ProxyAdmin.sol
pragma solidity ^0.8.0;
import "./TransparentUpgradeableProxy.sol";
import "../../access/Ownable.sol";
contract ProxyAdmin is Ownable {
function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
require(success);
return abi.decode(returndata, (address));
}
function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
require(success);
return abi.decode(returndata, (address));
}
function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
proxy.changeAdmin(newAdmin);
}
function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
proxy.upgradeTo(implementation);
}
function upgradeAndCall(
TransparentUpgradeableProxy proxy,
address implementation,
bytes memory data
) public payable virtual onlyOwner {
proxy.upgradeToAndCall{value: msg.value}(implementation, data);
}
}
文件 65 的 88:RollupAdminLogic.sol
pragma solidity ^0.8.0;
import {IRollupAdmin, IRollupUser} from "./IRollupLogic.sol";
import "./RollupCore.sol";
import "../bridge/IOutbox.sol";
import "../bridge/ISequencerInbox.sol";
import "../challenge/IChallengeManager.sol";
import "../libraries/DoubleLogicUUPSUpgradeable.sol";
import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import {NO_CHAL_INDEX} from "../libraries/Constants.sol";
contract RollupAdminLogic is RollupCore, IRollupAdmin, DoubleLogicUUPSUpgradeable {
function initialize(Config calldata config, ContractDependencies calldata connectedContracts)
external
override
onlyProxy
initializer
{
rollupDeploymentBlock = block.number;
bridge = connectedContracts.bridge;
sequencerInbox = connectedContracts.sequencerInbox;
connectedContracts.bridge.setDelayedInbox(address(connectedContracts.inbox), true);
connectedContracts.bridge.setSequencerInbox(address(connectedContracts.sequencerInbox));
inbox = connectedContracts.inbox;
outbox = connectedContracts.outbox;
connectedContracts.bridge.setOutbox(address(connectedContracts.outbox), true);
rollupEventInbox = connectedContracts.rollupEventInbox;
connectedContracts.bridge.setDelayedInbox(
address(connectedContracts.rollupEventInbox),
true
);
connectedContracts.rollupEventInbox.rollupInitialized(config.chainId);
connectedContracts.sequencerInbox.addSequencerL2Batch(0, "", 1, IGasRefunder(address(0)));
validatorUtils = connectedContracts.validatorUtils;
validatorWalletCreator = connectedContracts.validatorWalletCreator;
challengeManager = connectedContracts.challengeManager;
Node memory node = createInitialNode();
initializeCore(node);
confirmPeriodBlocks = config.confirmPeriodBlocks;
extraChallengeTimeBlocks = config.extraChallengeTimeBlocks;
chainId = config.chainId;
baseStake = config.baseStake;
wasmModuleRoot = config.wasmModuleRoot;
minimumAssertionPeriod = 75;
require(config.loserStakeEscrow != _getAdmin(), "INVALID_ESCROW_ADMIN");
require(config.loserStakeEscrow != config.owner, "INVALID_ESCROW_OWNER");
loserStakeEscrow = config.loserStakeEscrow;
stakeToken = config.stakeToken;
emit RollupInitialized(config.wasmModuleRoot, config.chainId);
}
function createInitialNode() private view returns (Node memory) {
GlobalState memory emptyGlobalState;
bytes32 state = RollupLib.stateHashMem(
RollupLib.ExecutionState(emptyGlobalState, MachineStatus.FINISHED),
1
);
return
NodeLib.createNode(
state,
0,
0,
0,
uint64(block.number),
0
);
}
function setOutbox(IOutbox _outbox) external override {
outbox = _outbox;
bridge.setOutbox(address(_outbox), true);
emit OwnerFunctionCalled(0);
}
function removeOldOutbox(address _outbox) external override {
require(_outbox != address(outbox), "CUR_OUTBOX");
bridge.setOutbox(_outbox, false);
emit OwnerFunctionCalled(1);
}
function setDelayedInbox(address _inbox, bool _enabled) external override {
bridge.setDelayedInbox(address(_inbox), _enabled);
emit OwnerFunctionCalled(2);
}
function pause() external override {
_pause();
emit OwnerFunctionCalled(3);
}
function resume() external override {
_unpause();
emit OwnerFunctionCalled(4);
}
function _authorizeUpgrade(address newImplementation) internal override {}
function _authorizeSecondaryUpgrade(address newImplementation) internal override {}
function setValidator(address[] calldata _validator, bool[] calldata _val) external override {
require(_validator.length > 0, "EMPTY_ARRAY");
require(_validator.length == _val.length, "WRONG_LENGTH");
for (uint256 i = 0; i < _validator.length; i++) {
isValidator[_validator[i]] = _val[i];
}
emit OwnerFunctionCalled(6);
}
function setOwner(address newOwner) external override {
_changeAdmin(newOwner);
emit OwnerFunctionCalled(7);
}
function setMinimumAssertionPeriod(uint256 newPeriod) external override {
minimumAssertionPeriod = newPeriod;
emit OwnerFunctionCalled(8);
}
function setConfirmPeriodBlocks(uint64 newConfirmPeriod) external override {
require(newConfirmPeriod > 0, "INVALID_CONFIRM_PERIOD");
confirmPeriodBlocks = newConfirmPeriod;
emit OwnerFunctionCalled(9);
}
function setExtraChallengeTimeBlocks(uint64 newExtraTimeBlocks) external override {
extraChallengeTimeBlocks = newExtraTimeBlocks;
emit OwnerFunctionCalled(10);
}
function setBaseStake(uint256 newBaseStake) external override {
baseStake = newBaseStake;
emit OwnerFunctionCalled(12);
}
function setStakeToken(address newStakeToken) external override whenPaused {
bool expectERC20Support = newStakeToken != address(0);
bool actualERC20Support = IRollupUser(address(this)).isERC20Enabled();
require(actualERC20Support == expectERC20Support, "NO_USER_LOGIC_SUPPORT");
require(stakerCount() == 0, "NO_ACTIVE_STAKERS");
require(totalWithdrawableFunds == 0, "NO_PENDING_WITHDRAW");
stakeToken = newStakeToken;
emit OwnerFunctionCalled(13);
}
function upgradeBeacon(address beacon, address newImplementation) external override {
UpgradeableBeacon(beacon).upgradeTo(newImplementation);
emit OwnerFunctionCalled(20);
}
function forceResolveChallenge(address[] calldata stakerA, address[] calldata stakerB)
external
override
whenPaused
{
require(stakerA.length > 0, "EMPTY_ARRAY");
require(stakerA.length == stakerB.length, "WRONG_LENGTH");
for (uint256 i = 0; i < stakerA.length; i++) {
uint64 chall = inChallenge(stakerA[i], stakerB[i]);
require(chall != NO_CHAL_INDEX, "NOT_IN_CHALL");
clearChallenge(stakerA[i]);
clearChallenge(stakerB[i]);
challengeManager.clearChallenge(chall);
}
emit OwnerFunctionCalled(21);
}
function forceRefundStaker(address[] calldata staker) external override whenPaused {
require(staker.length > 0, "EMPTY_ARRAY");
for (uint256 i = 0; i < staker.length; i++) {
require(_stakerMap[staker[i]].currentChallenge == NO_CHAL_INDEX, "STAKER_IN_CHALL");
reduceStakeTo(staker[i], 0);
turnIntoZombie(staker[i]);
}
emit OwnerFunctionCalled(22);
}
function forceCreateNode(
uint64 prevNode,
uint256 prevNodeInboxMaxCount,
RollupLib.Assertion calldata assertion,
bytes32 expectedNodeHash
) external override whenPaused {
require(prevNode == latestConfirmed(), "ONLY_LATEST_CONFIRMED");
createNewNode(assertion, prevNode, prevNodeInboxMaxCount, expectedNodeHash);
emit OwnerFunctionCalled(23);
}
function forceConfirmNode(
uint64 nodeNum,
bytes32 blockHash,
bytes32 sendRoot
) external override whenPaused {
confirmNode(nodeNum, blockHash, sendRoot);
emit OwnerFunctionCalled(24);
}
function setLoserStakeEscrow(address newLoserStakerEscrow) external override {
require(newLoserStakerEscrow != _getAdmin(), "INVALID_ESCROW");
loserStakeEscrow = newLoserStakerEscrow;
emit OwnerFunctionCalled(25);
}
function setWasmModuleRoot(bytes32 newWasmModuleRoot) external override {
wasmModuleRoot = newWasmModuleRoot;
emit OwnerFunctionCalled(26);
}
function setSequencerInbox(address _sequencerInbox) external override {
bridge.setSequencerInbox(_sequencerInbox);
emit OwnerFunctionCalled(27);
}
function setInbox(IInbox newInbox) external {
inbox = newInbox;
emit OwnerFunctionCalled(28);
}
function createNitroMigrationGenesis(RollupLib.Assertion calldata assertion)
external
whenPaused
{
bytes32 expectedSendRoot = bytes32(0);
uint64 expectedInboxCount = 1;
require(latestNodeCreated() == 0, "NON_GENESIS_NODES_EXIST");
require(GlobalStateLib.isEmpty(assertion.beforeState.globalState), "NOT_EMPTY_BEFORE");
require(
assertion.beforeState.machineStatus == MachineStatus.FINISHED,
"BEFORE_MACHINE_NOT_FINISHED"
);
require(
assertion.afterState.globalState.bytes32Vals[1] == expectedSendRoot,
"NOT_ZERO_SENDROOT"
);
require(
assertion.afterState.globalState.u64Vals[0] == expectedInboxCount,
"INBOX_NOT_AT_ONE"
);
require(assertion.afterState.globalState.u64Vals[1] == 0, "POSITION_IN_MESSAGE_NOT_ZERO");
require(
assertion.afterState.machineStatus == MachineStatus.FINISHED,
"AFTER_MACHINE_NOT_FINISHED"
);
bytes32 genesisBlockHash = assertion.afterState.globalState.bytes32Vals[0];
createNewNode(assertion, 0, expectedInboxCount, bytes32(0));
confirmNode(1, genesisBlockHash, expectedSendRoot);
emit OwnerFunctionCalled(29);
}
}
文件 66 的 88:RollupCore.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "./Node.sol";
import "./IRollupCore.sol";
import "./RollupLib.sol";
import "./IRollupEventInbox.sol";
import "./IRollupCore.sol";
import "../challenge/IChallengeManager.sol";
import "../bridge/ISequencerInbox.sol";
import "../bridge/IBridge.sol";
import "../bridge/IOutbox.sol";
import {NO_CHAL_INDEX} from "../libraries/Constants.sol";
abstract contract RollupCore is IRollupCore, PausableUpgradeable {
using NodeLib for Node;
using GlobalStateLib for GlobalState;
uint64 public confirmPeriodBlocks;
uint64 public extraChallengeTimeBlocks;
uint256 public chainId;
uint256 public baseStake;
bytes32 public wasmModuleRoot;
IInbox public inbox;
IBridge public bridge;
IOutbox public outbox;
ISequencerInbox public sequencerInbox;
IRollupEventInbox public rollupEventInbox;
IChallengeManager public override challengeManager;
address public validatorUtils;
address public validatorWalletCreator;
address public loserStakeEscrow;
address public stakeToken;
uint256 public minimumAssertionPeriod;
mapping(address => bool) public isValidator;
struct Zombie {
address stakerAddress;
uint64 latestStakedNode;
}
uint64 private _latestConfirmed;
uint64 private _firstUnresolvedNode;
uint64 private _latestNodeCreated;
uint64 private _lastStakeBlock;
mapping(uint64 => Node) private _nodes;
mapping(uint64 => mapping(address => bool)) private _nodeStakers;
address[] private _stakerList;
mapping(address => Staker) public _stakerMap;
Zombie[] private _zombies;
mapping(address => uint256) private _withdrawableFunds;
uint256 public totalWithdrawableFunds;
uint256 public rollupDeploymentBlock;
uint64 internal constant GENESIS_NODE = 0;
function getNodeStorage(uint64 nodeNum) internal view returns (Node storage) {
return _nodes[nodeNum];
}
function getNode(uint64 nodeNum) public view override returns (Node memory) {
return getNodeStorage(nodeNum);
}
function nodeHasStaker(uint64 nodeNum, address staker) public view override returns (bool) {
return _nodeStakers[nodeNum][staker];
}
function getStakerAddress(uint64 stakerNum) external view override returns (address) {
return _stakerList[stakerNum];
}
function isStaked(address staker) public view override returns (bool) {
return _stakerMap[staker].isStaked;
}
function isStakedOnLatestConfirmed(address staker) public view returns (bool) {
return _stakerMap[staker].isStaked && nodeHasStaker(_latestConfirmed, staker);
}
function latestStakedNode(address staker) public view override returns (uint64) {
return _stakerMap[staker].latestStakedNode;
}
function currentChallenge(address staker) public view override returns (uint64) {
return _stakerMap[staker].currentChallenge;
}
function amountStaked(address staker) public view override returns (uint256) {
return _stakerMap[staker].amountStaked;
}
function getStaker(address staker) external view override returns (Staker memory) {
return _stakerMap[staker];
}
function zombieAddress(uint256 zombieNum) public view override returns (address) {
return _zombies[zombieNum].stakerAddress;
}
function zombieLatestStakedNode(uint256 zombieNum) public view override returns (uint64) {
return _zombies[zombieNum].latestStakedNode;
}
function getZombieStorage(uint256 zombieNum) internal view returns (Zombie storage) {
return _zombies[zombieNum];
}
function zombieCount() public view override returns (uint256) {
return _zombies.length;
}
function isZombie(address staker) public view override returns (bool) {
for (uint256 i = 0; i < _zombies.length; i++) {
if (staker == _zombies[i].stakerAddress) {
return true;
}
}
return false;
}
function withdrawableFunds(address user) external view override returns (uint256) {
return _withdrawableFunds[user];
}
function firstUnresolvedNode() public view override returns (uint64) {
return _firstUnresolvedNode;
}
function latestConfirmed() public view override returns (uint64) {
return _latestConfirmed;
}
function latestNodeCreated() public view override returns (uint64) {
return _latestNodeCreated;
}
function lastStakeBlock() external view override returns (uint64) {
return _lastStakeBlock;
}
function stakerCount() public view override returns (uint64) {
return uint64(_stakerList.length);
}
function initializeCore(Node memory initialNode) internal {
__Pausable_init();
_nodes[GENESIS_NODE] = initialNode;
_firstUnresolvedNode = GENESIS_NODE + 1;
}
function nodeCreated(Node memory node) internal {
_latestNodeCreated++;
_nodes[_latestNodeCreated] = node;
}
function _rejectNextNode() internal {
_firstUnresolvedNode++;
}
function confirmNode(
uint64 nodeNum,
bytes32 blockHash,
bytes32 sendRoot
) internal {
Node storage node = getNodeStorage(nodeNum);
require(node.confirmData == RollupLib.confirmHash(blockHash, sendRoot), "CONFIRM_DATA");
outbox.updateSendRoot(sendRoot, blockHash);
_latestConfirmed = nodeNum;
_firstUnresolvedNode = nodeNum + 1;
emit NodeConfirmed(nodeNum, blockHash, sendRoot);
}
function createNewStake(address stakerAddress, uint256 depositAmount) internal {
uint64 stakerIndex = uint64(_stakerList.length);
_stakerList.push(stakerAddress);
_stakerMap[stakerAddress] = Staker(
depositAmount,
stakerIndex,
_latestConfirmed,
NO_CHAL_INDEX,
true
);
_nodeStakers[_latestConfirmed][stakerAddress] = true;
_lastStakeBlock = uint64(block.number);
emit UserStakeUpdated(stakerAddress, 0, depositAmount);
}
function inChallenge(address stakerAddress1, address stakerAddress2)
internal
view
returns (uint64)
{
Staker storage staker1 = _stakerMap[stakerAddress1];
Staker storage staker2 = _stakerMap[stakerAddress2];
uint64 challenge = staker1.currentChallenge;
require(challenge != NO_CHAL_INDEX, "NO_CHAL");
require(challenge == staker2.currentChallenge, "DIFF_IN_CHAL");
return challenge;
}
function clearChallenge(address stakerAddress) internal {
Staker storage staker = _stakerMap[stakerAddress];
staker.currentChallenge = NO_CHAL_INDEX;
}
function challengeStarted(
address staker1,
address staker2,
uint64 challenge
) internal {
_stakerMap[staker1].currentChallenge = challenge;
_stakerMap[staker2].currentChallenge = challenge;
}
function increaseStakeBy(address stakerAddress, uint256 amountAdded) internal {
Staker storage staker = _stakerMap[stakerAddress];
uint256 initialStaked = staker.amountStaked;
uint256 finalStaked = initialStaked + amountAdded;
staker.amountStaked = finalStaked;
emit UserStakeUpdated(stakerAddress, initialStaked, finalStaked);
}
function reduceStakeTo(address stakerAddress, uint256 target) internal returns (uint256) {
Staker storage staker = _stakerMap[stakerAddress];
uint256 current = staker.amountStaked;
require(target <= current, "TOO_LITTLE_STAKE");
uint256 amountWithdrawn = current - target;
staker.amountStaked = target;
increaseWithdrawableFunds(stakerAddress, amountWithdrawn);
emit UserStakeUpdated(stakerAddress, current, target);
return amountWithdrawn;
}
function turnIntoZombie(address stakerAddress) internal {
Staker storage staker = _stakerMap[stakerAddress];
_zombies.push(Zombie(stakerAddress, staker.latestStakedNode));
deleteStaker(stakerAddress);
}
function zombieUpdateLatestStakedNode(uint256 zombieNum, uint64 latest) internal {
_zombies[zombieNum].latestStakedNode = latest;
}
function removeZombie(uint256 zombieNum) internal {
_zombies[zombieNum] = _zombies[_zombies.length - 1];
_zombies.pop();
}
function addStaker(uint64 nodeNum, address staker) internal {
require(!_nodeStakers[nodeNum][staker], "ALREADY_STAKED");
_nodeStakers[nodeNum][staker] = true;
Node storage node = getNodeStorage(nodeNum);
require(node.deadlineBlock != 0, "NO_NODE");
uint64 prevCount = node.stakerCount;
node.stakerCount = prevCount + 1;
if (nodeNum > GENESIS_NODE) {
Node storage parent = getNodeStorage(node.prevNum);
parent.childStakerCount++;
if (prevCount == 0) {
parent.newChildConfirmDeadline(uint64(block.number) + confirmPeriodBlocks);
}
}
}
function removeStaker(uint64 nodeNum, address staker) internal {
require(_nodeStakers[nodeNum][staker], "NOT_STAKED");
_nodeStakers[nodeNum][staker] = false;
Node storage node = getNodeStorage(nodeNum);
node.stakerCount--;
if (nodeNum > GENESIS_NODE) {
getNodeStorage(node.prevNum).childStakerCount--;
}
}
function withdrawStaker(address stakerAddress) internal {
Staker storage staker = _stakerMap[stakerAddress];
uint64 latestConfirmedNum = latestConfirmed();
if (nodeHasStaker(latestConfirmedNum, stakerAddress)) {
assert(staker.latestStakedNode == latestConfirmedNum);
removeStaker(latestConfirmedNum, stakerAddress);
}
uint256 initialStaked = staker.amountStaked;
increaseWithdrawableFunds(stakerAddress, initialStaked);
deleteStaker(stakerAddress);
emit UserStakeUpdated(stakerAddress, initialStaked, 0);
}
function stakeOnNode(address stakerAddress, uint64 nodeNum) internal {
Staker storage staker = _stakerMap[stakerAddress];
addStaker(nodeNum, stakerAddress);
staker.latestStakedNode = nodeNum;
}
function withdrawFunds(address account) internal returns (uint256) {
uint256 amount = _withdrawableFunds[account];
_withdrawableFunds[account] = 0;
totalWithdrawableFunds -= amount;
emit UserWithdrawableFundsUpdated(account, amount, 0);
return amount;
}
function increaseWithdrawableFunds(address account, uint256 amount) internal {
uint256 initialWithdrawable = _withdrawableFunds[account];
uint256 finalWithdrawable = initialWithdrawable + amount;
_withdrawableFunds[account] = finalWithdrawable;
totalWithdrawableFunds += amount;
emit UserWithdrawableFundsUpdated(account, initialWithdrawable, finalWithdrawable);
}
function deleteStaker(address stakerAddress) private {
Staker storage staker = _stakerMap[stakerAddress];
require(staker.isStaked, "NOT_STAKED");
uint64 stakerIndex = staker.index;
_stakerList[stakerIndex] = _stakerList[_stakerList.length - 1];
_stakerMap[_stakerList[stakerIndex]].index = stakerIndex;
_stakerList.pop();
delete _stakerMap[stakerAddress];
}
struct StakeOnNewNodeFrame {
uint256 currentInboxSize;
Node node;
bytes32 executionHash;
Node prevNode;
bytes32 lastHash;
bool hasSibling;
uint64 deadlineBlock;
bytes32 sequencerBatchAcc;
}
function createNewNode(
RollupLib.Assertion calldata assertion,
uint64 prevNodeNum,
uint256 prevNodeInboxMaxCount,
bytes32 expectedNodeHash
) internal returns (bytes32 newNodeHash) {
require(
assertion.afterState.machineStatus == MachineStatus.FINISHED ||
assertion.afterState.machineStatus == MachineStatus.ERRORED,
"BAD_AFTER_STATUS"
);
StakeOnNewNodeFrame memory memoryFrame;
{
memoryFrame.prevNode = getNode(prevNodeNum);
memoryFrame.currentInboxSize = bridge.sequencerMessageCount();
require(
RollupLib.stateHash(assertion.beforeState, prevNodeInboxMaxCount) ==
memoryFrame.prevNode.stateHash,
"PREV_STATE_HASH"
);
uint64 afterInboxCount = assertion.afterState.globalState.getInboxPosition();
uint64 prevInboxPosition = assertion.beforeState.globalState.getInboxPosition();
require(afterInboxCount >= prevInboxPosition, "INBOX_BACKWARDS");
if (afterInboxCount == prevInboxPosition) {
require(
assertion.afterState.globalState.getPositionInMessage() >=
assertion.beforeState.globalState.getPositionInMessage(),
"INBOX_POS_IN_MSG_BACKWARDS"
);
}
if (
assertion.afterState.machineStatus == MachineStatus.ERRORED ||
assertion.afterState.globalState.getPositionInMessage() > 0
) {
afterInboxCount++;
}
require(afterInboxCount <= memoryFrame.currentInboxSize, "INBOX_PAST_END");
if (afterInboxCount > 0) {
memoryFrame.sequencerBatchAcc = bridge.sequencerInboxAccs(afterInboxCount - 1);
}
}
{
memoryFrame.executionHash = RollupLib.executionHash(assertion);
memoryFrame.deadlineBlock = uint64(block.number) + confirmPeriodBlocks;
memoryFrame.hasSibling = memoryFrame.prevNode.latestChildNumber > 0;
if (memoryFrame.hasSibling) {
memoryFrame.lastHash = getNodeStorage(memoryFrame.prevNode.latestChildNumber)
.nodeHash;
} else {
memoryFrame.lastHash = memoryFrame.prevNode.nodeHash;
}
newNodeHash = RollupLib.nodeHash(
memoryFrame.hasSibling,
memoryFrame.lastHash,
memoryFrame.executionHash,
memoryFrame.sequencerBatchAcc,
wasmModuleRoot
);
require(
newNodeHash == expectedNodeHash || expectedNodeHash == bytes32(0),
"UNEXPECTED_NODE_HASH"
);
memoryFrame.node = NodeLib.createNode(
RollupLib.stateHash(assertion.afterState, memoryFrame.currentInboxSize),
RollupLib.challengeRootHash(
memoryFrame.executionHash,
block.number,
wasmModuleRoot
),
RollupLib.confirmHash(assertion),
prevNodeNum,
memoryFrame.deadlineBlock,
newNodeHash
);
}
{
uint64 nodeNum = latestNodeCreated() + 1;
Node storage prevNode = getNodeStorage(prevNodeNum);
prevNode.childCreated(nodeNum);
nodeCreated(memoryFrame.node);
}
emit NodeCreated(
latestNodeCreated(),
memoryFrame.prevNode.nodeHash,
newNodeHash,
memoryFrame.executionHash,
assertion,
memoryFrame.sequencerBatchAcc,
wasmModuleRoot,
memoryFrame.currentInboxSize
);
return newNodeHash;
}
}
文件 67 的 88:RollupCreator.sol
pragma solidity ^0.8.0;
import "./BridgeCreator.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./RollupProxy.sol";
contract RollupCreator is Ownable {
event RollupCreated(
address indexed rollupAddress,
address inboxAddress,
address adminProxy,
address sequencerInbox,
address bridge
);
event TemplatesUpdated();
BridgeCreator public bridgeCreator;
IOneStepProofEntry public osp;
IChallengeManager public challengeManagerTemplate;
IRollupAdmin public rollupAdminLogic;
IRollupUser public rollupUserLogic;
address public validatorUtils;
address public validatorWalletCreator;
constructor() Ownable() {}
function setTemplates(
BridgeCreator _bridgeCreator,
IOneStepProofEntry _osp,
IChallengeManager _challengeManagerLogic,
IRollupAdmin _rollupAdminLogic,
IRollupUser _rollupUserLogic,
address _validatorUtils,
address _validatorWalletCreator
) external onlyOwner {
bridgeCreator = _bridgeCreator;
osp = _osp;
challengeManagerTemplate = _challengeManagerLogic;
rollupAdminLogic = _rollupAdminLogic;
rollupUserLogic = _rollupUserLogic;
validatorUtils = _validatorUtils;
validatorWalletCreator = _validatorWalletCreator;
emit TemplatesUpdated();
}
struct CreateRollupFrame {
ProxyAdmin admin;
IBridge bridge;
ISequencerInbox sequencerInbox;
IInbox inbox;
IRollupEventInbox rollupEventInbox;
IOutbox outbox;
RollupProxy rollup;
}
function createRollup(Config memory config, address expectedRollupAddr)
external
returns (address)
{
CreateRollupFrame memory frame;
frame.admin = new ProxyAdmin();
(
frame.bridge,
frame.sequencerInbox,
frame.inbox,
frame.rollupEventInbox,
frame.outbox
) = bridgeCreator.createBridge(
address(frame.admin),
expectedRollupAddr,
config.sequencerInboxMaxTimeVariation
);
frame.admin.transferOwnership(config.owner);
IChallengeManager challengeManager = IChallengeManager(
address(
new TransparentUpgradeableProxy(
address(challengeManagerTemplate),
address(frame.admin),
""
)
)
);
challengeManager.initialize(
IChallengeResultReceiver(expectedRollupAddr),
frame.sequencerInbox,
frame.bridge,
osp
);
frame.rollup = new RollupProxy(
config,
ContractDependencies({
bridge: frame.bridge,
sequencerInbox: frame.sequencerInbox,
inbox: frame.inbox,
outbox: frame.outbox,
rollupEventInbox: frame.rollupEventInbox,
challengeManager: challengeManager,
rollupAdminLogic: rollupAdminLogic,
rollupUserLogic: rollupUserLogic,
validatorUtils: validatorUtils,
validatorWalletCreator: validatorWalletCreator
})
);
require(address(frame.rollup) == expectedRollupAddr, "WRONG_ROLLUP_ADDR");
emit RollupCreated(
address(frame.rollup),
address(frame.inbox),
address(frame.admin),
address(frame.sequencerInbox),
address(frame.bridge)
);
return address(frame.rollup);
}
}
文件 68 的 88:RollupEventInbox.sol
pragma solidity ^0.8.0;
import "./IRollupEventInbox.sol";
import "../bridge/IBridge.sol";
import "../bridge/IDelayedMessageProvider.sol";
import "../libraries/DelegateCallAware.sol";
import {INITIALIZATION_MSG_TYPE} from "../libraries/MessageTypes.sol";
import {AlreadyInit, HadZeroInit} from "../libraries/Error.sol";
contract RollupEventInbox is IRollupEventInbox, IDelayedMessageProvider, DelegateCallAware {
IBridge public override bridge;
address public override rollup;
modifier onlyRollup() {
require(msg.sender == rollup, "ONLY_ROLLUP");
_;
}
function initialize(IBridge _bridge) external override onlyDelegated {
if (address(bridge) != address(0)) revert AlreadyInit();
if (address(_bridge) == address(0)) revert HadZeroInit();
bridge = _bridge;
rollup = address(_bridge.rollup());
}
function rollupInitialized(uint256 chainId) external override onlyRollup {
bytes memory initMsg = abi.encodePacked(chainId);
uint256 num = bridge.enqueueDelayedMessage(
INITIALIZATION_MSG_TYPE,
address(0),
keccak256(initMsg)
);
emit InboxMessageDelivered(num, initMsg);
}
}
文件 69 的 88:RollupLib.sol
pragma solidity ^0.8.0;
import "../challenge/IChallengeManager.sol";
import "../challenge/ChallengeLib.sol";
import "../state/GlobalState.sol";
import "../bridge/ISequencerInbox.sol";
import "../bridge/IBridge.sol";
import "../bridge/IOutbox.sol";
import "../bridge/IInbox.sol";
import "./IRollupEventInbox.sol";
import "./IRollupLogic.sol";
struct Config {
uint64 confirmPeriodBlocks;
uint64 extraChallengeTimeBlocks;
address stakeToken;
uint256 baseStake;
bytes32 wasmModuleRoot;
address owner;
address loserStakeEscrow;
uint256 chainId;
uint64 genesisBlockNum;
ISequencerInbox.MaxTimeVariation sequencerInboxMaxTimeVariation;
}
struct ContractDependencies {
IBridge bridge;
ISequencerInbox sequencerInbox;
IInbox inbox;
IOutbox outbox;
IRollupEventInbox rollupEventInbox;
IChallengeManager challengeManager;
IRollupAdmin rollupAdminLogic;
IRollupUser rollupUserLogic;
address validatorUtils;
address validatorWalletCreator;
}
library RollupLib {
using GlobalStateLib for GlobalState;
struct ExecutionState {
GlobalState globalState;
MachineStatus machineStatus;
}
function stateHash(ExecutionState calldata execState, uint256 inboxMaxCount)
internal
pure
returns (bytes32)
{
return
keccak256(
abi.encodePacked(
execState.globalState.hash(),
inboxMaxCount,
execState.machineStatus
)
);
}
function stateHashMem(ExecutionState memory execState, uint256 inboxMaxCount)
internal
pure
returns (bytes32)
{
return
keccak256(
abi.encodePacked(
execState.globalState.hash(),
inboxMaxCount,
execState.machineStatus
)
);
}
struct Assertion {
ExecutionState beforeState;
ExecutionState afterState;
uint64 numBlocks;
}
function executionHash(Assertion memory assertion) internal pure returns (bytes32) {
MachineStatus[2] memory statuses;
statuses[0] = assertion.beforeState.machineStatus;
statuses[1] = assertion.afterState.machineStatus;
GlobalState[2] memory globalStates;
globalStates[0] = assertion.beforeState.globalState;
globalStates[1] = assertion.afterState.globalState;
return executionHash(statuses, globalStates, assertion.numBlocks);
}
function executionHash(
MachineStatus[2] memory statuses,
GlobalState[2] memory globalStates,
uint64 numBlocks
) internal pure returns (bytes32) {
bytes32[] memory segments = new bytes32[](2);
segments[0] = ChallengeLib.blockStateHash(statuses[0], globalStates[0].hash());
segments[1] = ChallengeLib.blockStateHash(statuses[1], globalStates[1].hash());
return ChallengeLib.hashChallengeState(0, numBlocks, segments);
}
function challengeRootHash(
bytes32 execution,
uint256 proposedTime,
bytes32 wasmModuleRoot
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(execution, proposedTime, wasmModuleRoot));
}
function confirmHash(Assertion memory assertion) internal pure returns (bytes32) {
return
confirmHash(
assertion.afterState.globalState.getBlockHash(),
assertion.afterState.globalState.getSendRoot()
);
}
function confirmHash(bytes32 blockHash, bytes32 sendRoot) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(blockHash, sendRoot));
}
function nodeHash(
bool hasSibling,
bytes32 lastHash,
bytes32 assertionExecHash,
bytes32 inboxAcc,
bytes32 wasmModuleRoot
) internal pure returns (bytes32) {
uint8 hasSiblingInt = hasSibling ? 1 : 0;
return
keccak256(
abi.encodePacked(
hasSiblingInt,
lastHash,
assertionExecHash,
inboxAcc,
wasmModuleRoot
)
);
}
}
文件 70 的 88:RollupProxy.sol
pragma solidity ^0.8.0;
import "../libraries/AdminFallbackProxy.sol";
import "./IRollupLogic.sol";
contract RollupProxy is AdminFallbackProxy {
constructor(Config memory config, ContractDependencies memory connectedContracts)
AdminFallbackProxy(
address(connectedContracts.rollupAdminLogic),
abi.encodeWithSelector(IRollupAdmin.initialize.selector, config, connectedContracts),
address(connectedContracts.rollupUserLogic),
abi.encodeWithSelector(IRollupUserAbs.initialize.selector, config.stakeToken),
config.owner
)
{}
}
文件 71 的 88:RollupUserLogic.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {IRollupUser} from "./IRollupLogic.sol";
import "../libraries/UUPSNotUpgradeable.sol";
import "./RollupCore.sol";
abstract contract AbsRollupUserLogic is
RollupCore,
UUPSNotUpgradeable,
IRollupUserAbs,
IChallengeResultReceiver
{
using NodeLib for Node;
using GlobalStateLib for GlobalState;
modifier onlyValidator() {
require(isValidator[msg.sender], "NOT_VALIDATOR");
_;
}
function isERC20Enabled() public view override returns (bool) {
return stakeToken != address(0);
}
function rejectNextNode(address stakerAddress) external onlyValidator whenNotPaused {
requireUnresolvedExists();
uint64 latestConfirmedNodeNum = latestConfirmed();
uint64 firstUnresolvedNodeNum = firstUnresolvedNode();
Node storage firstUnresolvedNode_ = getNodeStorage(firstUnresolvedNodeNum);
if (firstUnresolvedNode_.prevNum == latestConfirmedNodeNum) {
require(isStakedOnLatestConfirmed(stakerAddress), "NOT_STAKED");
requireUnresolved(latestStakedNode(stakerAddress));
require(!nodeHasStaker(firstUnresolvedNodeNum, stakerAddress), "STAKED_ON_TARGET");
firstUnresolvedNode_.requirePastDeadline();
getNodeStorage(latestConfirmedNodeNum).requirePastChildConfirmDeadline();
removeOldZombies(0);
require(
firstUnresolvedNode_.stakerCount == countStakedZombies(firstUnresolvedNodeNum),
"HAS_STAKERS"
);
}
_rejectNextNode();
emit NodeRejected(firstUnresolvedNodeNum);
}
function confirmNextNode(bytes32 blockHash, bytes32 sendRoot)
external
onlyValidator
whenNotPaused
{
requireUnresolvedExists();
uint64 nodeNum = firstUnresolvedNode();
Node storage node = getNodeStorage(nodeNum);
node.requirePastDeadline();
assert(node.prevNum == latestConfirmed());
Node storage prevNode = getNodeStorage(node.prevNum);
prevNode.requirePastChildConfirmDeadline();
removeOldZombies(0);
uint256 stakedZombies = countStakedZombies(nodeNum);
uint256 zombiesStakedOnOtherChildren = countZombiesStakedOnChildren(node.prevNum) -
stakedZombies;
require(node.stakerCount > stakedZombies, "NO_STAKERS");
require(
prevNode.childStakerCount == node.stakerCount + zombiesStakedOnOtherChildren,
"NOT_ALL_STAKED"
);
confirmNode(nodeNum, blockHash, sendRoot);
}
function _newStake(uint256 depositAmount) internal onlyValidator whenNotPaused {
require(!isStaked(msg.sender), "ALREADY_STAKED");
require(!isZombie(msg.sender), "STAKER_IS_ZOMBIE");
require(depositAmount >= currentRequiredStake(), "NOT_ENOUGH_STAKE");
createNewStake(msg.sender, depositAmount);
}
function stakeOnExistingNode(uint64 nodeNum, bytes32 nodeHash)
public
onlyValidator
whenNotPaused
{
require(isStakedOnLatestConfirmed(msg.sender), "NOT_STAKED");
require(
nodeNum >= firstUnresolvedNode() && nodeNum <= latestNodeCreated(),
"NODE_NUM_OUT_OF_RANGE"
);
Node storage node = getNodeStorage(nodeNum);
require(node.nodeHash == nodeHash, "NODE_REORG");
require(latestStakedNode(msg.sender) == node.prevNum, "NOT_STAKED_PREV");
stakeOnNode(msg.sender, nodeNum);
}
function stakeOnNewNode(
RollupLib.Assertion calldata assertion,
bytes32 expectedNodeHash,
uint256 prevNodeInboxMaxCount
) public onlyValidator whenNotPaused {
require(isStakedOnLatestConfirmed(msg.sender), "NOT_STAKED");
uint64 prevNode = latestStakedNode(msg.sender);
{
uint256 timeSinceLastNode = block.number - getNode(prevNode).createdAtBlock;
require(timeSinceLastNode >= minimumAssertionPeriod, "TIME_DELTA");
require(
assertion.afterState.machineStatus == MachineStatus.ERRORED ||
assertion.afterState.globalState.getInboxPosition() >= prevNodeInboxMaxCount,
"TOO_SMALL"
);
require(assertion.numBlocks > 0, "EMPTY_ASSERTION");
require(
assertion.beforeState.machineStatus == MachineStatus.FINISHED,
"BAD_PREV_STATUS"
);
}
createNewNode(assertion, prevNode, prevNodeInboxMaxCount, expectedNodeHash);
stakeOnNode(msg.sender, latestNodeCreated());
}
function returnOldDeposit(address stakerAddress) external override onlyValidator whenNotPaused {
require(latestStakedNode(stakerAddress) <= latestConfirmed(), "TOO_RECENT");
requireUnchallengedStaker(stakerAddress);
withdrawStaker(stakerAddress);
}
function _addToDeposit(address stakerAddress, uint256 depositAmount)
internal
onlyValidator
whenNotPaused
{
requireUnchallengedStaker(stakerAddress);
increaseStakeBy(stakerAddress, depositAmount);
}
function reduceDeposit(uint256 target) external onlyValidator whenNotPaused {
requireUnchallengedStaker(msg.sender);
uint256 currentRequired = currentRequiredStake();
if (target < currentRequired) {
target = currentRequired;
}
reduceStakeTo(msg.sender, target);
}
function createChallenge(
address[2] calldata stakers,
uint64[2] calldata nodeNums,
MachineStatus[2] calldata machineStatuses,
GlobalState[2] calldata globalStates,
uint64 numBlocks,
bytes32 secondExecutionHash,
uint256[2] calldata proposedTimes,
bytes32[2] calldata wasmModuleRoots
) external onlyValidator whenNotPaused {
require(nodeNums[0] < nodeNums[1], "WRONG_ORDER");
require(nodeNums[1] <= latestNodeCreated(), "NOT_PROPOSED");
require(latestConfirmed() < nodeNums[0], "ALREADY_CONFIRMED");
Node storage node1 = getNodeStorage(nodeNums[0]);
Node storage node2 = getNodeStorage(nodeNums[1]);
require(node1.prevNum == node2.prevNum, "DIFF_PREV");
requireUnchallengedStaker(stakers[0]);
requireUnchallengedStaker(stakers[1]);
require(nodeHasStaker(nodeNums[0], stakers[0]), "STAKER1_NOT_STAKED");
require(nodeHasStaker(nodeNums[1], stakers[1]), "STAKER2_NOT_STAKED");
require(
node1.challengeHash ==
RollupLib.challengeRootHash(
RollupLib.executionHash(machineStatuses, globalStates, numBlocks),
proposedTimes[0],
wasmModuleRoots[0]
),
"CHAL_HASH1"
);
require(
node2.challengeHash ==
RollupLib.challengeRootHash(
secondExecutionHash,
proposedTimes[1],
wasmModuleRoots[1]
),
"CHAL_HASH2"
);
uint256 commonEndTime = getNodeStorage(node1.prevNum).firstChildBlock +
(node1.deadlineBlock - proposedTimes[0]) +
extraChallengeTimeBlocks;
if (commonEndTime < proposedTimes[1]) {
completeChallengeImpl(stakers[0], stakers[1]);
return;
}
uint64 challengeIndex = createChallengeHelper(
stakers,
machineStatuses,
globalStates,
numBlocks,
wasmModuleRoots,
commonEndTime - proposedTimes[0],
commonEndTime - proposedTimes[1]
);
challengeStarted(stakers[0], stakers[1], challengeIndex);
emit RollupChallengeStarted(challengeIndex, stakers[0], stakers[1], nodeNums[0]);
}
function createChallengeHelper(
address[2] calldata stakers,
MachineStatus[2] calldata machineStatuses,
GlobalState[2] calldata globalStates,
uint64 numBlocks,
bytes32[2] calldata wasmModuleRoots,
uint256 asserterTimeLeft,
uint256 challengerTimeLeft
) internal returns (uint64) {
return
challengeManager.createChallenge(
wasmModuleRoots[0],
machineStatuses,
globalStates,
numBlocks,
stakers[0],
stakers[1],
asserterTimeLeft,
challengerTimeLeft
);
}
function completeChallenge(
uint256 challengeIndex,
address winningStaker,
address losingStaker
) external override whenNotPaused {
require(msg.sender == address(challengeManager), "WRONG_SENDER");
require(challengeIndex == inChallenge(winningStaker, losingStaker), "NOT_IN_CHAL");
completeChallengeImpl(winningStaker, losingStaker);
}
function completeChallengeImpl(address winningStaker, address losingStaker) private {
uint256 remainingLoserStake = amountStaked(losingStaker);
uint256 winnerStake = amountStaked(winningStaker);
if (remainingLoserStake > winnerStake) {
remainingLoserStake -= reduceStakeTo(losingStaker, winnerStake);
}
uint256 amountWon = remainingLoserStake / 2;
increaseStakeBy(winningStaker, amountWon);
remainingLoserStake -= amountWon;
clearChallenge(winningStaker);
increaseWithdrawableFunds(loserStakeEscrow, remainingLoserStake);
turnIntoZombie(losingStaker);
}
function removeZombie(uint256 zombieNum, uint256 maxNodes)
external
onlyValidator
whenNotPaused
{
require(zombieNum < zombieCount(), "NO_SUCH_ZOMBIE");
address zombieStakerAddress = zombieAddress(zombieNum);
uint64 latestNodeStaked = zombieLatestStakedNode(zombieNum);
uint256 nodesRemoved = 0;
uint256 latestConfirmedNum = latestConfirmed();
while (latestNodeStaked >= latestConfirmedNum && nodesRemoved < maxNodes) {
Node storage node = getNodeStorage(latestNodeStaked);
removeStaker(latestNodeStaked, zombieStakerAddress);
latestNodeStaked = node.prevNum;
nodesRemoved++;
}
if (latestNodeStaked < latestConfirmedNum) {
removeZombie(zombieNum);
} else {
zombieUpdateLatestStakedNode(zombieNum, latestNodeStaked);
}
}
function removeOldZombies(uint256 startIndex) public onlyValidator whenNotPaused {
uint256 currentZombieCount = zombieCount();
uint256 latestConfirmedNum = latestConfirmed();
for (uint256 i = startIndex; i < currentZombieCount; i++) {
while (zombieLatestStakedNode(i) < latestConfirmedNum) {
removeZombie(i);
currentZombieCount--;
if (i >= currentZombieCount) {
return;
}
}
}
}
function currentRequiredStake(
uint256 _blockNumber,
uint64 _firstUnresolvedNodeNum,
uint256 _latestCreatedNode
) internal view returns (uint256) {
if (_firstUnresolvedNodeNum - 1 == _latestCreatedNode) {
return baseStake;
}
uint256 firstUnresolvedDeadline = getNodeStorage(_firstUnresolvedNodeNum).deadlineBlock;
if (_blockNumber < firstUnresolvedDeadline) {
return baseStake;
}
uint24[10] memory numerators = [
1,
122971,
128977,
80017,
207329,
114243,
314252,
129988,
224562,
162163
];
uint24[10] memory denominators = [
1,
114736,
112281,
64994,
157126,
80782,
207329,
80017,
128977,
86901
];
uint256 firstUnresolvedAge = _blockNumber - firstUnresolvedDeadline;
uint256 periodsPassed = (firstUnresolvedAge * 10) / confirmPeriodBlocks;
uint256 baseMultiplier = 2**(periodsPassed / 10);
uint256 withNumerator = baseMultiplier * numerators[periodsPassed % 10];
uint256 multiplier = withNumerator / denominators[periodsPassed % 10];
if (multiplier == 0) {
multiplier = 1;
}
return baseStake * multiplier;
}
function requiredStake(
uint256 blockNumber,
uint64 firstUnresolvedNodeNum,
uint64 latestCreatedNode
) external view returns (uint256) {
return currentRequiredStake(blockNumber, firstUnresolvedNodeNum, latestCreatedNode);
}
function owner() external view returns (address) {
return _getAdmin();
}
function currentRequiredStake() public view returns (uint256) {
uint64 firstUnresolvedNodeNum = firstUnresolvedNode();
return currentRequiredStake(block.number, firstUnresolvedNodeNum, latestNodeCreated());
}
function countStakedZombies(uint64 nodeNum) public view override returns (uint256) {
uint256 currentZombieCount = zombieCount();
uint256 stakedZombieCount = 0;
for (uint256 i = 0; i < currentZombieCount; i++) {
if (nodeHasStaker(nodeNum, zombieAddress(i))) {
stakedZombieCount++;
}
}
return stakedZombieCount;
}
function countZombiesStakedOnChildren(uint64 nodeNum) public view override returns (uint256) {
uint256 currentZombieCount = zombieCount();
uint256 stakedZombieCount = 0;
for (uint256 i = 0; i < currentZombieCount; i++) {
Zombie storage zombie = getZombieStorage(i);
if (
zombie.latestStakedNode != nodeNum && nodeHasStaker(nodeNum, zombie.stakerAddress)
) {
stakedZombieCount++;
}
}
return stakedZombieCount;
}
function requireUnresolvedExists() public view override {
uint256 firstUnresolved = firstUnresolvedNode();
require(
firstUnresolved > latestConfirmed() && firstUnresolved <= latestNodeCreated(),
"NO_UNRESOLVED"
);
}
function requireUnresolved(uint256 nodeNum) public view override {
require(nodeNum >= firstUnresolvedNode(), "ALREADY_DECIDED");
require(nodeNum <= latestNodeCreated(), "DOESNT_EXIST");
}
function requireUnchallengedStaker(address stakerAddress) private view {
require(isStaked(stakerAddress), "NOT_STAKED");
require(currentChallenge(stakerAddress) == NO_CHAL_INDEX, "IN_CHAL");
}
}
contract RollupUserLogic is AbsRollupUserLogic, IRollupUser {
function initialize(address _stakeToken) external view override onlyProxy {
require(_stakeToken == address(0), "NO_TOKEN_ALLOWED");
require(!isERC20Enabled(), "FACET_NOT_ERC20");
}
function newStakeOnExistingNode(uint64 nodeNum, bytes32 nodeHash) external payable override {
_newStake(msg.value);
stakeOnExistingNode(nodeNum, nodeHash);
}
function newStakeOnNewNode(
RollupLib.Assertion calldata assertion,
bytes32 expectedNodeHash,
uint256 prevNodeInboxMaxCount
) external payable override {
_newStake(msg.value);
stakeOnNewNode(assertion, expectedNodeHash, prevNodeInboxMaxCount);
}
function addToDeposit(address stakerAddress)
external
payable
override
onlyValidator
whenNotPaused
{
_addToDeposit(stakerAddress, msg.value);
}
function withdrawStakerFunds() external override onlyValidator whenNotPaused returns (uint256) {
uint256 amount = withdrawFunds(msg.sender);
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "TRANSFER_FAILED");
return amount;
}
}
contract ERC20RollupUserLogic is AbsRollupUserLogic, IRollupUserERC20 {
function initialize(address _stakeToken) external view override onlyProxy {
require(_stakeToken != address(0), "NEED_STAKE_TOKEN");
require(isERC20Enabled(), "FACET_NOT_ERC20");
}
function newStakeOnExistingNode(
uint256 tokenAmount,
uint64 nodeNum,
bytes32 nodeHash
) external override {
_newStake(tokenAmount);
stakeOnExistingNode(nodeNum, nodeHash);
receiveTokens(tokenAmount);
}
function newStakeOnNewNode(
uint256 tokenAmount,
RollupLib.Assertion calldata assertion,
bytes32 expectedNodeHash,
uint256 prevNodeInboxMaxCount
) external override {
_newStake(tokenAmount);
stakeOnNewNode(assertion, expectedNodeHash, prevNodeInboxMaxCount);
receiveTokens(tokenAmount);
}
function addToDeposit(address stakerAddress, uint256 tokenAmount)
external
onlyValidator
whenNotPaused
{
_addToDeposit(stakerAddress, tokenAmount);
receiveTokens(tokenAmount);
}
function withdrawStakerFunds() external override onlyValidator whenNotPaused returns (uint256) {
uint256 amount = withdrawFunds(msg.sender);
require(IERC20Upgradeable(stakeToken).transfer(msg.sender, amount), "TRANSFER_FAILED");
return amount;
}
function receiveTokens(uint256 tokenAmount) private {
require(
IERC20Upgradeable(stakeToken).transferFrom(msg.sender, address(this), tokenAmount),
"TRANSFER_FAIL"
);
}
}
文件 72 的 88:SequencerInbox.sol
pragma solidity ^0.8.0;
import {
AlreadyInit,
HadZeroInit,
NotOrigin,
DataTooLarge,
NotRollup,
DelayedBackwards,
DelayedTooFar,
ForceIncludeBlockTooSoon,
ForceIncludeTimeTooSoon,
IncorrectMessagePreimage,
NotBatchPoster,
BadSequencerNumber,
DataNotAuthenticated,
AlreadyValidDASKeyset,
NoSuchKeyset
} from "../libraries/Error.sol";
import "./IBridge.sol";
import "./IInbox.sol";
import "./ISequencerInbox.sol";
import "../rollup/IRollupLogic.sol";
import "./Messages.sol";
import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol";
import {GasRefundEnabled, IGasRefunder} from "../libraries/IGasRefunder.sol";
import "../libraries/DelegateCallAware.sol";
import {MAX_DATA_SIZE} from "../libraries/Constants.sol";
contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox {
uint256 public totalDelayedMessagesRead;
IBridge public bridge;
uint256 public constant HEADER_LENGTH = 40;
bytes1 public constant DATA_AUTHENTICATED_FLAG = 0x40;
IOwnable public rollup;
mapping(address => bool) public isBatchPoster;
ISequencerInbox.MaxTimeVariation public maxTimeVariation;
mapping(bytes32 => DasKeySetInfo) public dasKeySetInfo;
modifier onlyRollupOwner() {
if (msg.sender != rollup.owner()) revert NotOwner(msg.sender, address(rollup));
_;
}
function initialize(
IBridge bridge_,
ISequencerInbox.MaxTimeVariation calldata maxTimeVariation_
) external onlyDelegated {
if (bridge != IBridge(address(0))) revert AlreadyInit();
if (bridge_ == IBridge(address(0))) revert HadZeroInit();
bridge = bridge_;
rollup = bridge_.rollup();
maxTimeVariation = maxTimeVariation_;
}
function getTimeBounds() internal view virtual returns (TimeBounds memory) {
TimeBounds memory bounds;
if (block.timestamp > maxTimeVariation.delaySeconds) {
bounds.minTimestamp = uint64(block.timestamp - maxTimeVariation.delaySeconds);
}
bounds.maxTimestamp = uint64(block.timestamp + maxTimeVariation.futureSeconds);
if (block.number > maxTimeVariation.delayBlocks) {
bounds.minBlockNumber = uint64(block.number - maxTimeVariation.delayBlocks);
}
bounds.maxBlockNumber = uint64(block.number + maxTimeVariation.futureBlocks);
return bounds;
}
function forceInclusion(
uint256 _totalDelayedMessagesRead,
uint8 kind,
uint64[2] calldata l1BlockAndTime,
uint256 baseFeeL1,
address sender,
bytes32 messageDataHash
) external {
if (_totalDelayedMessagesRead <= totalDelayedMessagesRead) revert DelayedBackwards();
bytes32 messageHash = Messages.messageHash(
kind,
sender,
l1BlockAndTime[0],
l1BlockAndTime[1],
_totalDelayedMessagesRead - 1,
baseFeeL1,
messageDataHash
);
if (l1BlockAndTime[0] + maxTimeVariation.delayBlocks >= block.number)
revert ForceIncludeBlockTooSoon();
if (l1BlockAndTime[1] + maxTimeVariation.delaySeconds >= block.timestamp)
revert ForceIncludeTimeTooSoon();
bytes32 prevDelayedAcc = 0;
if (_totalDelayedMessagesRead > 1) {
prevDelayedAcc = bridge.delayedInboxAccs(_totalDelayedMessagesRead - 2);
}
if (
bridge.delayedInboxAccs(_totalDelayedMessagesRead - 1) !=
Messages.accumulateInboxMessage(prevDelayedAcc, messageHash)
) revert IncorrectMessagePreimage();
(bytes32 dataHash, TimeBounds memory timeBounds) = formEmptyDataHash(
_totalDelayedMessagesRead
);
(
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 afterAcc
) = addSequencerL2BatchImpl(dataHash, _totalDelayedMessagesRead, 0);
emit SequencerBatchDelivered(
seqMessageIndex,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds,
BatchDataLocation.NoData
);
}
function addSequencerL2BatchFromOrigin(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder
) external refundsGas(gasRefunder) {
if (msg.sender != tx.origin) revert NotOrigin();
if (!isBatchPoster[msg.sender]) revert NotBatchPoster();
(bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
data,
afterDelayedMessagesRead
);
(
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 afterAcc
) = addSequencerL2BatchImpl(dataHash, afterDelayedMessagesRead, data.length);
if (seqMessageIndex != sequenceNumber)
revert BadSequencerNumber(seqMessageIndex, sequenceNumber);
emit SequencerBatchDelivered(
sequenceNumber,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds,
BatchDataLocation.TxInput
);
}
function addSequencerL2Batch(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder
) external refundsGas(gasRefunder) {
if (!isBatchPoster[msg.sender] && msg.sender != address(rollup)) revert NotBatchPoster();
(bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
data,
afterDelayedMessagesRead
);
(
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 afterAcc
) = addSequencerL2BatchImpl(dataHash, afterDelayedMessagesRead, 0);
if (seqMessageIndex != sequenceNumber)
revert BadSequencerNumber(seqMessageIndex, sequenceNumber);
emit SequencerBatchDelivered(
sequenceNumber,
beforeAcc,
afterAcc,
delayedAcc,
afterDelayedMessagesRead,
timeBounds,
BatchDataLocation.SeparateBatchEvent
);
emit SequencerBatchData(sequenceNumber, data);
}
modifier validateBatchData(bytes calldata data) {
uint256 fullDataLen = HEADER_LENGTH + data.length;
if (fullDataLen > MAX_DATA_SIZE) revert DataTooLarge(fullDataLen, MAX_DATA_SIZE);
if (data.length > 0 && (data[0] & DATA_AUTHENTICATED_FLAG) == DATA_AUTHENTICATED_FLAG) {
revert DataNotAuthenticated();
}
if (data.length >= 33 && data[0] & 0x80 != 0) {
bytes32 dasKeysetHash = bytes32(data[1:33]);
if (!dasKeySetInfo[dasKeysetHash].isValidKeyset) revert NoSuchKeyset(dasKeysetHash);
}
_;
}
function packHeader(uint256 afterDelayedMessagesRead)
internal
view
returns (bytes memory, TimeBounds memory)
{
TimeBounds memory timeBounds = getTimeBounds();
bytes memory header = abi.encodePacked(
timeBounds.minTimestamp,
timeBounds.maxTimestamp,
timeBounds.minBlockNumber,
timeBounds.maxBlockNumber,
uint64(afterDelayedMessagesRead)
);
assert(header.length == HEADER_LENGTH);
return (header, timeBounds);
}
function formDataHash(bytes calldata data, uint256 afterDelayedMessagesRead)
internal
view
validateBatchData(data)
returns (bytes32, TimeBounds memory)
{
(bytes memory header, TimeBounds memory timeBounds) = packHeader(afterDelayedMessagesRead);
bytes32 dataHash = keccak256(bytes.concat(header, data));
return (dataHash, timeBounds);
}
function formEmptyDataHash(uint256 afterDelayedMessagesRead)
internal
view
returns (bytes32, TimeBounds memory)
{
(bytes memory header, TimeBounds memory timeBounds) = packHeader(afterDelayedMessagesRead);
return (keccak256(header), timeBounds);
}
function addSequencerL2BatchImpl(
bytes32 dataHash,
uint256 afterDelayedMessagesRead,
uint256 calldataLengthPosted
)
internal
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 acc
)
{
if (afterDelayedMessagesRead < totalDelayedMessagesRead) revert DelayedBackwards();
if (afterDelayedMessagesRead > bridge.delayedMessageCount()) revert DelayedTooFar();
(seqMessageIndex, beforeAcc, delayedAcc, acc) = bridge.enqueueSequencerMessage(
dataHash,
afterDelayedMessagesRead
);
totalDelayedMessagesRead = afterDelayedMessagesRead;
if (calldataLengthPosted > 0) {
address batchPoster = msg.sender;
bytes memory spendingReportMsg = abi.encodePacked(
block.timestamp,
batchPoster,
dataHash,
seqMessageIndex,
block.basefee
);
uint256 msgNum = bridge.submitBatchSpendingReport(
batchPoster,
keccak256(spendingReportMsg)
);
emit InboxMessageDelivered(msgNum, spendingReportMsg);
}
}
function inboxAccs(uint256 index) external view returns (bytes32) {
return bridge.sequencerInboxAccs(index);
}
function batchCount() external view returns (uint256) {
return bridge.sequencerMessageCount();
}
function setMaxTimeVariation(ISequencerInbox.MaxTimeVariation memory maxTimeVariation_)
external
onlyRollupOwner
{
maxTimeVariation = maxTimeVariation_;
emit OwnerFunctionCalled(0);
}
function setIsBatchPoster(address addr, bool isBatchPoster_) external onlyRollupOwner {
isBatchPoster[addr] = isBatchPoster_;
emit OwnerFunctionCalled(1);
}
function setValidKeyset(bytes calldata keysetBytes) external onlyRollupOwner {
uint256 ksWord = uint256(keccak256(bytes.concat(hex"fe", keccak256(keysetBytes))));
bytes32 ksHash = bytes32(ksWord ^ (1 << 255));
require(keysetBytes.length < 64 * 1024, "keyset is too large");
if (dasKeySetInfo[ksHash].isValidKeyset) revert AlreadyValidDASKeyset(ksHash);
dasKeySetInfo[ksHash] = DasKeySetInfo({
isValidKeyset: true,
creationBlock: uint64(block.number)
});
emit SetValidKeyset(ksHash, keysetBytes);
emit OwnerFunctionCalled(2);
}
function invalidateKeysetHash(bytes32 ksHash) external onlyRollupOwner {
if (!dasKeySetInfo[ksHash].isValidKeyset) revert NoSuchKeyset(ksHash);
dasKeySetInfo[ksHash].isValidKeyset = false;
emit InvalidateKeyset(ksHash);
emit OwnerFunctionCalled(3);
}
function isValidKeysetHash(bytes32 ksHash) external view returns (bool) {
return dasKeySetInfo[ksHash].isValidKeyset;
}
function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256) {
DasKeySetInfo memory ksInfo = dasKeySetInfo[ksHash];
if (ksInfo.creationBlock == 0) revert NoSuchKeyset(ksHash);
return uint256(ksInfo.creationBlock);
}
}
文件 73 的 88:SequencerInboxStub.sol
pragma solidity ^0.8.0;
import "../bridge/SequencerInbox.sol";
contract SequencerInboxStub is SequencerInbox {
constructor(
IBridge bridge_,
address sequencer_,
ISequencerInbox.MaxTimeVariation memory maxTimeVariation_
) {
bridge = bridge_;
rollup = IOwnable(msg.sender);
maxTimeVariation = maxTimeVariation_;
isBatchPoster[sequencer_] = true;
}
function addInitMessage() external {
(bytes32 dataHash, TimeBounds memory timeBounds) = formEmptyDataHash(0);
(
uint256 sequencerMessageCount,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 afterAcc
) = addSequencerL2BatchImpl(dataHash, 0, 0);
emit SequencerBatchDelivered(
sequencerMessageCount,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds,
BatchDataLocation.NoData
);
}
function getTimeBounds() internal view override returns (TimeBounds memory bounds) {
this;
return bounds;
}
}
文件 74 的 88:SimpleProxy.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/Proxy.sol";
contract SimpleProxy is Proxy {
address private immutable impl;
constructor(address impl_) {
impl = impl_;
}
function _implementation() internal view override returns (address) {
return impl;
}
}
文件 75 的 88:StackFrame.sol
pragma solidity ^0.8.0;
import "./Value.sol";
struct StackFrame {
Value returnPc;
bytes32 localsMerkleRoot;
uint32 callerModule;
uint32 callerModuleInternals;
}
struct StackFrameWindow {
StackFrame[] proved;
bytes32 remainingHash;
}
library StackFrameLib {
using ValueLib for Value;
function hash(StackFrame memory frame) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
"Stack frame:",
frame.returnPc.hash(),
frame.localsMerkleRoot,
frame.callerModule,
frame.callerModuleInternals
)
);
}
function hash(StackFrameWindow memory window) internal pure returns (bytes32 h) {
h = window.remainingHash;
for (uint256 i = 0; i < window.proved.length; i++) {
h = keccak256(abi.encodePacked("Stack frame stack:", hash(window.proved[i]), h));
}
}
function peek(StackFrameWindow memory window) internal pure returns (StackFrame memory) {
require(window.proved.length == 1, "BAD_WINDOW_LENGTH");
return window.proved[0];
}
function pop(StackFrameWindow memory window) internal pure returns (StackFrame memory frame) {
require(window.proved.length == 1, "BAD_WINDOW_LENGTH");
frame = window.proved[0];
window.proved = new StackFrame[](0);
}
function push(StackFrameWindow memory window, StackFrame memory frame) internal pure {
StackFrame[] memory newProved = new StackFrame[](window.proved.length + 1);
for (uint256 i = 0; i < window.proved.length; i++) {
newProved[i] = window.proved[i];
}
newProved[window.proved.length] = frame;
window.proved = newProved;
}
}
文件 76 的 88:StorageSlot.sol
pragma solidity ^0.8.0;
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly {
r.slot := slot
}
}
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly {
r.slot := slot
}
}
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly {
r.slot := slot
}
}
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly {
r.slot := slot
}
}
}
文件 77 的 88:TransparentUpgradeableProxy.sol
pragma solidity ^0.8.0;
import "../ERC1967/ERC1967Proxy.sol";
contract TransparentUpgradeableProxy is ERC1967Proxy {
constructor(
address _logic,
address admin_,
bytes memory _data
) payable ERC1967Proxy(_logic, _data) {
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
_changeAdmin(admin_);
}
modifier ifAdmin() {
if (msg.sender == _getAdmin()) {
_;
} else {
_fallback();
}
}
function admin() external ifAdmin returns (address admin_) {
admin_ = _getAdmin();
}
function implementation() external ifAdmin returns (address implementation_) {
implementation_ = _implementation();
}
function changeAdmin(address newAdmin) external virtual ifAdmin {
_changeAdmin(newAdmin);
}
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeToAndCall(newImplementation, bytes(""), false);
}
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
_upgradeToAndCall(newImplementation, data, true);
}
function _admin() internal view virtual returns (address) {
return _getAdmin();
}
function _beforeFallback() internal virtual override {
require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
super._beforeFallback();
}
}
文件 78 的 88:UUPSNotUpgradeable.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {DoubleLogicERC1967Upgrade} from "./AdminFallbackProxy.sol";
abstract contract UUPSNotUpgradeable is IERC1822Proxiable, DoubleLogicERC1967Upgrade {
address private immutable __self = address(this);
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(
_getSecondaryImplementation() == __self,
"Function must be called through active proxy"
);
_;
}
modifier notDelegated() {
require(
address(this) == __self,
"UUPSNotUpgradeable: must not be called through delegatecall"
);
_;
}
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SECONDARY_SLOT;
}
}
文件 79 的 88:UUPSUpgradeable.sol
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822.sol";
import "../ERC1967/ERC1967Upgrade.sol";
abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
address private immutable __self = address(this);
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
function upgradeTo(address newImplementation) external virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
function _authorizeUpgrade(address newImplementation) internal virtual;
}
文件 80 的 88:UpgradeableBeacon.sol
pragma solidity ^0.8.0;
import "./IBeacon.sol";
import "../../access/Ownable.sol";
import "../../utils/Address.sol";
contract UpgradeableBeacon is IBeacon, Ownable {
address private _implementation;
event Upgraded(address indexed implementation);
constructor(address implementation_) {
_setImplementation(implementation_);
}
function implementation() public view virtual override returns (address) {
return _implementation;
}
function upgradeTo(address newImplementation) public virtual onlyOwner {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract");
_implementation = newImplementation;
}
}
文件 81 的 88:ValidatorUtils.sol
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "../rollup/IRollupCore.sol";
import "../challenge/IChallengeManager.sol";
import {NO_CHAL_INDEX} from "../libraries/Constants.sol";
contract ValidatorUtils {
using NodeLib for Node;
enum ConfirmType {
NONE,
VALID,
INVALID
}
enum NodeConflictType {
NONE,
FOUND,
INDETERMINATE,
INCOMPLETE
}
struct NodeConflict {
NodeConflictType ty;
uint64 node1;
uint64 node2;
}
function findStakerConflict(
IRollupCore rollup,
address staker1,
address staker2,
uint256 maxDepth
) external view returns (NodeConflict memory) {
uint64 staker1NodeNum = rollup.latestStakedNode(staker1);
uint64 staker2NodeNum = rollup.latestStakedNode(staker2);
return findNodeConflict(rollup, staker1NodeNum, staker2NodeNum, maxDepth);
}
function checkDecidableNextNode(IRollupUserAbs rollup) external view returns (ConfirmType) {
try ValidatorUtils(address(this)).requireConfirmable(rollup) {
return ConfirmType.VALID;
} catch {}
try ValidatorUtils(address(this)).requireRejectable(rollup) {
return ConfirmType.INVALID;
} catch {
return ConfirmType.NONE;
}
}
function requireRejectable(IRollupCore rollup) external view {
IRollupUser(address(rollup)).requireUnresolvedExists();
uint64 firstUnresolvedNode = rollup.firstUnresolvedNode();
Node memory node = rollup.getNode(firstUnresolvedNode);
if (node.prevNum == rollup.latestConfirmed()) {
require(block.number >= node.deadlineBlock, "BEFORE_DEADLINE");
rollup.getNode(node.prevNum).requirePastChildConfirmDeadline();
require(
node.stakerCount ==
IRollupUser(address(rollup)).countStakedZombies(firstUnresolvedNode),
"HAS_STAKERS"
);
}
}
function requireConfirmable(IRollupUserAbs rollup) external view {
rollup.requireUnresolvedExists();
uint256 stakerCount = rollup.stakerCount();
require(stakerCount > 0, "NO_STAKERS");
uint64 firstUnresolved = rollup.firstUnresolvedNode();
Node memory node = rollup.getNode(firstUnresolved);
node.requirePastDeadline();
assert(node.prevNum == rollup.latestConfirmed());
Node memory prevNode = rollup.getNode(node.prevNum);
prevNode.requirePastChildConfirmDeadline();
uint256 zombiesStakedOnOtherChildren = rollup.countZombiesStakedOnChildren(node.prevNum) -
rollup.countStakedZombies(firstUnresolved);
require(
prevNode.childStakerCount == node.stakerCount + zombiesStakedOnOtherChildren,
"NOT_ALL_STAKED"
);
}
function refundableStakers(IRollupCore rollup) external view returns (address[] memory) {
uint256 stakerCount = rollup.stakerCount();
address[] memory stakers = new address[](stakerCount);
uint256 latestConfirmed = rollup.latestConfirmed();
uint256 index = 0;
for (uint64 i = 0; i < stakerCount; i++) {
address staker = rollup.getStakerAddress(i);
uint256 latestStakedNode = rollup.latestStakedNode(staker);
if (latestStakedNode <= latestConfirmed && rollup.currentChallenge(staker) == 0) {
stakers[index] = staker;
index++;
}
}
assembly {
mstore(stakers, index)
}
return stakers;
}
function latestStaked(IRollupCore rollup, address staker)
external
view
returns (uint64, Node memory)
{
uint64 num = rollup.latestStakedNode(staker);
if (num == 0) {
num = rollup.latestConfirmed();
}
Node memory node = rollup.getNode(num);
return (num, node);
}
function stakedNodes(IRollupCore rollup, address staker)
external
view
returns (uint64[] memory)
{
uint64[] memory nodes = new uint64[](100000);
uint256 index = 0;
for (uint64 i = rollup.latestConfirmed(); i <= rollup.latestNodeCreated(); i++) {
if (rollup.nodeHasStaker(i, staker)) {
nodes[index] = i;
index++;
}
}
assembly {
mstore(nodes, index)
}
return nodes;
}
function findNodeConflict(
IRollupCore rollup,
uint64 node1,
uint64 node2,
uint256 maxDepth
) public view returns (NodeConflict memory) {
uint64 firstUnresolvedNode = rollup.firstUnresolvedNode();
uint64 node1Prev = rollup.getNode(node1).prevNum;
uint64 node2Prev = rollup.getNode(node2).prevNum;
for (uint256 i = 0; i < maxDepth; i++) {
if (node1 == node2) {
return NodeConflict(NodeConflictType.NONE, node1, node2);
}
if (node1Prev == node2Prev) {
return NodeConflict(NodeConflictType.FOUND, node1, node2);
}
if (node1Prev < firstUnresolvedNode && node2Prev < firstUnresolvedNode) {
return NodeConflict(NodeConflictType.INDETERMINATE, 0, 0);
}
if (node1Prev < node2Prev) {
node2 = node2Prev;
node2Prev = rollup.getNode(node2).prevNum;
} else {
node1 = node1Prev;
node1Prev = rollup.getNode(node1).prevNum;
}
}
return NodeConflict(NodeConflictType.INCOMPLETE, 0, 0);
}
function getStakers(
IRollupCore rollup,
uint64 startIndex,
uint64 max
) public view returns (address[] memory, bool hasMore) {
uint256 maxStakers = rollup.stakerCount();
if (startIndex + max <= maxStakers) {
maxStakers = startIndex + max;
hasMore = true;
}
address[] memory stakers = new address[](maxStakers);
for (uint64 i = 0; i < maxStakers; i++) {
stakers[i] = rollup.getStakerAddress(startIndex + i);
}
return (stakers, hasMore);
}
function timedOutChallenges(
IRollupCore rollup,
uint64 startIndex,
uint64 max
) external view returns (uint64[] memory, bool hasMore) {
(address[] memory stakers, bool hasMoreStakers) = getStakers(rollup, startIndex, max);
uint64[] memory challenges = new uint64[](stakers.length);
uint256 index = 0;
IChallengeManager challengeManager = rollup.challengeManager();
for (uint256 i = 0; i < stakers.length; i++) {
address staker = stakers[i];
uint64 challengeIndex = rollup.currentChallenge(staker);
if (
challengeIndex != NO_CHAL_INDEX &&
challengeManager.isTimedOut(challengeIndex) &&
challengeManager.currentResponder(challengeIndex) == staker
) {
challenges[index++] = challengeIndex;
}
}
assembly {
mstore(challenges, index)
}
return (challenges, hasMoreStakers);
}
function areUnresolvedNodesLinear(IRollupCore rollup) external view returns (bool) {
uint256 end = rollup.latestNodeCreated();
for (uint64 i = rollup.firstUnresolvedNode(); i <= end; i++) {
if (i > 0 && rollup.getNode(i).prevNum != i - 1) {
return false;
}
}
return true;
}
}
文件 82 的 88:ValidatorWallet.sol
pragma solidity ^0.8.0;
import "../challenge/IChallengeManager.sol";
import "../libraries/DelegateCallAware.sol";
import "../libraries/IGasRefunder.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
error BadArrayLength(uint256 expected, uint256 actual);
error NotExecutorOrOwner(address actual);
error OnlyOwnerDestination(address expected, address actual, address destination);
error WithdrawEthFail(address destination);
contract ValidatorWallet is OwnableUpgradeable, DelegateCallAware, GasRefundEnabled {
using Address for address;
mapping(address => bool) public executors;
mapping(address => bool) public allowedExecutorDestinations;
modifier onlyExecutorOrOwner() {
if (!executors[_msgSender()] && owner() != _msgSender())
revert NotExecutorOrOwner(_msgSender());
_;
}
event ExecutorUpdated(address indexed executor, bool isExecutor);
function setExecutor(address[] calldata newExecutors, bool[] calldata isExecutor)
external
onlyOwner
{
if (newExecutors.length != isExecutor.length)
revert BadArrayLength(newExecutors.length, isExecutor.length);
unchecked {
for (uint64 i = 0; i < newExecutors.length; ++i) {
executors[newExecutors[i]] = isExecutor[i];
emit ExecutorUpdated(newExecutors[i], isExecutor[i]);
}
}
}
function initialize(
address _executor,
address _owner,
address[] calldata initialExecutorAllowedDests
) external initializer onlyDelegated {
__Ownable_init();
transferOwnership(_owner);
executors[_executor] = true;
emit ExecutorUpdated(_executor, true);
unchecked {
for (uint64 i = 0; i < initialExecutorAllowedDests.length; ++i) {
allowedExecutorDestinations[initialExecutorAllowedDests[i]] = true;
emit AllowedExecutorDestinationsUpdated(initialExecutorAllowedDests[i], true);
}
}
}
event AllowedExecutorDestinationsUpdated(address indexed destination, bool isSet);
function setAllowedExecutorDestinations(address[] calldata destinations, bool[] calldata isSet)
external
onlyOwner
{
if (destinations.length != isSet.length)
revert BadArrayLength(destinations.length, isSet.length);
unchecked {
for (uint256 i = 0; i < destinations.length; ++i) {
allowedExecutorDestinations[destinations[i]] = isSet[i];
emit AllowedExecutorDestinationsUpdated(destinations[i], isSet[i]);
}
}
}
function validateExecuteTransaction(address destination) public view {
if (!allowedExecutorDestinations[destination] && owner() != _msgSender())
revert OnlyOwnerDestination(owner(), _msgSender(), destination);
}
function executeTransactions(
bytes[] calldata data,
address[] calldata destination,
uint256[] calldata amount
) external payable {
executeTransactionsWithGasRefunder(IGasRefunder(address(0)), data, destination, amount);
}
function executeTransactionsWithGasRefunder(
IGasRefunder gasRefunder,
bytes[] calldata data,
address[] calldata destination,
uint256[] calldata amount
) public payable onlyExecutorOrOwner refundsGas(gasRefunder) {
uint256 numTxes = data.length;
if (numTxes != destination.length) revert BadArrayLength(numTxes, destination.length);
if (numTxes != amount.length) revert BadArrayLength(numTxes, amount.length);
for (uint256 i = 0; i < numTxes; i++) {
if (data[i].length > 0) require(destination[i].isContract(), "NO_CODE_AT_ADDR");
validateExecuteTransaction(destination[i]);
(bool success, ) = address(destination[i]).call{value: amount[i]}(data[i]);
if (!success) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
}
}
function executeTransaction(
bytes calldata data,
address destination,
uint256 amount
) external payable {
executeTransactionWithGasRefunder(IGasRefunder(address(0)), data, destination, amount);
}
function executeTransactionWithGasRefunder(
IGasRefunder gasRefunder,
bytes calldata data,
address destination,
uint256 amount
) public payable onlyExecutorOrOwner refundsGas(gasRefunder) {
if (data.length > 0) require(destination.isContract(), "NO_CODE_AT_ADDR");
validateExecuteTransaction(destination);
(bool success, ) = destination.call{value: amount}(data);
if (!success) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
}
function timeoutChallenges(IChallengeManager manager, uint64[] calldata challenges) external {
timeoutChallengesWithGasRefunder(IGasRefunder(address(0)), manager, challenges);
}
function timeoutChallengesWithGasRefunder(
IGasRefunder gasRefunder,
IChallengeManager manager,
uint64[] calldata challenges
) public onlyExecutorOrOwner refundsGas(gasRefunder) {
uint256 challengesCount = challenges.length;
for (uint256 i = 0; i < challengesCount; i++) {
try manager.timeout(challenges[i]) {} catch (bytes memory error) {
if (error.length == 0) {
require(false, "GAS");
}
}
}
}
receive() external payable {}
function withdrawEth(uint256 amount, address destination) external onlyOwner {
(bool success, ) = destination.call{value: amount}("");
if (!success) revert WithdrawEthFail(destination);
}
}
文件 83 的 88:ValidatorWalletCreator.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./ValidatorWallet.sol";
contract ValidatorWalletCreator is Ownable {
event WalletCreated(
address indexed walletAddress,
address indexed executorAddress,
address indexed ownerAddress,
address adminProxy
);
event TemplateUpdated();
address public template;
constructor() Ownable() {
template = address(new ValidatorWallet());
}
function setTemplate(address _template) external onlyOwner {
template = _template;
emit TemplateUpdated();
}
function createWallet(address[] calldata initialExecutorAllowedDests)
external
returns (address)
{
address _executor = msg.sender;
address _owner = msg.sender;
ProxyAdmin admin = new ProxyAdmin();
address proxy = address(
new TransparentUpgradeableProxy(address(template), address(admin), "")
);
admin.transferOwnership(_owner);
ValidatorWallet(payable(proxy)).initialize(_executor, _owner, initialExecutorAllowedDests);
emit WalletCreated(proxy, _executor, _owner, address(admin));
return proxy;
}
}
文件 84 的 88:Value.sol
pragma solidity ^0.8.0;
enum ValueType {
I32,
I64,
F32,
F64,
REF_NULL,
FUNC_REF,
INTERNAL_REF
}
struct Value {
ValueType valueType;
uint256 contents;
}
library ValueLib {
function hash(Value memory val) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("Value:", val.valueType, val.contents));
}
function maxValueType() internal pure returns (ValueType) {
return ValueType.INTERNAL_REF;
}
function assumeI32(Value memory val) internal pure returns (uint32) {
uint256 uintval = uint256(val.contents);
require(val.valueType == ValueType.I32, "NOT_I32");
require(uintval < (1 << 32), "BAD_I32");
return uint32(uintval);
}
function assumeI64(Value memory val) internal pure returns (uint64) {
uint256 uintval = uint256(val.contents);
require(val.valueType == ValueType.I64, "NOT_I64");
require(uintval < (1 << 64), "BAD_I64");
return uint64(uintval);
}
function newRefNull() internal pure returns (Value memory) {
return Value({valueType: ValueType.REF_NULL, contents: 0});
}
function newI32(uint32 x) internal pure returns (Value memory) {
return Value({valueType: ValueType.I32, contents: uint256(x)});
}
function newI64(uint64 x) internal pure returns (Value memory) {
return Value({valueType: ValueType.I64, contents: uint256(x)});
}
function newBoolean(bool x) internal pure returns (Value memory) {
if (x) {
return newI32(uint32(1));
} else {
return newI32(uint32(0));
}
}
}
文件 85 的 88:ValueArray.sol
pragma solidity ^0.8.0;
import "./Value.sol";
struct ValueArray {
Value[] inner;
}
library ValueArrayLib {
function get(ValueArray memory arr, uint256 index) internal pure returns (Value memory) {
return arr.inner[index];
}
function set(
ValueArray memory arr,
uint256 index,
Value memory val
) internal pure {
arr.inner[index] = val;
}
function length(ValueArray memory arr) internal pure returns (uint256) {
return arr.inner.length;
}
function push(ValueArray memory arr, Value memory val) internal pure {
Value[] memory newInner = new Value[](arr.inner.length + 1);
for (uint256 i = 0; i < arr.inner.length; i++) {
newInner[i] = arr.inner[i];
}
newInner[arr.inner.length] = val;
arr.inner = newInner;
}
function pop(ValueArray memory arr) internal pure returns (Value memory popped) {
popped = arr.inner[arr.inner.length - 1];
Value[] memory newInner = new Value[](arr.inner.length - 1);
for (uint256 i = 0; i < newInner.length; i++) {
newInner[i] = arr.inner[i];
}
arr.inner = newInner;
}
}
文件 86 的 88:ValueArrayTester.sol
pragma solidity ^0.8.0;
import "../state/ValueArray.sol";
contract ValueArrayTester {
using ValueArrayLib for ValueArray;
function test() external pure {
ValueArray memory arr = ValueArray(new Value[](2));
require(arr.length() == 2, "START_LEN");
arr.set(0, ValueLib.newI32(1));
arr.set(1, ValueLib.newI32(2));
arr.push(ValueLib.newI32(3));
require(arr.length() == 3, "PUSH_LEN");
for (uint256 i = 0; i < arr.length(); i++) {
Value memory val = arr.get(i);
require(val.valueType == ValueType.I32, "PUSH_VAL_TYPE");
require(val.contents == i + 1, "PUSH_VAL_CONTENTS");
}
Value memory popped = arr.pop();
require(popped.valueType == ValueType.I32, "POP_RET_TYPE");
require(popped.contents == 3, "POP_RET_CONTENTS");
require(arr.length() == 2, "POP_LEN");
for (uint256 i = 0; i < arr.length(); i++) {
Value memory val = arr.get(i);
require(val.valueType == ValueType.I32, "POP_VAL_TYPE");
require(val.contents == i + 1, "POP_VAL_CONTENTS");
}
}
}
文件 87 的 88:ValueStack.sol
pragma solidity ^0.8.0;
import "./Value.sol";
import "./ValueArray.sol";
struct ValueStack {
ValueArray proved;
bytes32 remainingHash;
}
library ValueStackLib {
using ValueLib for Value;
using ValueArrayLib for ValueArray;
function hash(ValueStack memory stack) internal pure returns (bytes32 h) {
h = stack.remainingHash;
uint256 len = stack.proved.length();
for (uint256 i = 0; i < len; i++) {
h = keccak256(abi.encodePacked("Value stack:", stack.proved.get(i).hash(), h));
}
}
function peek(ValueStack memory stack) internal pure returns (Value memory) {
uint256 len = stack.proved.length();
return stack.proved.get(len - 1);
}
function pop(ValueStack memory stack) internal pure returns (Value memory) {
return stack.proved.pop();
}
function push(ValueStack memory stack, Value memory val) internal pure {
return stack.proved.push(val);
}
}
文件 88 的 88:draft-IERC1822.sol
pragma solidity ^0.8.0;
interface IERC1822Proxiable {
function proxiableUUID() external view returns (bytes32);
}
{
"compilationTarget": {
"src/rollup/RollupProxy.sol": "RollupProxy"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 100
},
"remappings": []
}
[{"inputs":[{"components":[{"internalType":"uint64","name":"confirmPeriodBlocks","type":"uint64"},{"internalType":"uint64","name":"extraChallengeTimeBlocks","type":"uint64"},{"internalType":"address","name":"stakeToken","type":"address"},{"internalType":"uint256","name":"baseStake","type":"uint256"},{"internalType":"bytes32","name":"wasmModuleRoot","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"loserStakeEscrow","type":"address"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint64","name":"genesisBlockNum","type":"uint64"},{"components":[{"internalType":"uint256","name":"delayBlocks","type":"uint256"},{"internalType":"uint256","name":"futureBlocks","type":"uint256"},{"internalType":"uint256","name":"delaySeconds","type":"uint256"},{"internalType":"uint256","name":"futureSeconds","type":"uint256"}],"internalType":"struct ISequencerInbox.MaxTimeVariation","name":"sequencerInboxMaxTimeVariation","type":"tuple"}],"internalType":"struct Config","name":"config","type":"tuple"},{"components":[{"internalType":"contract IBridge","name":"bridge","type":"address"},{"internalType":"contract ISequencerInbox","name":"sequencerInbox","type":"address"},{"internalType":"contract IInbox","name":"inbox","type":"address"},{"internalType":"contract IOutbox","name":"outbox","type":"address"},{"internalType":"contract IRollupEventInbox","name":"rollupEventInbox","type":"address"},{"internalType":"contract IChallengeManager","name":"challengeManager","type":"address"},{"internalType":"contract IRollupAdmin","name":"rollupAdminLogic","type":"address"},{"internalType":"contract IRollupUser","name":"rollupUserLogic","type":"address"},{"internalType":"address","name":"validatorUtils","type":"address"},{"internalType":"address","name":"validatorWalletCreator","type":"address"}],"internalType":"struct ContractDependencies","name":"connectedContracts","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"UpgradedSecondary","type":"event"},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"payable","type":"receive"}]