4 logging.basicConfig(level=logging.DEBUG)
6 from binascii import b2a_hex
11 import jsonrpc_getwork
14 from struct import pack
18 from util import RejectedShare
21 import jsonrpc.authproxy
22 jsonrpc.authproxy.USER_AGENT = 'gmp-proxy/0.1'
26 pool = jsonrpc.ServiceProxy(sys.argv[1])
29 currentwork = [None, 0, 0]
32 coinbase = bytes.fromhex(mp['coinbasetxn'])
33 cbtxn = bitcoin.txn.Txn(coinbase)
35 cbtxn.originalCB = cbtxn.getCoinbase()
36 txnlist = [cbtxn,] + list(map(bitcoin.txn.Txn, map(bytes.fromhex, mp['transactions'])))
37 merkleTree = merkletree.MerkleTree(txnlist)
39 prevBlock = bytes.fromhex(mp['previousblockhash'])[::-1]
40 bits = bytes.fromhex(mp['bits'])[::-1]
42 MRD = (merkleRoot, merkleTree, coinbase, prevBlock, bits, rollPrevBlk, mp)
43 if 'coinbase/append' in mp.get('mutable', ()):
44 currentwork[:] = (MRD, time(), 0)
51 if currentwork[1] < now - 45:
52 mp = pool.getmemorypool()
58 (merkleRoot, merkleTree, coinbase, prevBlock, bits, rollPrevBlk, mp) = MRD
59 cbtxn = merkleTree.data[0]
60 coinbase = cbtxn.originalCB + pack('>Q', currentwork[2]).lstrip(b'\0')
61 if len(coinbase) > 100:
62 if len(cbtxn.originalCB) > 100:
63 raise RuntimeError('Pool gave us a coinbase that is too long!')
66 cbtxn.setCoinbase(coinbase)
68 merkleRoot = merkleTree.merkleRoot()
69 MRD = (merkleRoot, merkleTree, coinbase, prevBlock, bits, rollPrevBlk, mp)
72 def MakeWork(username):
74 (merkleRoot, merkleTree, coinbase, prevBlock, bits, rollPrevBlk, mp) = MRD
75 timestamp = pack('<L', int(time()))
76 hdr = b'\1\0\0\0' + prevBlock + merkleRoot + timestamp + bits + b'ppmg'
77 worklog[hdr[4:68]] = (MRD, time())
80 def SubmitShare(share):
81 hdr = share['data'][:80]
84 raise RejectedShare('LOCAL unknown-work')
85 (MRD, issueT) = worklog[k]
86 (merkleRoot, merkleTree, coinbase, prevBlock, bits, rollPrevBlk, mp) = MRD
87 cbtxn = merkleTree.data[0]
88 cbtxn.setCoinbase(coinbase)
90 blkdata = bitcoin.varlen.varlenEncode(len(merkleTree.data))
91 for txn in merkleTree.data:
93 data = b2a_hex(hdr + blkdata).decode('utf8')
96 a.append({'workid': mp['workid']})
97 rejReason = pool.submitblock(*a)
98 if not rejReason is None:
100 raise RejectedShare('pool-' + rejReason)
105 # FIXME: get path from gmp!
106 pool = jsonrpc.ServiceProxy(sys.argv[1].rstrip('/') + '/LP')
109 mp = pool.getmemorypool()
111 except socket.timeout:
113 jsonrpc_getwork._CheckForDupesHACK = {}
115 server.wakeLongpoll()
118 LPTrackReal = jsonrpcserver.JSONRPCHandler.LPTrack
122 if LPThread is None or not LPThread.is_alive():
123 LPThread = threading.Thread(target=HandleLP)
124 LPThread.daemon = True
126 return LPTrackReal(self)
127 jsonrpcserver.JSONRPCHandler.LPTrack = LPHook.LPTrack
129 server = jsonrpcserver.JSONRPCServer()
130 server.getBlockHeader = MakeWork
131 server.receiveShare = SubmitShare
132 jsonrpcserver.JSONRPCListener(server, ('', 9332))
134 server.serve_forever()