mirror of
git://projects.qi-hardware.com/openwrt-packages.git
synced 2025-04-21 12:27:27 +03:00
new pakcage: icarus python miner software
This commit is contained in:
323
icarus-miner/data/root/queue_ver/miner.py
Executable file
323
icarus-miner/data/root/queue_ver/miner.py
Executable file
@@ -0,0 +1,323 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# by teknohog
|
||||
|
||||
# Python wrapper for my serial port FPGA Bitcoin miners
|
||||
|
||||
from jsonrpc import ServiceProxy
|
||||
from time import ctime, sleep, time
|
||||
from serial import Serial
|
||||
from threading import Thread, Event, Lock
|
||||
from Queue import Queue
|
||||
from optparse import OptionParser
|
||||
|
||||
def stats(count, starttime):
|
||||
# 2**32 hashes per share (difficulty 1)
|
||||
mhshare = 4294.967296
|
||||
|
||||
s = sum(count)
|
||||
tdelta = time() - starttime
|
||||
rate = s * mhshare / tdelta
|
||||
|
||||
# This is only a rough estimate of the true hash rate,
|
||||
# particularly when the number of events is low. However, since
|
||||
# the events follow a Poisson distribution, we can estimate the
|
||||
# standard deviation (sqrt(n) for n events). Thus we get some idea
|
||||
# on how rough an estimate this is.
|
||||
|
||||
# s should always be positive when this function is called, but
|
||||
# checking for robustness anyway
|
||||
if s > 0:
|
||||
stddev = rate / s**0.5
|
||||
else:
|
||||
stddev = 0
|
||||
|
||||
return "[%i accepted, %i failed, %.2f +/- %.2f Mhash/s]" % (count[0], count[1], rate, stddev)
|
||||
|
||||
class Reader(Thread):
|
||||
def __init__(self):
|
||||
Thread.__init__(self)
|
||||
|
||||
self.daemon = True
|
||||
|
||||
# flush the input buffer
|
||||
#ser.read(1000)
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
nonce = ser.read(4)
|
||||
|
||||
if len(nonce) == 4:
|
||||
# Keep this order, because writer.block will be
|
||||
# updated due to the golden event.
|
||||
submitter = Submitter(writer.block, nonce)
|
||||
submitter.start()
|
||||
if options.debug:
|
||||
print("raise golden event\n")
|
||||
golden.set()
|
||||
|
||||
|
||||
class Writer(Thread):
|
||||
def __init__(self):
|
||||
Thread.__init__(self)
|
||||
|
||||
# Keep something sensible available while waiting for the
|
||||
# first getwork
|
||||
#self.block = "0" * 256
|
||||
#self.midstate = "0" * 64
|
||||
|
||||
# This will produce nonce 063c5e01 -> debug by using a bogus URL
|
||||
self.block = "0000000120c8222d0497a7ab44a1a2c7bf39de941c9970b1dc7cdc400000079700000000e88aabe1f353238c668d8a4df9318e614c10c474f8cdf8bc5f6397b946c33d7c4e7242c31a098ea500000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"
|
||||
self.midstate = "33c5bf5751ec7f7e056443b5aee3800331432c83f404d9de38b94ecbf907b92d"
|
||||
|
||||
self.daemon = True
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
result =0
|
||||
#try:
|
||||
# work = bitcoin.getwork()
|
||||
# self.block = work['data']
|
||||
# self.midstate = work['midstate']
|
||||
#except:
|
||||
# print("RPC getwork error")
|
||||
# In this case, keep crunching with the old data. It will get
|
||||
# stale at some point, but it's better than doing nothing.
|
||||
|
||||
# Just a reminder of how Python slices work in reverse
|
||||
#rdata = self.block.decode('hex')[::-1]
|
||||
#rdata2 = rdata[32:64]
|
||||
work = wq.read_work_queue()
|
||||
self.block = work['data']
|
||||
self.midstate = work['midstate']
|
||||
#print("push work to miner")
|
||||
rdata2 = self.block.decode('hex')[95:63:-1]
|
||||
|
||||
rmid = self.midstate.decode('hex')[::-1]
|
||||
|
||||
payload = rmid + rdata2
|
||||
|
||||
ser.write(payload)
|
||||
result = golden.wait(options.askrate)
|
||||
|
||||
if result:
|
||||
golden.clear()
|
||||
if options.debug:
|
||||
print("clear golden event")
|
||||
|
||||
class WorkQueue:
|
||||
def __init__(self, max_num):
|
||||
self.max_num = max_num+1
|
||||
self.ptr = 0
|
||||
self.ptr_tobe = 0;
|
||||
self.tail = 0
|
||||
self.in_wr = 0;
|
||||
self.work = {}
|
||||
self.work_queue = []
|
||||
for i in range(self.max_num):
|
||||
self.work_queue.append({})
|
||||
def get_from_server(self):
|
||||
get_success = 0
|
||||
while get_success != 1 :
|
||||
try:
|
||||
self.work_queue[self.ptr_tobe] = bitcoin.getwork()
|
||||
get_success = 1
|
||||
except:
|
||||
print("RPC getwork error")
|
||||
def is_full(self):
|
||||
ptr_mutex.acquire()
|
||||
full = (self.ptr + 1) % self.max_num == self.tail
|
||||
ptr_mutex.release()
|
||||
return full
|
||||
def write_work_queue(self):
|
||||
#print("update work queue")
|
||||
|
||||
ptr_mutex.acquire()
|
||||
if (self.ptr + 1) % self.max_num == self.tail:
|
||||
if options.debug:
|
||||
print("Queue is full")
|
||||
self.tail = (self.tail + 1) % self.max_num
|
||||
self.ptr_tobe = (self.ptr + 1) % self.max_num
|
||||
#print("write0:tail=", self.tail, "ptr_tobe=", self.ptr_tobe, "ptr="+self.ptr)
|
||||
if options.debug:
|
||||
print "write0:tail=%d, ptr_tobe=%d, ptr=%d" % (self.tail, self.ptr_tobe, self.ptr)
|
||||
ptr_mutex.release()
|
||||
#self.work_queue[self.ptr] = bitcoin.getwork()
|
||||
|
||||
write_queue_mutex.acquire()
|
||||
self.get_from_server()
|
||||
write_queue_mutex.release()
|
||||
|
||||
ptr_mutex.acquire()
|
||||
if (self.ptr + 1) % self.max_num != self.ptr_tobe:
|
||||
self.work_queue[self.ptr] = self.work_queue[self.ptr_tobe]
|
||||
else:
|
||||
self.ptr = self.ptr_tobe
|
||||
if options.debug:
|
||||
print "write1:tail=%d, ptr_tobe=%d, ptr=%d" % (self.tail, self.ptr_tobe, self.ptr)
|
||||
#print("write1:tail="+self.tail+"ptr_tobe="+self.ptr_tobe+"ptr="+self.ptr)
|
||||
ptr_mutex.release()
|
||||
|
||||
#print("1update work queue")
|
||||
|
||||
def read_work_queue(self):
|
||||
ptr_mutex.acquire()
|
||||
#print("read from queue")
|
||||
if options.debug:
|
||||
print"read0:tail=%d, ptr=%d" % (self.tail, self.ptr)
|
||||
if self.ptr == self.tail:
|
||||
ptr_mutex.release()
|
||||
#print("Queue is empty")
|
||||
#print("1read from queue")
|
||||
write_queue_mutex.acquire()
|
||||
ptr_mutex.acquire()
|
||||
if self.ptr == self.tail:
|
||||
print("reader get queue")
|
||||
self.ptr_tobe = (self.ptr + 1) % self.max_num
|
||||
self.get_from_server()
|
||||
self.ptr = self.ptr_tobe
|
||||
write_queue_mutex.release()
|
||||
|
||||
self.work = self.work_queue[self.ptr]
|
||||
|
||||
if self.ptr == 0:
|
||||
self.ptr = self.max_num - 1
|
||||
else:
|
||||
self.ptr = self.ptr - 1
|
||||
#print("read0:tail="+self.tail+"ptr="+self.ptr)
|
||||
if options.debug:
|
||||
print"read1:tail=%d, ptr=%d" % (self.tail, self.ptr)
|
||||
|
||||
ptr_mutex.release()
|
||||
|
||||
return self.work
|
||||
|
||||
|
||||
class GetWorkQueue(Thread):
|
||||
def __init__(self):
|
||||
Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.delay = (options.askrate>>1)+1
|
||||
def run(self):
|
||||
while True:
|
||||
if options.debug:
|
||||
print("GetWorkQueue thread")
|
||||
wq.write_work_queue()
|
||||
#if (self.ptr + 1) % self.max_num == self.tail:
|
||||
if(wq.is_full()):
|
||||
sleep(4)
|
||||
if options.debug:
|
||||
print("queue is full, slow down request")
|
||||
else:
|
||||
if options.debug:
|
||||
print("****\nfill the work queue at speed\n****")
|
||||
#else:
|
||||
# sleep(2)
|
||||
|
||||
|
||||
class Submitter(Thread):
|
||||
def __init__(self, block, nonce):
|
||||
Thread.__init__(self)
|
||||
|
||||
self.block = block
|
||||
self.nonce = nonce
|
||||
|
||||
def run(self):
|
||||
# This thread will be created upon every submit, as they may
|
||||
# come in sooner than the submits finish.
|
||||
|
||||
print("Block found on " + ctime() + "\n")
|
||||
|
||||
if stride > 0:
|
||||
n = self.nonce.encode('hex')
|
||||
print(n + " % " + str(stride) + " = " + str(int(n, 16) % stride))
|
||||
elif options.debug:
|
||||
print(self.nonce.encode('hex'))
|
||||
|
||||
hrnonce = self.nonce[::-1].encode('hex')
|
||||
|
||||
data = self.block[:152] + hrnonce + self.block[160:]
|
||||
|
||||
try:
|
||||
result = bitcoin.getwork(data)
|
||||
print("Upstream result: " + str(result))
|
||||
print(self.nonce.encode('hex'))
|
||||
except:
|
||||
print("RPC send error")
|
||||
print(self.nonce.encode('hex'))
|
||||
# a sensible boolean for stats
|
||||
result = False
|
||||
|
||||
results_queue.put(result)
|
||||
|
||||
class Display_stats(Thread):
|
||||
def __init__(self):
|
||||
Thread.__init__(self)
|
||||
|
||||
self.count = [0, 0]
|
||||
self.starttime = time()
|
||||
self.daemon = True
|
||||
|
||||
print("Miner started on " + ctime())
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
result = results_queue.get()
|
||||
|
||||
if result:
|
||||
self.count[0] += 1
|
||||
else:
|
||||
self.count[1] += 1
|
||||
|
||||
print(stats(self.count, self.starttime))
|
||||
|
||||
results_queue.task_done()
|
||||
|
||||
parser = OptionParser()
|
||||
|
||||
parser.add_option("-a", "--askrate", dest="askrate", default=8, help="Seconds between getwork requests")
|
||||
|
||||
parser.add_option("-d", "--debug", dest="debug", default=False, action="store_true", help="Show each nonce result in hex")
|
||||
|
||||
parser.add_option("-m", "--miners", dest="miners", default=0, help="Show the nonce result remainder mod MINERS, to identify the node in a cluster")
|
||||
|
||||
parser.add_option("-u", "--url", dest="url", default="http://test_fpga_btc@hotmail.com:lzhjxntswc@pit.deepbit.net:8332/", help="URL for bitcoind or mining pool, typically http://user:password@host:8332/")
|
||||
|
||||
parser.add_option("-s", "--serial", dest="serial_port", default="com3", help="Serial port, e.g. /dev/ttyS0 on unix or COM1 in Windows")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
stride = int(options.miners)
|
||||
|
||||
golden = Event()
|
||||
|
||||
ptr_mutex = Lock();
|
||||
write_queue_mutex = Lock();
|
||||
|
||||
bitcoin = ServiceProxy(options.url)
|
||||
|
||||
results_queue = Queue()
|
||||
|
||||
ser = Serial(options.serial_port, 115200, timeout=options.askrate)
|
||||
|
||||
wq = WorkQueue(5)
|
||||
|
||||
reader = Reader()
|
||||
writer = Writer()
|
||||
get_work_queue = GetWorkQueue()
|
||||
disp = Display_stats()
|
||||
|
||||
get_work_queue.start()
|
||||
reader.start()
|
||||
writer.start()
|
||||
disp.start()
|
||||
|
||||
try:
|
||||
while True:
|
||||
# Threads are generally hard to interrupt. So they are left
|
||||
# running as daemons, and we do something simple here that can
|
||||
# be easily terminated to bring down the entire script.
|
||||
sleep(10000)
|
||||
except KeyboardInterrupt:
|
||||
print("Terminated")
|
||||
|
||||
Reference in New Issue
Block a user