IMG-LOGO
Home 암호화폐 강의 비트코인뽀개기 4편

비트코인뽀개기[4편]


비트코인의 블록구조는 크게 블록 해시, 블록 헤더, 블록 바디 정보로 나누어볼 수 있으며, 블록헤더는 버전(Version), 이전 블록 해시(Previous block hash), 머클 루트(Merkle Root), 타임(Time), 난이도 목표(bits), 논스(Nonce) 정보로 구성됩니다. 지난 비트코인뽀개기 3편에서는 버전, 이전 블록 해시, 머클 루트 정보에 대해 알아봤으면 이번 시간에는 지난 시간에 이어서 타임, 난이도 목표(bits), 논스(nonce) 정보에 대해 알아보도록 하겠습니다.

타임(Time)


타임 정보는 블록이 생성된 시점의 시간 정보를 나타내며, 유닉스 기준일자로 표시됩니다. (1970년 1월 1일 자정부터 경과한 시간을 초 단위로 계산한 값) 또한, 타임 정보는 새로운 블록의 유효성을 검증하는 과정에서 사용되며, 새로운 블록의 타임 정보는 이전 블록의 타임 정보보다 크면서 2시간 이내의 블록이어야 합니다.

난이도 목표(bits)


비트코인 네트워크에서 새로운 블록은 평균 10분에 한 번씩 생성될 수 있도록 설계되었으며, 난이도 목표(bits) 정보는 블록이 10분에 한 번씩 생성될 수 있도록 도와주는 역할을 수행합니다. 난이도목표(bits) 정보는 2주에 한 번씩 변경되며, 지난 2주 동안 비트코인 네트워크의 해시 파워에 의해 평균적으로 블록이 생성된 시간을 계산하여, 다음 2주 동안에도 블록이 10분에 한 번씩 생성될 수 있도록 난이도를 조절하게 됩니다.

논스(Nonce)


논스(Nonce) 정보는 채굴(마이닝)과 밀접한 관계가 있는 구성요소입니다. 논스(Nonce)는 값 그 자체로는 아무런 의미를 가지고 있지 않지만, 해시 함수의 특징을 활용하여 작업 증명(Proof-of-Work) 방식의 합의 알고리즘이 유지될 수 있도록 도와주는 아주 중요한 구성요소입니다.


* 난이도 목표(bits) 정보와, 논스(Nonce) 정보의 자세한 내용은 채굴(마이닝)편에서 조금더 심도있게 다루도록하겠습니다.

블록 해시(Hash of Block)


code>블록 해시 정보는 이전 블록 해시의 참조 값으로 사용되며, 블록의 식별자 역할을 수행합니다. 블록 해시 정보는 아래의 그림과 같이 블록 헤더(버전, 이전 블록 해시, 머클루트, 타임, bit, nonce)정보를 토대로 값을 구할 수 있습니다.


IMG

위의 그림과 같이 블록의 모든 구성 요소는 서로 연관 관계를 가지고 있으며, 일부의 값이 변경될 경우 해시 함수의 도미노 효과로 인하여 모든 정보가 변경되어, 어떠한 값을 쉽게 변경할 수 없는 구조를 가지고 있습니다. 더 자세한 내용은 비트코인 마이닝 시리즈가 끝난 시점에서 이야기하도록 하겠습니다. 비트코인 마이닝 과정을 이해하기 위해서는 블록 해시 연산과정에 대한 이해가 필요합니다.


* 블록해시 연산 과정을 이해하기 위해서는 지난 비트코인뽀개기 3편에서 언급한 엔디안의 개념정리가 필요합니다. (비트코인뽀개기 3편)

블록 해시 연산과정


* 블록 해싱 알고리즘은 아래의 그림과 같은 흐름으로 진행됩니다.


IMG

  • * 블록 헤더 정보중 숫자 정보인 version, time, bits, nonce 정보를 Little Endian 형태로 변형하고, Hex값 형태인 이전 블록 해시, 머클 루트 정보는 스왑한다.
  • * 블록 헤더 정보를 모두 이어 붙여 하나의 문자열로 만든다. 이때 순서는 반드시 버전, 이전 블록 해시, 머클 루트, time, bits, nonce 정보 순서대로 이어 붙여야한다.
  • * 이어 붙인 문자열을 바이너리 형태로 변형한다.
  • * 바이너리 형태로 변형한 결과 값을 SHA 256 해시 값으로 출력한 후 출력한 해시 값을 다시 바이너리로 변경한다.
  • * 바이너리 결과 값을 다시 SHA 256 해시 값으로 출력 한다.
  • * 해시 결과 값을 스왑한다.

  • 블록 해시 정보를 구하는 연산과정을 블록 해싱 알고리즘이라고 표현하며, 블록 해싱 알고리즘은 위의 연산과정으로 진행됩니다. 위의 연산 과정을 통해 블록 해시 정보가 정상적으로 구해지는지 검증하기 위하여, 예제 코드를 작성하고 그 결과를 확인해보도록 하겠습니다.

    먼저 연산 과정을 검증하기 위해 블록체인 인포사이트에서 제공하는 API를 활용하여 실제 비트코인 메인넷의 #508217번째 블록 정보를 확인해 보겠습니다.


    * 블록체인 인포 사이트에서는 블록의 상세정보를 Json 형태로 쉽게 가져갈 수 있도록 API를 제공하고 있으며, 아래의 URL 정보에서 bolck-height/ 뒤에 있는 숫자 정보를 변경하여 블록의 Height에 따라 상세 정보를 요청할 수 있게 됩니다. (궁금하신분들은 아래의 URL을 브라우저 주소 입력창에 입력해보세요!)

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    {
        "blocks": [
            {
                "hash": "000000000000000000081759445e2a44cb808c2b5e144c41d5d24d8fe7149269",
                "ver": 536870912,
                "prev_block": "00000000000000000060e66690d8a6646b7f8bb4aeb3fa7be258ae4011e362b5",
                "mrkl_root": "98f0bb94fc154733f22ac54994e9637981900fcee8a0db7d5880b5b79ca3853d",
                "time": 1518070436,
                "bits": 392292856,
                "fee": 100861384,
                "nonce": 2699712111,
                "n_tx": 1338,
                "size": 1040139,
                "block_index": 1671288,
                "main_chain": true,
                "height": 508217,
                "tx":[
                 ....
                 ]
            }
        ]
    }
    cs


    위의 Json 데이터중 블록헤더 정보만을 정리해보면 아래와 같습니다.


  • hash(블록 해시) : 000000000000000000081759445e2a44cb808c2b5e144c41d5d24d8fe7149269
  • prev_block(이전블록해시) : 00000000000000000060e66690d8a6646b7f8bb4aeb3fa7be258ae4011e362b5
  • mrkl_root(머클루트) : 98f0bb94fc154733f22ac54994e9637981900fcee8a0db7d5880b5b79ca3853d
  • time(타임) : 1518070436
  • bits(난이도 목표) : 392292856
  • nonce(논스) : 2699712111

  • * 블록 #508217 헤더 정보를 토대로 비트코인 위키 사이트에서 제공하는 블록 해싱 알고리즘 PHP 예제 소스를 응용하여 해당 블록 정보로 대입한 후 결과를 출력해보도록 하겠습니다.

    Block hashing algorithm


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    <?
        
        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
        } 
     
        //-- Block #508217 헤더 정보
        $ver            = 536870912;
        $prev_b            = '00000000000000000060e66690d8a6646b7f8bb4aeb3fa7be258ae4011e362b5';
        $mrkl_r            = '98f0bb94fc154733f22ac54994e9637981900fcee8a0db7d5880b5b79ca3853d';
        $time            = 1518070436;
        $bits            = 392292856;
        $nonce            = 2699712111;
        
        //1-1. version, time, bits, nonce 정보를 리틀 엔디안 형태로 변형.
        $ver            = littleEndian($ver);
        $time            = littleEndian($time);
        $bits            = littleEndian($bits); 
        $nonce            = littleEndian($nonce); 
        
        //1-2. 이전 블록 해시, 머클루트 결과 값을 모두 반대 순서로 변형
        $prev_b            = SwapOrder($prev_b);
        $mrkl_r            = SwapOrder($mrkl_r);
        
        //2. 블록 헤더 정보를 모두 합산(순서가 꼭 맞아야합니다.)
        $header            = $ver . $prev_b . $mrkl_r . $time . $bits . $nonce;
        
        //3. 바이너리 형태로 변형
        $header_bin        = hextobin($header);
        
        //4. SHA256 해시 값 출력 후 바이너리 데이터로 변형
        $hasing_1        = hextobin(hash('sha256'$header_bin ));
     
        //5. SHA256 해시 값 출력 
        $hasing_2        = hash('sha256'$hasing_1);
     
        //6. 결과 값을 스왑(리버스)
        $block_hash        = SwapOrder($hasing_2);
        
        //-- 화면에 결과 값 출력
        echo $block_hash;
        
    ?>
    cs

    결과 화면



    IMG

    블록 #508217의 블록 해시 정보와, 예제 코드의 결과가 동일한것을 확인할 수 있었습니다.

    비트코인 위키 영문판에서는 비트코인에 관한 많은 내용을 다루고 있으며, 블록 해싱 알고리즘에 대한 내용도 자세히 서술되어 있습니다. 혹시 보다 더 자세한 사항을 알고 싶으신 분들을 위해 아래의 링크를 남겨두도록 하겠습니다.

    비트코인 위키 - 블록 해싱 알고리즘


    블록 해싱 알고리즘 연산 과정에 대한 모든 요소를 다 이해하지 않더라도, 연산 과정의 흐름을 이해하고 있어야만 비트코인 마이닝 편을 쉽게 이해할 수 있으며, 비트코인 마이닝 과정을 이해할 경우 왜 비트코인의 합의 알고리즘이 작업 증명 방식인지에 대한 명확한 이해를 할 수 있습니다.

    블록 해싱 알고리즘 연산 과정에 대한 모든 요소를 다 이해하지 않더라도, 연산 과정의 흐름을 이해하고 있어야만 비트코인 마이닝 편을 쉽게 이해할 수 있으며, 비트코인 마이닝 과정을 이해할 경우 왜 비트코인의 합의 알고리즘이 작업 증명 방식인지에 대한 명확한 이해를 할 수 있습니다.


    IMG
    출처 : Keep!T / 작성자 : yahweh87