|
|
|
|
|
|
|
|
|
|
|
|
|
|
| export interface SealedEvent {
|
| index: number
|
| seal: string
|
| previousSeal: string
|
| payload: Record<string, unknown>
|
| timestampMs: number
|
| }
|
|
|
| export interface VerifyResult {
|
| valid: boolean
|
| failures: number[]
|
| merkleRoot: string
|
| eventCount: number
|
| error?: string
|
| }
|
|
|
|
|
|
|
| interface LedgeWasm {
|
| ledge_genesis(): string
|
| ledge_seal(prev: string, payload: string, ts: bigint, idx: bigint): string
|
| ledge_verify(events_json: string): string
|
| ledge_merkle_root(seals_json: string): string
|
| }
|
|
|
|
|
|
|
| export class LedgeChain {
|
| private events: SealedEvent[] = []
|
| private head: string
|
| private genesis: string
|
| private wasm: LedgeWasm
|
|
|
| constructor(wasm: LedgeWasm) {
|
| this.wasm = wasm
|
| this.genesis = wasm.ledge_genesis()
|
| this.head = this.genesis
|
| }
|
|
|
| seal(payload: Record<string, unknown>, timestampMs = Date.now()): SealedEvent {
|
| const index = this.events.length
|
| const payloadJson = JSON.stringify(payload)
|
| const seal = this.wasm.ledge_seal(
|
| this.head,
|
| payloadJson,
|
| BigInt(timestampMs),
|
| BigInt(index),
|
| )
|
|
|
| const event: SealedEvent = {
|
| index,
|
| seal,
|
| previousSeal: this.head,
|
| payload,
|
| timestampMs,
|
| }
|
|
|
| this.head = seal
|
| this.events.push(event)
|
| return event
|
| }
|
|
|
| verify(): VerifyResult {
|
| const result = JSON.parse(this.wasm.ledge_verify(JSON.stringify(this.events)))
|
| return result as VerifyResult
|
| }
|
|
|
| merkleRoot(): string {
|
| const seals = this.events.map(e => e.seal)
|
| return this.wasm.ledge_merkle_root(JSON.stringify(seals))
|
| }
|
|
|
| getEvents(): SealedEvent[] {
|
| return [...this.events]
|
| }
|
|
|
| getGenesis(): string {
|
| return this.genesis
|
| }
|
| }
|
|
|
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| export async function initLedge(wasmModule?: LedgeWasm): Promise<{
|
| createChain: () => LedgeChain
|
| genesis: () => string
|
| }> {
|
| let wasm: LedgeWasm
|
|
|
| if (wasmModule) {
|
| wasm = wasmModule
|
| } else {
|
|
|
| const mod = await import('../pkg/ledge.js' as string) as LedgeWasm & { default?: () => Promise<void> }
|
| if (mod.default) await mod.default()
|
| wasm = mod
|
| }
|
|
|
| return {
|
| createChain: () => new LedgeChain(wasm),
|
| genesis: () => wasm.ledge_genesis(),
|
| }
|
| }
|
|
|