diff --git a/contrib/merged-mine-proxy b/contrib/merged-mine-proxy index d3d8dd82ac73..4c382152fa17 100755 --- a/contrib/merged-mine-proxy +++ b/contrib/merged-mine-proxy @@ -12,15 +12,19 @@ import sys import traceback import json import base64 +import socket + from datetime import datetime -from twisted.internet import defer, reactor -from twisted.web import server, resource, client +from twisted.internet import defer, reactor, threads +from twisted.web import server, resource from twisted.internet.error import ConnectionRefusedError import twisted.internet.error from urlparse import urlsplit +import httplib +import thread -__version__ = '0.2' +__version__ = '0.2.2' ''' merge-mine-proxy @@ -50,6 +54,10 @@ logger.setLevel(logging.DEBUG) def reverse_chunks(s, l): return ''.join(reversed([s[x:x+l] for x in xrange(0, len(s), l)])) +def getresponse(http, path, postdata, headers): + http.request(path, 'POST', postdata, headers) + return http.getresponse().read() + class Error(Exception): def __init__(self, code, message, data=''): if not isinstance(code, int): @@ -72,12 +80,24 @@ class Proxy(object): auth = None if netloc.find('@') >= 0: (auth, netloc) = netloc.split("@") - self._url = "%s://%s/%s" % (schema, netloc, path) + if path == "": + path = "/" + self._url = "%s://%s%s" % (schema, netloc, path) + self._path = path self._auth = auth + self._netloc = netloc + self._http = None - @defer.inlineCallbacks def callRemote(self, method, *params): try: + if self._http is None: + (host, port) = self._netloc.split(":") + self._http = httplib.HTTPConnection(host, port) + try: + self._http.connect() + except socket.error: + raise httplib.HTTPException() + id_ = 0 headers = { @@ -86,29 +106,25 @@ class Proxy(object): if self._auth is not None: headers['Authorization'] = 'Basic ' + base64.b64encode(self._auth) resp = None - try: - resp = (yield client.getPage( - url=self._url, - method='POST', - headers=headers, - postdata=json.dumps({ - 'jsonrpc': '2.0', - 'method': method, - 'params': params, - 'id': id_, - }), - )) - except twisted.web.error.Error, e: - resp = e.response - - resp = json.loads(resp) + + postdata=json.dumps({ + 'jsonrpc': '2.0', + 'method': method, + 'params': params, + 'id': id_, + }) + + content = getresponse(self._http, self._path, postdata, headers) + + resp = json.loads(content) if resp['id'] != id_: raise ValueError('invalid id') if 'error' in resp and resp['error'] is not None: raise Error(resp['error']['code'], resp['error']['message']) - defer.returnValue(resp['result']) - except ConnectionRefusedError: + return resp['result'] + except httplib.HTTPException: + self._http = None logger.error("Could not connect to %s", self._url) raise Error(-32099, u'Could not connect to backend', self._url) @@ -222,8 +238,10 @@ class Listener(Server): self.merkle_tree_queue = [] self.merkle_trees = {} self.rewrite_target = None - if rewrite_target: + if rewrite_target == 1: self.rewrite_target = reverse_chunks("00000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffe", 2) + elif rewrite_target == 100: + self.rewrite_target = reverse_chunks("00000000028f5c28000000000000000000000000000000000000000000000000", 2) if merkle_size > 255: raise ValueError('merkle size up to 255') self.putChild('', self) @@ -280,8 +298,36 @@ class Listener(Server): reactor.callLater(AUX_UPDATE_INTERVAL, self.update_aux_process) self.update_auxs() + def rpc_getaux(self, data=None): + ''' Use this rpc call to get the aux chain merkle root and aux target. Pool software + can then call getworkaux(aux) instead of going through this proxy. It is enough to call this + once a second. + ''' + try: + # Get aux based on the latest tree + merkle_root = self.merkle_tree_queue[-1] + # nonce = 0, one byte merkle size + aux = merkle_root + ("%02x000000" % self.merkle_size) + "00000000" + result = {'aux': aux} + + if self.rewrite_target: + result['aux_target'] = self.rewrite_target + else: + # Find highest target + targets = [] + targets.extend(self.aux_targets) + targets.sort() + result['aux_target'] = reverse_chunks(targets[-1], 2) # fix endian + return result + except Exception: + logger.error(traceback.format_exc()) + raise + @defer.inlineCallbacks def rpc_getwork(self, data=None): + ''' This rpc call generates bitcoin miner compatible work from data received + from the aux and parent chains. + ''' try: if data: # Submit work upstream @@ -400,7 +446,10 @@ def run(): dest='merkle_size') parser.add_argument('-r', '--rewrite-target', help='rewrite target difficulty to 1', - action='store_true', default=False, + action='store_const', const=1, default=False, + dest='rewrite_target') + parser.add_argument('-R', '--rewrite-target-100', help='rewrite target difficulty to 100', + action='store_const', const=100, default=False, dest='rewrite_target') parser.add_argument('-i', '--pidfile', metavar='PID', type=str, action='store', default=None, dest='pidfile') diff --git a/src/auxpow.cpp b/src/auxpow.cpp index 2131b0c7ccb4..620504f05c14 100644 --- a/src/auxpow.cpp +++ b/src/auxpow.cpp @@ -20,6 +20,9 @@ void RemoveMergedMiningHeader(vector& vchAux) bool CAuxPow::Check(uint256 hashAuxBlock, int nChainID) { + if (nIndex != 0) + return error("AuxPow is not a generate"); + if (!fTestNet && parentBlock.GetChainID() == nChainID) return error("Aux POW parent has our chain ID"); diff --git a/src/serialize.h b/src/serialize.h index dcf6f548371c..d26ac771e810 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -33,7 +33,7 @@ class CDataStream; class CAutoFile; static const unsigned int MAX_SIZE = 0x02000000; -static const int VERSION = 32463; +static const int VERSION = 32464; static const char* pszSubVer = ""; static const bool VERSION_IS_BETA = true;