As in Ethereum, Arbitrum clients submit transactions they want to see happen, and the system (usually) executes those transactions at some later time. In Arbitrum Rollup, clients submit transactions by posting messages to the Ethereum chain, either directly or through an aggregator, or on a Sequencer chain, though a Sequencer. These messages are put into the chain's inbox.
Messages in an ArbChain's inbox 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.
Block Numbers: Arbitrum vs. Ethereum
Arbitrum blocks are assigned their own block numbers, distinct from Ethereum's L1 block numbers.
A single Ethereum block could include within it multiple Arbitrum blocks (if, say, the Arbitrum chain is getting heavy activity); 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
On a Sequencer chain, 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. On a non-sequencer chain,
block.number will return the L1 block number at which the transaction was inserted into the L1 inbox.
// 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; one should expect to see Arbitrum blocks produced at a relatively steady rate.
A client that queries an Arbitrum node's RPC interface (for, ie., 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
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:
ArbSys(100).arbBlockNumber() // returns Arbitrum block number