MySQL 에서 출금 건의 수수료 정산을 검증하고 있었다. 이름이 가장 비슷한 fee 를 SELECT 하니 0.00000000 이 나와서 수수료 누락으로 보였는데 화면에는 「출금 수수료 0.0005 BTC」가 찍혀 있었다.
Table of contents
Open Table of contents
증상 — 화면의 금액과 조회한 0
누락이라고 결론 내기 전에 그 화면이 어느 값을 읽어서 보여 주는지를 grep 으로 코드에서 확인했다. 화면은 내가 조회한 컬럼이 아니라 다른 컬럼을 읽고 있었다.
같은 표의 다른 컬럼을 함께 뽑아 보니 금액은 다른 자리에 있었다.
fee 0.00000000
network_fee 0.00050000 ← 여기
fee_from_balance 0.00000000
fee_from_amount 0.00000000
자료가 없었던 것이 아니라 내가 다른 자리를 보고 있었던 것이다.
원인 — 컬럼마다 다른 뜻
왜 컬럼이 여러 개인지 보려고 DESC 로 전부 뽑아 각각이 무엇인지 정리했다.
fee 거래소 수수료를 별도 항목으로 청구할 때의 금액
network_fee 노드가 낸 네트워크 수수료. 회원에게 그대로 전가
fee_from_balance 잔액에서 따로 떼는 방식일 때의 금액
fee_from_amount 출금액에서 차감하는 방식일 때의 금액
이름이 비슷해도 채우는 시점과 주체가 서로 달랐다.
fee 는 거래소 수수료를 별도 항목으로 청구할 때만 채워지는 자리였다. 이 코인은 네트워크 수수료만 전가하는 정책이라 그 방식으로 처리되지 않은 건에서는 NULL 이 아니라 0으로 남으므로 미기입과 실제 0이 구분되지 않았다.
받는 방식이 금액을 바꾼다
정리하다 보니 수수료를 어떤 방식으로 받느냐에 따라 계산되는 금액 자체가 달라진다는 것이 보였다. 체인에서 실제로 얼마가 나갔는지와 무관하게 선택한 방식이 값을 정하고 있었다.
방식에 따라 회원이 받는 수량이 달라졌다. 출금액에서 차감하면 받는 쪽이 적게 받는다. 그 대신 잔액에서 따로 떼면 요청한 수량이 그대로 간다. Bitcoin Core 0.17 의 sendtoaddress 공식 문서가 subtractfeefromamount 를 「수수료를 보내는 금액에서 차감하고 받는 쪽은 입력한 금액보다 적게 받는다」로 적는 그 갈림이 우리 컬럼 넷을 갈랐다. 그러면 운영에서 무엇을 고를지가 정산 결과를 직접 바꾸는 셈이었다.
제약 — 이미 브로드캐스트된 건의 영향
이미 체인에 나간 건이라도 뒤늦게 방식을 바꾸면 우리 쪽 금액이 다시 계산되는 구조였다. 상황이 끝났으니 값이 굳어 있을 것으로 봤던 짐작이 틀렸다.
거기에 방식에 따라 차액 보정 출금이 자동으로 나가는 것까지 있어서 선택지가 사실상 하나로 좁혀졌다. 두 가지 방법 중 재계산이 없고 자동 보정 출금도 안 나가는 방식을 골랐다. 이유는 체인에 나간 수량은 어차피 안 바뀌는데 우리 기록만 다시 계산되면 대사가 어긋나서다.
0을 만났을 때의 순서
이 건에서 얻은 것은 0을 누락으로 바로 읽지 않는다는 순서였다. NULL 이면 안 채워진 것이 분명하지만 0은 정상값일 수 있고 그 판단은 그 컬럼이 언제 채워지는지를 봐야 나온다.
그래서 검증 규칙에 화면이 읽는 컬럼을 grep 으로 먼저 확인한다는 항목을 넣었다. 수수료 구성을 함께 보면 왜 그 값이 나왔는지까지 설명되므로 검증이 한 번에 끝났다.
정리
- 화면 금액이 이름이 비슷한 컬럼에 없을 수 있다
- 화면이 어느 컬럼을 읽는지
grep으로 확인한다 - 컬럼마다 채우는 시점과 주체가 다르다
- 특정 방식일 때만 채워지는 컬럼은
NULL아닌 0이 정상이다 - 수수료를 받는 방식이 금액을 바꾼다
- 이미 브로드캐스트된 건도 방식 변경의 영향을 받는다
- 재계산과 자동 보정 출금까지 보면 선택지가 좁혀진다
- 0을 만나면
DESC로 다른 컬럼을 먼저 본다