انتقل إلى المحتوى الرئيسي

Service Challenges

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

سياق Develop

هذه المرجعية جزء من طرح البناء في BTX.

ارجع إلى موقع Develop المصغر لتقرأ هذا الدليل داخل إطار CAPTCHA للوكلاء، وقصة الهوية ما بعد الكم، وحزمة المطورين.

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.