비트코인 난이도 구하는 공식 및 삽질...

in #kr7 years ago (edited)


main.jpg


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


이번 포스팅은 비트코인 난이도 값을 구하는 공식에 대해서 알아보겠습니다. 준비는 많이했으나 진척이 없어 그동안 미뤄두었던 포스팅 내용입니다. 많이 부족할 수 있지만 혹시나 저와 같이 공부하시는분에게 조금이라도 도움이 될 수 있었으면 하는 바램입니다. 추가적으로 혹시 저의 부족함을 채워주실 블록체인 기술자님! 댓글로 알려주시면 너무너무 감사하겠습니다!


'#5 - 블록해시에관한정의'편을 통해 블록해시 값을 어떻게 구하는지 그리고 실제 그렇게 값이 구해지는지 예제소스를 통해서 직접 확인까지 해봤습니다.


그리고 채굴과 관련된 포스팅을 통해 수학문제는 어떻게 풀어내는지에 대해서 알아봤습니다.


채굴(마이닝)이란 임이의 nonce 값을 대입하여 target 값보다 작은 블록해시 결과 값을 찾아야합니다. 그렇다면 target의 정보는 어떻게 구할까요?



난이도(Difficulty)구하는 공식



비트코인 난이도는 2주(2016 블록)마다 변경됩니다. 난이도를 구하기 위해서는 블록헤더의 구성요소인 'bits'정보를 이용하여 구할 수 있습니다.

난이도 공식

비트코인 위키에 정의된 난이도를 구하는 공식과 설명은 아래와 같습니다.


What is the formula for difficulty?

difficulty = difficulty_1_target / current_target

(target is a 256 bit number)

difficulty_1_target can be different for various ways to measure difficulty. Traditionally, it represents a hash where the leading 32 bits are zero and the rest are one (this is known as "pool difficulty" or "pdiff"). The Bitcoin protocol represents targets as a custom floating point type with limited precision; as a result, Bitcoin clients often approximate difficulty based on this (this is known as "bdiff").

How is difficulty stored in blocks?

Each block stores a packed representation (called "Bits") for its actual hexadecimal target. The target can be derived from it via a predefined formula. For example, if the packed target in the block is 0x1b0404cb, the hexadecimal target is

0x0404cb * 2**(8*(0x1b - 3)) = 0x00000000000404CB000000000000000000000000000000000000000000000000

Note that the 0x0404cb value is a signed value in this format. The largest legal value for this field is 0x7fffff. To make a larger value you must shift it down one full byte. Also 0x008000 is the smallest positive valid value.

How is difficulty calculated? What is the difference between bdiff and pdiff?

The highest possible target (difficulty 1) is defined as 0x1d00ffff, which gives us a hex target of

0x00ffff * 2**(8*(0x1d - 3)) = 0x00000000FFFF0000000000000000000000000000000000000000000000000000

It should be noted that pooled mining often uses non-truncated targets, which puts "pool difficulty 1" at

0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

So the difficulty at 0x1b0404cb is therefore:

0x00000000FFFF0000000000000000000000000000000000000000000000000000 /
0x00000000000404CB000000000000000000000000000000000000000000000000 
= 16307.420938523983 (bdiff)

And:

0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF /
0x00000000000404CB000000000000000000000000000000000000000000000000 
= 16307.669773817162 (pdiff)

[출처 - 비트코인 위키(https://en.bitcoin.it/wiki/Difficulty)]


위의 내용을 이해하고자 아주 많은 삽질을 했던 것 같습니다. 우선 비트코인 난이도를 구하는 공식을 살펴보겠습니다.


difficulty = difficulty_1_target / current_target

(target is a 256 bit number)


위의 공식을 조금 쉽게 풀어보면 아래와 같습니다.

난이도 = 최고 난이도 / 현재 난이도


여기서 최고 난이도(maximum_target)은 항상 고정된 상수 값으로 '0x00000000FFFF0000000000000000000000000000000000000000000000000000'미리 정해져있습니다.


최고 난이도가 변하지 않는 상수로 정해져있기 때문에 현재 난이도(current_target) 정보값을 구하여 나누어주면 비트코인 난이도 값을 구할 수 있겠습니다.


현재 난이도를 구하기 위해서는 블록헤더 정보인 'bits'값을 통해 구할 수 있으며 bits 정보를 아래와 같이 연산하여 현재 난이도 값을 구할 수 있습니다.


  1. bits를 16진수로 변환합니다.
  2. 16진수로 변환된 결과 값에서 뒤에서 6자리 숫자와 2자리 숫자를 분리합니다.
  3. 0x(뒤 6자리) * 2 *(8(0x(뒤 2자리)-3)) <- 다음과 같은 대입하여 연산하면 현재 난이도를 구할 수 있습니다.


실제 난이도를 구하는 공식은 비트코인 위키에서 제공하고 있습니다.


#include <iostream>
#include <cmath>
 
inline float fast_log(float val)
{
   int * const exp_ptr = reinterpret_cast <int *>(&val);
   int x = *exp_ptr;
   const int log_2 = ((x >> 23) & 255) - 128;
   x &= ~(255 << 23);
   x += 127 << 23;
   *exp_ptr = x;
 
   val = ((-1.0f/3) * val + 2) * val - 2.0f/3;
   return ((val + log_2) * 0.69314718f);
} 
 
float difficulty(unsigned int bits)
{
    static double max_body = fast_log(0x00ffff), scaland = fast_log(256);
    return exp(max_body - fast_log(bits & 0x00ffffff) + scaland * (0x1d - ((bits & 0xff000000) >> 24)));
}
 
int main()
{
    std::cout << difficulty(0x1b0404cb) << std::endl;
    return 0;
}

[출처 - 비트코인 위키(https://en.bitcoin.it/wiki/Difficulty)]


흠.. C언어를 공부해본적이 없는 저로써는 C언어 보다 익숙한 PHP로 포팅하고 싶었습니다. 왜냐구요? 제가 해보고 싶은 무언가가 있어서 그랬습니다.. 하지만 이 코드를 이해하기 위해서는 쉬프트 연산에 대한 이해도와 수학적 지식이 필요하더군요.. 그래서 PHP로 완벽히 포팅하는데 실패하였습니다 ㅠㅠ (하지만.. 포기하지 않고 언젠간 꼭 해낼겁니다 흐흐흐..)



하고 싶었던 예제코드



블록해시 값을 어떻게 구하는지 완벽히 이해했고, 추가적으로 채굴에 대한 이론도 완벽히 이해했었습니다. 그래서 채굴 프로그램의 일부 구성이 어떻게 이루어졌는지에 대해서 검증을 하기 위한 예제코드를 만들고 싶었습니다.


채굴프로그램은 결국 nonce값을 0부터 1씩 증가하면서 얻은 '블록해시'값이 'target'보다 작으면 성공입니다. 제가 작성하던 예제코드의 핵심 코드만 추출하면 아래와 같습니다.



14_0.png


위의 코드를 조금 설명해보자면 새로운 블록을 생성하기 위해 제공받을 수 있는 5가지 구성요소를 블록해시 값을 구하기 위하여 변형시켰습니다.(이와 관련된 내용은5편의 내용에 상세하게 있습니다.) 그리고 nonce를 최초에 0으로 대입시키고 '블록해시' 정보를 추출한 후 'target'값과 비교하여 값이 작을 경우 while문을 빠져나오게 하였습니다. 만약 '블록해'값이 작지 않다면 nonce의 값을 1만큼 증가시킨 후 다시 이와 같은 작업을 계속해서 반복하도록 작성하였습니다.


위의 코드가 정상적으로 동작하기 위해서는 우선 target의 값을 구해야 합니다. 하지만 target의 값을 구하는 소스를 완벽히 구현하지 못했습니다. 그래서 생각한 방식이 난이도는 2주마다 변경되기 때문에 현재 난이도 정보를 알려주는 사이트가 있지 않을까? 그리고 이러한 정보를 제공해주는 사이트를 찾게되었습니다.

(https://data.bitcoinity.org/bitcoin/difficulty/5y?t=l)



14_1.png

현재 적용된 난이도 정보와, 다음에 적용될 예상 난이도 정보,그리고 남은 시간 정보등을 확인할 수 있었습니다.


하지만 여기서 또 문제점이 발생합니다. 제가 추출한 블록해시 값은 0000000000000000004e5c0a5a398b92a032663b1287e92efce4cbd4c94fd02a와 같은 해시 문자열입니다. 그리고 제공 받은 난이도의 정보는 3,007,383,866,430와 같은 숫자입니다. 어떻게 이 2가지의 값을 비교하여 값이 작은지 판단할 수 있을까요? 이런 문제점들 때문에 제가 생각했던 채굴 프로그램의 일부 구현은 잠시 중단할 수 밖에 없었습니다.(하지만 추후에 꼭 완성시키겠습니다.)


내용이 어수선 하지만 제가 정말 하고 싶었던 과정은 아래와 같습니다.


  1. target값을 구하는 예제소스를 작성한다.
  2. nonce값을 1씩 증가시켜 target값과 비교하여 진짜 블록을 찾아내는 예제소스를 작성한다.


위의 과정이 학습에 왜 필요했냐구요? 정말 제가 가진 고물 컴퓨터로 채굴에 걸리는 시간이 얼마나 걸리는지 알고 싶었습니다. 그래야지만 마이닝풀에 필요성을 더 느낄 수 있다고 생각했습니다. 그리고 추가적으로 혼자서 '채굴' 할 수 있는 방식에 대한 로직을 만들고 싶었습니다.


예를 들어서 nonce의 값을 단순히 0씩 증가 시키지 않고 임이의 높은 값을 정하여, 예를들어 100,000,000의 숫자 값에서 -1씩 감소하면서 대입해보는겁니다. 또는 일부 숫자를 제외하는 패턴을 적용해서 문제를 풀어보는겁니다. 이렇게 할 경우 매번 블록을 찾지 못하더라도 한달에 한번만 채굴에 성공할 수 있다면.. 보상이 1억7천만원 수준입니다.. 이런 응용 프로그램을 만들고 싶어서 위의 삽질을 했던겁니다!!


비록 내용이 부족하고.. 완벽하지 못한 포스팅이었지만 저와 같이 공부하고 있는 누군가에게 도움이 될 수도 있을 것 같다는 생각이들어서 이번 포스팅을 작성하게 되었습니다...


다음포스팅에서는 지난 포스팅 노드에 대한 개념정리에 이어서 비트코인 지갑에 대한 개념정리를 하도록 하겠습니다.

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



[참고자료]

https://steemit.com/kr/@loum/21zhq3-how-to-calculate-the-difficulty-of-bitcoin

https://data.bitcoinity.org/bitcoin/difficulty/5y?r=day&t=l

https://en.bitcoin.it/wiki/Difficulty

https://jayground8.github.io/what_is_hash_and_mining/

http://coinnews.tistory.com/14

Sort:  

아..ㅠ무슨 이야기인지 저는 지식이 없어서.ㅠ
그냥 스팀잇이나 열심히 해야겟어요.ㅎ

하하 저도 너무 어렵네요ㅜㅜ 눙물이난당

꼭 성공하셔서 포스팅 해주세요^^

넵 언젠간 해드릴게요!! ^^;

짱짱맨은 스티밋이 좋아요^^ 즐거운 스티밋 행복한하루 보내세요!

그러니까 난이도는 현재 난이도가 높을수록 낮아진다는 건가요?

비트코인에서는 블록이 평균적으로 10분마다 생성되도록 설정되어있습니다.
블록이 10분마다 잘 생성될 수 있도록 '난이도'를 조정하게 됩니다.
난이도가 높을 수록 문제가 어려우니 블록 생성이 늦어지게 되고..
난이도가 낮을 수록 문제가 쉬우니 블록 생성이 빨라지게됩니다..
비트코인은 평균적으로 블록을 생성하는데 얼마나 걸리는지를 학습하고
문제의 난이도를 변경하고 있습니다! 아래의 관련 글을 읽으시면 더 도움이 될 것 같습니다!
(https://steemit.com/kr/@yahweh87/10-difficulty-51)

도움이 되셨길.. 오늘도 즐거운 스팀잇 되세요:)

왜 이 글 보상이 1 밖에 되지않는지 의문이고.. 포스팅과 공부하면서 들인 어미새 님의 노력에 감탄이 절로 나오네요..! 잘 읽고있습니다 :)

글잘읽었습니다. ^_^
제가들은바로는 2주마다 난이도가 변경되는것 외에 개별노드가 10분보다 빠르게 블록을생성하면 그 개별노드만 자체적으로 난이도 변화가 일어난다고 들었었는데 혹시 이부분아시나요? 저도 듣기만하고 어떻게 이뤄지는지를 몰라서 여쭈어봅니다.