서비스, OFAC 데이터셋, 응답의 서명은 어떻게 모니터링합니까?

오류, 한도, 신뢰 · 프로세스 가동 상태, 제재 목록의 경과 시간과 개수, 서비스 자체의 예산 — 그리고 서명하는 배포가 모든 응답에 덧붙이는 Ed25519 증명(attestation)

  • API 가이드
  • 7분
  • 중급
  • 개발자
  • GET /health
  • /ready
  • /v1/sanctions
  • /v1/stats/slo
  • POST /v1/verify-attestation

ACHIVX Academy 원문 (영어) ↗

체인이 아니라 서비스를 감시하는 조회가 네 가지 있습니다. /health와 /ready는 프로세스 가동 상태 — 실행 중이며 데이터베이스가 응답함 — 이며, 인덱싱에 대해서는 아무것도 말하지 않습니다. GET /v1/sanctions는 OFAC 데이터셋입니다. 생태계별 개수(2026-10-24에 주소 385개: EVM 120, 트론 261, 솔라나 4)와 updated_at이 있습니다. GET /v1/stats/slo?chain=은 서비스의 지연 시간 예산과 배치 기준점 — OFAC 목록, 주간 그래프 배치 — 의 경과 시간입니다. 그리고 응답에 서명하는 배포는 응답에 attestation 객체를 덧붙입니다. POST /v1/verify-attestation은 본문을 그것과 대조해 확인하며, 무료이고 독립적입니다. 이 배포는 현재 서명하지 않으며, /.well-known/jwks.json은 비어 있습니다.

가동 상태

curl -s https://stablescan.achivx.com/health    # {"status": "ok"}
curl -s https://stablescan.achivx.com/ready     # {"status": "ready"}, or 503 not_ready

둘 다 no-store입니다. 프로세스가 실행 중이고 데이터베이스가 응답한다고 답합니다. 둘 다 예라고 답하는 동안에도 네트워크는 몇 시간 뒤처져 있을 수 있습니다. 최신성은 네트워크별 /v1/sync/status?chain=이며, 데이터가 최신인가에 맞는 확인 수단입니다.

제재 데이터셋

curl -s https://stablescan.achivx.com/v1/sanctions
{
  "source": "ofac_sdn",
  "evm_count": 120,
  "solana_count": 4,
  "tron_count": 261,
  "total": 385,
  "updated_at": "2026-10-24T04:00:04Z",
  "note": "OFAC SDN digital-currency addresses (public, 0xB10C list). Heuristic exposure only — not legal advice; verify against the official SDN list."
}

updated_at은 모든 판정이 sanctions_list_as_of로 반복하는 날짜입니다. 목록이 7일보다 오래되면 깨끗한 판정이 ofac_list_stale과 함께 unknown으로 읽힙니다. 주소 목록 내보내기는 없습니다. 등재 여부는 주소 개요의 sanctioned입니다. max-age=300이며, ETag로 재검증됩니다.

서비스 자체의 예산

curl -s 'https://stablescan.achivx.com/v1/stats/slo?chain=1'
{
  "chain_id": 1, "chain_source": "explicit",
  "latency": [
    {"class": "verify_attestation", "budget_ms": 50,  "observed_p95_ms": 0,    "samples": 0,   "within_budget": true},
    {"class": "ego_graph",          "budget_ms": 800, "observed_p95_ms": 4707, "samples": 148, "within_budget": false},
    {"class": "cached_aggregate",   "budget_ms": 300, "…": "…"}
  ],
  "freshness": [
    {"anchor": "ofac_sanctions", "scope": "global", "known": true, "age_seconds": 24519,  "budget_seconds": 86400,  "within_slo": true, "last_refresh": "2026-10-24T04:00:04Z"},
    {"anchor": "graph_batch",    "scope": "chain",  "known": true, "age_seconds": 530664, "budget_seconds": 691200, "within_slo": true, "last_refresh": "2026-10-18T07:24:18Z"}
  ],
  "signal_firing": [{"detector": "wash", "scope": "chain", "known": true, "count": 0}, {"detector": "inflation", "…": "…"}, "…"],
  "as_of": "2026-10-24T10:48:43Z"
}

latency[]는 경로 유형별 최근 프로세스 내 p95를 공개된 예산과 비교한 것입니다(samples: 0 = 아직 관측되지 않음). 그날 아침 에고 그래프는 p95 4.7초로 800 ms 예산을 초과했으며, 무거운 주소에서의 202 building이 여기서는 이렇게 보입니다. freshness[]는 각 배치 기준점의 경과 시간입니다. OFAC 목록(전역, 하루 예산)과 주간 그래프 배치(체인별, 8일 예산 — 최근 주간 실행보다 오래된 last_refresh는 해당 체인의 실행이 반영되지 않았다는 뜻)입니다. 한 체인에 대해 응답합니다. chain을 넘기거나, 그렇지 않으면 chain_source: "default"가 베이스(Base)임을 알려 줍니다. no-store: 모든 조회는 실시간입니다.

첫 번째 요청의 헬퍼 세 개로 한 같은 호출:

Python

slo = scan("/v1/stats/slo", chain=1)
late = [l["class"] for l in slo["latency"] if l["samples"] and not l["within_budget"]]
stale = [f["anchor"] for f in slo["freshness"] if not f["within_slo"]]
sanctions = scan("/v1/sanctions")
print("over budget:", late, "| stale anchors:", stale, "| OFAC list:", sanctions["total"], "addresses as of", sanctions["updated_at"])

Go

var slo struct {
	Latency []struct {
		Class        string `json:"class"`
		Samples      int    `json:"samples"`
		WithinBudget bool   `json:"within_budget"`
	} `json:"latency"`
	Freshness []struct {
		Anchor     string `json:"anchor"`
		AgeSeconds int    `json:"age_seconds"`
		WithinSLO  bool   `json:"within_slo"`
	} `json:"freshness"`
}
if err := get("/v1/stats/slo", url.Values{"chain": {"1"}}, &slo); err != nil {
	return err
}

TypeScript

type Slo = {
  chain_id: number; chain_source: "explicit" | "default";
  latency: { class: string; budget_ms: number; observed_p95_ms: number; samples: number; within_budget: boolean }[];
  freshness: { anchor: string; scope: "global" | "chain"; known: boolean; age_seconds: number; budget_seconds: number; within_slo: boolean; last_refresh: string }[];
  as_of: string;
};
const slo = await scan<Slo>("/v1/stats/slo", { chain: 1 });
const sanctions = await scan<{ total: number; updated_at: string }>("/v1/sanctions");

증명: 서명된 응답

서명하는 배포는 모든 주소 응답에 attestation 객체를 덧붙입니다. OpenAPI 스키마는 개요, risk, exposure, approvals, balances, heuristics에서 이를 설명합니다: an Ed25519 signature over the JCS-canonical body without this field(이 필드를 제외한 JCS 정규화 본문에 대한 Ed25519 서명). alg, kid, method, observed_hash, ruleset_version, data_vintage, signed_at, sig가 있습니다. 확인 방법은 두 가지입니다.

  • /.well-known/jwks.json의 공개 키로 오프라인 확인 — 본문을 정규화하고(RFC 8785, attestation 제외), 해시한 뒤, kid가 가리키는 키로 sig를 검증합니다.
  • 또는 본문과 그 증명을 POST /v1/verify-attestation으로 보냅니다. 서버가 해시를 다시 계산해 {"valid": true|false, "alg", "kid", "observed_hash"}로 응답하며, valid가 false이면 reason을 덧붙입니다 — false is an answer, not an error: the body was altered, the signature does not verify, or the algorithm is not Ed25519. HTTP stays 200.(false는 오류가 아니라 답입니다: 본문이 변경되었거나, 서명이 검증되지 않거나, 알고리즘이 Ed25519가 아닙니다. HTTP는 200으로 유지됩니다.) 자신의 키로 확인하려면 public_key(base64url 원시 Ed25519 키)를 넘기십시오.

이 배포는 현재 서명하지 않습니다. 2026-10-24에 어떤 주소 응답에도 attestation이 없었고, /v1/methodology에도 없었으며, /.well-known/jwks.json은 {"keys": []}로 응답했고, 본문과 증명을 넣은 POST /v1/verify-attestation은 400 no_key로 응답했습니다 — no public_key supplied and this deployment has no signing key(public_key가 제공되지 않았고 이 배포에는 서명 키가 없습니다). 잘못된 형식의 키는 400 invalid_public_key, 두 부분이 없는 본문은 400 invalid_body(body and attestation are required)입니다. attestation이 없는 응답을 무효가 아니라 서명 없음으로 처리하도록 확인 코드를 작성하면, 키가 설정되는 날에도 올바르게 동작합니다.

def attested(answer):
    '''None when the deployment does not sign; True/False from the server's check otherwise'''
    att = answer.get("attestation")
    if not att:
        return None
    body = {k: v for k, v in answer.items() if k != "attestation"}
    req = urllib.request.Request(BASE + "/v1/verify-attestation", method="POST", data=json.dumps({"body": body, "attestation": att}).encode(),
                                 headers={"Content-Type": "application/json", "Accept": "application/json"})
    with urllib.request.urlopen(req, timeout=30) as r:
        return json.load(r)["valid"]

무엇에 대해 알림을 보낼 것인가

  • /ready가 1분 동안 200이 아님: 데이터가 아니라 서비스 문제입니다.
  • 의존하는 네트워크에서 /v1/sync/status의 freshness_seconds가 임계값을 넘음: 데이터 문제입니다.
  • /v1/sanctions의 updated_at이 하루보다 오래됨: OFAC 기준점(/v1/stats/slo의 ofac_sanctions 행에서 within_slo: false와 같습니다).
  • graph_batch가 예산 초과: 거래 상대 그래프가 오래되고 있습니다. /graph 응답에 snapshot_age_seconds로 나타납니다.

Stablecoin scanner ACHIVX에서

출처

더 알아보기

오류, 한도, 신뢰 · GET /health · /ready · /v1/sanctions · /v1/stats/slo · POST /v1/verify-attestation · 2026-10-24 작성, openapi.json, agents.md 및 당일 실제 호출 기반. 구조는 인용한 것이며, 수치는 날짜 기준이고 인덱스에 따라 바뀝니다.

이 페이지는 ACHIVX Academy 영어 원문을 한국어로 옮긴 것입니다. 번역과 원문이 다르면 영어 원문이 기준입니다.