Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update section Differences with Ethereum #689

Merged
merged 8 commits into from
Oct 23, 2023
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
104 changes: 0 additions & 104 deletions arbitrum-docs/arbitrum-ethereum-differences.mdx

This file was deleted.

10 changes: 8 additions & 2 deletions arbitrum-docs/arbos/l1-to-l2-messaging.mdx
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
title: 'L1 to L2 messaging'
sidebar_label: 'L1 to L2 messaging'
description: This concept page provides information about how arbitrary messages are passed from L1 to L2
target_audience: developers who want to build on Arbitrum
content-type: concept
---

import { AddressAliasHelper } from '@site/src/components/AddressAliasHelper';
import {
MermaidWithHtml,
Expand All @@ -8,8 +16,6 @@ import {
NodeDescription,
} from '/src/components/MermaidWithHtml/MermaidWithHtml';

# L1 To L2 Messaging

## Retryable Tickets

Retryable tickets are Arbitrum's canonical method for creating L1 to L2 messages, i.e., L1 transactions that initiate a message to be executed on L2. A retryable can be submitted for a fixed cost (dependent only on its calldata size) paid at L1; its _submission_ on L1 is separable / asynchronous with its _execution_ on L2. Retryables provide atomicity between the cross chain operations; if the L1 transaction to request submission succeeds (i.e. does not revert) then the execution of the Retryable on L2 has a strong guarantee to ultimately succeed as well.
Expand Down
8 changes: 7 additions & 1 deletion arbitrum-docs/arbos/l2-to-l1-messaging.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# L2-to-L1-Messages and the Outbox
---
title: 'L2 to L1 messaging and the outbox'
sidebar_label: 'L2 to L1 messaging'
description: This concept page provides information about how arbitrary messages are passed from L2 to L1
target_audience: developers who want to build on Arbitrum
content-type: concept
---

Arbitrum's Outbox system allows for arbitrary L2 to L1 contract calls; i.e., messages initiated from L2 which eventually resolve in execution on L1. L2-to-L1 messages (aka "outgoing" messages) bear many things in common with Arbitrum's [L1-to-L2 messages](./l1-to-l2-messaging.mdx) (Retryables), "in reverse" though with a few differences.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
title: 'Block numbers and time'
sidebar_label: Block numbers and time
sidebar_position: 2
description: This concept page provides information about the differences between Arbitrum and Ethereum in terms of block numbers and timing, so developers can easily understand what to expect when deploying to Arbitrum
target_audience: developers who want to build on Arbitrum
content-type: concept
---

:::info Arbitrum chains and their parent chains

With the release of Arbitrum Orbit, Arbitrum chains can now be L2s that settle to Ethereum (or one of their testnets), or L3s that settle to one of the Arbitrum L2 chains. For simplicity, in this page we speak in terms of Arbitrum One (L2) and Ethereum (L1), but the same logic can be applied to any chain and its parent chain.

:::

As in Ethereum, Arbitrum clients submit transactions, and the system executes those transactions at some later time. In Arbitrum, clients submit transactions by posting messages to the Ethereum chain, either [through the sequencer](/sequencer.mdx#happycommon-case-sequencer-is-live-and-well-behaved) or via the chain's [delayed inbox](/sequencer.mdx#unhappyuncommon-case-sequencer-isnt-doing-its-job).

Once in the chain's core inbox contract, transactions are processed in order. Generally, some time will elapse between the time when a message is put into the inbox (and timestamped) and the time when the contract processes the message and carries out the transaction requested by the message.

In this page we describe what does this mechanism mean for the block numbers and the time assumptions of the transactions submitted to Arbitrum.

## Block numbers: Arbitrum vs. Ethereum

Arbitrum blocks are assigned their own L2 block numbers, distinct from Ethereum's block numbers.
DZGoldman marked this conversation as resolved.
Show resolved Hide resolved

A single Ethereum block could include multiple Arbitrum blocks within it; however, an Arbitrum block cannot span across multiple Ethereum blocks. Thus, any given Arbitrum transaction is associated with exactly one Ethereum block and one Arbitrum block.

### Ethereum block numbers within Arbitrum

Accessing block numbers within an Arbitrum smart contract (i.e., `block.number` in Solidity) will return a value _close to_ (but not necessarily exactly) the L1 block number at which the sequencer received the transaction.

```sol
// some Arbitrum contract:
block.number // => returns L1 block number ("ish")
```

As a general rule, any timing assumptions a contract makes about block numbers and timestamps should be considered generally reliable in the longer term (i.e., on the order of at least several hours) but unreliable in the shorter term (minutes). (It so happens these are generally the same assumptions one should operate under when using block numbers directly on Ethereum!)

### Arbitrum block numbers

Arbitrum blocks have their own block numbers, starting at 0 at the Arbitrum genesis block and updating sequentially.

ArbOS and the sequencer are responsible for delineating when one Arbitrum block ends and the next one begins. However, block creation depends entirely on chain usage, meaning that blocks are only produced when there are transactions to sequence. In active chains, one can expect to see Arbitrum blocks produced at a relatively steady rate. In more quiet chains, block production might be sporadic depending on the rate at which transactions are received.

A client that queries an Arbitrum node's RPC interface (for, e.g., transaction receipts) will receive the transaction's Arbitrum block number as the standard block number field. The L1 block number will also be included in the added `l1BlockNumber field`.

```ts
const txnReceipt = await arbitrumProvider.getTransactionReceipt('0x...');
/**
txnReceipt.blockNumber => Arbitrum block number
txnReceipt.l1BlockNumber => L1 block number ("ish")
*/
```

The Arbitrum block number can also be retrieved within an Arbitrum contract via [ArbSys](/for-devs/dev-tools-and-resources/precompiles.mdx#arbsys) precompile:

```sol
ArbSys(100).arbBlockNumber() // returns Arbitrum block number
```

### Example

| Wall Clock time | 12:00 am | 12:00:15 am | 12:00:30 am | 12:00:45 am | 12:01 am | 12:01:15 am |
| -------------------------------------- | -------- | ----------- | ----------- | ----------- | -------- | ----------- |
| L1 `block.number` | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 |
| L2 `block.number` \* | 1000 | 1000 | 1000 | 1000 | 1004 | 1004 |
| Arbitrum Block number (from RPCs) \*\* | 370000 | 370005 | 370006 | 370008 | 370012 | 370015 |

_\* **L2 `block.number`:** updated to sync with L1 `block.number` approximately every minute. Thus, over time, it will, like the L1 `block.number`, average to ~12 seconds per block._

_\*\* **Arbitrum block number from RPCs:** note that this can be updated multiple times per L1 block (this lets the sequencer give sub-L1-block-time transaction receipts.)_

### Case study: the Multicall contract

The Multicall contract offers a great case study for the differences between L1 and L2 block numbers.

The [canonical implementation](https://github.com/makerdao/multicall/) of Multicall returns the value of `block.number`. If attempting to use out-of-the-box, some applications might face unintended behaviour.

You can find a version of the adapted Multicall2 deployed on Arbitrum One at [0x7eCfBaa8742fDf5756DAC92fbc8b90a19b8815bF](https://arbiscan.io/address/0x7eCfBaa8742fDf5756DAC92fbc8b90a19b8815bF#code).

By default the `getBlockNumber`, `tryBlockAndAggregate`, and `aggregate` functions return the L2 block number. This allows you to use this value to compare your state against the tip of the chain.

The `getL1BlockNumber` function can be queried if applications need to surface the L1 block number.

## Block timestamps: Arbitrum vs. Ethereum

Block timestamps on Arbitrum are not linked to the timestamp of the L1 block. They are updated every L2 block based on the sequencer's clock. These timestamps must follow these two rules:

1. Must be always equal or greater than the previous L2 block timestamp
2. Must fall within the established boundaries (24 hours earlier than the current time or 1 hour in the future). More on this below.

Furthermore, for transactions that are force-included from L1 (bypassing the sequencer), the block timestamp will be equal to either the L1 timestamp when the transaction was put in the delayed inbox on L1 (not when it was force-included), or the L2 timestamp of the previous L2 block, whichever of the two timestamps is greater.

### Timestamp boundaries of the sequencer

As mentioned, block timestamps are usually set based on the sequencer's clock. Because there's a possibility that the sequencer fails to post batches on the parent chain (for example, Ethereum) for a period of time, it should have the ability to slightly adjust the timestamp of the block to account for those delays and prevent any potential reorganisations of the chain. To limit the degree to which the sequencer can adjust timestamps, some boundaries are set, currently to 24 hours earlier than the current time, and 1 hour in the future.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: 'Differences between Arbitrum and Ethereum: Overview'
sidebar_label: Overview
sidebar_position: 1
description: This concept page provides information about the differences between Arbitrum and Ethereum so developers can easily understand what to expect when deploying to Arbitrum
author: jose-franco
sme: jose-franco
target_audience: developers who want to build on Arbitrum
content-type: concept
---

Arbitrum is designed to be as compatible and consistent with Ethereum as possible, from its high-level RPCs to its low-level bytecode and everything in between. <a data-quicklook-from="dapp">Decentralized app (dApp)</a> developers with experience building on Ethereum will likely find that little-to-no new specific knowledge is required to build on Arbitrum.

This section describes the differences, perks, and gotchas that devs are advised to be aware of when working with Arbitrum. This first page serves as an overview of where you might these differences, with links to the relevant pages when needed.

## Block numbers and time

Time in L2s is tricky. The timing assumptions one is used to making about Ethereum blocks don't exactly carry over into the timing of Arbitrum blocks. See [Block numbers and time](/for-devs/concepts/differences-between-arbitrum-ethereum/block-numbers-and-time.mdx) for details about how block numbers and time are handled in Arbitrum.

## RPC methods

Although the majority of RPC methods follow the same behavior than in Ethereum, some methods might produce a different result, or add more information, when used on an Arbitrum chain. You can find more information about these differences in [RPC methods](/for-devs/concepts/differences-between-arbitrum-ethereum/rpc-methods.mdx).

## Solidity support

You can deploy Solidity contracts onto Arbitrum just like you do Ethereum. There are only a few minor differences in behavior. Find more information about it in [Solidity support](/for-devs/concepts/differences-between-arbitrum-ethereum/solidity-support.mdx).

## Fees

The fees an Arbitrum transaction pays for execution essentially work identically to gas fees on Ethereum. Arbitrum transactions must also, however, pay a fee component to cover the cost of posting their calldata to the parent chain (for example, calldata on Arbitrum One, an L2, is posted to Ethereum, an L1). Find more information about the two components of gas fees in [Gas and fees](/arbos/gas.mdx) and [L1 pricing](/arbos/l1-pricing.mdx).

## Cross-chain messaging

Arbitrum chains support arbitrary message passing from a parent chain (for example, a Layer 1 (L1) like Ethereum) to a child chain (for example, a Layer 2 (L2) like Arbitrum One or Arbitrum Nova). These are commonly known as "L1 to L2 messages". Developers using this functionality should familiarize themselves with how they work. Find more information about it in [L1 to L2 messaging](/arbos/l1-to-l2-messaging.mdx).

Similarly, Arbitrum chains can also send messages to the parent chain. Find more information about them in [L2 to L1 messaging and the outbox](/arbos/l2-to-l1-messaging.mdx).

## Precompiles

Besides supporting all precompiles available in Ethereum, Arbitrum provides L2-specific precompiles with methods smart contracts can call the same way they can solidity functions. You can find a full reference of them in [Precompiles](/for-devs/concepts/precompiles.mdx).

## NodeInterface

Arbitrum Nitro software includes a special `NodeInterface` contract available at address `0xc8` that is only accessible via RPCs (it's not actually deployed on-chain, and thus can't be called by smart contracts). Find more information about this interface in [NodeInterface.sol](/arbos/gas.mdx#nodeinterfacesol).
Loading