Skip to content

Commit

Permalink
Merge pull request #121 from OffchainLabs/develop
Browse files Browse the repository at this point in the history
Merge develop into main
  • Loading branch information
joshuacolvin0 authored Nov 22, 2024
2 parents e6ef548 + 755456d commit 31bc4ea
Show file tree
Hide file tree
Showing 16 changed files with 319 additions and 158 deletions.
9 changes: 8 additions & 1 deletion .ci/build_and_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,11 @@ if [ "$CFG_RELEASE_CHANNEL" == "nightly" ]; then
else
cargo build --locked
fi
cargo test

cargo test

if [ "$(uname -s)" != "Darwin" ]; then
# The MacOS CI doesn't support Docker because of licensing issues, so only run them on Linux.
# Also, run the docker tests on a single thread to avoid concurrency issues.
cargo test -F docker-test -- --test-threads 1 docker
fi
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
./target
2 changes: 1 addition & 1 deletion .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: install rustup
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
sh rustup-init.sh -y --default-toolchain none
sh rustup-init.sh -y --default-toolchain ${{ matrix.cfg_release_channel }}
rustup target add ${{ matrix.target }}
- name: Build and Test
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/mac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: install rustup
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
sh rustup-init.sh -y --default-toolchain none
sh rustup-init.sh -y --default-toolchain ${{ matrix.cfg_release_channel }}
rustup target add ${{ matrix.target }}
- name: Build and Test
Expand Down
14 changes: 9 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
ARG TARGETPLATFORM=linux/amd64
FROM rust:1.80 AS builder
ARG BUILD_PLATFORM=linux/amd64
ARG RUST_VERSION=1.80
ARG CARGO_STYLUS_VERSION=0.5.6

FROM --platform=${BUILD_PLATFORM} rust:${RUST_VERSION} AS builder
RUN apt-get update && apt-get install -y git
RUN rustup target add x86_64-unknown-linux-gnu
RUN git clone https://github.com/offchainlabs/cargo-stylus.git
ARG CARGO_STYLUS_VERSION
RUN test -n "$CARGO_STYLUS_VERSION"
RUN git clone --branch v$CARGO_STYLUS_VERSION https://github.com/offchainlabs/cargo-stylus.git
WORKDIR /cargo-stylus
RUN git checkout v0.5.6
RUN cargo build --release --manifest-path main/Cargo.toml

FROM rust:1.80
FROM --platform=${BUILD_PLATFORM} rust:${RUST_VERSION} AS cargo-stylus-base
COPY --from=builder /cargo-stylus/target/release/cargo-stylus /usr/local/bin/cargo-stylus
29 changes: 29 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
CARGO_STYLUS_VERSION := $(shell cargo pkgid --manifest-path main/Cargo.toml | cut -d '@' -f 2)

.PHONY: build
build:
cargo build

.PHONY: test
test:
cargo test

.PHONY: bench
bench:
cargo +nightly bench -F nightly

.PHONY: fmt
fmt:
cargo fmt

.PHONY: lint
lint:
cargo clippy --package cargo-stylus --package cargo-stylus-example

.PHONY: install
install: fmt lint
cargo install --path main

.PHONY: docker
docker:
docker build -t cargo-stylus-base:$(CARGO_STYLUS_VERSION) --build-arg CARGO_STYLUS_VERSION=$(CARGO_STYLUS_VERSION) .
3 changes: 0 additions & 3 deletions install.sh

This file was deleted.

4 changes: 4 additions & 0 deletions main/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ license.workspace = true
version.workspace = true
repository.workspace = true

[features]
docker-test = []
nightly = []

[dependencies]
alloy-primitives.workspace = true
alloy-json-abi.workspace = true
Expand Down
32 changes: 7 additions & 25 deletions main/src/activate.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
// Copyright 2023-2024, Offchain Labs, Inc.
// For licensing, see https://github.com/OffchainLabs/cargo-stylus/blob/stylus/licenses/COPYRIGHT.md

use crate::check::check_activate;
use crate::constants::ARB_WASM_H160;
use crate::macros::greyln;
use crate::util::color::{Color, DebugColor};
use crate::util::sys;
use crate::ActivateConfig;
use alloy_primitives::Address;
use alloy_sol_macro::sol;
use alloy_sol_types::SolCall;
use ethers::middleware::{Middleware, SignerMiddleware};
use ethers::signers::Signer;
use ethers::types::transaction::eip2718::TypedTransaction;
use ethers::types::{Eip1559TransactionRequest, U256};
use ethers::types::Eip1559TransactionRequest;
use ethers::utils::format_units;
use eyre::{bail, Context, Result};

use crate::check::check_activate;
use crate::constants::ARB_WASM_H160;
use crate::macros::greyln;

use crate::ActivateConfig;

sol! {
interface ArbWasm {
function activateProgram(address program)
Expand All @@ -41,25 +39,14 @@ pub async fn activate_contract(cfg: &ActivateConfig) -> Result<()> {
let client = SignerMiddleware::new(provider.clone(), wallet);

let code = client.get_code(cfg.address, None).await?;
let data_fee = check_activate(code, cfg.address, &provider).await?;
let mut data_fee = alloy_ethers_typecast::alloy_u256_to_ethers(data_fee);

greyln!(
"obtained estimated activation data fee {}",
format_units(data_fee, "ether")?.debug_lavender()
);
greyln!(
"bumping estimated activation data fee by {}%",
cfg.data_fee_bump_percent.debug_lavender()
);
data_fee = bump_data_fee(data_fee, cfg.data_fee_bump_percent);
let data_fee = check_activate(code, cfg.address, &cfg.data_fee, &provider).await?;

let contract: Address = cfg.address.to_fixed_bytes().into();
let data = ArbWasm::activateProgramCall { program: contract }.abi_encode();
let tx = Eip1559TransactionRequest::new()
.from(client.address())
.to(*ARB_WASM_H160)
.value(data_fee)
.value(alloy_ethers_typecast::alloy_u256_to_ethers(data_fee))
.data(data);
let tx = TypedTransaction::Eip1559(tx);
if cfg.estimate_gas {
Expand Down Expand Up @@ -96,8 +83,3 @@ pub async fn activate_contract(cfg: &ActivateConfig) -> Result<()> {
}
Ok(())
}

fn bump_data_fee(fee: U256, pct: u64) -> U256 {
let num = 100 + pct;
fee * U256::from(num) / U256::from(100)
}
49 changes: 33 additions & 16 deletions main/src/check.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// Copyright 2023-2024, Offchain Labs, Inc.
// For licensing, see https://github.com/OffchainLabs/cargo-stylus/blob/main/licenses/COPYRIGHT.md

use crate::util::{color::Color, sys, text};
use crate::{
check::ArbWasm::ArbWasmErrors,
constants::{ARB_WASM_H160, ONE_ETH, TOOLCHAIN_FILE_NAME},
macros::*,
project::{self, extract_toolchain_channel, BuildConfig},
CheckConfig,
util::{
color::{Color, GREY, LAVENDER},
sys, text,
},
CheckConfig, DataFeeOpts,
};
use alloy_primitives::{Address, B256, U256};
use alloy_sol_macro::sol;
Expand Down Expand Up @@ -87,9 +90,7 @@ pub async fn check(cfg: &CheckConfig) -> Result<ContractCheck> {
}

let address = cfg.contract_address.unwrap_or(H160::random());
let fee = check_activate(code.clone().into(), address, &provider).await?;
let visual_fee = format_data_fee(fee).unwrap_or("???".red());
greyln!("wasm data fee: {visual_fee} ETH");
let fee = check_activate(code.clone().into(), address, &cfg.data_fee, &provider).await?;
Ok(ContractCheck::Ready { code, fee })
}

Expand All @@ -112,7 +113,7 @@ impl ContractCheck {
pub fn suggest_fee(&self) -> U256 {
match self {
Self::Active { .. } => U256::default(),
Self::Ready { fee, .. } => fee * U256::from(120) / U256::from(100),
Self::Ready { fee, .. } => *fee,
}
}
}
Expand All @@ -128,7 +129,7 @@ impl CheckConfig {
let cfg = BuildConfig::new(rust_stable);
let wasm = project::build_dylib(cfg.clone())?;
let project_hash =
project::hash_files(self.common_cfg.source_files_for_project_hash.clone(), cfg)?;
project::hash_project(self.common_cfg.source_files_for_project_hash.clone(), cfg)?;
Ok((wasm, project_hash))
}
}
Expand All @@ -148,17 +149,19 @@ pub fn format_file_size(len: usize, mid: u64, max: u64) -> String {
}

/// Pretty-prints a data fee.
fn format_data_fee(fee: U256) -> Result<String> {
let fee: u64 = (fee / U256::from(1e9)).try_into()?;
fn format_data_fee(fee: U256) -> String {
let Ok(fee): Result<u64, _> = (fee / U256::from(1e9)).try_into() else {
return ("???").red();
};
let fee: f64 = fee as f64 / 1e9;
let text = format!("{fee:.6}");
Ok(if fee <= 5e14 {
let text = format!("{fee:.6} ETH");
if fee <= 5e14 {
text.mint()
} else if fee <= 5e15 {
text.yellow()
} else {
text.pink()
})
}
}

pub struct EthCallError {
Expand Down Expand Up @@ -247,7 +250,12 @@ Perhaps the Arbitrum node for the endpoint you are connecting to has not yet upg
}

/// Checks contract activation, returning the data fee.
pub async fn check_activate(code: Bytes, address: H160, provider: &Provider<Http>) -> Result<U256> {
pub async fn check_activate(
code: Bytes,
address: H160,
opts: &DataFeeOpts,
provider: &Provider<Http>,
) -> Result<U256> {
let contract = Address::from(address.to_fixed_bytes());
let data = ArbWasm::activateProgramCall { program: contract }.abi_encode();
let tx = Eip1559TransactionRequest::new()
Expand All @@ -256,8 +264,17 @@ pub async fn check_activate(code: Bytes, address: H160, provider: &Provider<Http
.value(ONE_ETH);
let state = spoof::code(address, code);
let outs = eth_call(tx, state, provider).await??;
let ArbWasm::activateProgramReturn { dataFee, .. } =
ArbWasm::activateProgramCall::abi_decode_returns(&outs, true)?;
let ArbWasm::activateProgramReturn {
dataFee: data_fee, ..
} = ArbWasm::activateProgramCall::abi_decode_returns(&outs, true)?;

let bump = opts.data_fee_bump_percent;
let adjusted_data_fee = data_fee * U256::from(100 + bump) / U256::from(100);
greyln!(
"wasm data fee: {} {GREY}(originally {}{GREY} with {LAVENDER}{bump}%{GREY} bump)",
format_data_fee(adjusted_data_fee),
format_data_fee(data_fee)
);

Ok(dataFee)
Ok(adjusted_data_fee)
}
32 changes: 18 additions & 14 deletions main/src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,13 @@ pub type SignerClient = SignerMiddleware<Provider<Http>, Wallet<SigningKey>>;

/// Deploys a stylus contract, activating if needed.
pub async fn deploy(cfg: DeployConfig) -> Result<()> {
macro_rules! run {
($expr:expr) => {
$expr.await?
};
($expr:expr, $($msg:expr),+) => {
$expr.await.wrap_err_with(|| eyre!($($msg),+))?
};
}

let contract = run!(check::check(&cfg.check_config), "cargo stylus check failed");
let contract = check::check(&cfg.check_config)
.await
.expect("cargo stylus check failed");
let verbose = cfg.check_config.common_cfg.verbose;

let client = sys::new_provider(&cfg.check_config.common_cfg.endpoint)?;
let chain_id = run!(client.get_chainid(), "failed to get chain id");
let chain_id = client.get_chainid().await.expect("failed to get chain id");

let wallet = cfg.auth.wallet().wrap_err("failed to load wallet")?;
let wallet = wallet.with_chain_id(chain_id.as_u64());
Expand All @@ -67,7 +60,10 @@ pub async fn deploy(cfg: DeployConfig) -> Result<()> {

if let ContractCheck::Ready { .. } = &contract {
// check balance early
let balance = run!(client.get_balance(sender, None), "failed to get balance");
let balance = client
.get_balance(sender, None)
.await
.expect("failed to get balance");
let balance = alloy_ethers_typecast::ethers_u256_to_alloy(balance);

if balance < data_fee && !cfg.estimate_gas {
Expand All @@ -93,8 +89,16 @@ pub async fn deploy(cfg: DeployConfig) -> Result<()> {

match contract {
ContractCheck::Ready { .. } => {
cfg.activate(sender, contract_addr, data_fee, &client)
.await?
if cfg.no_activate {
mintln!(
r#"NOTE: You must activate the stylus contract before calling it. To do so, we recommend running:
cargo stylus activate --address {}"#,
hex::encode(contract_addr)
);
} else {
cfg.activate(sender, contract_addr, data_fee, &client)
.await?
}
}
ContractCheck::Active { .. } => greyln!("wasm already activated!"),
}
Expand Down
Loading

0 comments on commit 31bc4ea

Please sign in to comment.