Skip to content
isdnetworks
Go back

전환 전에 확인할 셋

(수정됨)

출금을 내부 이체로 바꿔 달라는 요청이 둘 왔다. 하나는 됐고 하나는 실패 팝업이 떴다.

Table of contents

Open Table of contents

증상 — 같은 유형의 두 건

두 건의 출금 상태를 봤다.

건 A   signed     (서명 완료, 미전파)
건 B   broadcast  (전파 완료)

signed 와 broadcast 로 서로 달랐다.

같은 유형의 요청인데 화면에서의 결과가 갈린 이유가 여기 있을 것 같았다. 그래서 updateWithdrawalType 이 이 값을 어떻게 다루는지 봤다.

원인 — 상태별로 갈렸다

전환 로직에 상태 분기가 있었다.

public function updateWithdrawalType($withdrawal, $newType)
{
    if ($withdrawal->status === 'broadcast') {
        return $this->fail('철회 불가');
    }
    // signed 면 타입 직접 변경
    $withdrawal->type = $newType;
    ...
}

broadcast 면 철회 불가로 막고 signed 면 타입을 그대로 바꾼다.

broadcast 까지 간 건은 체인에 나갔으니 그 자리에서 막는 것이 정책상 맞았다. 그런데 건 B 는 철회가 안 되자 취소 신청 자체를 시도했고 거기서도 실패했다.

제약 — 가능 금액과 대체 트랜잭션

취소 신청 검증을 봤다.

$cancelable = $this->calcCancelableAmount($withdrawal);
if ($cancelable <= 0) {
    return $this->fail('취소 가능 금액 없음');
}

calcCancelableAmount 가 0 을 내면 신청이 거부된다.

계산 안쪽에 조건이 하나 더 있었다.

private function calcCancelableAmount($withdrawal)
{
    if (!$withdrawal->lock_active) {
        return 0;
    }
    ...
}

원본의 잔액 잠금 플래그 lock_active 가 0 이면 가능 금액이 0 이 된다.

더 보니 조건이 하나 더 있었다. 수수료를 올려 다시 보낸 대체 트랜잭션이 이미 확정 상태였다.

대체 트랜잭션 status  confirmed

confirmed 면 그 대체 건을 먼저 정리해야 한다.

코인이 나갔는데 내부 이체로 바꾸면 나간 코인의 처리가 안 정해진다. confirmed 인 대체 건의 정리가 선행되지 않으면 그것이 어디에도 속하지 않는 상태로 남는다.

전체 흐름 — 셋이 순서였다

조건이 셋이고 순서가 있었다.

1. 출금 상태 확인       →  전파 완료면 직접 처리 필요
2. 대체 트랜잭션 확인    →  확정이면 정리 선행
3. 잠금 플래그 확인     →  0 이면 가능 금액 0

1 이 통과해야 2 를 보는 순서이고 하나라도 안 맞으면 거기서 막힌다.

그런데 화면에서는 실패만 보인다. 어느 조건에서 막혔는지를 안 알려 주니 운영자는 문의를 넣는 수밖에 없다.

검증 — 셋을 한 번에 뽑는 쿼리

이 유형의 문의를 받으면 셋을 함께 뽑는다.

-- 1. 출금 상태
SELECT status FROM withdrawals WHERE id = ?;

-- 2. 대체 트랜잭션
SELECT id, status FROM withdrawal_replacements
 WHERE origin_withdrawal_id = ?;

-- 3. 잠금 플래그
SELECT lock_active FROM balance_locks WHERE withdrawal_id = ?;

status 와 대체 건의 status 와 lock_active 가 한 번에 나온다.

세 값을 나란히 놓으면 어디서 막혔는지가 바로 갈린다. 막힌 자리마다 대응도 달랐다.

1 에서 막힘  →  직접 처리 (정식 경로 불가)
2 에서 막힘  →  대체 건 정리 선행
3 에서 막힘  →  플래그 확인. 왜 0 인지 조사

화면의 같은 실패 팝업이 실제로는 세 가지 다른 상황을 덮고 있었다.

대응 — 메시지에 조건을 담기

근본은 실패 팝업이 이유를 안 알려 주는 데 있었다.

[보이는 것]  실패했습니다
[실제]       조건 셋 중 하나에서 막힘

진단 쿼리를 운영자에게 주는 것과 메시지에 조건을 담는 것 두 가지 방법 중 뒤쪽을 골랐다. 이유는 조건을 표시하면 문의 자체가 줄어서다.

"전파 완료 상태에서는 철회할 수 없습니다"
"대체 트랜잭션이 확정 상태입니다"
"취소 가능 금액이 없습니다"

같은 실패인데 세 가지로 다르게 안내된다.

체인에 나가 전환할 수 없다는 것과 금액이 남지 않았다는 것은 받는 쪽에서 할 일이 다르다. 이것을 별도 개선 항목으로 적었다.

정리


Share this post on:

Previous Post
키를 돌려 쓰려면 죽은 키를 걸러야 했다
Next Post
노드가 밖에서 안으로가 아니라 안에서 밖으로 붙었다