Bitcoin Forum
April 27, 2024, 03:20:35 PM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1] 2 »  All
  Print  
Author Topic: Python based Solo miner for CPU | Learn Basic Bitcoin Mining | Just for fun  (Read 568 times)
irsada (OP)
Full Member
***
Offline Offline

Activity: 994
Merit: 117


View Profile
February 09, 2023, 08:20:06 PM
Merited by NotATether (5), Nexus9090 (5), vapourminer (1), paid2 (1)
 #1

Hello Bitcoiners

I want to share a python based solo bitcoin miner which uses ckpool. You can use other pools as well if you want. It is basically like a lottery which has extremly low chances to win but it can be used as a proof of concept. Maybe it has already been shared somewhere and I do not remember its true origin so cannot give proper reference.
You can make changes as you want. This code can help users understand true basics of mining bitcoins.
Installing Dependencies
You must have python. Try with old versions first.
Install dependencies with
Code:
pip install hashlib
pip install binascii
If any dependency is missing you can use pip install DependencyName.

Code
Code:
# -*- coding: utf-8 -*-

import socket
import json
import hashlib
import binascii
from pprint import pprint
import random


address = 'YourBitcoinAddress'
nonce   = hex(random.randint(0,2**32-1))[2:].zfill(8)
host    = 'solo.ckpool.org'
port    = 3333
#host    = 'pool.mainnet.bitcoin-global.io'
#port    = 9223

def main():
    print("address:{} nonce:{}".format(address,nonce))
    print("host:{} port:{}".format(host,port))
   
    sock    = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((host,port))
   
    #server connection
    sock.sendall(b'{"id": 1, "method": "mining.subscribe", "params": []}\n')
    lines = sock.recv(1024).decode().split('\n')
    response = json.loads(lines[0])
    sub_details,extranonce1,extranonce2_size = response['result']
   
    #authorize workers
    sock.sendall(b'{"params": ["'+address.encode()+b'", "password"], "id": 2, "method": "mining.authorize"}\n')
   
    #we read until 'mining.notify' is reached
    response = b''
    while response.count(b'\n') < 4 and not(b'mining.notify' in response):
        response += sock.recv(1024)
   
   
    #get rid of empty lines
    responses = [json.loads(res) for res in response.decode().split('\n') if len(res.strip())>0 and 'mining.notify' in res]
    pprint(responses)
   
    job_id,prevhash,coinb1,coinb2,merkle_branch,version,nbits,ntime,clean_jobs \
        = responses[0]['params']
   
    target = (nbits[2:]+'00'*(int(nbits[:2],16) - 3)).zfill(64)
    print('nbits:{} target:{}\n'.format(nbits,target))
   
    # extranonce2 = '00'*extranonce2_size
    extranonce2 = hex(random.randint(0,2**32-1))[2:].zfill(2*extranonce2_size)      # create random
   
    coinbase = coinb1 + extranonce1 + extranonce2 + coinb2
    coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest()
   
    print('coinbase:\n{}\n\ncoinbase hash:{}\n'.format(coinbase,binascii.hexlify(coinbase_hash_bin)))
    merkle_root = coinbase_hash_bin
    for h in merkle_branch:
        merkle_root = hashlib.sha256(hashlib.sha256(merkle_root + binascii.unhexlify(h)).digest()).digest()
   
    merkle_root = binascii.hexlify(merkle_root).decode()
   
    #little endian
    merkle_root = ''.join([merkle_root[i]+merkle_root[i+1] for i in range(0,len(merkle_root),2)][::-1])
   
    print('merkle_root:{}\n'.format(merkle_root))
   
    def noncework():
        nonce   = hex(random.randint(0,2**32-1))[2:].zfill(8)   #hex(int(nonce,16)+1)[2:]
        blockheader = version + prevhash + merkle_root + nbits + ntime + nonce +\
            '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'
       
    #    print('blockheader:\n{}\n'.format(blockheader))
       
        hash = hashlib.sha256(hashlib.sha256(binascii.unhexlify(blockheader)).digest()).digest()
        hash = binascii.hexlify(hash).decode()
        # print('hash: {}'.format(hash))
        if(hash[:5] == '00000'): print('hash: {}'.format(hash))
        if hash < target :
    #    if(hash[:10] == '0000000000'):
            print('success!!')
            print('hash: {}'.format(hash))
            payload = bytes('{"params": ["'+address+'", "'+job_id+'", "'+extranonce2 \
                +'", "'+ntime+'", "'+nonce+'"], "id": 1, "method": "mining.submit"}\n', 'utf-8')
            sock.sendall(payload)
            print(sock.recv(1024))
            input("Press Enter to continue...")
    #    else:
    #        print('failed mine, hash is greater than target')
   
    for k in range(10000000):
        noncework()
    print("Finished 10M Search. Regaining Information.")
    sock.close()
    main()

main()



Edit Code
You can edit code. Set your Bitcoin address to receive your mining rewards. Set pool host and port. Save code in a .py file.
One of popular solo pool is solo.ckpool.org which has low fee of like 2%. You get 98% of your mining reward.

Run Code
You can run code by opening command prompt in same folder of file and run command
Code:
python FileName.py


Missing Dependencies and errors
As decribed above you can use pip install command to install any missing dependency. You can google errors and still if you did not find solution maybe your python version is not compatible. Try changing python version.

Future Work
If you improve this code then share here so others can benefit as well and I will update this code as well.


Honor List for Code Improvers
  • 1.
  • 2.
  • 3.


Tribute
I want to pay tribute to original author of this code. I am not original author.
1714231235
Hero Member
*
Offline Offline

Posts: 1714231235

View Profile Personal Message (Offline)

Ignore
1714231235
Reply with quote  #2

1714231235
Report to moderator
1714231235
Hero Member
*
Offline Offline

Posts: 1714231235

View Profile Personal Message (Offline)

Ignore
1714231235
Reply with quote  #2

1714231235
Report to moderator
It is a common myth that Bitcoin is ruled by a majority of miners. This is not true. Bitcoin miners "vote" on the ordering of transactions, but that's all they do. They can't vote to change the network rules.
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
1714231235
Hero Member
*
Offline Offline

Posts: 1714231235

View Profile Personal Message (Offline)

Ignore
1714231235
Reply with quote  #2

1714231235
Report to moderator
1714231235
Hero Member
*
Offline Offline

Posts: 1714231235

View Profile Personal Message (Offline)

Ignore
1714231235
Reply with quote  #2

1714231235
Report to moderator
cixegz
Newbie
*
Offline Offline

Activity: 13
Merit: 0


View Profile
February 10, 2023, 05:10:00 AM
 #2

Hello Bitcoiners

I want to share a python based solo bitcoin miner which uses ckpool. You can use other pools as well if you want. It is basically like a lottery which has extremly low chances to win but it can be used as a proof of concept. Maybe it has already been shared somewhere and I do not remember its true origin so cannot give proper reference.
You can make changes as you want. This code can help users understand true basics of mining bitcoins.
Installing Dependencies
You must have python. Try with old versions first.
Install dependencies with
Code:
pip install hashlib
pip install binascii
If any dependency is missing you can use pip install DependencyName.

Code
Code:
# -*- coding: utf-8 -*-

import socket
import json
import hashlib
import binascii
from pprint import pprint
import random


address = 'YourBitcoinAddress'
nonce   = hex(random.randint(0,2**32-1))[2:].zfill(8)
host    = 'solo.ckpool.org'
port    = 3333
#host    = 'pool.mainnet.bitcoin-global.io'
#port    = 9223

def main():
    print("address:{} nonce:{}".format(address,nonce))
    print("host:{} port:{}".format(host,port))
   
    sock    = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((host,port))
   
    #server connection
    sock.sendall(b'{"id": 1, "method": "mining.subscribe", "params": []}\n')
    lines = sock.recv(1024).decode().split('\n')
    response = json.loads(lines[0])
    sub_details,extranonce1,extranonce2_size = response['result']
   
    #authorize workers
    sock.sendall(b'{"params": ["'+address.encode()+b'", "password"], "id": 2, "method": "mining.authorize"}\n')
   
    #we read until 'mining.notify' is reached
    response = b''
    while response.count(b'\n') < 4 and not(b'mining.notify' in response):
        response += sock.recv(1024)
   
   
    #get rid of empty lines
    responses = [json.loads(res) for res in response.decode().split('\n') if len(res.strip())>0 and 'mining.notify' in res]
    pprint(responses)
   
    job_id,prevhash,coinb1,coinb2,merkle_branch,version,nbits,ntime,clean_jobs \
        = responses[0]['params']
   
    target = (nbits[2:]+'00'*(int(nbits[:2],16) - 3)).zfill(64)
    print('nbits:{} target:{}\n'.format(nbits,target))
   
    # extranonce2 = '00'*extranonce2_size
    extranonce2 = hex(random.randint(0,2**32-1))[2:].zfill(2*extranonce2_size)      # create random
   
    coinbase = coinb1 + extranonce1 + extranonce2 + coinb2
    coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest()
   
    print('coinbase:\n{}\n\ncoinbase hash:{}\n'.format(coinbase,binascii.hexlify(coinbase_hash_bin)))
    merkle_root = coinbase_hash_bin
    for h in merkle_branch:
        merkle_root = hashlib.sha256(hashlib.sha256(merkle_root + binascii.unhexlify(h)).digest()).digest()
   
    merkle_root = binascii.hexlify(merkle_root).decode()
   
    #little endian
    merkle_root = ''.join([merkle_root[i]+merkle_root[i+1] for i in range(0,len(merkle_root),2)][::-1])
   
    print('merkle_root:{}\n'.format(merkle_root))
   
    def noncework():
        nonce   = hex(random.randint(0,2**32-1))[2:].zfill(8)   #hex(int(nonce,16)+1)[2:]
        blockheader = version + prevhash + merkle_root + nbits + ntime + nonce +\
            '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'
       
    #    print('blockheader:\n{}\n'.format(blockheader))
       
        hash = hashlib.sha256(hashlib.sha256(binascii.unhexlify(blockheader)).digest()).digest()
        hash = binascii.hexlify(hash).decode()
        # print('hash: {}'.format(hash))
        if(hash[:5] == '00000'): print('hash: {}'.format(hash))
        if hash < target :
    #    if(hash[:10] == '0000000000'):
            print('success!!')
            print('hash: {}'.format(hash))
            payload = bytes('{"params": ["'+address+'", "'+job_id+'", "'+extranonce2 \
                +'", "'+ntime+'", "'+nonce+'"], "id": 1, "method": "mining.submit"}\n', 'utf-8')
            sock.sendall(payload)
            print(sock.recv(1024))
            input("Press Enter to continue...")
    #    else:
    #        print('failed mine, hash is greater than target')
   
    for k in range(10000000):
        noncework()
    print("Finished 10M Search. Regaining Information.")
    sock.close()
    main()

main()



Edit Code
You can edit code. Set your Bitcoin address to receive your mining rewards. Set pool host and port. Save code in a .py file.
One of popular solo pool is solo.ckpool.org which has low fee of like 2%. You get 98% of your mining reward.

Run Code
You can run code by opening command prompt in same folder of file and run command
Code:
python FileName.py


Missing Dependencies and errors
As decribed above you can use pip install command to install any missing dependency. You can google errors and still if you did not find solution maybe your python version is not compatible. Try changing python version.

Future Work
If you improve this code then share here so others can benefit as well and I will update this code as well.


Honor List for Code Improvers
  • 1.
  • 2.
  • 3.


Tribute
I want to pay tribute to original author of this code. I am not original author.


how to mine testnet
any GPU speed, python mining
cixegz
Newbie
*
Offline Offline

Activity: 13
Merit: 0


View Profile
February 10, 2023, 05:20:16 AM
 #3

pip install  error
/home/user/Downloads# pip install hashlib
Code:
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
Collecting hashlib
  Using cached hashlib-20081119.zip (42 kB)
  error: subprocess-exited-with-error
 
  × python setup.py egg_info did not run successfully.
  │ exit code: 1
  ╰─> See above for output.
 
  note: This error originates from a subprocess, and is likely not a problem with pip.
  Preparing metadata (setup.py) ... error
error: metadata-generation-failed

× Encountered error while generating package metadata.
╰─> See above for output.

note: This is an issue with the package mentioned above, not pip.
hint: See above for details.

/home/user/Downloads# pip install binascii
Code:
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
ERROR: Could not find a version that satisfies the requirement binascii (from versions: none)
ERROR: No matching distribution found for binascii

witcher_sense
Legendary
*
Offline Offline

Activity: 2310
Merit: 4313

🔐BitcoinMessage.Tools🔑


View Profile WWW
February 10, 2023, 09:37:23 AM
Merited by ABCbits (1)
 #4

pip install  error
/home/user/Downloads# pip install hashlib

/home/user/Downloads# pip install binascii


You don't need to install from pip, these modules are from standard python library, which means they come with interpreter.

Just import them like this:

Code:
import binascii
import hashlib

█▀▀▀











█▄▄▄
▀▀▀▀▀▀▀▀▀▀▀
e
▄▄▄▄▄▄▄▄▄▄▄
█████████████
████████████▄███
██▐███████▄█████▀
█████████▄████▀
███▐████▄███▀
████▐██████▀
█████▀█████
███████████▄
████████████▄
██▄█████▀█████▄
▄█████████▀█████▀
███████████▀██▀
████▀█████████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
c.h.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▀▀▀█











▄▄▄█
▄██████▄▄▄
█████████████▄▄
███████████████
███████████████
███████████████
███████████████
███░░█████████
███▌▐█████████
█████████████
███████████▀
██████████▀
████████▀
▀██▀▀
irsada (OP)
Full Member
***
Offline Offline

Activity: 994
Merit: 117


View Profile
February 10, 2023, 06:44:34 PM
 #5

Quote
My quick search your code might be based on one of these repository,
https://github.com/iceland2k14/solominer
https://github.com/Pymmdrza/SoloMiner


Yeah I guess its from iceland with few modifications.

Quote
This only applies to Python 2, your code is in Python 3.
Yes but this code was initially written for Python 2.7 so I described that method. For python3 users can directly import as suggested by @witcher_sense. And usually people don't get missing dependecy errors in Python3 as it comes with multiple pre installed libraries.
For python3 pip3 install works fine in many cases.
digaran
Copper Member
Hero Member
*****
Offline Offline

Activity: 1330
Merit: 899

🖤😏


View Profile
February 10, 2023, 07:24:12 PM
 #6

You say just for fun, I wonder where is the fun if we start mining with our CPU 24/7 and never mine anything, could you provide some probability estimations on a single block found/time?

🖤😏
number435398
Jr. Member
*
Offline Offline

Activity: 260
Merit: 6


View Profile
April 04, 2023, 04:43:14 AM
 #7

This code is great! Its a good start to what I was looking for. Any intentions on updating it? I'm curious, why does it randomly go through nonces instead of just counting through them by counting up one by one?
witcher_sense
Legendary
*
Offline Offline

Activity: 2310
Merit: 4313

🔐BitcoinMessage.Tools🔑


View Profile WWW
April 04, 2023, 06:08:46 AM
Merited by vapourminer (1)
 #8

I'm curious, why does it randomly go through nonces instead of just counting through them by counting up one by one?
It may be that I am missing something but I think it is just an implementation detail that doesn't affect the chances of finding a correct hash but makes the function a little bit easier to design and reason about. As you can see from the code, the algorithm performs a predetermined number of operations and then starts over by invoking the main function. If it were incrementing nonce instead of taking a random value, it would need to keep track of the actual value, pass it back to the main function, and reset it after each found block. Using random numbers saves you from having to choose the right moment to relaunch the nonce management algorithm. The only problem I see is that the range of random values is tiny compared to all possible values.

█▀▀▀











█▄▄▄
▀▀▀▀▀▀▀▀▀▀▀
e
▄▄▄▄▄▄▄▄▄▄▄
█████████████
████████████▄███
██▐███████▄█████▀
█████████▄████▀
███▐████▄███▀
████▐██████▀
█████▀█████
███████████▄
████████████▄
██▄█████▀█████▄
▄█████████▀█████▀
███████████▀██▀
████▀█████████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
c.h.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▀▀▀█











▄▄▄█
▄██████▄▄▄
█████████████▄▄
███████████████
███████████████
███████████████
███████████████
███░░█████████
███▌▐█████████
█████████████
███████████▀
██████████▀
████████▀
▀██▀▀
NotATether
Legendary
*
Offline Offline

Activity: 1582
Merit: 6688


bitcoincleanup.com / bitmixlist.org


View Profile WWW
April 04, 2023, 07:18:45 AM
 #9

Congratulations on learning how to mine bitcoins!

I also appreciate the fact that you're not connecting to some regtest node, but rather, you are using a live mining pool (ckpool, in this case).

Have you considered making a guide to connecting a USB miner such as the Compac F or AntMiner U1/2 to a mining pool?

.
.BLACKJACK ♠ FUN.
█████████
██████████████
████████████
█████████████████
████████████████▄▄
░█████████████▀░▀▀
██████████████████
░██████████████
████████████████
░██████████████
████████████
███████████████░██
██████████
CRYPTO CASINO &
SPORTS BETTING
▄▄███████▄▄
▄███████████████▄
███████████████████
█████████████████████
███████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
███████████████████████
█████████████████████
███████████████████
▀███████████████▀
█████████
.
serveria.com
Legendary
*
Offline Offline

Activity: 2226
Merit: 1172


Privacy Servers. Since 2009.


View Profile WWW
April 04, 2023, 08:53:55 PM
 #10

You say just for fun, I wonder where is the fun if we start mining with our CPU 24/7 and never mine anything, could you provide some probability estimations on a single block found/time?

Yeah, doesn't sound fun... for educational purposes only? I'd prefer to mine some shitcoin using my CPU or GPU but with some real results/mining involved. Solo mining even on an Antminer S19 Pro is a lottery now already - 0.000065% chance of catching the block every 10 minutes (around 30 years to solo mine a block), CPU mining is not even a lottery, you're just losing money on electricity and burning out your CPU.  Grin
Sha256explorer
Jr. Member
*
Offline Offline

Activity: 47
Merit: 18


View Profile
April 04, 2023, 09:08:02 PM
 #11

thanks, i also want to practice some code for cpu/gpu bitcoin mining, so i very gladly looked at your work.

a question regarding this line of code: hash = hashlib.sha256(hashlib.sha256(binascii.unhexlify(blockheader)).digest()).digest()
why are you calling sha256 twice? so you hash the hash of the header.
maybe it's a mistake?
number435398
Jr. Member
*
Offline Offline

Activity: 260
Merit: 6


View Profile
April 04, 2023, 11:56:04 PM
 #12

You say just for fun, I wonder where is the fun if we start mining with our CPU 24/7 and never mine anything, could you provide some probability estimations on a single block found/time?

Yeah, doesn't sound fun... for educational purposes only? I'd prefer to mine some shitcoin using my CPU or GPU but with some real results/mining involved. Solo mining even on an Antminer S19 Pro is a lottery now already - 0.000065% chance of catching the block every 10 minutes (around 30 years to solo mine a block), CPU mining is not even a lottery, you're just losing money on electricity and burning out your CPU.  Grin

If you're "burning out" your CPU, you need a better cooling solution Wink.
number435398
Jr. Member
*
Offline Offline

Activity: 260
Merit: 6


View Profile
April 04, 2023, 11:57:37 PM
 #13

thanks, i also want to practice some code for cpu/gpu bitcoin mining, so i very gladly looked at your work.

a question regarding this line of code: hash = hashlib.sha256(hashlib.sha256(binascii.unhexlify(blockheader)).digest()).digest()
why are you calling sha256 twice? so you hash the hash of the header.
maybe it's a mistake?

Should be able to implement PyCuda into that code. I'd love to see that myself. 

Bitcoin double hashes. That's how it works. When you hash the block and think you're done, you're not. You have to hash it a second time to see if it has the requisite zeros.
garlonicon
Hero Member
*****
Offline Offline

Activity: 800
Merit: 1932


View Profile
April 05, 2023, 04:44:47 AM
Merited by vapourminer (1), ABCbits (1), nc50lc (1)
 #14

Quote
why are you calling sha256 twice? so you hash the hash of the header.
Because Bitcoin works in that way. For example, the latest block hash (at the moment of writing) is calculated in this way:
Code:
SHA-256(00000020ceee9013d84c76a7e5a980df9dec537f313a3259da2d02000000000000000000b90235771c6c90b9d13e4b3670b489cb0fadc6bcbf610f4d0ead0c1d1c8d068deaf22c643e020617cb4b5c51)=88b46b0817fd187eba000740d5b727fd961bcb8df91fb4a7564610a4fe2fc76c
SHA-256(88b46b0817fd187eba000740d5b727fd961bcb8df91fb4a7564610a4fe2fc76c)=ce1c179317c8c1271adf317798d8d9ba5cb0cdf93c0404000000000000000000
Sha256explorer
Jr. Member
*
Offline Offline

Activity: 47
Merit: 18


View Profile
April 05, 2023, 06:53:11 AM
 #15

Quote
why are you calling sha256 twice? so you hash the hash of the header.
Because Bitcoin works in that way. For example, the latest block hash (at the moment of writing) is calculated in this way:
Code:
SHA-256(00000020ceee9013d84c76a7e5a980df9dec537f313a3259da2d02000000000000000000b90235771c6c90b9d13e4b3670b489cb0fadc6bcbf610f4d0ead0c1d1c8d068deaf22c643e020617cb4b5c51)=88b46b0817fd187eba000740d5b727fd961bcb8df91fb4a7564610a4fe2fc76c
SHA-256(88b46b0817fd187eba000740d5b727fd961bcb8df91fb4a7564610a4fe2fc76c)=ce1c179317c8c1271adf317798d8d9ba5cb0cdf93c0404000000000000000000
I did so.e investigation and....i Was wrong. Really thanks, this helped me a lot!!
Sha256explorer
Jr. Member
*
Offline Offline

Activity: 47
Merit: 18


View Profile
April 20, 2023, 08:56:20 PM
Last edit: April 22, 2023, 07:25:27 AM by Sha256explorer
 #16

I made some small improvements:
1) I called the noncework function 2**32 times, not just 10 million million times
2) every time i called the noncework function, i passed the loop value k, using that number as the nounce and not a random number

I could also have used the time parameter, another 5000 or 6000 times cycle, so that the root merkle only resets once every 5000*2**32. In that case, if we had a 100 TH/S asic instead of a CPU, it would have to recalculate the nounce every 4 or 5 seconds, if I'm not mistaken.

Code:
# -*- coding: utf-8 -*-

import socket
import json
import hashlib
import binascii
from pprint import pprint
import random
import time

address = 'YourBitcoinAddress'
nonce   = hex(0)[2:].zfill(8)
host    = 'solo.ckpool.org'
port    = 3333
#host    = 'pool.mainnet.bitcoin-global.io'
#port    = 9223

def main():
    print("address:{} nonce:{}".format(address,nonce))
    print("host:{} port:{}".format(host,port))
   
    sock    = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((host,port))
   
    #server connection
    sock.sendall(b'{"id": 1, "method": "mining.subscribe", "params": []}\n')
    lines = sock.recv(1024).decode().split('\n')
    response = json.loads(lines[0])
    sub_details,extranonce1,extranonce2_size = response['result']
   
    #authorize workers
    sock.sendall(b'{"params": ["'+address.encode()+b'", "password"], "id": 2, "method": "mining.authorize"}\n')
   
    #we read until 'mining.notify' is reached
    response = b''
    while response.count(b'\n') < 4 and not(b'mining.notify' in response):
        response += sock.recv(1024)
   
   
    #get rid of empty lines
    responses = [json.loads(res) for res in response.decode().split('\n') if len(res.strip())>0 and 'mining.notify' in res]
    pprint(responses)
   
    job_id,prevhash,coinb1,coinb2,merkle_branch,version,nbits,ntime,clean_jobs \
        = responses[0]['params']
   
    target = (nbits[2:]+'00'*(int(nbits[:2],16) - 3)).zfill(64)

    print('nbits:{} target:{}\n'.format(nbits,target))
   
    # extranonce2 = '00'*extranonce2_size
    extranonce2 = hex(random.randint(0,2**32-1))[2:].zfill(2*extranonce2_size)      # create random
   
    coinbase = coinb1 + extranonce1 + extranonce2 + coinb2
    coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest()
   
    print('coinbase:\n{}\n\ncoinbase hash:{}\n'.format(coinbase,binascii.hexlify(coinbase_hash_bin)))
    merkle_root = coinbase_hash_bin
    for h in merkle_branch:
        merkle_root = hashlib.sha256(hashlib.sha256(merkle_root + binascii.unhexlify(h)).digest()).digest()
   
    merkle_root = binascii.hexlify(merkle_root).decode()
   
    #little endian
    merkle_root = ''.join([merkle_root[i]+merkle_root[i+1] for i in range(0,len(merkle_root),2)][::-1])
   
    print('merkle_root:{}\n'.format(merkle_root))
   
    def noncework(k):
        nonce   = hex(k)[2:].zfill(8)   #hex(int(nonce,16)+1)[2:]
        blockheader = version + prevhash + merkle_root + nbits + ntime + nonce +\
            '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'
       
        # print('blockheader:\n{}\n'.format(blockheader))
       
        hash = hashlib.sha256(hashlib.sha256(binascii.unhexlify(blockheader)).digest()).digest()
        hash = binascii.hexlify(hash).decode()
        # print('hash: {}'.format(hash))
        if(hash[:5] == '00000'): print('hash: {}'.format(hash))
        if hash < target :
    #    if(hash[:10] == '0000000000'):
            print('success!!')
            print('hash: {}'.format(hash))
            payload = bytes('{"params": ["'+address+'", "'+job_id+'", "'+extranonce2 \
                +'", "'+ntime+'", "'+nonce+'"], "id": 1, "method": "mining.submit"}\n', 'utf-8')
            sock.sendall(payload)
            print(sock.recv(1024))
            input("Press Enter to continue...")
    #    else:
    #        print('failed mine, hash is greater than target')
   
    #  use this loop if you want to do a speed test with only 1 million rounds
    start = time.time()
    for k in range(1000000):
        noncework(k)
    end = time.time()
    print(end - start)
    # about 42.5
    '''
    # use this loop if you want to try all the nounce with 2**32 rounds
    for k in range(2**32):
    noncework(k)
    '''
    print("Finished nounce. Regaining Information.")
    sock.close()
    main()

main()

Sha256explorer
Jr. Member
*
Offline Offline

Activity: 47
Merit: 18


View Profile
April 22, 2023, 07:37:01 AM
 #17

Another small improvement, the last one I think. I didn't use hashlib to hash the nounce, but I used this 100% python implementation: https://github.com/keanemind/python-sha-256.
In this way the code is about 3.5 slower (but that's just to understand, performances aren't important) but you can understand how the hash is encoded.
It sure is useful to me, and I will use it as a starting point for my own serious mining algorithm that I am building (https://bitcointalk.org/index.php?topic=5446391.0). I hope  it is useful to others too.

Code:
# -*- coding: utf-8 -*-

import socket
import json
import hashlib
import binascii
from pprint import pprint
import random
import time

address = 'YourBitcoinAddress'
nonce   = hex(0)[2:].zfill(8)
host    = 'solo.ckpool.org'
port    = 3333
#host    = 'pool.mainnet.bitcoin-global.io'
#port    = 9223

K = [
    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]

def generate_hash(message: bytearray) -> bytearray:
    """Return a SHA-256 hash from the message passed.
    The argument should be a bytes, bytearray, or
    string object."""

    if isinstance(message, str):
        message = bytearray(message, 'ascii')
    elif isinstance(message, bytes):
        message = bytearray(message)
    elif not isinstance(message, bytearray):
        raise TypeError

    # Padding
    length = len(message) * 8 # len(message) is number of BYTES!!!
    message.append(0x80)
    while (len(message) * 8 + 64) % 512 != 0:
        message.append(0x00)

    message += length.to_bytes(8, 'big') # pad to 8 bytes or 64 bits

    assert (len(message) * 8) % 512 == 0, "Padding did not complete properly!"

    # Parsing
    blocks = [] # contains 512-bit chunks of message
    for i in range(0, len(message), 64): # 64 bytes is 512 bits
        blocks.append(message[i:i+64])

    # Setting Initial Hash Value
    h0 = 0x6a09e667
    h1 = 0xbb67ae85
    h2 = 0x3c6ef372
    h3 = 0xa54ff53a
    h5 = 0x9b05688c
    h4 = 0x510e527f
    h6 = 0x1f83d9ab
    h7 = 0x5be0cd19

    # SHA-256 Hash Computation
    for message_block in blocks:
        # Prepare message schedule
        message_schedule = []
        for t in range(0, 64):
            if t <= 15:
                # adds the t'th 32 bit word of the block,
                # starting from leftmost word
                # 4 bytes at a time
                message_schedule.append(bytes(message_block[t*4:(t*4)+4]))
            else:
                term1 = _sigma1(int.from_bytes(message_schedule[t-2], 'big'))
                term2 = int.from_bytes(message_schedule[t-7], 'big')
                term3 = _sigma0(int.from_bytes(message_schedule[t-15], 'big'))
                term4 = int.from_bytes(message_schedule[t-16], 'big')

                # append a 4-byte byte object
                schedule = ((term1 + term2 + term3 + term4) % 2**32).to_bytes(4, 'big')
                message_schedule.append(schedule)

        assert len(message_schedule) == 64

        # Initialize working variables
        a = h0
        b = h1
        c = h2
        d = h3
        e = h4
        f = h5
        g = h6
        h = h7

        # Iterate for t=0 to 63
        for t in range(64):
            t1 = ((h + _capsigma1(e) + _ch(e, f, g) + K[t] +
                   int.from_bytes(message_schedule[t], 'big')) % 2**32)

            t2 = (_capsigma0(a) + _maj(a, b, c)) % 2**32

            h = g
            g = f
            f = e
            e = (d + t1) % 2**32
            d = c
            c = b
            b = a
            a = (t1 + t2) % 2**32

        # Compute intermediate hash value
        h0 = (h0 + a) % 2**32
        h1 = (h1 + b) % 2**32
        h2 = (h2 + c) % 2**32
        h3 = (h3 + d) % 2**32
        h4 = (h4 + e) % 2**32
        h5 = (h5 + f) % 2**32
        h6 = (h6 + g) % 2**32
        h7 = (h7 + h) % 2**32

    return ((h0).to_bytes(4, 'big') + (h1).to_bytes(4, 'big') +
            (h2).to_bytes(4, 'big') + (h3).to_bytes(4, 'big') +
            (h4).to_bytes(4, 'big') + (h5).to_bytes(4, 'big') +
            (h6).to_bytes(4, 'big') + (h7).to_bytes(4, 'big'))

def _sigma0(num: int):
    """As defined in the specification."""
    num = (_rotate_right(num, 7) ^
           _rotate_right(num, 18) ^
           (num >> 3))
    return num

def _sigma1(num: int):
    """As defined in the specification."""
    num = (_rotate_right(num, 17) ^
           _rotate_right(num, 19) ^
           (num >> 10))
    return num

def _capsigma0(num: int):
    """As defined in the specification."""
    num = (_rotate_right(num, 2) ^
           _rotate_right(num, 13) ^
           _rotate_right(num, 22))
    return num

def _capsigma1(num: int):
    """As defined in the specification."""
    num = (_rotate_right(num, 6) ^
           _rotate_right(num, 11) ^
           _rotate_right(num, 25))
    return num

def _ch(x: int, y: int, z: int):
    """As defined in the specification."""
    return (x & y) ^ (~x & z)

def _maj(x: int, y: int, z: int):
    """As defined in the specification."""
    return (x & y) ^ (x & z) ^ (y & z)

def _rotate_right(num: int, shift: int, size: int = 32):
    """Rotate an integer right."""
    return (num >> shift) | (num << size - shift)



def main():
    print("address:{} nonce:{}".format(address,nonce))
    print("host:{} port:{}".format(host,port))
   
    sock    = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((host,port))
   
    #server connection
    sock.sendall(b'{"id": 1, "method": "mining.subscribe", "params": []}\n')
    lines = sock.recv(1024).decode().split('\n')
    response = json.loads(lines[0])
    sub_details,extranonce1,extranonce2_size = response['result']
   
    #authorize workers
    sock.sendall(b'{"params": ["'+address.encode()+b'", "password"], "id": 2, "method": "mining.authorize"}\n')
   
    #we read until 'mining.notify' is reached
    response = b''
    while response.count(b'\n') < 4 and not(b'mining.notify' in response):
        response += sock.recv(1024)
   
   
    #get rid of empty lines
    responses = [json.loads(res) for res in response.decode().split('\n') if len(res.strip())>0 and 'mining.notify' in res]
    pprint(responses)
   
    job_id,prevhash,coinb1,coinb2,merkle_branch,version,nbits,ntime,clean_jobs \
        = responses[0]['params']
   
    target = (nbits[2:]+'00'*(int(nbits[:2],16) - 3)).zfill(64)

    print('nbits:{} target:{}\n'.format(nbits,target))
   
    # extranonce2 = '00'*extranonce2_size
    extranonce2 = hex(random.randint(0,2**32-1))[2:].zfill(2*extranonce2_size)      # create random
   
    coinbase = coinb1 + extranonce1 + extranonce2 + coinb2
    coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest()
   
    print('coinbase:\n{}\n\ncoinbase hash:{}\n'.format(coinbase,binascii.hexlify(coinbase_hash_bin)))
    merkle_root = coinbase_hash_bin
    for h in merkle_branch:
        merkle_root = hashlib.sha256(hashlib.sha256(merkle_root + binascii.unhexlify(h)).digest()).digest()
   
    merkle_root = binascii.hexlify(merkle_root).decode()
   
    #little endian
    merkle_root = ''.join([merkle_root[i]+merkle_root[i+1] for i in range(0,len(merkle_root),2)][::-1])
   
    print('merkle_root:{}\n'.format(merkle_root))
   
    def noncework(k):
        nonce   = hex(k)[2:].zfill(8)   #hex(int(nonce,16)+1)[2:]
        blockheader = version + prevhash + merkle_root + nbits + ntime + nonce +\
            '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'
       
       
        # print('blockheader:\n{}\n'.format(blockheader))

        hash=generate_hash(generate_hash(binascii.unhexlify(blockheader))).hex()

        # hash = hashlib.sha256(hashlib.sha256(binascii.unhexlify(blockheader)).digest()).digest()
        #hash = binascii.hexlify(blockheader).decode()
        # print('hash: {}'.format(hash))
        if(hash[:5] == '00000'): print('hash: {}'.format(hash))
        if hash < target :
    #    if(hash[:10] == '0000000000'):
            print('success!!')
            print('hash: {}'.format(hash))
            payload = bytes('{"params": ["'+address+'", "'+job_id+'", "'+extranonce2 \
                +'", "'+ntime+'", "'+nonce+'"], "id": 1, "method": "mining.submit"}\n', 'utf-8')
            sock.sendall(payload)
            print(sock.recv(1024))
            input("Press Enter to continue...")
    #    else:
    #        print('failed mine, hash is greater than target')
   
    start = time.time()
    for k in range(1000000):
        noncework(k)
    end = time.time()
    print(end - start)
    '''
    for k in range(2**32):
    noncework(k)
    '''
    sock.close()
    main()

main()
vshoes
Newbie
*
Offline Offline

Activity: 4
Merit: 0


View Profile
February 26, 2024, 04:11:59 PM
 #18

You say just for fun, I wonder where is the fun if we start mining with our CPU 24/7 and never mine anything, could you provide some probability estimations on a single block found/time?

I've just fired this up on one core of a i5, running through 10MM hashes in around 56 seconds. That gives me 178,000 hashes/s or 0.178M/h, which presently equates to 65 BILLION years to find a block. That's between 14 and 15 times the age of the Earth, and slightly less than 5 times the age of the universe and everything in it.

Still, gotta be in it to win it!
ranochigo
Legendary
*
Offline Offline

Activity: 2954
Merit: 4165


View Profile
February 27, 2024, 03:13:22 AM
 #19

You say just for fun, I wonder where is the fun if we start mining with our CPU 24/7 and never mine anything, could you provide some probability estimations on a single block found/time?
Looks to be more of a fun project to learn about Bitcoin mining, rather than doing so seriously. It's an easy way to see what is being hashed and being sent over to the pool. This script isn't particularly optimized, don't think it is multithreaded?

If you want to do so, then there are more optimized CPU miners to use, but even so you shouldn't expect anything at all.

.
.HUGE.
▄██████████▄▄
▄█████████████████▄
▄█████████████████████▄
▄███████████████████████▄
▄█████████████████████████▄
███████▌██▌▐██▐██▐████▄███
████▐██▐████▌██▌██▌██▌██
█████▀███▀███▀▐██▐██▐█████

▀█████████████████████████▀

▀███████████████████████▀

▀█████████████████████▀

▀█████████████████▀

▀██████████▀▀
█▀▀▀▀











█▄▄▄▄
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
.
CASINSPORTSBOOK
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▀▀▀▀█











▄▄▄▄█
vshoes
Newbie
*
Offline Offline

Activity: 4
Merit: 0


View Profile
February 29, 2024, 11:37:02 AM
 #20

I made some small improvements:
1) I called the noncework function 2**32 times, not just 10 million million times
2) every time i called the noncework function, i passed the loop value k, using that number as the nounce and not a random number

I could also have used the time parameter, another 5000 or 6000 times cycle, so that the root merkle only resets once every 5000*2**32. In that case, if we had a 100 TH/S asic instead of a CPU, it would have to recalculate the nounce every 4 or 5 seconds, if I'm not mistaken.

Code:
# omitted for brevity
   
    #  use this loop if you want to do a speed test with only 1 million rounds
    start = time.time()
    for k in range(1000000):
        noncework(k)
    end = time.time()
    print(end - start)
    # about 42.5
    '''
    # use this loop if you want to try all the nounce with 2**32 rounds
    for k in range(2**32):
    noncework(k)
    '''
    print("Finished nounce. Regaining Information.")
    sock.close()
    main()

main()


I'm interested to understand why you chose (2**32) as the target for noncework. Given the end-start times when I tried your script, the noncework function takes around 2.5 hours. In that time, it's almost certain that a block would be found and you'd be looking at coinbase etc information from a non-current block. Am I wrong here, or should you be regaining information much sooner?

Also, can you explain the advantage of noncework(k) instead of noncework() ? Thanks!

I'm trying to optimize the script as a bit of fun, given I'll never mine a block, my goal is to improve my Mh/s figure as much as possible and learn more about the technical background underpinning mining.
Pages: [1] 2 »  All
  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!