diff --git a/chains/solana/README.md b/chains/solana/README.md index 289fdec8e4..195a136d70 100644 --- a/chains/solana/README.md +++ b/chains/solana/README.md @@ -1,28 +1,89 @@ # CCIP Solana Onchain -- `contracts`: solana programs (rust) + tests (go) built on the anchor framework -- `gobindings`: auto-generated go bindings for contracts using `anchor-go` -- `scripts`: various scripts for generating artifacts +## Project Structure + +- `contracts/` — Solana programs (Rust/Anchor) + integration tests (Go) + - `programs/` — Anchor program source code (ccip-router, fee-quoter, token pools, mcm, timelock, etc.) + - `tests/` — Go integration tests organized by area (`ccip/`, `mcms/`, `examples/`) + - `target/deploy/` — compiled `.so` program binaries and IDL JSON files + - `target/vendor/` — pre-built third-party program binaries (CCTP), committed to git +- `gobindings/` — auto-generated Go bindings for contracts using `anchor-go` +- `scripts/` — build and generation scripts (e.g. `anchor-go-gen.sh`) +- `utils/` — shared Go utility libraries ## Dependencies -- rust: https://www.rust-lang.org/tools/install -- go: https://go.dev/doc/install -- solana: https://docs.anza.xyz/cli/install -- anchor: https://www.anchor-lang.com/docs/installation +- [Rust](https://www.rust-lang.org/tools/install) (version pinned via `contracts/rust-toolchain.toml`) +- [Go](https://go.dev/doc/install) (see `go.mod` for required version) +- [Solana CLI](https://docs.anza.xyz/cli/install) (provides `solana-test-validator`) +- [Anchor CLI](https://www.anchor-lang.com/docs/installation) +- [anchor-go](https://github.com/gagliardetto/anchor-go) v0.2.3 — `GOTOOLCHAIN=go1.20 go install github.com/gagliardetto/anchor-go@v0.2.3` +- [golangci-lint](https://golangci-lint.run/welcome/install/) v2.7.0 — `go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.0` +- [gotestloghelper](https://github.com/smartcontractkit/chainlink-testing-framework) — for `make go-tests` output formatting + +### macOS (Apple Silicon) Note + +The `solana-test-validator` requires GNU tar. Without it, you'll see errors like +`Archive error: extra entry found: "._genesis.bin"`. Install it and put it on your PATH: + +```bash +brew install gnu-tar +export PATH="/opt/homebrew/opt/gnu-tar/libexec/gnubin:$PATH" +``` + +See [solana-labs/solana#35629](https://github.com/solana-labs/solana/issues/35629) for details. ## Development +### Build contracts + +```bash +# Build on the host (requires Anchor CLI + Solana CLI + Rust toolchain) +make build-contracts + +# Or build inside Docker for reproducibility +make docker-build-contracts +``` + +### Generate Go bindings + +After any contract changes, regenerate the Go bindings: + ```bash -# install anchor-go if needed -go install github.com/gagliardetto/anchor-go@v0.2.3 +make anchor-go-gen +``` + +This builds the contracts, then runs `anchor-go` against the IDL files to produce bindings in `gobindings/`. + +### Run tests + +```bash +# Go integration tests (spins up local solana-test-validator per test) +make go-tests + +# Rust unit tests +make rust-tests + +# Run a specific test suite +go test ./contracts/tests/ccip/ -run TestCCIPRouter -v -count=1 +go test ./contracts/tests/mcms/ -run TestMcmSetConfig -v -count=1 +go test ./contracts/tests/examples/ -run TestBaseTokenPoolHappyPath -v -count=1 +``` -# build contracts + IDL -anchor build +Note: Go integration tests require that contracts have been built (`make build-contracts`) +and that the vendor `.so` files exist in `contracts/target/vendor/`. -# go bindings need to be regenerated if contract changes were made -./scripts/anchor-go-gen.sh +### Format and lint -# test contracts -go test ./... -v -count=1 -failfast +```bash +make format # format Go + Rust +make lint-go # run golangci-lint ``` + +### Full CI check + +```bash +make solana-checks +``` + +This runs, in order: `clippy`, `anchor-go-gen`, `format`, `gomodtidy`, `lint-go`, `rust-tests`, `go-tests`, `build-contracts`. diff --git a/chains/solana/contracts/README.md b/chains/solana/contracts/README.md index 09242816ee..76d5af9c4f 100644 --- a/chains/solana/contracts/README.md +++ b/chains/solana/contracts/README.md @@ -1,97 +1,75 @@ -# Chainlink Solana contracts (programs) +# Chainlink Solana Contracts (Programs) ## Prerequisites -Install Rust, Solana & Anchor. See https://solana.com/docs/intro/installation +- [Rust](https://www.rust-lang.org/tools/install) (version pinned via `rust-toolchain.toml`) +- [Solana CLI](https://docs.anza.xyz/cli/install) (provides `solana-test-validator`) +- [Anchor CLI](https://www.anchor-lang.com/docs/installation) +- [Go](https://go.dev/doc/install) (see `go.mod` for required version) +- [anchor-go](https://github.com/gagliardetto/anchor-go) v0.2.3 — `GOTOOLCHAIN=go1.20 go install github.com/gagliardetto/anchor-go@v0.2.3` ## Build To build on the host: -``` +```bash anchor build +# or from the repo root: +make build-contracts ``` -To build inside a docker environment: +To build inside a Docker environment (reproducible builds): ```bash -anchor build --verifiable +make docker-build-contracts ``` -To build for a specific network, specify via a cargo feature: +## Test + +### Rust unit tests ```bash -anchor build -- --features mainnet +cargo test +# or from the repo root: +make rust-tests ``` -Available networks with declared IDs: - -- mainnet -- testnet -- devnet -- localnet (default) +### Go integration tests -## Test +The Go tests spin up a local `solana-test-validator`, deploy the compiled programs, and run +integration tests against them. -Make sure to run `pnpm i` to fetch mocha and other test dependencies. +Prerequisites: -Start a dockerized shell that contains Solana and Anchor: +- `solana-test-validator` installed and on your PATH +- Contracts built (`anchor build` or `make build-contracts`) +- Vendor programs present in `target/vendor/` (pre-built CCTP `.so` files, committed to git) ```bash -./scripts/anchor-shell.sh +# from the repo root: +make go-tests ``` -Next, generate a keypair for anchor: +To run specific test suites: ```bash -solana-keygen new -o id.json +go test ./tests/ccip/ -run TestCCIPRouter -v -count=1 +go test ./tests/mcms/ -run TestMcmSetConfig -v -count=1 +go test ./tests/examples/ -run TestBaseTokenPoolHappyPath -v -count=1 ``` -### Run anchor TypeScript tests (automatically tests against a local node) +Note: subtests within a single top-level `Test*` function share sequential state, so running +an individual subtest in isolation (e.g. `-run TestCCIPRouter/Config`) will likely fail because +earlier setup subtests won't have executed. -```bash -anchor test -``` - -### Run GoLang tests (automatically tests against a local node) +## Go bindings generation -Pre-requisites: - -- Have the `solana-test-validator` command installed -- Run `anchor build` if there have been any changes to the program under test. +Install `anchor-go` and regenerate bindings after contract changes: ```bash -make contracts-go-tests +GOTOOLCHAIN=go1.20 go install github.com/gagliardetto/anchor-go@v0.2.3 +make anchor-go-gen ``` -#### `anchor-go` bindings generation - -Install `https://github.com/gagliardetto/anchor-go` - -Current version: [v0.2.3](https://github.com/gagliardetto/anchor-go/tree/v0.2.3) - -To install `anchor-go` locally so that you can use the `anchor-go` command globally, follow these steps: - -1. **Clone the repository:** - - ```bash - git clone https://github.com/gagliardetto/anchor-go.git - cd anchor-go - git checkout v0.2.3 - ``` - -2. **Install the command globally:** - - Run the following command to install the `anchor-go` command globally: - - ```bash - go install - ``` - - This will install the `anchor-go` binary to your `$GOPATH/bin` directory. Make sure that this directory is included in your system's `PATH` environment variable. - -3. **Then run the following command to generate the Go bindings:** - - ```bash - make anchor-go-gen - ``` +This builds the contracts, generates Go bindings from the IDL files in `target/idl/` and +`target/vendor/`, and outputs them to `gobindings/`. diff --git a/chains/solana/contracts/rust-toolchain.toml b/chains/solana/contracts/rust-toolchain.toml new file mode 100644 index 0000000000..3c4b81ebf6 --- /dev/null +++ b/chains/solana/contracts/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.73.0" +components = ["clippy", "rustfmt"] diff --git a/chains/solana/scripts/anchor-go-gen.sh b/chains/solana/scripts/anchor-go-gen.sh index adc02e2aa2..4efb79fec6 100755 --- a/chains/solana/scripts/anchor-go-gen.sh +++ b/chains/solana/scripts/anchor-go-gen.sh @@ -2,6 +2,13 @@ set -e +# Ensure anchor-go v0.2.3 is installed. It requires Go <= 1.22 to compile, +# so we pin GOTOOLCHAIN=go1.20 for the install step. +if ! command -v anchor-go &>/dev/null; then + echo "anchor-go not found, installing v0.2.3..." + GOTOOLCHAIN=go1.20 go install github.com/gagliardetto/anchor-go@v0.2.3 +fi + function generate_bindings() { local idl_path_str="$1" IFS='/' read -r -a idl_path <<< "${idl_path_str}"