비트코인 채굴은 프로그래밍적으로 어떻게 되는 것인가?

By @jayground811/25/2017kr

안녕하세요. 고양이를 좋아하는 Jay입니다.

채굴(mining)하면 뭐가 제일 먼저 떠오르나요? 저는 비트코인에 대해서 잘 모를 때, 광산에서 금을 캐내는 것처럼 비트코인을 채굴하는 이미지에 많이 노출되서 이런 그림이 제일 먼저 떠오르네요. 이번에는 채굴을 어떻게 하는 것인지 프로그래밍적으로 설명해보고자 합니다. 혹시나 저처럼 막연하게 채굴을 금캐는 모습을 상상하는 분이 있다면, 이번 설명으로 조금은 구체적인 그림을 그릴 수 있게 되었으면 좋겠습니다.

mining image

제일 먼저 **해시함수**가 무엇인지 이해할 필요가 있습니다. 간단하게 설명하면 어떤 메세지를 입력하면 해시함수가 이상하게 생긴 문자를 만들어줍니다. 비트코인 블락정보를 보면 아래처럼 Hash라고 이상하게 긴 문자가 있습니다.

**00000000000000000054022a7d9fd14761c9962f9f5d44f1caffbd740b73d6a2**

비트코인 블록의 정보는 여기서 볼 수 있습니다. 이번블락의 해시값, 머클루트값도 해시함수에 의해서 생성된 문자입니다. 그럼 간단하게 해시함수의 특징들을 살펴보겠습니다.

해시함수


해쉬 함수는 블록체인뿐만 아니라 다른 곳에서 다양한 목적으로 사용됩니다. 여기서는 암호에 사용되는 해시함수 중 비트코인에 사용되고 있는 SHA256 해시함수를 바탕으로 설명하고 있습니다.

해시함수는

1.똑같은 메세지 값을 해시하면 똑같은 결과가 나옵니다.

'hello world!'를 해시하면 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 결과값이 나옵니다.
'hello world!'를 다시 해시하면 동일한 결과값 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 이 나옵니다. 'hello world!'를 해시하면 언제나 동일한 결과값이 나오게 됩니다.

2.결과값으로 어떤 메세지가 해시되었는지 알수가 없다.

7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 결과값만 가지고 'hello world!'이라는 걸 알 수 없습니다. 결과값이 어떤 메세지 값을 가지고 있는지 알 수 있는 방법은 하나씩 메세지 값을 넣어 보는 수밖에 없죠. 즉, 'hello'를 해시해서 결과값과 같은지 확인하고 다르면, 다른 값 'hello jay'를 넣어서 해시해보고, 이것도 아니면 다른 메세지 값을 해시해서 결과값과 같은지 보고, 이렇게 수많은 경우의 수를 하나씩 해보면서 동일한 결과값이 나오길 바래야 합니다.

3.메시지 값을 조금만 바꿔도 해시결과값을 많이 달라진다.

'hello world!'를 해시하면 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9가 나왔습니다. 그럼 글자하나만 대문자로 바꿔서 'Hello world!'를 해시해보면 c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a 많이 달리진 해시결과값이 나옵니다.

4.메세지 길이에 상관없이 똑같은 길이의 해시 결과값이 나옵니다.

'hello world!'를 해시하니깐 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9로 64자리의 문자가 만들어졌죠? 메세지값을 'Hello world!Hello world!Hello world!Hello world!Hello world!Hello world!Hello world!'라고 해서 해시해도 결과값은 동일한 64자리의 문자 3738d3dfa02f603e849ad63c5aaf54ae64b95a9e837f1485401a8449d3b1cf7f 가 나옵니다. (16진수로 되어 있어서 64자리인데 Sha256에서 힌트를 얻으면 2진수로는 256자리가 됩니다.)

5.다른 두개의 메세지 값이 동일한 해시 결과값을 가지는 것이 거의 불가능하다.

생성된 해시값은 유일한 값이 됩니다. 'hello world'를 해시했더니 A가 나왔는데, 다른 메세지 값인 'welcome to korea'로 해시했더니 동일한 A가 나오는 경우가 없다는 것입니다.

6.메시지값을 해시하여 해시 결과값을 얻는데 큰 연산이 필요하지 않고 빠르게 작동합니다.


그럼 해시함수가 마이닝에 어떻게 활용될까요?


블록의 해더파일이 위에서 설명한 메세지값이 되고, 마이너는 이것을 해시합니다. 'hello world!'를 해시해서 7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 값이 나온 것처럼, 해더파일을 해시해서 해시값을 얻는 것입니다.

그럼 375210번째 블록의 정보를 가지고 해시값이 생성되는 과정을 설명해보겠습니다. 먼저 해더는 아래와 같이 구성되어 있습니다. 머클루트에 대해서는 제가 이전 포스팅으로 설명했으니 참고하세요.

해더 종류 설명
버전 버전별의 일종의 규칙이 달라집니다
이전 블록의 해시값 연결된 블록의 해시값
해시머클루트 값 트랙잭션의 값을 통합해서 가지고 있는 값
타임스탬프 시간값을 보여줍니다
Bits 난이도값
Nonce 채굴자가 이 값을 하나씩 늘려가서 정답을 찾습니다

그럼 이제 375210번째 블록의 정보로 정리해보겠습니다.

버전 : 3

이전 블록의 해시값 : 0000000000000000051f5de334085b92ce27c03888c726c9b2bb78069e55aeb6

해시머클루트 값 : f4db18d3ecab87eeb23a56490d5b0b514848d510d409b43f6bbf2b82f55da8db

타임스탬프 : 2015-09-19 11:59:45

Bits : 403867578

Nonce : 3548193207

이제 이 값들을 다 더해서 메시지 값을 만듭니다. 이 값들은 사이즈(바이트값)에 맞게 그리고 16진수 형식으로 그리고 리틀 엔디언(little endian) 형식으로 나타내야 합니다. 타임스탬프는 Unix Epoch타임으로 변경해줘야 합니다. 그냥 저 값들을 형식에 맞게 바꿔주는 작업이 필요하다는 걸로 이해하시면 될 것 같습니다.

**버전 + 이전블록해시값 + 해시머클루트값 + 타임스탬프 + bits + nonce. 이렇게 값들을 연결해서 긴 메시지 값을 만듭니다. ** 이걸 위에서 설명한 해시함수에 한번 넣어서 해시를 만들고 그걸 다시 해시함수에 넣어서 해시를 만듭니다. 두번해주는거죠. 그럼 짜잔 해시값이 나옵니다.

**00000000000000000be983a81043933c38008010b849fd6a35d5dd2d57f929bd**

그럼 채굴자(마이너)는 CPU나 GPU로 엄청나게 전기를 쓰면서 무엇을 하는 것일까요?

mining device

간단하게 말하면 채굴자는 해더에 있는 nonce값을 하나씩 변경해가면서 특정 값보다 작은 해시를 찾습니다. 해시함수 특징중에 '2.결과값으로 어떤 메세지가 해시되었는지 알 수 없다.', '3.메시지 값을 조금만 바꿔도 해시결과값이 많이 달라진다.' 기억나시나요? nonce 값을 조금만 바꿔도 해시값을 크게 달라집니다. 그리고 해시결과값을 통해서 역으로 어떤 메세지값을 넣어야되는지 알수가 없으니, 원하는 해시값을 찾기 위해서는 하나씩 넣어서 결과값을 볼 수 밖에 없습니다.

예를 들면, 채굴자는 나머지 해더값에 nonce값을 1로 넣어봐서 해시값을 구해봅니다. 원하는 해시값이 안 나오면, nonce값에 2를 넣어서 다시 해시값을 구해봅니다. 또 원하는 해시값이 안 나오면 다른 값을 넣어봅니다. 이렇게 숫자를 하나씩 변경해가면서 원하는 값이 나올때까지 계속 반복합니다. 컴퓨터가 이렇게 반복하면서 연산을 하는 거죠.

특정 값보다 작은 해시를 찾는 것은 경쟁입니다. 저랑 여러분이 이 해시값을 찾는데 제가 먼저 찾으면 제가 그에 대한 보상으로 비트코인을 받습니다. 홍길동이라는 사람이 먼저 찾으면 그사람이 블록을 생성한거고 그사람이 비트코인을 보상으로 받는 것이죠. 그래서 컴퓨터를 최대한으로 빠르게 돌려서 다른 사람보다 이 해시값을 찾을려고 하는 것이죠.

그럼 특정한 값보다 작은 해시값은 어떻게 결정되는건가요?


495954번째 블록 해시값을 한번 봅시다.

00000000000000000029f9bc75b5e62e12e4dc3387ea5abfe6951519f66e59c3

100000번째 블록 해시값은 어떨까요?

000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506

1000번째 블록 해시값은

00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09

여기서 뭔가 패턴이 보이시나요? 495954번째 블록부터 1000번째 블록으로 갈수록 해시값의 0이 점점 줄어드는게 보이네요. 반대로 블록의 순서(Height) 커질수록 0이 많이진다고 할 수 있죠. 위의 값은 16진수로 되어 있는데 우리가 보기 편한 10진수 값으로 바꾸면 더 확실한 패턴을 볼 수 있습니다.

1000 : 21190640912980581113825823661692185883147471094586368510990797434121

100000 : 1533267872647776902154320487930659211795065581998445848740226310

495954 : 4020457218155086056100726400279037738012423080228313539

뒤에 블록일수록 값이 작아지죠? 숫자가 너무 많이 나와서 좀 머리가 아프실수도 있는데, 숫자의 자릿수가 줄어드는 것만 보세요. 블록이 뒤로 갈 수록 값이 작이지는 것을 볼수가 있습니다.

이제 난이도(Difficulty)랑 연결해서 생각해야 합니다. '작은 값은 난이도가 높다.'


작은 값은 난이도가 높습니다. 채굴자(마이너)가 해시를 하면서 정답을 찾기가 더 어려워진다는 것을 의미합니다. 예를 들어서 설명을 하겠습니다. 우리가 주사위 두개를 던진다고 합시다. 주사위 두개를 던져서 나오는 값을 더한 것이 해시값이라고 해보겠습니다. 그럼 주사위를 던져서 나올수 있는 값의 범위는 2 ~ 12가 되고, 경우 수는 36가지가 되겠죠. 여기서 12보다 작은 값을 찾으라고 하면 6,6이 나오는 경우 빼고 35가지 경우가 다 12보다 작은 값이 될 것입니다. 그럼 7보다 작은 값을 찾으라고 하면 9가지 경우만 해당되겠죠.

12보다 작은 값 : 36가지 중에 35가지만 포함

7보다 작은 값 : 36가지 중에 9가지만 포함

36가지 중에 한 가지를 임의로 선택했을 때 12보다 작은 값은 35/36의 확률로 찾습니다. 한번의 시도로 정답을 찾을 가능성이 높겠죠. 근데 7보다 작은 값은 9/36의 확률로 찾게 될 것입니다. 한번의 시도로 정답을 찾기는 쉽지가 않겠죠. 더 많은 시도를 해서 찾을 가능성이 높습니다.

1000번째 블록의 값은 컸죠? 채굴자가 블록의 해더로 만드는 해시값이 큰 값보다 작으면 되니깐(12보다 작은 값을 찾는 것처럼), 적은 시도로 찾을 가능성이 높겠죠. 10000번째 블록의 값은 작아졌으니깐(7보다 작은 값을 찾는 것처럼), 더 많은 시도를 해서 찾을 가능성이 높을 것입니다.

어느 특정한 값보다 작아야 한다는 것은 해더 값의 bits(난이도 값)에 표시되어 있습니다.


예제로 설명했던 375210번째 블록을 봅시다.

bits는 403867578였습니다. 이 값보다 작은 해시값을 찾아야합니다. bits값을 해당하는 공식에 넣고 똑같은 16진수로 바꿔보면 아래와 같습니다.

**타켓 값 : 00000000000000001287ba000000000000000000000000000000000000000000**

그럼 375210번째 블록 해시값만 비교해볼까요? 그냥 단순하게 앞부터 0이 더 많으면 더 작은 값이니깐, 375210번째 블록 해시값이 bits로 계산된 타켓(Target)보다 작은 걸 확인할 수 있습니다. 채굴자들이 nonce값에 하나씩 넣어보면서 타켓(target)값보다 작은 해시값을 찾아야지 정답이 됩니다. 정답을 찾으면 이제 블록을 생성하고 보상으로 비트코인을 받는 거죠.

**블록 해시 값 : 00000000000000000be983a81043933c38008010b849fd6a35d5dd2d57f929bd**

타켓값 앞의 0 갯수 : 0000000000000000
해시값 앞의 0 갯수 : 00000000000000000

좀 더 자세히 알고 싶은 분들을 위해서 추가적으로 설명하면, 난이도(difficulty)는

**난이도 = 제일 어려운 난이도 타켓 값 / 현재 타겟 값**

으로 되어 있습니다. 현재 타켓 값이 작아질수록 난이도가 증가하겠죠? 나눗셈이 보이니깐 이건 소수값이 됩니다. 그래서 bits는 부동소수값으로 표현되어 있습니다.

난이도 값은 2016블록마다 변경됩니다.


난이도는 20160블록마다 변경이 됩니다. 비트코인에서는 블록하나당 10분을 걸리는 걸 목표로 하니깐, 약 2주에 한번씩 난이도가 조정됩니다. 채굴자(마니어)들이 너무 빨리 찾으면 난이도를 올려야겠죠. 블록하나당 10분을 기준으로 잡았으니깐, 20160블록 * 10분 하면 201600분 걸리는데 기준이 됩니다. 이보다 더 빨리 블록 20160개가 생성되었다면 난이도를 올리고, 이보다 늦게 블록 2016개가 생성되었다면 난이도를 낮추게 되어있습니다.

**새로운 난이도 = 현재 난이도 * ( 2016개 걸린 시간(분) / 20160분)**
mining image
*[img-2] 난이도 증가. 출처 : blockchain.info chart*

당연히 채굴하는 장비들이 좋아져서 빨리 정답을 찾을 수 있게 되니깐, 난이도는 img-2의 그래프처럼 계속 증가했습니다.

마무리


여기까지 오느라 고생하셨습니다. 최대한 쉽게 이해할 수 있도록 작성해보려고 노력했는데, 이해가 되셨는지 궁금하네요. 세부적으로 더 설명하고 싶은 점들이 많았는데, 다음 포스팅때 더 설명하도록 하겠습니다.

제가 공부한 내용을 바탕으로 작성하였습니다. 혹시 잘 못 설명된 내용이 있으면 댓글로 알려주세요.

질문 답변

1. 해더의 bits 값을 16진수 혹은 10진수로 변경하는 공식

bits 값 403867578을 가지고 설명을 하겠습니다. 먼저 403867578을 16진수로 바꾸면, 181287BA가 됩니다. 처음 두자리 18와 나머지 1287BA를 나누어서 아래의 식에 대입하면 됩니다. 16진수 18은 10진수로 24가 되고, 16진수 1287BA는 10진수로 1214394가 됩니다.

타켓 = 1214394 * 2 ^ (8 * (24 - 3 ))

그럼 이 식은 어떻게 나온 것인지 궁금하실 것 같은데, 1001를 어떻게 bits으로 표현하는 지 예를 들어보겠습니다. 일단 256으로 자르고, 16진수로 표현을 해볼께요. 그럼 1001은 256^1 * 3 + 256^0 * 233이고 16진수로 0x03 * 256^1 + 0xE9 * 256^0이 됩니다.

0x03 * 256^1 + 0xE9 * 256 는 256이 0승부터 1승까지 사용되었으니, bits의 첫 두자리는 02가 됩니다. 그리고 03E9값에 6자리로 채워야하니깐 03E900이 됩니다.

1001을 bits와 동일한 형식으로 표현하면 0203E900

그럼 좀전에 말한 공식에 똑같이 넣어 볼께요.

03E900 => 256256
02 = >2
256256 * 2 ^ (8 * (2 - 3)) = 1001

부동소수점을 어떻게 표현하는지랑 프로그래밍에서 비트 쉬프트를 어떻게 하는지 이해해보면 더 쉽게 이해 될 것 같아요.

일단 256을 베이스로 표현했습니다. 3 * 256^1 + 233 * 256^0. 근데 6자리 맞출려고 03E900이 되었고 이건 3256^2 + 233256^1 + 0*256^0 이 되었습니다. 우린 원래 2라는 걸 알고 있었으니깐, 하나가 더 간걸 알 수 있습니다. 그래서 2^(8 * (2-3)) 즉 256으로 나눠주면 다시 3 * 256^1 + 233 * 256^0 이 됩니다.

조금 복잡한데, 이해가 되셨나요?;;;

2. SHA256(SHA256(headermessage).digest()).digest() 왜 해시를 두번 하는것인지?

저도 이부분에 대해서 고민을 안해보고 bitcoin에서 그렇게 사용한다로만 알고 있었어요. 이렇게 두번 해시하는게 SHA256D라고 불리고, 보안 공격으로부터 좀 더 안전할려고 SHA256D가 사용된다고 합니다. SHA256D가 비트코인에서 블록을 해시하는데 어떻게 이점이 있는건지에 대해서는 좀 더 공부를 해야지 알 수 있을 것 같아요.

30

comments