ArbOS
ArbOS is the Layer 2 EVM hypervisor that facilitates the execution environment of L2 Arbitrum. ArbOS accounts for and manages network resources, produces blocks from incoming messages, and operates its instrumented instance of Geth for smart contract execution.
Precompiles
ArbOS provides L2-specific precompiles with methods smart contracts can call the same way they can solidity functions. Visit the precompiles conceptual page for more information about how these work, and the precompiles reference page for a full reference of the precompiles available in Arbitrum chains.
A precompile consists of a solidity interface in contracts/src/precompiles/
and a corresponding Golang implementation in precompiles/
. Using Geth's ABI generator, solgen/gen.go
generates solgen/go/precompilesgen/precompilesgen.go
, which collects the ABI data of the precompiles. The runtime installer uses this generated file to check the type safety of each precompile's implementer.
The installer uses runtime reflection to ensure each implementer has all the right methods and signatures. This includes restricting access to stateful objects like the EVM and statedb based on the declared purity. Additionally, the installer verifies and populates event function pointers to provide each precompile the ability to emit logs and know their gas costs. Additional configuration like restricting a precompile's methods to only be callable by chain owners is possible by adding precompile wrappers like ownerOnly
and debugOnly
to their installation entry.
The calling, dispatching, and recording of precompile methods are done via runtime reflection as well. This avoids any human error manually parsing and writing bytes could introduce, and uses Geth's stable APIs for packing and unpacking values.
Each time a transaction calls a method of an L2-specific precompile, a call context
is created to track and record the gas burnt. For convenience, it also provides access to the public fields of the underlying TxProcessor
. Because sub-transactions could revert without updates to this struct, the TxProcessor
only makes public that which is safe, such as the amount of L1 calldata paid by the top level transaction.
Messages
An L1IncomingMessage
represents an incoming sequencer message. A message includes one or more user transactions depending on load, and is made into a unique L2 block. The L2 block may include additional system transactions added in while processing the message's user transactions, but ultimately the relationship is still bijective: for every L1IncomingMessage
there is an L2 block with a unique L2 block hash, and for every L2 block after chain initialization there was an L1IncomingMessage
that made it. A sequencer batch may contain more than one L1IncomingMessage
.
Retryables
A Retryable is a special message type for creating atomic L1 to L2 messages; for details, see L1 To L2 Messaging.
ArbOS State
ArbOS's state is viewed and modified via ArbosState
objects, which provide convenient abstractions for working with the underlying data of its backingStorage
. The backing storage's keyed subspace strategy makes possible ArbosState
's convenient getters and setters, minimizing the need to directly work with the specific keys and values of the underlying storage's stateDB
.
Because two ArbosState
objects with the same backingStorage
contain and mutate the same underlying state, different ArbosState
objects can provide different views of ArbOS's contents. Burner
objects, which track gas usage while working with the ArbosState
, provide the internal mechanism for doing so. Some are read-only, causing transactions to revert with vm.ErrWriteProtection
upon a mutating request. Others demand the caller have elevated privileges. While yet others dynamically charge users when doing stateful work. For safety the kind of view is chosen when OpenArbosState()
creates the object and may never change.
Much of ArbOS's state exists to facilitate its precompiles. The parts that aren't are detailed below.