BOLT 12는 Lightning Network에서 결제 조건을 협의하는 프로토콜입니다. 제안인 offer, 인보이스 요청인 invoice_request, 그 결과인 invoice를 구분합니다. 제안은 여러 결제에 쓰도록 계속 공개할 수 있지만, 각 인보이스는 해당 결제의 구체적인 조건을 정합니다.
카페가 자발적 후원을 받을 코드 하나를 카운터에 두고 싶다고 해 봅시다. 같은 일반 BOLT 11 인보이스를 계속 결제하면 문제가 생깁니다. BOLT 12는 그 대신 offer를 공개합니다. 손님의 지갑이 이를 바탕으로 invoice_request를 보내 자기 인보이스를 요청하면 수취인이 새 invoice로 답합니다. 그때 비로소 결제할 수 있습니다. 인쇄한 QR 하나를 여러 사람이 써도 같은 인보이스를 공유하지 않는 것입니다. fetchinvoice 같은 기능으로 인보이스를 받았다고 돈을 보낸 것은 아닙니다. 제안 자체가 카페에 다른 사람 지갑에서 추가 결제를 출금할 권한을 주지도 않습니다. [1] [3] [4]
제안은 비트코인이나 다른 통화로 가격을 표시할 수 있습니다. offer_currency는 ISO 4217 코드를 사용하며, 예를 들어 USD 금액은 센트 단위입니다. 인보이스를 만들 때 수량과 환율 계산이 반영될 수 있습니다. 그러나 최종 비트코인 invoice_amount는 satoshi의 천분의 일인 millisatoshi 단위로, 1000 msat = 1 sat입니다. 지불자는 원래 가격표뿐 아니라 이 금액과 수수료를 결제 전에 알아야 합니다. 요청에서 정확한 invreq_amount를 정했다면 인보이스와 같아야 합니다. 그렇지 않으면 지갑이 허용된 범위를 확인하고 벗어날 때 새 승인을 받아야 합니다. 환산이 어떤 가격이든 묵시적으로 동의한 일이 되어서는 안 됩니다. [1] [3]
인쇄된 코드는 카운터에 남아 있어도 제안 자체는 offer_absolute_expiry로 만료될 수 있습니다. 각 인보이스에도 생성 시각 invoice_created_at과 유효 기간 invoice_relative_expiry가 있습니다. 기간이 없으면 기본값은 7200초, 즉 두 시간입니다. 오래된 인보이스가 영구 연락처는 아닌 셈입니다. 지갑은 메시지에 명시된 필수 기능도 이해해야 합니다. 모르는 짝수 비트는 필수 기능을 뜻해 거절해야 하고, 모르는 홀수 비트는 선택 사항이라 무시할 수 있습니다. 이는 안전한 호환성을 위한 규칙이지 사용자가 코드를 직접 고쳐 넘어가야 할 장애물이 아닙니다. [1]
결제 후에는 인보이스와 지갑의 결과를 보관하세요. 정산 증거에는 결제가 완료될 때 받는 비밀값인 preimage도 포함됩니다. 지갑은 이 값에서 확인용 값인 해시를 계산하고 인보이스에 기록된 결제 해시와 비교합니다. 인보이스와 함께 제시하면 결제되었음을 보여 줄 수 있지만 그것만으로 누가 지불했는지는 알 수 없습니다. 앱 연결이 끊기거나 응답을 잃으면 다시 시도하기 전에 앞선 결제 상태를 확인하세요. 새 인보이스는 또 다른 결제로 이어질 수 있습니다. 정기 결제를 지원한다는 말도 신중히 살펴야 합니다. BOLT 12 지원은 모든 확장 기능 지원이나 자동 출금 허가를 뜻하지 않습니다. 제안으로 돈 받기, 다른 사람의 제안에 결제하기, 연결한 앱에 부여한 권한을 따로 확인하세요. [1] [3]
인보이스 요청과 자금 전송은 네트워크를 다른 목적으로 사용합니다. offer_paths는 요청 메시지의 경로이고 invoice_paths는 결제 경로입니다. BOLT 12는 수취인 연결 정보 일부를 숨기는 blinded paths를 사용합니다. 네트워크 구조를 덜 공개하면 프라이버시에 도움이 되지만 완전한 익명성을 약속하지는 않습니다. 숨겨진 경로도 수취인의 접속이나 유동성, 즉 채널의 필요한 쪽에 충분한 돈이 있음을 보장하지 않습니다. 기술적으로 현재 invoice에는 이런 경로와 대응하는 invoice_blindedpay 결제 정보가 필요하며, 수취인에게 직접 가는 경로도 같습니다. 인보이스 요청에는 전통적인 HTTPS 결제 서버가 필요하지 않습니다. [1] [2]
상점이 손님에게 환불하려면 협의 방향이 바뀝니다. 돈을 보낼 쪽이 앞선 offer 없이 invoice_request를 공개할 수 있습니다. 수취인이 될 손님이 자기 invoice로 답하면 상점이 그것을 결제합니다. 원래 결제를 지우거나 취소하는 것이 아니라 반대 방향의 새 결제입니다. 상점은 인보이스가 의도한 수취인의 것인지 확인해야 하며 때로는 프로토콜 밖에서 연락해야 합니다. 요청을 스캔한 것만으로 환불 자격이 증명되거나 송금이 승인되지는 않습니다. 기술 절차는 소통을 돕지만 누구에게 돌려줘야 하는지 대신 결정하지 않습니다. [1]
BOLT 12는 TLV로 데이터를 저장합니다. 각 필드가 형식, 길이, 값을 담는 방식입니다. 텍스트 제안은 lno, 요청은 lnr로 시작합니다. 문자 집합은 Bech32와 비슷하지만 끝의 체크섬은 없습니다. 그것만으로 누구에게 돈을 보내도 되는지 알 수는 없습니다. offer 자체에는 서명이 없습니다. BIP340 Schnorr 디지털 서명은 인보이스와 제안에 응답하는 일반적인 요청을 검증하는 데 쓰입니다. 환불할 때처럼 앞선 제안 없이 독립적으로 공개하는 요청에는 서명이 없습니다. 서명은 Merkle 구조의 루트, 즉 관련 필드를 함께 계산해 얻은 확인용 값에 연결됩니다. 따라서 항상 모든 세부 정보를 드러내지 않고 선택한 필드를 증명할 수 있습니다. 서명된 조건을 바꿔도 된다는 뜻도, 상인의 법적 신원을 증명한다는 뜻도 아닙니다. [1]
지갑은 아무 서명된 인보이스가 아니라 자기 요청에 대한 답을 받았는지 확인해야 합니다. invoice_request에서 invoice로 복사된 필드와 네트워크, 금액, 서명을 비교합니다. invoice_node_id 공개키는 offer_issuer_id와 같아야 하며, 그 식별자 없이 해당 숨겨진 경로를 쓰는 제안이라면 마지막 blinded_node_id를 확인합니다. 도장이 진짜인지만 보는 게 아니라 계산서가 내 테이블 것인지 살피는 것과 같습니다. Merkle 구조가 선택적 증명을 가능하게 해도 지갑은 결제에 필요한 전체 조건을 검증해야 합니다. 다른 사람의 유효한 인보이스가 서명 검사를 통과했다는 이유만으로 올바른 청구서가 되지는 않습니다. [1]
더 정확히 이해하려면 이 항목과 함께 다음도 읽어 보세요 BOLT 11, Lightning Network, Lightning Routing, Bitcoin 프라이버시, Satoshi, LNURL. 다음 항목에서도 이 글을 참조합니다 BOLT 11, LNURL, Just-in-Time Channels.