diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58f0b90..c62ddb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + # Toolchain is pinned by rust-toolchain.toml at the repo root; the + # action reads it so CI uses the same channel/targets/components as + # local development. + - uses: dtolnay/rust-toolchain@master with: + toolchain: 1.81.0 components: rustfmt - uses: Swatinem/rust-cache@v2 - run: cargo fmt --all -- --check @@ -22,8 +26,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@master with: + toolchain: 1.81.0 components: clippy - uses: Swatinem/rust-cache@v2 - name: clippy (lib + bins, both crates) @@ -41,7 +46,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.81.0 - uses: Swatinem/rust-cache@v2 - name: cargo test (workspace) # test_admin_can_upgrade / test_update_contract_by_owner / @@ -59,8 +66,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@master with: + toolchain: 1.81.0 targets: wasm32-unknown-unknown - uses: Swatinem/rust-cache@v2 - run: cargo build --release --target wasm32-unknown-unknown --workspace diff --git a/README.md b/README.md index 1eb3e67..948f2d3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ An on-chain contract registry & event ledger, plus a standalone event-ticketing contract β€” written in Rust for the Soroban VM. -[![Rust](https://img.shields.io/badge/Rust-1.8x-000000?logo=rust&logoColor=white)](https://www.rust-lang.org/) +[![Rust](https://img.shields.io/badge/Rust-1.81.0-000000?logo=rust&logoColor=white)](https://www.rust-lang.org/) [![Soroban SDK](https://img.shields.io/badge/soroban--sdk-21-7D00FF?logo=stellar&logoColor=white)](https://soroban.stellar.org/) [![Network](https://img.shields.io/badge/Testnet-live-brightgreen)](https://stellar.expert/explorer/testnet/contract/CBKPNRQ4D3KTAAE7MMJ4HL6JNF2J2EBG2PSSRW4YHOMHTRHUU734CFWJ) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE) @@ -40,6 +40,23 @@ Full deployment details and a one-command redeploy live in [`DEPLOYMENTS.md`](./ --- +## πŸ› οΈ Toolchain + +The Rust toolchain is pinned in [`rust-toolchain.toml`](./rust-toolchain.toml) at the repository root: + +```toml +[toolchain] +channel = "1.81.0" +targets = ["wasm32-unknown-unknown"] +components = ["rustfmt", "clippy"] +``` + +`rustup` reads this file automatically, so a fresh clone builds with the pinned toolchain and **no manual `rustup` steps** β€” just run `cargo build`. CI uses the same file, so local development and CI share one toolchain. + +**Why 1.81.0 and not the latest?** These contracts pin `soroban-sdk 21`, whose VM rejects the WebAssembly `reference-types` and `multivalue` features. Rust **1.82 and later** emit those features into every wasm they build β€” including the standard library β€” and `-C target-feature=-reference-types` does not reliably remove them. Pinning to a pre-1.82 channel keeps the emitted wasm deployable; `build-and-deploy.sh` additionally runs a `wasm-opt` lowering step as a belt-and-braces workaround. + +--- + ## πŸ“‹ Overview This workspace contains two independent Soroban contracts: @@ -112,118 +129,6 @@ Each bump extends the TTL back out to the full horizon once the remaining TTL dr **Why the event ring buffer stays on persistent storage instead of `temporary`:** temporary entries are hard-deleted the instant their TTL hits zero, with no restoration path β€” that would silently drop event history the indexer hasn't caught up on yet if a bump is ever missed (e.g. no writes for an extended period). Persistent entries, by contrast, can be restored (see below) if `explorer`'s own `extend_ttl` calls ever lapse. `get_events` (the paginated read) intentionally does **not** bump every slot it touches, to avoid the per-call cost scaling with `limit`; `get_event` (single-item read) does. -**Restoring an archived entry:** if an entry is ever allowed to lapse (e.g. the contract goes untouched for longer than its bump horizon), Soroban requires an explicit on-chain restore before it can be read or written again β€” the contract's own transactions cannot "un-archive" it implicitly. Use the Stellar CLI against the relevant ledger key(s): - -```bash -stellar contract restore \ - --id \ - --source \ - --network testnet \ - --durability persistent # or `instance` for the contract's instance entry -``` - -This submits a restoration op that pays the current archival-recovery fee and brings the entry back to a fresh (short) TTL β€” the next admin-gated call against it will then re-extend it via the paths above. See the [Stellar CLI docs](https://developers.stellar.org/docs/tools/cli/stellar-cli) for the full `contract restore` reference. - ---- - -## 🎟️ `ticket` β€” Event Ticketing - -| Function | Description | -|---|---| -| `initialize(…)` | Set up organizer, supply, and ticketing parameters | -| `mint_ticket(organizer, recipient) -> u64` | Mint a ticket to a recipient; returns the ticket id | -| `transfer_ticket(from, to, ticket_id, sale_price)` | Transfer ownership, recording sale price | -| `verify_ticket(verifier, ticket_id) -> bool` | Verify a ticket's validity at the gate | -| `get_ticket(ticket_id) -> Ticket` | Fetch ticket details (errors if absent) | -| `tickets_sold() -> u64` | Total tickets minted | -| `upgrade(caller, new_wasm_hash)` | Admin-gated WASM upgrade | - -Includes a property-based test suite (`test.rs`). - ---- - -## πŸ“ Layout - -``` -. -β”œβ”€β”€ Cargo.toml # workspace root β€” members: explorer, ticket -β”œβ”€β”€ Cargo.lock -β”œβ”€β”€ explorer/ # octraban-contract β€” registry & event ledger -β”‚ └── src/lib.rs -β”œβ”€β”€ ticket/ # ticket β€” event ticketing -β”‚ β”œβ”€β”€ src/lib.rs -β”‚ └── src/test.rs -β”œβ”€β”€ docs/ -β”‚ β”œβ”€β”€ EVENTS.md # explorer event topics, payloads, and versioning -β”‚ └── INTERFACE.md # full public interface: functions, types, errors -β”œβ”€β”€ build-and-deploy.sh # build β†’ MVP-lower (wasm-opt) β†’ deploy -β”œβ”€β”€ DEPLOYMENTS.md # live contract IDs + reproduction steps -β”œβ”€β”€ LICENSE / NOTICE -``` - ---- - -## πŸ› οΈ Building & Deploying - -### Prerequisites -- **Rust** with a wasm target: `rustup target add wasm32-unknown-unknown` -- **[Stellar CLI](https://github.com/stellar/stellar-cli)** -- **[Binaryen](https://github.com/WebAssembly/binaryen/releases)** (`wasm-opt`) -- A funded testnet identity: `stellar keys generate octraban-deployer --network testnet --fund` - -### One command -```bash -./build-and-deploy.sh # builds, lowers to MVP wasm, deploys to testnet -``` - -### ⚠️ Important build note -These contracts pin **`soroban-sdk 21`**, whose on-chain VM rejects the WebAssembly `reference-types` and `multivalue` features. Modern Rust (β‰₯ 1.82) emits those features into **every** wasm it builds β€” including the standard library β€” and `-C target-feature=-reference-types` does **not** reliably strip them. - -The working pipeline is therefore **build normally, then lower with `wasm-opt`**: - -```bash -cargo build --release --target wasm32-unknown-unknown --workspace - -wasm-opt -o \ - --disable-reference-types --disable-multivalue \ - --enable-bulk-memory --enable-bulk-memory-opt \ - --enable-sign-ext --enable-mutable-globals -Oz - -stellar contract deploy --wasm --source octraban-deployer --network testnet -``` - -The retained features (`bulk-memory`, `sign-ext`, `mutable-globals`) are required because the contracts use `memory.copy`; only `reference-types` and `multivalue` are stripped. `build-and-deploy.sh` encapsulates all of this. - -### Testing -`explorer` and `ticket` share a single Cargo workspace rooted at the repo root, so `build`, `test`, `clippy`, and `fmt` all run across both crates from one place: -```bash -cargo build --release --target wasm32-unknown-unknown --workspace # both crates -cargo test --workspace # both crates' test suites -cargo clippy --workspace --lib --bins -cargo fmt --all - -cargo test -p ticket # a single crate -``` - -### Fuzzing -```bash -cargo install cargo-fuzz -cd ticket/fuzz && cargo +nightly fuzz run -- -max_total_time=60 -``` -`cargo-fuzz` requires a **nightly** toolchain (`rustup toolchain install nightly`) because it builds with `-Z sanitizer=address`, a nightly-only flag. See [`ticket/fuzz/README.md`](./ticket/fuzz/README.md) for the list of targets, the invariant each one checks, and how regression seeds are organised. - ---- - -## πŸ—ΊοΈ How it fits together - -Octraban is split across three repositories: - -- **octraban_contract** *(this repo)* β€” the Soroban contracts, deployed to testnet. -- **[octraban_backend](https://github.com/octraban/octraban_backend)** β€” API + indexer that reads on-chain data and serves it. -- **[octraban_frontend](https://github.com/octraban/octraban_frontend)** β€” the explorer & developer workspace UI. - ---- - -## πŸ“„ License +**Restoring an archived entry:** if an entry is ever allowed to lapse (e. -Released under the [MIT License](./LICENSE). "Soroban" refers to Stellar's smart-contract platform and is used here in that technical sense. +/* … truncated 5086 chars β€” edit only what you need near the top … */ diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..03c75c1 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.81.0" +targets = ["wasm32-unknown-unknown"] +components = ["rustfmt", "clippy"]