비트코인의 트랜잭션은 하나 이상의 input 과 하나 이상의 output 으로 구성되어있다.
비트코인 인풋은 이전 트랜잭션의 아웃풋으로부터 비트코인을 가져온다는 의미이다.
전통적인 은행 시스템에서 돈을 보내는 과정을 생각해보자.
내가 국민은행 계좌에 10만원을 갖고 있을 때, 친구의 카카오뱅크 계좌로 5만원을 보낸다고 하면,
나는 국민은행 계좌에 로그인해서 국민은행 서버에게 카카오뱅크 계좌로 5만원을 보내라는 트랜잭션을 지시하면 된다.
그러면 은행 서버는 이 트랜잭션을 지시하는 사람이 정말 그 계좌의 주인이 맞는지 확인할 것이다. (otp 등 인증수단)
그리고 이 확인 절차가 통과되었을 때, 계좌의 잔액을 확인한 뒤, 잔액이 충분하다면 돈이 실제로 이동한다.
전통적인 은행 시스템에서 돈을 보낼 때는, 오로지 현재 남아있는 잔액만을 확인한다.
그 잔액이 무슨 과정을 거쳐서 나온 결과인지는 따지지 않는다.
그냥 지금 돈을 보내는 사람이 계좌의 주인이 맞고, 잔액이 충분하다면 돈을 보낸다.
비트코인의 트랜잭션은 완전히 다르다.
내가 누군가에게 비트코인을 보낸다는 것은, 누군가 나에게 보냈던 비트코인을 가져다가 내가 쓰겠다는 것과 같다.
(이 외에는 내가 비트코인을 사용할 수 있는 방법이 없다!)
만약 홍길동이라는 사람이 자신이 직접 채굴한 비트코인을 어떤 주소로 보낸다고 하자.
그러면 홍길동이라는 사람은 채굴 보상에 대한 트랜잭션이 있을 때, 그 트랜잭션 ID(주소)를 인풋으로 지정해야 한다.
그리고 누군가 나에게 보내온 그 주소에 내가 접근할 권한이 있다는 증명을 함께 인풋에 담는다.
다시 예를 들어보자.
앨리스라는 사람이 2개의 비트코인 주소를 갖고 있다고 해보자.
(이전 글에서 설명한 것처럼 비트코인 주소는 월렛 프로그램에 의해서 생성, 관리되며, 여러 개가 생성될 수 있다.)
그리고 a라는 주소에는 누군가 1비트코인을 보냈었고, b라는 주소에는 0.5비트코인을 보냈었다고 해보자.
이때 앨리스가 밥이라는 사람에게 1.4 비트코인을 보내고 싶다면, 이 두 비트코인 주소를 묶어서 밥에게 1.4 비트코인을 지불하는 트랜잭션을 만든다. output 에는 보낼 비트코인의 양(value)과 보낼 밥의 퍼블릭 키를 담아서 트랜잭션을 만든다.
(밥의 비트코인 주소는 밥의 퍼블릭키를 기반으로 생성할 수 있다.)
여기에 더해 이 트랜잭션을 만드는 앨리스는 내가 a, b 라는 두 주소에 모두 접근할 수 있는 권한이 있다는 것을 증명해야 한다.
증명은 '서명'을 통해 할 수 있다. 비트코인 주소가 교묘하게도 퍼블릭 키를 기반으로 만들어져 있기 때문에, 이 퍼블릭 키에 대응하는 프라이빗 키로 뭔가를 서명해서 그 서명도 인풋에 포함시킨다.
그럼 다른 사람이 이를 검증할 때는 인풋에 존재하는 서명을 앨리스의 퍼블릭 키로 검증하면 된다.
그림을 보면 인풋에는 이전 트랜잭션 ID 값들이 들어있다.
이전 트랜잭션의 ID를 통해 이전 트랜잭션의 output을 식별할 수 있고, 이전의 트랜잭션 output 에는 비트코인을 받았던 내 계좌가 들어있다.
(즉, 이전 트랜잭션은 앨리스의 주소로 비트코인을 보내는 트랜잭션인 것이다.)
아웃풋에는 보낼 돈의 양인 value를 satoshi 단위로 적고, 보낼 주소를 만드는데 사용할 보낼 사람의 퍼블릭키를 담는다.
(사토시 단위는 10^8 사토시 = 1비트코인이다.)
이 외에도 비트코인 트랜잭션에는 아주 간단한 스크립트 코드가 들어가 있다.
그래서 매우 제한된 형태이긴 하지만 비트코인에서도 프로그래밍이 가능하다.
이 스크립트 언어를 통해 트랜잭션의 안전성을 보장할 수 있는데, 자세한 것은 뒤에서 스크립트에 대한 내용을 따로 정리할 예정이다.
또 Lock Time 이라는 것이 있는데, 락타임은 이 트랜잭션의 유효기간을 락타임이 지날 때까지로 막을 수 있다.
내가 이 트랜잭션을 통해서 지불을 하긴 하는데, 이 락타임이 지날 때까지 이걸 빼내가지 말라고 막는 것이다.
락 타임의 단위는 실제 시간이 될 수도 있고, 특정 개수의 블록이 채굴될 때까지로 지정할 수도 있다.
비트코인에서는 1개 블록이 채굴되는데 걸리는 평균 시간을 10분으로 유지하기 때문에 만약 50블록동안으로 락 타임을 걸면 대략 500분동안 수신자는 돈을 빼내갈 수 없게 된다.
그래서 만약 내가 상대방과 계약을 맺었고, 이 계약 조건을 이행하기 전에는 빼내가지 못하게 하고 싶을 때 락타임을 걸어둘 수 있다.
만약 상대방이 계약을 지키지 않는 경우, 트랜잭션을 원복하는 등의 조치를 취할 수 있다.
트랜잭션을 이런 형태로 표현할 수도 있다.
트랜잭션의 input, output 은 모두 여러개가 될 수 있다.
내가 스포츠카를 사려면 1.8 비트코인이 필요한데, 여러 주소에 들어있는 비트코인을 합해야 1.8 비트코인이 나올 수도 있다.
또한 비트코인이 나가는 주소 역시 여러군데 일 수 있다.
차를 살 때 외장재 내장 물품 등을 함께 구매하려고 하면 이 각각에 대해 다른 주소로 지불할 수도 있다.
또 굉장히 독특한 점은, 이렇게 지불하고 남은 나의 계좌 잔고를 계산할 때,
일반적인 은행 계좌에서는 그 계좌에 입금되었거나 출금도니 모든 내역을 다 합쳐볼 수 밖에 없다.
하지만 비트코인 시스템은 이를 따르지 않는다.
잔고 금액도 나의 계좌로 내보내는 output으로 하여 내보내도록 하는 것이다.
(이때는 기존의 input 에 들어있는 주소 말고 새로운 나의 output 주소를 사용하면 된다.)
그래서 모든 트랜잭션에 대해서는 그 트랜잭션의 가장 최근 사용되지 않은 아웃풋을 통해 현재 잔액이 얼마가 남았는지를 알 수 있다.
위 그림을 보면 input 에는 3, 2, 5 비트코인이 있으니 총 10 비트코인을 가져다가 지불하는 상황을 보여준다.
output 은 6, 3, 0.9 비트코인을 지불하고 있으며, 이때 6, 3 비트코인은 다른 사용자에게, 0.9 비트코인은 나의 주소로 보내는 잔액으로써 보내고 있다.
그렇다면 남은 0.1 비트코인은 어디로 갔을까?
바로 이 남은 비트코인이 이 트랜잭션을 블록에 포함시켜 채굴하는 채굴자에게 주는 수수료가 된다.
(수수료 값은 자동으로 계산된다.)
이 수수료 가격 역시 시장가격으로 정해져 있고, 시장 가격보다 낮은 수수료를 책정하면 채굴자들이 이 트랜잭션을 포함시킬 확률이 낮아진다. 보통 트랜잭션은 월렛이 만들기 때문에 월렛이 시장 가격으로 알아서 수수료를 책정한다.
물론 수수료 값은 많이 내고 싶으면 그냥 많이 낼 수도 있다.
그리고 실제로 2023년 10월 경에는 누군가 40억원에 달하는 수수료를 냈던 적이 있다.
실수인지 의도인지 모르겠지만 실수라고 해도 이 트랜잭션이 포함된 블록이 채굴되면 이 트랜잭션은 확정되기 때문에 더 이상 되돌릴 수 없게 된다. 그리고 이렇게 채굴된 트랜잭션들은 채굴자들이 더 이상 보지 않는다. (비트코인 트랜잭션의 고유한 특성 중 하나다)
Coinbase Transaction
코인 베이스 트랜잭션은 채굴자에게 주는 작업 증명을 통한 블록 채굴에 대해 주는 보상이다.
그래서 채굴자들은 자신이 명시한 비트코인 어드레이스로 채굴보상을 넘기는 트랜잭션을 포함하여 채굴한다.
물론 이 채굴 보상 역시 다른 채굴자들에 의해 받아들여져야 하기 때문에 내가 마음대로 채굴 보상을 바꿀 수는 없다.
2024년 10월 기준 현재 채굴보상은 3.125 비트코인이며, 21만 블록이 채굴될 때마다 반씩 보상이 줄어든다.
그런데 내가 채굴에 성공해서 비트코인을 받는 트랜잭션을 확정했더라도 이 트랜잭션을 바로 지불하는데 사용할 수는 없다.
왜냐하면 서로 다른 마이너 사이에 거의 동시에 체굴이 이루어질 수도 있기 때문이다.
그래서 채굴에 성공했더라도 내가 보상을 100% 받을 수 있다는 보장은 되지 않으며, 내가 받은 트랜잭션은 100 블록이 이후에 채굴된 뒤에 사용할 수 있게 된다. (1블록을 채굴하는 시간이 10분으로 유지되도록 난이도가 조절되므로 대략 하루가 조금 안되는 시간을 기다려야만 사용할 수 있다.)
그리고 코인베이스 트랜잭션에는 임의의 100바이트 데이터를 집어넣을 수 있는 공간이 있다.
이 공간은 추가적인 Nonce 로 사용할 수 있다.
비트코인 헤더에 있는 32비트 넌스 값이 될 수 있는 값은 2의 32승이므로 10진수로는 꽤 큰 값이다.
(대략 40억이 조금 넘는다.)
이때 운이 안좋으면 내가 40억번 해시 계산을 해도 난이도에 맞는 해시값이 나오지 않을 수 있다.
그렇다고 내가 집어넣겠다고 유효성을 다 검증해둔 트랜잭션을 바꾸는 것은 아쉬우므로 (머클 트리에서 위치를 바꾸면 다시 해시값을 계산해야 한다..) 코인베이스 트랜잭션에 있는 이 임의 데이터 공간에 들어가는 값을 바꾸고 그 위로 올라가면서만 다시 머클트리 해시값을 계산하면 비교적 적은 오버헤드로 머클트리 루트 해시값을 계산할 수 있고, 이 상태에서 다시 넌스 값을 바꿔가며 해시 퍼즐을 풀 수 있다.
참고로 2009년 1월 3일 채굴된 제네시스 블록에는 영국의 일간지 타임즈에 있는 은행에 대한 구제금융 관련 기사 제목이 들어있다.
이것처럼 내가 원하는 데이터를 코인 베이스 트랜잭션에 넣어서 영구히 기록으로 남길 수도 있다.
'CS > 블록체인' 카테고리의 다른 글
[블록체인] 7. 비트코인 네트워크 (0) | 2024.10.15 |
---|---|
[블록체인] 6. Proof-of-Work (Consensus Protocol & Native Currency) (0) | 2024.10.11 |
[블록체인] 4. 디지털 서명과 비트코인 주소 (0) | 2024.10.10 |
[블록체인] 3. 블록체인의 구조와 해시 함수 (0) | 2024.10.09 |
[블록체인] 2. 블록체인의 활용 (0) | 2024.10.09 |