# 트랜잭션 추적: debug_traceTransaction 및 Data API trace 엔드포인트

> Source: https://docs.blockvectra.com/ko/guides/transaction-traces/

## 호출 트리를 재구성하는 두 가지 방법

트랜잭션 추적(trace)은 실행 시점의 재구성된 호출 트리입니다. 즉, 어떤 컨트랙트가 어떤 입력값으로 호출되었는지, 가스를 얼마나 소비했는지, 어떤 하위 호출을 수행했는지를 보여줍니다. BlockVectra는 두 가지 인터페이스를 통해 이를 제공합니다:

* **JSON-RPC `debug_trace` 메서드**(`debug_traceTransaction` 등) — JSON-RPC 엔드포인트를 통해 체인 노드를 대상으로 실행되므로, 노드가 여전히 보유하고 있는 최근 상태를 추적할 수 있습니다.
* **Data API traces** — `GET /{chain}/transactions/{hash}/trace` 및 `GET /{chain}/blocks/{number}/traces`는 REST를 통해 저장 및 인덱싱된 호출 트리를 반환합니다.

두 방식 모두 동일한 API key를 사용하며 메서드 가중치에 따라 CU로 측정됩니다(아래 가중치 참조). 어느 방식을 선택할지는 단일 트랜잭션이 필요한지 전체 블록이 필요한지, 대상이 얼마나 최근의 것인지, 페이지네이션 없이 전체 블록을 탐색하려는지에 따라 결정됩니다.

## debug\_trace 메서드에 적용되는 제한 사항

`debug_trace` 요청은 체인의 메서드 정책에서 허용하는 메서드와 tracer에 대해서만 승인됩니다:

* **허용되는 tracer**: `tracer` 파라미터는 내장 네이티브 tracer인 `callTracer`, `flatCallTracer`, `prestateTracer`, `4byteTracer`, `noopTracer`만 허용하거나, 생략하여 기본 struct logger를 사용할 수 있습니다. 그 외의 값은 JSON-RPC 오류 `-32602 tracer not allowed`(과금되지 않음)로 거부됩니다.
* **추적 제한 시간**: `timeout` 파라미터는 유효한 기간이어야 하며 최대 30초여야 합니다. 그렇지 않으면 요청이 `-32602 trace timeout not allowed`(과금되지 않음)로 거부됩니다.
* **노드 동기화 가드**: 체인의 노드가 동기화되지 않은 동안에는 `eth_chainId`를 제외한 모든 메서드(`debug_trace` 메서드 포함)가 `-32010`(과금되지 않음)을 반환합니다.
* **상태 윈도우**: `debug_traceCall`, `debug_traceBlockByNumber`, `debug_traceTransaction`, `debug_traceBlockByHash`는 체인의 상태 윈도우 내에 있는 블록을 대상으로 해야 합니다. 윈도우보다 이전 대상이거나 `safe`, `finalized`, `earliest` 태그를 사용하는 경우 `-32011`(과금되지 않음)을 반환합니다.
* **해시 및 블록 조회**: 형식이 잘못되었거나 알 수 없는 해시는 `-32000 transaction not found` / `block not found`를 반환하며, 일시적인 오류는 `-32603 upstream unavailable`(재시도 가능)을 반환합니다. 과금되지 않습니다.
* **체인별 메서드 정책**: 체인이 어떤 `debug_trace` 메서드를 허용하는지는 공개된 `GET /v1/chains` 응답을 통해 게시됩니다. 메서드 목록을 하드코딩하지 말고 런타임에 이를 확인하세요. 체인 목록은 [지원 체인](https://docs.blockvectra.com/en/chains/)에서 볼 수 있으며, 메서드 레퍼런스는 [JSON-RPC 메서드](https://docs.blockvectra.com/en/api/json-rpc/methods/) 페이지에 있습니다.

### callTracer로 debug\_traceTransaction 요청하기

아래 호출은 `tracer` 파라미터를 추가하여 호출 트리를 요청합니다:

**cURL**

```bash
export BLOCKVECTRA_API_KEY=rgw_your_api_key

# Add "tracer" to request a call tree with one of the allowed native tracers.
curl -s "https://api.blockvectra.com/v1/robinhood_mainnet" \
  -H 'Content-Type: application/json' \
  -H "x-api-key: $BLOCKVECTRA_API_KEY" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "debug_traceTransaction",
    "params": [
      "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
      { "tracer": "callTracer" }
    ]
  }'
```


  **TypeScript**

```ts
const RPC_ENDPOINT = "https://api.blockvectra.com/v1/robinhood_mainnet";

const res = await fetch(RPC_ENDPOINT, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": process.env.BLOCKVECTRA_API_KEY!,
  },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "debug_traceTransaction",
    params: [
      "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
      { tracer: "callTracer" },
    ],
  }),
});

const body = (await res.json()) as {
  result?: unknown;
  error?: { code: number; message: string };
};

if (body.error) {
  throw new Error(`debug_traceTransaction error ${body.error.code}: ${body.error.message}`);
}
console.log(body.result);

// npx tsx example.mts
```


  **Python**

```python
import os
import requests

RPC_ENDPOINT = "https://api.blockvectra.com/v1/robinhood_mainnet"

res = requests.post(
    RPC_ENDPOINT,
    headers={
        "Content-Type": "application/json",
        "x-api-key": os.environ["BLOCKVECTRA_API_KEY"],
    },
    json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "debug_traceTransaction",
        "params": [
            "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
            {"tracer": "callTracer"},
        ],
    },
)
res.raise_for_status()
body = res.json()

if "error" in body:
    err = body["error"]
    raise RuntimeError(f"debug_traceTransaction error {err.get('code')}: {err.get('message')}")
print(body["result"])
```


## Data API trace 엔드포인트가 제공하는 항목

Data API는 두 가지 범위에 대해 저장된 호출 트리를 반환합니다. 둘 다 페이지네이션되지 않으며 `next_cursor`는 절대 제공되지 않습니다.

* `GET /{chain}/transactions/{hash}/trace` — 트랜잭션 해시로 조회한 단일 트랜잭션의 호출 프레임입니다.
* `GET /{chain}/blocks/{number}/traces` — 블록 내 트랜잭션당 하나의 호출 트리로, `tx_index` 순서대로 정렬됩니다. 트랜잭션이 없는 블록은 `data: []`를 반환합니다.

응답 봉투 구조는 다음과 같습니다:

* `TxTraceEnvelope`: `data`는 직접 `CallFrame`이며, 여기에 `meta`가 추가됩니다.
* `BlockTracesEnvelope`: `data`는 `BlockTraceItem` 배열이며, 각각 `txHash`와 `result`(`CallFrame`), 그리고 `meta`를 포함합니다.

두 trace 엔드포인트 모두 표준 이더리움 `callTracer` 형식을 반환합니다. 이는 Data API의 금액 안전 인코딩의 예외입니다. 다른 곳에서는 `2^53`을 초과할 수 있는 값이 10진수 문자열로 직렬화되지만, 이 두 엔드포인트에서는 `value`, `gas`, `gasUsed`가 10진수 문자열이 아닌 `0x` 접두사가 붙은 16진수 수량으로 반환됩니다. 모든 `CallFrame`은 `type`, `from`, `gas`, `gasUsed`, `input`을 포함합니다. `type`은 `CALL`, `DELEGATECALL`, `STATICCALL`, `CREATE`, `CREATE2`, `SELFDESTRUCT` 중 하나입니다. `CREATE`/`CREATE2` 프레임의 대상에 대해서는 `to`가 생략되며, `STATICCALL` 프레임의 경우 `value`가 생략됩니다. 선택적 멤버는 `output`(호출이 데이터를 반환하지 않은 경우 생략), `error`(성공 시 생략), `revertReason`(`Error(string)`으로 revert된 경우에만 존재), `calls`(호출 순서에 따른 중첩 하위 호출)입니다. 프레임의 추가 멤버는 원본 그대로 유지됩니다.

구조를 구체적으로 보여주는 `CallFrame` 필드 골격은 다음과 같습니다:

```jsonc
{
  "type": "CALL | DELEGATECALL | STATICCALL | CREATE | CREATE2 | SELFDESTRUCT",
  "from": "0x…",                      // 20-byte address
  "to": "0x…",                        // absent for a CREATE/CREATE2 target
  "value": "0x…",                     // 0x-prefixed hex quantity; absent for STATICCALL
  "gas": "0x…",                       // 0x-prefixed hex quantity
  "gasUsed": "0x…",                   // 0x-prefixed hex quantity
  "input": "0x…",
  "output": "0x…",                    // absent when the call returned no data
  "error": "…",                       // absent on success
  "revertReason": "…",                // absent unless the call reverted with Error(string)
  "calls": []                         // nested sub-calls in call order; absent for a leaf frame
}
```

### 파라미터

* `{chain}` (경로 파라미터, 필수): 체인 식별자이며 `GET /chains` 항목의 `chain` 값입니다. 대소문자를 구분하여 정확히 일치해야 하며, 별칭 및 숫자 체인 ID는 허용되지 않습니다.
* `{hash}` (경로 파라미터, 트랜잭션 추적 시 필수): 32바이트 트랜잭션 해시로, `0x` 접두사는 선택 사항이며 대소문자를 구분하지 않습니다.
* `{number}` (경로 파라미터, 블록 추적 시 필수): 음수가 아닌 블록 높이입니다.

### 커버리지 및 완결성

* 두 엔드포인트 모두 `traces` 기능에 속합니다. 이 기능이 없는 체인은 `422 no_coverage`를 반환합니다. 이 데이터셋을 제공하는 체인은 [지원 체인](https://docs.blockvectra.com/en/chains/) 페이지 및 데이터셋 디렉터리를 따릅니다.
* 추적 데이터는 해당 체인의 나머지 인덱싱된 이력보다 늦게 시작될 수 있습니다. `GET /chains`는 이 경계를 `coverage.traces_from_block`으로 보고하며, 이보다 이전이거나 추적할 수 없는 범위 내의 요청은 `422 no_coverage`를 반환합니다.
* 트랜잭션 추적의 경우: 해시를 찾을 수 없는 경우 `404 not_found`를 반환합니다(방금 제출되었거나 채굴된 트랜잭션의 경우 영구적인 것으로 간주하기 전에 몇 초 후 재시도하세요). 해시가 `as_of_block`보다 높은 블록으로 확인되면 `409 not_indexed_yet`을 대신 반환합니다.
* 블록 추적 엔드포인트는 블록 번호를 받습니다. `as_of_block`보다 높은 `{number}`는 `indexed_through`와 함께 `409 not_indexed_yet`을 반환하며, `as_of_block` 이하인 `{number}`는 즉시 제공됩니다.
* 트랜잭션이 있지만 아직 추적 데이터가 없는 최근 블록은 `Retry-After` 헤더와 함께 `503 unavailable`을 반환합니다.

### Data API에서 추적 데이터 요청하기

**cURL**

```bash
export BLOCKVECTRA_API_KEY=rgw_your_api_key

# One transaction's call frame.
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/transactions/0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd/trace" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"

# One call tree per transaction in a block.
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/blocks/79900000/traces" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
```


  **TypeScript**

```ts
const hash = "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd";

const txRes = await fetch(
  `https://api.blockvectra.com/v1/data/robinhood_mainnet/transactions/${hash}/trace`,
  { headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! } },
);
const txBody = await txRes.json();
console.log(txBody.data, txBody.meta);

const blockRes = await fetch("https://api.blockvectra.com/v1/data/robinhood_mainnet/blocks/79900000/traces", {
  headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! },
});
const blockBody = await blockRes.json();
console.log(blockBody.data.map((item: { txHash: string }) => item.txHash));

// npx tsx example.mts
```


  **Python**

```python
import os
import requests

hash_ = "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
headers = {"x-api-key": os.environ["BLOCKVECTRA_API_KEY"]}

tx = requests.get(
    f"https://api.blockvectra.com/v1/data/robinhood_mainnet/transactions/{hash_}/trace",
    headers=headers,
)
tx.raise_for_status()
tx_body = tx.json()
print(tx_body["data"], tx_body["meta"])

block = requests.get(
    "https://api.blockvectra.com/v1/data/robinhood_mainnet/blocks/79900000/traces",
    headers=headers,
)
block.raise_for_status()
block_body = block.json()
print([item["txHash"] for item in block_body["data"]])
```


## 어떤 것을 사용해야 하는가

| 전형적인 작업                                 | 더 적합한 방식                                 | 이유                                                                         |
| --------------------------------------- | ---------------------------------------- | -------------------------------------------------------------------------- |
| 트랜잭션이 블록에 포함된 직후 단일 트랜잭션 재구성            | `debug_traceTransaction`                 | 노드의 현재 상태를 대상으로 실행되며, 가용성은 체인의 메서드 정책을 따릅니다.                               |
| 단일 트랜잭션의 저장된 호출 트리 읽기                   | `GET /{chain}/transactions/{hash}/trace` | REST를 통해 트랜잭션의 `CallFrame`을 직접 반환하며, `as_of_block`까지 제공됩니다.                |
| 한 번의 요청으로 한 블록 내 모든 호출 트리 읽기            | `GET /{chain}/blocks/{number}/traces`    | 페이지네이션 없이 블록 전체를 `tx_index` 순서대로 반환하며, `as_of_block`까지 제공됩니다.              |
| 노드는 아직 보유하고 있지만 데이터셋에는 아직 저장되지 않은 상태 추적 | `debug_trace` 메서드                        | Data API는 `as_of_block`까지 저장된 데이터를 제공하며, 노드는 아직 기록되지 않은 블록에 대해 응답할 수 있습니다. |

## 호출당 CU

모든 메서드는 해당 CU 가중치에 따라 과금됩니다. 아래 가중치는 플랫폼 플랜 API에서 읽어온 값입니다:

**호출당 CU 가중치**

| 메서드 | 호출당 CU |
| --- | --- |
| `debug_traceBlockByHash` | 100 |
| `debug_traceBlockByNumber` | 100 |
| `debug_traceCall` | 100 |
| `debug_traceTransaction` | 100 |
| `trace_block` | 100 |
| `trace_call` | 100 |
| `trace_get` | 100 |
| `trace_replayTransaction` | 100 |
| `trace_transaction` | 100 |
| `data.block_traces` | 200 |
| `data.transaction_trace` | 200 |

거부된 요청은 과금되지 않습니다. 전체 과금 규칙은 [과금되지 않는 요청: 오류 코드 및 과금 규칙](https://docs.blockvectra.com/en/guides/billing-rules/)을 참조하세요.

## 다음 단계

* [무료 플랜 및 요금 확인](https://blockvectra.com/en/pricing/#free): 내 계정에 포함된 혜택 확인.
* [콘솔 로그인](https://console.blockvectra.com/login/?next=%2Fkeys%2F): API key 생성.
