저는 제 노트북에 Bitcoin Core를 설치하고 동기화하여 실행했습니다. 또한, RPC를 통해 Bitcoin Core와 연결하여 솔로 마이닝을 수행하는 Python 프로그램을 개발하였습니다.
이 프로그램에서는 다양한 nonce 값을 생성하여 마이닝 과정에 적용하는 알고리즘을 구현하였습니다. 비록 블록 채굴에 성공할 확률이 매우 낮다는 것을 알고 있지만, 제가 만든 이 솔로 마이닝 Python 프로그램이 실제 비트코인 네트워크에서 기술적으로 올바르게 동작하며 오류 없이 운영되는지를 확인받고 싶습니다.
제 프로그램을 검토해 주시고, 문제점이나 개선 사항이 있다면 알려주신다면 저에게 큰 도움이 될 것입니다. 이와 같은 요청에 시간을 내어 주시고 도움을 주셔서 진심으로 감사드립니다.
import hashlib
import requests
import json
import struct
import time
import random
# RPC 설정
RPC_USER = "user"
RPC_PASSWORD = "passwd"
RPC_URL = "
http://127.0.0.1:8332/"
# 사용자 정의 주소
MINING_ADDRESS = "your_bitcoin_address"
def is_valid_bitcoin_address(address):
"""비트코인 주소의 유효성을 검증"""
try:
alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
base58_decoded = 0
for char in address:
base58_decoded = base58_decoded * 58 + alphabet.index(char)
address_bytes = base58_decoded.to_bytes(25, byteorder="big")
checksum = address_bytes[-4:]
hash_checksum = hashlib.sha256(hashlib.sha256(address_bytes[:-4]).digest()).digest()[:4]
return checksum == hash_checksum
except Exception as e:
print(f"주소 검증 실패: {e}")
return False
# MINING_ADDRESS 검증
if not is_valid_bitcoin_address(MINING_ADDRESS):
raise ValueError(f"유효하지 않은 비트코인 주소입니다: {MINING_ADDRESS}")
def rpc_request(method, params=None):
"""RPC 요청"""
payload = json.dumps({"jsonrpc": "2.0", "id": "mining", "method": method, "params": params or []})
response = requests.post(RPC_URL, auth=(RPC_USER, RPC_PASSWORD), data=payload)
try:
response.raise_for_status()
result = response.json()
if "result" not in result:
raise ValueError("RPC 응답에 'result' 필드가 없습니다.")
return result["result"]
except Exception as e:
print(f"RPC 요청 실패: {e}")
print(f"응답 내용: {response.text}")
raise
def address_to_script_pubkey(address):
"""비트코인 주소를 ScriptPubKey로 변환"""
try:
alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
base58_decoded = 0
for char in address:
base58_decoded = base58_decoded * 58 + alphabet.index(char)
address_bytes = base58_decoded.to_bytes(25, byteorder="big")
print(f"Base58 디코딩 성공: {address_bytes.hex()}")
pubkey_hash = address_bytes[1:-4] # 네트워크 바이트와 체크섬 제외
script_pubkey = b"\x76\xa9" + bytes([len(pubkey_hash)]) + pubkey_hash + b"\x88\xac"
print(f"ScriptPubKey 생성 성공: {script_pubkey.hex()}")
return script_pubkey
except Exception as e:
print(f"주소 변환 실패: {e}")
raise
def modify_coinbase_tx(block_template, extra_nonce):
"""코인베이스 트랜잭션 생성"""
coinbase_value = block_template["coinbasevalue"]
script_pubkey = address_to_script_pubkey(MINING_ADDRESS)
extra_nonce_script = struct.pack("
script_pubkey = extra_nonce_script + script_pubkey
coinbase_tx = (
b"\x01"
b"\x00"
b"\x01"
+ b"\x00" * 32
+ b"\xff" * 4
+ b"\x01"
+ struct.pack("
+ struct.pack("B", len(script_pubkey))
+ script_pubkey
)
return coinbase_tx
def calculate_merkle_root(transactions):
"""머클 루트 계산"""
transaction_hashes = [hashlib.sha256(bytes.fromhex(tx["data"])).digest() for tx in transactions]
while len(transaction_hashes) > 1:
if len(transaction_hashes) % 2 == 1: # 홀수인 경우 마지막 해시 복사
transaction_hashes.append(transaction_hashes[-1])
transaction_hashes = [
hashlib.sha256(transaction_hashes
+ transaction_hashes[i + 1]).digest()
for i in range(0, len(transaction_hashes), 2)
]
return transaction_hashes[0][::-1] # Little-endian 반환
def calculate_block_hash(header):
"""블록 헤더를 해싱하여 블록 해시 생성"""
hash1 = hashlib.sha256(header).digest()
hash2 = hashlib.sha256(hash1).digest()
return hash2[::-1] # Little-endian 반환
def mine():
"""마이닝 루프"""
print("비트코인 채굴을 시작합니다...")
extra_nonce = 0 # Extra Nonce를 처음부터 적용
while True:
try:
block_template = rpc_request("getblocktemplate", [{"rules": ["segwit"]}])
previous_block = block_template["previousblockhash"]
target = int(block_template["target"], 16)
print(f"마이닝 타겟: {block_template['target']}")
while True: # Extra Nonce 루프
coinbase_tx = modify_coinbase_tx(block_template, extra_nonce)
transactions = [{"data": coinbase_tx.hex()}] + block_template["transactions"]
merkle_root = calculate_merkle_root(transactions)
version = struct.pack(" prev_block_hash = bytes.fromhex(previous_block)[::-1]
ntime = struct.pack(" nbits = bytes.fromhex(block_template["bits"])[::-1]
nonce = 0
while nonce < 2**32: # Nonce 값 범위
header = (
version
+ prev_block_hash
+ merkle_root
+ ntime
+ nbits
+ struct.pack(" )
block_hash = calculate_block_hash(header)
if int(block_hash.hex(), 16) < target:
print(f"마이닝 성공! 블록 해시: {block_hash.hex()}")
print(f"Extra Nonce: {extra_nonce}, Nonce: {nonce}")
result = rpc_request("submitblock", [header.hex()])
if result is None:
print("블록 제출 성공!")
else:
print(f"블록 제출 실패: {result}")
return # 마이닝 루프 종료
nonce += 1
# Nonce 소진 시 Extra Nonce 증가
print(f"Nonce 소진 - Extra Nonce 증가: {extra_nonce}")
extra_nonce += 1
except Exception as e:
print(f"에러 발생: {e}")
time.sleep(5)
if __name__ == "__main__":
mine()