Direct Cell: 거래는 원장 밖에서 어디까지 준비할 수 있을까?
A가 가진 자산 100 중 20을 B에게 보내려고 한다. B는 그중 5를 C에게 보낼 생각이다. A에게 남을 80 중 10은 D에게 보낼 예정이다.
이 거래들을 준비하려면 매번 앞의 거래가 블록에 들어갈 때까지 기다려야 할까? 또 거래의 내용을 만드는 사람과 서명하는 사람, 그 내용이 맞는지 확인하는 사람이 모두 같은 곳에 있어야 할까?
nigo-protocol의 Direct Cell은 소비할 기록과 새로 만들 기록을 거래에 직접 담는다. 하나의 원장, 세 가지 거래 실행 방식에서는 이 요청을 Native Program과 EVM의 요청에 비교했다. 여기서는 Direct Cell의 명시적인 변경안이 거래를 준비하는 장소와 역할을 어떻게 나눌 수 있게 하는지 살펴보자.
그 가능성을 이해하려면 두 가지를 함께 봐야 한다. 어떤 결과를 제안할지 미리 정할 수 있다는 것과, 그 제안이 실제 원장에 확정됐다는 것은 서로 다른 사실이다.
바꾸고 싶은 결과를 거래에 담는다
먼저 A의 100이 하나의 기록 u0에 있다고 하자. nigo-protocol은 이런 상태 기록을 StateCell이라고 부른다.
예제의 자산은 소유자의 직접 이전이 허용되고, 거래 수수료는 0이며, 처리 중 자산 정책과 실행 규칙은 바뀌지 않는다고 가정한다.
추가 발행이나 소각은 없다. u0, u1 같은 이름은 기록을 구별하기 위한 예제 이름이다.
A가 서명할 첫 거래 T1에는 다음 변경안이 들어간다.
T1 — A가 서명
소비: u0 A의 100
생성: u1 B의 20
u2 A의 80
기존 기록 u0의 숫자를 100에서 80으로 고치는 방식이 아니다. u0를 소비하고 수신자와 수량이 정해진
새 기록 두 개를 만든다. 입력 100과 출력 합계 20 + 80은 같다.
이처럼 아직 소비되지 않은 출력을 다음 거래의 입력으로 쓰는 구조를 UTXO라고 한다.
UTXO에서 StateCell까지에서 출발점으로 삼았던 원장 모델이다.
지갑이나 별도의 거래 구성 도구는 이 변경안을 먼저 만들 수 있다. A는 자신이 어떤 기록을 사용하고, 누가 무엇을 받게 되는지 검토한 뒤 서명한다. 도구가 변경안을 만들었다고 A의 서명 권한까지 갖는 것은 아니다.
원장은 제출된 거래에서 서명을 확인하고, 입력을 사용할 권한과 자산별 수량 보존 같은 규칙을 검사한다. 검사를 통과하면 제안된 입력을 소비하고 출력을 반영한다. 따라서 이 경로에서는 다음 상태를 제안하는 일과 그 제안을 원장 규칙으로 판단하는 일이 분리된다.
실행하지 않은 거래의 다음 거래를 준비한다
여기서 출력의 내용뿐 아니라 출력의 식별자도 실행 전에 정할 수 있다면 어떤 일이 가능할까?
nigo-protocol의 Direct Cell 출력 ID는 입력 목록, 출력의 소유자·내용 등 거래의 의미를 묶은 값과 출력의 순번에서 정해진 방식으로 계산된다. 최종 거래 해시는 이 내용과 출력 ID를 함께 묶고, 서명은 그 거래 해시를 대상으로 한다. 전달 과정에서 출력의 수신자나 수량만 바꿔도 같은 서명으로 통과할 수 없다.
이 구조에서는 T1을 원장에 반영하기 전에도 u1과 u2의 실제 ID를 계산할 수 있다.
A가 서명한 T1을 B에게 전달하면, B는 자신에게 올 u1의 20을 입력으로 쓰는 후속 거래 T2를 준비할 수 있다.
A도 u2의 80을 입력으로 쓰는 T3를 준비한다.
T1: A의 u0 100 소비
├─ u1: B의 20
│ └─ T2 (B 서명)
│ C의 5 + B의 15
│
└─ u2: A의 80
└─ T3 (A 서명)
D의 10 + A의 70
세 거래가 순서 조건을 지키며 모두 반영되면 최종 수량은 A=70, B=15, C=5, D=10이다. 합계는 처음의 100과 같다. T2와 T3는 각각 다른 입력을 사용하고, 각 거래는 자기 입력의 소유자가 서명한다.
T2를 미리 만들었다고 그 입력 u1이 현재 원장에 이미 존재하는 것은 아니다.
T2의 변경안은 T1이 먼저 유효하게 반영되어 u1을 만든다는 조건 위에 있다.
반면 T1 뒤의 T2와 T3 사이에는 이 예제의 입력을 놓고 경쟁하는 관계가 없다.
앞선 거래의 결과를 기다려야 하는 관계와, 서로 독립적으로 준비할 수 있는 관계가 거래의 연결에 드러난다.
nigo-protocol에는 선행 거래가 앞에 오는 서명된 Direct 거래 묶음을 제출하는 경로도 있다. 이때 묶음을 수납했다는 사실이 모든 거래를 한 블록에 넣거나, 여러 블록에 걸친 거래를 전부 성공 또는 전부 취소로 처리하겠다는 보장은 아니다. 미리 연결할 수 있는 범위와 함께 확정되는 범위는 따로 정해야 한다.
결정론이 도움이 되는 지점
이 구조의 장점을 결정론으로 설명할 수 있다. 다만 무엇을 같게 두었을 때 결과가 같은지까지 밝혀야 한다.
거래를 검증하는 사람들이 같은 입력 상태, 같은 자산 정책과 실행 규칙, 같은 거래를 사용하면 같은 검증 결과를 얻어야 한다. 이런 성질은 여러 노드가 하나의 원장을 유지하는 데 필요하다. 계정 기반 원장과 EVM 실행에서도 같은 상태와 실행 조건에 대한 결정론은 중요하다.
Direct Cell에서 추가로 눈여겨볼 점은 검증할 변경안과 그 변경이 직접 사용하는 상태가 거래에 드러난다는 것이다. B는 T1을 읽고 자신에게 올 기록의 내용과 ID를 계산할 수 있다. 그 기록을 입력으로 삼아 T2의 출력 5와 15를 미리 정하고, 수량이 맞는지 확인할 수 있다. 원장이 나중에 임의의 수신자나 수량을 골라 주기를 기다리는 구조가 아니다.
검증에 필요한 것이 입력·출력뿐인 것은 아니다. 현재 자산 정책이 직접 이전을 허용하는지, 수수료와 실행량 제한을 지키는지, 입력이 아직 사용 가능한지도 확인해야 한다. 그래서 사전 검증은 확보한 상태와 규칙을 기준으로 이 변경안이 유효한가에 답한다. 정책이 바뀌거나 입력이 먼저 소비되면 제출 뒤의 판단은 달라질 수 있다.
이 구분 덕분에 결정론을 과장하지 않고 활용할 수 있다. 검증에 필요한 맥락을 모아 같은 판단을 재현할 수 있게 만들고, 그 판단이 여전히 성립하는지는 원장에 반영할 때 다시 확인하는 것이다.
작성·서명·검증을 여러 참여자에게 나눈다
앞의 거래를 준비하는 일을 한 서버가 모두 맡을 필요는 없다. 거래 구성 도구가 T1을 만들고, A는 별도의 서명 환경에서 내용을 확인할 수 있다. B는 전달받은 T1을 바탕으로 T2를 만들고 서명하며, A는 자신의 남은 출력으로 T3를 준비한다. 제출을 맡은 다른 참여자는 변경할 수 없는 서명된 거래들을 순서에 맞게 모아 전달할 수 있다.
필요한 상태와 규칙을 확보한 참여자는 다른 사람이 만든 변경안도 다시 검사할 수 있다. 어떤 서비스를 믿고 그 서비스가 말하는 잔액을 그대로 받아들이는 대신, 소비할 기록과 제안된 결과, 서명이 서로 맞는지 대조할 자료를 주고받는 것이다.
여기서 외부 서명은 원장 밖에서 nigo-protocol이 정한 거래 형식과 서명 규칙에 맞춰 서명한다는 뜻이다. 다른 체인의 서명이나 외부 서비스의 승인서를 붙이기만 하면 이 원장의 입력을 사용할 수 있다는 뜻은 아니다. 현재 Direct Cell에서는 한 거래의 모든 입력이 그 거래 서명자의 소유여야 한다. 예제도 A와 B가 각자 자신의 입력을 사용하는 별도의 거래로 구성했다.
오프체인 작성과 서명 자체는 다른 원장 모델에서도 가능하다. 이 설계에서 관심을 둔 부분은 내용과 의존 관계가 구체적인 상태 전이를 참여자 사이에 전달할 수 있다는 것이다. 그 덕분에 변경안 작성과 사전 검증을 여러 장소에 배치하는 설계를 생각할 수 있다.
이것이 곧 노드가 외부 작업자의 “검증 완료”라는 답을 믿고 자신의 검증을 생략한다는 뜻은 아니다. 현재 원장은 블록 실행에서 거래를 다시 검증한다. 외부 작업에 실행을 맡기고 그 결과만 받아들이려면, 그 결과를 신뢰하거나 검증할 별도의 근거가 필요하다.
같은 입력에 서명한 두 약속은 어떻게 될까
A가 B에게 준 T1 외에, 같은 u0의 100을 E에게 전부 보내는 다른 거래에도 서명했다고 하자.
T1: u0의 100 → B의 20 + A의 80
X : u0의 100 → E의 100
두 거래의 서명은 모두 A의 진짜 서명일 수 있다. u0가 아직 사용 가능하고 다른 조건도 맞다면,
각 거래를 따로 검사했을 때 수량과 소유권 규칙도 만족할 수 있다.
하지만 하나의 원장에서 둘을 모두 반영할 수는 없다. 먼저 반영된 거래가 u0를 소비하면
나머지 거래는 사용할 입력을 잃는다.
따라서 B가 T1과 T2를 검토하고 서명을 확인했다고 해서 20을 확정적으로 받은 것은 아니다.
X가 원장에 확정되면 T1의 u1은 만들어지지 않고, 그 출력을 쓰는 T2도 반영될 수 없다.
결정론은 같은 조건에서의 판단을 재현하지만, 충돌하는 두 제안 중 어느 것을 확정할지 대신 결정하지 않는다.
입력의 자료를 어디에서 받았는지도 이 문제와 연결된다.
어떤 확정 상태에서 u0가 존재했다는 증거를 확보하더라도, 그 이후 지금까지 소비되지 않았다는 사실까지
자동으로 따라오지는 않는다. 증거의 기준 상태가 해당 원장의 확정 결과인지 확인하는 일도 필요하다.
거래의 연결을 계산하는 일, 기준 상태의 진위를 확인하는 일, 최종적으로 하나의 이력을 확정하는 일은
서로 이어지지만 맡은 질문이 다르다.
사이드체인으로 이어가려면 무엇이 더 필요할까
여기까지는 Direct Cell의 현재 구조에서 설명할 수 있는 거래 준비와 검증의 분리였다. 이 구조를 바탕으로 원장 밖에서 여러 번 거래하고 결과를 나중에 정산하는 방식을 탐구할 수도 있다. 이 부분은 nigo-protocol에 완성된 기능이 있다는 설명이 아니라 확장 설계의 질문이다.
예를 들어 참여자들이 일부 자산을 본체인에서 잠그고, 그 자산을 둘러싼 변경에 원장 밖에서 합의하는 상태채널을 생각할 수 있다. 잠금은 같은 자산을 본체인에서도 다시 사용하는 일을 막는 역할을 한다. 여기에 어느 상태가 참여자들이 합의한 최신 상태인지, 누군가 오래된 상태를 제출하면 어떻게 대응하는지, 마지막 자산 배분을 어떻게 본체인에 반영하는지에 대한 규칙이 더해져야 한다.
실제 비교 사례로 Cardano의 Hydra가 있다. Hydra Head는 본체인과 같은 거래 형식을 사용하는 상태채널이며, 참여자들의 합의와 서명, 이의제기 기간을 포함한 본체인 정산 절차를 갖춘다. 명시적인 상태 전이를 재사용하는 것 위에 별도의 합의·정산 프로토콜을 쌓는 사례다. Cardano의 Hydra 설명
별도 합의로 동작하는 사이드체인에서는 다른 질문이 생긴다. 본체인이 사이드체인의 어느 상태를 확정된 결과로 인정할지, 그 결과를 어떤 증거로 확인할지, 두 원장에서 자산이 중복 사용되지 않도록 어떻게 이동·정산을 연결할지 정해야 한다. 검증이나 이의제기에 필요한 거래와 상태 자료를 참여자가 계속 얻을 수 있는지도 중요하다.
Direct Cell의 명시적인 입출력과 결정적인 검증은 이런 설계에서 재사용할 기반이 된다. 외부에서 어떤 전이를 계산하고 합의했는지를 구체적으로 표현하기 쉽기 때문이다. 다만 상태 전이를 표현하는 원장 모델과, 그 전이를 어디까지 신뢰하고 확정하는 프로토콜은 함께 설계해야 한다.
변경안에 더 복잡한 사용 조건을 붙인다면
처음의 예제에서 거래 준비는 한곳에 묶이지 않았다. A와 B는 서로 연결된 변경안을 작성하고 각자의 거래에 서명했다. 필요한 자료를 갖춘 참여자는 그 내용을 사전에 검토할 수 있었다. 원장에는 현재 상태에서도 유효한지 검사하고, 충돌하는 제안 중 무엇을 확정할지 판단하는 책임이 남았다.
이 역할 분리가 Direct Cell에서 살펴볼 설계의 장점이다. 명시적인 상태 전이는 거래를 실행할 순서를 분석하는 데 도움이 될 뿐 아니라, 작성·서명·검증을 어디에서 수행할지 선택할 여지도 만든다.
다음에는 그 변경안의 사용 조건을 확장해 볼 수 있다. A가 직접 보내는 대신 S에게 30까지 사용할 권한을 주고, S가 그중 20을 보낸다면 소유자의 서명과 수량 보존만으로는 판단할 수 없다. 승인받은 사용자인지, 남은 한도와 변경 후 기록이 맞는지를 검사할 규칙이 필요하다.
Native Program은 거래의 변경안을 어떻게 검증할까?에서는 명시적인 입력·출력을 유지하면서 이런 업무 조건을 프로그램으로 검증하는 구조를 이어서 살펴본다.