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
'''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)
'''
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)
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
('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
+