RAILGUN 서비스 상태 API
Anon은 지갑이 의존하는 Railgun 서비스를 점검하는 모니터를 운영합니다. 점검 대상은 PPOI 노드, Anon 자체 인덱서, Subsquid, 브로드캐스터, Waku입니다. 모니터는 체인별로 약 30초마다 다시 확인하고, 그 결과를 공개 URL의 작은 JSON 문서 하나로 게시합니다. 지갑, 대시보드, 상태 페이지, 스크립트 등 누구나 읽을 수 있습니다. API 키도 계정도 필요하지 않습니다.
GET https://api.anon.inc/api/v1/railgun/liveness
이 문서는 Anon이 자체 모니터로 확인한 독립적인 관점입니다. Railgun 공식 상태가 아니며, “안전하게 거래할 수 있음”을 뜻하는 신호도 결코 아닙니다. 한계는 알려 주지 않는 것에 정리되어 있습니다.
베타: 이 API는 베타입니다. 필드, 열거형 값, 응답의 형태는 예고 없이 바뀔 수 있습니다. 예고 기간도, 지원 중단(deprecation)이나 종료(sunset)에 대한 약속도 없습니다. 알 수 없는 필드와 값은 무시하도록 클라이언트를 작성하십시오. 베타 상태를 참고하십시오.
| 속성 | 값 |
|---|---|
| 기본 URL | https://api.anon.inc |
| 인증 | 없음 |
| CORS | 모든 오리진, 자격 증명 없음 (GET, HEAD, OPTIONS) |
| 상태 | 베타: 예고 없이 바뀔 수 있음 (베타 상태) |
| 형식 | JSON, schemaVersion 1 (JSON Schema) |
| 재확인 주기 | 약 30초마다, 계속 실패하는 소스는 그보다 드물게 |
| 캐시 | 브라우저 15초, 공유 캐시 30초 |
요청이 프로브를 일으키는 일은 없으며, 모든 응답은 저장된 스냅샷에서 나옵니다.
빠른 시작
curl -i https://api.anon.inc/api/v1/railgun/liveness
응답에는 보고서와 캐시 헤더가 포함됩니다.
HTTP/2 200
content-type: application/json; charset=utf-8
cache-control: public, max-age=15, s-maxage=30, stale-while-revalidate=30, stale-if-error=300
etag: "79d583eb71a37058"
access-control-allow-origin: *
access-control-expose-headers: ETag
ETag를 If-None-Match로 되돌려 보내면 변경 여부를 확인할 수 있습니다. 변경이 없으면 본문 없이 304 Not Modified로 응답합니다.
curl -i https://api.anon.inc/api/v1/railgun/liveness \
-H 'If-None-Match: "79d583eb71a37058"'
브라우저에서는 일반 fetch를 어떤 오리진에서든 사용할 수 있습니다.
const response = await fetch("https://api.anon.inc/api/v1/railgun/liveness", {
headers: { Accept: "application/json" },
signal: AbortSignal.timeout(8000),
});
if (!response.ok) throw new Error(`liveness: HTTP ${response.status}`);
const report = await response.json();
각 행은 자체 만료 시각까지만 유효합니다. 표시하기 전에 각 행을 시스템 시계와 비교해 판단하십시오. 사용할 만한 근거가 없는 행은 unknown이고, 수명이 지난 행은 stale입니다. 어느 쪽도 정상으로 표시해서는 안 됩니다.
const FIVE_MINUTES = 5 * 60 * 1000;
const CLOCK_SKEW = 30 * 1000;
const ACTIONABLE = new Set(["current", "catching-up", "degraded", "unavailable"]);
function effectiveStatus(check, now = Date.now()) {
// Neither of these asserts anything that could go stale.
if (check.status === "unmonitored" || check.status === "unknown") return check.status;
// A status this client does not know is not evidence.
if (!ACTIONABLE.has(check.status)) return "unknown";
const observed = Date.parse(check.observedAt);
const expires = Date.parse(check.expiresAt);
// Missing, unparseable or inconsistent timestamps are not evidence either.
if (!Number.isFinite(observed) || !Number.isFinite(expires)) return "unknown";
if (observed > now + CLOCK_SKEW || expires <= observed) return "unknown";
const stale = expires <= now || now - observed >= FIVE_MINUTES;
return stale ? "stale" : check.status;
}
// Decide for yourself which chains count as mainnets.
const MAINNETS = new Set([1, 42161, 137, 56]);
const ppoi = report.checks.filter((c) => c.service === "ppoi" && MAINNETS.has(c.chainId));
console.log(ppoi.map((c) => `${c.chainId}: ${effectiveStatus(c)}`));
엔드포인트
GET https://api.anon.inc/api/v1/railgun/liveness
- 인증도 매개변수도 필요하지 않습니다. 쿼리 문자열은 무시됩니다.
HEAD는 헤더만 반환합니다.OPTIONS는 CORS 프리플라이트 요청에 응답합니다.- 본문은
application/json; charset=utf-8이며 길이는 수 KB입니다. - 응답 하나가 모든 체인의 모든 서비스를 담고 있습니다. 한 번 가져와서 필요한 항목만 걸러 쓰면 됩니다.
응답 예시
검사 5개만 남긴 축약 보고서이며, 값은 예시입니다. 실제 보고서에는 모든 체인의 모든 서비스가 나열됩니다.
{
"schemaVersion": 1,
"generatedAt": "2026-10-03T12:00:05.418Z",
"checks": [
{
"service": "waku",
"chainId": null,
"status": "current",
"reason": "responding",
"observedAt": "2026-10-03T11:59:40.993Z",
"lastSuccessAt": "2026-10-03T11:59:40.993Z",
"expiresAt": "2026-10-03T12:02:10.993Z",
"metrics": { "peers": 2 }
},
{
"service": "ppoi",
"chainId": 1,
"status": "current",
"reason": "synced",
"observedAt": "2026-10-03T11:59:52.206Z",
"lastSuccessAt": "2026-10-03T11:59:52.206Z",
"expiresAt": "2026-10-03T12:02:22.206Z",
"metrics": { "position": 139296, "head": 139296 }
},
{
"service": "broadcasters",
"chainId": 1,
"status": "current",
"reason": "responding",
"observedAt": "2026-10-03T11:59:40.993Z",
"lastSuccessAt": "2026-10-03T11:59:40.993Z",
"expiresAt": "2026-10-03T12:02:10.993Z",
"metrics": { "responding": 82, "monitored": 85 }
},
{
"service": "indexer",
"chainId": 1,
"status": "catching-up",
"reason": "behind",
"observedAt": "2026-10-03T11:59:58.731Z",
"lastSuccessAt": "2026-10-03T11:59:58.731Z",
"expiresAt": "2026-10-03T12:02:28.731Z",
"metrics": { "position": 26115307, "head": 26115332 }
},
{
"service": "subsquid",
"chainId": 137,
"status": "unavailable",
"reason": "unreachable",
"observedAt": "2026-10-03T12:00:01.093Z",
"lastSuccessAt": "2026-10-03T11:58:09.870Z",
"expiresAt": "2026-10-03T12:02:31.093Z",
"metrics": {}
}
]
}
waku행은 공유 Waku 검사이므로chainId가null입니다. 상태는current이며,peers는 Anon이 모니터링하는 Waku 연결의 피어 수입니다.broadcasters행은current입니다. 해당 체인에서 Anon이 모니터링하는 브로드캐스터 85개 중 82개가 응답했습니다.monitored가 실제 분모입니다.ppoi행은 최신 상태입니다.position은 PPOI 노드가 검증한 TXID 인덱스이고,head는 같은 노드의 현재 인덱스입니다.indexer행은 기준값보다 25블록 뒤처져 허용 범위를 넘었으므로catching-up으로 보고됩니다.subsquid행은unavailable입니다. Anon의 모니터가 연속 세 번의 프로브에서 사용할 수 있는 응답을 받지 못했습니다.observedAt은 가장 최근에 실패한 프로브의 시각이고,lastSuccessAt은 서비스가 마지막으로 응답한 시각을 유지합니다. 실패에는 지표가 없습니다.- 검사는 현재
waku,ppoi,broadcasters,indexer,subsquid순으로 정렬되며, 각 서비스 안에서는chainId오름차순입니다. 이 순서에 의존하지 마십시오.
필드
보고서
| 필드 | 타입 | 의미 |
|---|---|---|
schemaVersion |
정수 | 현재는 1입니다. 베타 기간에는 바뀔 수 있습니다. |
generatedAt |
타임스탬프 | 스냅샷이 조립된 시각이며, 제공된 시각이 아닙니다. 모니터가 동작하는 동안 최소 30초마다 갱신됩니다. |
checks |
배열 | 서비스와 범위마다 객체 하나입니다. 서비스와 chainId의 조합은 최대 한 번만 나타납니다. |
검사
| 필드 | 타입 | 의미 |
|---|---|---|
service |
문자열 | 현재는 ppoi, broadcasters, waku, indexer 또는 subsquid입니다. 더 추가될 수 있습니다. |
chainId |
정수 또는 null |
양의 체인 ID입니다. 현재는 공유 검사 하나인 waku가 null입니다. |
status |
문자열 | 이 행을 어떻게 다룰지 나타냅니다. 상태를 참고하십시오. |
reason |
문자열 | 이 행이 해당 상태인 이유입니다. 새로운 값이 추가될 수 있습니다. 사유를 참고하십시오. |
observedAt |
타임스탬프 또는 null |
가장 최근 프로브가 완료된 시각입니다. 실패한 프로브도 관측으로 칩니다. 한 번도 검사하지 않았거나 모니터링되지 않으면 null입니다. |
lastSuccessAt |
타임스탬프 또는 null |
서비스가 마지막으로 응답하여 비교가 이루어진 시각입니다. 이후에 실패해도 유지됩니다. 한 번도 없었다면 null입니다. |
expiresAt |
타임스탬프 또는 null |
이 관측이 더는 의미를 갖지 않게 되는 시각입니다. observedAt에 행의 수명(출시 시점에는 150초)을 더한 값입니다. 조치가 필요한 모든 상태(current, catching-up, degraded, unavailable)에서 제공됩니다. |
metrics |
객체 | 측정값입니다. 항상 존재하며, 알 수 없는 키는 생략됩니다. |
타임스탬프는 UTC이며 밀리초 정밀도이고 마지막에 문자 그대로 Z가 붙습니다: YYYY-MM-DDTHH:mm:ss.sssZ.
지표
| 키 | 의미 |
|---|---|
position |
서비스 자체의 위치입니다. ppoi는 검증된 TXID 인덱스, indexer와 subsquid는 인덱싱된 블록입니다. |
head |
비교 대상입니다. PPOI 노드의 현재 TXID 인덱스, 또는 체인의 최신 블록에서 해당 서비스의 확인 깊이를 뺀 값입니다. |
responding |
응답한 브로드캐스터의 수입니다. monitored와 함께 설정되며 그 값을 넘지 않습니다. |
monitored |
실제로 점검한 브로드캐스터의 수입니다. 실질적인 분모입니다. |
peers |
모니터링 대상 Waku 연결에 현재 연결된 피어 수입니다. |
새로운 키가 추가될 수 있습니다. 알 수 없는 키는 무시하십시오. 여기에 나열된 모든 지표는 2^53 − 1 이하의 음이 아닌 정수입니다. 알 수 없는 지표는 생략되며 0으로 채워지지 않으므로, 없는 키를 0으로 읽지 마십시오. 모니터링되지 않는 행은 "metrics": {}입니다.
position이 head보다 클 수 있습니다. 기준 최신 블록은 자체 주기로 읽으며 최대 1분 정도 지난 값일 수 있습니다. 뒤처짐 값은 0 이상으로 제한하십시오.
상태와 사유
상태
현재의 상태는 다음과 같습니다. 닫힌 집합이 아닙니다. 베타 기간에는 예고 없이 값이 추가되거나 이름이 바뀔 수 있습니다. 알 수 없는 상태는 해당 행에 한해 unknown으로 취급하십시오.
| 상태 | 의미 | 대응 |
|---|---|---|
current |
서비스가 응답했고 허용 범위 안에서 기준값을 따라잡았습니다. | 응답했고 따라잡은 상태로, observedAt 시점 기준으로 표시합니다. |
catching-up |
서비스가 응답했지만 기준값보다 허용 범위를 넘어 뒤처져 있습니다. | 지연을 예상하십시오. 장애는 아닙니다. |
degraded |
서비스가 응답하지만 심하게 손상되었습니다. 오랫동안 크게 뒤처졌거나, 담당해야 할 범위의 일부만 처리합니다. | 경고합니다. 시간에 민감한 작업에는 의존하지 마십시오. |
unavailable |
Anon의 모니터가 연속 세 번의 프로브에서 사용할 수 있는 응답을 받지 못했습니다. | 응답하지 않는 것으로 취급합니다. |
unknown |
아직 쓸 만한 근거가 없거나, 근거를 안전하게 비교할 수 없습니다. | 좋은 소식도 나쁜 소식도 아닙니다. 녹색 상태로 표시하지 마십시오. |
unmonitored |
Anon이 이 검사를 모니터링하지 않습니다. | 실패가 아닙니다. 대상 외로 표시하십시오. |
expiresAt이 지난 행은 상태가 무엇이라고 하든 만료된 것이며, 중단된 서비스의 행도 그런 상태로 도착할 수 있습니다. 최신성과 캐싱을 참고하십시오.
사유
| 사유 | 함께 나타나는 상태 | 의미 |
|---|---|---|
synced |
current |
위치가 head(기준 최신 값)의 허용 범위 안에 있거나, PPOI 노드가 자체 현재 인덱스까지 검증했습니다. |
behind |
catching-up, degraded |
위치가 head보다 허용 범위를 넘어 뒤처져 있습니다. |
responding |
current |
비교할 위치가 없는 서비스, 즉 Waku와 브로드캐스터에 사용됩니다. |
partial-coverage |
degraded |
모니터링 대상 구성원 중 일부만 응답합니다. 브로드캐스터에 사용됩니다. |
unreachable |
unknown, unavailable |
프로브가 서비스에 닿지 못했거나 응답을 이해하지 못했습니다. 연속 실패가 두 번까지는 unknown, 세 번이면 unavailable입니다. |
not-configured |
unmonitored |
Anon이 이 검사를 모니터링하지 않습니다. |
no-observation |
unknown |
아직 관측된 것이 없거나, 서비스는 응답했지만 이 체인에 대한 데이터가 없습니다. |
incompatible-reference |
unknown |
서비스가 응답했지만 그 수치를 안전하게 비교할 수 없습니다. 예를 들어 PPOI 노드에 필요한 목록이 없거나, 기준으로 쓰는 체인 head가 너무 오래되었습니다. |
사유도 닫힌 집합이 아닙니다. 알 수 없는 사유는 status만 보고 판단하도록 클라이언트를 작성하십시오. Waku와 브로드캐스터 모니터링으로 새로운 사유가 앞으로도 생길 수 있습니다.
임계값
다음은 출시 시점의 값입니다. 스키마의 일부가 아니라 모니터 정책이므로, Anon은 스키마 버전을 바꾸지 않고 값을 다시 조정할 수 있습니다.
| 규칙 | 값 |
|---|---|
| 재확인 | 응답하는 소스는 약 30초마다, 최대 3초의 지터를 두고 확인합니다. 계속 실패하는 소스는 더 드물게 확인합니다. 연속 실패할 때마다 대기 시간이 두 배가 되어 30초, 60초, 그다음 상한인 2분이 됩니다. |
| 행 수명 | 150초입니다. expiresAt은 observedAt에 150초를 더한 값입니다. |
| 장애 | 프로브가 연속 3회 실패하면 unavailable입니다. 처음 두 번은 unknown입니다. |
| 지연 허용 범위 | indexer와 subsquid는 뒤처짐이 10블록과 약 2분 분량의 블록 중 큰 값 이하이면 current입니다. |
| 성능 저하 | 연속 2회 평가에서 30분 이상 뒤처진 경우입니다. |
| PPOI 뒤처짐 | 노드가 검증한 인덱스가 자체 현재 인덱스보다 45초 동안 계속 뒤처져 있는 경우입니다. |
| 기준 head | 기준으로 쓰는 체인 head는 60초를 넘지 않아야 하며, 넘으면 해당 행은 unknown이고 사유는 incompatible-reference입니다. |
서비스와 체인
| 서비스 | Anon이 확인하는 것 | position |
head |
|---|---|---|---|
ppoi |
설정된 PPOI 노드는 해당 네트워크에 필요한 목록을 갖고 있어야 합니다. 노드가 검증한 TXID 인덱스를 같은 노드의 현재 인덱스와 비교합니다. | 검증된 TXID 인덱스 | 노드의 현재 TXID 인덱스 |
indexer |
Anon 자체 인덱서가 마지막으로 처리한 블록을, 체인 head에서 인덱서의 확인 깊이를 뺀 값과 비교합니다. | 마지막으로 처리한 블록 | 확인 깊이를 뺀 기준 head |
subsquid |
설정된 Subsquid 배포의 인덱싱 높이를, 체인 head에서 해당 squid의 확인 깊이를 뺀 값과 비교합니다. | 인덱싱 높이 | 확인 깊이를 뺀 기준 head |
broadcasters |
체인별로, 한정된 브로드캐스터 집합 중 몇 개가 응답하는지 확인합니다. 2026-10-04부터 모니터링됩니다. | — | — |
waku |
Anon이 모니터링하는 Waku 연결에 대한 공유 검사 하나입니다. 2026-10-04부터 모니터링됩니다. | — | — |
- 체인. 모니터링되는 메인넷은 Ethereum(
1), Arbitrum(42161), Polygon(137), BNB Chain(56)입니다. Sepolia(11155111)는 테스트 네트워크로 메인넷 집계에 포함되지 않으며 Subsquid 배포도 없으므로, 해당subsquid행은 모니터링되지 않습니다. 예고 없이 체인이 더 추가될 수 있습니다. - Waku와 브로드캐스터. 둘 다 2026-10-04부터 모니터링되며 실제 상태를 보고합니다. 사유는
responding또는partial-coverage이고, 지표는peers,responding,monitored입니다. 새로운reason값과 새로운metrics키가 앞으로도 나타날 수 있습니다. 이 경우 베타 상태에 설명된 대로 처리하십시오. - 기준 head. 체인 head는 공개 RPC 엔드포인트에서 가져옵니다. 별도의 행은 없습니다.
- 운영 주체. PPOI 노드와 Subsquid 배포는 Anon이 운영하지 않습니다. 그곳의 장애는 설정된 배포에 대한 Anon의 판독값으로 나타납니다.
서비스 자체에 대해서는 PPOI 프록시, 브로드캐스터 네트워크, 지갑 동기화를 참고하십시오.
최신성과 캐싱
모니터는 응답하는 각 소스를 약 30초마다 다시 확인하고 스냅샷을 저장합니다. 모든 요청은 메모리에 있는 이 스냅샷으로 응답합니다. 응답에는 다음이 포함됩니다.
Cache-Control: public, max-age=15, s-maxage=30, stale-while-revalidate=30, stale-if-error=300
| 지시어 | 효과 |
|---|---|
max-age=15 |
브라우저가 사본을 15초 동안 재사용합니다. |
s-maxage=30 |
CDN 같은 공유 캐시가 자신의 사본을 30초 동안 재사용합니다. 재확인 한 번의 주기입니다. |
stale-while-revalidate=30 |
캐시는 그 이후에도 최대 30초 동안 만료된 사본을 제공하면서 새 사본을 가져올 수 있습니다. |
stale-if-error=300 |
오리진에 오류가 생기면 캐시는 사본을 최대 5분 동안 계속 제공할 수 있습니다. |
행은 최대 얼마나 오래될 수 있습니까? 응답하는 소스의 경우, 오리진에서 행은 최대 약 44초 지난 상태일 수 있습니다. 30초 주기, 3초의 지터, 최대 10초가 걸리는 프로브, 게시에 걸리는 1초를 더한 값입니다. 캐시는 여기에 최대 60초를 더합니다(s-maxage 30초와 stale-while-revalidate 30초). 따라서 정상 행은 관측된 뒤 최대 약 104초 만에 도착하며, 150초의 수명 안에 들어오므로 이미 만료된 상태로 도착해서는 안 됩니다.
계속 실패하는 소스는 더 드물게 재확인합니다. 연속 실패할 때마다 모니터는 해당 소스를 다시 시도하기까지의 대기 시간을 두 배로 늘립니다. 30초, 60초, 그다음 상한인 2분입니다. 지터와 최대 10초가 걸릴 수 있는 프로브를 더하면, 중단된 소스의 행은 오리진에서 최대 약 133초, 캐시가 여러분에게 전달할 즈음에는 최대 약 193초 지난 상태일 수 있습니다. 이는 150초의 수명을 넘기므로 unavailable 행이 이미 만료된 채로 도착할 수 있습니다. 그러면 unavailable이 아니라 만료된 행으로 보입니다. 만료된 행은 “최근 측정값 없음”으로 취급하고 절대 정상으로 보지 마십시오. 중단된 서비스가 바로 그렇게 보일 수 있습니다.
최신성은 HTTP가 아니라 각 행에 속합니다. 행의 expiresAt이 시스템 시계 기준 현재 시각과 같거나 그보다 이전이거나, observedAt이 5분 이상 지났다면 status가 무엇이든 만료된 행으로 취급하십시오. 상태가 요구하는 타임스탬프가 없거나 읽을 수 없는 행, observedAt이 현재보다 약 30초를 넘게 미래인 행, expiresAt이 observedAt보다 늦지 않은 행은 unknown으로 취급하십시오. 200, 304, 캐시 적중은 어느 것도 행의 수명을 갱신하지 않습니다.
모니터가 멈춘 경우. 모니터가 동작하는 동안에는 모든 프로브가 멈추더라도 generatedAt이 최소 30초마다 갱신됩니다. 모니터가 멈추면 저장된 보고서는 그대로 남고 행은 expiresAt에 따라 만료됩니다. stale-if-error로 제공된 사본도 마찬가지입니다. 둘 다 만료된 것으로 보이며, 정상으로 보이는 일은 없습니다.
ETag와 304. ETag는 강한 검증자로, 본문에서 얻은 따옴표로 묶인 16자 해시입니다. 모니터는 프로브가 완료될 때마다, 그리고 최소 30초마다 게시하며 generatedAt이 본문에 포함되므로 ETag도 최소한 그만큼 자주 바뀝니다. If-None-Match는 약한 비교로 판단하며 W/ 접두사는 무시되고 *는 모두와 일치합니다. 304에는 ETag, Cache-Control, CORS 헤더가 있고 본문은 없습니다.
HTTP 상태 코드와 오류
| 상태 | 발생 시점 | 참고 |
|---|---|---|
200 |
스냅샷입니다. | 서비스가 비정상일 때도 동일합니다. 200은 보고서를 읽을 수 있다는 뜻이며 서비스가 정상이라는 뜻이 아닙니다. |
304 |
If-None-Match가 일치했습니다. |
본문이 없습니다. |
204 |
OPTIONS 프리플라이트입니다. |
CORS를 참고하십시오. |
405 |
그 밖의 모든 메서드입니다. | Allow: GET, HEAD, OPTIONS. 캐시되지 않습니다. |
503 |
응답한 서버가 아직 첫 스냅샷을 불러오지 못했습니다. | 오래가지 않으며, 예를 들어 배포 직후에 발생합니다. 캐시되지 않습니다. 백오프를 적용해 다시 시도하십시오. |
404 |
그 밖의 모든 경로입니다. | 게이트웨이가 응답합니다. |
429 |
공정 사용의 속도 제한을 넘었습니다. 이 경로로 IP당 분당 120건을 초과한 경우입니다. | API가 아니라 CDN(Cloudflare 오류 1015)에서 나옵니다. 약 60초 동안 지속되며 Retry-After는 약 60입니다. 캐시 적중 요청도 집계됩니다. |
이 경로에서 오류는 {"error": "<message>"} 형식이며 Content-Type: application/json; charset=utf-8과 Cache-Control: no-store가 붙습니다.
{"error":"liveness report unavailable"}
HTTP 상태 코드로 분기하고, 메시지 텍스트로 분기하지 마십시오. 게이트웨이의 404({"message":"Not Found"})와 CDN의 429는 다른 본문을 사용합니다. 429는 Cloudflare의 text/plain 페이지입니다.
브라우저에서는 429를 읽을 수 없습니다. CDN의 429 페이지에는 Access-Control-Allow-Origin이 없으므로 브라우저가 이를 차단하고, fetch는 다른 네트워크 또는 CORS 오류와 마찬가지로 TypeError로 거부됩니다. 코드에서는 상태 코드나 Retry-After를 볼 수 없습니다. 모든 네트워크 실패를 429나 503처럼 처리하십시오. 백오프하고, 마지막으로 받은 정상 보고서를 유지하며, 그 행은 expiresAt에 따라 만료되도록 두십시오.
첫 스냅샷을 불러온 뒤에는 장애가 생겨도 503이 발생하지 않습니다. 서버는 마지막 스냅샷을 계속 제공하며, 그 행은 expiresAt에 따라 만료됩니다.
CORS
보고서는 공개 자료이며 호출자별 내용이 없으므로, 모든 응답이 모든 오리진을 허용합니다.
| 헤더 | 값 |
|---|---|
Access-Control-Allow-Origin |
* |
Access-Control-Expose-Headers |
ETag |
이 헤더는 요청의 Origin과 관계없이 모든 응답(200, 304, 204, 405, 503)에 포함됩니다. Access-Control-Allow-Credentials는 없습니다. 응답은 Vary: Origin을 보내지 않지만, CDN은 Origin 요청 헤더 값마다 별도의 캐시 사본을 보관하므로, 새로운 오리진의 첫 요청은 캐시 MISS일 수 있습니다. 쿼리 문자열은 무시되므로, ?x=가 붙은 요청도 같은 사본을 사용합니다.
프리플라이트(OPTIONS)에는 204로 응답하며 다음 헤더가 포함됩니다.
| 헤더 | 값 |
|---|---|
Access-Control-Allow-Methods |
GET, HEAD, OPTIONS |
Access-Control-Allow-Headers |
Accept, Content-Type, If-None-Match |
Access-Control-Max-Age |
86400 |
Accept 헤더를 붙인 일반 fetch는 단순 요청이므로 프리플라이트가 필요하지 않습니다. If-None-Match를 직접 설정하는 스크립트는 프리플라이트가 필요하며, 해당 헤더는 허용됩니다.
공정 사용
- 키도 SLA도 없습니다. 베타 단계의 최선 노력 방식 공개 피드입니다.
Cache-Control을 준수하고ETag와If-None-Match를 사용해, 바뀌지 않은 보고서는304로 끝나게 하십시오.- 15~30초보다 자주 폴링하지 마십시오. 데이터는 약 30초마다 바뀌므로, 더 자주 폴링해도 캐시된 사본만 돌아옵니다.
- 지갑은 타이머로 가져오지 말고, 사용자가 이 데이터에 의존하는 화면을 열 때 가져와야 합니다.
- 폴링하는 서버는 신원을 밝히는 설명적인
User-Agent를 보내야 합니다. 예:my-wallet/1.4 (+https://example.com/contact). - 이 경로로 IP당 분당 120건을 넘는 요청은 속도 제한되어 약 60초 동안
429로 응답받습니다. 캐시 적중 요청도 집계됩니다.429와5xx가 오면 백오프하십시오. - 브라우저에서는
429가 읽을 수 있는 응답이 아니라 CORS 또는 네트워크 오류로 나타납니다. 모든 네트워크 실패를429나503처럼 처리하십시오. 백오프하고, 마지막으로 받은 정상 보고서를 유지하며, 그 행은expiresAt에 따라 만료되도록 두십시오(HTTP 상태 코드와 오류 참조).
베타 상태
이 API는 베타이며, Anon은 아직 안정성에 대한 약속을 하지 않습니다.
- 예고 없이 바뀔 수 있습니다. 필드, 열거형 값, 응답의 형태는 예고 기간 없이 추가, 이름 변경, 타입 변경 또는 제거될 수 있습니다. Anon은 지원 중단(deprecation)이나 종료(sunset) 절차, 또는
Deprecation·Sunset헤더를 약속하지 않습니다. schemaVersion도 바뀔 수 있습니다./api/v1은 게이트웨이 배포 전체의 경로 버전이며 이 엔드포인트의 버전이 아닙니다. 이 엔드포인트 자체의schemaVersion은 본문에 있으며 현재는1이지만, 이 값도 바뀔 수 있습니다. JSON Schema는 느슨하게 작성되어 현재의 응답을 설명할 뿐, 약속이 아닙니다.- 호스트는 당분간
api.anon.inc입니다. 이후api.railscan.io같은 별칭이 생길 수 있지만 시점은 약속하지 않습니다. - 변경 기록. 변경은 최선을 다해 아래의 변경 내역에 기록합니다.
변경이 있어도 동작하는 클라이언트를 작성하는 방법:
- 알 수 없는 필드는 무시합니다. 보고서, 각 검사,
metrics등 모든 수준에서 알 수 없는 객체 필드를 무시하십시오. - 닫힌 집합에 의존하지 않습니다. 알 수 없는
status는 해당 행에 한해unknown으로 취급하십시오. 알 수 없는reason은 "세부 정보 없음"으로 취급하고status를 기준으로 행동하십시오. 사용하지 않는service나chainId의 행은 무시하고, 알 수 없는metrics키도 무시하십시오. - 보고서 전체가 아니라 한 행만 실패하게 합니다. 읽을 수 없는 행 하나 때문에 다른 모든 행이 비어서는 안 됩니다.
schemaVersion을 확인합니다. 아는 값이 아니라면 형태가 바뀌었을 수 있습니다. 추측하지 말고, 업데이트할 때까지 보고서를 읽을 수 없는 것으로 취급하십시오.
현재 성립하는 사항입니다. 이는 엔드포인트의 현재 동작이므로 올바르게 처리하십시오. 다만 약속은 아닙니다.
- 지표. 모든 검사에는
metrics객체가 있으며, 알 수 없는 지표 키는 생략됩니다. 모니터링되지 않는 행은metrics: {}입니다. 없는 지표를0으로 읽지 마십시오. - 범위당 행 하나. 서비스와
chainId의 조합은 최대 한 번만 나타납니다.waku는 유일한 공유 행이며chainId: null입니다. 행을 무작정 합산하지 마십시오. 메인넷 포함 여부는 직접 정한 체인 허용 목록으로 결정하십시오. Sepolia(11155111)는 메인넷 집계에 포함되지 않습니다. - 최신성은 행별입니다. 최신성과 캐싱의 규칙을 사용하십시오. 현재
expiresAt이null인 것은unknown과unmonitored행뿐입니다. - 숫자.
position이head를 넘을 수 있으므로 뒤처짐 값은 0 이상으로 제한하십시오.responding은monitored를 넘지 않습니다. 모든 지표는 음이 아닌 안전한 정수입니다.
알려 주지 않는 것
- Railgun 공식 상태가 아닙니다. Anon의 모니터가 Anon의 인프라에서, Anon이 사용하도록 설정된 서비스를 읽은 결과입니다. 해당 서비스에 대해 사용자가 보는 상태는 다를 수 있습니다.
- “안전하게 거래할 수 있음”을 뜻하는 신호가 아닙니다.
ppoi가current라고 해서 특정 쉴드를 사용할 수 있거나 특정 증명이 유효하다는 뜻은 아닙니다. 설정된 PPOI 노드가 자체 현재 인덱스까지 검증했다는 뜻입니다. 개별 지갑의 PPOI 유효성, 규정 준수, 사용 가능한 잔액에 대해서는 아무것도 알려 주지 않습니다. - 브로드캐스터 행이 성능 저하 상태라는 것은 부분적인 측정값일 뿐입니다. 모니터링 대상 브로드캐스터 중 일부가 응답하지 않았다는 뜻입니다. 다른 브로드캐스터나 전달 방식은 여전히 작동할 수 있습니다. 해당 방식과 그 프라이버시 한계는 브로드캐스터 네트워크에서 확인하십시오.
- Waku 피어 수는 전달을 뜻하지 않습니다.
peers는 Anon이 모니터링하는 연결의 연결 수를 셉니다. 메시지가 브로드캐스터에 도달했다가 돌아온다는 사실을 보여 주지는 않습니다. - 인덱서와 Subsquid 행은 사용자의 지갑 동기화 상태가 아닙니다. 해당 서비스가 각자의 체인을 따라잡았는지를 알려 줄 뿐입니다. 지갑 자체의 동기화는 별개입니다. 지갑 동기화를 참고하십시오.
이력
GET https://api.anon.inc/api/v1/railgun/liveness/history는 지난 14일 동안의 같은 행을 5분 버킷으로 반환하며, 24시간·7일·14일 가동률도 함께 제공합니다. 별도의 캐시를 가진 독립된 엔드포인트로, 차트와 상태 페이지에 쓰기 위한 것입니다. 서비스 상태 이력 API를 참고하십시오. 지금 이 순간의 사실을 알려면 이 엔드포인트를 계속 사용하십시오.
프라이버시
이 엔드포인트로 보내는 요청에는 지갑에 관한 정보가 전혀 담기지 않습니다. 주소도 계정도 없습니다. 그래도 Anon과 앞단의 CDN은 다른 HTTPS 요청과 마찬가지로 IP 주소와 User-Agent를 볼 수 있습니다. 타이머로 폴링하는 지갑은 해당 IP가 Railgun에 관심을 갖고 있다는 사실을 30초 간격으로 드러냅니다. 이 점이 중요하다면 필요할 때만 폴링하거나, 자체 서버에서 보고서를 가져와 그 캐시로 사용자에게 제공하십시오.
변경 내역
2026-10-04
이제 Waku와 브로드캐스터가 모니터링되므로, 그 행은 unmonitored 대신 실제 상태를 보고합니다. 속도 제한이 적용됩니다. 이 경로로 IP당 분당 120건을 넘는 요청은 약 60초 동안 429로 응답받습니다.
버전 1 (베타)
최초 릴리스입니다. 베타이며 안정성에 대한 약속은 없습니다. schemaVersion 1. 서비스는 ppoi, indexer, subsquid, broadcasters, waku이며 Ethereum, Arbitrum, Polygon, BNB Chain, Sepolia를 다룹니다. Waku와 브로드캐스터는 나열되어 있지만 출시 시점에는 모니터링되지 않았습니다. 각 검사의 수명은 150초이고, 모니터는 응답하는 소스를 약 30초마다(계속 실패하는 소스는 더 드물게) 다시 확인하며, 응답은 공유 캐시에 30초 동안 캐시될 수 있습니다.