Service Challenges
MatMul-based proof-of-work challenges for API rate limiting, spam prevention, and AI endpoint gating.
이 참고 문서는 BTX 개발 전개의 일부입니다.
Develop 마이크로사이트로 돌아가면 이 가이드를 에이전트 CAPTCHA, PQ 신원, 개발 시작 키트 속에서 다시 볼 수 있습니다.
Overview
BTX service challenges are one-shot MatMul proof-of-work envelopes for API admission, spam resistance, and AI endpoint gating. This page is the RPC contract: use it when you need the exact method signatures, response fields, replay semantics, and deployment constraints for a gateway or agent-facing application.
For the request choreography, tuning guidance, and gateway-side runbook, see the core flow guide and the protected route contract.
Use Cases
- Public API gating via
purpose=api_gateand route-specificresourcebindings. - Signup, comment, or message throttling via
purpose=rate_limit. - AI inference admission via
purpose=ai_inference_gateplus route, tier, or model metadata inresource. - Agent-native anti-abuse where requesters must solve fresh work before a costly action is admitted.
getmatmulservicechallenge
Issues a domain-bound service challenge. Most integrations pass the first seven arguments and accept the
default fixed policy. The full 13-argument form is for gateways that need adaptive-window
tuning, explicit min/max clamping, or solver-capacity assumptions.
# Common shorthand: first seven arguments, fixed policy defaults
btx-cli getmatmulservicechallenge \
"ai_inference_gate" \
"model:gpt-x|route:/v1/generate|tier:free" \
"tenant:abc123" \
2 300 0.25 0.75 curl --silent --user "$BTX_RPC_USER:$BTX_RPC_PASSWORD" \
--data-binary '{
"jsonrpc":"1.0",
"id":"issue",
"method":"getmatmulservicechallenge",
"params":[
"ai_inference_gate",
"model:gpt-x|route:/v1/generate|tier:free",
"tenant:abc123",
2,
300,
0.25,
0.75,
"adaptive_window",
24,
0.25,
6,
4,
35
]
}' \
-H 'content-type: text/plain;' \
http://127.0.0.1:19334/ Parameters
| Pos | Name | Type | Default | Description |
|---|---|---|---|---|
| 1 | purpose | string | Required | Application policy label such as `rate_limit`, `api_gate`, or `ai_inference_gate`. |
| 2 | resource | string | Required | Bound resource identifier such as `signup:/v1/messages` or `POST:/v1/generate`. |
| 3 | subject | string | Required | Bound requester identifier such as `user:[email protected]`, `tenant:abc123`, or `api_key:key-42`. |
| 4 | target_solve_time_s | number | `1` | Requested service solve-time target in seconds before policy resolution. |
| 5 | expires_in_s | number | `300` | Challenge lifetime in seconds. Must stay between `1` and `86400`. |
| 6 | validation_overhead_s | number | `0` | Estimated validation overhead to include in the total request budget. |
| 7 | propagation_overhead_s | number | `0` | Estimated routing or propagation overhead to include in the total request budget. |
| 8 | difficulty_policy | string | `fixed` | Difficulty policy: `fixed` or `adaptive_window`. |
| 9 | difficulty_window_blocks | number | `24` | Recent block window used when `difficulty_policy=adaptive_window`. |
| 10 | min_solve_time_s | number | `0.25` | Minimum solve-time target allowed after adaptive resolution. |
| 11 | max_solve_time_s | number | `30` | Maximum solve-time target allowed after adaptive resolution. |
| 12 | solver_parallelism | number | `1` | Expected independent solver workers on the client or gateway tier. |
| 13 | solver_duty_cycle_pct | number | `100` | Expected share of wall-clock time those workers may use. |
The node rejects invalid issue requests early. Examples from the live RPC implementation include
expires_in_s must be between 1 and 86400,validation_overhead_s must be non-negative, andsolver_duty_cycle_pct must be greater than 0 and less than or equal to 100.
Response Envelope
| Field | What it gives you |
|---|---|
| `kind` | Envelope version. Current value is `matmul_service_challenge_v1`. |
| `challenge_id` | Replay-resistant identifier for this issued challenge. |
| `issued_at` / `expires_at` / `expires_in_s` | Unix timestamps and lifetime window for the challenge. |
| `binding` | Application binding plus anchor metadata such as `purpose`, `resource`, `subject`, hashes, salt, `anchor_height`, and `anchor_hash`. |
| `proof_policy` | Verification policy and replay contract, including `redeem_rpc`, `solve_rpc`, `issued_challenge_store`, and `issued_challenge_scope`. |
| `challenge` | MatMul challenge payload, including `header_context`, `bits`, `target`, and `service_profile`. |
Key binding fields
| Field | Meaning |
|---|---|
| `purpose` / `resource` / `subject` | The caller-supplied application binding. |
| `resource_hash` / `subject_hash` / `salt` | Hashes and entropy used when deriving the challenge identity. |
| `anchor_height` / `anchor_hash` | The chain tip that anchored issuance time and seeds. |
| `challenge_id_rule` | Documents the exact challenge-id derivation rule used by the node. |
| `seed_derivation_rule` | Documents how per-challenge seeds are derived from `challenge_id` and the anchor. |
Key proof_policy fields
| Field | Meaning |
|---|---|
| `verification_rule` | Current digest / transcript verification contract used by the node. |
| `expiration_enforced` | Whether the node rejects proofs after `expires_at`. |
| `challenge_id_required` | Whether replay-resistant challenge ids are mandatory. |
| `replay_protection` / `redeem_rpc` | Points callers at `redeemmatmulserviceproof` for one-shot admission control. |
| `solve_rpc` | The local helper RPC for daemon-side solving: `solvematmulservicechallenge`. |
| `locally_issued_required` | Whether redeem requires the configured issued-challenge registry to recognize the challenge. |
| `issued_challenge_store` / `issued_challenge_scope` | Whether the registry is local-persistent or shared-file backed for this daemon. |
Key challenge fields
| Field | Meaning |
|---|---|
| `algorithm` | Current algorithm label. Expected value: `matmul`. |
| `header_context` | Chain-anchored header inputs including `previousblockhash`, `seed_a`, and `seed_b`. |
| `bits` / `target` | Difficulty target the client proof must satisfy. |
| `service_profile` | Resolved difficulty, total budget, operator-capacity assumptions, and policy resolution details. |
verifymatmulserviceproof
Stateless verification for one proof envelope. Use it for diagnostics, offline checks, or gateway-side
observability. It does not consume the challenge. Production admission control should still
end at redeemmatmulserviceproof.
curl --silent --user "$BTX_RPC_USER:$BTX_RPC_PASSWORD" \
--data-binary '{
"jsonrpc":"1.0",
"id":"verify",
"method":"verifymatmulserviceproof",
"params":[CHALLENGE_ENVELOPE,"0000000000000001","DIGEST_HEX",true]
}' \
-H 'content-type: text/plain;' \
http://127.0.0.1:19334/ Parameters
| Pos | Name | Type | Default | Description |
|---|---|---|---|---|
| 1 | challenge | object | Required | Challenge envelope returned by getmatmulservicechallenge. |
| 2 | nonce64_hex | hex string | Required | Submitted 64-bit nonce. Must be exactly 16 hex characters. |
| 3 | digest_hex | hex string | Required | Submitted transcript digest. Must be exactly 64 hex characters. |
| 4 | lookup_local_status | boolean | true | When true, also report whether the configured challenge registry knows or has redeemed the envelope. |
Result fields
| Field | Meaning |
|---|---|
| `challenge_id` | Challenge identifier from the submitted envelope. |
| `checked_at` / `expires_at` | Verification timestamp and envelope expiration timestamp. |
| `local_registry_status_checked` | Whether the node consulted its local or shared registry. |
| `issued_by_local_node` | Present when registry lookup is enabled. Shows whether the configured store recognizes the challenge. |
| `redeemed` / `redeemable` / `redeemed_at` | Present when registry lookup is enabled. Shows replay state for this challenge. |
| `valid` / `expired` / `reason` | The decision triple your application should inspect first. |
| `mismatch_field` | Present when canonical challenge verification fails, for example `challenge.bits`. |
| `proof` | Optional diagnostics such as transcript checks, commitment checks, target checks, and parsed nonce / digest values. |
If you set lookup_local_status=false, the registry-backed fields like
issued_by_local_node, redeemed, and redeemable may be omitted. That is
useful for stateless, high-volume verification but it removes replay-state diagnostics.
redeemmatmulserviceproof
Verifies and atomically consumes a locally issued service challenge. This is the anti-replay RPC your application should use before admitting a protected request.
curl --silent --user "$BTX_RPC_USER:$BTX_RPC_PASSWORD" \
--data-binary '{
"jsonrpc":"1.0",
"id":"redeem",
"method":"redeemmatmulserviceproof",
"params":[CHALLENGE_ENVELOPE,"0000000000000001","DIGEST_HEX"]
}' \
-H 'content-type: text/plain;' \
http://127.0.0.1:19334/ Accept the request only when all three conditions hold:
valid = truereason = "ok"redeemed = true
The response shape mirrors verifymatmulserviceproof, but the registry-backed replay fields are
always relevant here because redemption is a state-changing operation.
Common reason codes
| Reason | Meaning |
|---|---|
| `ok` | Proof matched the challenge and, for redeem, was accepted and consumed. |
| `invalid_proof` | Nonce and digest failed the canonical MatMul proof checks. |
| `challenge_mismatch` | The submitted envelope was tampered or does not canonically match the anchored challenge payload. |
| `expired` | The challenge lifetime elapsed before verification or redemption. |
| `unknown_challenge` | Redeem could not find the issued challenge in the configured registry, usually because the wrong node handled redemption or the issuing registry is unavailable. |
| `already_redeemed` | Redeem saw a duplicate proof for a challenge that has already been consumed. |
verifymatmulserviceproofs
Batch verification for high-throughput gateways. The request is an array of proof envelopes shaped like
{ challenge, nonce64_hex, digest_hex }. The node enforces a batch size of 1..256.
The response contains top-level counts count, valid, invalid,
per-reason totals in by_reason, and ordered per-proof details in results.
redeemmatmulserviceproofs
Batch verify-and-consume for queue workers and public API frontends. Processing is sequential, not
all-or-nothing, so later duplicates in the same batch can legitimately return already_redeemed.
curl --silent --user "$BTX_RPC_USER:$BTX_RPC_PASSWORD" \
--data-binary '{
"jsonrpc":"1.0",
"id":"redeem-batch",
"method":"redeemmatmulserviceproofs",
"params":[[
{
"challenge": CHALLENGE_A,
"nonce64_hex": "0000000000000001",
"digest_hex": "DIGEST_A"
},
{
"challenge": CHALLENGE_B,
"nonce64_hex": "0000000000000002",
"digest_hex": "DIGEST_B"
}
]]
}' \
-H 'content-type: text/plain;' \
http://127.0.0.1:19334/
The batch result includes the same top-level accounting fields as batch verify:
count, valid, invalid, by_reason, and ordered
results.
Related helper RPCs
These helper RPCs are useful when you want to size or simulate challenge budgets for AI gateways rather than manually choosing solve targets.
| RPC | When to use it |
|---|---|
| `solvematmulservicechallenge` | Local helper that solves an issued envelope and returns `nonce64_hex`, `digest_hex`, and a ready-to-submit `proof` object. |
| `getmatmulservicechallengeprofile` | Returns a network-relative difficulty recommendation with ready-to-issue defaults for interactive, balanced, strict, or background flows. |
| `getmatmulservicechallengeplan` | Works backwards from a target throughput objective and returns issuance defaults plus operator-capacity assumptions. |
| `issuematmulservicechallengeprofile` | Issues a challenge directly from a named difficulty profile or short alias. |
Deployment Patterns
Single Node
A single BTX service node is the simplest production shape. Issued challenges are tracked in the node's persistent challenge registry, so restarts do not have to imply a blank in-memory challenge cache.
The current daemon exposes the registry path through -matmulservicechallengefile=<file>.
By default it lives under the network datadir as matmul_service_challenges.dat.
Shared Registry
Multiple BTX service nodes can point at the same -matmulservicechallengefile when you want
issuance on one node and redemption on another. When configured this way, the proof policy exposes a
shared-file-backed issued-challenge store instead of a purely node-local registry.
Multi Node Without Shared State
If nodes do not share a registry, redemption still needs sticky routing or another affinity
layer so the request lands on the issuing node. Otherwise redeem calls can return
unknown_challenge.
Operator rule of thumb: verify can be stateless, but redeem is where your replay guarantees actually live. Design routing, storage, and retries around the redeem path, not around diagnostics-only verification.