Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions .github/workflows/copy-artifacts.yaml

This file was deleted.

27 changes: 27 additions & 0 deletions .github/workflows/crates-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Crates Release
# The five rainlang crates publish to crates.io on merge to main via
# rainix-autopublish's next-version lifecycle, as a lockstep set in dependency
# order: changing any member republishes the others with matching version pins.
# `rainlang_test_fixtures` depends on none of the others but is released with
# them so its embedded bytecode stays in step.
#
# DELIBERATELY separate from `package-release.yaml`, which is the same split
# rain.math.float.deploy made. The Soldeer `rainlang` package is a deploy
# artifact that only advances at deploy time behind a chain-verified `sol-v*`
# tag; the crates are bindings whose version tracks binding-code changes. Held
# in one workflow, autopublish's own next-version invariant applied to both
# halves at once and the Soldeer half — already at its published version by
# design — blocked the crates from ever bumping.
#
# No `soldeer-package` input here for that reason: this half publishes crates
# only.
on:
push:
branches:
- main
jobs:
release:
uses: rainlanguage/rainix/.github/workflows/rainix-autopublish.yaml@main
with:
crates: rainlang_bindings rainlang_dispair rainlang_parser rainlang-eval rainlang_test_fixtures
secrets: inherit
Comment thread
coderabbitai[bot] marked this conversation as resolved.
13 changes: 13 additions & 0 deletions .github/workflows/git-clean.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: Git is clean
on: [push]
jobs:
copy-artifacts:
# Shared reusable (rainix#201): rebuild the committed artifacts from
# committed sources — `script/Build.sol`, `forge build`, CopyArtifacts,
# `forge fmt` — then `git diff --exit-code`. This is what makes the
# committed `src/generated/` record current at PR time rather than only at
# tag time. Includes the Cachix substitution + 8G GC cap; no prelude
# (committing the artifacts is what removes the need for one).
# secrets: inherit carries CACHIX_AUTH_TOKEN.
uses: rainlanguage/rainix/.github/workflows/rainix-copy-artifacts.yaml@main
secrets: inherit
34 changes: 25 additions & 9 deletions .github/workflows/package-release.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
name: Package Release
# Deploy-shaped repo: the `rainlang` Soldeer package is released by a manual
# `sol-v*` tag via rainix-tag-release, never by a merge.
#
# rainix-autopublish's merge-driven next-version lifecycle is wrong for this
# shape. `[external.package].version` in `foundry.toml` is the LAST published
# revision and names the frozen `src/generated/<tag>/` record cut with it, so
# it may only move in lockstep with a deployment that already happened. The
# tag flow enforces exactly that: it re-runs the suite, then `release-guard`
# checks version == tag, the frozen dir present, byte-identical to a freshly
# regenerated `candidate/`, no later release frozen and a clean tree — then
# publishes.
#
# Push-free: the frozen snapshot and the version bump reach main through a
# reviewed PR BEFORE the tag, and this workflow commits nothing, so it works
# against a protected main.
#
# The Rust crates are NOT released here — see `crates-release.yaml`. They are
# ordinary bindings whose version tracks code changes and is safe to bump on
# merge, and coupling them to this trigger is what wedged the release lane.
#
# `snapshot-generate-cmd` is deliberately absent: it was removed org-wide and
# is no longer an input at all.
on:
push:
branches:
- main
tags:
- sol-v*
jobs:
release:
# Bumps + publishes the rainlang crates to crates.io as a lockstep set, in
# dependency order (bindings, dispair, parser, eval, then test_fixtures):
# changing any member republishes the others with matching version pins, via
# the PUBLISH_PRIVATE_KEY deploy key. test_fixtures depends on none of the
# others but is released in lockstep so its embedded bytecode stays in sync.
uses: rainlanguage/rainix/.github/workflows/rainix-autopublish.yaml@main
uses: rainlanguage/rainix/.github/workflows/rainix-tag-release.yaml@main
with:
crates: rainlang_bindings rainlang_dispair rainlang_parser rainlang-eval rainlang_test_fixtures
soldeer-package: rainlang
secrets: inherit
6 changes: 6 additions & 0 deletions .soldeerignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
.soldeerignore
.vscode
CLAUDE.md
TESTING.md
Cargo.lock
Cargo.toml
/audit
/cache
/crates
/dependencies
/flake.lock
/flake.nix
Expand All @@ -28,3 +32,5 @@ CLAUDE.md
/REUSE.toml
/deployments
/meta
/script
/target
36 changes: 31 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,20 @@ nix develop -c rainlang-prelude # generates meta/ needed by the sol build
Common tasks (all via `nix develop -c`): `rainix-sol-test`, `rainix-sol-static`,
`rainix-rs-test`, `rainix-rs-static`, `test-wasm-build`.

## Generated pointers
## Generated code

`src/generated/*.pointers.sol` are AUTOGENERATED constants (bytecode hashes,
function pointer tables, parse meta, Zoltu deploy addresses), committed because
contract and pointers file depend on each other circularly. After any source
change affecting bytecode:
`script/Build.sol` writes ALL of it. Never hand-edit:

- `src/generated/<Name>Pointers.sol` — parse meta, function pointer tables, meta
hashes. Committed because contract and pointers file depend on each other
circularly.
- `src/generated/candidate/<Name>.sol` — each deployed contract's rolling deploy
snapshot: hash, Zoltu address, creation/runtime code, dependencies.
- `src/generated/<x_y_z>/` — FROZEN release records. Append-only: never
regenerate, move or delete a tag dir.
- `src/lib/Lib*Released.sol` and `src/lib/LibReleasedSuites.sol`.

After any source change affecting bytecode:

1. `nix develop -c rainlang-prelude`
2. `nix develop -c forge script --silent ./script/Build.sol`
Expand All @@ -35,6 +43,24 @@ change affecting bytecode:
Address all `forge build` warnings before pointer rebuild, tests, or the next
task.

## Deploy and release

`src/abstract/RainlangDeploySuites.sol` is the ONE declaration of what this repo
deploys. `script/Deploy.sol`, `script/Build.sol` and the deploy tests all read
it; a deployment declared anywhere else is invisible to all three.

`[external.package].version` in `foundry.toml` is the LAST Soldeer publish, not
a next-version slot: a normal PR never moves it. Releasing is deploy (Manual sol
artifacts) → verify (`RainlangDeployChainTest`) → a PR carrying `cutRelease()`'s
frozen dir and the version bump → merge → push `sol-v<x.y.z>`.

Three things look wrong and are load-bearing: `optimizer_runs = 1000000` (not
the org's 100000 — it is baked into every live CREATE2 address here); `/test`
absent from `.soldeerignore` (raindex imports `test/abstract/OpTest.sol` through
the published package); and `src/lib/deploy/LibInterpreterDeploy.sol` being
hand-written rather than a generated alias lib (its constant names and
`etchRainlang` are a published consumer API).

## Conventions

- Compiler, optimizer and fuzz settings: `foundry.toml` is the source of truth.
Expand Down
59 changes: 54 additions & 5 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
[package]
# Release metadata, not foundry config. `[external.*]` is the namespace foundry
# reserves for other tools and ignores outright, so it raises no unknown-section
# warning and `forge config --fix` leaves it alone (a section foundry does not
# reserve is read as a profile, warned about on every invocation and rewritten
# into `[profile.*]` by the fixer).
#
# `version` is the LAST-published Soldeer release, not a next-version slot. A
# normal PR never moves it; only a release does, in lockstep with the frozen
# `src/generated/<tag>/` snapshot it names. `LibRainDeploySnapshot.deployTag()`
# reads it here when `script/Build.sol`'s `cutRelease()` runs, and rainix's
# `release-guard` checks it against the pushed `sol-v<version>` tag before
# anything publishes.
[external.package]
name = "rainlang"
version = "0.1.8"

Expand All @@ -21,6 +33,11 @@ evm_version = "cancun"

# These settings should be used for snapshots
optimizer = true
# NOT the org default of 100000. Every deploy address this repo pins is
# `CREATE2` over creation code, so this number is part of every address and
# codehash already live on chain. Lowering it to match the other deploy repos
# would move all five deployments and orphan every consumer pin, so it stays at
# the value the live deployments were compiled under.
optimizer_runs = 1000000

ffi = true
Expand All @@ -30,23 +47,51 @@ cbor_metadata = false
fs_permissions = [
{ access = "read-write", path = "./out/test/" },
{ access = "read-write", path = "./meta" },
{ access = "read-write", path = "src/generated" },
# `script/Build.sol` writes the rolling candidate snapshots under
# `src/generated/`, the non-deploy codegen beside them, and the generated
# released-suites libs under `src/lib/`.
{ access = "read-write", path = "./src" },
{ access = "read-write", path = "./crates/bindings/abi" },
{ access = "read-write", path = "./crates/test_fixtures/abi" },
{ access = "read", path = "./out" },
# `LibRainDeploySnapshot.deployTag` reads `[external.package].version` to name
# the frozen per-release snapshot dir.
{ access = "read", path = "foundry.toml" },
{ access = "write", path = "./deployments/latest/RainlangParser" },
{ access = "write", path = "./deployments/latest/RainlangStore" },
{ access = "write", path = "./deployments/latest/RainlangInterpreter" },
{ access = "write", path = "./deployments/latest/RainlangExpressionDeployer" },
]

remappings = [
# `rain-deploy` 0.1.7, and the `rain-sol-codegen` 0.1.36 it is built on, spell
# forge-std as `forge-std-1.16.2/`; this repo's own sources and several of its
# other dependencies still spell it `forge-std-1.16.1/`. Soldeer installs ONE
# version per package name, so the older prefix is aliased onto the installed
# one. Not cosmetic: two forge-std copies in one compilation are two DISTINCT
# `Vm` types, and a `vm` handed from one library to another would not type
# check.
#
# These live here rather than in `remappings.txt` because `forge soldeer
# install` owns that file and regenerates it from the installed set.
"forge-std-1.16.1/=dependencies/forge-std-1.16.2/",
# Same, for `rain-sol-codegen`. `rain-deploy` 0.1.7 needs 0.1.36, while this
# repo and `rainlang-interface` 0.2.5 import the `IParserToolingV1` /
# `ISubParserToolingV1` / `IOpcodeToolingV1` / `IIntegrityToolingV1`
# interfaces under the `rain-sol-codegen-0.1.0/` prefix. Those four interfaces
# are byte-identical between the two versions bar `pure` widening to `view` on
# three functions, which an implementation is free to narrow again, so nothing
# here moves any contract's bytecode.
"rain-sol-codegen-0.1.0/=dependencies/rain-sol-codegen-0.1.36/",
]

gas_limit = "18446744073709551615"

[dependencies]
forge-std = "1.16.1"
forge-std = "1.16.2"
"@openzeppelin-contracts" = "5.6.1"
"rain-datacontract" = "0.1.3"
"rain-deploy" = "0.1.3"
rain-deploy = "0.1.7"
"rain-extrospection" = "0.1.13"
"rain-intorastring" = "0.1.0"
"rain-lib-hash" = "0.1.0"
Expand All @@ -55,7 +100,7 @@ forge-std = "1.16.1"
"rain-math-binary" = "0.1.4"
"rain-math-float" = "0.1.1"
"rain-metadata" = "0.1.0"
"rain-sol-codegen" = "0.1.0"
rain-sol-codegen = "0.1.36"
"rain-solmem" = "0.1.26"
"rain-string" = "0.2.0"
"rain-tofu-erc20-decimals" = "0.1.1"
Expand All @@ -71,12 +116,16 @@ runs = 2048
arbitrum = "${ARBITRUM_RPC_URL}"
base = "${BASE_RPC_URL}"
base_sepolia = "${BASE_SEPOLIA_RPC_URL}"
ethereum = "${ETHEREUM_RPC_URL}"
flare = "${FLARE_RPC_URL}"
hyperevm = "${HYPEREVM_RPC_URL}"
polygon = "${POLYGON_RPC_URL}"

[etherscan]
arbitrum = { key = "${CI_DEPLOY_ARBITRUM_ETHERSCAN_API_KEY}" }
base = { key = "${CI_DEPLOY_BASE_ETHERSCAN_API_KEY}" }
base_sepolia = { key = "${CI_DEPLOY_BASE_SEPOLIA_ETHERSCAN_API_KEY}" }
ethereum = { key = "${CI_DEPLOY_ETHEREUM_ETHERSCAN_API_KEY}", chain = 1 }
flare = { key = "${CI_DEPLOY_FLARE_ETHERSCAN_API_KEY}" }
hyperevm = { key = "${CI_DEPLOY_HYPEREVM_ETHERSCAN_API_KEY}", chain = 999 }
polygon = { key = "${CI_DEPLOY_POLYGON_ETHERSCAN_API_KEY}" }
6 changes: 3 additions & 3 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
@openzeppelin-contracts-5.6.1/=dependencies/@openzeppelin-contracts-5.6.1/
forge-std-1.16.1/=dependencies/forge-std-1.16.1/
forge-std-1.16.2/=dependencies/forge-std-1.16.2/
rain-datacontract-0.1.3/=dependencies/rain-datacontract-0.1.3/
rain-deploy-0.1.3/=dependencies/rain-deploy-0.1.3/
rain-deploy-0.1.7/=dependencies/rain-deploy-0.1.7/
rain-extrospection-0.1.13/=dependencies/rain-extrospection-0.1.13/
rain-intorastring-0.1.0/=dependencies/rain-intorastring-0.1.0/
rain-lib-hash-0.1.0/=dependencies/rain-lib-hash-0.1.0/
Expand All @@ -10,7 +10,7 @@ rain-lib-typecast-0.1.0/=dependencies/rain-lib-typecast-0.1.0/
rain-math-binary-0.1.4/=dependencies/rain-math-binary-0.1.4/
rain-math-float-0.1.1/=dependencies/rain-math-float-0.1.1/
rain-metadata-0.1.0/=dependencies/rain-metadata-0.1.0/
rain-sol-codegen-0.1.0/=dependencies/rain-sol-codegen-0.1.0/
rain-sol-codegen-0.1.36/=dependencies/rain-sol-codegen-0.1.36/
rain-solmem-0.1.26/=dependencies/rain-solmem-0.1.26/
rain-string-0.2.0/=dependencies/rain-string-0.2.0/
rain-tofu-erc20-decimals-0.1.1/=dependencies/rain-tofu-erc20-decimals-0.1.1/
Expand Down
Loading
Loading