CoinCraft
기술 가이드

출금 이중 레이어 추적: 요청과 실행을 왜 분리해야 하는가

이서연

이서연

솔리디티 개발자 출신. 복잡한 기술을 누구나 이해할 수 있게 쓴다.

Patent-D 시리즈 D-6 | 출금 이중 레이어 분리 추적 시스템

난이도: ★★★★ | #이중레이어추적 #nonce관리 #TxAttempt #블록체인예외처리

문제: tx_hash 하나로 관리하면 생기는 일

블록체인으로 송금하면 끝난 줄 안다. 그런데 실제 시스템을 운영해보면 그 사이에 온갖 일이 생긴다.

상황 1 Gas Price가 너무 낮았다: 이더리움이 혼잡할 때 gas price를 낮게 설정하면 트랜잭션이 멤풀(mempool)에 갇힌다. gas price를 올린 새 트랜잭션을 같은 nonce로 제출한다(Replacement). 이제 같은 출금에 대해 tx_hash가 두 개가 되었다. 어느 것이 최종 확정인가?

상황 2 트랜잭션이 사라졌다: 네트워크 혼잡으로 트랜잭션이 멤풀에서 제거(Drop)되었다. 출금 상태는 전송 중이지만 실제로는 사라진 상태다.

핵심 아이디어: 1:N 이중 레이어 분리

비즈니스 레이어(Withdrawal)와 체인 실행 레이어(TxAttempt)를 1:N으로 분리하고, DB 제약으로 nonce 중복과 원장 중복을 구조적으로 차단한다.

이중 레이어 엔티티 관계

  id, tenant_id, to_address, amount, asset_type
  status: PENDING/PROCESSING/SETTLED/FAILED
      | 1:N

  id, withdrawal_id (FK)
  tx_hash, nonce, gas_price
  status: PENDING/CONFIRMED/FAILED/DROPPED/REPLACED/REVERTED/RPC_INCONSISTENT
  canonical: BOOLEAN
      | 1:1

  chain_type, from_address, nonce
  UNIQUE(chain_type, from_address, nonce)

canonical 플래그 DB 보장

-- withdrawal당 canonical=true는 최대 1건만 허용
CREATE UNIQUE INDEX idx_tx_attempts_canonical
    ON tx_attempts (withdrawal_id)
    WHERE canonical = true;

두 번째로 canonical=true를 설정하려는 UPDATE는 DB 제약 위반으로 차단된다. 코드가 실수해도 DB가 막는다.

6종 예외 분류 및 자동 라우팅

예외 코드원인자동 처리
FAILED트랜잭션 제출 자체 실패새 TxAttempt 생성
EXPIRED제출 deadline 초과새 TxAttempt 생성
DROPPED멤풀에서 제거됨새 TxAttempt 생성 (gas 상향)
REPLACED다른 tx가 같은 nonce로 확정원장 불일치 검사 to canonical 재지정
REVERTED체인 실행 후 revert수동 개입 필요
RPC_INCONSISTENT복수 RPC 간 불일치수동 개입 + D-7 강등 모드

Gas Price Spike 시나리오

Withdrawal W-001 (10 ETH to 0x...)
  |
  TxAttempt T-1 (nonce=42, gas=30gwei) to DROPPED
  nonce_reservations: (EVM, 0xFrom, 42) 기록
  |
  TxAttempt T-2 재시도
  nonce=42 INSERT: UNIQUE 위반! to nonce=43으로 자동 재시도
  TxAttempt T-2 (nonce=43, gas=80gwei) to CONFIRMED
  canonical=true to Withdrawal W-001.status = SETTLED

핵심 요약

  • Withdrawal(비즈니스)과 TxAttempt(체인 실행)를 1:N으로 분리
  • nonce_reservations UNIQUE 제약으로 nonce 중복을 DB 계층에서 원자적 차단
  • canonical 플래그로 원장 반영 기준 단일 보장
  • 6종 예외 분류로 자동 재시도/수동 개입 경로 결정

다음 편: D-7 RPC 장애 대응, 멀티 RPC 쿼럼과 동적 강등 모드