-
Notifications
You must be signed in to change notification settings - Fork 2
refactor(deploy): migrate deploy constants to the per-version snapshot canon #253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 8 commits
627c609
d1f2f50
e318d66
68531c7
3b59115
48175ec
865a49e
6d569cd
b0ddd1f
160fd5b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -60,14 +60,19 @@ deterministic address is a function of bytecode + salt only — not the branch o | |
| deployer — so a successful deploy from any branch lands at the same address a | ||
| main-branch deploy would. | ||
|
|
||
| **Typical flow for a source-changing PR**: trigger the `Manual sol artifacts` | ||
| GitHub workflow on the PR's branch before merge. | ||
| **The deploy is decoupled from the merge.** A source-changing PR regenerates its | ||
| deployment record and merges on that record alone; nothing about landing it | ||
| waits on an on-chain deploy. The deploy itself is a separate manual dispatch, | ||
| run when someone decides to publish: | ||
| `gh workflow run manual-sol-artifacts.yaml --ref <branch> -f suite=decimal-float` | ||
| (use `log-tables` only when table bytecode changes, which is rare). The workflow | ||
| runs `script/Deploy.sol` with `--broadcast --verify` across all networks, using | ||
| `PRIVATE_KEY` regardless of ref. Do NOT wait for merge before deploying — there | ||
| is nothing to gain from waiting, and the CI deploy-constant tests need updating | ||
| anyway based on the deployed address. | ||
| `PRIVATE_KEY` regardless of ref. | ||
|
|
||
| `test/src/lib/deploy/LibDecimalFloatDeployProd.t.sol` forks all five networks | ||
| and asserts the current record's addresses already carry the expected code, so | ||
| it goes red between a bytecode change and the deploy that publishes it. That is | ||
| a statement about the state of the chains, not about the branch under test. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- tracked workflow and documentation files ---'
git ls-files | rg '(^|/)(CLAUDE\.md|.*github/workflows/.*|.*\.ya?ml$)' | head -200
printf '%s\n' '--- CLAUDE.md relevant ranges ---'
sed -n '1,130p' CLAUDE.md
printf '%s\n' '--- fork-test references across repository ---'
rg -n -S 'LibDecimalFloatDeployProd|forge test|fork|non-block|continue-on-error|DEPLOYMENT_KEY|PRIVATE_KEY' \
CLAUDE.md .github test script 2>/dev/null | head -300Repository: rainlanguage/rain.math.float Length of output: 4046 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- workflow job definitions and test commands ---'
for f in .github/workflows/*.yaml; do
echo "### $f"
rg -n -C 5 'forge|test|solidity|manual|workflow_dispatch|pull_request|continue-on-error|if:|required|artifact' "$f" || true
done
printf '%s\n' '--- complete PR and manual Solidity workflows ---'
for f in .github/workflows/pr-assessment.yaml .github/workflows/manual-sol-artifacts.yaml .github/workflows/rainix-sol.yaml; do
echo "### $f"
cat -n "$f"
done
printf '%s\n' '--- production fork test implementation and configuration references ---'
cat -n test/src/lib/deploy/LibDecimalFloatDeployProd.t.sol
rg -n -S 'MAINNET_RPC|ARBITRUM_RPC|OPTIMISM_RPC|BASE_RPC|POLYGON_RPC|fork|LibDecimalFloatDeployProd' .github script test foundry.toml 2>/dev/null || trueRepository: rainlanguage/rain.math.float Length of output: 6251 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- referenced reusable Solidity workflow ---'
curl -fsSL https://raw.githubusercontent.com/rainlanguage/rainix/main/.github/workflows/rainix-sol.yaml | sed -n '1,240p'
printf '%s\n' '--- referenced manual deployment workflow ---'
curl -fsSL https://raw.githubusercontent.com/rainlanguage/rainix/main/.github/workflows/rainix-manual-sol-artifacts.yaml | sed -n '1,240p'
printf '%s\n' '--- repository branch protection and workflow metadata ---'
curl -fsSL https://api.github.com/repos/rainlanguage/rain.math.float/branches/main/protection \
-H 'Accept: application/vnd.github+json' 2>/dev/null | jq '{required_status_checks,required_pull_request_reviews}' || true
curl -fsSL https://api.github.com/repos/rainlanguage/rain.math.float/actions/workflows \
-H 'Accept: application/vnd.github+json' 2>/dev/null | jq -r '.workflows[] | [.name,.path,.state] | `@tsv`' || trueRepository: rainlanguage/rain.math.float Length of output: 10104 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- referenced reusable Solidity test workflow ---'
curl -fsSL https://raw.githubusercontent.com/rainlanguage/rainix/main/.github/workflows/rainix-sol-test.yaml | sed -n '1,320p'
printf '%s\n' '--- referenced reusable Solidity static workflow ---'
curl -fsSL https://raw.githubusercontent.com/rainlanguage/rainix/main/.github/workflows/rainix-sol-static.yaml | sed -n '1,240p'
printf '%s\n' '--- repository workflow runs and check conclusions ---'
curl -fsSL 'https://api.github.com/repos/rainlanguage/rain.math.float/actions/runs?per_page=10' \
-H 'Accept: application/vnd.github+json' |
jq -r '.workflow_runs[] | [.name,.event,.head_branch,.status,.conclusion,.created_at] | `@tsv`'Repository: rainlanguage/rain.math.float Length of output: 8679 Exclude
🤖 Prompt for AI Agents |
||
|
|
||
| **Two deployment suites** (log-tables must be deployed first if redeploying | ||
| tables): | ||
|
|
@@ -77,12 +82,17 @@ DEPLOYMENT_KEY=<key> DEPLOYMENT_SUITE=log-tables forge script script/Deploy.sol: | |
| DEPLOYMENT_KEY=<key> DEPLOYMENT_SUITE=decimal-float forge script script/Deploy.sol:Deploy --broadcast --verify | ||
| ``` | ||
|
|
||
| Expected addresses and code hashes are in | ||
| `src/lib/deploy/LibDecimalFloatDeploy.sol`. Any source change to | ||
| `LibDecimalFloat` or `LibFormatDecimalFloat` invalidates these constants; CI's | ||
| `testDeployAddress` and `testExpectedCodeHashDecimalFloat` will fail until | ||
| they're regenerated and committed. Network RPC URLs are configured in | ||
| `foundry.toml` via `CI_DEPLOY_*_RPC_URL` env vars. | ||
| Expected addresses and code hashes are generated, never hand-written. Each | ||
| release freezes its own record under `src/generated/<tag>/` (tag = | ||
| `[package].version` from `foundry.toml`, dots as underscores) and the current | ||
| build's record sits in `src/generated/`; | ||
| `src/lib/deploy/LibDecimalFloatDeploy.sol` only aliases the current release's. | ||
| Any source change to `LibDecimalFloat` or `LibFormatDecimalFloat` changes the | ||
| deployed bytecode, so `script/Build.sol` must be re-run and its output | ||
| committed. `LibDecimalFloatDeployTaggedConstantsTest` re-derives every frozen | ||
| record from its own bytecode offline — no network, no skips — and fails if the | ||
| library constants drift from the current release's snapshot. Network RPC URLs | ||
| are configured in `foundry.toml` via `CI_DEPLOY_*_RPC_URL` env vars. | ||
|
|
||
| ## Architecture | ||
|
|
||
|
|
@@ -105,8 +115,8 @@ they're regenerated and committed. Network RPC URLs are configured in | |
|
|
||
| - **`Deploy.sol`** — Production deployment script using Zoltu deterministic | ||
| proxy. Deploys log tables and DecimalFloat contract to all supported networks. | ||
| - **`BuildPointers.sol`** — Generates `src/generated/LogTables.pointers.sol` | ||
| (committed to repo; must be regenerated if log table data changes). | ||
| - **`Build.sol`** — Generates `src/generated/LogTables.sol` (committed to repo; | ||
| must be regenerated if log table data changes). | ||
|
|
||
| ### Rust Layer (`crates/float/`) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| // SPDX-License-Identifier: LicenseRef-DCL-1.0 | ||
| // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd | ||
| pragma solidity =0.8.25; | ||
|
|
||
| import {Script} from "forge-std-1.16.1/src/Script.sol"; | ||
| import {LibCodeGen} from "rain-sol-codegen-0.1.4/src/lib/LibCodeGen.sol"; | ||
| import {LibFs} from "rain-sol-codegen-0.1.4/src/lib/LibFs.sol"; | ||
| import {LibSnapshot} from "rain-sol-codegen-0.1.4/src/lib/LibSnapshot.sol"; | ||
| import {LibDataContract} from "rain-datacontract-0.1.0/src/lib/LibDataContract.sol"; | ||
| import {LibRainDeploy} from "rain-deploy-0.1.3/src/lib/LibRainDeploy.sol"; | ||
| import {LibLogTable} from "../src/lib/table/LibLogTable.sol"; | ||
| import {LibDecimalFloatDeploy} from "../src/lib/deploy/LibDecimalFloatDeploy.sol"; | ||
| import {DecimalFloat} from "../src/concrete/DecimalFloat.sol"; | ||
|
|
||
| contract Build is Script { | ||
| /// @notice The log/antilog lookup table data consumed by | ||
| /// `LibDecimalFloatDeploy.combinedTables()`. This is source data, not a | ||
| /// deployment record, so it is not part of the per-release snapshot. | ||
| function buildLogTablesData() internal { | ||
| LibFs.buildFileForContract( | ||
| vm, | ||
| address(0), | ||
| "LogTables", | ||
| string.concat( | ||
| LibCodeGen.bytesConstantString( | ||
| vm, "/// @dev Log tables.", "LOG_TABLES", LibLogTable.toBytes(LibLogTable.logTableDec()) | ||
| ), | ||
| LibCodeGen.bytesConstantString( | ||
| vm, | ||
| "/// @dev Log tables small.", | ||
| "LOG_TABLES_SMALL", | ||
| LibLogTable.toBytes(LibLogTable.logTableDecSmall()) | ||
| ), | ||
| LibCodeGen.bytesConstantString( | ||
| vm, | ||
| "/// @dev Log tables small alt.", | ||
| "LOG_TABLES_SMALL_ALT", | ||
| LibLogTable.toBytes(LibLogTable.logTableDecSmallAlt()) | ||
| ), | ||
| LibCodeGen.bytesConstantString( | ||
| vm, | ||
| "/// @dev Anti log tables.", | ||
| "ANTI_LOG_TABLES", | ||
| LibLogTable.toBytes(LibLogTable.antiLogTableDec()) | ||
| ), | ||
| LibCodeGen.bytesConstantString( | ||
| vm, | ||
| "/// @dev Anti log tables small.", | ||
| "ANTI_LOG_TABLES_SMALL", | ||
| LibLogTable.toBytes(LibLogTable.antiLogTableDecSmall()) | ||
| ) | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| /// @notice The deployment record for one deployable: its Zoltu-deterministic | ||
| /// address, the creation bytecode it is deployed FROM, and the runtime | ||
| /// bytecode it is verified AGAINST on-chain. `LibFs` prepends `BYTECODE_HASH` | ||
| /// derived from the passed instance, so the record is complete — address + | ||
| /// codehash + creation + runtime. A pin carrying only address + codehash | ||
| /// cannot reproduce or independently verify a past release. | ||
| /// | ||
| /// One file PER contract: `BYTECODE_HASH` identifies a single instance, so | ||
| /// combining two deployables into one file would leave it meaningless. | ||
| function buildDeployRecordFor(string memory contractName, bytes memory creationCode, address deployed) internal { | ||
| LibFs.buildFileForContract( | ||
| vm, | ||
| deployed, | ||
| contractName, | ||
| string.concat( | ||
| LibCodeGen.addressConstantString( | ||
| vm, | ||
| "/// @dev Address of the contract deployed via Zoltu's deterministic\n" | ||
| "/// deployment proxy. Identical across all EVM-compatible networks.", | ||
| "DEPLOYED_ADDRESS", | ||
| deployed | ||
| ), | ||
| LibCodeGen.bytesConstantString( | ||
| vm, "/// @dev The creation bytecode of the contract.", "CREATION_CODE", creationCode | ||
| ), | ||
| LibCodeGen.bytesConstantString( | ||
| vm, "/// @dev The runtime bytecode of the contract.", "RUNTIME_CODE", deployed.code | ||
| ) | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| /// @notice This release's deployment record: both deployables, each in its | ||
| /// own generated file. Every address is a pure function of its creation code | ||
| /// (Zoltu CREATE2), so the whole record is computed offline through a locally | ||
| /// etched factory. Frozen per release by `LibSnapshot`. | ||
| function buildDeployRecords() internal { | ||
| // The log tables must land first: DecimalFloat's constructor calls | ||
| // `checkLogTablesDeployed()`, which reads the codehash at their address. | ||
| bytes memory logTablesCreationCode = | ||
| LibDataContract.contractCreationCode(LibDecimalFloatDeploy.combinedTables()); | ||
| buildDeployRecordFor("LogTablesDeploy", logTablesCreationCode, LibRainDeploy.deployZoltu(logTablesCreationCode)); | ||
|
|
||
| bytes memory decimalFloatCreationCode = type(DecimalFloat).creationCode; | ||
| buildDeployRecordFor( | ||
| "DecimalFloatDeploy", decimalFloatCreationCode, LibRainDeploy.deployZoltu(decimalFloatCreationCode) | ||
| ); | ||
| } | ||
|
|
||
| /// @notice The generated files that make up this release's deployment | ||
| /// record, frozen per release tag by `LibSnapshot`. The log-tables DATA is | ||
| /// deliberately absent: it is source input, not a deployment record. | ||
| function snapshotContractNames() internal pure returns (string[] memory names) { | ||
| names = new string[](2); | ||
| names[0] = "LogTablesDeploy"; | ||
| names[1] = "DecimalFloatDeploy"; | ||
| } | ||
|
|
||
| function run() external { | ||
| LibRainDeploy.etchZoltuFactory(vm); | ||
|
|
||
| buildLogTablesData(); | ||
| buildDeployRecords(); | ||
|
|
||
| // Freeze this release's record into `src/generated/<tag>/`. The tag, the | ||
| // freeze and the guard that refuses to rewrite a frozen record without a | ||
| // `[package].version` bump all live in the shared `LibSnapshot` — this | ||
| // repo does not carry its own copy. | ||
| LibSnapshot.freezeSnapshot(vm, snapshotContractNames()); | ||
| } | ||
| } |
This file was deleted.
This file was deleted.
Large diffs are not rendered by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
Repository: rainlanguage/rain.math.float
Length of output: 24809
🏁 Script executed:
Repository: rainlanguage/rain.math.float
Length of output: 8686
🏁 Script executed:
Repository: rainlanguage/rain.math.float
Length of output: 10161
🏁 Script executed:
Repository: rainlanguage/rain.math.float
Length of output: 6836
🏁 Script executed:
Repository: rainlanguage/rain.math.float
Length of output: 1310
🌐 Web query:
GitHub Actions workflow_dispatch run workflow on selected branch actions/checkout default ref github.ref💡 Result:
When you trigger a workflow manually using the workflow_dispatch event, GitHub Actions sets the github.ref context to the reference (branch or tag) you selected when initiating the run [1][2]. By default, the actions/checkout action automatically uses this github.ref value [3][4][5]. If you do not explicitly define a ref parameter in your checkout step, the action will check out the branch or tag that triggered the workflow [3][4]. For example: - uses: actions/checkout@v4 In this configuration, if you trigger the workflow on a branch named feature-xyz, actions/checkout will automatically check out feature-xyz [2][3]. If you wish to override this behavior and force the checkout of a specific branch (e.g., main or master) regardless of the branch selected during the manual trigger, you must explicitly set the ref parameter in your workflow file [2]: - uses: actions/checkout@v4 with: ref: main This ensures that the specified branch is checked out, ignoring the reference that triggered the event [2]. The internal logic of actions/checkout handles this by checking the input ref; if it is provided, it uses that value, and if it is omitted, it defaults to the event's reference (or the repository's default branch if no trigger context is available) [4][5].
Citations:
🏁 Script executed:
Repository: rainlanguage/rain.math.float
Length of output: 385
Restrict the deployment ref before loading
PRIVATE_KEY.The manual workflow runs the selected branch or tag and maps
PRIVATE_KEYtoDEPLOYMENT_KEYforscript/Deploy.sol. Restrict dispatches to protected release tags or reviewed commits, or validate the ref before loading the key.🤖 Prompt for AI Agents