Bitcoin Forum
December 14, 2024, 09:43:26 PM *
News: Latest Bitcoin Core release: 28.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Python Mining Process | Visual Mining Learning | Community Updated  (Read 259 times)
DaCryptoRaccoon (OP)
Hero Member
*****
Offline Offline

Activity: 1241
Merit: 623


OGRaccoon


View Profile
February 18, 2023, 01:21:50 AM
Last edit: February 28, 2024, 06:10:52 PM by DaCryptoRaccoon
 #1

** Update 28/02/2024 - Final code now on Github. https://github.com/DaCryptoRaccoon/BitcoinSoloPy

Looking for some advice on the mining process with python I have added the sections below I am most interested in knowing if they are in the correct order they seem to be working and output looks good.  I would be interested to have the community update maybe add in some features use it for a learning tool to visually see the mining process so I included the full script at the bottom of the post.  

I would also like to know how I can calculate the hashrate of the CPU and display that along size the nonce value that runs on the same line while the script is running I am unsure how to go about calculating the hashrate so this would be something I would be interested in having added.

Any help or updates if anyone is interested in this would be great!

As stated at the start of the post here are some section that I would like to know if they are in the correct sequence.

Code:
    ## This code is used to create a target (difficulty) and extranonce2 value for a mining context (ctx).
    ## The target is created by taking the last 3 bits of the nbits field from the context and appending '00' to the end of it ctx.nbits[2:] times.
    ## The extranonce2 value is a random number between 0 and 2^32-1, which is converted to hex and padded with zeros to match the length of the ctx.extranonce2_size.

    target = (ctx.nbits[2 :] + '00' * (int(ctx.nbits[:2] , 16) - 3)).zfill(64)
    extranonce2 = hex(random.randint(0 , 2 ** 32 - 1))[2 :].zfill(2 * ctx.extranonce2_size)  # create random

    ## This code is used to create a coinbase hash from the mining context (ctx) and the extranonce2 value generated in the previous code.
    ## The coinbase is created by combining the ctx.coinb1, ctx.extranonce1, extranonce2 and ctx.coinb2 fields.
    ## The coinbase hash is then generated by taking the SHA-256 hash of the coinbase twice and getting the binary digest.

    coinbase = ctx.coinb1 + ctx.extranonce1 + extranonce2 + ctx.coinb2
    coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest()

    ## This code is used to generate a Merkle root from the mining context (ctx) and the coinbase hash generated in the previous code.
    ## The Merkle root is generated by looping through the ctx.merkle_branch list and combining the merkle_root and the current branch element in each iteration.
    ## The combined values are then hashed twice with SHA-256 to generate the new merkle_root.

    merkle_root = coinbase_hash_bin
    for h in ctx.merkle_branch :
        merkle_root = hashlib.sha256(hashlib.sha256(merkle_root + binascii.unhexlify(h)).digest()).digest()

   ## This code is used to convert the binary Merkle root generated in the previous code to a hexadecimal string.
   ## The binary merkle_root is converted to a hexadecimal string using the binascii.hexlify() function,
   ## and then the result is decoded to a string using the decode() method.

    merkle_root = binascii.hexlify(merkle_root).decode()

    ## This code is used to format the Merkle root generated in the previous code. The string is split into two-character substrings,
    ## and the result is reversed using the [::-1] slice notation.
    ## The work_on variable is used to get the current block height,
    ## and the ctx.nHeightDiff dictionary is updated with the new block height and a value of 0.

    merkle_root = ''.join([merkle_root[i] + merkle_root[i + 1] for i in range(0 , len(merkle_root) , 2)][: :-1])
    work_on = get_current_block_height()
    ctx.nHeightDiff[work_on + 1] = 0

    ## This code is used to calculate the difficulty for the current block.
    ## The difficulty is calculated by taking the hex string "00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
    ## and dividing it by the target value which is also in hex format. The result is the difficulty for the current block.

    _diff = int("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" , 16)

     ## This code is used to generate a blockheader from the mining context (ctx), the Merkle root,
     ## a random nonce, and the hash of the blockheader. The blockheader is created by combining the
     ## ctx.version, ctx.prevhash, merkle_root, ctx.ntime, ctx.nbits, nonce and,
     ## '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'.
     ## The hash of the blockheader is then generated by taking the SHA-256 hash of the blockheader twice and getting the binary digest.
     ## The result is then converted to a hexadecimal string using the binascii.hexlify() function.

        nonce = hex(random.randint(0 , 2 ** 32 - 1))[2 :].zfill(8)  # nNonce   #hex(int(nonce,16)+1)[2:]
        blockheader = ctx.version + ctx.prevhash + merkle_root + ctx.ntime + ctx.nbits + nonce + \
                      '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'
        hash = hashlib.sha256(hashlib.sha256(binascii.hexlify()



Running Output In Terminal :

Code:
[ 00:52:13.570480 ]  Solo Miner Active
[ 00:52:13.570503 ]  [*] Bitcoin Miner Restarted
[*] Target:  [ 0000000000000000000730390000000000000000000000000000000000000000
[*] Extranonce2:  [ 0000000081c85ef1
[*] Coinbase Hash:  [ 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff35037fdb0b00043d21f06304a91445120c663eb5880000000081c85ef10a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff035da99424000000001976a914de7065b31fad6c0f9c66b81f1958ebb356af9fb888ac941dbf00000000001976a914f4cbe6c6bb3a8535c963169c22963d3a20e7686988ac0000000000000000266a24aa21a9ed120b0cd349e61ea31bd80040ca4e6a2daae782690bd6c70c597f6f00f43bf3ec00000000
[*] Merkle Root:  [ 7132975fd8b01f54806294db489ff4628474e43d5486680692a7c4186aae2d99
[*] Diff:  [ 26959946667150639794667015087019630673637144422540572481103610249215 ]
[*] Nonce: d501c71560





UPDATED CODE READ DOWN TOPIC


The code connects to CK Solo pool for work and pulls the block height from blockchain.info you can change the address in the script you might get lucky! but probably not!

If anyone can work out how I can calculate the hashrate of the CPU and have it output in the same terminal line as the nonce value would be great!

SoloMine.py


Code:

# Bitcoin Solo Miner
import requests
import socket
import threading
import json
import hashlib
import binascii
import logging
import random
import time
import traceback
import context as ctx
from datetime import datetime
from signal import SIGINT , signal
from colorama import Back , Fore , Style


sock = None

def timer() :
    tcx = datetime.now().time()
    return tcx

## Lucky BTC Address! May Satoshi Be With You!
address = '1MH9f5wc5phwL2KzqjzAdriERHPawmaRjy'

print(Back.BLUE , Fore.WHITE , 'SOLO ADDRESS:' , Fore.GREEN, str(address) , Style.RESET_ALL)

def handler(signal_received , frame) :
    ## Handle Cleanup ##
    ctx.fShutdown = True
    print(Fore.MAGENTA , '[' , timer() , ']' , Fore.YELLOW , 'Force Close, Please Wait..')

## Start Logging to file miner.log
## Include Timestamps

def logg(msg) :
    # basic logging
    logging.basicConfig(level = logging.INFO , filename = "miner.log" ,
                        format = '%(asctime)s %(message)s')
    logging.info(msg)

 ## This code is used to get the current block height of the Bitcoin network.
 ## The request is made to the blockchain.info API and the response is parsed to get the height field.
 ## The height is then converted to an integer and returned.

def get_current_block_height() :
    # returns the current network height
    r = requests.get('https://blockchain.info/latestblock')
    return int(r.json()['height'])

## This code is used to check if the mining context (ctx) is in shutdown mode.
## If the ctx.fShutdown flag is set to True, the ctx.listfThreadRunning list is updated with the current thread's index (n) and set to False.
## The thread's exit flag is also set to True to signal the thread to exit.

def check_for_shutdown(t) :
    ## handle shutdown ##
    n = t.n
    if ctx.fShutdown :
        if n != -1 :
            ctx.listfThreadRunning[n] = False
            t.exit = True

## This code is defining a custom thread class called ExitedThread which is a subclass of threading.Thread.
## The class has two attributes, exit and arg, and four methods,
## __init__, run, thread_handler and thread_handler2. The __init__ method is used to initialize the class and set the exit,
## arg and n attributes. The run method is used to call the thread_handler method with the arg and n attributes as parameters.
## The thread_handler method is used to check for shutdown and if the exit flag is set to True, the thread exits.
## The thread_handler2 method is used to be implemented by subclasses and is not implemented in this class.
## The check_self_shutdown and try_exit methods are used to check for shutdown and try to exit the thread, respectively.


class ExitedThread(threading.Thread) :
    def __init__(self , arg , n) :
        super(ExitedThread , self).__init__()
        self.exit = False
        self.arg = arg
        self.n = n

    def run(self) :
        self.thread_handler(self.arg , self.n)
        pass

    def thread_handler(self , arg , n) :
        while True :
            check_for_shutdown(self)
            if self.exit :
                break
            ctx.listfThreadRunning[n] = True
            try :
                self.thread_handler2(arg)
            except Exception as e :
                logg("ThreadHandler()")
                print(Fore.MAGENTA , '[' , timer() , ']' , Fore.WHITE , 'ThreadHandler()')
                logg(e)
                print(Fore.RED , e)
            ctx.listfThreadRunning[n] = False

            time.sleep(2)
            pass

    def thread_handler2(self , arg) :
        raise NotImplementedError("must impl this func")

    def check_self_shutdown(self) :
        check_for_shutdown(self)

    def try_exit(self) :
        self.exit = True
        ctx.listfThreadRunning[self.n] = False
        pass

 ## This code is defining a function called bitcoin_miner which is used to start and restart the bitcoin miner.
 ## If the miner is restarted, it will log and print that it has been restarted and sleep for 5 seconds.
 ## It will then log and print that the miner has started. It then runs a loop which checks if the miner thread is still alive and if the subscribe thread is running.
 ## If either of these conditions are not true, the loop will break. Otherwise,
 ## it will set the miner thread to be running, call the mining method on the miner thread, and set the miner thread to be not running.
 ## If an exception occurs, it is logged and the traceback is printed, and the loop breaks.

def bitcoin_miner(t , restarted = False) :
    if restarted :
        logg('\n[*] Bitcoin Miner restarted')
        print(Fore.MAGENTA , '[' , timer() , ']' , Fore.YELLOW , 'Solo Miner Active')
        print(Fore.MAGENTA , '[' , timer() , ']' , Fore.BLUE , '[*] Bitcoin Miner Restarted')
        time.sleep(5)

    ## This code is used to create a target (difficulty) and extranonce2 value for a mining context (ctx).
    ## The target is created by taking the last 3 bits of the nbits field from the context and appending '00' to the end of it ctx.nbits[2:] times.
    ## The extranonce2 value is a random number between 0 and 2^32-1, which is converted to hex and padded with zeros to match the length of the ctx.extranonce2_size.

    target = (ctx.nbits[2 :] + '00' * (int(ctx.nbits[:2] , 16) - 3)).zfill(64)
    extranonce2 = hex(random.randint(0 , 2 ** 32 - 1))[2 :].zfill(2 * ctx.extranonce2_size)  # create random
    print( Fore.YELLOW , '[*] Target:' ,Fore.GREEN, '[' , target) , ']'
    print( Fore.YELLOW , '[*] Extranonce2:' ,Fore.GREEN , '[' , extranonce2) , ']'

    ## This code is used to create a coinbase hash from the mining context (ctx) and the extranonce2 value generated in the previous code.
    ## The coinbase is created by combining the ctx.coinb1, ctx.extranonce1, extranonce2 and ctx.coinb2 fields.
    ## The coinbase hash is then generated by taking the SHA-256 hash of the coinbase twice and getting the binary digest.

    coinbase = ctx.coinb1 + ctx.extranonce1 + extranonce2 + ctx.coinb2
    coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest()
    print( Fore.YELLOW , '[*] Coinbase Hash:' ,Fore.GREEN , '[' , coinbase) , ']'

    ## This code is used to generate a Merkle root from the mining context (ctx) and the coinbase hash generated in the previous code.
    ## The Merkle root is generated by looping through the ctx.merkle_branch list and combining the merkle_root and the current branch element in each iteration.
    ## The combined values are then hashed twice with SHA-256 to generate the new merkle_root.

    merkle_root = coinbase_hash_bin
    for h in ctx.merkle_branch :
        merkle_root = hashlib.sha256(hashlib.sha256(merkle_root + binascii.unhexlify(h)).digest()).digest()

        ## This code is used to convert the binary Merkle root generated in the previous code to a hexadecimal string.
        ## The binary merkle_root is converted to a hexadecimal string using the binascii.hexlify() function,
        ## and then the result is decoded to a string using the decode() method.

    merkle_root = binascii.hexlify(merkle_root).decode()
    print( Fore.YELLOW , '[*] Merkle Root:' ,Fore.YELLOW , '[' , merkle_root) , ']'

    # This code is used to format the Merkle root generated in the previous code. The string is split into two-character substrings,
    ## and the result is reversed using the [::-1] slice notation.
    ## The work_on variable is used to get the current block height,
    ## and the ctx.nHeightDiff dictionary is updated with the new block height and a value of 0.

    merkle_root = ''.join([merkle_root[i] + merkle_root[i + 1] for i in range(0 , len(merkle_root) , 2)][: :-1])
    work_on = get_current_block_height()
    ctx.nHeightDiff[work_on + 1] = 0

    ## This code is used to calculate the difficulty for the current block.
    ## The difficulty is calculated by taking the hex string "00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
    ## and dividing it by the target value which is also in hex format. The result is the difficulty for the current block.

    _diff = int("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" , 16)
    print( Fore.YELLOW , '[*] Diff:' ,Fore.YELLOW , '[' , int(_diff) , ']')
    logg('[*] Working to solve block at block height {}'.format(work_on + 1))
    print(Fore.MAGENTA , '[' , timer() , ']' , Fore.YELLOW , '[*] Working to solve block at ' , Fore.RED , 'height {}'.format(work_on + 1))

    ## Start Mining Loop ##

    ## This code is a while loop which checks if the thread should be shut down and if so, it breaks out of the loop.
    ## It then checks if a new block has been detected and if so, it logs and prints that a new block has been detected,
    ## logs and prints the difficulty of the block, restarts the bitcoin miner, and continues the loop.

    while True :
        t.check_self_shutdown()
        if t.exit :
            break

        if ctx.prevhash != ctx.updatedPrevHash :
            logg('[*] NEW BLOCK {} DETECTED ON NETWORK'.format(ctx.prevhash))
            print(Fore.YELLOW , '[' , timer() , ']' , Fore.MAGENTA , '[*] New block {} detected on' , Fore.BLUE , ' network '.format(ctx.prevhash))
            logg('[*] Best difficulty previous block {} was {}'.format(work_on + 1 ,ctx.nHeightDiff[work_on + 1]))
            print(Fore.MAGENTA , '[' , timer() , ']' , Fore.GREEN , '[*] Best Diff Trying Block' , Fore.YELLOW , ' {} ' , Fore.BLUE , 'was {}'.format(work_on + 1 ,ctx.nHeightDiff[work_on + 1]))
            ctx.updatedPrevHash = ctx.prevhash
            bitcoin_miner(t , restarted = True)
            print(Back.YELLOW , Fore.MAGENTA , '[' , timer() , ']' , Fore.BLUE , 'NEW BLOCK DETECTED - RESTARTING MINER...' ,
                  Style.RESET_ALL)
            continue

            ## This code is used to generate a blockheader from the mining context (ctx), the Merkle root,
            ## a random nonce, and the hash of the blockheader. The blockheader is created by combining the
            ## ctx.version, ctx.prevhash, merkle_root, ctx.ntime, ctx.nbits, nonce and,
            ## '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'.
            ## The hash of the blockheader is then generated by taking the SHA-256 hash of the blockheader twice and getting the binary digest.
            ## The result is then converted to a hexadecimal string using the binascii.hexlify() function.

        nonce = hex(random.randint(0 , 2 ** 32 - 1))[2 :].zfill(8)  # nNonce   #hex(int(nonce,16)+1)[2:]
        blockheader = ctx.version + ctx.prevhash + merkle_root + ctx.ntime + ctx.nbits + nonce + \
                      '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'
        hash = hashlib.sha256(hashlib.sha256(binascii.unhexlify(blockheader)).digest()).digest()
        hash = binascii.hexlify(hash).decode()

        ## Print Functions for terminal output
        ## Print Rolling Nonce
        ## Print Rolling Nonce + Block Header
        ## Print Block Header

        print( Fore.YELLOW + '[*] Nonce: ' + Fore.GREEN + str(nonce) , end="\r")
        ## Print Nonce Rolling + Rolling Block Header ##
        #print( Fore.YELLOW + '[*] Nonce: ' + Fore.GREEN + str(nonce) + Fore.YELLOW , '[*] Block Header:' ,Fore.GREEN , '[' , str(blockheader) , end="\r")
        ## Print Block Header ##
        #print( Fore.YELLOW , '[*] Block Header:' ,Fore.GREEN , '[' , str(blockheader) ,  end="\r")


        ##Log all hashes that start with 7 zeros or more ##
        if hash.startswith('000000') :
            logg('[*] New hash: {} for block {}'.format(hash , work_on + 1))
            print(Fore.MAGENTA , '[' , timer() , ']' , Fore.GREEN, '[*] New hash:' , Fore.GREEN , ' {} for block' , Fore.YELLOW ,' {}'.format(hash , work_on + 1))
            print(Fore.MAGENTA , '[' , timer() , ']' , Fore.YELLOW , 'Hash:' , str(hash).format(work_on + 1))

            ## This code is used to check if the difficulty of the current block is greater than the difficulty of the previous block.
            ## The difficulty of the current block is calculated by dividing the predetermined difficulty value _diff by the hash of the blockheader this_hash.
            ## If the current difficulty is greater than the previous difficulty stored in the ctx.nHeightDiff dictionary,
            ## the new difficulty is set as the value for the current block.

        this_hash = int(hash , 16)
        difficulty = _diff / this_hash

        if ctx.nHeightDiff[work_on + 1] < difficulty :
            # new best difficulty for block at x height
            ctx.nHeightDiff[work_on + 1] = difficulty

            ## This code is used to check if the hash of the blockheader is less than the target value.
            ## If the hash is less than the target, it means the block has been successfully solved and the ctx.solved flag is set to True.

        if hash < target :
            logg('[*] Block {} solved.'.format(work_on + 1))

            print(Fore.MAGENTA , '[' , timer() , ']' , Fore.YELLOW , '[*] Block {} solved.'.format(work_on + 1))
            logg('[*] Block hash: {}'.format(hash))
            print(Fore.YELLOW)
            print(Fore.MAGENTA , '[' , timer() , ']' , Fore.YELLOW , '[*] Block hash: {}'.format(hash))
            logg('[*] Blockheader: {}'.format(blockheader))
            print(Fore.BLUE , '--------------~~( ' , Fore.GREEN  , 'BLOCK SOLVED CHECK WALLET!' , Fore.ORANGE , ' )~~--------------')

            print(Fore.YELLOW , '[*] Blockheader: {}'.format(blockheader))
            payload = bytes('{"params": ["' + address + '", "' + ctx.job_id + '", "' + ctx.extranonce2 \
                            + '", "' + ctx.ntime + '", "' + nonce + '"], "id": 1, "method": "mining.submit"}\n' ,
                            'utf-8')
            logg('[*] Payload: {}'.format(payload))
            print(Fore.MAGENTA , '[' , timer() , ']' , Fore.BLUE , '[*] Payload:' , Fore.GREEN , ' {}'.format(payload))
            sock.sendall(payload)
            ret = sock.recv(1024)
            logg('[*] Pool response: {}'.format(ret))
            print(Fore.MAGENTA , '[' , timer() , ']' , Fore.GREEN , '[*] Pool Response:' , Fore.CYAN ,
                  ' {}'.format(ret))
            print(payload)
            return True

         ## This code is used to set up a connection to the ckpool server and send a handle subscribe message.
         ## The response is parsed to get the ctx.sub_details, ctx.extranonce1 and ctx.extranonce2_size fields.
         ## Then an authorize message is sent with the address and password, and the response is read until the mining.notify message is received.

def block_listener(t) :
    # init a connection to ckpool
    sock = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
    sock.connect(('solo.ckpool.org' , 3333))
    # send a handle subscribe message
    sock.sendall(b'{"id": 1, "method": "mining.subscribe", "params": []}\n')
    lines = sock.recv(1024).decode().split('\n')
    response = json.loads(lines[0])
    ctx.sub_details , ctx.extranonce1 , ctx.extranonce2_size = response['result']
    # send and handle authorize message
    sock.sendall(b'{"params": ["' + address.encode() + b'", "password"], "id": 2, "method": "mining.authorize"}\n')
    response = b''
    while response.count(b'\n') < 4 and not (b'mining.notify' in response) : response += sock.recv(1024)
    print(response)

    ## This code is used to parse the response from the ckpool server and get the necessary fields for the mining context (ctx).
    ## The response is split into individual lines and only lines that contain the 'mining.notify' string are parsed.
    ## The parsed results are then stored in the,
    ## ctx.job_id, ctx.prevhash, ctx.coinb1, ctx.coinb2, ctx.merkle_branch, ctx.version, ctx.nbits, ctx.ntime and ctx.clean_jobs fields.

    responses = [json.loads(res) for res in response.decode().split('\n') if
                 len(res.strip()) > 0 and 'mining.notify' in res]
    ctx.job_id , ctx.prevhash , ctx.coinb1 , ctx.coinb2 , ctx.merkle_branch , ctx.version , ctx.nbits , ctx.ntime , ctx.clean_jobs = \
        responses[0]['params']

    ## Do this one time, will be overwriten by mining loop when new block is detected

    ctx.updatedPrevHash = ctx.prevhash

    while True :
        t.check_self_shutdown()
        if t.exit :
            break

        ## This code is used to check if the previous hash in the response from the ckpool server is different from the previous hash,
        ## in the mining context (ctx). If the hashes are different, the response is parsed to get the necessary fields
        ## for the mining context and the fields are updated with the new values.

        response = b''
        while response.count(b'\n') < 4 and not (b'mining.notify' in response) : response += sock.recv(1024)
        responses = [json.loads(res) for res in response.decode().split('\n') if
                     len(res.strip()) > 0 and 'mining.notify' in res]

        if responses[0]['params'][1] != ctx.prevhash :

            ## New block detected on network
            ## update context job data

            ctx.job_id , ctx.prevhash , ctx.coinb1 , ctx.coinb2 , ctx.merkle_branch , ctx.version , ctx.nbits , ctx.ntime , ctx.clean_jobs = \
                responses[0]['params']

    ## This code is defining a custom thread class called CoinMinerThread which is a subclass of ExitedThread.
    ## The class has two methods, __init__ and thread_handler2. The __init__ method is used to initialize the class and set the n attribute to 0.
    ## The thread_handler2 method calls the thread_bitcoin_miner method with the arg parameter. The thread_bitcoin_miner method is used to check for shutdown,
    ## and then calls the bitcoin_miner function with the current thread object as the parameter. The result of the bitcoin_miner function is logged to the console.

class CoinMinerThread(ExitedThread) :
    def __init__(self , arg = None) :
        super(CoinMinerThread , self).__init__(arg , n = 0)

    def thread_handler2(self , arg) :
        self.thread_bitcoin_miner(arg)

    def thread_bitcoin_miner(self , arg) :
        ctx.listfThreadRunning[self.n] = True
        check_for_shutdown(self)
        try :
            ret = bitcoin_miner(self)
            logg(Fore.MAGENTA , "[" , timer() , "] [*] Miner returned %s\n\n" % "true" if ret else "false")
            print(Fore.LIGHTCYAN_EX , "[*] Miner returned %s\n\n" % "true" if ret else "false")
        except Exception as e :
            logg("[*] Miner()")
            print(Back.WHITE , Fore.MAGENTA , "[" , timer() , "]" , Fore.BLUE , "[*] Miner()")
            logg(e)
            traceback.print_exc()
        ctx.listfThreadRunning[self.n] = False

    pass

## This code is defining a new class called NewSubscribeThread which is a subclass of ExitedThread. It has two methods,
## __init__ and thread_handler2. The __init__ method sets up the thread with the specified argument and sets the number of threads to 1.
## The thread_handler2 method calls the thread_new_block method with the specified argument.
## The thread_new_block method sets the thread to be running, checks for shutdown, and then calls the block_listener function. If an exception occurs,
## it is logged and the traceback is printed. Finally, the thread is set to be not running.

class NewSubscribeThread(ExitedThread) :
    def __init__(self , arg = None) :
        super(NewSubscribeThread , self).__init__(arg , n = 1)

    def thread_handler2(self , arg) :
        self.thread_new_block(arg)

    def thread_new_block(self , arg) :
        ctx.listfThreadRunning[self.n] = True
        check_for_shutdown(self)
        try :
            ret = block_listener(self)
        except Exception as e :
            logg("[*] Subscribe thread()")
            print(Fore.MAGENTA , "[" , timer() , "]" , Fore.YELLOW , "[*] Subscribe thread()")
            logg(e)
            traceback.print_exc()
        ctx.listfThreadRunning[self.n] = False

    pass

    ## This code is defining a function called StartMining which creates a thread for subscribing and one for mining.
    ## It first creates a new thread called subscribe_t which uses the NewSubscribeThread class.
    ## It then starts the thread and logs that the subscribe thread has been started.
    ## It then sleeps for 4 seconds and creates a new thread called miner_t which uses the CoinMinerThread class.
    ## It then starts the thread and logs that the Bitcoin solo miner has been started.

def StartMining() :
    subscribe_t = NewSubscribeThread(None)
    subscribe_t.start()
    logg("[*] Subscribe thread started.")
    print(Fore.MAGENTA , "[" , timer() , "]" , Fore.GREEN , "[*] Subscribe thread started.")

    time.sleep(4)

    miner_t = CoinMinerThread(None)
    miner_t.start()
    logg("[*]£££ Bitcoin Solo Miner Started £££")
    print(Fore.MAGENTA , "[" , timer() , '(', Fore.GREEN  , 'SOLO MINER STARTED' , Fore.BLUE , ' )~~--------------')
    print(Fore.BLUE , '--------------~~( ' , Fore.YELLOW , 'IN SATOSHI WE TRUST' , Fore.BLUE , ' )~~--------------')
    print(Fore.BLUE , '--------------~~( ' , Fore.GREEN  , 'DO NOT TRUST VERIFY' , Fore.BLUE , ' )~~--------------')


if __name__ == '__main__' :
    signal(SIGINT , handler)
    StartMining()



Context.py

Code:
fShutdown = False
listfThreadRunning = [False] * 2
local_height = 0
nHeightDiff = {}
updatedPrevHash = None
job_id = None
prevhash = None
coinb1 = None
coinb2 = None
merkle_branch = None
version = None
nbits = None
ntime = None
clean_jobs = None
sub_details = None
extranonce1 = None
extranonce2_size = None





┏━━━━━━━━━━━━━━━━━┓
┃     𝔱𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔬𝔯ⱪ 𝔣𝔬𝔯 𝔶𝔬𝔲𝔯 𝔟𝔞𝔤𝔰       ┃
┃                ➤21/M                      ┃
┃ ███▓▓  ███▓▓  ███▓▓  ███▓▓┃
Kostelooscoin
Member
**
Offline Offline

Activity: 206
Merit: 16


View Profile
February 18, 2023, 12:58:12 PM
 #2

ImportError: No module named context

python3
pip3 install context = ERROR: No matching distribution found for context.viewer
DaCryptoRaccoon (OP)
Hero Member
*****
Offline Offline

Activity: 1241
Merit: 623


OGRaccoon


View Profile
February 18, 2023, 03:19:27 PM
Last edit: February 19, 2023, 12:49:34 PM by MagicByt3
 #3

ImportError: No module named context

python3
pip3 install context = ERROR: No matching distribution found for context.viewer

Context should be with python above 3.7 if below update python to the later version.

Context is not a pip module.

Edit : Added the context file just include it in the same directory as the SoloMine.py file.

┏━━━━━━━━━━━━━━━━━┓
┃     𝔱𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔬𝔯ⱪ 𝔣𝔬𝔯 𝔶𝔬𝔲𝔯 𝔟𝔞𝔤𝔰       ┃
┃                ➤21/M                      ┃
┃ ███▓▓  ███▓▓  ███▓▓  ███▓▓┃
DaCryptoRaccoon (OP)
Hero Member
*****
Offline Offline

Activity: 1241
Merit: 623


OGRaccoon


View Profile
February 24, 2023, 07:07:58 PM
 #4



Breakdown now shows:
Target - Extranonce2 - Coinbase Hash - Coinbase Hash BIN Hex - Coinb-1 - Coinb-2 - Merkel Root - Block Height - Nonce - Hashrate

Code:
[*] Target:  [ 0000000000000000000730390000000000000000000000000000000000000000
[*] Extranonce2:  [ 00000000dd398605
[*] Coinbase Hash:  [ 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff35039fdf0b0004fb09f963041a71420c0c4f52e28800000000dd3986050a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff0394a2b225000000001976a914de7065b31fad6c0f9c66b81f1958ebb356af9fb888aca4f3c400000000001976a914f4cbe6c6bb3a8535c963169c22963d3a20e7686988ac0000000000000000266a24aa21a9ed39a54281bf28eedaa2da014692e7417cfe7d2ad5f2558f7036d730ccda8d941000000000
[*] Coinbase Hash Bin Hex:  [ b'\xab{\xecV&\xfd?\xcf\xdd\xe3\xef\xc4\x9b\x99\xcdq$ov&\x94\xe8jP\x8f\x9f/\xa3\x89\x0f\xe7\xd3'
[*] Coinb-1:  [ 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff35039fdf0b0004fb09f963041a71420c0c
[*] Coinb-2:  [ 0a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff0394a2b225000000001976a914de7065b31fad6c0f9c66b81f1958ebb356af9fb888aca4f3c400000000001976a914f4cbe6c6bb3a8535c963169c22963d3a20e7686988ac0000000000000000266a24aa21a9ed39a54281bf28eedaa2da014692e7417cfe7d2ad5f2558f7036d730ccda8d941000000000
 [*] Merkle Root:  [ ebc4cc2a50e3cfb379320491c03253ad3fbb251affd42b8243f5e4bb921abad1
 [*] Block Height:  [ 778142 ]
 [ 19:03:36.767895 ]  [*] Working to solve block Good Luck!
[*] Nonce: 3a3b78b1 [*] Hashrate: 9320675.555555556

┏━━━━━━━━━━━━━━━━━┓
┃     𝔱𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔬𝔯ⱪ 𝔣𝔬𝔯 𝔶𝔬𝔲𝔯 𝔟𝔞𝔤𝔰       ┃
┃                ➤21/M                      ┃
┃ ███▓▓  ███▓▓  ███▓▓  ███▓▓┃
alexeyneu
Member
**
Online Online

Activity: 372
Merit: 37


View Profile
February 25, 2023, 03:34:50 PM
 #5

Coinbase Hash smth output looks like garbage
DaCryptoRaccoon (OP)
Hero Member
*****
Offline Offline

Activity: 1241
Merit: 623


OGRaccoon


View Profile
February 25, 2023, 04:05:29 PM
Last edit: February 26, 2023, 09:40:58 AM by MagicByt3
 #6

Coinbase Hash smth output looks like garbage

Seems fine here could you elaborate why you think it's incorrect?  It decodes correctly.  



Code:
  SOLO ADDRESS:  1MH9f5wc5phwL2KzqjzAdriERHPawmaRjy 
[ 20:06:25.205196 ]  [*] Subscribe thread started.
b'{"params":["5eebeafb0018d3a2","d52462208723afbf50e768bd417f12c042107f740005596e0000000000000000","01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff350315e00b0004076afa6304b1d2bf1f0c","0a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff030ff94e25000000001976a914de7065b31fad6c0f9c66b81f1958ebb356af9fb888acf5eac200000000001976a914f4cbe6c6bb3a8535c963169c22963d3a20e7686988ac0000000000000000266a24aa21a9ed8060d1d70f0e2a5ad8dafa90110c982049d48ddd3d8baac3950de4a510948cd800000000",["643c00c388d1e21f5d80241a80e767007e2df4102067eb7af5944259448993f8","1e89696b69c10f50edd41aa1c9b6bdd1118e483df2ae7e65f9771dcfbe7af12c","317959a9a67b01c436c5fc8157fe53cc985319b51c58e584c743849aedf9e6e2","4f3c0b9e356ffaa1d6807aa597c5591e2035dff11325a6cdfabdc47b727c51f5","c3e6ddae4f3c578bed721e48f6bd9b0d90a20d55930823b77429629cb2b51d09","b514b4d495627c99525ce537dcc001f68823d90073a37892f3419282874dcde9","0cb0a22c092c00d753afe7e5b48b01f0b0c073986111f4bb04f7871b1ebd2971","13674fd28edfcc48223cecbff3ffab129991c50b99c9366936ee2f1508862bac","b2fd85e1716ed267ee3ec1087ff93da892f202cef4f9320129fcae6f7db8ab0d","bf70597a04f7aadda795bbbd3488599edf6c08a38fd1700f2ce8bd48f717c877","5074da5f8c301f5b11d600c914ab4494b2954c8882f988fa316a9b22a6bbc13c"],"20000000","170689a3","63fa6a07",true],"id":null,"method":"mining.notify"}\n{"params":[10000],"id":null,"method":"mining.set_difficulty"}\n{"result":true,"error":null,"id":2}\n'
[*] Target:  [ 0000000000000000000689a30000000000000000000000000000000000000000
[*] Extranonce2:  [ 00000000bfc82f61
[ 20:06:29.210088 (  SOLO MINER STARTED   )~~--------------
 --------------~~(   IN SATOSHI WE TRUST   )~~--------------
 --------------~~(   DO NOT TRUST VERIFY   )~~--------------
[*] Coinbase Hash:  [ 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff350315e00b0004076afa6304b1d2bf1f0cadc6e88800000000bfc82f610a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff030ff94e25000000001976a914de7065b31fad6c0f9c66b81f1958ebb356af9fb888acf5eac200000000001976a914f4cbe6c6bb3a8535c963169c22963d3a20e7686988ac0000000000000000266a24aa21a9ed8060d1d70f0e2a5ad8dafa90110c982049d48ddd3d8baac3950de4a510948cd800000000
 [*] Coinbase Hash Bin Hex:  [ b'\x87c\x05@\x1b\x9e\x91\x1a\xb8\x17\xc2r\xafs"\n\x8c\xa2k\x1a\x97\xc0\x99\x14;\xc5\x82&\x10?\xa4_'
 [*] Coinb-1:  [ 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff350315e00b0004076afa6304b1d2bf1f0c
 [*] Coinb-2:  [ 0a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff030ff94e25000000001976a914de7065b31fad6c0f9c66b81f1958ebb356af9fb888acf5eac200000000001976a914f4cbe6c6bb3a8535c963169c22963d3a20e7686988ac0000000000000000266a24aa21a9ed8060d1d70f0e2a5ad8dafa90110c982049d48ddd3d8baac3950de4a510948cd800000000
 [*] Merkle Root:  [ 01deed1aa10f17f91810cc5697bb89d82950db1c39a954a58b3e11a77edb34f8
 [*] Block Height:  [ 778260 ]
 [ 20:06:29.496780 ]  [*] Working to solve block Good Luck!
 [ 20:07:15.322047 ]  [*] New hash:   {} for block   000000a4d882b03fa38f9ec9e2b032966b93b9a6b3cd5a4e222efce5d92184d3
 [ 20:07:15.322076 ]  Hash: 000000a4d882b03fa38f9ec9e2b032966b93b9a6b3cd5a4e222efce5d92184d3
[*] Nonce: 43598071 [*] Hashrate: 16777216.0695652



Decoded :

Code:
{
    "addresses": [
        "1MH9f5wc5phwL2KzqjzAdriERHPawmaRjy",
        "1PKN98VN2z5gwSGZvGKS2bj8aADZBkyhkZ"
    ],
    "block_height": -1,
    "block_index": -1,
    "confirmations": 0,
    "data_protocol": "unknown",
    "double_spend": false,
    "fees": 0,
    "hash": "5fa43f102682c53b1499c0971a6ba28c0a2273af72c217b81a919e1b40056387",
    "inputs": [
        {
            "age": 0,
            "output_index": -1,
            "script": "0315e00b0004076afa6304b1d2bf1f0cadc6e88800000000bfc82f610a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672f",
            "script_type": "empty",
            "sequence": 4294967295
        }
    ],
    "outputs": [
        {
            "addresses": [
                "1MH9f5wc5phwL2KzqjzAdriERHPawmaRjy"
            ],
            "script": "76a914de7065b31fad6c0f9c66b81f1958ebb356af9fb888ac",
            "script_type": "pay-to-pubkey-hash",
            "value": 625932559
        },
        {
            "addresses": [
                "1PKN98VN2z5gwSGZvGKS2bj8aADZBkyhkZ"
            ],
            "script": "76a914f4cbe6c6bb3a8535c963169c22963d3a20e7686988ac",
            "script_type": "pay-to-pubkey-hash",
            "value": 12774133
        },
        {
            "addresses": null,
            "data_hex": "aa21a9ed8060d1d70f0e2a5ad8dafa90110c982049d48ddd3d8baac3950de4a510948cd8",
            "script": "6a24aa21a9ed8060d1d70f0e2a5ad8dafa90110c982049d48ddd3d8baac3950de4a510948cd8",
            "script_type": "null-data",
            "value": 0
        }
    ],
    "preference": "low",
    "received": "2023-02-25T20:12:08.805687149Z",
    "relayed_by": "54.197.21.66",
    "size": 219,
    "total": 638706692,
    "ver": 1,
    "vin_sz": 1,
    "vout_sz": 3,
    "vsize": 219
}

Input New Transaction Hex
Transaction Hex*
01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff350315e00b0004076afa6304b1d2bf1f0cadc6e88800000000bfc82f610a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff030ff94e25000000001976a914de7065b31fad6c0f9c66b81f1958ebb356af9fb888acf5eac200000000001976a914f4cbe6c6bb3a8535c963169c22963d3a20e7686988ac0000000000000000266a24aa21a9ed8060d1d70f0e2a5ad8dafa90110c982049d48ddd3d8baac3950de4a510948cd800000000



Best regards

┏━━━━━━━━━━━━━━━━━┓
┃     𝔱𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔬𝔯ⱪ 𝔣𝔬𝔯 𝔶𝔬𝔲𝔯 𝔟𝔞𝔤𝔰       ┃
┃                ➤21/M                      ┃
┃ ███▓▓  ███▓▓  ███▓▓  ███▓▓┃
DaCryptoRaccoon (OP)
Hero Member
*****
Offline Offline

Activity: 1241
Merit: 623


OGRaccoon


View Profile
December 21, 2023, 10:52:29 AM
Last edit: December 22, 2023, 05:08:13 AM by DaCryptoRaccoon
 #7

Sorry for the long term push on this but I have recently returned to the script and have some updated and have some questions maybe someone might be able to help with.  New code posted below.


1. Added hashrate tracking and showing best hash found with a diff value and store it to miner.log and print on terminal.
2. I am intersted to know more about how a miner will submit a "share" at the moment I just set it to  if difficulty >= 16: but I am sure this is probably not the correct method for this.

Any help or advice on this would be great also I know not going to find a block with this just doing to to learn.

I would be interested to know more about how the shares work and if there is a way to add in some calculations for total work done or total work done in relation to the target value.

I added the miner.log file also after a short run.

Thanks in advance.

Updated Miner.py

Code:
# Python Bitcoin Solo Miner
import requests
import socket
import threading
import json
import hashlib
import binascii
import logging
import random
import time
import traceback
import context as ctx
import psutil
from datetime import datetime
from signal import SIGINT, signal
from colorama import Back, Fore, Style
from tabulate import tabulate
from tqdm import tqdm

sock = None
best_difficulty = 0
best_hash = None
# Initialize difficulty outside the loop
difficulty = 0

# Initialize best share difficulty and hash
best_share_difficulty = float('inf')
best_share_hash = None

# Set the difficulty level
difficulty = 16

def show_loading_splash():
    ascii_art = """
⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣴⣶⣾⣿⣿⣿⣿⣷⣶⣦⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⣠⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣄⠀⠀⠀⠀⠀
⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀
⠀⠀⣴⣿⣿⣿⣿⣿⣿⣿⠟⠿⠿⡿⠀⢰⣿⠁⢈⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⠀
⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣤⣄⠀⠀⠀⠈⠉⠀⠸⠿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀
⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⢠⣶⣶⣤⡀⠀⠈⢻⣿⣿⣿⣿⣿⣿⣿⡆
⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠼⣿⣿⡿⠃⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣷
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠀⠀⢀⣀⣀⠀⠀⠀⠀⢴⣿⣿⣿⣿⣿⣿⣿⣿⣿
⢿⣿⣿⣿⣿⣿⣿⣿⢿⣿⠁⠀⠀⣼⣿⣿⣿⣦⠀⠀⠈⢻⣿⣿⣿⣿⣿⣿⣿⡿
⠸⣿⣿⣿⣿⣿⣿⣏⠀⠀⠀⠀⠀⠛⠛⠿⠟⠋⠀⠀⠀⣾⣿⣿⣿⣿⣿⣿⣿⠇
⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⣤⡄⠀⣀⣀⣀⣀⣠⣾⣿⣿⣿⣿⣿⣿⣿⡟⠀
⠀⠀⠻⣿⣿⣿⣿⣿⣿⣿⣄⣰⣿⠁⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀
⠀⠀⠀⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀
⠀⠀⠀⠀⠀⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠋⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⢿⣿⣿⣿⣿⡿⠿⠟⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀
       WE ARE ALL SATOSHI
         B I T C O I N
    """
    # ANSI escape code for orange text
    orange_text = '\033[38;5;202m'
    # ANSI escape code to reset color
    reset_color = '\033[0m'

    print(orange_text + ascii_art + reset_color)

# Call this function at the start of your script
show_loading_splash()

def timer():
    return datetime.now().time()

## Mining Address **Change Me**

address = '123dAmdR7vV8FXRZ6hFzZCquyAzLuzEhAJ'
print(Back.BLUE, Fore.WHITE, 'SOLO ADDRESS:', Fore.GREEN, str(address), Style.RESET_ALL)

def handler(signal_received, frame):
    ctx.fShutdown = True
    print(Fore.MAGENTA, '[', timer(), ']', Fore.YELLOW, 'Force Close, Please Wait..')


# Define the logger with the desired format
logging.basicConfig(level=logging.INFO, filename="miner.log", format='%(asctime)s %(message)s')
logger = logging.getLogger("miner_logger")

# Update the logg function to use the logger
def logg(msg):
    logger.info(msg)


 ## This code is used to get the current block height of the Bitcoin network.
 ## The request is made to the blockchain.info API and the response is parsed to get the height field.
 ## The height is then converted to an integer and returned.
def get_current_block_height():
    r = requests.get('https://blockchain.info/latestblock')
    return int(r.json()['height'])


## This code is used to check if the mining context (ctx) is in shutdown mode.
## If the ctx.fShutdown flag is set to True, the ctx.listfThreadRunning list is updated with the current thread's index (n) and set to False.
## The thread's exit flag is also set to True to signal the thread to exit.
def check_for_shutdown(t):
    n = t.n
    if ctx.fShutdown:
        if n != -1:
            ctx.listfThreadRunning[n] = False
            t.exit = True

## This code is defining a custom thread class called ExitedThread which is a subclass of threading.Thread.
## The class has two attributes, exit and arg, and four methods,
## __init__, run, thread_handler and thread_handler2. The __init__ method is used to initialize the class and set the exit,
## arg and n attributes. The run method is used to call the thread_handler method with the arg and n attributes as parameters.
## The thread_handler method is used to check for shutdown and if the exit flag is set to True, the thread exits.
## The thread_handler2 method is used to be implemented by subclasses and is not implemented in this class.
## The check_self_shutdown and try_exit methods are used to check for shutdown and t
class ExitedThread(threading.Thread):
    def __init__(self, arg, n):
        super(ExitedThread, self).__init__()
        self.exit = False
        self.arg = arg
        self.n = n

    def run(self):
        self.thread_handler(self.arg, self.n)

    def thread_handler(self, arg, n):
        while True:
            check_for_shutdown(self)
            if self.exit:
                break
            ctx.listfThreadRunning[n] = True
            try:
                self.thread_handler2(arg)
            except Exception as e:
                logg("ThreadHandler()")
                print(Fore.MAGENTA, '[', timer(), ']', Fore.WHITE, 'ThreadHandler()')
                logg(str(e))
                print(Fore.GREEN, str(e))
            ctx.listfThreadRunning[n] = False
            time.sleep(2)

    def thread_handler2(self, arg):
        raise NotImplementedError("must implement this function")

    def check_self_shutdown(self):
        check_for_shutdown(self)

    def try_exit(self):
        self.exit = True
        ctx.listfThreadRunning[self.n] = False

 ## This code is defining a function called bitcoin_miner which is used to start and restart the bitcoin miner.
 ## If the miner is restarted, it will log and print that it has been restarted and sleep for 5 seconds.
 ## It will then log and print that the miner has started. It then runs a loop which checks if the miner thread is still alive and if the subscribe thread is running.
 ## If either of these conditions are not true, the loop will break. Otherwise,
 ## it will set the miner thread to be running, call the mining method on the miner thread, and set the miner thread to be not running.
 ## If an exception occurs, it is logged and the traceback is printed, and the loop breaks.
# Initialize best difficulty outside the loop
best_difficulty = 0  # Add this line to initialize best_difficulty

def bitcoin_miner(t, restarted=False):
    global best_share_difficulty, best_share_hash
    start_time = time.time()  # Start time for performance metrics
    total_hashes = 0  # Initialize total_hashes
    if restarted:
        logg('\n[*] Bitcoin Miner restarted')
        print(Fore.MAGENTA, '[', timer(), ']', Fore.YELLOW, 'Solo Miner Active')
        print(Fore.MAGENTA, '[', timer(), ']', Fore.BLUE, '[*] Bitcoin Miner Restarted')

    # Initialize share_difficulty outside the loop
    share_difficulty = 0

    # Initialize difficulty outside the loop
    difficulty = 0

    # Initialize best difficulty
    best_difficulty = 0  # Add this line to initialize best_difficulty

    ## This code is used to create a target (difficulty) and extranonce2 value for a mining context (ctx).
    ## The target is created by taking the last 3 bits of the nbits field from the context and appending '00' to the end of it ctx.nbits[2:] times.
    ## The extranonce2 value is a random number between 0 and 2^32-1, which is converted to hex and padded with zeros to match the length of the ctx.extranonce2_size.
    target = (ctx.nbits[2:] + '00' * (int(ctx.nbits[:2], 16) - 3)).zfill(64)
    extranonce2 = hex(random.randint(0, 2**32 - 1))[2:].zfill(2 * ctx.extranonce2_size)
    print(Fore.YELLOW, '[*] Target:', Fore.GREEN, '[', target, ']')
    print(Fore.YELLOW, '[*] Extranonce2:', Fore.GREEN, '[', extranonce2, ']')

    ## This code is used to create a coinbase hash from the mining context (ctx) and the extranonce2 value generated in the previous code.
    ## The coinbase is created by combining the ctx.coinb1, ctx.extranonce1, extranonce2 and ctx.coinb2 fields.
    ## The coinbase hash is then generated by taking the SHA-256 hash of the coinbase t
    coinbase = ctx.coinb1 + ctx.extranonce1 + extranonce2 + ctx.coinb2
    coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest()
    print(Fore.YELLOW, '[*] Coinbase Hash:', Fore.GREEN, '[', coinbase, ']')

    ## This code is used to generate a Merkle root from the mining context (ctx) and the coinbase hash generated in the previous code.
    ## The Merkle root is generated by looping through the ctx.merkle_branch list and combining the merkle_root and the current branch element in each iteration.
    ## The combined values are then hashed twice with SHA-256 to generate the new merkle_root.
    merkle_root = coinbase_hash_bin
    for h in ctx.merkle_branch:
        merkle_root = hashlib.sha256(hashlib.sha256(merkle_root + binascii.unhexlify(h)).digest()).digest()

    ## This code is used to convert the binary Merkle root generated in the previous code to a hexadecimal string.
    ## The binary merkle_root is converted to a hexadecimal string using the binascii.hexlify() function,
    ## and then the result is decoded to a string using the decode() method.
    merkle_root = binascii.hexlify(merkle_root).decode()
    print(Fore.YELLOW, '[*] Merkle Root:', Fore.YELLOW, '[', merkle_root, ']')

    ## This code is used to format the Merkle root generated in the previous code. The string is split into two-character substrings,
    ## and the result is reversed using the [::-1] slice notation.
    ## The work_on variable is used to get the current block height,
    ## and the ctx.nHeightDiff dictionary is updated with the new block height and a value of 0.
    merkle_root = ''.join([merkle_root[i] + merkle_root[i + 1] for i in range(0, len(merkle_root), 2)][::-1])
    work_on = get_current_block_height()
    ctx.nHeightDiff[work_on + 1] = 0

    ## This code is used to calculate the difficulty for the current block.
    ## The difficulty is calculated by taking the hex string "00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
    ## and dividing it by the target value which is also in hex format. The result is the difficulty for the current block.
    ## Calculate the difficulty as you did in your original code
    _diff = int("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16)

    # Print and log the difficulty value
    print(Fore.YELLOW, '[*] Diff:', Fore.YELLOW, '[', int(_diff), ']')
    logg('[*] Working to solve block at block height {}'.format(work_on + 1))
    print(Fore.MAGENTA, '[', timer(), ']', Fore.YELLOW, '[*] Working to solve block at ', Fore.GREEN, 'height {}'.format(work_on + 1))
   

    # Improved difficulty calculation
    def calculate_difficulty(target, hash_hex):
        hash_int = int(hash_hex, 16)
        target_int = int(target, 16)
        return target_int / max(hash_int, 1)  # Avoid division by zero

    # Enhanced metrics logging
    def log_metrics(start_time, nonce, hashes_computed, best_difficulty, best_hash):
        elapsed_time = time.time() - start_time
        hash_rate = hashes_computed / max(elapsed_time, 1)  # Avoid division by zero
        print(f"Nonce: {nonce}, Hash Rate: {hash_rate:.2f} hashes/sec")
        print(f"Hash Rate: {hash_rate:.2f} hashes/sec")
        print(f"Best Difficulty: {best_difficulty:.2f}")
        print(f"Best Hash: {best_hash}")

        # Initialize a variable to keep track of the previous progress percentage
        prev_progress_percentage = None

        # Initialize total_hashes before entering the mining loop
        total_hashes = 0

        # Initialize hash_rate
        hash_rate = 0.0

    ## Modify bitcoin_miner function to include improved difficulty analysis and metrics logging
    ## This code is a while loop which checks if the thread should be shut down and if so, it breaks out of the loop.
    ## It then checks if a new block has been detected and if so, it logs and prints that a new block has been detected,
    ## logs and prints the difficulty of the block, restarts the bitcoin miner, and continues the loop.
    while True:
        t.check_self_shutdown()
        if t.exit:
            break

        if ctx.prevhash != ctx.updatedPrevHash:
            logg('[*] NEW BLOCK {} DETECTED ON NETWORK'.format(ctx.prevhash))
            print(Fore.YELLOW, '[', timer(), ']', Fore.MAGENTA, '[*] New block {} detected on', Fore.BLUE,
                  ' network '.format(ctx.prevhash))
            logg('[*] Best difficulty previous block {} was {}'.format(work_on + 1, ctx.nHeightDiff[work_on + 1]))
            print(Fore.MAGENTA, '[', timer(), ']', Fore.GREEN, '[*] Best Diff Trying Block', Fore.YELLOW, ' {} ',
                  Fore.BLUE, 'was {}'.format(work_on + 1, ctx.nHeightDiff[work_on + 1]))
            ctx.updatedPrevHash = ctx.prevhash
            bitcoin_miner(t, restarted=True)
            print(Back.YELLOW, Fore.MAGENTA, '[', timer(), ']', Fore.BLUE, 'NEW BLOCK DETECTED - RESTARTING MINER...',
                  Style.RESET_ALL)
            continue

            ## This code is used to generate a blockheader from the mining context (ctx), the Merkle root,
            ## a random nonce, and the hash of the blockheader. The blockheader is created by combining the
            ## ctx.version, ctx.prevhash, merkle_root, ctx.ntime, ctx.nbits, nonce and,
            ## '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'.
            ## The hash of the blockheader is then generated by taking the SHA-256 hash of the blockheader twice and getting the binary digest.
            ## The result is then converted to a hexadecimal string using the binascii.hexlify() function.

        nonce = hex(random.randint(0, 2**32 - 1))[2:].zfill(8)
        blockheader = ctx.version + ctx.prevhash + merkle_root + ctx.ntime + ctx.nbits + nonce + '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'
        hash = hashlib.sha256(hashlib.sha256(binascii.unhexlify(blockheader)).digest()).digest()
        hash = binascii.hexlify(hash).decode()

        ctx.total_hashes_computed += 1  # Increment total hash count
        #print(Fore.YELLOW + '[*] Nonce: ' + Fore.GREEN + str(nonce), end="\r")

        # Define the target difficulty as a hexadecimal string.
        # The target difficulty represents the level of complexity required for a block to be considered valid.
        # It consists of leading zeros followed by a sequence of 'F' characters.
        # In hexadecimal format, it is represented as '0000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'.
        target_difficulty = '0000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'

        # Calculate the hash value of the current block as an integer.
        # The 'hash' variable contains the hash value of the block in hexadecimal format.
        # Converting it to an integer is useful for comparing it to the target difficulty.
        this_hash = int(hash, 16)

        # Check if the current hash meets or exceeds the target difficulty
        if this_hash <= int(target_difficulty, 16):
            logg(f'[*] New hash: {hash} for block {work_on + 1}')
            print(Fore.MAGENTA, '[', timer(), ']', Fore.GREEN, f'[*] New hash: {hash} for block', Fore.YELLOW, work_on + 1)
            print(Fore.MAGENTA, '[', timer(), ']', Fore.YELLOW, 'Hash:', hash.format(work_on + 1))

            ## This code is used to check if the difficulty of the current block is greater than the difficulty of the previous block.
            ## The difficulty of the current block is calculated by dividing the predetermined difficulty value _diff by the hash of the blockheader this_hash.
            ## If the current difficulty is greater than the previous difficulty stored in the ctx.nHeightDiff dictionary,
            ## the new difficulty is set as the value for the current block.

        # Calculate the difficulty for the current block.
        difficulty = _diff / this_hash

        # Check if this is the best difficulty so far
        if difficulty > best_difficulty:
            best_difficulty = difficulty
            best_hash = hash
            logg(f'[BEST HASH UPDATE] New best hash: {best_hash} with difficulty: {best_difficulty}')
            print(f'[BEST HASH UPDATE] New best hash: {best_hash} with difficulty: {best_difficulty}')

        # Update the difficulty for the current block in the context
        if ctx.nHeightDiff[work_on + 1] < difficulty:
            ctx.nHeightDiff[work_on + 1] = difficulty

        # Increment the total number of hashes computed
        total_hashes += 1
       
        # Calculate elapsed time
        elapsed_time = time.time() - start_time
       
        # Calculate hash rate
        hash_rate = total_hashes / elapsed_time
       
        # Display total hashes and hash rate on the same line with carriage return
        print(f"\rTotal Hashes: {total_hashes} | Hash Rate: {hash_rate:.2f} H/s", end='')

            ## This code is used to check if the hash of the blockheader is less than the target value.
            ## If the hash is less than the target, it means the block has been successfully solved and the ctx.solved flag is set to True.

        if hash < target:
            logg('[*] Share found for block {}.'.format(work_on + 1))
            print(Fore.MAGENTA, '[', timer(), ']', Fore.YELLOW, '[*] Share found for block {}.'.format(work_on + 1))
            print(Fore.MAGENTA, '[', timer(), ']', Fore.YELLOW, 'Share:', hash.format(work_on + 1))
            logg('[*] Block hash: {}'.format(hash))
            print(Fore.YELLOW)
            print(Fore.MAGENTA, '[', timer(), ']', Fore.YELLOW, '[*] Block hash: {}'.format(hash))
            logg('[*] Blockheader: {}'.format(blockheader))
            print(Fore.BLUE, '--------------~~( ', Fore.GREEN, 'BLOCK SOLVED CHECK WALLET!', Fore.ORANGE, ' )~~--------------')
            print(Fore.YELLOW, '[*] Blockheader: {}'.format(blockheader))

            # Print nonce value when a new share is found
            logg('[*] Nonce Value: {}'.format(nonce))
            print(Fore.YELLOW, '[*] Nonce Value: {}'.format(nonce))

            payload = bytes('{"params": ["' + address + '", "' + ctx.job_id + '", "' + ctx.extranonce2 + '", "' + ctx.ntime + '", "' + nonce + '"], "id": 1, "method": "mining.submit"}\n', 'utf-8')
            logg('[*] Payload: {}'.format(payload))
            print(Fore.MAGENTA, '[', timer(), ']', Fore.BLUE, '[*] Payload:', Fore.GREEN, ' {}'.format(payload))
            sock.sendall(payload)
            ret = sock.recv(1024)
            logg('[*] Pool response: {}'.format(ret))
            print(Fore.MAGENTA, '[', timer(), ']', Fore.GREEN, '[*] Pool Response:', Fore.CYAN, ' {}'.format(ret))
            print(payload)
            return True

        if difficulty >= 16:
            # Construct JSON-RPC request for share submission
            share_payload = {
                "params": [address, ctx.job_id, ctx.extranonce2, ctx.ntime, nonce],
                "id": 1,
                "method": "mining.submit"
            }
           
            # Send the share payload to the pool's mining.submit endpoint
            share_payload = json.dumps(share_payload) + '\n'
            sock.sendall(share_payload.encode())
           
            # Receive and handle the pool's response
            response = sock.recv(1024).decode()
           
            # Log and print the response for monitoring purposes
            logg('[*] Pool response for share submission: {}'.format(response))
            print(Fore.MAGENTA, '[', timer(), ']', Fore.GREEN, '[*] Pool Response for share submission:', Fore.CYAN, ' {}'.format(response))

            # Calculate the difficulty for the current share
            share_difficulty = _diff / this_hash

        # Check if this share is better than the best share
        if share_difficulty < best_share_difficulty:
            best_share_difficulty = share_difficulty
            best_share_hash = hash
            logg(f'[BEST SHARE UPDATE] New best share hash: {best_share_hash} with difficulty: {best_share_difficulty}')
            print(f'[BEST SHARE UPDATE] New best share hash: {best_share_hash} with difficulty: {best_share_difficulty}')

        # Update the difficulty for the current block in the context
        if ctx.nHeightDiff[work_on + 1] < share_difficulty:
            ctx.nHeightDiff[work_on + 1] = share_difficulty


            # Calculate elapsed time
            elapsed_time = time.time() - start_time

            # Calculate hash rate
            hash_rate = total_hashes / elapsed_time

            # Display total hashes, hash rate, and best share on the same line with carriage return
            print(f"\rTotal Hashes: {total_hashes} | Hash Rate: {hash_rate:.2f} H/s | Best Share: {best_share_hash} (Difficulty: {best_share_difficulty:.2f})", end='')

         ## This code is used to set up a connection to the ckpool server and send a handle subscribe message.
         ## The response is parsed to get the ctx.sub_details, ctx.extranonce1 and ctx.extranonce2_size fields.
         ## Then an authorize message is sent with the address and password, and the response is read until the mining.notify message is received.

def block_listener(t) :
    # init a connection to ckpool
    sock = socket.socket(socket.AF_INET , socket.SOCK_STREAM)
    sock.connect(('solo.ckpool.org' , 3333))
    # send a handle subscribe message
    sock.sendall(b'{"id": 1, "method": "mining.subscribe", "params": []}\n')
    lines = sock.recv(1024).decode().split('\n')
    response = json.loads(lines[0])
    ctx.sub_details , ctx.extranonce1 , ctx.extranonce2_size = response['result']
    # send and handle authorize message
    sock.sendall(b'{"params": ["' + address.encode() + b'", "x"], "id": 2, "method": "mining.authorize"}\n')
    response = b''
    while response.count(b'\n') < 4 and not (b'mining.notify' in response) : response += sock.recv(1024)
    print(response)

    ## This code is used to parse the response from the ckpool server and get the necessary fields for the mining context (ctx).
    ## The response is split into individual lines and only lines that contain the 'mining.notify' string are parsed.
    ## The parsed results are then stored in the,
    ## ctx.job_id, ctx.prevhash, ctx.coinb1, ctx.coinb2, ctx.merkle_branch, ctx.version, ctx.nbits, ctx.ntime and ctx.clean_jobs fields.

    responses = [json.loads(res) for res in response.decode().split('\n') if
                 len(res.strip()) > 0 and 'mining.notify' in res]
    ctx.job_id , ctx.prevhash , ctx.coinb1 , ctx.coinb2 , ctx.merkle_branch , ctx.version , ctx.nbits , ctx.ntime , ctx.clean_jobs = \
        responses[0]['params']

    ## Do this one time, will be overwriten by mining loop when new block is detected

    ctx.updatedPrevHash = ctx.prevhash

    while True :
        t.check_self_shutdown()
        if t.exit :
            break

        ## This code is used to check if the previous hash in the response from the ckpool server is different from the previous hash,
        ## in the mining context (ctx). If the hashes are different, the response is parsed to get the necessary fields
        ## for the mining context and the fields are updated with the new values.

        response = b''
        while response.count(b'\n') < 4 and not (b'mining.notify' in response) : response += sock.recv(1024)
        responses = [json.loads(res) for res in response.decode().split('\n') if
                     len(res.strip()) > 0 and 'mining.notify' in res]

        if responses[0]['params'][1] != ctx.prevhash :

            ## New block detected on network
            ## update context job data

            # Update mining context with new work
            ctx.job_id, ctx.prevhash, ctx.coinb1, ctx.coinb2, ctx.merkle_branch, ctx.version, ctx.nbits, ctx.ntime, ctx.clean_jobs = responses[0]['params']

            # Call the splash screen function here
            show_loading_splash()

            # Log the new mining context
            logger.info(f"New Work Received from Pool:\n"
                         f"Job ID: {ctx.job_id}\n"
                         f"Previous Block Hash: {ctx.prevhash}\n"
                         f"Coinbase 1: {ctx.coinb1}\n"
                         f"Coinbase 2: {ctx.coinb2}\n"
                         f"Merkle Branch: {ctx.merkle_branch}\n"
                         f"Version: {ctx.version}\n"
                         f"nBits: {ctx.nbits}\n"
                         f"nTime: {ctx.ntime}\n"
                         f"Clean Jobs: {ctx.clean_jobs}")

    ## This code is defining a custom thread class called CoinMinerThread which is a subclass of ExitedThread.
    ## The class has two methods, __init__ and thread_handler2. The __init__ method is used to initialize the class and set the n attribute to 0.
    ## The thread_handler2 method calls the thread_bitcoin_miner method with the arg parameter. The thread_bitcoin_miner method is used to check for shutdown,
    ## and then calls the bitcoin_miner function with the current thread object as the parameter. The result of the bitcoin_miner function is logged to the console.

class CoinMinerThread(ExitedThread) :
    def __init__(self , arg = None) :
        super(CoinMinerThread , self).__init__(arg , n = 0)

    def thread_handler2(self , arg) :
        self.thread_bitcoin_miner(arg)

    def thread_bitcoin_miner(self , arg) :
        ctx.listfThreadRunning[self.n] = True
        check_for_shutdown(self)
        try :
            ret = bitcoin_miner(self)
            logg(Fore.MAGENTA , "[" , timer() , "] [*] Miner returned %s\n\n" % "true" if ret else "false")
            print(Fore.LIGHTCYAN_EX , "[*] Miner returned %s\n\n" % "true" if ret else "false")
        except Exception as e :
            logg("[*] Miner()")
            print(Back.WHITE , Fore.MAGENTA , "[" , timer() , "]" , Fore.BLUE , "[*] Miner()")
            logg(e)
            traceback.print_exc()
        ctx.listfThreadRunning[self.n] = False

    pass

    ## This code is defining a new class called NewSubscribeThread which is a subclass of ExitedThread. It has two methods,
    ## __init__ and thread_handler2. The __init__ method sets up the thread with the specified argument and sets the number of threads to 1.
    ## The thread_handler2 method calls the thread_new_block method with the specified argument.
    ## The thread_new_block method sets the thread to be running, checks for shutdown, and then calls the block_listener function. If an exception occurs,
    ## it is logged and the traceback is printed. Finally, the thread is set to be not running.

class NewSubscribeThread(ExitedThread) :
    def __init__(self , arg = None) :
        super(NewSubscribeThread , self).__init__(arg , n = 1)

    def thread_handler2(self , arg) :
        self.thread_new_block(arg)

    def thread_new_block(self , arg) :
        ctx.listfThreadRunning[self.n] = True
        check_for_shutdown(self)
        try :
            ret = block_listener(self)
        except Exception as e :
            logg("[*] Subscribe thread()")
            print(Fore.MAGENTA , "[" , timer() , "]" , Fore.YELLOW , "[*] Subscribe thread()")
            logg(e)
            traceback.print_exc()
        ctx.listfThreadRunning[self.n] = False

    pass

## This code is defining a function called StartMining which creates a thread for subscribing and one for mining.
## It first creates a new thread called subscribe_t which uses the NewSubscribeThread class.
## It then starts the thread and logs that the subscribe thread has been started.
## It then sleeps for 4 seconds and creates a new thread called miner_t which uses the CoinMinerThread class.
## It then starts the thread and logs that the Bitcoin solo miner has been started.

def StartMining() :
    subscribe_t = NewSubscribeThread(None)
    subscribe_t.start()
    logg("[*] Subscribe thread started.")
    print(Fore.MAGENTA , "[" , timer() , "]" , Fore.GREEN , "[*] Subscribe thread started.")

    time.sleep(1)

    miner_t = CoinMinerThread(None)
    miner_t.start()
    logg("[*]£££ Bitcoin Solo Miner Started £££")
    print(Fore.MAGENTA , "[" , timer() , '(', Fore.GREEN  , 'SOLO MINER STARTED' , Fore.BLUE , ' )~~--------------')
    print(Fore.BLUE , '--------------~~( ' , Fore.YELLOW , 'IN SATOSHI WE TRUST' , Fore.BLUE , ' )~~--------------')
    print(Fore.BLUE , '--------------~~( ' , Fore.GREEN  , 'DO NOT TRUST VERIFY' , Fore.BLUE , ' )~~--------------')


if __name__ == '__main__':
    # Initialize performance metrics in context
    ctx.total_hashes_computed = 0
    ctx.mining_time_per_block = []

    signal(SIGINT, handler)
    StartMining()




Updated Context.py

Code:
# context.py for CPU-based Bitcoin Mining

# Flag to indicate if the mining process should be shut down
fShutdown = False

# List to keep track of the running state of threads (e.g., mining, listening)
listfThreadRunning = [False] * 6

# Current height of the local blockchain copy
local_height = 0

# Dictionary to store the best difficulty achieved for each height
nHeightDiff = {}

# Hash of the previous block (to detect new blocks in the network)
updatedPrevHash = None

# Mining-related parameters (updated with each new block or job)
job_id = None
prevhash = None
coinb1 = None
coinb2 = None
merkle_branch = None
version = None
nbits = None
ntime = None
clean_jobs = None
sub_details = None
extranonce1 = None
extranonce2_size = None

# Performance Metrics for CPU Mining
total_hashes_computed = 0  # Total number of hashes computed
hash_rate = 0              # Hash rate (hashes per second)
mining_time_per_block = [] # Time taken to mine each block
resource_utilization = {   # Resource utilization (CPU, memory)
    'cpu_usage': 0,
    'memory_usage': 0
}

# Network Statistics
network_difficulty = None  # Current network difficulty
average_block_time = None  # Average time for block discovery in the network

# Error Handling and Logging
error_count = 0            # Number of errors encountered
last_error_message = ""    # Last error message for debugging

# Adaptive Mining Configuration
adaptive_difficulty = True  # Flag to enable adaptive difficulty
reconnection_attempts = 0    # Number of attempts to reconnect to the pool

# Blockchain Data
last_block_hashes = []     # Store hashes of the last N blocks

# User Customization
user_preferences = {
    'logging_level': 'info',
    'ui_settings': {}
}



Miner.log

Code:
2023-12-21 10:17:35,805 [*] Subscribe thread started.
2023-12-21 10:17:36,807 [*]£££ Bitcoin Solo Miner Started £££
2023-12-21 10:17:37,376 [*] Working to solve block at block height 822222
2023-12-21 10:17:37,376 [BEST HASH UPDATE] New best hash: ccd3e0d1874c7495b166e2153fea0c019c647c12a6aee6cd4d5246f10c31cdf2 with difficulty: 2.9099901798400617e-10
2023-12-21 10:17:37,376 [BEST SHARE UPDATE] New best share hash: ccd3e0d1874c7495b166e2153fea0c019c647c12a6aee6cd4d5246f10c31cdf2 with difficulty: 0
2023-12-21 10:17:37,376 [BEST HASH UPDATE] New best hash: 53468a173e208a2422ea0e0dd63366117236b8caf4a00a4c3c38a3901df7f946 with difficulty: 7.157520861969146e-10
2023-12-21 10:17:37,376 [BEST HASH UPDATE] New best hash: 1ea56d0f3087b9a7997950cedbdc27523860181de956c64b24121f928c6d29a9 with difficulty: 1.94492804306208e-09
2023-12-21 10:17:37,377 [BEST HASH UPDATE] New best hash: 1a3341863ced131675314867621be86a7cbe9df660a5a2306747666b62a986be with difficulty: 2.2749674629798407e-09
2023-12-21 10:17:37,378 [BEST HASH UPDATE] New best hash: 186162795ac73905af2ea6e135696fdef6a7342544d5de81f5039fe678e75666 with difficulty: 2.4447762609415232e-09
2023-12-21 10:17:37,379 [BEST HASH UPDATE] New best hash: 1696c3988e897a3abd9f1253c4f4e2c84e3faeef755f51e0a17be2ab632dd73f with difficulty: 2.6386670698624605e-09
2023-12-21 10:17:37,379 [BEST HASH UPDATE] New best hash: 04499e0f5cd9f69620eb414b938e21b08266e897ebdb5259e23fa58c4909682b with difficulty: 1.3901737306484555e-08
2023-12-21 10:17:37,380 [BEST HASH UPDATE] New best hash: 004887f35ee30a2b1fe3454a2c9f0afc9773cbba5a2f008a43b928b2c0f3e3d4 with difficulty: 2.103759359413156e-07
2023-12-21 10:17:37,385 [BEST HASH UPDATE] New best hash: 0012173bb6966922e05a882c633db5f4e526e78ceef3f43e31f641c580bf9867 with difficulty: 8.43457840509098e-07
2023-12-21 10:17:37,786 [BEST HASH UPDATE] New best hash: 0000e6ea6543f305f5a2e7024bad21835b75adb070549ca29eb994a780e3643d with difficulty: 1.6916353290772178e-05
2023-12-21 10:17:40,082 [BEST HASH UPDATE] New best hash: 000023fd2a1af6e9327675eb9c580108f1e47ad3bd8827aede257d7f2f1f8985 with difficulty: 0.00010854033951395945
2023-12-21 10:17:47,226 [BEST HASH UPDATE] New best hash: 000003fd492be5222be82c58273d91a868bc9155dc84e3dba69e974aae0edad2 with difficulty: 0.0009791578170452227
2023-12-21 10:18:10,802 [BEST HASH UPDATE] New best hash: 000001ff682e93460a6a6c41ae9aa4b0ce5b05530ce2244a66556fef534a8127 with difficulty: 0.0019553898888381794
2023-12-21 10:20:34,773 [BEST HASH UPDATE] New best hash: 000000cc1d71b6278b94af1e5996c4724060c38f7166e0f0bfe49e1bdded5833 with difficulty: 0.004899198588521477
2023-12-21 10:23:00,681 [BEST HASH UPDATE] New best hash: 000000a7880b9c07990c3e495da47c779d4b0841432f82551c4f0db0ac7ad44f with difficulty: 0.005969029316057255
2023-12-21 10:23:02,474 [BEST HASH UPDATE] New best hash: 000000a47471f18dd68f8058aad44049d451661a10511f051f9e71773db8569f with difficulty: 0.006080695808325444
2023-12-21 10:25:07,961 New Work Received from Pool:
Job ID: 648516380008eef1
Previous Block Hash: 349904fddbc9beb9533181e7f1557f9c492edfcd0001f2300000000000000000
Coinbase 1: 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3503cf8b0c000483128465044ea5612b0c
Coinbase 2: 0a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff036484f52d000000001976a9140b77264c27eddef8af2a19ff48b9a7d2c49bdfb988acd31cf0000000000016001451ed61d2f6aa260cc72cdf743e4e436a82c010270000000000000000266a24aa21a9ed344146b7a2d62b4a5df5870ed5e40f976b9f66cbb334196f03d93499bc5a976200000000
Merkle Branch: ['29685f9dbc68e260ce3f2ecd3c5a475bf0f6dd03f0092640e0275abd597136f5', '994aad30200ec30f2c9a5cad9674bebb1e3e1e7371728975477b85e36f85ebf4', '08a7b6b31e54481aed30a24b507d48456c977b6ce8bdc2d6fd84dc2c3e6b8b3a', 'cebc8342f6e2c6972eed7962b80911881a5751b0a72307eef32bf02a85a30c02', '6a6bea0ce88850e497f539cbfef27e1cc32b3c5ab72436e7f49ca8bea376246c', '94dce5025c14bea311c7291d38b8dd174c7b21c727b9926c22aa472499047cb9', 'a0180477d1012732b64c747c5a8b266dd0089304c5331d07c2602ef70eb4932c', '293bf744548703b244e18b602cdb2f16b083e5e2ef360d04a1aaff6e14d4fe62', 'af530079a227bddf781270635d79effc935ba65c8bfdfe95b68b583019665dba', '74f5ce6a590a0f5de08213b682bdeb4d826bc70168e55b010f7795a5ff865b78', '35bf2a71d14a859ddb5ddfda4ea605821e5e4a178335970bb344e7a41b37478d', '21ebbc181cc0ec37c168baa53d3ae56cb26a9314a3e9e45e9542ec6a2cabbbde', '7147ad630bd346e772d36c9fa5da04a84f1598d1d5eceea198d45d76e26fbfb5']
Version: 20000000
nBits: 17042e95
nTime: 65841283
Clean Jobs: True
2023-12-21 10:25:07,961 [*] NEW BLOCK 349904fddbc9beb9533181e7f1557f9c492edfcd0001f2300000000000000000 DETECTED ON NETWORK
2023-12-21 10:25:07,962 [*] Best difficulty previous block 822222 was 0.006080695808325444
2023-12-21 10:25:07,962
[*] Bitcoin Miner restarted
2023-12-21 10:25:08,253 [*] Working to solve block at block height 822222
2023-12-21 10:25:08,253 [BEST HASH UPDATE] New best hash: 65b7852f1820f57e9de9580f676fc616fc4ea4051335f239d5b9b26bd4c70df8 with difficulty: 5.859857983592134e-10
2023-12-21 10:25:08,254 [BEST HASH UPDATE] New best hash: 03836ccde2e03ef60b2af15ad88937402feeb623d340f7726ee6db5802acdfd8 with difficulty: 1.696504853802239e-08
2023-12-21 10:25:08,254 [BEST HASH UPDATE] New best hash: 02b9299b642a8ef7f982504cdd69eb08166dd71ef6ce73d7c31109d3748a0a05 with difficulty: 2.1886989710820586e-08
2023-12-21 10:25:08,258 [BEST HASH UPDATE] New best hash: 00912f545396efc81ccc13591df2d29c3044f942fea0e45bbac4ca660460089e with difficulty: 1.050990227979622e-07
2023-12-21 10:25:08,262 [BEST HASH UPDATE] New best hash: 0075b0bdde7dacee6abdf2249b25180155d7ccbcbc0a6d13f4fed7362d0d2097 with difficulty: 1.296519463700919e-07
2023-12-21 10:25:08,305 [BEST HASH UPDATE] New best hash: 00429b2c987fe6617d300bad4806617e9be1571de129a1817b33e78110e0cdac with difficulty: 2.2908979485712655e-07
2023-12-21 10:25:08,419 [BEST HASH UPDATE] New best hash: 00198de895e30d36f14a7f43d0ae99c6590dce4a6638f0b37512f51ae1485332 with difficulty: 5.97111680460128e-07
2023-12-21 10:25:08,496 [BEST HASH UPDATE] New best hash: 00174f3ba93e32dceeaa4931dfc95864ea83c5ea447123032a30c03ff9cb2ef1 with difficulty: 6.54616631609394e-07
2023-12-21 10:25:08,787 [BEST HASH UPDATE] New best hash: 0002673e3f2cc8a66c5ca689001bce556320374cac544211d019575485e05a45 with difficulty: 6.349115777473579e-06
2023-12-21 10:25:09,486 [BEST HASH UPDATE] New best hash: 000253a7f8a8e8da57de0d044090f5d3e25ec88e39a4956969694fe2985697c8 with difficulty: 6.557894313206096e-06
2023-12-21 10:25:11,273 [BEST HASH UPDATE] New best hash: 0002032bd0178b8644c2a21a812eb2dd8c9b2f0a4f8fb40d851a546bdc098e95 with difficulty: 7.582431674667211e-06
2023-12-21 10:25:11,919 [BEST HASH UPDATE] New best hash: 00013a79c0d4a9d9278b36d651082d677e221b522696bf23ec79a58146dcff5a with difficulty: 1.2421472499697014e-05
2023-12-21 10:25:12,321 [BEST HASH UPDATE] New best hash: 000126a69eea12dfb7b1d9a264f6eeb0dad743428db7851acbf0332d5a0e92fa with difficulty: 1.3257215570220232e-05
2023-12-21 10:25:13,129 [BEST HASH UPDATE] New best hash: 0000ba75a6496a9796d31070c709037f65a5709f53d0d431c69e38f2684b2e1f with difficulty: 2.09495818833267e-05
2023-12-21 10:25:13,828 [BEST HASH UPDATE] New best hash: 00002f993735b5260416de75f88d3c863260e7c72d7059f8fa13f20d973263d7 with difficulty: 8.206666403245318e-05
2023-12-21 10:25:23,237 [BEST HASH UPDATE] New best hash: 00001b4d60229cc775f6f792dcaa449491150eb07614c292d70f10ad6d1816f7 with difficulty: 0.000143074298408116
2023-12-21 10:25:23,262 [BEST HASH UPDATE] New best hash: 0000167282564bbf3dd7adfc75f623c02761c7321be3025f3daec663cef95da0 with difficulty: 0.00017401869160989323
2023-12-21 10:25:24,103 [BEST HASH UPDATE] New best hash: 000010363c42f22998d1921e366a32b8c74b7cfa709ad5a22cc249c9cb24be3d with difficulty: 0.00024095018823267985
2023-12-21 10:26:23,708 [BEST HASH UPDATE] New best hash: 00000befd54d1b5be2678fa2f704e254dab315e62f5c86fff0bbff283d1482bf with difficulty: 0.00032724299135340827
2023-12-21 10:26:56,460 [BEST HASH UPDATE] New best hash: 0000074b6a16f7c1a3c8729f966de2a09cbe72c53446aebd21f37315c276decb with difficulty: 0.0005354997760858537
2023-12-21 10:28:11,052 [BEST HASH UPDATE] New best hash: 0000014096e5696620809f5dbd91632c3415131f10b2263ae8f2e6d44ae45088 with difficulty: 0.0031192543525396937
2023-12-21 10:29:32,311 [BEST HASH UPDATE] New best hash: 000000f49686383002a9a996c54842d808646e9e44b49d02a69aa5cfae484ea3 with difficulty: 0.00408850826358574
2023-12-21 10:33:39,352 New Work Received from Pool:
Job ID: 648516380008ef03
Previous Block Hash: 21fd050571c9066b3bea88bdb6825b8ae683b46f0003a8090000000000000000
Coinbase 1: 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3503d08b0c00048314846504bf9ab2080c
Coinbase 2: 0a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff034248eb2d000000001976a9140b77264c27eddef8af2a19ff48b9a7d2c49bdfb988ac5ae7ef000000000016001451ed61d2f6aa260cc72cdf743e4e436a82c010270000000000000000266a24aa21a9ed038ae70f65d0ab8e246e1fd245dd8a7ea9bf2c9a0075ab1d39206ea2970d4ce400000000
Merkle Branch: ['dc05a3c00350579e42a5ff0ad85a46535341f7b1befbd82709a76946e99a58b4', '152e3c58a1c26ba59f4622b81f19979b88cbfd86f788b172c324209693a5ec90', '6dc5a658413f2d81e398b413353048f900f67a4aea90580a0b301bfe9e0b171e', '83872cf872862a52993cb18736950ab9e2389a4dac74610387a3c001ae412ae4', '213d0d6965adf3f4ac6b1a3455ca8f064bf9fd1d4bcda0c3cddf1a2993de783f', '948524b6c6ee31c1847b0dceb5e96ee7a25c5d707f25df142ef73c0e56969647', '0085f79f7178bf1c7da298762c45b8c07d908ec2de7356eba9b71a3112544ac4', '478b8021ba8ac018f387f22627a43156a976d00006db0a27e200fef33187c5b3', 'd7f43c4e5ab49c986a041ca1b2da682ee5176e5921a6b7be367dc53ee7191d18', '8afc080a03289ebd3f4287cb6825143b4e66f56c723decacceabee58685d3c64', 'cd9b0fd9ebeccee58e77d6a1a26b5065640608ef8bf4978f1ee32536cca5b017', '9037dd761acec84255a6d48411b3dc89fe09f65b00a01de20678b0438e3db4e9', '93b10cd3648cceae4e438e0999c89cbee3264531987bd0e2b93b5fe2f7fea592']
Version: 20000000
nBits: 17042e95
nTime: 65841483
Clean Jobs: True
2023-12-21 10:33:39,352 [*] NEW BLOCK 21fd050571c9066b3bea88bdb6825b8ae683b46f0003a8090000000000000000 DETECTED ON NETWORK
2023-12-21 10:33:39,352 [*] Best difficulty previous block 822222 was 0.00408850826358574
2023-12-21 10:33:39,352
[*] Bitcoin Miner restarted
2023-12-21 10:33:39,690 [*] Working to solve block at block height 822223
2023-12-21 10:33:39,690 [BEST HASH UPDATE] New best hash: 1332c13b1f544d2e855953ac624b899892e6965a096d66a33e9ccce76e6754cb with difficulty: 3.104689787670445e-09
2023-12-21 10:33:39,690 [BEST HASH UPDATE] New best hash: 111d982311d22247395cb9c99c9c9951ee169a05118c3dc1fb8669987e8172a1 with difficulty: 3.48247420221444e-09
2023-12-21 10:33:39,690 [BEST HASH UPDATE] New best hash: 0fe768f65218126e9ce5528e520ab1c17252e97f39f534c366e6b4ef2dfe2a76 with difficulty: 3.747789839499474e-09
2023-12-21 10:33:39,692 [BEST HASH UPDATE] New best hash: 08fa4e40beb1071da653b25d581ab12be9f6df248fc4b5ea3bec430bf7b1af58 with difficulty: 6.639146927074643e-09
2023-12-21 10:33:39,693 [BEST HASH UPDATE] New best hash: 085ceffc324522762e1726e0c698b2ccf4edf9bea46faa46c5dfc8a303abdca0 with difficulty: 7.127153163579793e-09
2023-12-21 10:33:39,696 [BEST HASH UPDATE] New best hash: 0351a69270adbaeb8b6dc9793a92189df1e826aaff3d8afeea746982ef2ed4a8 with difficulty: 1.795889718605585e-08
2023-12-21 10:33:39,697 [BEST HASH UPDATE] New best hash: 003f5ffd898682b56d21462862a5cbf7c318cb1f7d3639671e31d5544208a5db with difficulty: 2.4076998990842845e-07
2023-12-21 10:33:39,708 [BEST HASH UPDATE] New best hash: 0032549a87552a013f6b2bc3c1d3df3b2b5cd3a9b70fca1fed280a53dd559c2b with difficulty: 3.031719184328591e-07
2023-12-21 10:33:39,987 [BEST HASH UPDATE] New best hash: 00075dc73632d355460ff55f5a2fb9f31dea6b3753807391ed2c44992a83fc6b with difficulty: 2.071426035458905e-06
2023-12-21 10:33:40,154 [BEST HASH UPDATE] New best hash: 00014e5fc33d0b19b559cd582b20626e0065e5e824b3f2020166746fc260489e with difficulty: 1.1682275383011119e-05
2023-12-21 10:33:41,156 [BEST HASH UPDATE] New best hash: 00009d425e0748c4a3e17b3d2810a87325979afdf5d4b94d27f4c187575655e0 with difficulty: 2.4839556770439673e-05
2023-12-21 10:33:42,135 [BEST HASH UPDATE] New best hash: 0000495886b356e94e54267661bc074cb406e9e51c383daff631fdac73e05f9d with difficulty: 5.325798769873194e-05
2023-12-21 10:33:55,704 [BEST HASH UPDATE] New best hash: 00000d55f6e8a92ca9feb74671ada5247de400573c2781d057671de31e792bcf with difficulty: 0.0002929145876078991
2023-12-21 10:34:18,731 [BEST HASH UPDATE] New best hash: 00000930bcd78120bd123b51870fc5edad1e0c4ce9b51bb21af66be3596ed4ae with difficulty: 0.00042503676273960883

┏━━━━━━━━━━━━━━━━━┓
┃     𝔱𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔬𝔯ⱪ 𝔣𝔬𝔯 𝔶𝔬𝔲𝔯 𝔟𝔞𝔤𝔰       ┃
┃                ➤21/M                      ┃
┃ ███▓▓  ███▓▓  ███▓▓  ███▓▓┃
digaran
Copper Member
Hero Member
*****
Offline Offline

Activity: 1330
Merit: 900

🖤😏


View Profile
December 22, 2023, 01:30:49 AM
Merited by DaCryptoRaccoon (1)
 #8

Hey *magi... I mean DaCryptoRaccoon, is there a way to run this on smart phone? I would like to try it out. 😄

*= 😉

🖤😏
DaCryptoRaccoon (OP)
Hero Member
*****
Offline Offline

Activity: 1241
Merit: 623


OGRaccoon


View Profile
December 22, 2023, 03:45:08 AM
 #9

Hey *magi... I mean DaCryptoRaccoon, is there a way to run this on smart phone? I would like to try it out. 😄

*= 😉

Probably in nethunter with termux but not advised.  Cheesy usual warnings apply.  Smiley... Will burn out not worth it ect ect all the usual stuff.

I'm seeing on average with 2 cores on VM around 60k hashes p/s if you try it on a mobile device would be interested to know what your miner.log looks like.

It's interesting to see how quickly you can run up to 5 of 6 leading zeros but after 6 the time to find a hash with more than 7 really takes some time.

approximately 4 minutes and 24 seconds the difficulty increased from 9.96572131917006e-07 to 0.0017594876221516073, a significant jump showing the mining software's progression towards finding a valid block hash.

The final hash (0000023858e72f1bf2f6fd953f87dfeb6a6b393915260baeda0e19bc79afbd49)

Best hash found to date :

2023-12-21 12:42:47,904 [BEST HASH UPDATE] New best hash: 000000085bb2f248a7bf29e8908a8246dc557b4e158733958680959d88f332a8 with difficulty:

Code:
2023-12-22 03:25:04,440 [BEST HASH UPDATE] New best hash: 1db444db8f550c15191018e34220957301a2ab5fc4560eb48de0e630ddd4cf64 with difficulty: 2.0066082765125252e-09
2023-12-22 03:25:04,440 [BEST HASH UPDATE] New best hash: 1ab47481a55bd53da5b501458965d1e3b80d5329700adaf83b8a617e301ad413 with difficulty: 2.231973856636394e-09
2023-12-22 03:25:04,441 [BEST HASH UPDATE] New best hash: 0d3d42c600a94948ddf7cc4bb8b99c6374a55bc5cc67b2a1e545071c4b512a90 with difficulty: 4.5020993694025145e-09
2023-12-22 03:25:04,442 [BEST HASH UPDATE] New best hash: 02daed391238cf1fc9741de175cc1b61f52ff7029d96644e4c3c829799c5a294 with difficulty: 2.0875951121675577e-08
2023-12-22 03:25:04,442 [BEST HASH UPDATE] New best hash: 01d42658076f388fdab1bf8af59b8275ba7ea774ba0c800a8047d85de2691698 with difficulty: 3.259381866876962e-08
2023-12-22 03:25:04,443 [BEST HASH UPDATE] New best hash: 013f2182eb30ae674d4e2dd5d6c0090dc75f667219a34ab5fed0e92358a0d975 with difficulty: 4.781357391434335e-08
2023-12-22 03:25:04,444 [BEST HASH UPDATE] New best hash: 007c9877ff44e42d3b68f41f4b9ed2c77ca5b31a7e0305bc183b7ec80608d387 with difficulty: 1.224665348375222e-07
2023-12-22 03:25:04,456 [BEST HASH UPDATE] New best hash: 005eaf421eb8ee5161a054e9a4638e37aa09049e11a111513f1e14419f07d981 with difficulty: 1.6115385853269968e-07
2023-12-22 03:25:04,474 [BEST HASH UPDATE] New best hash: 00396b012b6ba612fa40a331b2d53ba9ee54d6dc4d321105818ed7b67f2402ff with difficulty: 2.657492881043723e-07
2023-12-22 03:25:04,476 [BEST HASH UPDATE] New best hash: 000f4fafa8a5c6a70b4e25e67e3889676e878f1732621eafac7faaca0a9a2800 with difficulty: 9.96572131917006e-07
2023-12-22 03:25:04,494 [BEST HASH UPDATE] New best hash: 0003f3efab5e22b7ddfa5144f9306b190e407d476ccbd859eba1369152ac5ffb with difficulty: 3.860174155988332e-06
2023-12-22 03:25:05,128 [BEST HASH UPDATE] New best hash: 0000b1943dc8aead148bc79c03e913dda76d220fd23eaf5f74670aae6b328d0d with difficulty: 2.1997243535196427e-05
2023-12-22 03:25:09,996 [BEST HASH UPDATE] New best hash: 00004ed4e0c0d0e1e4cdc35430053cf083e3929cb3e79fdaeb6299737136cf41 with difficulty: 4.9551858093943016e-05
2023-12-22 03:25:11,137 [BEST HASH UPDATE] New best hash: 000030e2bf06b31fcb5804e7bc12f68e48066355ae56e0be6f7449b9e67ec784 with difficulty: 7.99057355490974e-05
2023-12-22 03:25:11,943 [BEST HASH UPDATE] New best hash: 00001452c7a6c39b98bbddecd7f3f8443e54092b7c93cccc72a249c5d3079c22 with difficulty: 0.00019220494071557886
2023-12-22 03:25:15,270 [BEST HASH UPDATE] New best hash: 000005bc0510323d35deb11dc2a8f8521ddecf7772964629b2d9d132fbf20809 with difficulty: 0.0006811897324026841
2023-12-22 03:25:24,097 [BEST HASH UPDATE] New best hash: 000005a9293acda83a322c2c8406551ab19b29c998e0b34212415d853c85f1e7 with difficulty: 0.0006900544267129364
2023-12-22 03:29:26,714 [BEST HASH UPDATE] New best hash: 0000038fb6d0b10d8e0c53d1540878acd3cad213aa7313e306fe47a394456dc2 with difficulty: 0.00109683504510879
2023-12-22 03:29:28,344 [BEST HASH UPDATE] New best hash: 0000023858e72f1bf2f6fd953f87dfeb6a6b393915260baeda0e19bc79afbd49 with difficulty: 0.0017594876221516073






┏━━━━━━━━━━━━━━━━━┓
┃     𝔱𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔬𝔯ⱪ 𝔣𝔬𝔯 𝔶𝔬𝔲𝔯 𝔟𝔞𝔤𝔰       ┃
┃                ➤21/M                      ┃
┃ ███▓▓  ███▓▓  ███▓▓  ███▓▓┃
DaCryptoRaccoon (OP)
Hero Member
*****
Offline Offline

Activity: 1241
Merit: 623


OGRaccoon


View Profile
February 28, 2024, 06:10:15 PM
 #10

Full code now on Github.

https://github.com/DaCryptoRaccoon/BitcoinSoloPy

Raccoon Out!  Wink

┏━━━━━━━━━━━━━━━━━┓
┃     𝔱𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔬𝔯ⱪ 𝔣𝔬𝔯 𝔶𝔬𝔲𝔯 𝔟𝔞𝔤𝔰       ┃
┃                ➤21/M                      ┃
┃ ███▓▓  ███▓▓  ███▓▓  ███▓▓┃
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!