Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
306 changes: 73 additions & 233 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 0 additions & 4 deletions src/config/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,6 @@ export const getSidebar = () => {
title: t("sidebar.technology.rollupNode"),
url: "technology/sequencer/rollup-node",
},
{
title: t("sidebar.technology.zkTrie"),
url: "technology/sequencer/zktrie",
},
],
},
// {
Expand Down
54 changes: 3 additions & 51 deletions src/content/docs/en/developers/ethereum-and-scroll-differences.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ For open-source contributors and infrastructure builders, please contact our tea

| Opcode | Solidity equivalent | Scroll Behavior |
| --------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------- |
| `BLOCKHASH` | `block.blockhash` | Returns `keccak(chain_id \|\| block_number)` for the last 256 blocks. |
| `COINBASE` | `block.coinbase` | Returns the pre-deployed fee vault contract address. See [Scroll Contracts](/developers/scroll-contracts). |
| `DIFFICULTY` / `PREVRANDAO` | `block.difficulty` | Returns 0. |
| `SELFDESTRUCT` | `selfdestruct` | Disabled. If the opcode is encountered, the transaction will be reverted.[^willadpot] |
Expand All @@ -38,60 +37,13 @@ We support the `cancun` EVM target and the latest Solidity version `0.8.26`.

## EVM Precompiles

The `RIPEMD-160` (address `0x3`) `blake2f` (address `0x9`), and `point evaluation` (address `0x0a`) precompiles are currently not supported. Calls to unsupported precompiled contracts will revert. We plan to enable these precompiles in future hard forks.
The `RIPEMD-160` (address `0x3`), `blake2f` (address `0x9`), and `point evaluation` (address `0x0a`) precompiles are currently not supported. Calls to unsupported precompiled contracts will revert.

The `modexp` precompile is supported but only supports inputs of size less than or equal to 32 bytes (i.e. `u256`).

The `ecPairing` precompile is supported, but the number of points(sets, pairs) is limited to 4, instead of 6.

The other EVM precompiles are all supported: `ecRecover`, `identity`, `ecAdd`, `ecMul`.

### Precompile Limits

Because of a bounded size of the zkEVM circuits, there is an upper limit on the number of calls that can be made for some precompiles. These transactions will not revert, but simply be skipped by the sequencer if they cannot fit into the space of the circuit. Read more about the [Circuit Capacity Checker](/en/technology/sequencer/execution-node#circuit-capacity-checker).

| Precompile / Opcode | Limit |
| ------------------- | ----- |
| `keccak256` | 3157 |
| `ecRecover` | 119 |
| `modexp` | 23 |
| `ecAdd` | 50 |
| `ecMul` | 50 |
| `ecPairing` | 2 |
{/* TODO: Add SHA256 after upgrade */}


## State Account

### **Additional Fields**

We added two fields in the current `StateAccount` object: `PoseidonCodehash` and `CodeSize`.

```go
type StateAccount struct {
Nonce uint64
Balance *big.Int
Root common.Hash // merkle root of the storage trie
KeccakCodeHash []byte // still the Keccak codehash
// added fields
PoseidonCodeHash []byte // the Poseidon codehash
CodeSize uint64
}
```

### **CodeHash**

Related to this, we maintain two types of codehash for each contract bytecode: Keccak hash and Poseidon hash.

`KeccakCodeHash` is kept to maintain compatibility for `EXTCODEHASH`. `PoseidonCodeHash` is used for verifying the correctness of bytecodes loaded in the zkEVM, where Poseidon hashing is far more efficient.

### CodeSize

When verifying `EXTCODESIZE`, it is expensive to load the whole contract data into the zkEVM. Instead, we store the contract size in storage during contract creation. This way, we do not need to load the code — a storage proof is sufficient to verify this opcode.
All other EVM precompiles are fully supported and behave the same as Ethereum.

## Block Time

To improve the throughput of the Scroll chain, we introduced a dynamic block time in our [Curie upgrade](/technology/overview/scroll-upgrades#curie-upgrade). During the congestion period, a block will be sealed once the transactions in the block reach the circuit limit instead of waiting for the 3-second interval. During normal hours, blocks will still be sealed at 3-second interval to ensure a consistent user experience.
Scroll uses a dynamic block time to optimize throughput. During congestion periods, blocks are sealed as soon as they are full instead of waiting for the 3-second interval. During normal hours, blocks are sealed at 3-second intervals to ensure a consistent user experience.

## Transaction Ordering

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ When bridging ERC20 tokens, you don’t have to worry about selecting the right
All Gateway contracts will form the message and send it to the `L1ScrollMessenger` which can send arbitrary messages to L2. The `L1ScrollMessenger` passes the message to the `L1MessageQueue`. Any user can send messages directly to the Messenger to execute arbitrary data on L2. This means they can execute any function on L2 from a transaction made on L1 via the bridge. Although an application could directly pass messages to existing token contracts, the Gateway abstracts the specifics and simplifies making transfers and calls.

<Aside type="tip" title="">
In future upgrades, users will be able to bypass the `L1ScrollMessenger` and send messages directly to the `L1MessageQueue`. If a message is sent
via the `L1MessageQueue`, the transaction's sender will be the address of the user sending the transaction, not the
address of the `L1ScrollMessenger`.
Users can bypass the `L1ScrollMessenger` and send messages directly to the `L1MessageQueue` using the `EnforcedTxGateway` contract. When a message is sent this way, the transaction's sender on L2 will be the address of the user, not the address of the `L1ScrollMessenger`.
</Aside>

When a new block gets created on L1, the Watcher will detect the message on the `L1MessageQueue` and will pass it to the Relayer service, which will submit the transaction to the L2 via the l2geth node. Finally, the l2geth node will pass the transaction to the `L2ScrollMessenger` contract for execution on L2.
Expand Down
76 changes: 57 additions & 19 deletions src/content/docs/en/developers/transaction-fees-on-scroll.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,29 @@ when the sequencer commits the data to L1.

As mentioned, the `L1GasPriceOracle` is used to estimate the L1 gas fee given raw transaction data. This is a **push oracle**, updated by a relayer run by Scroll.

The data fee is based on multiple factors:
<Aside type="note" title="Fee Calculation Changes">
The L1 data fee calculation has evolved through several network upgrades:
- **Pre-Curie**: Based on calldata gas costs
- **Curie**: Introduced blob-based data availability with `commitScalar` and `blobScalar`
- **Feynman**: Added compression penalty factor
- **Galileo**: Updated penalty calculation formula
</Aside>

#### Post-Curie Fee Calculation (Current)

- The bytes which are `zeros` and `nonzeros` of an RLP-encoded transaction with Signature
- `l1BaseFee` - Current base fee on the L1
- `overhead` - Additional gas overhead of a data commitment transaction
- `scalingFactor` - A scaling factor used to account for price spikes
- `PRECISION` - A constant used to scale the final fee
Since the [Curie upgrade](/technology/overview/scroll-upgrades/curie-upgrade), transaction data is stored in blobs, and the fee is calculated as:

The following steps are taken to calculate the L1 data fee:
```javascript
l1Fee = (commitScalar * l1BaseFee + blobScalar * txDataLength * l1BlobBaseFee) / PRECISION
```

1. Read three fields `l1BaseFee`, `overhead`, `scalar` from the `L1GasPriceOracle` contract. The slots for these fields in the contract are:
Where `PRECISION = 1e9`.

| Field | Slot |
| --------- | ---- |
| l1BaseFee | 1 |
| overhead | 2 |
| scalar | 3 |
#### Pre-Curie Fee Calculation (Legacy)

Before Curie, the fee was based on calldata gas costs:

1. Read three fields `l1BaseFee`, `overhead`, `scalar` from the `L1GasPriceOracle` contract.

2. Count the number of zero bytes and non-zero bytes from the transaction.
3. Calculate the L1 data fee, given `TX_DATA_ZERO_GAS = 4` and `TX_DATA_NON_ZERO_GAS = 16`[^eip-2028] and `PRECISION = 1e9`:
Expand All @@ -119,31 +125,63 @@ The following steps are taken to calculate the L1 data fee:
function overhead() external view returns (uint256);
```

Returns the current L1 fee overhead
Returns the current L1 fee overhead (used in pre-Curie fee calculation).

#### scalar

```solidity
function scalar() external view returns (uint256);
```

Returns the current l1 fee scalar
Returns the current L1 fee scalar (used in pre-Curie fee calculation).

#### l1BaseFee

```solidity
function l1BaseFee() external view returns (uint256);
```

Returns the latest known l1 base fee
Returns the latest known L1 base fee.

#### l1BlobBaseFee

```solidity
function l1BlobBaseFee() external view returns (uint256);
```

Returns the latest known L1 blob base fee (introduced in Curie upgrade).

#### commitScalar

```solidity
function commitScalar() external view returns (uint256);
```

Returns the current L1 commit fee scalar (introduced in Curie upgrade).

#### blobScalar

```solidity
function blobScalar() external view returns (uint256);
```

Returns the current L1 blob fee scalar (introduced in Curie upgrade).

#### penaltyFactor

```solidity
function penaltyFactor() external view returns (uint256);
```

Returns the current compression penalty factor (introduced in Feynman upgrade).

#### getL1Fee

```solidity
function getL1Fee(bytes memory data) external view returns (uint256);
```

Computes the L1 portion of the fee based on the size of the RLP encoded input transaction, the current L1 base fee, and the various dynamic parameters.
Computes the L1 portion of the fee based on the size of the RLP encoded input transaction, the current L1 base fee, and the various dynamic parameters. The calculation method depends on the current network fork (pre-Curie, Curie, Feynman, or Galileo).

**Returns:** L1 fee that should be paid for the transaction

Expand All @@ -157,9 +195,9 @@ Computes the L1 portion of the fee based on the size of the RLP encoded input tr
function getL1GasUsed(bytes memory data) external view returns (uint256);
```

Computes the amount of L1 gas used for a transaction. Adds the overhead which represents the per-transaction gas overhead of posting the transaction and state roots to L1. Adds 74 bytes of padding to account for the fact that the input does not have a signature.
Computes the amount of L1 gas used for a transaction. After the Curie upgrade, this returns 0 since all transaction data is stored in blobs.

**Returns:** Amount of L1 gas used to publish the transaction.
**Returns:** Amount of L1 gas used to publish the transaction (0 post-Curie).

| Parameter | Description |
| --------- | ----------------------------------------------------------- |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ Scroll has an arbitrary message passing bridge that enables token transfers and

There are two primary approaches to sending a message from L1 to L2: sending arbitrary messages via `L1ScrollMessenger` and sending enforced transactions via `EnforcedTxGateway`. Both approaches allow users to initiate a L2 transaction on L1 and call arbitrary contracts on L2. For arbitrary messages, the sender of the L2 transactions is the aliased `L1ScrollMessenger` address. For enforced transactions, the L2 sender is an externally-owned account (EOA). In addition, we provide several standard token gateways to make it easier for users to deposit ETH and other standard tokens including ERC-20, ERC-677, ERC-721, and ERC-1155. In essence, these gateways encode token deposits into a message and send it to their counterparts on L2 through the `L1ScrollMessenger` contract. You can find more details about the L1 token gateways in the [Deposit Gateways](/technology/bridge/deposit-gateways).

<Aside type="danger" title="">
Enforced Transactions are not yet enabled on Scroll. In future upgrades, users will be able to use this functionality to bypass the `L1ScrollMessenger` and send messages directly to the `L1MessageQueue`.
<Aside type="tip" title="">
Enforced Transactions allow users to bypass the `L1ScrollMessenger` and send messages directly to the `L1MessageQueue`. This provides a censorship-resistance mechanism, ensuring users can always force transaction inclusion on L2.
</Aside>

As depicted in Figure 1, both arbitrary messages and enforced transactions are appended to the message queue stored in the `L1MessageQueue` contract. The `L1MessageQueue` contract provides two functions `appendCrossDomainMessage` and `appendEnforcedTransaction` for appending arbitrary messages and enforced transactions respectively.
Expand Down Expand Up @@ -117,8 +117,8 @@ The deposited ETH of `value` amount is locked in the `L1ScrollMessenger` contrac

### Sending Enforced Transactions

<Aside type="danger" title="">
Enforced Transactions are not yet enabled on Scroll. In future upgrades, users will be able to use this functionality to bypass the `L1ScrollMessenger` and send messages directly to the `L1MessageQueue`.
<Aside type="tip" title="">
Enforced Transactions allow users to bypass the `L1ScrollMessenger` and send messages directly to the `L1MessageQueue`. This provides a censorship-resistance mechanism, ensuring users can always force transaction inclusion on L2.
</Aside>

The `EnforcedTxGateway` contract provides two `sendTransaction` functions to send an enforced transaction. In the first function, the sender of the generated `L1MessageTx` transaction is the transaction sender. On the other hand, the second function uses the passed `sender` address as the sender of the `L1MessageTx` transaction. This allows a third party to send an enforced transaction on behalf of the user and pay the relay fee. Note that the second function requires providing a valid signature of the generated `L1MessageTx` transaction that matches the `sender` address. Both `sendTransaction` functions enforce the sender to be an EOA account.
Expand Down
10 changes: 3 additions & 7 deletions src/content/docs/en/technology/chain/accounts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,15 @@ whatsnext: { "Transactions": "/en/technology/chain/transactions/" }

Same as Ethereum, Scroll has two account types: Externally-owned account (EOA) and contract account that holds the smart contract and additional storage.

Scroll stores additional information of the contract bytecode in the account to facilitate the zkEVM circuit to prove the state transition more efficiently.

The account in Scroll contains the following fields:
The account structure in Scroll follows the standard Ethereum format:

- `nonce`: A counter that indicates the number of transactions sent by the sender.
- `balance`: The balance of `ETH` token in the account (unit in wei).
- `storageRoot`: The root hash of the storage trie. Since Scroll uses the [zkTrie](/technology/sequencer/zktrie) for the storage trie, the `storageRoot` stores the Poseidon hash digest in a 256-bit integer.
- `storageRoot`: The root hash of the storage trie.
- `codeHash`: The Keccak hash digest of the contract bytecode.
- `PoseidonCodeHash` (**new field**): The Poseidon hash digest of the contract bytecode in a 256-bit integer.
- `CodeSize` (**new field**): The size of the contract bytecode in bytes.

## State

The state of a blockchain is a collection of account data. The _state trie_ encodes account data and their corresponding addresses to a [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree) data structure. The root of tree, or the state of the blockchain, is a cryptographic digest of all the account data contained in the tree.

Ethereum uses a data structure called [Patricia Merkle Trie](https://ethereum.org/en/developers/docs/data-structures-and-encoding/patricia-merkle-trie/) for both the state trie and the storage trie that stores the key-value entries stored in a smart contract. In Scroll, we replace the Patricia Merkle Trie with a more zk-friendly data structure, called zkTrie, for both state trie and storage trie. At a high level, the zkTrie data structure is a sparse binary Merkle tree with the [Poseidon hash](https://eprint.iacr.org/2019/458.pdf), a zk-friendly hash function. The [zkTrie](/technology/sequencer/zktrie) document describes more details about this data structure.
Scroll uses Ethereum's [Merkle-Patricia Trie](https://ethereum.org/en/developers/docs/data-structures-and-encoding/patricia-merkle-trie/) (MPT) for both the state trie and the storage trie that stores the key-value entries in smart contracts. This ensures full compatibility with Ethereum's state proof format and tooling.
2 changes: 1 addition & 1 deletion src/content/docs/en/technology/chain/blocks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The block header in Scroll mirrors the structure of Ethereum's. However, certain
| `extraData` | Signature by the block's signer, followed by arbitrary additional data. |
| `mixHash` | Always 0. |
| `nonce` | Always 0. |
| `baseFee` | Currently empty in Scroll because we haven't enabled the EIP-1559. |
| `baseFee` | The base fee for this block. Since the [Curie upgrade](/technology/overview/scroll-upgrades/curie-upgrade), Scroll uses EIP-1559 with the base fee set by the sequencer. |

## Block Time

Expand Down
15 changes: 6 additions & 9 deletions src/content/docs/en/technology/chain/differences.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,19 @@ import Aside from "../../../../../components/Aside.astro"

| Opcode | Scroll Behavior |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `BLOCKHASH` | Returns `keccak(chain_id \|\| block_number)` for the last 256 blocks. |
| `COINBASE` | Returns the fee vault address (predeployed contract `0x5300000000000000000000000000000000000005`). |
| `DIFFICULTY` / `PREVRANDAO` | Always return 0. |
| `SELFDESTRUCT` | Disabled. If the opcode is encountered, the transaction will be reverted. |

## Precompiled Contracts

| Address | Name | Scroll behavior |
| ------- | ------------ | ----------------------------------------------------------------------------------------------- |
| `0x03` | `RIPEMD-160` | Currently not supported. |
| `0x05` | `modexp` | Restrict the input values `B, E, M` to unsigned integers less than $2^{256}$. |
| `0x08` | `ecPairing` | The inputs are still multiple of 6 32-byte values, but limit the number of tuples to at most 4. |
| `0x09` | `blake2f` | Currently not supported. |
| `0x0a` | `point evaluation` | Currently not supported. |
| Address | Name | Scroll behavior |
| ------- | ------------------ | ----------------- |
| `0x03` | `RIPEMD-160` | Not supported. |
| `0x09` | `blake2f` | Not supported. |
| `0x0a` | `point evaluation` | Not supported as a precompile. Blob verification is done in ZK circuits. |

The remaining precompiled contracts have the same behavior as Ethereum. However, their maximum usage within a block is constrained by a limit tied to the zkEVM circuit capacity.
The remaining precompiled contracts have the same behavior as Ethereum.

## EIPs

Expand Down
Loading