Skip to content

feat(runtime): implement payment receipt signing#11

Merged
simonovic86 merged 1 commit intomainfrom
claude/naughty-lederberg
Mar 4, 2026
Merged

feat(runtime): implement payment receipt signing#11
simonovic86 merged 1 commit intomainfrom
claude/naughty-lederberg

Conversation

@simonovic86
Copy link
Owner

Overview

Implements cryptographic payment receipts (Task 10, Phase 4: Economics). Nodes now sign and persist receipts attesting to agent execution costs, enabling auditable payment trails.

Key Changes

Receipt Infrastructure

  • pkg/receipt/ — Payment receipt data structure with Ed25519 signing and binary serialization
  • internal/storage/ — Receipt persistence (SaveReceipts/LoadReceipts/DeleteReceipts)
  • internal/hostcall/wallet.go — Wallet hostcall implementations:
    • wallet_balance() — Returns current budget in microcents (observation)
    • wallet_receipt_count() — Returns number of accumulated receipts (observation)
    • wallet_receipt(index, buf, len) — Copies receipt at index into buffer (observation)

Agent Lifecycle Integration

  • internal/agent/instance.go — Receipt creation per checkpoint epoch with cost tracking; receipts loaded/saved alongside checkpoints
  • internal/migration/service.go — Receipts travel with agents during migration; signing key extracted from libp2p host
  • cmd/igord/main.go — Node signing key passed to agent loader

Replay & Verification

  • internal/replay/engine.go — Wallet hostcall replay support for deterministic verification (CE-3)
  • internal/eventlog/eventlog.go — Added wallet hostcall event types

SDK & Testing

  • sdk/igor/ — Hostcall wrappers and mocks for agent development
  • internal/simulator/hostcalls.go — Simulator wallet support (balance only, no receipts)
  • Updated all agent loading tests to pass signing key and node ID parameters

Documentation

  • docs/runtime/HOSTCALL_ABI.md — Wallet function signatures and replay behavior
  • docs/governance/ROADMAP.md — Task 10 marked complete; Phase 4 in progress
  • CLAUDE.md — Updated architecture overview with receipt module

Design Highlights

  • Cryptographic proof: Receipts signed by node's Ed25519 peer key; anyone with public key can verify
  • Deterministic replay: All wallet hostcalls recorded in event log for replay verification
  • Migration continuity: Receipts persist across agent migrations for unbroken audit trail
  • Observation hostcalls: All wallet operations are read-only observations (idempotent, replayable)
  • Backward compatible: Signing key is optional; nil key disables receipt creation

Testing

  • Receipt save/load/delete tests with atomic semantics
  • Updated checkpoint/resume tests
  • Replay engine wallet integration tests

Add cryptographic payment receipts for Phase 4 (Economics). Nodes sign
Ed25519 receipts after each checkpoint epoch attesting execution cost.
Agents introspect receipts via wallet hostcalls. Receipts travel with
agents during migration for audit trail continuity.

New packages:
- pkg/receipt: Receipt type, binary serialization, Ed25519 sign/verify
- internal/hostcall/wallet.go: WalletState interface + 3 wallet hostcalls

Key changes:
- wallet_balance, wallet_receipt_count, wallet_receipt hostcalls (CM-4 observation)
- Receipt creation per checkpoint epoch with cost tracking
- Receipt persistence (SaveReceipts/LoadReceipts/DeleteReceipts)
- Wallet replay support for single-tick and chain replay
- Receipts included in AgentPackage for migration
- SDK wrappers, mocks, and simulator support
- "wallet" added to NodeCapabilities

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@simonovic86 simonovic86 merged commit 4bc6e2b into main Mar 4, 2026
1 check passed
@simonovic86 simonovic86 deleted the claude/naughty-lederberg branch March 4, 2026 04:30
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fbba3902b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +47 to +49
if err != nil {
r.logger.Warn("wallet_receipt: invalid index", "index", index, "error", err)
return -1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Record failed wallet_receipt calls for replay

wallet_receipt returns -1 on invalid index without writing any event-log entry, but replay always consumes a WalletReceipt entry for each call; this causes deterministic replay to fail for agents that probe unavailable receipts (or any path where the runtime returns an error instead of payload bytes). The hostcall should still record an entry that encodes the failure outcome so replay can reproduce the same return value.

Useful? React with 👍 / 👎.

Comment on lines +638 to +640
if len(receipts) > 0 {
i.lastReceiptTick = receipts[len(receipts)-1].EpochEnd
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Seed receipt epoch start when no receipts are restored

lastReceiptTick is only set from the restored receipt chain; when an agent resumes from an existing checkpoint that has no receipts (the documented backward-compatible path), TickNumber is restored but lastReceiptTick stays 0, so the next signed receipt claims an epoch starting at tick 1 even though epochCost only includes post-resume work. That produces incorrect signed accounting ranges after upgrade/migration from pre-receipt checkpoints.

Useful? React with 👍 / 👎.

Comment on lines +93 to +95
func (w *walletStateRef) GetBudget() int64 { return w.instance.Budget }
func (w *walletStateRef) GetReceiptCount() int {
return len(w.instance.Receipts)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard wallet state access before instance wiring

walletStateRef dereferences w.instance unconditionally, but the reference is wired after module instantiation and _initialize execution; if agent initialization code invokes wallet_* during that phase, this path panics with a nil dereference. Add a nil guard (or wire state before any initialization callbacks) so wallet-enabled agents cannot crash during load.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant