文件 1 的 13:AddressAliasHelper.sol
pragma solidity ^0.8.7;
library AddressAliasHelper {
uint160 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);
}
}
}
文件 2 的 13:CanonicalTransactionChain.sol
pragma solidity ^0.8.9;
import { AddressAliasHelper } from "../../standards/AddressAliasHelper.sol";
import { Lib_BVMCodec } from "../../libraries/codec/Lib_BVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { ICanonicalTransactionChain } from "./ICanonicalTransactionChain.sol";
import { IChainStorageContainer } from "./IChainStorageContainer.sol";
contract CanonicalTransactionChain is ICanonicalTransactionChain, Lib_AddressResolver {
uint256 public constant MIN_ROLLUP_TX_GAS = 100000;
uint256 public constant MAX_ROLLUP_TX_SIZE = 50000;
uint256 public enqueueGasCost;
uint256 public l2GasDiscountDivisor;
uint256 public enqueueL2GasPrepaid;
uint256 internal constant BATCH_CONTEXT_SIZE = 16;
uint256 internal constant BATCH_CONTEXT_LENGTH_POS = 12;
uint256 internal constant BATCH_CONTEXT_START_POS = 15;
uint256 internal constant TX_DATA_HEADER_SIZE = 3;
uint256 internal constant BYTES_TILL_TX_DATA = 65;
uint256 public maxTransactionGasLimit;
uint40 private _nextQueueIndex;
Lib_BVMCodec.QueueElement[] queueElements;
constructor(
address _libAddressManager,
uint256 _maxTransactionGasLimit,
uint256 _l2GasDiscountDivisor,
uint256 _enqueueGasCost
) Lib_AddressResolver(_libAddressManager) {
maxTransactionGasLimit = _maxTransactionGasLimit;
l2GasDiscountDivisor = _l2GasDiscountDivisor;
enqueueGasCost = _enqueueGasCost;
enqueueL2GasPrepaid = _l2GasDiscountDivisor * _enqueueGasCost;
}
modifier onlyBurnAdmin() {
require(msg.sender == libAddressManager.owner(), "Only callable by the Burn Admin.");
_;
}
function setGasParams(uint256 _l2GasDiscountDivisor, uint256 _enqueueGasCost)
external
onlyBurnAdmin
{
enqueueGasCost = _enqueueGasCost;
l2GasDiscountDivisor = _l2GasDiscountDivisor;
enqueueL2GasPrepaid = _l2GasDiscountDivisor * _enqueueGasCost;
emit L2GasParamsUpdated(l2GasDiscountDivisor, enqueueGasCost, enqueueL2GasPrepaid);
}
function batches() public view returns (IChainStorageContainer) {
return IChainStorageContainer(resolve("ChainStorageContainer-CTC-batches"));
}
function getTotalElements() public view returns (uint256 _totalElements) {
(uint40 totalElements, , , ) = _getBatchExtraData();
return uint256(totalElements);
}
function getTotalBatches() public view returns (uint256 _totalBatches) {
return batches().length();
}
function getNextQueueIndex() public view returns (uint40) {
return _nextQueueIndex;
}
function getLastTimestamp() public view returns (uint40) {
(, , uint40 lastTimestamp, ) = _getBatchExtraData();
return lastTimestamp;
}
function getLastBlockNumber() public view returns (uint40) {
(, , , uint40 lastBlockNumber) = _getBatchExtraData();
return lastBlockNumber;
}
function getQueueElement(uint256 _index)
public
view
returns (Lib_BVMCodec.QueueElement memory _element)
{
return queueElements[_index];
}
function getNumPendingQueueElements() public view returns (uint40) {
return uint40(queueElements.length) - _nextQueueIndex;
}
function getQueueLength() public view returns (uint40) {
return uint40(queueElements.length);
}
function enqueue(
address _target,
uint256 _gasLimit,
bytes memory _data
) external {
require(
_data.length <= MAX_ROLLUP_TX_SIZE,
"Transaction data size exceeds maximum for rollup transaction."
);
require(
_gasLimit <= maxTransactionGasLimit,
"Transaction gas limit exceeds maximum for rollup transaction."
);
require(_gasLimit >= MIN_ROLLUP_TX_GAS, "Transaction gas limit too low to enqueue.");
if (_gasLimit > enqueueL2GasPrepaid) {
uint256 gasToConsume = (_gasLimit - enqueueL2GasPrepaid) / l2GasDiscountDivisor;
uint256 startingGas = gasleft();
require(startingGas > gasToConsume, "Insufficient gas for L2 rate limiting burn.");
uint256 i;
while (startingGas - gasleft() < gasToConsume) {
i++;
}
}
address sender;
if (msg.sender == tx.origin) {
sender = msg.sender;
} else {
sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
}
bytes32 transactionHash = keccak256(abi.encode(sender, _target, _gasLimit, _data));
queueElements.push(
Lib_BVMCodec.QueueElement({
transactionHash: transactionHash,
timestamp: uint40(block.timestamp),
blockNumber: uint40(block.number)
})
);
uint256 queueIndex = queueElements.length - 1;
emit TransactionEnqueued(sender, _target, _gasLimit, _data, queueIndex, block.timestamp);
}
function appendSequencerBatch() external {
uint40 shouldStartAtElement;
uint24 totalElementsToAppend;
uint24 numContexts;
assembly {
shouldStartAtElement := shr(216, calldataload(4))
totalElementsToAppend := shr(232, calldataload(9))
numContexts := shr(232, calldataload(12))
}
require(
shouldStartAtElement == getTotalElements(),
"Actual batch start index does not match expected start index."
);
require(
msg.sender == resolve("BVM_Sequencer"),
"Function can only be called by the Sequencer."
);
uint40 nextTransactionPtr = uint40(
BATCH_CONTEXT_START_POS + BATCH_CONTEXT_SIZE * numContexts
);
require(msg.data.length >= nextTransactionPtr, "Not enough BatchContexts provided.");
uint32 numSequencerTransactions = 0;
uint40 nextQueueIndex = _nextQueueIndex;
BatchContext memory curContext;
for (uint32 i = 0; i < numContexts; i++) {
BatchContext memory nextContext = _getBatchContext(i);
curContext = nextContext;
numSequencerTransactions += uint32(curContext.numSequencedTransactions);
nextQueueIndex += uint40(curContext.numSubsequentQueueTransactions);
}
require(
nextQueueIndex <= queueElements.length,
"Attempted to append more elements than are available in the queue."
);
uint40 numQueuedTransactions = totalElementsToAppend - numSequencerTransactions;
uint40 blockTimestamp;
uint40 blockNumber;
if (curContext.numSubsequentQueueTransactions == 0) {
blockTimestamp = uint40(curContext.timestamp);
blockNumber = uint40(curContext.blockNumber);
} else {
Lib_BVMCodec.QueueElement memory lastElement = queueElements[nextQueueIndex - 1];
blockTimestamp = lastElement.timestamp;
blockNumber = lastElement.blockNumber;
}
_appendBatch(
blockhash(block.number - 1),
totalElementsToAppend,
numQueuedTransactions,
blockTimestamp,
blockNumber
);
emit SequencerBatchAppended(
nextQueueIndex - numQueuedTransactions,
numQueuedTransactions,
getTotalElements()
);
_nextQueueIndex = nextQueueIndex;
}
function _getBatchContext(uint256 _index) internal pure returns (BatchContext memory) {
uint256 contextPtr = 15 + _index * BATCH_CONTEXT_SIZE;
uint256 numSequencedTransactions;
uint256 numSubsequentQueueTransactions;
uint256 ctxTimestamp;
uint256 ctxBlockNumber;
assembly {
numSequencedTransactions := shr(232, calldataload(contextPtr))
numSubsequentQueueTransactions := shr(232, calldataload(add(contextPtr, 3)))
ctxTimestamp := shr(216, calldataload(add(contextPtr, 6)))
ctxBlockNumber := shr(216, calldataload(add(contextPtr, 11)))
}
return
BatchContext({
numSequencedTransactions: numSequencedTransactions,
numSubsequentQueueTransactions: numSubsequentQueueTransactions,
timestamp: ctxTimestamp,
blockNumber: ctxBlockNumber
});
}
function _getBatchExtraData()
internal
view
returns (
uint40,
uint40,
uint40,
uint40
)
{
bytes27 extraData = batches().getGlobalMetadata();
uint40 totalElements;
uint40 nextQueueIndex;
uint40 lastTimestamp;
uint40 lastBlockNumber;
assembly {
extraData := shr(40, extraData)
totalElements := and(
extraData,
0x000000000000000000000000000000000000000000000000000000FFFFFFFFFF
)
nextQueueIndex := shr(
40,
and(extraData, 0x00000000000000000000000000000000000000000000FFFFFFFFFF0000000000)
)
lastTimestamp := shr(
80,
and(extraData, 0x0000000000000000000000000000000000FFFFFFFFFF00000000000000000000)
)
lastBlockNumber := shr(
120,
and(extraData, 0x000000000000000000000000FFFFFFFFFF000000000000000000000000000000)
)
}
return (totalElements, nextQueueIndex, lastTimestamp, lastBlockNumber);
}
function _makeBatchExtraData(
uint40 _totalElements,
uint40 _nextQueueIdx,
uint40 _timestamp,
uint40 _blockNumber
) internal pure returns (bytes27) {
bytes27 extraData;
assembly {
extraData := _totalElements
extraData := or(extraData, shl(40, _nextQueueIdx))
extraData := or(extraData, shl(80, _timestamp))
extraData := or(extraData, shl(120, _blockNumber))
extraData := shl(40, extraData)
}
return extraData;
}
function _appendBatch(
bytes32 _transactionRoot,
uint256 _batchSize,
uint256 _numQueuedTransactions,
uint40 _timestamp,
uint40 _blockNumber
) internal {
IChainStorageContainer batchesRef = batches();
(uint40 totalElements, uint40 nextQueueIndex, , ) = _getBatchExtraData();
Lib_BVMCodec.ChainBatchHeader memory header = Lib_BVMCodec.ChainBatchHeader({
batchIndex: batchesRef.length(),
batchRoot: _transactionRoot,
batchSize: _batchSize,
prevTotalElements: totalElements,
signature: hex"",
extraData: hex""
});
emit TransactionBatchAppended(
header.batchIndex,
header.batchRoot,
header.batchSize,
header.prevTotalElements,
header.signature,
header.extraData
);
bytes32 batchHeaderHash = Lib_BVMCodec.hashBatchHeader(header);
bytes27 latestBatchContext = _makeBatchExtraData(
totalElements + uint40(header.batchSize),
nextQueueIndex + uint40(_numQueuedTransactions),
_timestamp,
_blockNumber
);
batchesRef.push(batchHeaderHash, latestBatchContext);
}
function resetIndex(uint256 _batchIndex, uint40 _totalElement, uint40 _batchSize,
uint40 _nextqIndex,uint40 _numQueuedTransactions ,
uint40 _timestamp, uint40 _blockNumber) external {
require(_batchIndex < batches().length(), "Invalid batch index.");
require(msg.sender == libAddressManager.owner(), "Only callable by the address manager owner.");
bytes27 latestBatchContext = _makeBatchExtraData(
_totalElement + _batchSize, _nextqIndex + _numQueuedTransactions,
_timestamp, _blockNumber
);
batches().deleteElementsAfterInclusive(_batchIndex,latestBatchContext);
_nextQueueIndex = _nextqIndex;
emit CTCBatchReset(_batchIndex,_nextqIndex,_totalElement,_batchSize,_numQueuedTransactions,_timestamp,_blockNumber);
}
}
文件 3 的 13: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;
}
}
文件 4 的 13:ICanonicalTransactionChain.sol
pragma solidity >0.5.0 <0.9.0;
import { Lib_BVMCodec } from "../../libraries/codec/Lib_BVMCodec.sol";
import { IChainStorageContainer } from "./IChainStorageContainer.sol";
interface ICanonicalTransactionChain {
event L2GasParamsUpdated(
uint256 l2GasDiscountDivisor,
uint256 enqueueGasCost,
uint256 enqueueL2GasPrepaid
);
event TransactionEnqueued(
address indexed _l1TxOrigin,
address indexed _target,
uint256 _gasLimit,
bytes _data,
uint256 indexed _queueIndex,
uint256 _timestamp
);
event QueueBatchAppended(
uint256 _startingQueueIndex,
uint256 _numQueueElements,
uint256 _totalElements
);
event SequencerBatchAppended(
uint256 _startingQueueIndex,
uint256 _numQueueElements,
uint256 _totalElements
);
event TransactionBatchAppended(
uint256 indexed _batchIndex,
bytes32 _batchRoot,
uint256 _batchSize,
uint256 _prevTotalElements,
bytes _signature,
bytes _extraData
);
event CTCBatchReset(
uint256 indexed _batchIndex,
uint40 _nextqIndex,
uint40 _totalElement,
uint40 _batchSize,
uint40 _numQueuedTransactions ,
uint40 _timestamp,
uint40 _blockNumber
);
struct BatchContext {
uint256 numSequencedTransactions;
uint256 numSubsequentQueueTransactions;
uint256 timestamp;
uint256 blockNumber;
}
function setGasParams(uint256 _l2GasDiscountDivisor, uint256 _enqueueGasCost) external;
function batches() external view returns (IChainStorageContainer);
function getTotalElements() external view returns (uint256 _totalElements);
function getTotalBatches() external view returns (uint256 _totalBatches);
function getNextQueueIndex() external view returns (uint40);
function getQueueElement(uint256 _index)
external
view
returns (Lib_BVMCodec.QueueElement memory _element);
function getLastTimestamp() external view returns (uint40);
function getLastBlockNumber() external view returns (uint40);
function getNumPendingQueueElements() external view returns (uint40);
function getQueueLength() external view returns (uint40);
function enqueue(
address _target,
uint256 _gasLimit,
bytes memory _data
) external;
function appendSequencerBatch(
) external;
function resetIndex(uint256 _batchIndex, uint40 _totalElement, uint40 _batchSize,
uint40 _nextqIndex,uint40 _numQueuedTransactions ,
uint40 _timestamp, uint40 _blockNumber) external;
}
文件 5 的 13:IChainStorageContainer.sol
pragma solidity >0.5.0 <0.9.0;
interface IChainStorageContainer {
function setGlobalMetadata(bytes27 _globalMetadata) external;
function getGlobalMetadata() external view returns (bytes27);
function length() external view returns (uint256);
function push(bytes32 _object) external;
function push(bytes32 _object, bytes27 _globalMetadata) external;
function get(uint256 _index) external view returns (bytes32);
function deleteElementsAfterInclusive(uint256 _index) external;
function deleteElementsAfterInclusive(uint256 _index, bytes27 _globalMetadata) external;
}
文件 6 的 13:Lib_AddressManager.sol
pragma solidity ^0.8.9;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
contract Lib_AddressManager is Ownable {
event AddressSet(string indexed _name, address _newAddress, address _oldAddress);
mapping(bytes32 => address) private addresses;
function setAddress(string memory _name, address _address) external onlyOwner {
bytes32 nameHash = _getNameHash(_name);
address oldAddress = addresses[nameHash];
addresses[nameHash] = _address;
emit AddressSet(_name, _address, oldAddress);
}
function getAddress(string memory _name) external view returns (address) {
return addresses[_getNameHash(_name)];
}
function _getNameHash(string memory _name) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(_name));
}
}
文件 7 的 13:Lib_AddressResolver.sol
pragma solidity ^0.8.9;
import { Lib_AddressManager } from "./Lib_AddressManager.sol";
abstract contract Lib_AddressResolver {
Lib_AddressManager public libAddressManager;
constructor(address _libAddressManager) {
libAddressManager = Lib_AddressManager(_libAddressManager);
}
function resolve(string memory _name) public view returns (address) {
return libAddressManager.getAddress(_name);
}
}
文件 8 的 13:Lib_BVMCodec.sol
pragma solidity ^0.8.9;
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol";
import { Lib_Bytes32Utils } from "../utils/Lib_Bytes32Utils.sol";
library Lib_BVMCodec {
enum QueueOrigin {
SEQUENCER_QUEUE,
L1TOL2_QUEUE
}
struct EVMAccount {
uint256 nonce;
uint256 balance;
bytes32 storageRoot;
bytes32 codeHash;
}
struct ChainBatchHeader {
uint256 batchIndex;
bytes32 batchRoot;
uint256 batchSize;
uint256 prevTotalElements;
bytes signature;
bytes extraData;
}
struct ChainInclusionProof {
uint256 index;
bytes32[] siblings;
}
struct Transaction {
uint256 timestamp;
uint256 blockNumber;
QueueOrigin l1QueueOrigin;
address l1TxOrigin;
address entrypoint;
uint256 gasLimit;
bytes data;
}
struct TransactionChainElement {
bool isSequenced;
uint256 queueIndex;
uint256 timestamp;
uint256 blockNumber;
bytes txData;
}
struct QueueElement {
bytes32 transactionHash;
uint40 timestamp;
uint40 blockNumber;
}
function encodeTransaction(Transaction memory _transaction)
internal
pure
returns (bytes memory)
{
return
abi.encodePacked(
_transaction.timestamp,
_transaction.blockNumber,
_transaction.l1QueueOrigin,
_transaction.l1TxOrigin,
_transaction.entrypoint,
_transaction.gasLimit,
_transaction.data
);
}
function hashTransaction(Transaction memory _transaction) internal pure returns (bytes32) {
return keccak256(encodeTransaction(_transaction));
}
function decodeEVMAccount(bytes memory _encoded) internal pure returns (EVMAccount memory) {
Lib_RLPReader.RLPItem[] memory accountState = Lib_RLPReader.readList(_encoded);
return
EVMAccount({
nonce: Lib_RLPReader.readUint256(accountState[0]),
balance: Lib_RLPReader.readUint256(accountState[1]),
storageRoot: Lib_RLPReader.readBytes32(accountState[2]),
codeHash: Lib_RLPReader.readBytes32(accountState[3])
});
}
function hashBatchHeader(Lib_BVMCodec.ChainBatchHeader memory _batchHeader)
internal
pure
returns (bytes32)
{
return
keccak256(
abi.encode(
_batchHeader.batchRoot,
_batchHeader.batchSize,
_batchHeader.prevTotalElements,
_batchHeader.signature,
_batchHeader.extraData
)
);
}
}
文件 9 的 13:Lib_Bytes32Utils.sol
pragma solidity ^0.8.9;
library Lib_Bytes32Utils {
function toBool(bytes32 _in) internal pure returns (bool) {
return _in != 0;
}
function fromBool(bool _in) internal pure returns (bytes32) {
return bytes32(uint256(_in ? 1 : 0));
}
function toAddress(bytes32 _in) internal pure returns (address) {
return address(uint160(uint256(_in)));
}
function fromAddress(address _in) internal pure returns (bytes32) {
return bytes32(uint256(uint160(_in)));
}
}
文件 10 的 13:Lib_BytesUtils.sol
pragma solidity ^0.8.9;
library Lib_BytesUtils {
function slice(
bytes memory _bytes,
uint256 _start,
uint256 _length
) internal pure returns (bytes memory) {
require(_length + 31 >= _length, "slice_overflow");
require(_start + _length >= _start, "slice_overflow");
require(_bytes.length >= _start + _length, "slice_outOfBounds");
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
tempBytes := mload(0x40)
let lengthmod := and(_length, 31)
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
mstore(0x40, and(add(mc, 31), not(31)))
}
default {
tempBytes := mload(0x40)
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) {
if (_start >= _bytes.length) {
return bytes("");
}
return slice(_bytes, _start, _bytes.length - _start);
}
function toBytes32(bytes memory _bytes) internal pure returns (bytes32) {
if (_bytes.length < 32) {
bytes32 ret;
assembly {
ret := mload(add(_bytes, 32))
}
return ret;
}
return abi.decode(_bytes, (bytes32));
}
function toUint256(bytes memory _bytes) internal pure returns (uint256) {
return uint256(toBytes32(_bytes));
}
function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
bytes memory nibbles = new bytes(_bytes.length * 2);
for (uint256 i = 0; i < _bytes.length; i++) {
nibbles[i * 2] = _bytes[i] >> 4;
nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16);
}
return nibbles;
}
function fromNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
bytes memory ret = new bytes(_bytes.length / 2);
for (uint256 i = 0; i < ret.length; i++) {
ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]);
}
return ret;
}
function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) {
return keccak256(_bytes) == keccak256(_other);
}
}
文件 11 的 13:Lib_RLPReader.sol
pragma solidity ^0.8.9;
library Lib_RLPReader {
uint256 internal constant MAX_LIST_LENGTH = 32;
enum RLPItemType {
DATA_ITEM,
LIST_ITEM
}
struct RLPItem {
uint256 length;
uint256 ptr;
}
function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory) {
uint256 ptr;
assembly {
ptr := add(_in, 32)
}
return RLPItem({ length: _in.length, ptr: ptr });
}
function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory) {
(uint256 listOffset, , RLPItemType itemType) = _decodeLength(_in);
require(itemType == RLPItemType.LIST_ITEM, "Invalid RLP list value.");
RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH);
uint256 itemCount = 0;
uint256 offset = listOffset;
while (offset < _in.length) {
require(itemCount < MAX_LIST_LENGTH, "Provided RLP list exceeds max list length.");
(uint256 itemOffset, uint256 itemLength, ) = _decodeLength(
RLPItem({ length: _in.length - offset, ptr: _in.ptr + offset })
);
out[itemCount] = RLPItem({ length: itemLength + itemOffset, ptr: _in.ptr + offset });
itemCount += 1;
offset += itemOffset + itemLength;
}
assembly {
mstore(out, itemCount)
}
return out;
}
function readList(bytes memory _in) internal pure returns (RLPItem[] memory) {
return readList(toRLPItem(_in));
}
function readBytes(RLPItem memory _in) internal pure returns (bytes memory) {
(uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in);
require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes value.");
return _copy(_in.ptr, itemOffset, itemLength);
}
function readBytes(bytes memory _in) internal pure returns (bytes memory) {
return readBytes(toRLPItem(_in));
}
function readString(RLPItem memory _in) internal pure returns (string memory) {
return string(readBytes(_in));
}
function readString(bytes memory _in) internal pure returns (string memory) {
return readString(toRLPItem(_in));
}
function readBytes32(RLPItem memory _in) internal pure returns (bytes32) {
require(_in.length <= 33, "Invalid RLP bytes32 value.");
(uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in);
require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes32 value.");
uint256 ptr = _in.ptr + itemOffset;
bytes32 out;
assembly {
out := mload(ptr)
if lt(itemLength, 32) {
out := div(out, exp(256, sub(32, itemLength)))
}
}
return out;
}
function readBytes32(bytes memory _in) internal pure returns (bytes32) {
return readBytes32(toRLPItem(_in));
}
function readUint256(RLPItem memory _in) internal pure returns (uint256) {
return uint256(readBytes32(_in));
}
function readUint256(bytes memory _in) internal pure returns (uint256) {
return readUint256(toRLPItem(_in));
}
function readBool(RLPItem memory _in) internal pure returns (bool) {
require(_in.length == 1, "Invalid RLP boolean value.");
uint256 ptr = _in.ptr;
uint256 out;
assembly {
out := byte(0, mload(ptr))
}
require(out == 0 || out == 1, "Lib_RLPReader: Invalid RLP boolean value, must be 0 or 1");
return out != 0;
}
function readBool(bytes memory _in) internal pure returns (bool) {
return readBool(toRLPItem(_in));
}
function readAddress(RLPItem memory _in) internal pure returns (address) {
if (_in.length == 1) {
return address(0);
}
require(_in.length == 21, "Invalid RLP address value.");
return address(uint160(readUint256(_in)));
}
function readAddress(bytes memory _in) internal pure returns (address) {
return readAddress(toRLPItem(_in));
}
function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory) {
return _copy(_in);
}
function _decodeLength(RLPItem memory _in)
private
pure
returns (
uint256,
uint256,
RLPItemType
)
{
require(_in.length > 0, "RLP item cannot be null.");
uint256 ptr = _in.ptr;
uint256 prefix;
assembly {
prefix := byte(0, mload(ptr))
}
if (prefix <= 0x7f) {
return (0, 1, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xb7) {
uint256 strLen = prefix - 0x80;
require(_in.length > strLen, "Invalid RLP short string.");
return (1, strLen, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xbf) {
uint256 lenOfStrLen = prefix - 0xb7;
require(_in.length > lenOfStrLen, "Invalid RLP long string length.");
uint256 strLen;
assembly {
strLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfStrLen)))
}
require(_in.length > lenOfStrLen + strLen, "Invalid RLP long string.");
return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xf7) {
uint256 listLen = prefix - 0xc0;
require(_in.length > listLen, "Invalid RLP short list.");
return (1, listLen, RLPItemType.LIST_ITEM);
} else {
uint256 lenOfListLen = prefix - 0xf7;
require(_in.length > lenOfListLen, "Invalid RLP long list length.");
uint256 listLen;
assembly {
listLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfListLen)))
}
require(_in.length > lenOfListLen + listLen, "Invalid RLP long list.");
return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM);
}
}
function _copy(
uint256 _src,
uint256 _offset,
uint256 _length
) private pure returns (bytes memory) {
bytes memory out = new bytes(_length);
if (out.length == 0) {
return out;
}
uint256 src = _src + _offset;
uint256 dest;
assembly {
dest := add(out, 32)
}
for (uint256 i = 0; i < _length / 32; i++) {
assembly {
mstore(dest, mload(src))
}
src += 32;
dest += 32;
}
uint256 mask;
unchecked {
mask = 256**(32 - (_length % 32)) - 1;
}
assembly {
mstore(dest, or(and(mload(src), not(mask)), and(mload(dest), mask)))
}
return out;
}
function _copy(RLPItem memory _in) private pure returns (bytes memory) {
return _copy(_in.ptr, 0, _in.length);
}
}
文件 12 的 13:Lib_RLPWriter.sol
pragma solidity ^0.8.9;
library Lib_RLPWriter {
function writeBytes(bytes memory _in) internal pure returns (bytes memory) {
bytes memory encoded;
if (_in.length == 1 && uint8(_in[0]) < 128) {
encoded = _in;
} else {
encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);
}
return encoded;
}
function writeList(bytes[] memory _in) internal pure returns (bytes memory) {
bytes memory list = _flatten(_in);
return abi.encodePacked(_writeLength(list.length, 192), list);
}
function writeString(string memory _in) internal pure returns (bytes memory) {
return writeBytes(bytes(_in));
}
function writeAddress(address _in) internal pure returns (bytes memory) {
return writeBytes(abi.encodePacked(_in));
}
function writeUint(uint256 _in) internal pure returns (bytes memory) {
return writeBytes(_toBinary(_in));
}
function writeBool(bool _in) internal pure returns (bytes memory) {
bytes memory encoded = new bytes(1);
encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));
return encoded;
}
function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {
bytes memory encoded;
if (_len < 56) {
encoded = new bytes(1);
encoded[0] = bytes1(uint8(_len) + uint8(_offset));
} else {
uint256 lenLen;
uint256 i = 1;
while (_len / i != 0) {
lenLen++;
i *= 256;
}
encoded = new bytes(lenLen + 1);
encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);
for (i = 1; i <= lenLen; i++) {
encoded[i] = bytes1(uint8((_len / (256**(lenLen - i))) % 256));
}
}
return encoded;
}
function _toBinary(uint256 _x) private pure returns (bytes memory) {
bytes memory b = abi.encodePacked(_x);
uint256 i = 0;
for (; i < 32; i++) {
if (b[i] != 0) {
break;
}
}
bytes memory res = new bytes(32 - i);
for (uint256 j = 0; j < res.length; j++) {
res[j] = b[i++];
}
return res;
}
function _memcpy(
uint256 _dest,
uint256 _src,
uint256 _len
) private pure {
uint256 dest = _dest;
uint256 src = _src;
uint256 len = _len;
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
uint256 mask;
unchecked {
mask = 256**(32 - len) - 1;
}
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
function _flatten(bytes[] memory _list) private pure returns (bytes memory) {
if (_list.length == 0) {
return new bytes(0);
}
uint256 len;
uint256 i = 0;
for (; i < _list.length; i++) {
len += _list[i].length;
}
bytes memory flattened = new bytes(len);
uint256 flattenedPtr;
assembly {
flattenedPtr := add(flattened, 0x20)
}
for (i = 0; i < _list.length; i++) {
bytes memory item = _list[i];
uint256 listPtr;
assembly {
listPtr := add(item, 0x20)
}
_memcpy(flattenedPtr, listPtr, item.length);
flattenedPtr += _list[i].length;
}
return flattened;
}
}
文件 13 的 13: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() {
_setOwner(_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 {
_setOwner(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
{
"compilationTarget": {
"contracts/L1/rollup/CanonicalTransactionChain.sol": "CanonicalTransactionChain"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_libAddressManager","type":"address"},{"internalType":"uint256","name":"_maxTransactionGasLimit","type":"uint256"},{"internalType":"uint256","name":"_l2GasDiscountDivisor","type":"uint256"},{"internalType":"uint256","name":"_enqueueGasCost","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_batchIndex","type":"uint256"},{"indexed":false,"internalType":"uint40","name":"_nextqIndex","type":"uint40"},{"indexed":false,"internalType":"uint40","name":"_totalElement","type":"uint40"},{"indexed":false,"internalType":"uint40","name":"_batchSize","type":"uint40"},{"indexed":false,"internalType":"uint40","name":"_numQueuedTransactions","type":"uint40"},{"indexed":false,"internalType":"uint40","name":"_timestamp","type":"uint40"},{"indexed":false,"internalType":"uint40","name":"_blockNumber","type":"uint40"}],"name":"CTCBatchReset","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"l2GasDiscountDivisor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"enqueueGasCost","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"enqueueL2GasPrepaid","type":"uint256"}],"name":"L2GasParamsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_startingQueueIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_numQueueElements","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_totalElements","type":"uint256"}],"name":"QueueBatchAppended","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_startingQueueIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_numQueueElements","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_totalElements","type":"uint256"}],"name":"SequencerBatchAppended","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_batchIndex","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_batchRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"_batchSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_prevTotalElements","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_signature","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"TransactionBatchAppended","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_l1TxOrigin","type":"address"},{"indexed":true,"internalType":"address","name":"_target","type":"address"},{"indexed":false,"internalType":"uint256","name":"_gasLimit","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"},{"indexed":true,"internalType":"uint256","name":"_queueIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"TransactionEnqueued","type":"event"},{"inputs":[],"name":"MAX_ROLLUP_TX_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_ROLLUP_TX_GAS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"appendSequencerBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"batches","outputs":[{"internalType":"contract IChainStorageContainer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"enqueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enqueueGasCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enqueueL2GasPrepaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastBlockNumber","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastTimestamp","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNextQueueIndex","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumPendingQueueElements","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getQueueElement","outputs":[{"components":[{"internalType":"bytes32","name":"transactionHash","type":"bytes32"},{"internalType":"uint40","name":"timestamp","type":"uint40"},{"internalType":"uint40","name":"blockNumber","type":"uint40"}],"internalType":"struct Lib_BVMCodec.QueueElement","name":"_element","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getQueueLength","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalBatches","outputs":[{"internalType":"uint256","name":"_totalBatches","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalElements","outputs":[{"internalType":"uint256","name":"_totalElements","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l2GasDiscountDivisor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"libAddressManager","outputs":[{"internalType":"contract Lib_AddressManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTransactionGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_batchIndex","type":"uint256"},{"internalType":"uint40","name":"_totalElement","type":"uint40"},{"internalType":"uint40","name":"_batchSize","type":"uint40"},{"internalType":"uint40","name":"_nextqIndex","type":"uint40"},{"internalType":"uint40","name":"_numQueuedTransactions","type":"uint40"},{"internalType":"uint40","name":"_timestamp","type":"uint40"},{"internalType":"uint40","name":"_blockNumber","type":"uint40"}],"name":"resetIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"resolve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2GasDiscountDivisor","type":"uint256"},{"internalType":"uint256","name":"_enqueueGasCost","type":"uint256"}],"name":"setGasParams","outputs":[],"stateMutability":"nonpayable","type":"function"}]