Skip to content

Commit

Permalink
resolve conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
rachel-bousfield committed May 3, 2024
1 parent 46c29f5 commit cd5af1d
Show file tree
Hide file tree
Showing 83 changed files with 2,137 additions and 617 deletions.
89 changes: 29 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,89 +1,58 @@
<br />
<p align="center">
<a href="https://arbitrum.io/">
<img src="https://arbitrum.io/assets/stylus/stylus_with_paint_bg.png" alt="Logo" width="100%">
<img src="https://arbitrum.io/assets/arbitrum/logo_color.png" alt="Logo" width="80" height="80">
</a>

<h3 align="center">Arbitrum Nitro</h3>

<p align="center">
<a href="https://developer.arbitrum.io/"><strong>Next Generation Ethereum L2 Technology »</strong></a>
<br />
</p>
</p>

## About Arbitrum Stylus

Stylus is a next-gen programming environment for Arbitrum chains. Through the power of WebAssembly smart contracts, users can deploy programs written in their favorite programming languages, including Rust, C, and C++, to run alongside EVM smart contracts on Arbitrum. It's over an order of magnitude faster, slashes fees, and is fully interoperable with the Ethereum Virtual Machine.

This repo is a fork of [Arbitrum Nitro][Nitro] and is designed as an upgrade for all Arbitrum chains. Included is the Stylus VM and working fraud prover. If you are looking to write and deploy Stylus programs, please see the following SDKs.

| Repo | Use cases | License |
|:-------------------------------|:----------------------------|:------------------|
| [Rust SDK][Rust] | Everything! | Apache 2.0 or MIT |
| [C/C++ SDK][C] | Cryptography and algorithms | Apache 2.0 or MIT |
| [Bf SDK][Bf] | Educational | Apache 2.0 or MIT |
| [Cargo Stylus CLI Tool][Cargo] | Program deployment | Apache 2.0 or MIT |

[Nitro]: https://github.com/OffchainLabs/nitro
[Orbit]: https://docs.arbitrum.io/launch-orbit-chain/orbit-gentle-introduction

Stylus is entirely opt-in. Devs familiar with Solidity can continue to enjoy Arbitrum's EVM-equivalent experience without any changes. This is because Stylus is entirely additive &mdash; a model we call EVM+. Stylus introduces a second, fully composible virtual machine for executing WebAssembly that coordinates with the EVM to produce state transitions. And since the Stylus SDK uses solidity ABIs, a contract written in one language can call out to any other.

For example, existing Solidity DEXs can &mdash; without modifications &mdash; list Rust ERC20 tokens, which might call out to C programs to do cryptography. Everything is fully interoperable, so users never have to care about the specific language or implementation details of the contracts they call.

## Roadmap
## About Arbitrum Nitro

Stylus is currently testnet-only and not recommended for production use. This will change as we complete an audit and add additional features.
<img src="https://arbitrum.io/assets/arbitrum/logo_color.png" alt="Logo" width="80" height="80">

Arbitrum [Orbit L3s][Orbit] may opt into Stylus at any time. Arbitrum One and Arbitrum Nova will upgrade to Stylus should the DAO vote for it.
Nitro is the latest iteration of the Arbitrum technology. It is a fully integrated, complete
layer 2 optimistic rollup system, including fraud proofs, the sequencer, the token bridges,
advanced calldata compression, and more.

If you'd like to be a part of this journey, join us in the `#stylus` channel on [Discord][discord]!
See the live docs-site [here](https://developer.arbitrum.io/) (or [here](https://github.com/OffchainLabs/arbitrum-docs) for markdown docs source.)

## Gas Pricing
See [here](./audits) for security audit reports.

Stylus introduces new pricing models for WASM programs. Intended for high-compute applications, Stylus makes the following more affordable:
The Nitro stack is built on several innovations. At its core is a new prover, which can do Arbitrum’s classic
interactive fraud proofs over WASM code. That means the L2 Arbitrum engine can be written and compiled using
standard languages and tools, replacing the custom-designed language and compiler used in previous Arbitrum
versions. In normal execution,
validators and nodes run the Nitro engine compiled to native code, switching to WASM if a fraud proof is needed.
We compile the core of Geth, the EVM engine that practically defines the Ethereum standard, right into Arbitrum.
So the previous custom-built EVM emulator is replaced by Geth, the most popular and well-supported Ethereum client.

- Compute, which is generally **10-100x** cheaper depending on the program. This is primarily due to the efficiency of the WASM runtime relative to the EVM, and the quality of the code produced by Rust, C, and C++ compilers. Another factor that matters is the quality of the code itself. For example, highly optimized and audited C libraries that implement a particular cryptographic operation are usually deployable without modification and perform exceptionally well. The fee reduction may be smaller for highly optimized Solidity that makes heavy use of native precompiles vs an unoptimized Stylus equivalent that doesn't do the same.
The last piece of the stack is a slimmed-down version of our ArbOS component, rewritten in Go, which provides the
rest of what’s needed to run an L2 chain: things like cross-chain communication, and a new and improved batching
and compression system to minimize L1 costs.

- Memory, which is **100-500x** cheaper due to Stylus's novel exponential pricing mechanism intended to address Vitalik's concerns with the EVM's per-call, [quadratic memory][quadratic] pricing policy. For the first time ever, high-memory applications are possible on an EVM-equivalent chain.
Essentially, Nitro runs Geth at layer 2 on top of Ethereum, and can prove fraud over the core engine of Geth
compiled to WASM.

- Storage, for which the Rust SDK promotes better access patterns and type choices. Note that while the underlying [`SLOAD`][SLOAD] and [`SSTORE`][SSTORE] operations cost as they do in the EVM, the Rust SDK implements an optimal caching policy that minimizes their use. Exact savings depends on the program.

- VM affordances, including common operations like keccak and reentrancy detection. No longer is it expensive to make safety the default.

There are, however, minor overheads to using Stylus that may matter to your application:

- The first time a WASM is deployed, it must be _activated_. This is generally a few million gas, though to avoid testnet DoS, we've set it to a fixed 14 million. Note that you do not have to activate future copies of the same program. For example, the same NFT template can be deployed many times without paying this cost more than once. We will soon make the fees paid depend on the program, so that the gas used is based on the complexity of the WASM instead of this very conservative, worst-case estimate.

- Calling a Stylus program costs 200-2000 gas. We're working with Wasmer to improve setup costs, but there will likely always be some amount of gas one pays to jump into WASM execution. This means that if a contract does next to nothing, it may be cheaper in Solidity. However if a contract starts doing interesting work, the dynamic fees will quickly make up for this fixed-cost overhead.

Though conservative bounds have been chosen for testnet, all of this is subject to change as pricing models mature and further optimizations are made. Since gas numbers will vary across updates, it may make more sense to clock the time it takes to perform an operation rather than going solely by the numbers reported in receipts.

[quadratic]: https://notes.ethereum.org/@vbuterin/proposals_to_adjust_memory_gas_costs
[SLOAD]: https://www.evm.codes/#54
[SSTORE]: https://www.evm.codes/#55
Arbitrum One successfully migrated from the Classic Arbitrum stack onto Nitro on 8/31/22. (See [state migration](https://developer.arbitrum.io/migration/state-migration) and [dapp migration](https://developer.arbitrum.io/migration/dapp_migration) for more info).

## License

We currently have the Stylus VM and fraud prover (the contents of this repo) [licensed](./LICENSE) under a Business Source License, similar to our friends at Uniswap and Aave, with an "Additional Use Grant" to ensure that everyone can have full comfort using and running nodes on all public Arbitrum chains.
Nitro is currently licensed under a [Business Source License](./LICENSE.md), similar to our friends at Uniswap and Aave, with an "Additional Use Grant" to ensure that everyone can have full comfort using and running nodes on all public Arbitrum chains.

The Stylus SDK, however, is licensed under different terms. Please see each repo below for more information.
The Additional Use Grant also permits the deployment of the Nitro software, in a permissionless fashion and without cost, as a new blockchain provided that the chain settles to either Arbitrum One or Arbitrum Nova.

| Repo | Use cases | License |
|:-------------------------------|:----------------------------|:------------------|
| [Rust SDK][Rust] | Everything! | Apache 2.0 or MIT |
| [C/C++ SDK][C] | Cryptography and algorithms | Apache 2.0 or MIT |
| [Bf SDK][Bf] | Educational | Apache 2.0 or MIT |
| [Cargo Stylus CLI Tool][Cargo] | Program deployment | Apache 2.0 or MIT |

[Rust]: https://github.com/OffchainLabs/stylus-sdk-rs
[C]: https://github.com/OffchainLabs/stylus-sdk-c
[Bf]: https://github.com/OffchainLabs/stylus-sdk-bf
[Cargo]: https://github.com/OffchainLabs/cargo-stylus
For those that prefer to deploy the Nitro software either directly on Ethereum (i.e. an L2) or have it settle to another Layer-2 on top of Ethereum, the [Arbitrum Expansion Program (the "AEP")](https://docs.arbitrum.foundation/assets/files/Arbitrum%20Expansion%20Program%20Jan182024-4f08b0c2cb476a55dc153380fa3e64b0.pdf) was recently established. The AEP allows for the permissionless deployment in the aforementioned fashion provided that 10% of net revenue (as more fully described in the AEP) is contributed back to the Arbitrum community in accordance with the requirements of the AEP.

## Contact

Discord - [Arbitrum][discord]
Discord - [Arbitrum](https://discord.com/invite/5KE54JwyTs)

Twitter: [Arbitrum](https://twitter.com/arbitrum)

Twitter - [OffchainLabs](https://twitter.com/OffchainLabs)

[discord]: https://discord.com/invite/5KE54JwyTs
1 change: 1 addition & 0 deletions arbitrator/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions arbitrator/prover/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ num-traits = "0.2.17"
c-kzg = { version = "0.4.0", optional = true } # TODO: look into switching to rust-kzg (no crates.io release or hosted rustdoc yet)
sha2 = "0.9.9"
lru = "0.12.3"
once_cell = "1.19.0"

[lib]
name = "prover"
Expand Down
74 changes: 40 additions & 34 deletions arbitrator/prover/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use machine::{
argument_data_to_inbox, get_empty_preimage_resolver, GlobalState, MachineStatus,
PreimageResolver,
};
use once_cell::sync::OnceCell;
use static_assertions::const_assert_eq;
use std::{
ffi::CStr,
Expand All @@ -45,7 +46,7 @@ use std::{
use utils::CBytes;

lazy_static::lazy_static! {
static ref BLOBHASH_PREIMAGE_CACHE: Mutex<LruCache<Bytes32, CBytes>> = Mutex::new(LruCache::new(NonZeroUsize::new(12).unwrap()));
static ref BLOBHASH_PREIMAGE_CACHE: Mutex<LruCache<Bytes32, Arc<OnceCell<CBytes>>>> = Mutex::new(LruCache::new(NonZeroUsize::new(12).unwrap()));
}

#[repr(C)]
Expand Down Expand Up @@ -332,28 +333,32 @@ pub struct ResolvedPreimage {
pub len: isize, // negative if not found
}

macro_rules! handle_preimage_resolution {
($context:expr, $ty:expr, $hash:expr, $resolver:expr) => {{
let res = $resolver($context, $ty.into(), $hash.as_ptr());
if res.len < 0 {
return None;
}
let data = CBytes::from_raw_parts(res.ptr, res.len as usize);
// Check if preimage rehashes to the provided hash
match crate::utils::hash_preimage(&data, $ty) {
Ok(have_hash) if have_hash.as_slice() == *$hash => {}
Ok(got_hash) => panic!(
"Resolved incorrect data for hash {} (rehashed to {})",
$hash,
Bytes32(got_hash),
),
Err(err) => panic!(
"Failed to hash preimage from resolver (expecting hash {}): {}",
$hash, err,
),
}
Some(data)
}};
#[cfg(feature = "native")]
unsafe fn handle_preimage_resolution(
context: u64,
ty: PreimageType,
hash: Bytes32,
resolver: unsafe extern "C" fn(u64, u8, *const u8) -> ResolvedPreimage,
) -> Option<CBytes> {
let res = resolver(context, ty.into(), hash.as_ptr());
if res.len < 0 {
return None;
}
let data = CBytes::from_raw_parts(res.ptr, res.len as usize);
// Check if preimage rehashes to the provided hash
match crate::utils::hash_preimage(&data, ty) {
Ok(have_hash) if have_hash.as_slice() == *hash => {}
Ok(got_hash) => panic!(
"Resolved incorrect data for hash {} (rehashed to {})",
hash,
Bytes32(got_hash),
),
Err(err) => panic!(
"Failed to hash preimage from resolver (expecting hash {}): {}",
hash, err,
),
}
Some(data)
}

#[no_mangle]
Expand All @@ -364,18 +369,19 @@ pub unsafe extern "C" fn arbitrator_set_preimage_resolver(
) {
(*mach).set_preimage_resolver(Arc::new(
move |context: u64, ty: PreimageType, hash: Bytes32| -> Option<CBytes> {
if let PreimageType::EthVersionedHash = ty {
let mut cache = BLOBHASH_PREIMAGE_CACHE.lock().unwrap();
if cache.contains(&hash) {
return cache.get(&hash).cloned();
}
if let Some(data) = handle_preimage_resolution!(context, ty, hash, resolver) {
cache.put(hash, data.clone());
return Some(data);
}
return None;
if ty == PreimageType::EthVersionedHash {
let cache: Arc<OnceCell<CBytes>> = {
let mut locked = BLOBHASH_PREIMAGE_CACHE.lock().unwrap();
locked.get_or_insert(hash, Default::default).clone()
};
return cache
.get_or_try_init(|| {
handle_preimage_resolution(context, ty, hash, resolver).ok_or(())
})
.ok()
.cloned();
}
handle_preimage_resolution!(context, ty, hash, resolver)
handle_preimage_resolution(context, ty, hash, resolver)
},
) as PreimageResolver);
}
Expand Down
1 change: 1 addition & 0 deletions arbitrator/wasm-libraries/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 4 additions & 5 deletions arbnode/batch_poster.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,8 @@ var DefaultBatchPosterConfig = BatchPosterConfig{
Enable: false,
DisableDasFallbackStoreDataOnChain: false,
// This default is overridden for L3 chains in applyChainParameters in cmd/nitro/nitro.go
MaxSize: 100000,
// TODO: is 1000 bytes an appropriate margin for error vs blob space efficiency?
Max4844BatchSize: blobs.BlobEncodableData*(params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) - 1000,
MaxSize: 100000,
Max4844BatchSize: blobs.BlobEncodableData*(params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) - 2000,
PollInterval: time.Second * 10,
ErrorDelay: time.Second * 10,
MaxDelay: time.Hour,
Expand Down Expand Up @@ -491,7 +490,7 @@ func (b *BatchPoster) checkReverts(ctx context.Context, to int64) (bool, error)
return false, fmt.Errorf("getting a receipt for transaction: %v, %w", tx.Hash, err)
}
if r.Status == types.ReceiptStatusFailed {
shouldHalt := !b.config().DataPoster.UseNoOpStorage
shouldHalt := !b.dataPoster.UsingNoOpStorage()
logLevel := log.Warn
if shouldHalt {
logLevel = log.Error
Expand Down Expand Up @@ -1278,7 +1277,7 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error)
return false, err
}
if len(kzgBlobs)*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock {
return false, fmt.Errorf("produced %v blobs for batch but a block can only hold %v", len(kzgBlobs), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob)
return false, fmt.Errorf("produced %v blobs for batch but a block can only hold %v (compressed batch was %v bytes long)", len(kzgBlobs), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob, len(sequencerMsg))
}
accessList := b.accessList(int(batchPosition.NextSeqNum), int(b.building.segments.delayedMsg))
// On restart, we may be trying to estimate gas for a batch whose successor has
Expand Down
Loading

0 comments on commit cd5af1d

Please sign in to comment.