#5 - 블록해시에 관한 정의

in kr •  7 years ago 


main.png


안녕하세요. 어미새입니다.


이전 포스팅에서는 머클루트는 무엇이고 어떻게 머클루트 값을 구하는지, 그리고 실제 그렇게 값이 구해지는지 검증까지 해봤습니다. 혹시 이전 글을 읽지 않으신 분은 한 번 읽어보고 오셨으면 좋겠습니다.

(https://steemit.com/kr/@yahweh87/4-merkle-tree-merkle-root)

이번 포스팅에서는 지난 포스팅에 이어서 비트코인 블록 정보가 어떻게 구성되어 있는지 알아보겠습니다, 오늘은 비트코인의 블록 정보 중 블록의 이름 역할, 즉 블록의 식별자 역할을 하는 블록 해시 정보에 대해 알아보겠습니다.


블록 해시(Hash of the block)


블록 해시(Block Hash)는 블록의 식별자 역할을 수행합니다. 쉽게 블록의 이름 정보라고 생각하시면 될 것 같습니다. 블록 해시는 블록 헤더 정보인 버전, 이전 블록 해시, 머클루트, 타임, bits, Nonce 정보를 모두 더하여 합을 구한 후 SHA 256방식으로 변환된 결과 값입니다.

3편에서 이야기한 블록의 구성요소를 기억하시나요? 다시 블록의 구조를 그림으로 살펴보겠습니다.




5_0.png


블록 해시는 블록의 헤더 정보 6가지를 이용하여 정보가 구성됩니다. 아마 제 포스팅을 처음부터 읽으셨다면 이제 블록구조가 어느 정도 익숙해졌을 거라고 믿습니다.

자 그럼 본론으로 들어가 블록 헤더 정보를 이용하여 블록 해시 정보 값을 구해보겠습니다.

우선 블록의 정보를 확인해보기 위해 이전 포스팅에서 소개해드린 '블록체인 인포' 사이트에 접속하여 가장 최근에 생성된 블록 정보를 확인해보겠습니다.

(https://blockchain.info/ko)

이 글을 작성하기 시작한 시점에서 가장 최근에 생성된 블록의 높이는 #508217번째 블록입니다. 해당 블록을 선택하여 블록의 상세 정보를 확인해보겠습니다.



5_1.png

위의 정보를 살펴보면 타임 스탬프, Bits, 해시 난수, 이전 차단, Merkle Root 정보를 확인할 수 있습니다. 앞서 설명한 블록 해시를 구하는 공식에는 6가지 요소가 필요하나 여기에는 버전 정보가 누락되어 있습니다. 그리고 타임 스탬프 정보 또한 우리가 보기 편한 형식으로 변형되어 있습니다. 실습을 위해 Json 형태로 디테일한 블록의 데이터를 획득해보겠습니다. 블록체인 인포에서는 해당 블록의 정보를 Json 형태로 제공해주고 있습니다.

아래의 URL처럼 정보를 구성하여 요청하면 우리가 원하는 #508217번째 블록 정보를 Json 형태로 제공받을 수 있습니다.

(https://blockchain.info/block-height/508217?format=json)

참고로 위의 URL의 /508217? 이 부분에 숫자 부분이 블록 높이 정보입니다. 다른 블록 정보의 Json을 요청하고 싶다면 이 숫자 정보를 해당 블록의 높이 정보로 변경하여 호출하시면 되겠습니다.



5_2.png

Json 데이터로 확인해보니 보다 상세하게 블록 정보를 확인할 수 있었습니다.(개발자라서 그런지 Json 데이터가 더 보기 편하네요..) Json 데이터를 보시면 버전(ver), 이전 블록 해시(prev_block), 머클루트(mrkl_root), 타임(time), bits, 논스(nonce) 정보가 정확하게 출력되어 있습니다.

"ver":536870912
"prev_block":"00000000000000000060e66690d8a6646b7f8bb4aeb3fa7be258ae4011e362b5"
"mrkl_root":"98f0bb94fc154733f22ac54994e9637981900fcee8a0db7d5880b5b79ca3853d"
"time":1518070436
"bits":392292856
"nonce":2699712111

위의 정보를 이용하여 아래의 블록해시 값을 구할 수 있다는거죠~

"hash":"000000000000000000081759445e2a44cb808c2b5e144c41d5d24d8fe7149269"

그럼 바로 PHP를 활용하여 소스를 작성해보고 실행해보겠습니다.



5_3.png


5_4.png

저번 시간에도 이런 오류가 발생하였습니다.. 당황하지 않고 저번 시간에 해결했던 방법 처럼 엔디안 형태로 변행해 보았습니다......................하지만 결과는 실패였습니다. 왜일까요?

오랜 시간 끝에 찾아낸 코드는 아래와 같습니다.

<?

function SwapOrder($in){
  $Split = str_split(strrev($in));
  $x='';
  for ($i = 0; $i < count($Split); $i+=2) {
      $x .= $Split[$i+1].$Split[$i];
  } 
  return $x;
}

function littleEndian($value){
  return implode (unpack('H*',pack("V*",$value)));
}

function hextobin($hexstr) 
{ 
    $n = strlen($hexstr); 
    $sbin="";   
    $i=0; 
    while($i<$n) 
    {       
        $a =substr($hexstr,$i,2);           
        $c = pack("H*",$a); 
        if ($i==0){$sbin=$c;} 
        else {$sbin.=$c;} 
        $i+=2; 
    } 
    return $sbin; 
} 

$ver            = 536870912;
$prev_b         = '00000000000000000060e66690d8a6646b7f8bb4aeb3fa7be258ae4011e362b5';
$mrkl_r         = '98f0bb94fc154733f22ac54994e9637981900fcee8a0db7d5880b5b79ca3853d';
$time           = 1518070436;
$bits           = 392292856;
$nonce          = 2699712111;

//1. 버전, 타임, bits, nonce 정보를 리틀 엔디안 형태로 변형.
$ver            = littleEndian($ver);
$time           = littleEndian($time);
$bits           = littleEndian($bits); 
$nonce          = littleEndian($nonce); 

//2. 이전 블록 해시, 머클루트 결과 값을 모두 반대 순서로 변형
$prev_b         = SwapOrder($prev_b);
$mrkl_r         = SwapOrder($mrkl_r);

//3. 블록 헤더 정보를 모두 합산(순서가 꼭 맞아야합니다.)
$header         = $ver . $prev_b . $mrkl_r . $time . $bits . $nonce;

//4. 바이너리 형태로 변형
$header_bin     = hextobin($header);

//5. SHA 형태로 변형 후 바이너리 형태로 변형
$hasing_1       = hextobin(hash('sha256', $header_bin ));

//6. SHA 형태로 변형 
$hasing_2       = hash('sha256', $hasing_1);

//7. 결과를 모두 반대 순서로 변형.
$block_hash     = SwapOrder($hasing_2);

echo $block_hash;

?>

위의 코드 처럼 블록해시 정보는 블록헤더의 정보를 단순히 합산하여 해싱하는 것이 아닙니다. 버전, 타임, bits, 논스정보는 리틀 엔디안 형태로 변형 해야 하며, 이미 해싱된 머클루트와 이전 블록 해시 정보는 반대로 뒤집어 주어야합니다.

다시 정리해보면 아래의 7가지 변환 과정을 거쳐서 블록 해시 정보를 구할 수 있습니다!

  1. 버전, 타임, bits, 논스 정보는 리틀 엔디안 형태로 데이터를 변형해야 한다.
  2. 이전 블록 해시, 머클루트는 결과 값을 모두 반대 순서로 바꿔주어야 한다.
  3. 헤더 정보들을 모두 합산합니다.(이어붙이기)
  4. 합산한 헤더 정보를 바이너리 형태로 변형합니다.
  5. 다시 SHA 형태로 변형 후 바이너리 형태로 또 변형합니다.
  6. 변형한 값을 다시 SHA 형태로 변형합니다. (5~6번 과정은 합산한 정보를 2중 해싱한다고 생각하시면 됩니다.)
  7. 이렇게 얻은 결과 값을 다시 뒤집어 놓습니다.

추가적으로 저는 숫자를 문자열로 입력하는 멍청한 실수를 해서 2시간을 허비했습니다.. 개발자로써 자괴감이..

자 그럼 결과가 정상적으로 출력되는지 확인해보겠습니다.



5_8.png

드디어 블록해시 정보를 구할 수 있었습니다. 아래의 링크는 비트코인 블록 해싱 알고리즘에 대한 자세한 설명을 해주고 있는 사이트입니다. 꼭 접속하셔서 해당 내용 확인해보셨으면 좋겠습니다!

(https://en.bitcoin.it/wiki/Block_hashing_algorithm)

자 그럼 오늘 배운내용을 간략하게 정리를 해보겠습니다.

  1. 블록해시는 블록의 이름정보를 의미하면 해당 블록의 식별자 역할을 수행한다.

  2. 블록해시는 블록 헤더 정보를 7단계의 복잡한 과정을 통하여 구할 수 있다. (아마 인터넷상에서는 자세하게 설명할 경우 오히려 이해하기 어려울 것 같아 7가지 과정을 누락하신 것 같습니다..)

추가로 혹시 위의 7가지 과정이 왜 필요한지에 대해서 자세히 아시는 고수님이 있으시다면 알려주시면 정말 감사하겠습니다.
(조만간에 엔디안의 개념과 바이너리 형태로 변형하는 이유 그리고 문자열을 뒤집는 이유도 반드시 알아내고말겠습니다..)

이상으로 블록 헤더의 구성요소인 머클루트를 구하는 과정, 그리고 블록의 이름정보인 블록해시를 구하는 과정까지 학습하였습니다. 아마도 이 글을 읽으시는 분들 중에서는 왜 이렇게 까지 과정에 대해서 집착하지? 라는 생각을 하실 수 있을 것 같습니다. 하지만 이 과정이 반드시 학습하는데에 큰 도움이 될것이라고 믿습니다!

다음 포스팅은 채굴이란 무엇이고, 어떻게 채굴을 하는지에 대한 포스팅을 진행하고자 합니다.

이상 긴 글 읽어주셔서 감사합니다!


[참고자료]
https://en.bitcoin.it/wiki/Block_hashing_algorithm
https://steemit.com/kr/@loum/how-to-calculate-the-block-hash-in-bitcoin
https://homoefficio.github.io/2016/01/23/BlockChain-%EA%B8%B0%EC%B4%88-%EA%B0%9C%EB%85%90/
http://hanaloum.blogspot.kr/2014/06/block-1_9584.html

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

"블록 해시는 블록 헤더 정보인 버전, 이전 블록 해시, 머클루트, 타임, bits, Nonce 정보를 모두 더하여 합을 구한 후 SHA 256방식으로 변환된 결과 값입니다." 이라고 하셨는데, 정보를 모두 더한다는 표현보다는 각 정보를 "덧붙이다", "연결하다", "이어붙이다"등 표현이 더 적합할것 같네요. 더한다고 하면 1+2=3 이런식으로 생각하게 되네요.

넵 이어 붙인다는 표현이 더 좋은 표현인것 같습니다 ^^

좋은글 감사합니다! 디자이너인데 공부하기 좋은거 같아요 ^^

공부에 도움이 되셨다니 뿌듯하네요~ 즐거운 하루 보내세요 ~ ^^

정성글이네요 정말!!.
저도 지난번에 손으로 해봤다가(코딩은잘못해서) 안되서 궁금했는데 엔디안 저 친구 때문이군요. 저도 궁금하네요 왜 엔디안을 쓰는지ㅎㅎ

넵 저도 엔디안에대해서 찾아보고 있습니다 흐흐.. 조만간 엔디안에 관련 포스팅을 할것같습니다! 추가로 이 사이트 들어가셔서 정보 보시면 좋을것 같아요~ (https://en.bitcoin.it/wiki/Block_hashing_algorithm)

  ·  7 years ago (edited)

http://genesis8.tistory.com/37
http://firejune.com/1790

이런 블로그 자료들 있는데.. 저에게는 외계용어 같네요ㅎㅎ 분명 한글인데ㅜㅜ

하하.. 저도 외계어 같아요.. 언제간.. 반드시 이해할 수 있다고 믿어봅니다 ^^;

첫편부터 정주행했습니다. 모든 글 리스팀해놓고, 반복해서 읽으며 공부하겠습니다.

감사합니다~ 학습하시는데 많은 도움이 되었으면 좋겠네요 ^^;

좋은 글 감사합니다. 팔로하고 가요. 행복한
휴일 보내세요!

저도 맞팔하겠습니다~ 행복한 주말 보내세요~

실습까지 해가며, 이런 글을 올려주시니 읽고 감명 받았습니다ㅎ

하하 저도 공부하면서 이해한 내용을 공유해드리고 있습니다~ ^^;

오래된 포스팅이라서 이미 알아냈을수도 있지만 궁금해하시는것같아 답변을 남겨봅니다. 이전해시와 머클루트를 swaporder하는것과 나머지 4개의 필드를 리틀엔디안으로 저장하는것은 동일한 작업이며 모두 데이터를 리틀엔디안으로 통일 시키는 작업입니다. 16진수로 표시한 해시는 0000으로 시작을 하는데 이는 빅엔디안형식이며, 리틀엔디안일 경우 0000이 뒤로 붙습니다.
즉, 이전해시와 머클루트는 모두 빅엔디안 형식으로 표기되어있으며 사람이 읽기좋게 표한하기 위함입니다. 계산을 위해 이를 LE으로 바꾸어 나머지 필드들과 합치는 것입니다.
저도 개발자지만 실제로 해시값을 도출하는 테스트를 해보지는 않았는데, 어미새님의 노력에 감명받았습니다. 좋은 포스팅 감사합니다!