Open Source · ESP32 · Nervos CKB

ckb-light-esp
#include <LightClient.h>

First C/Arduino implementation of the CKB light client protocol. Watch any CKB address from ESP32 hardware — no cloud, no custodian, no trust required. Modular transports. From a $3 C6 to a full P4 node with RISC-V script execution.

ESP32 / S3 / C6 / P4 Nervos CKB WiFi · LoRa · LoRaWAN MIT License
View on GitHub Quick Start Roadmap

The Wyltek Embedded Stack

Three repos. One coherent platform for CKB on embedded hardware.

🔧 wyltek-embedded-builder Board targets, peripheral defines, 32+ boards
↑ depends on
🔐 CKB-ESP32 Blake2b, Eaglesong, secp256k1, Molecule, RPC client
↑ depends on
📡 ckb-light-esp ← this repo Light client node — header sync, filter, Merkle proofs, UTXO tracking

Quick Start

Add to your platformio.ini:

lib_deps =
    toastmanAu/CKB-ESP32
    toastmanAu/ckb-light-esp
    bblanchon/ArduinoJson @ ^7.0.0

Then in your sketch:

#define LIGHT_PROFILE_STANDARD   // ESP32-S3 with PSRAM
#include <LightClient.h>

LightClient client;

void setup() {
  WiFi.begin("ssid", "pass");
  client.begin("192.168.1.100", 9000);  // CKB light client node RPC

  client.watchScript(
    "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8",
    "0xYOUR_LOCK_ARGS"
  );
}

void loop() {
  client.sync();   // non-blocking state machine

  if (client.hasPendingEvents()) {
    char txHash[67]; uint64_t block;
    while (client.nextEvent(txHash, &block))
      Serial.printf("💰 CKB received at block #%llu\n  TX: %s\n", block, txHash);
  }
}

The backend is the Nervos CKB light client node (Rust, runs on a Pi or server). Your ESP talks to its JSON-RPC interface — no P2P from the device.

Build Profiles

One #define before #include selects your profile. Everything else is handled.

LIGHT_MINIMAL
ESP32-C6 / ESP32 classic
  • Header sync + PoW verify
  • Address watch (2 scripts)
  • GPIO trigger on receive
  • Merkle proofs
  • UTXO storage
LIGHT_STANDARD
ESP32-S3 + PSRAM
  • Header sync + PoW verify
  • 16 watched scripts
  • Merkle proof verification
  • Persistent UTXO store
  • CKB-VM
LIGHT_FULL
ESP32-P4 (32MB PSRAM)
  • Everything in STANDARD
  • CKB-VM RISC-V interpreter
  • Custom lock scripts
  • Native secp256k1/multisig
LIGHT_LORA
Any ESP32 + SX1276
  • Header sync over LoRa
  • Private point-to-point
  • 5–40km range
  • No WiFi needed
LIGHT_LORAWAN
TTGO T-Beam
  • LoRaWAN OTAA join
  • TTN / Chirpstack
  • GPS + 18650 battery
  • No private gateway needed

Transports

Same LightClient API regardless of transport. Swap at compile time.

WiFi
TCP JSON-RPC

Direct to CKB light client node RPC (port 9000).

Home, office, LAN-connected devices.

Raw LoRa
Point-to-point

Pi/server gateway ↔ device. Your infrastructure.

Off-grid setups — shed, remote sensor, no internet.

LoRaWAN
TTN / Chirpstack

OTAA join, public network.

Ship a product — user points at TTN, no gateway setup.

Cellular
SIM7080G / A7670

NB-IoT / LTE-M. Global. Planned.

Matches boards in wyltek-embedded-builder.

Implementation Notes

Things that will trip up anyone implementing CKB from spec alone — documented here so you don't have to rediscover them.

ComponentWhat you need to know
RawHeaderMolecule struct, not table — 192 bytes flat, no length prefix or offset table
NonceRPC returns "0x" + hex(u128_big_endian) — reverse the 16 bytes for Eaglesong input
Eaglesong outputBig-endian bytes — compare result[0] first (not LE as mining pools use)
transactions_rootmerge(txs_CBMT_root, witnesses_root) — NOT just CBMT of tx hashes
Proof field nameCalled lemmas in CKB RPC, not siblings as in RFC 0006
GCS hash functionSipHash-2-4 (not Blake2b) — constants M, P from the golomb_coded_set spec
Filter syncCheckpoint-based initial sync — download checkpoints first, then filters from script's block_number
Backend nodeRequires CKB light client node (port 9000) — full nodes don't serve block filters

Roadmap

✓ Complete Phase 1 — Core verification
  • header_chain.cpp — Eaglesong PoW, Molecule serialisation, block hash
  • merkle.cpp — CBMT proof verification, transactions_root, witnesses_root
  • Build profiles: MINIMAL / STANDARD / FULL / LORA / LORAWAN
  • Transport stubs: WiFi, raw LoRa, LoRaWAN, cellular
  • Host test suite — all verified against live mainnet
In Progress Phase 2 — Transport + sync loop
  • wifi_transport.cpp — TCP JSON-RPC to CKB light client node
  • LightClient.cpp — sync state machine
  • block_filter.cpp — GCS filter sync (SipHash-2-4, checkpoint-based)
  • utxo_store.cpp — persistent UTXO set (NVS/LittleFS)
Planned Phase 3 — Script execution
  • native_locks.cpp — secp256k1 / multisig / ACP without VM
  • ckbvm_interp.cpp — minimal RISC-V interpreter (ESP32-P4 / S3 + PSRAM)
Planned Phase 4 — Off-grid transports
  • lora_transport.cpp — raw LoRa bridge implementation
  • lorawan_transport.cpp — OTAA + LMIC (TTGO T-Beam)
  • ckb-lora-bridge — companion Pi/server gateway repo
  • cellular_transport.cpp — SIM7080G / A7670
Planned Phase 5 — Example products
  • CKB Payment Terminal — ESP32 + display, QR invoices, on-chain confirmation
  • Off-grid Balance Checker — T-Beam, LoRaWAN, e-paper, battery powered
  • LoRa ASIC Relay — Stratum bridge for miners with no direct internet
  • IoT Payment Trigger — C6, one address, GPIO on receive (door, vending, etc.)