본문으로 건너뛰기

Service Challenges

MatMul-based proof-of-work challenges for API rate limiting, spam prevention, and AI endpoint gating.

Develop 맥락

이 참고 문서는 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_gate and route-specific resource bindings.
  • Signup, comment, or message throttling via purpose=rate_limit.
  • AI inference admission via purpose=ai_inference_gate plus route, tier, or model metadata in resource.
  • 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

PosNameTypeDefaultDescription
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, and solver_duty_cycle_pct must be greater than 0 and less than or equal to 100.

Response Envelope

FieldWhat 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

FieldMeaning
`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

FieldMeaning
`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

FieldMeaning
`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

PosNameTypeDefaultDescription
1challengeobjectRequiredChallenge envelope returned by getmatmulservicechallenge.
2nonce64_hexhex stringRequiredSubmitted 64-bit nonce. Must be exactly 16 hex characters.
3digest_hexhex stringRequiredSubmitted transcript digest. Must be exactly 64 hex characters.
4lookup_local_statusbooleantrueWhen true, also report whether the configured challenge registry knows or has redeemed the envelope.

Result fields

FieldMeaning
`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 = true
  • reason = "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

ReasonMeaning
`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.

These helper RPCs are useful when you want to size or simulate challenge budgets for AI gateways rather than manually choosing solve targets.

RPCWhen 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.