Author

Topic: Solo mining with Bitcoin Core + Python program (Read 15 times)

?
Activity: -
Merit: -
January 28, 2025, 02:13:59 AM
#1
저는 제 노트북에 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()
Jump to: