Skip to content
Merged
99 changes: 99 additions & 0 deletions .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: smoke

# Validate ALREADY-PUBLISHED base-anvil binaries on each target OS by doing
# exactly what an external developer does: run the public install one-liner,
# then run a real Base precompile test. This is the per-platform coverage a
# single laptop cannot do locally (BOP-385).
#
# v0 scope: Linux gnu (amd64 and arm64, each on new + old glibc) and macOS arm64.
# Deferred to follow-ups: Windows and Alpine/musl (extra shell/dependency
# handling) and Intel macOS (needs the macos-15-intel label; test-or-drop TBD).

on:
workflow_dispatch:
inputs:
version:
description: "Published release to validate (e.g. v1.1.0). Blank = base-foundryup default."
required: false
default: ""
# Self-test the smoke harness whenever it changes (and on this PR). Scoped to
# smoke files so it does not run on unrelated PRs. workflow_dispatch only
# becomes triggerable once this file is on the default branch.
pull_request:
paths:
- "smoke/**"
- ".github/workflows/smoke.yml"
# Once this is green, enable a daily run against the current default release:
# schedule:
# - cron: "0 12 * * *"

permissions: {}

jobs:
smoke:
name: smoke ${{ matrix.label }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 20
strategy:
fail-fast: false # one platform failing must not hide the others
matrix:
include:
- label: linux-amd64 (glibc, ubuntu 24.04)
runner: ubuntu-24.04
- label: linux-amd64 (older glibc, ubuntu 22.04)
runner: ubuntu-22.04
- label: linux-arm64 (glibc, ubuntu 24.04)
runner: ubuntu-24.04-arm
- label: linux-arm64 (older glibc, ubuntu 22.04)
runner: ubuntu-22.04-arm
- label: macos-arm64
runner: macos-latest
# macos-amd64 (Intel) is deferred. GitHub retired the macos-13 image
# on 2025-12-04, so that label never provisions (jobs queue until they
# time out). Intel x86_64 macOS now runs on the macos-15-intel label,
# supported until ~Aug 2027 when Actions drops Intel macOS entirely.
# Follow-up decision: cover Intel-Mac (uncomment the leg below) or drop
# the darwin_amd64 build from the release pipeline. Don't ship it untested.
# - label: macos-amd64 (intel)
# runner: macos-15-intel
steps:
- name: Check out the proof test
uses: actions/checkout@v6
with:
persist-credentials: false

- name: Install base-anvil via the public flow
shell: bash
env:
VERSION: ${{ inputs.version }}
FOUNDRY_DISABLE_NIGHTLY_WARNING: "1"
run: |
set -euo pipefail
# Pin the install dir: the installer otherwise uses
# ${XDG_CONFIG_HOME:-$HOME}/.foundry, and XDG_CONFIG_HOME is set on the
# Linux runners (but not macOS), which moves the bin dir out from under us.
export FOUNDRY_DIR="$HOME/.foundry"
curl -L https://raw.githubusercontent.com/base/base-anvil/HEAD/foundryup/install | bash
bin="$FOUNDRY_DIR/bin"
echo "$bin" >> "$GITHUB_PATH"

# Resilient to either install variant: the namespaced base-foundryup
# (current default branch) or the older `foundryup --network base`.
if [ -x "$bin/base-foundryup" ]; then
"$bin/base-foundryup" ${VERSION:+--install "$VERSION"}
echo "FORGE=base-forge" >> "$GITHUB_ENV"
else
"$bin/foundryup" --network base ${VERSION:+--install "$VERSION"}
echo "FORGE=forge" >> "$GITHUB_ENV"
fi

- name: Run the Base proof test
shell: bash
run: |
set -euo pipefail
cd smoke
if [ "$FORGE" = base-forge ]; then
base-forge test -vvv # base-forge enables Base by default
else
forge test --base -vvv
fi
3 changes: 3 additions & 0 deletions smoke/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cache/
out/
broadcast/
5 changes: 5 additions & 0 deletions smoke/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[profile.default]
test = "test"
# Deliberately dependency-free so the smoke test stays hermetic: no forge-std,
# no `forge install`, no submodules, no network. The proof test inlines the one
# interface it needs.
46 changes: 46 additions & 0 deletions smoke/test/BasePrecompile.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IActivationRegistry {
function isActivated(bytes32 feature) external view returns (bool);
}

/// @notice Proof that a base-anvil binary actually installed and seeded the Base
/// precompiles. Run via `base-forge test` (Base enabled by default) or
/// `forge test --base`.
///
/// The address and feature ids are the real Base values:
/// - ActivationRegistry address: base-std `StdPrecompiles.sol`.
/// - feature ids: base-std `ActivationRegistryFeatureList.sol`, which match
/// the three features base-anvil seeds active in
/// `crates/evm/networks/src/lib.rs` (`base_activation_seeds()`).
///
/// WITHOUT --base the address is an empty account, `isActivated()` returns
/// false, and this test FAILS: the false-pass becomes a visible failure.
/// WITH --base the precompile is registered and seeded, so it returns true.
contract BasePrecompileSmokeTest {
IActivationRegistry constant ACTIVATION_REGISTRY =
IActivationRegistry(0x8453000000000000000000000000000000000001);

// keccak256("base.b20_asset")
bytes32 constant B20_ASSET = 0xcdcc772fe4cbdb1029f822861176d09e646db96723d4c1e82ddfdeb8163ef54c;
// keccak256("base.b20_stablecoin")
bytes32 constant B20_STABLECOIN = 0xecfa0def2c10020caaf65e6155aa69c84b24892aaef76eeac52e0e2b3a0b8601;
// keccak256("base.policy_registry")
bytes32 constant POLICY_REGISTRY = 0xb582ebae03f16fee49a6763f78df482fb11ae73f103ed0d330bbe556aa90a43f;

function test_basePrecompileSeededActive() external view {
require(
ACTIVATION_REGISTRY.isActivated(B20_ASSET),
"B20_ASSET inactive: --base not applied or precompile missing"
);
require(
ACTIVATION_REGISTRY.isActivated(B20_STABLECOIN),
"B20_STABLECOIN inactive: --base not applied or precompile missing"
);
require(
ACTIVATION_REGISTRY.isActivated(POLICY_REGISTRY),
"POLICY_REGISTRY inactive: --base not applied or precompile missing"
);
}
}
Loading