X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=mining%2Fservice.py;h=30451d971d28206532a8b20818200d782b740a2a;hb=8a7474eb0eefdbc68e9b57371a68c25f33427f0d;hp=f3a68613010bcc1e60cb148f9015bf2d14db0cf4;hpb=1e086b3786e3708cb71205962d9db1684f2271f2;p=stratum-mining.git diff --git a/mining/service.py b/mining/service.py index f3a6861..30451d9 100644 --- a/mining/service.py +++ b/mining/service.py @@ -2,16 +2,13 @@ import binascii from twisted.internet import defer from stratum.services import GenericService, admin -from stratum.custom_exceptions import ServiceException from stratum.pubsub import Pubsub from interfaces import Interfaces from subscription import MiningSubscription +from lib.exceptions import SubmitException import stratum.logger log = stratum.logger.get_logger('mining') - -class SubmitException(ServiceException): - pass class MiningService(GenericService): '''This service provides public API for Stratum mining proxy @@ -29,26 +26,38 @@ class MiningService(GenericService): '''Connect this RPC call to 'bitcoind -blocknotify' for instant notification about new block on the network. See blocknotify.sh in /scripts/ for more info.''' + + log.info("New block notification received") Interfaces.template_registry.update_block() return True def authorize(self, worker_name, worker_password): '''Let authorize worker on this connection.''' - return Interfaces.worker_manager.authorize(worker_name, worker_password) - def subscribe(self): + session = self.connection_ref().get_session() + session.setdefault('authorized', {}) + + if Interfaces.worker_manager.authorize(worker_name, worker_password): + session['authorized'][worker_name] = worker_password + return True + + else: + if worker_name in session['authorized']: + del session['authorized'][worker_name] + return False + + def subscribe(self, *args): '''Subscribe for receiving mining jobs. This will return subscription details, extranonce1_hex and extranonce2_size''' extranonce1 = Interfaces.template_registry.get_new_extranonce1() extranonce2_size = Interfaces.template_registry.extranonce2_size - + extranonce1_hex = binascii.hexlify(extranonce1) + session = self.connection_ref().get_session() session['extranonce1'] = extranonce1 session['difficulty'] = 1 # Following protocol specs, default diff is 1 - extranonce1_hex = binascii.hexlify(extranonce1) - return Pubsub.subscribe(self.connection_ref(), MiningSubscription()) + (extranonce1_hex, extranonce2_size) ''' @@ -65,11 +74,17 @@ class MiningService(GenericService): log.info("LEN %.03f" % (time.time() - start)) return ret ''' - + def submit(self, worker_name, job_id, extranonce2, ntime, nonce): '''Try to solve block candidate using given parameters.''' session = self.connection_ref().get_session() + session.setdefault('authorized', {}) + + # Check if worker is authorized to submit shares + if not Interfaces.worker_manager.authorize(worker_name, + session['authorized'].get(worker_name)): + raise SubmitException("Worker is not authorized") # Check if extranonce1 is in connection session extranonce1_bin = session.get('extranonce1', None) @@ -77,22 +92,30 @@ class MiningService(GenericService): raise SubmitException("Connection is not subscribed for mining") difficulty = session['difficulty'] - + submit_time = Interfaces.timestamper.time() + + Interfaces.share_limiter.submit(self.connection_ref, difficulty, submit_time) + # This checks if submitted share meet all requirements # and it is valid proof of work. - (is_valid, reason, block_header, block_hash) = Interfaces.template_registry.submit_share(job_id, - worker_name, extranonce1_bin, extranonce2, ntime, nonce, difficulty, - Interfaces.share_manager.on_submit_block) - - if block_header != None: - # block header is missing when template registry was unable to build it - # from given parameters. Client side is probably broken, storing such - # submit don't have any sense. - Interfaces.share_manager.on_submit_share(worker_name, block_header, block_hash, difficulty, - Interfaces.timestamper.time(), is_valid) + try: + (block_header, block_hash, on_submit) = Interfaces.template_registry.submit_share(job_id, + worker_name, extranonce1_bin, extranonce2, ntime, nonce, difficulty) + except SubmitException: + # block_header and block_hash are None when submitted data are corrupted + Interfaces.share_manager.on_submit_share(worker_name, None, None, difficulty, + submit_time, False) + raise + + + Interfaces.share_manager.on_submit_share(worker_name, block_header, block_hash, difficulty, + submit_time, True) - if not is_valid: - raise SubmitException(reason) + if on_submit != None: + # Pool performs submitblock() to bitcoind. Let's hook + # to result and report it to share manager + on_submit.addCallback(Interfaces.share_manager.on_submit_block, + worker_name, block_header, block_hash, submit_time) return True @@ -115,4 +138,4 @@ class MiningService(GenericService): ('extranonce2', 'string', 'hex-encoded big-endian extranonce2, length depends on extranonce2_size from mining.notify.'), ('ntime', 'string', 'UNIX timestamp (32bit integer, big-endian, hex-encoded), must be >= ntime provided by mining,notify and <= current time'), ('nonce', 'string', '32bit integer, hex-encoded, big-endian'),] - \ No newline at end of file +