본문 바로가기

[중급] 가볍게 이것저것

비트코인 알고리즘 직접 구현해보기

1. 비트코인의 채굴 난이도 구하기

 

비트코인은 채굴이라는 과정으로 얻을 수 있습니다.

그런데 이 과정은 난이도라는 변수가 존재하는데요

 

bits 라는 입력값 하나를 이용해 난이도를 구하는 함수 diff()를 구현해 주세요.

 

아래 링크를 참조하세요.

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

https://learnmeabitcoin.com/beginners/difficulty

https://www.quora.com/What-is-the-Bitcoin-mining-difficulty-target-formula

 

 

'''

Block #530396

bits = 389315112

difficulty = 5363678461481.357

from reference : 5,363,678,461,481.36

https://www.blockchain.com/btc/block/0000000000000000002a16b0b266d1d568516acb337acdfd6dec1dddce9e07b5

 

Block #521878

bits = 390462291

difficulty = 4022059196164.954

from reference : 4,022,059,196,164.95

https://www.blockchain.com/en/btc/block/0000000000000000003ab5fdfdce6f17a19a2cefcf3fd21b029a089350d402bc

'''

 

bits = 389315112

 

max_target = '0x00000000FFFF0000000000000000000000000000000000000000000000000000'

# MAX_bits = 0x1d00ffff

 

def dif_cal(a):

    tail = str(hex(a))[0:4]

    head = "0x" + str(hex(a))[4:]

    head_hex = hex(int(head, 16)) 

    zeroer = int(str(hex(a))[0:4], 16)

    realzero = int((2 * (zeroer - 3)))

    zerostring = ""

    for i in range(realzero):

        zerostring = zerostring + "0"

    diff_c_s = head + zerostring

    diff_c_h = hex(int(diff_c_s,16))

    diff_c_i = int(diff_c_s,16)

    diff_m_h = hex(int(max_target, 16))

    diff_m_i = int(max_target, 16)

    diff_target = diff_m_i / diff_c_i

    print(diff_target)

 

dif_cal(bits)

 

 

 

2. 비트코인 블럭에 대한 정보인 해시값 구해보기

 

아래 링크를 참조하세요

https://blockgeeks.com/guides/what-is-hashing/

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

 

 

 

'''
https://www.blockchain.com/ko/btc/block/0000000000000000001add5c0da07ac67536318a8e14b23c7e5fe37320a5f73d
Block #530384
bits = 389315112
difficulty = 5,363,678,461,481.36
merckle = 3177fbb8e5a279480c2eaf1da267ec17605366aeb028ace412fc53fc87456b60
nonce = 778197127
이전 블럭의 해시값 : "000000000000000000332f4032babc1a239afd57195320a3d4ee05c794506f91"
현재 블럭의 해시값 : "0000000000000000001add5c0da07ac67536318a8e14b23c7e5fe37320a5f73d

이전 블럭의 해시값과 현재 블럭이 생성된 시간, bits 수(난이도), nonce 값을 이용하여
현재 블럭이 생성될 때 현재 블럭의 해시값을 구하는 문제

다음 블럭이 생성될 때 자동으로 해시값을 생성하기 위한 로직
version, 이전 블럭의 해시값, 블럭 생성시 생성되는 머클값, 블럭 생성시의 시간, 난이도와 넌스값이 input

				
import hashlib
import binascii
import time


# 1. Getting header values from blockexplorer.com
version = "20000000" # 2
hashPrevBlock = "000000000000000000332f4032babc1a239afd57195320a3d4ee05c794506f91"
hashMerkleRoot = "3177fbb8e5a279480c2eaf1da267ec17605366aeb028ace412fc53fc87456b60"

time = hex(int(time.mktime(time.strptime('2018-07-04 02:19:41', '%Y-%m-%d %H:%M:%S'))) - time.timezone)
bits = 389315112
nonce = 778197127 # in decimal notation
nonce = hex(int(0x100000000)+nonce)[-8:] 


bits = hex(bits)
time = time[2:] # 파이썬 계산식에서 16진수의 0x가 없어야 동작해서 문자열 슬라이싱으로 제거합니다.
bits = bits[2:]
print("hex-time = " + time)
print("hex-bits = " + bits)


def un_hex(input):
    output = binascii.unhexlify(input)
    return output
    
def re_hex(input):
    output = binascii.hexlify(input)
    return output

def SHA256_x2(input):
    output = hashlib.sha256(hashlib.sha256(input).digest()).digest()
    return output



# 2. 리틀-엔디안 헥사코드로 변환합니다.

# 2-1 Un-hex
version = un_hex(version)
hashPrevBlock = un_hex(hashPrevBlock)
hashMerkleRoot = un_hex(hashMerkleRoot)
time = un_hex(time)
bits = un_hex(bits)
nonce = un_hex(nonce)

# 2-2 Reverse(Little Endian)
version = version[::-1]
hashPrevBlock = hashPrevBlock[::-1]
hashMerkleRoot = hashMerkleRoot[::-1]
time = time[::-1]
bits = bits[::-1]
nonce = nonce[::-1]

# 2-1 Hexlify
version = re_hex(version)
hashPrevBlock = re_hex(hashPrevBlock)
hashMerkleRoot = re_hex(hashMerkleRoot)
time = re_hex(time)
bits = re_hex(bits)
nonce = re_hex(nonce)



# 3. 헤더값을 이어붙입니다.(Concatenate)
header = version+hashPrevBlock+hashMerkleRoot+time+bits+nonce

# 4. SHA256 두 번 취해주고
# unhexlify -> sha256 digest x2 -> hexlify
header = un_hex(header)
hash = SHA256_x2(header)
hash = re_hex(hash)

# 5. 이제 다시 빅-엔디안으로 변환합니다.
hash = un_hex(hash)
hash = hash[::-1]
hash = re_hex(hash)

print(hash)