One way to failed Crack BTC POW funciton
Abstract : 概述
I try to Crack BTC POW funciton.
我尝试去破解BTC的POW函数
I think if a result has more zero it will more near target.
如果一个结果里面有更多的0,那么它应该更容易实现目标。
I use simply dynamic programming to write progame.
我使用简单的动态规划方式来实现。
Progame Design : 程序设计
Brute force : 暴力破解
Difficulty(难度):000000f000000000ff0000000000000000000000000000000000000000000000
Try times(尝试次数):100次
All time(总时间):2499.62012219429s
Average time(平均时间):24.9962012219429s
Dynamic Programming : 动态规划
Difficulty(难度):000000f000000000ff0000000000000000000000000000000000000000000000
Try times(尝试次数)::100次
All time(总时间):3011.75244140625s
Average time(平均时间):30.1175244140625s
Result:结论
Brute force is the best way.
暴力破解是最快的一种方式。
Appendix
Brute force Code
# ntgbtminer - vsergeev - https://github.com/vsergeev/ntgbtminer
#
# No Thrils GetBlockTemplate Bitcoin Miner
#
# This is mostly a demonstration of the GBT protocol.
# It mines at a measly 550 KH/s on my computer, but
# with a whole lot of spirit ;)
#
import urllib.request
import urllib.error
import urllib.parse
import base64
import json
import hashlib
import struct
import random
import time
import os
import sys
# JSON-HTTP RPC Configuration
# This will be particular to your local ~/.bitcoin/bitcoin.conf
'''
RPC_URL = os.environ.get("RPC_URL", "http://127.0.0.1:8332")
RPC_USER = os.environ.get("RPC_USER", "bitcoinrpc")
RPC_PASS = os.environ.get("RPC_PASS", "")
'''
RPC_URL = os.environ.get("RPC_URL", "http://172.17.0.2:19001")
RPC_USER = os.environ.get("RPC_USER", "admin1")
RPC_PASS = os.environ.get("RPC_PASS", "123")
################################################################################
# Bitcoin Daemon JSON-HTTP RPC
################################################################################
def rpc(method, params=None):
"""
Make an RPC call to the Bitcoin Daemon JSON-HTTP server.
Arguments:
method (string): RPC method
params: RPC arguments
Returns:
object: RPC response result.
"""
rpc_id = random.getrandbits(32)
data = json.dumps({"id": rpc_id, "method": method, "params": params}).encode()
auth = base64.encodebytes((RPC_USER + ":" + RPC_PASS).encode()).decode().strip()
request = urllib.request.Request(RPC_URL, data, {"Authorization": "Basic {:s}".format(auth)})
with urllib.request.urlopen(request) as f:
response = json.loads(f.read())
if response['id'] != rpc_id:
raise ValueError("Invalid response id: got {}, expected {:u}".format(response['id'], rpc_id))
elif response['error'] is not None:
raise ValueError("RPC error: {:s}".format(json.dumps(response['error'])))
return response['result']
################################################################################
# Bitcoin Daemon RPC Call Wrappers
################################################################################
def rpc_getblocktemplate():
try:
return rpc("getblocktemplate", [{"rules": ["segwit"]}])
except ValueError:
return {}
def rpc_submitblock(block_submission):
return rpc("submitblock", [block_submission])
################################################################################
# Representation Conversion Utility Functions
################################################################################
def int2lehex(value, width):
"""
Convert an unsigned integer to a little endian ASCII hex string.
Args:
value (int): value
width (int): byte width
Returns:
string: ASCII hex string
"""
return value.to_bytes(width, byteorder='little').hex()
def int2varinthex(value):
"""
Convert an unsigned integer to little endian varint ASCII hex string.
Args:
value (int): value
Returns:
string: ASCII hex string
"""
if value < 0xfd:
return int2lehex(value, 1)
elif value <= 0xffff:
return "fd" + int2lehex(value, 2)
elif value <= 0xffffffff:
return "fe" + int2lehex(value, 4)
else:
return "ff" + int2lehex(value, 8)
def bitcoinaddress2hash160(addr):
"""
Convert a Base58 Bitcoin address to its Hash-160 ASCII hex string.
Args:
addr (string): Base58 Bitcoin address
Returns:
string: Hash-160 ASCII hex string
"""
table = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
hash160 = 0
addr = addr[::-1]
for i, c in enumerate(addr):
hash160 += (58 ** i) * table.find(c)
# Convert number to 50-byte ASCII Hex string
hash160 = "{:050x}".format(hash160)
# Discard 1-byte network byte at beginning and 4-byte checksum at the end
return hash160[2:50 - 8]
################################################################################
# Transaction Coinbase and Hashing Functions
################################################################################
def tx_encode_coinbase_height(height):
"""
Encode the coinbase height, as per BIP 34:
https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki
Arguments:
height (int): height of the mined block
Returns:
string: encoded height as an ASCII hex string
"""
width = (height.bit_length() + 7) // 8
return bytes([width]).hex() + int2lehex(height, width)
def tx_make_coinbase(coinbase_script, address, value, height):
"""
Create a coinbase transaction.
Arguments:
coinbase_script (string): arbitrary script as an ASCII hex string
address (string): Base58 Bitcoin address
value (int): coinbase value
height (int): mined block height
Returns:
string: coinbase transaction as an ASCII hex string
"""
# See https://en.bitcoin.it/wiki/Transaction
coinbase_script = tx_encode_coinbase_height(height) + coinbase_script
# Create a pubkey script
# OP_DUP OP_HASH160 <len to push> <pubkey> OP_EQUALVERIFY OP_CHECKSIG
pubkey_script = "76" + "a9" + "14" + bitcoinaddress2hash160(address) + "88" + "ac"
tx = ""
# version
tx += "01000000"
# in-counter
tx += "01"
# input[0] prev hash
tx += "0" * 64
# input[0] prev seqnum
tx += "ffffffff"
# input[0] script len
tx += int2varinthex(len(coinbase_script) // 2)
# input[0] script
tx += coinbase_script
# input[0] seqnum
tx += "ffffffff"
# out-counter
tx += "01"
# output[0] value
tx += int2lehex(value, 8)
# output[0] script len
tx += int2varinthex(len(pubkey_script) // 2)
# output[0] script
tx += pubkey_script
# lock-time
tx += "00000000"
return tx
def tx_compute_hash(tx):
"""
Compute the SHA256 double hash of a transaction.
Arguments:
tx (string): transaction data as an ASCII hex string
Return:
string: transaction hash as an ASCII hex string
"""
return hashlib.sha256(hashlib.sha256(bytes.fromhex(tx)).digest()).digest()[::-1].hex()
def tx_compute_merkle_root(tx_hashes):
"""
Compute the Merkle Root of a list of transaction hashes.
Arguments:
tx_hashes (list): list of transaction hashes as ASCII hex strings
Returns:
string: merkle root as a big endian ASCII hex string
"""
# Convert list of ASCII hex transaction hashes into bytes
tx_hashes = [bytes.fromhex(tx_hash)[::-1] for tx_hash in tx_hashes]
# Iteratively compute the merkle root hash
while len(tx_hashes) > 1:
# Duplicate last hash if the list is odd
if len(tx_hashes) % 2 != 0:
tx_hashes.append(tx_hashes[-1])
tx_hashes_new = []
for i in range(len(tx_hashes) // 2):
# Concatenate the next two
concat = tx_hashes.pop(0) + tx_hashes.pop(0)
# Hash them
concat_hash = hashlib.sha256(hashlib.sha256(concat).digest()).digest()
# Add them to our working list
tx_hashes_new.append(concat_hash)
tx_hashes = tx_hashes_new
# Format the root in big endian ascii hex
return tx_hashes[0][::-1].hex()
################################################################################
# Block Preparation Functions
################################################################################
def block_make_header(block):
"""
Make the block header.
Arguments:
block (dict): block template
Returns:
bytes: block header
"""
header = b""
# Version
header += struct.pack("<L", block['version'])
# Previous Block Hash
header += bytes.fromhex(block['previousblockhash'])[::-1]
# Merkle Root Hash
header += bytes.fromhex(block['merkleroot'])[::-1]
# Time
header += struct.pack("<L", block['curtime'])
# Target Bits
header += bytes.fromhex(block['bits'])[::-1]
# Nonce
header += struct.pack("<L", block['nonce'])
return header
def block_compute_raw_hash(header):
"""
Compute the raw SHA256 double hash of a block header.
Arguments:
header (bytes): block header
Returns:
bytes: block hash
"""
return hashlib.sha256(hashlib.sha256(header).digest()).digest()[::-1]
def block_bits2target(bits):
"""
Convert compressed target (block bits) encoding to target value.
Arguments:
bits (string): compressed target as an ASCII hex string
Returns:
bytes: big endian target
"""
# Bits: 1b0404cb
# 1b left shift of (0x1b - 3) bytes
# 0404cb value
bits = bytes.fromhex(bits)
shift = bits[0] - 3
value = bits[1:]
# Shift value to the left by shift
target = value + b"\x00" * shift
# Add leading zeros
target = b"\x00" * (32 - len(target)) + target
return target
def block_make_submit(block):
"""
Format a solved block into the ASCII hex submit format.
Arguments:
block (dict): block template with 'nonce' and 'hash' populated
Returns:
string: block submission as an ASCII hex string
"""
submission = ""
# Block header
submission += block_make_header(block).hex()
# Number of transactions as a varint
submission += int2varinthex(len(block['transactions']))
# Concatenated transactions data
for tx in block['transactions']:
submission += tx['data']
return submission
################################################################################
# Block Miner
################################################################################
def block_mine(block_template, coinbase_message, extranonce_start, address, timeout=None, debugnonce_start=False):
"""
Mine a block.
Arguments:
block_template (dict): block template
coinbase_message (bytes): binary string for coinbase script
extranonce_start (int): extranonce offset for coinbase script
address (string): Base58 Bitcoin address for block reward
Timeout:
timeout (float): timeout in seconds
debugnonce_start (int): nonce start for testing purposes
Returns:
(block submission, hash rate) on success,
(None, hash rate) on timeout or nonce exhaustion.
"""
# Add an empty coinbase transaction to the block template transactions
coinbase_tx = {}
block_template['transactions'].insert(0, coinbase_tx)
# Add a nonce initialized to zero to the block template
block_template['nonce'] = 0
# Compute the target hash
target_hash = block_bits2target(block_template['bits'])
target_hash = bytes.fromhex("000000f000000000ff0000000000000000000000000000000000000000000000")
# Mark our mine start time
time_start = time.time()
# Initialize our running average of hashes per second
hash_rate, hash_rate_count = 0.0, 0
# Loop through the extranonce
extranonce = extranonce_start
while extranonce <= 0xffffffff:
# Update the coinbase transaction with the new extra nonce
coinbase_script = coinbase_message + int2lehex(extranonce, 4)
coinbase_tx['data'] = tx_make_coinbase(coinbase_script, address, block_template['coinbasevalue'], block_template['height'])
coinbase_tx['hash'] = tx_compute_hash(coinbase_tx['data'])
# Recompute the merkle root
block_template['merkleroot'] = tx_compute_merkle_root([tx['hash'] for tx in block_template['transactions']])
# Reform the block header
block_header = block_make_header(block_template)
time_stamp = time.time()
# Loop through the nonce
nonce = 0 if not debugnonce_start else debugnonce_start
while nonce <= 0xffffffff:
# Update the block header with the new 32-bit nonce
block_header = block_header[0:76] + nonce.to_bytes(4, byteorder='little')
# Recompute the block hash
block_hash = block_compute_raw_hash(block_header)
# Check if it the block meets the target hash
if block_hash < target_hash:
block_template['nonce'] = nonce
block_template['hash'] = block_hash.hex()
hash_rate = time.time() - time_start
return (block_template, hash_rate)
# Measure hash rate and check timeout
if nonce > 0 and nonce % 1048576 == 0:
hash_rate = hash_rate + ((1048576 / (time.time() - time_stamp)) - hash_rate) / (hash_rate_count + 1)
hash_rate_count += 1
time_stamp = time.time()
# If our mine time expired, return none
if timeout and (time_stamp - time_start) > timeout:
hash_rate = time.time() - time_start
return (None, hash_rate)
nonce += 1
extranonce += 1
# If we ran out of extra nonces, return none
hash_rate = time.time() - time_start
return (None, hash_rate)
################################################################################
# Standalone Bitcoin Miner, Single-threaded
################################################################################
def standalone_miner(coinbase_message, address):
fo = open("foo.txt", "w")
flag = 0
sum = 0
while True:
block_template = rpc_getblocktemplate()
print("Mining block template, height {:d}...".format(block_template['height']))
mined_block, time_stamp = block_mine(block_template, coinbase_message, 0, address, timeout=120)
#print(" {:.4f} KH/s\n".format(hash_rate / (120*1000.0)))
if mined_block:
print("Solved a block! Block hash: {}".format(mined_block['hash']))
f = open("out.txt", "a")
print("Solved a block! Block hash: {}".format(mined_block['hash']), file = f)
submission = block_make_submit(mined_block)
print("Submitting:", submission, "\n")
response = rpc_submitblock(submission)
#break
if response is not None:
print("Submission Error: {}".format(response))
break
print(time_stamp)
sum = sum + time_stamp
fo.write(str(time_stamp))
fo.write("\n")
flag = flag + 1
if flag >= 100 :
break
fo.write("sum:")
fo.write(str(sum))
fo.write("\n")
fo.write("avg:")
fo.write(str(sum/flag))
fo.write("\n")
fo.close()
if __name__ == "__main__":
'''
if len(sys.argv) < 3:
print("Usage: {:s} <coinbase message> <block reward address>".format(sys.argv[0]))
sys.exit(1)
'''
#standalone_miner(sys.argv[1].encode().hex(), sys.argv[2])
standalone_miner("test".encode().hex(), "bc1qxzpkwm59303hupgww470ppugscaj3vdfcgwtuc")
Dynamic Programming Code
# ntgbtminer - vsergeev - https://github.com/vsergeev/ntgbtminer
#
# No Thrils GetBlockTemplate Bitcoin Miner
#
# This is mostly a demonstration of the GBT protocol.
# It mines at a measly 550 KH/s on my computer, but
# with a whole lot of spirit ;)
#
import urllib.request
import urllib.error
import urllib.parse
import base64
import json
import hashlib
import struct
import random
import time
import os
import sys
import numpy as np
# JSON-HTTP RPC Configuration
# This will be particular to your local ~/.bitcoin/bitcoin.conf
'''
RPC_URL = os.environ.get("RPC_URL", "http://127.0.0.1:8332")
RPC_USER = os.environ.get("RPC_USER", "admin1")
RPC_PASS = os.environ.get("RPC_PASS", "123")
'''
RPC_URL = os.environ.get("RPC_URL", "http://172.17.0.2:19001")
RPC_USER = os.environ.get("RPC_USER", "admin1")
RPC_PASS = os.environ.get("RPC_PASS", "123")
################################################################################
# Bitcoin Daemon JSON-HTTP RPC
################################################################################
def rpc(method, params=None):
"""
Make an RPC call to the Bitcoin Daemon JSON-HTTP server.
Arguments:
method (string): RPC method
params: RPC arguments
Returns:
object: RPC response result.
"""
#随机生成矿工ID
rpc_id = random.getrandbits(32)
#设置ID,method为getblocktemplate(调用的接口),参数为: [{"rules": ["segwit"]}]
data = json.dumps({"id": rpc_id, "method": method, "params": params}).encode()
#生成认证字符串
auth = base64.encodebytes((RPC_USER + ":" + RPC_PASS).encode()).decode().strip()
#发送请求
request = urllib.request.Request(RPC_URL, data, {"Authorization": "Basic {:s}".format(auth)})
#获取返回的数据包
with urllib.request.urlopen(request) as f:
response = json.loads(f.read())
#判断是否有错误
if response['id'] != rpc_id:
raise ValueError("Invalid response id: got {}, expected {:u}".format(response['id'], rpc_id))
elif response['error'] is not None:
raise ValueError("RPC error: {:s}".format(json.dumps(response['error'])))
#返回收到的数据
return response['result']
################################################################################
# Bitcoin Daemon RPC Call Wrappers
################################################################################
def rpc_getblocktemplate():
try:
return rpc("getblocktemplate", [{"rules": ["segwit"]}])
except ValueError:
return {}
def rpc_submitblock(block_submission):
return rpc("submitblock", [block_submission])
################################################################################
# Representation Conversion Utility Functions
################################################################################
def int2lehex(value, width):
"""
Convert an unsigned integer to a little endian ASCII hex string.
Args:
value (int): value
width (int): byte width
Returns:
string: ASCII hex string
"""
return value.to_bytes(width, byteorder='little').hex()
def int2varinthex(value):
"""
Convert an unsigned integer to little endian varint ASCII hex string.
Args:
value (int): value
Returns:
string: ASCII hex string
"""
if value < 0xfd:
return int2lehex(value, 1)
elif value <= 0xffff:
return "fd" + int2lehex(value, 2)
elif value <= 0xffffffff:
return "fe" + int2lehex(value, 4)
else:
return "ff" + int2lehex(value, 8)
def bitcoinaddress2hash160(addr):
"""
Convert a Base58 Bitcoin address to its Hash-160 ASCII hex string.
Args:
addr (string): Base58 Bitcoin address
Returns:
string: Hash-160 ASCII hex string
"""
table = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
hash160 = 0
addr = addr[::-1]
for i, c in enumerate(addr):
hash160 += (58 ** i) * table.find(c)
# Convert number to 50-byte ASCII Hex string
hash160 = "{:050x}".format(hash160)
# Discard 1-byte network byte at beginning and 4-byte checksum at the end
return hash160[2:50 - 8]
################################################################################
# Transaction Coinbase and Hashing Functions
################################################################################
def tx_encode_coinbase_height(height):
"""
Encode the coinbase height, as per BIP 34:
https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki
Arguments:
height (int): height of the mined block
Returns:
string: encoded height as an ASCII hex string
"""
width = (height.bit_length() + 7) // 8
return bytes([width]).hex() + int2lehex(height, width)
def tx_make_coinbase(coinbase_script, address, value, height):
"""
Create a coinbase transaction.
Arguments:
coinbase_script (string): arbitrary script as an ASCII hex string
address (string): Base58 Bitcoin address
value (int): coinbase value
height (int): mined block height
Returns:
string: coinbase transaction as an ASCII hex string
"""
# See https://en.bitcoin.it/wiki/Transaction
coinbase_script = tx_encode_coinbase_height(height) + coinbase_script
# Create a pubkey script
# OP_DUP OP_HASH160 <len to push> <pubkey> OP_EQUALVERIFY OP_CHECKSIG
pubkey_script = "76" + "a9" + "14" + bitcoinaddress2hash160(address) + "88" + "ac"
tx = ""
# version
tx += "01000000"
# in-counter
tx += "01"
# input[0] prev hash
tx += "0" * 64
# input[0] prev seqnum
tx += "ffffffff"
# input[0] script len
tx += int2varinthex(len(coinbase_script) // 2)
# input[0] script
tx += coinbase_script
# input[0] seqnum
tx += "ffffffff"
# out-counter
tx += "01"
# output[0] value
tx += int2lehex(value, 8)
# output[0] script len
tx += int2varinthex(len(pubkey_script) // 2)
# output[0] script
tx += pubkey_script
# lock-time
tx += "00000000"
return tx
def tx_compute_hash(tx):
"""
Compute the SHA256 double hash of a transaction.
Arguments:
tx (string): transaction data as an ASCII hex string
Return:
string: transaction hash as an ASCII hex string
"""
return hashlib.sha256(hashlib.sha256(bytes.fromhex(tx)).digest()).digest()[::-1].hex()
def tx_compute_merkle_root(tx_hashes):
"""
Compute the Merkle Root of a list of transaction hashes.
Arguments:
tx_hashes (list): list of transaction hashes as ASCII hex strings
Returns:
string: merkle root as a big endian ASCII hex string
"""
# Convert list of ASCII hex transaction hashes into bytes
tx_hashes = [bytes.fromhex(tx_hash)[::-1] for tx_hash in tx_hashes]
# Iteratively compute the merkle root hash
while len(tx_hashes) > 1:
# Duplicate last hash if the list is odd
if len(tx_hashes) % 2 != 0:
tx_hashes.append(tx_hashes[-1])
tx_hashes_new = []
for i in range(len(tx_hashes) // 2):
# Concatenate the next two
concat = tx_hashes.pop(0) + tx_hashes.pop(0)
# Hash them
concat_hash = hashlib.sha256(hashlib.sha256(concat).digest()).digest()
# Add them to our working list
tx_hashes_new.append(concat_hash)
tx_hashes = tx_hashes_new
# Format the root in big endian ascii hex
return tx_hashes[0][::-1].hex()
################################################################################
# Block Preparation Functions
################################################################################
def block_make_header(block):
"""
Make the block header.
Arguments:
block (dict): block template
Returns:
bytes: block header
"""
header = b""
# Version
header += struct.pack("<L", block['version'])
# Previous Block Hash
header += bytes.fromhex(block['previousblockhash'])[::-1]
# Merkle Root Hash
header += bytes.fromhex(block['merkleroot'])[::-1]
# Time
header += struct.pack("<L", block['curtime'])
# Target Bits
header += bytes.fromhex(block['bits'])[::-1]
# Nonce
header += struct.pack("<L", block['nonce'])
return header
def block_compute_raw_hash(header):
"""
Compute the raw SHA256 double hash of a block header.
Arguments:
header (bytes): block header
Returns:
bytes: block hash
"""
return hashlib.sha256(hashlib.sha256(header).digest()).digest()[::-1]
def block_bits2target(bits):
"""
Convert compressed target (block bits) encoding to target value.
Arguments:
bits (string): compressed target as an ASCII hex string
Returns:
bytes: big endian target
"""
# Bits: 1b0404cb
# 1b left shift of (0x1b - 3) bytes
# 0404cb value
bits = bytes.fromhex(bits)
shift = bits[0] - 3
value = bits[1:]
# Shift value to the left by shift
target = value + b"\x00" * shift
# Add leading zeros
target = b"\x00" * (32 - len(target)) + target
return target
def block_make_submit(block):
"""
Format a solved block into the ASCII hex submit format.
Arguments:
block (dict): block template with 'nonce' and 'hash' populated
Returns:
string: block submission as an ASCII hex string
"""
submission = ""
# Block header
submission += block_make_header(block).hex()
# Number of transactions as a varint
submission += int2varinthex(len(block['transactions']))
# Concatenated transactions data
for tx in block['transactions']:
submission += tx['data']
return submission
################################################################################
# Block Miner
################################################################################
#统计整数中1的个数
def countnum(block_hash, target_hash_num):
#print(block_hash.hex())
#target_hash_num = target_hash_num + 2
nonce_byte = bin(int(block_hash.hex(),16))[2:]
nonce_byte= nonce_byte.zfill(256)
nonce_byte = nonce_byte[0:target_hash_num]
nonce_byte = nonce_byte.count("1")
#print(nonce_byte)
#sys.exit()
#count("1")
'''
count = 0
for i in range(0,len):
if(nonce&(0x00000001<<i) != 0):
count = count + 1
'''
return nonce_byte
'''
统计难度值之前有几个0
'''
def count_target(target_hash) :
#target_hash_t = target_hash[::-1]
#print(target_hash.hex())
#a=bin(int(target_hash.hex()[::-1],16))
a=bin(int(target_hash.hex(),16))
#print(a)
a=a[2:]
a = a.zfill(256)[::-1]
#print(a)
target_hash_num = 0
#print(len(a))
len_a = len(a)
for i in range(1, len_a+1) :
#print(i)
#print( ":" + a[-i])
if a[-i] == "1":
target_hash_num = i - 1
break
#print(target_hash_num)
return target_hash_num
################################################################################
# Block Miner
################################################################################
def block_mine(block_template, coinbase_message, extranonce_start, address, timeout=None, debugnonce_start=False):
"""
Mine a block.
Arguments:
block_template (dict): block template
coinbase_message (bytes): binary string for coinbase script
extranonce_start (int): extranonce offset for coinbase script
address (string): Base58 Bitcoin address for block reward
Timeout:
timeout (float): timeout in seconds
debugnonce_start (int): nonce start for testing purposes
Returns:
(block submission, hash rate) on success,
(None, hash rate) on timeout or nonce exhaustion.
"""
# Add an empty coinbase transaction to the block template transactions
coinbase_tx = {}
block_template['transactions'].insert(0, coinbase_tx)
# Add a nonce initialized to zero to the block template
block_template['nonce'] = 0
# Compute the target hash
target_hash = block_bits2target(block_template['bits'])
target_hash = bytes.fromhex("000000f000000000ff0000000000000000000000000000000000000000000000")
target_hash_num = count_target(target_hash)
# Mark our mine start time
time_start = time.time()
# Initialize our running average of hashes per second
hash_rate, hash_rate_count = 0.0, 0
# Loop through the extranonce
extranonce = extranonce_start
while extranonce <= 0xffffffff:
# Update the coinbase transaction with the new extra nonce
coinbase_script = coinbase_message + int2lehex(extranonce, 4)
coinbase_tx['data'] = tx_make_coinbase(coinbase_script, address, block_template['coinbasevalue'], block_template['height'])
coinbase_tx['hash'] = tx_compute_hash(coinbase_tx['data'])
# Recompute the merkle root
block_template['merkleroot'] = tx_compute_merkle_root([tx['hash'] for tx in block_template['transactions']])
# Reform the block header
block_header = block_make_header(block_template)
time_stamp = time.time()
# Loop through the nonce
nonce = 0 if not debugnonce_start else debugnonce_start
while nonce <= 0xffffffff:
block_header = block_header[0:76] + nonce.to_bytes(4, byteorder='little')
# Recompute the block hash
block_hash = block_compute_raw_hash(block_header)
# Check if it the block meets the target hash
if block_hash < target_hash:
block_template['nonce'] = nonce
block_template['hash'] = block_hash.hex()
time_stamp = time.time() - time_start
return (block_template, time_stamp)
#print("nonce: %x " %(nonce))
countone_now = countnum(block_hash, target_hash_num)
if countone_now >= 18 :
#print("Ship: %x " %(nonce))
nonce = nonce + 0x10000
hash_rate = hash_rate + 1
else :
#print("target: %d ; current: %d " %(target_hash_num, target_hash_num-countone_now))
second_nonce = 0
hash_rate = hash_rate + 0xffff
while second_nonce <= 0xffff:
block_header = block_header[0:76] + nonce.to_bytes(4, byteorder='little')
# Recompute the block hash
block_hash = block_compute_raw_hash(block_header)
# Check if it the block meets the target hash
if block_hash < target_hash:
block_template['nonce'] = nonce
block_template['hash'] = block_hash.hex()
time_stamp = time.time() - time_start
return (block_template, time_stamp)
nonce += 1
second_nonce += 1
#print("Second: %x " %(nonce))
#nonce += 1
extranonce += 1
# Measure hash rate and check timeout
if extranonce%10 == 0 :
if extranonce%200 == 0 :
print("New extranonce:%d" %(extranonce))
time_stamp = time.time()
# If our mine time expired, return none
if timeout and (time_stamp - time_start) > timeout:
time_stamp = time.time() - time_start
return (None, time_stamp)
# If we ran out of extra nonces, return none
print("Return None!")
time_stamp = time.time() - time_start
return (None, time_stamp)
################################################################################
# Standalone Bitcoin Miner, Single-threaded
################################################################################
def standalone_miner(coinbase_message, address):
fo = open("foo.txt", "w")
flag = 0
sum = 0
while True:
block_template = rpc_getblocktemplate()
print("Mining block template, height {:d}...".format(block_template['height']))
mined_block, time_stamp = block_mine(block_template, coinbase_message, 0, address, timeout=120)
#print(" {:.4f} KH/s\n".format(hash_rate / (120*1000.0)))
if mined_block:
print("Solved a block! Block hash: {}".format(mined_block['hash']))
f = open("out.txt", "a")
print("Solved a block! Block hash: {}".format(mined_block['hash']), file = f)
submission = block_make_submit(mined_block)
print("Submitting:", submission, "\n")
response = rpc_submitblock(submission)
#break
if response is not None:
print("Submission Error: {}".format(response))
break
print(time_stamp)
sum = sum + time_stamp
fo.write(str(time_stamp))
fo.write("\n")
flag = flag + 1
if flag >= 100 :
break
fo.write("sum:")
fo.write(str(sum))
fo.write("\n")
fo.write("avg:")
fo.write(str(sum/flag))
fo.write("\n")
fo.close()
if __name__ == "__main__":
'''
if len(sys.argv) < 3:
print("Usage: {:s} <coinbase message> <block reward address>".format(sys.argv[0]))
sys.exit(1)
'''
#standalone_miner(sys.argv[1].encode().hex(), sys.argv[2])
standalone_miner("test".encode().hex(), "bc1qxzpkwm59303hupgww470ppugscaj3vdfcgwtuc")
浙公网安备 33010602011771号