Problem System
This document defines daqq’s Problem System: the framework that turns daqq from a fixed “shared random quantum circuit” chain into a general platform where multiple problems can coexist, each consumed by the same shared randomness beacon, and each chosen freely by participants.
x/qcledger has been renamed to x/random_circuit and registers itself as Problem #1 in the new x/problems module at chain genesis. See random_circuit and problems for the module-level documentation.Goals
- Multiple problems can coexist on-chain. The current single-purpose ledger becomes one of many.
- Participants choose which problem to solve. No one is forced into a single round-wide problem.
- The shared beacon seed remains the common input. Every problem can read the same per-round seed.
- New problems are added through Cosmos upgrade governance. No on-chain WASM or dynamic code loading in the MVP.
- No problem is ever deleted. Stopped problems are flagged
enabled = false; their historical data stays valid forever.
Non-goals (for the MVP)
- On-chain user-supplied code (e.g., CosmWasm). The schema leaves room for this only conceptually.
- A single “winner” per round, scoring, or rewards.
- Cross-problem aggregation.
Architecture
graph LR
beacon["x/beacon<br/>(unchanged)<br/>shared seed per round"]
problems["x/problems<br/>(new)<br/>problem registry"]
rc["x/random_circuit<br/>problem #1: theoretical distribution"]
future["x/random_circuit_sampling<br/>(future)<br/>problem #2: sampling histograms"]
other["x/<your_problem><br/>(future)<br/>community-contributed"]
beacon -- "Seeds[roundID]" --> rc
beacon -- "Seeds[roundID]" --> future
beacon -- "Seeds[roundID]" --> other
rc -- "RegisterAt(genesis/upgrade)" --> problems
future -- "RegisterAt(genesis/upgrade)" --> problems
other -- "RegisterAt(genesis/upgrade)" --> problems
participant1["Participant A"]
participant2["Participant B"]
participant3["Participant C"]
participant1 -. "freely picks" .-> rc
participant2 -. "freely picks" .-> future
participant3 -. "freely picks" .-> other
Module responsibilities
| Module | Role |
|---|---|
x/beacon | Unchanged. Produces a 256-bit Seeds[roundID] per round. |
x/problems | New. Holds the registry of problems: ID, name, owning module, enabled flag, added round. |
x/random_circuit | The renamed x/qcledger. Implements Problem #1: theoretical output distribution of a randomly generated quantum circuit. |
x/<future_problems> | Future modules. Each registers itself into x/problems at genesis or upgrade time. |
Participant flow
sequenceDiagram
participant U as Participant
participant Reg as x/problems
participant B as x/beacon
participant P as x/random_circuit (Problem #1)
U->>Reg: QueryProblems()
Reg-->>U: [{id:1, name:"random_circuit"}, ...]
Note over U: participant picks one freely
U->>B: QuerySeed(roundID)
B-->>U: seed
U->>U: compute solution locally
U->>P: MsgSubmitSolution{roundID, ...}
P->>B: GetSeed(roundID)
B-->>P: seed
P->>P: validate & store
P-->>U: ack
Each problem module owns its own message types, validation, and storage. The x/problems module is purely a directory.
Data model
x/problems
type ProblemKind int32
const (
PROBLEM_KIND_BUILTIN ProblemKind = 0
// PROBLEM_KIND_WASM ProblemKind = 1 // intentionally unreserved in the MVP;
// // see "Future extensions" below.
)
type Problem struct {
ID uint64
Name string // unique, e.g. "random_circuit"
ModuleName string // implementing module, e.g. "random_circuit"
Kind ProblemKind // BUILTIN only for now
Enabled bool // false => no new submissions accepted; history kept
AddedAtRound uint64 // first round at which this problem was selectable
Description string // short human-readable summary
}
type Params struct {
NextProblemID uint64 // monotonically increasing; IDs are never reused
}Invariants:
- IDs are assigned sequentially and never reused even after disable.
- Problems are only added or toggled, never deleted.
Nameis unique across all problems, including disabled ones.
x/random_circuit (renamed x/qcledger)
Stores submitted solutions to Problem #1. Each submission represents a participant’s locally computed theoretical output probability distribution for the random circuit generated from the round’s seed.
type Submission struct {
RoundID uint64
ProblemID uint64 // always == ID of random_circuit problem
Submitter string // bech32 address
// For MVP (A): exact theoretical distribution
Distribution []DistributionEntry
// TODO(future B): when a separate problem 'random_circuit_sampling' is added,
// it will use its own Submission type carrying histogram counts,
// sample size, and (optional) device metadata.
SubmittedAtBlock int64
}
type DistributionEntry struct {
BasisState uint64 // computational basis index (0..2^n-1)
Probability string // decimal string to avoid float rounding issues across nodes
}Round and submission rules
- Submissions for round
Rare accepted only afterbeacon.Seeds[R]is finalised (i.e., after the EndBlocker at blockR*50). - Submissions for round
Rare accepted indefinitely thereafter (no closing deadline in the MVP). Closing rules can be added later via params. - A submitter may submit at most one solution per
(round, problem)pair. Re-submissions are rejected. - The
Enabled=falsestate means new submissions are rejected at the message handler level; existing submissions remain queryable.
Choosing a problem
There is no on-chain selection mechanism. Participants:
- Query
x/problemsto list allEnabled=trueproblems. - Decide locally which problem(s) to solve.
- Submit to one or more problem modules.
This is the defining property of the “β” model: each participant independently picks what to solve. The chain provides the common seed and the common registry; everything else is voluntary.
Lifecycle of a problem
stateDiagram-v2
[*] --> Proposed: GitHub issue + spec PR
Proposed --> Implemented: implementation PR merged
Implemented --> Released: tagged release with the new x/<problem> module
Released --> Enabled: x/upgrade gov proposal accepted; registry entry created
Enabled --> Disabled: gov proposal flips Enabled=false
Disabled --> Enabled: gov proposal flips Enabled=true
Disabled --> Disabled: data remains queryable; no new submissions
Note that Disabled is terminal in the sense that there is no [*] exit: a problem never leaves the registry.
Adding a new problem (community contribution)
The full process is documented under Contributing → Proposing a Problem (TODO). In short:
- Open a GitHub issue describing the problem: inputs, outputs, verification, expected use.
- Submit a spec PR adding a draft markdown to
docs/content/docs/modules/. - Implement the new
x/<problem>module in Go. - The module must:
- Depend on
BeaconKeeper.GetSeed(ctx, roundID). - Call
ProblemsKeeper.Register(...)at genesis init or in its upgrade handler, idempotently. - Define its own messages and storage.
- Depend on
- Cut a release containing the new module.
- Submit a
software-upgradegovernance proposal pointing at the release. - On the upgrade height, every node restarts on the new binary and the registry entry appears.
Disabling a problem
To stop a problem from accepting new submissions:
- Submit a parameter-change governance proposal flipping
problems.Problem[id].Enabledtofalse. - After the proposal passes, the message handler in the implementing module starts rejecting new submissions.
- Historical submissions and queries continue to work.
No code change or binary upgrade is required for disabling — only a gov proposal.
Future extensions
- Problem B:
random_circuit_sampling. Same circuit-generation logic, but accepts sampling histograms with sample count and optional device metadata. Verification will be statistical (e.g., χ² against the theoretical distribution from Problem A). To be added as a newx/random_circuit_samplingmodule. - WASM problems (
Kind=WASM). Intentionally not implemented in the MVP. If we ever want truly permissionless problem addition (Tx, not gov), we can introducex/wasm, add a newProblemKind, and let problems point to a WASM code ID. - Submission deadlines / round windows. A per-problem
submission_windowparameter to allow time-bounded competitions. - Cross-problem aggregation / scoreboards. Out of scope.
Implementation plan
- Rename
x/qcledger→x/random_circuit(Go package, proto package, module name, Cosmos keys, expected-keepers, app wiring). No semantic change in this step. - Define the solution type for Problem #1: replace whatever the current
MsgSubmitResultcarries with theDistributionpayload above. Add a TODO comment referencing the futurerandom_circuit_samplingmodule. - Add
x/problemswith the registry, params, queries, and the disable gov proposal. The genesis seeds the registry with Problem #1 (random_circuit). - Wire
x/random_circuitto register itself intox/problemsat genesis. - Update docs: add module reference pages for
x/problemsandx/random_circuit; deprecate theqcledgerpage in favour of a redirect; expand this page with concrete proto definitions once implemented. - Migration note: because no production chain is running yet, no on-chain state migration is needed. If a chain has already been started locally,
localnet:clean/quickstart:cleanand re-init.
Open questions for later
- What is the precise validation for the
Distributionpayload? (Must sum to ~1, dimension =2^width, etc.) — to be specified inx/random_circuitmodule doc. - How is
width/depthof the circuit chosen per round? Constant in genesis params? Derived from seed? — to be decided. - Should
x/random_circuitcap the byte size ofDistributionto prevent state bloat for large circuits?