Sol.College

Full lesson

Alight

Alight is a self-hosted observatory that sends small, budgeted test transactions called canaries through Solami

What it does

From the project README:

Bots, wallets and trading backends must choose a route, priority fee and tip before knowing whether a transaction will arrive in time. An RPC acknowledgment cannot answer that question, and a successful landing can still miss the deadline.
Original
hicksonhaziel/Alight
SuperStack fork
Blockchains/Alight @ 759a597
Stars
0
Last push (original)
2026-10-13
Languages
Rust, TypeScript, Python, CSS, JavaScript, Shell
Detected stack
not detected
Categories
Infrastructure & Tooling
Licence
MIT

Architecture

183 source files. By extension: .rs ×125, .py ×25, .ts ×17, .tsx ×14, .js ×2.

Top-level directorySource files
crates106
web28
scripts25
bin19
sdk5

Dapp: devnet deploy pending

⏳ Devnet deploy pending — goes live when the devnet wallet is topped up. This fork's own dapp is not deployed yet, so there is no program address or transaction to show. It is queued in dapp-queue.txt; once devnet SOL is available it is deployed, exercised with real devnet transactions, and this section switches to the live dapp at /dapps/alight/. Until then, the lesson and step-by-step guide below are complete, and you can run it locally with the commands below.

Key code, explained

Excerpts chosen automatically where the code uses the most Solana concepts, pinned to the fork's commit.

hicksonhaziel/Alight · crates/alight-types/src/lib.rs L97–120 @ 759a597 · MIT · original
    /// Coarse block timestamps require a long window and do not measure first-seen latency.    pub fn mean_slot_ms(self) -> Option<f64> {        let slots = self.end_slot.checked_sub(self.start_slot)?;        let seconds = self.end_unix_s.checked_sub(self.start_unix_s)?;        if slots == 0 || seconds <= 0 {            return None;        }        Some(seconds as f64 * 1000.0 / slots as f64)    }} #[cfg(test)]mod tests {    use super::*;    #[test]    fn one_process_has_one_comparable_monotonic_origin() {        let (a, start) = process_clock_origin();        let (b, second) = process_clock_origin();        assert_eq!(a, b);        assert_eq!(start, second);    }     #[test]    fn expiry_needs_both_strict_height_and_absence() {
  1. Line 99 let slots = self.end_slot.checked_sub(self.start_slot)?;: Uses checked arithmetic so overflow fails instead of wrapping.
  2. Line 112 fn one_process_has_one_comparable_monotonic_origin() {: Checks that a stored pubkey field matches the passed account.
hicksonhaziel/Alight · crates/alight-ingest/src/leaders.rs L61–84 @ 759a597 · MIT · original
            if bs58::decode(identity)                .into_vec()                .map_or(true, |b| b.len() != 32)            {                return Err(ProbeError::Format);            }            for relative in relative_slots.as_array().ok_or(ProbeError::Format)? {                let relative = relative                    .as_u64()                    .filter(|s| *s < slots_in_epoch)                    .ok_or(ProbeError::Format)?;                let slot = first_slot.checked_add(relative).ok_or(ProbeError::Format)?;                if slots.insert(slot, identity.clone()).is_some() {                    return Err(ProbeError::Format);                }            }        }        if slots.len() as u64 != slots_in_epoch {            return Err(ProbeError::Format);        }        let mut stakes = BTreeMap::<String, u64>::new();        for group in ["current", "delinquent"] {            for vote in raw["getVoteAccounts"][group]                .as_array()
  1. Line 72 let slot = first_slot.checked_add(relative).ok_or(ProbeError::Format)?;: Uses checked arithmetic so overflow fails instead of wrapping.
  2. Line 81 let mut stakes = BTreeMap::<String, u64>::new();: Touches staking state: the amount locked and when it was locked.

How to run, build and test

These commands come from the repo's own manifests (package.json scripts, Anchor.toml, Cargo, go.mod, Makefile). Check the README for prerequisites and environment variables.

DirectoryCommandRuns
sdk/tsnpm run buildtsc -p tsconfig.json
sdk/tsnpm run testnpm run build && node --test test/*.mjs
sdk/tsnpm run linttsc -p tsconfig.check.json
webnpm run devvite --host 127.0.0.1
webnpm run buildtsc --noEmit && vite build
webnpm run testnode --experimental-strip-types --test test/*.ts
webnpm run linttsc --noEmit && eslint src
.cargo buildRust workspace build
.cargo testRust tests

What you could build from it