노드의 검사 한눈에: 작업 증명, 앞 블록, 시각, 머클 루트, 거래

블록 하나가 다섯 개의 문을 차례로 지나 사슬 끝에 이어진다. 그 아래에서는 한 군데가 노랗게 고쳐진 블록이 첫 문 앞에서 ✗ 를 받고 멈춰 있다.

앞 글은 블록이 노드 사이에 전해지는 길을 다뤘습니다. 노드는 받은 블록을 먼저 검사합니다. 무엇을 볼까요?

검사는 받은 노드가 저마다 합니다

네트워크의 컴퓨터 하나하나를 노드라고 합니다. 그중 전체 노드1는 모든 블록과 거래를 내려받아 스스로 검증한 다음에야 다른 노드에 전합니다 [S2]. 검사에 쓰는 값은 대부분 블록 맨 앞의 헤더에 있습니다(그림 1).

받은 블록의 어느 칸을 어느 검사가 보나 받은 블록은 헤더 80바이트와 그 뒤에 실린 거래들이다. 헤더의 여섯 칸은 version, 앞 블록 헤더의 해시 값, 머클 루트, 시각, nBits, 논스다. 헤더 전체를 해시한 값과 nBits 칸은 작업 증명 검사가, 앞 블록 헤더의 해시 값 칸은 앞 블록 검사가, 시각 칸은 시각 검사가, 머클 루트 칸과 거래들은 머클 루트 검사가, 거래들은 거래 검사가 본다. 받은 블록이 칸을 보는 검사헤더 80바이트 — 통째로 해시하면 ① 작업 증명version앞 블록 헤더의 해시 값② 앞 블록머클 루트④ 머클 루트시각③ 시각nBits (목표 값을 줄여 적은 칸)① 작업 증명논스거래들헤더 뒤에 실려 온다④ 머클 루트⑤ 거래
그림 1. 받은 블록의 어느 칸을 어느 검사가 보는지. 헤더의 여섯 칸은 개발자 참고서의 차례대로입니다 [S3].

328,734번 블록을 받았다고 하고, 노드가 보는 것 가운데 다섯 가지를 따라갑니다. 헤더의 칸은 진짜 블록을 열어 보는 글에서 하나씩 봤습니다.

① 작업 증명: 해시 값이 목표 값 이하인가

작업 증명 검사가 견주는 두 값 받은 헤더 80바이트를 SHA-256 에 두 번 넣으면 해시 값 000000000000000009a11b39…67af3728 이 나온다. nBits 칸 30c31b18 을 풀어 쓰면 목표 값 00000000000000001bc330…0000 이다. 해시 값은 0 이 17개로, 목표 값은 0 이 16개로 시작해 해시 값이 더 작다. 받은 헤더 80바이트 (328,734번 블록)02000000 b6ff0b1b … 30c31b18 fe9f0864SHA-256 두 번1헤더의 해시 값000000000000000009a11b39…67af3728nBits 칸30c31b182목표 값 (풀어 쓴 것)00000000000000001bc330…00001 ≤ 2 인가? — 0 이 17개 대 16개, 더 작다 ✓
그림 2. 작업 증명 검사. 헤더를 해시한 값(1)이 nBits 칸에서 나온 목표 값(2)보다 작거나 같아야 합니다 [S3]. nBits 칸 30c31b18 을 수로 읽으면 0x181bc330 이고, 목표 값은 0x1bc330 × 256(0x18 − 3), 곧 1bc330 뒤에 값이 0 인 바이트 21개가 붙은 수입니다 [S3].

노드는 받은 헤더 80바이트를 SHA-256 에 두 번 넣어 해시 값을 계산합니다. 이 값이 nBits 칸에 줄여 적힌 목표 값보다 작거나 같아야 합니다 [S3]. 16진수로 적으면 이 블록의 해시 값은 0 이 17개로, 목표 값은 0 이 16개로 시작합니다. 그런 헤더를 찾는 작업 증명은 수없이 해 봐야 하지만, 맞는지는 이 계산 한 번이면 압니다 [S4].

목표 값은 블록을 만드는 쪽이 고르지 않습니다. 2,016블록마다 그동안 걸린 시간을 재어 다시 정합니다. 해시 값이 그렇게 정한 목표 값 이하일 때만 블록이 사슬에 들어갑니다 [S1]. 그래서 노드는 nBits 칸이 자기가 기대한 값인지도 봅니다 [S2]. 328,734번은 다시 정하는 자리가 아니라 앞 블록과 같아야 하고, 실제로 같습니다.

② 앞 블록: 이미 받은 블록에 이어지는가

앞 블록 검사가 견주는 두 값 내 사슬의 끝인 328,733번 블록의 헤더를 SHA-256 에 두 번 넣으면 00000000000000000cca48eb…1b0bffb6 이 나온다. 받은 328,734번 블록의 앞 블록 칸에도 같은 값이 적혀 있다. 내가 이미 받은 블록 — 내 사슬의 끝 328,733번 헤더02000000 9dbd8389 … 30c31b18 08699083SHA-256 두 번1그 해시 값00000000000000000cca48eb…1b0bffb62받은 328,734번 블록의 앞 블록 칸00000000000000000cca48eb…1b0bffb61 과 2 가 같은가? — 끝자리 1b0bffb6 까지 같다 ✓
그림 3. 앞 블록 검사. 이미 받은 블록의 헤더를 해시한 값(1)이 받은 블록의 앞 블록 칸(2)과 같아야 합니다 [S3].

헤더의 «앞 블록 헤더의 해시 값» 칸(아래부터 앞 블록 칸)에는 바로 앞 블록 헤더를 SHA-256 에 두 번 넣은 값이 적혀 있습니다 [S3]. 노드는 이 칸이 자기가 이미 받은 블록을 가리키는지 봅니다. 여기서는 내 사슬의 끝인 328,733번의 헤더를 해시해 이 칸과 견줍니다. 두 값은 같습니다. 이 칸이 가리키는 블록을 아직 받지 못했다면, 틀린 블록이라서가 아니라 검증을 끝낼 수 없는 블록입니다 [S2]. 간직했다가 앞 블록을 받은 뒤 검증하는 노드도, 바로 버리는 노드도 있습니다 [S2]2.

③ 시각: 두 가지 범위 안인가

시각 검사가 견주는 값 시간 축 위에 앞 11개 블록의 시각이 점으로 찍혀 있다. 그 중앙값은 01:03:32 이다. 받은 블록의 시각 02:12:52 는 중앙값보다 뒤이고, 내 시계에 두 시간을 더한 04:17:52(3) 보다 앞이라 범위 안에 있다. 00:0001:0002:0003:0004:00○ 앞 11개 블록의 시각 (2014-11-06, UTC)1앞 11개의 중앙값01:03:322받은 블록의 시각02:12:523내 시계 + 두 시간04:17:52이 사이에 있어야 한다1 < 2 ≤ 3 인가? ✓
그림 4. 시각 검사. 받은 블록의 시각(2)이 앞 11개 블록 시각의 중앙값(1)보다 뒤이고, 내 시계에 두 시간을 더한 때(3)를 넘지 않아야 합니다 [S3]. 내 시계는 02:17:52 로 두었습니다.

헤더의 시각은 블록을 만드는 쪽이 적은 값입니다 [S3]. 노드는 두 가지를 봅니다. 이 시각은 앞 11개 블록 시각의 중앙값(크기순으로 줄 세웠을 때 한가운데에 오는 값)보다 뒤여야 합니다. 또 노드의 시계보다 두 시간 넘게 앞서 있으면 안 됩니다 [S3].

이 블록의 시각은 02:12:52 로, 바로 앞 블록의 02:15:26 보다 이릅니다. 그래도 앞 11개 블록 시각의 중앙값 01:03:32 보다는 뒤라서 통과합니다3.

④ 머클 루트: 받은 거래로 다시 계산한 값과 같은가

머클 루트 검사가 견주는 두 값 받은 거래 49건의 해시 값을 둘씩 묶어 SHA-256 에 두 번 넣기를 여섯 줄 되풀이하면 머클 루트 7114b3aa…52aa109d 가 나온다. 헤더의 머클 루트 칸에도 같은 값이 적혀 있다. 받은 거래 49건의 해시 값거래 126473dc4거래 2b9818f9e거래 30ae78e71거래 497833a5dc…둘씩 묶어 SHA-256 두 번, 여섯 줄1다시 계산한 머클 루트7114b3aa8a049bbc12cdde10…52aa109d2헤더의 머클 루트 칸7114b3aa8a049bbc12cdde10…52aa109d1 과 2 가 같은가? — 끝자리 52aa109d 까지 같다 ✓
그림 5. 머클 루트 검사. 받은 거래로 다시 계산한 값(1)이 헤더의 머클 루트 칸(2)과 같아야 합니다 [S3]. 나무는 줄여 그렸습니다.

헤더 뒤에는 거래가 실려 옵니다. 노드는 받은 거래 49건을 저마다 해시하고, 그 값을 둘씩 묶어 가며 머클 루트를 다시 계산하고, 헤더의 머클 루트 칸과 견줍니다. 머클 루트는 블록의 모든 거래에서 나온 값입니다. 따라서 거래 하나만 달라도 헤더의 값과 맞지 않습니다 [S3]. 거래가 실린 차례도 머클 트리의 첫 줄과 같아야 합니다 [S3].

⑤ 거래: 서명이 맞고, 아직 쓰지 않은 돈인가

거래 검사가 보는 것 — 이 블록의 둘째 거래 블록의 둘째 거래는 앞 거래 0cfb070d…f5682a35 의 출력 1번에 든 0.12193137 비트코인을 쓰고, 0.003 과 0.11883137 비트코인을 보낸다. 거래 내용의 해시와 공개 키, 서명으로 계산한 값 e30fea4f…9ec14ffc 가 서명에 적힌 값과 같아 서명이 맞다. 그 출력을 먼저 쓴 거래는 없어 아직 쓰지 않은 돈이다. 블록의 둘째 거래 (259바이트)쓰는 돈: 앞 거래 0cfb070d… 의 출력 1번, 0.12193137보내는 돈: 0.003 + 0.11883137 (비트코인)거래 내용의 해시 · 공개 키 · 서명으로1계산한 값e30fea4f598a32ea10cd5611…9ec14ffc2서명에 적힌 값e30fea4f598a32ea10cd5611…9ec14ffc1 과 2 가 같은가? — 같다, 서명이 맞다 ✓그 출력을 먼저 쓴 거래318,490번 블록에서 생긴 뒤 328,733번 블록까지 없다아직 쓰지 않은 돈인가? — 그렇다 ✓
그림 6. 거래 검사, 이 블록의 둘째 거래. 노드는 먼저 거래에 실린 공개 키를 해시한 값이 가리킨 출력에 적힌 값과 같은지 봅니다 [S7]. 그다음 서명을 뺀 거래 내용을 해시하고, 그 해시와 공개 키, 서명으로 계산한 값(1)이 서명에 적힌 값(2)과 같아야 서명이 맞습니다 [S9]. 1 이 나오는 차례는 아래 시뮬레이터의 «거래» 검사에서 한 칸씩 볼 수 있습니다. 가리킨 출력을 먼저 쓴 거래도 없어야 합니다 [S1]. 값은 블록 탐색기에서 받은 거래에서 나왔습니다 [S6].

백서는 블록 안의 모든 거래가 유효하고 이미 쓴 돈이 아닐 때만 노드가 그 블록을 받아들인다고 적습니다 [S4]. 이 블록의 둘째 거래 같은 거래는 앞 거래가 내보낸 돈(출력)을 가리켜 쓰고, 그 돈 주인의 서명과 공개 키를 싣습니다 [S7]. 그 출력에는 주인의 공개 키를 해시한 값이 적혀 있어, 노드는 실린 공개 키를 해시해 그 값과 같은지부터 봅니다 [S7]. 그 공개 키로 서명을 검증하고, 가리킨 돈이 아직 쓰지 않은 돈인지 봅니다. 한 번 쓴 돈을 다시 가리키는 거래는 이중 지불이라 받지 않습니다 [S1]. 나가는 돈이 들어온 돈보다 많은 거래도 받지 않습니다. 적으면 그 차이가 수수료입니다 [S1]. 이 블록의 둘째 거래는 0.12193137 비트코인을 가리켜 0.12183137 비트코인을 보냅니다. 서명이 맞고, 블록 탐색기의 기록에 그 돈을 먼저 쓴 거래도 없습니다 [S6]. 블록의 첫 거래만은 블록을 만든 쪽이 새로 생기는 돈과 수수료를 받아 가는 거래이고, 그 둘의 합보다 많이 받아 가면 안 됩니다 [S3].

어느 돈이 아직 남았는지는 지금까지의 거래를 모두 알아야 압니다. 전체 노드는 첫 블록부터 가장 새 블록까지 모두 내려받아 검증합니다 [S5].

한 곳을 바꾸면 어디서 걸릴까

받은 블록의 한 곳을 바꾸고 다섯 검사를 다시 해 보세요.

시뮬레이터 ① · 질문: 블록의 한 곳을 바꾸면 어느 검사에서 걸릴까?

받은 블록의 헤더 80바이트 (328,734번 블록) — 바뀐 바이트는 테두리

한 곳을 바꿔 보기

다섯 검사 — 눌러서 하나씩 자세히

여기서 견줍니다

1
2

시각은 2014년 11월 6일(UTC)이고, «내 시계» 는 블록에 적힌 시각의 5분 뒤로 두었습니다. 거래 검사는 거래 49건 가운데 둘째 거래(거래 2) 하나만 합니다. 노드는 그 출력을 먼저 쓴 거래가 있는지를 자기가 가진 사슬에서 찾지만, 여기서는 블록 탐색기의 기록을 받아 두고 봅니다.

헤더의 칸을 바꾸면 해시 값이 달라져, 그 칸을 보는 검사와 함께 작업 증명에도 걸립니다. 이 블록에서는 헤더의 어느 비트를 바꿔도 그랬습니다. 새 해시 값이 다시 목표 값 이하일 가망은 약 1.7해(1.7 × 1020) 분의 1 입니다. 거래를 바꾸면 서명과 머클 루트가 어긋나고, 머클 루트 칸까지 고쳐 적으면 작업 증명이 어긋납니다. 고친 블록이 통과하려면 논스를 다시 찾아야 하고, 그래도 나머지 검사가 남습니다.

통과하면 잇고, 걸리면 전하지 않습니다

노드는 검사를 모두 통과한 블록만 자기 사슬에 잇고 다른 노드에 알립니다 [S2]. 규칙에 어긋난 블록은 잇지도 전하지도 않습니다 [S1] [S2]. 전해지지 않은 블록이 어디서 멈추는지는 앞 글의 시뮬레이터에서 볼 수 있습니다.

노드마다 같은 규칙으로 같은 검사를 합니다. 그러면 노드마다 규칙이 조금 다르면 어떻게 될까요? 실제로 그런 날이 있었고, 곁가지 글에서 다룹니다.

이 글의 계산과 확인

받은 블록은 개발자 참고서가 예시로 싣는 헤더(328,734번 블록)입니다 [S3]. 거래 49건의 해시 값과 앞 11개 블록의 헤더는 공개 블록 탐색기에서 받았습니다 [S6]. 받은 헤더 열두 개는 해시 값으로 서로 이어집니다. 거래 49건으로 계산한 머클 루트는 예시 헤더의 칸과 같습니다. 본문의 시각 세 개는 이 헤더들의 시각 칸을 읽은 값입니다(2014년 11월 6일, UTC). 중앙값은 이 글이 계산했습니다.

SHA-256 은 브라우저의 Web Crypto 로 계산하고 Node 의 crypto 와 교차 확인했습니다. 여덟 가지 바꿔 보기도 저마다 본문에 적은 검사에서 걸렸습니다. 헤더 640비트를 하나씩 뒤집으면 모두 목표 값보다 큰 해시 값이 나옵니다. «약 1.7해 분의 1» 은 2256 을 «목표 값 + 1» 로 나눈 값이고, 해시 값이 고르게 나온다고 본 계산입니다. 이 블록의 첫 거래가 받아 간 25.00381342 비트코인은 새로 생기는 25 비트코인에 나머지 48건의 수수료 0.00381342 비트코인을 더한 값과 같습니다 [S6]. 받아 간 값과 수수료는 블록 탐색기의 값이고, 새로 생기는 25 비트코인은 «처음 50, 210,000블록마다 반» [S3] 에서 계산했습니다.

거래 검사는 이 블록의 둘째 거래 259바이트와, 그 입력이 가리키는 앞 거래를 블록 탐색기에서 받아서 합니다 [S6]. 둘째 거래를 SHA-256 에 두 번 넣으면 머클 트리의 둘째 값이, 앞 거래를 넣으면 입력에 적힌 값이 나옵니다. 입력이 가리키는 출력에는 0.12193137 비트코인과 주인의 공개 키 해시가 적혀 있습니다. 거래에 실린 공개 키를 SHA-256 과 RIPEMD-160 에 차례로 넣은 값이 그 공개 키 해시와 같습니다 [S8]. 서명한 내용은 서명 스크립트를 뺀 거래 전체입니다 [S7]. 서명용 해시는 입력의 서명 스크립트 자리에 앞 출력의 스크립트를 넣고 해시 유형 4바이트를 붙여 SHA-256 에 두 번 넣은 값입니다 [S11]. 서명은 secp256k1 곡선 [S10] 의 ECDSA 이고, 검증은 점 R = u₁·G + u₂·Q 의 x 좌표를 n 으로 나눈 나머지가 서명의 r 과 같은지 보는 계산입니다 [S9]. 들어온 돈에서 나가는 돈을 뺀 0.0001 비트코인이 이 거래의 수수료입니다. 그 출력을 쓴 거래는 블록 탐색기의 기록에 이 거래 하나뿐이고, 앞 거래는 318,490번 블록에 실려 있습니다 [S6].

타원곡선 계산과 RIPEMD-160 은 이 글이 자바스크립트로 직접 짰습니다(교육용 — 실제로 쓰지 말 것). 같은 서명용 해시·서명·공개 키를 Node crypto 의 ECDSA(secp256k1)로도 검증했고, RIPEMD-160 도 Node crypto 의 값과 같습니다. 거래의 어느 비트를 뒤집어도 서명 검증은 통과하지 않았습니다. 서명 스크립트 안의 비트는 서명한 내용이 아니라서, 서명이나 공개 키 자체가 달라져 걸립니다 (verify.mjs 88개 통과).

곁질문
  1. 전체 노드가 아닌 노드도 있나요? 있습니다. 블록 헤더만 내려받고 필요한 거래는 그때그때 전체 노드에 요청하는 방식으로, 개발자 안내서는 SPV(simplified payment verification)라고 부릅니다 [S5]. 헤더는 블록마다 80바이트라, 받는 양은 블록의 수만큼만 늘고 블록의 크기와는 상관없습니다 [S5]. ↩
  2. 앞 블록을 아직 못 받았으면 어떻게 하나요? 블록을 먼저 받는 방식의 노드는 그런 블록을 검증하지 않고 두었다가, 보낸 노드에게 빠진 블록들을 요청해 받은 뒤에 검증합니다 [S2]. 헤더를 먼저 받는 방식의 노드는 앞 블록을 모르는 블록을 받으면 바로 버립니다 [S2]. 두 방식의 차례는 앞 글의 «놓친 블록» 에 있습니다. ↩
  3. 앞 블록보다 이른 시각이 왜 통과하나요? 규칙이 블록의 시각이 차례대로일 것까지는 요구하지 않기 때문입니다 [S12]. 시각은 블록을 만드는 쪽이 자기 시계로 적는 값입니다 [S3]. 그래도 블록마다 앞 11개의 중앙값보다는 뒤여야 하므로, 그 중앙값은 블록이 이어져도 거꾸로 가지 않습니다 [S12]. ↩

출처

  1. [S1] Bitcoin Developer Guide — Block Chain
  2. [S2] Bitcoin Developer Guide — P2P Network
  3. [S3] Bitcoin Developer Reference — Block Chain
  4. [S4] Nakamoto, Bitcoin: A Peer-to-Peer Electronic Cash System (2008) §2 · §4 · §5
  5. [S5] Bitcoin Developer Guide — Operating Modes
  6. [S6] Blockstream 블록 탐색기 — 328,734번 블록 (2026-10-06 기준, 앞 11개 블록과 둘째 거래, 그 앞 거래는 같은 탐색기)
  7. [S7] Bitcoin Developer Guide — Transactions
  8. [S8] Bitcoin Developer Reference — Transactions
  9. [S9] NIST FIPS 186-5, Digital Signature Standard (2023) §6.4.2
  10. [S10] SEC 2: Recommended Elliptic Curve Domain Parameters, Version 2.0 (2010) §2.4.1
  11. [S11] Bitcoin Wiki — OP_CHECKSIG
  12. [S12] BIP 113 — Median time-past as endpoint for lock-time calculations