Example #1
0
    def submit_share(self, job_id, worker_name, extranonce1_bin, extranonce2,
                     ntime, nonce, difficulty):
        '''Check parameters and finalize block template. If it leads
           to valid block candidate, asynchronously submits the block
           back to the bitcoin network.

            - extranonce1_bin is binary. No checks performed, it should be from session data
            - job_id, extranonce2, ntime, nonce - in hex form sent by the client
            - difficulty - decimal number from session, again no checks performed
            - submitblock_callback - reference to method which receive result of submitblock()
        '''

        # Check if extranonce2 looks correctly. extranonce2 is in hex form...
        if len(extranonce2) != self.extranonce2_size * 2:
            raise SubmitException(
                "Incorrect size of extranonce2. Expected %d chars" %
                (self.extranonce2_size * 2))

        # Check for job
        job = self.get_job(job_id)
        if job == None:
            raise SubmitException("Job '%s' not found" % job_id)

        # Check if ntime looks correct
        if len(ntime) != 8:
            raise SubmitException("Incorrect size of ntime. Expected 8 chars")

        if not job.check_ntime(int(ntime, 16)):
            raise SubmitException("Ntime out of range")

        # Check nonce
        if len(nonce) != 8:
            raise SubmitException("Incorrect size of nonce. Expected 8 chars")

        # Convert from hex to binary
        extranonce2_bin = binascii.unhexlify(extranonce2)
        ntime_bin = binascii.unhexlify(ntime)
        nonce_bin = binascii.unhexlify(nonce)

        # Check for duplicated submit
        if not job.register_submit(extranonce1_bin, extranonce2_bin, ntime_bin,
                                   nonce_bin):
            log.info("Duplicate from %s, (%s %s %s %s)" % \
                    (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce))
            raise SubmitException("Duplicate share")

        # Now let's do the hard work!
        # ---------------------------

        # 1. Build coinbase
        coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin)
        coinbase_hash = util.doublesha(coinbase_bin)

        # 2. Calculate merkle root
        merkle_root_bin = job.merkletree.withFirst(coinbase_hash)
        merkle_root_int = util.uint256_from_str(merkle_root_bin)

        # 3. Serialize header with given merkle, ntime and nonce
        header_bin = job.serialize_header(merkle_root_int, ntime_bin,
                                          nonce_bin)

        # 4. Reverse header and compare it with target of the user
        hash_bin = x13bcd_hash.getPoWHash(''.join(
            [header_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 20)]))
        hash_int = util.uint256_from_str(hash_bin)
        block_hash_hex = "%064x" % hash_int
        header_hex = binascii.hexlify(header_bin)

        target_user = self.diff_to_target(difficulty)
        if hash_int > target_user:
            raise SubmitException("Share is above target")

        # Mostly for debugging purposes
        target_info = self.diff_to_target(100000)
        if hash_int <= target_info:
            log.info("Yay, share with diff above 100000")

        # 5. Compare hash with target of the network
        if hash_int <= job.target:
            # Yay! It is block candidate!
            log.info("We found a block candidate! %s" % block_hash_hex)

            # 6. Finalize and serialize block object
            job.finalize(merkle_root_int, extranonce1_bin, extranonce2_bin,
                         int(ntime, 16), int(nonce, 16))

            if not job.is_valid():
                # Should not happen
                log.error("Final job validation failed!")

            # 7. Submit block to the network
            serialized = binascii.hexlify(job.serialize())
            on_submit = self.bitcoin_rpc.submitblock(serialized)

            return (header_hex, block_hash_hex, on_submit)

        return (header_hex, block_hash_hex, None)
    def submit_share(self,
                     job_id,
                     worker_name,
                     session,
                     extranonce1_bin,
                     extranonce2,
                     ntime,
                     nonce,
                     difficulty,
                     ip=False):
        '''Check parameters and finalize block template. If it leads
           to valid block candidate, asynchronously submits the block
           back to the bitcoin network.
        
            - extranonce1_bin is binary. No checks performed, it should be from session data
            - job_id, extranonce2, ntime, nonce - in hex form sent by the client
            - difficulty - decimal number from session
            - submitblock_callback - reference to method which receive result of submitblock()
            - difficulty is checked to see if its lower than the vardiff minimum target or pool target
              from conf/config.py and if it is the share is rejected due to it not meeting the requirements for a share
              
        '''
        if settings.VARIABLE_DIFF == True:
            # Share Diff Should never be 0
            if difficulty < settings.VDIFF_MIN_TARGET:
                log.exception(
                    "Worker %s @ IP: %s seems to be submitting Fake Shares" %
                    (worker_name, ip))
                raise SubmitException(
                    "Diff is %s Share Rejected Reporting to Admin" %
                    (difficulty))
        else:
            if difficulty < settings.POOL_TARGET:
                log.exception(
                    "Worker %s @ IP: %s seems to be submitting Fake Shares" %
                    (worker_name, ip))
                raise SubmitException(
                    "Diff is %s Share Rejected Reporting to Admin" %
                    (difficulty))

        # Check if extranonce2 looks correctly. extranonce2 is in hex form...
        if len(extranonce2) != self.extranonce2_size * 2:
            raise SubmitException(
                "Incorrect size of extranonce2. Expected %d chars" %
                (self.extranonce2_size * 2))

            # normalize the case to prevent duplication of valid shares by the client
            ntime = ntime.lower()
            nonce = nonce.lower()
            extranonce2 = extranonce2.lower()

        # Check for job
        job = self.get_job(job_id, worker_name, ip)
        if job == None:
            raise SubmitException("Job '%s' not found" % job_id)

        # Check if ntime looks correct
        if len(ntime) != 8:
            raise SubmitException("Incorrect size of ntime. Expected 8 chars")

        if not job.check_ntime(int(ntime, 16)):
            raise SubmitException("Ntime out of range")

        # Check nonce
        if len(nonce) != 8:
            raise SubmitException("Incorrect size of nonce. Expected 8 chars")

        # 0. Some sugar
        extranonce2_bin = binascii.unhexlify(extranonce2)
        ntime_bin = binascii.unhexlify(ntime)
        nonce_bin = binascii.unhexlify(nonce)

        # Check for duplicated submit
        if not job.register_submit(extranonce1_bin, extranonce2_bin, ntime_bin,
                                   nonce_bin):
            log.info("Duplicate from %s, (%s %s %s %s)" % \
                    (worker_name, binascii.hexlify(extranonce1_bin), extranonce2, ntime, nonce))
            raise SubmitException("Duplicate share")

        # Now let's do the hard work!
        # ---------------------------

        # 1. Build coinbase
        coinbase_bin = job.serialize_coinbase(extranonce1_bin, extranonce2_bin)
        coinbase_hash = util.doublesha(coinbase_bin)

        # 2. Calculate merkle root
        merkle_root_bin = job.merkletree.withFirst(coinbase_hash)
        merkle_root_int = util.uint256_from_str(merkle_root_bin)

        # 3. Serialize header with given merkle, ntime and nonce
        header_bin = job.serialize_header(merkle_root_int, ntime_bin,
                                          nonce_bin)

        # 4. Reverse header and compare it with target of the user
        # hash_bin = algolib.getPoWHash(''.join([ header_bin[i*4:i*4+4][::-1] for i in range(0, 20) ]))
        hash_bin = x13bcd_hash.getPoWHash(''.join(
            [header_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 20)]))
        hash_int = util.uint256_from_str(hash_bin)
        scrypt_hash_hex = "%064x" % hash_int
        header_hex = binascii.hexlify(header_bin)
        if settings.CUSTOM_HEADER != None:
            header_hex = header_hex + settings.CUSTOM_HEADER

        target_user = self.diff_to_target(difficulty)
        if hash_int > target_user:
            raise SubmitException("Share is above target")

        # Mostly for debugging purposes
        target_info = self.diff_to_target(100000)
        if hash_int <= target_info:
            log.info("Yay, share with diff above 100000")

        # Algebra tells us the diff_to_target is the same as hash_to_diff
        share_diff = int(self.diff_to_target(hash_int))

        # 5. Compare hash with target of the network
        if hash_int <= job.target:
            # Yay! It is block candidate!
            log.info("We found a block candidate! %s" % scrypt_hash_hex)

            block_hash_bin = util.doublesha(''.join(
                [header_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 20)]))
            block_hash_hex = block_hash_bin[::-1].encode('hex_codec')

            # 6. Finalize and serialize block object
            job.finalize(merkle_root_int, extranonce1_bin, extranonce2_bin,
                         int(ntime, 16), int(nonce, 16))

            if not job.is_valid():
                # Should not happen
                log.exception(
                    "FINAL JOB VALIDATION FAILED!(Try enabling/disabling tx messages)"
                )

            # 7. Submit block to the network
            serialized = binascii.hexlify(job.serialize())
            on_submit = self.bitcoin_rpc.submitblock(serialized,
                                                     block_hash_hex,
                                                     scrypt_hash_hex)
            if on_submit:
                self.update_block()

            if settings.SOLUTION_BLOCK_HASH:
                return (header_hex, block_hash_hex, share_diff, on_submit)
            else:
                return (header_hex, scrypt_hash_hex, share_diff, on_submit)

        if settings.SOLUTION_BLOCK_HASH:
            block_hash_bin = util.doublesha(''.join(
                [header_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 20)]))
            block_hash_hex = block_hash_bin[::-1].encode('hex_codec')
            return (header_hex, block_hash_hex, share_diff, None)
        else:
            return (header_hex, scrypt_hash_hex, share_diff, None)
Example #3
0
def bcd_Hash(x):
    x = to_bytes(x, 'utf8')
    out = bytes(x13bcd_hash.getPoWHash(x))
    return out
Example #4
0
import x13bcd_hash

from binascii import unhexlify, hexlify

block_hash = 'fd21da3c2b0b6e5f438d365ef3f9a2e3a5018b9402fff79bec0a2e47657e802b'
block_header_hex = '600000006df1d486138ba00b9ceabc42c71c9d1925ea25896ee5555e78507642be52a4d761f93e1f507975d05a33de16bea7784f5cf492aa8e0eda6bf71029d78e3d939a5a2fa97e1d08379f000b3a0e'
block_header_bin = unhexlify(block_header_hex)
block_hash_bin = x13bcd_hash.getPoWHash(b''.join(
    [block_header_bin[i * 4:i * 4 + 4][::-1] for i in range(0, 20)]))
block_hash_hex = hexlify(block_hash_bin[::-1]).decode("utf-8")
assert block_hash_hex == block_hash
Example #5
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pycoin.block import Block
import io, struct
import x13bcd_hash


def uint256_from_str(s):
    r = 0L
    t = struct.unpack("<IIIIIIII", s[:32])
    for i in xrange(8):
        r += t[i] << (i * 32)
    return r


rawblock = '00000060b38cb32058b774ea735c0f6cfaf3fb0153a03496be87208219717f4e4ad744ee5dc71fd1295bfe406e03e23877b2b9a64be33f2a2f1e05a238ef6fdf04bb574ca24ec05b6394001b00cfc14c02010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4c0335350804a24ec05b08fabe6d6d00000000000003600000000000003960000039da4b3161e0000039da4b3161c8010000000000000030d6c52e000000000d2f6e6f64655374726174756d2f00000000020000000000000000266a24aa21a9edd76d419006b113123076afec5868f6b6e3dfde054e82adf4a9693d2a1cc58b256880814a000000001976a914829a4b1a792e9e1514ae902d622aed18a99601b088ac01200000000000000000000000000000000000000000000000000000000000000000000000000c000000d13244a2054b9b33808e72daabd3d9a7c5685b10abd7a4b932f273dd498f131601d4063756d72c0f08af818741b198c97ecf1ae065c464a0ef08ea7c4f0679089d010000006a4730440220243539823fb5fe8fdb8991dda0e5f7e7cf8e3beee36e2dbce6b905e58d142373022058996510c2edf2fbbe77f77016cbfafbe53cc4505e58de05083194af714c50000121021e6a4b6673be9f25e54f4028ebf8459bd2d0726d836dbcee8cecaa856bec458bffffffff0280778e06000000001976a91481b2e127d9c7fec0fbc6b1a1784ba421acf3889d88ac67ccd617000000001976a9145f2bc24285493cafc8ef44b35a5ffe63c5eab5ce88ac00000000'

b = Block.parse_as_header(io.BytesIO(rawblock.decode('hex')))
hash_bin = x13bcd_hash.getPoWHash(b.as_bin())

print uint256_from_str(hash_bin)
Example #6
0
    def submit(self, connection_ref, _id, _params):
        # TODO: Job ID Check 구현해야함
        # TODO: Diff Check 해서 그냥 Share 기록 or Submit 구별 해야함
        # TODO: Share Result를 Database에 기록 해야함 - Database 는 Redis가 될듯
        session_id = connection_ref.get_session()

        _worker_name = _params[0]
        _split_worker_name = _worker_name.strip().split('.')
        username = _split_worker_name[0]
        if len(_split_worker_name) == 2:
            worker = _split_worker_name[1]
        else:
            worker = None
        _job_id = _params[1]

        _nonce_1 = self.job_manager.get_nonce_from_session_id(session_id)
        _block_template = self.job_manager.get_block_template(_job_id)

        if _block_template is None:
            logger.info('rejected share, worker : %s, reason : job not found' %
                        _worker_name)
            return {'id': _id, 'result': False, 'error': [21, 'job not found']}

        if os.getenv("COIN_TYPE") == 'bitcoin':
            _nonce_2 = _params[2]
            _time = _params[3]
            _time_reverse = hash_util.hex_to_reverse_hex(_time)
            _nonce = _params[4]
            _nonce_reverse = hash_util.hex_to_reverse_hex(_nonce)

            if len(_nonce) != 8:
                logger.info(
                    'rejected share, worker : %s, reason : incorrect size of nonce'
                    % _worker_name)
                return {
                    'id': _id,
                    'result': False,
                    'error': [20, 'incorrect size of nonce']
                }

            coinbase = binascii.hexlify(_block_template.coinbase_tx).split(
                _block_template.extranonce_placeholder)
            serialized_coinbase = binascii.unhexlify(coinbase[0] + _nonce_1 +
                                                     _nonce_2.encode() +
                                                     coinbase[1])

            if os.getenv("COIN_ALGORITHM") == 'keccak':
                coinbase_hash = binascii.hexlify(
                    hash_util.reverse_bytes(
                        hash_util.sha(serialized_coinbase)))
            else:
                coinbase_hash = hash_util.bytes_to_reverse_hash(
                    serialized_coinbase)

            tx_hashes = [coinbase_hash
                         ] + [h['hash'] for h in _block_template.transactions]
            merkle_root_reverse_hex = hash_util.hex_to_reverse_hex(
                hash_util.merkle_root(tx_hashes))

            # Header POW 종류별 구별 해야댐
            header = _block_template.serialize_block_header(
                _time_reverse, _nonce_reverse,
                merkle_root_reverse_hex)  # 80 bytes
            block_hex = _block_template.serialize_block(
                header, None, serialized_coinbase)
            if os.getenv("COIN_ALGORITHM") == 'lyra2rev2':
                import lyra2re2_hash
                header_hash = lyra2re2_hash.getPoWHash(header)
            elif os.getenv("COIN_ALGORITHM") == 'lyra2rev3':
                import lyra2re3_hash
                header_hash = lyra2re3_hash.getPoWHash(header)
            elif os.getenv("COIN_ALGORITHM") == 'keccak' or os.getenv(
                    "COIN_ALGORITHM") == 'keccakc':
                import sha3
                header_hash = sha3.keccak_256(header).digest()
            elif os.getenv("COIN_ALGORITHM") == 'x13-bcd':
                import x13bcd_hash
                header_hash = x13bcd_hash.getPoWHash(header)
            elif os.getenv("COIN_ALGORITHM") == 'neoscrypt':
                import neoscrypt
                header_hash = neoscrypt.getPoWHash(header)
            elif os.getenv("COIN_ALGORITHM") == 'yescrypt':
                import yescrypt_hash
                header_hash = yescrypt_hash.getHash(header, len(header))
            elif os.getenv("COIN_ALGORITHM") == 'xevan':
                import xevan_hash
                header_hash = xevan_hash.getPoWHash(header)
            elif os.getenv("COIN_ALGORITHM") == 'phi2':
                import phi2_hash
                header_hash = phi2_hash.getPoWHash(header)
            elif os.getenv("COIN_ALGORITHM") == 'x16r':
                import x16r_hash
                header_hash = x16r_hash.getPoWHash(header)
            elif os.getenv("COIN_ALGORITHM") == 'x16s':
                import x16s_hash
                header_hash = x16s_hash.getPoWHash(header)
            elif os.getenv("COIN_ALGORITHM") == 'timetravel10':
                import timetravel10_hash
                header_hash = timetravel10_hash.getPoWHash(header)
            else:
                header_hash = double_sha(header)

        elif os.getenv("COIN_TYPE") == 'zcash':
            _time = _params[2]
            _nonce_2 = _params[3]
            _soln = _params[4]

            _nonce = _nonce_1 + _nonce_2.encode()

            if len(_nonce) != 64:
                return {
                    'id': _id,
                    'result': False,
                    'error': [20, 'incorrect size of nonce']
                }

            if os.getenv("COIN_ALGORITHM") == 'zhash' and len(_soln) != 202:
                return {
                    'id': _id,
                    'result': False,
                    'error': [20, 'incorrect size of solution']
                }
            elif os.getenv("COIN_ALGORITHM") != 'zhash' and len(_soln) != 2694:
                return {
                    'id': _id,
                    'result': False,
                    'error': [20, 'incorrect size of solution']
                }

            n_time_int = int(_time, 16)
            curtime_int = int(_block_template.curtime, 16)

            if n_time_int < curtime_int:
                return {
                    'id': _id,
                    'result': False,
                    'error': [20, 'ntime out of range']
                }

            header = _block_template.serialize_block_header(
                _time.encode(), _nonce)  # 140 bytes

            header_soln = header + binascii.unhexlify(_soln)
            header_hash = double_sha(header_soln)

            block_hex = _block_template.serialize_block(
                header, binascii.unhexlify(_soln), None)
        else:
            raise Exception('invalid coin type')

        header_bignum = uint256_from_str(header_hash)

        share_diff = os.getenv("POW_LIMIT") / header_bignum
        logger.debug('share diff : {0:.8f}'.format(share_diff))

        diff = self.user_diffs[connection_ref.username]

        if share_diff < diff:
            # logger.debug('low difficulty share of %s' % share_diff)
            logger.info(
                'rejected share, worker : %s, reason : low difficulty share' %
                _worker_name)
            self.database_ref.insert_accepted_share(
                username, worker, False, False, _block_template.block_height,
                share_diff, _block_template.pool_reward, diff)
            return {
                'id': _id,
                'result': None,
                'error': [23, 'low difficulty share of %s' % share_diff]
            }

        if not self.job_manager.register_submit(_nonce_1, _nonce_2, _nonce,
                                                _time):
            logger.info(
                'rejected share, worker : %s, reason : duplicate share' %
                _worker_name)
            return {
                'id': _id,
                'result': None,
                'error': [22, 'duplicate share']
            }

        if share_diff >= _block_template.difficulty * 0.99:
            block_hash = binascii.hexlify(
                hash_util.reverse_bytes(header_hash)).decode()
            if os.getenv("COIN") in [
                    'monacoin', 'feathercoin', 'phoenixcoin', 'vertcoin',
                    'shield'
            ]:
                temp_hash = double_sha(header)
                block_hash = binascii.hexlify(
                    hash_util.reverse_bytes(temp_hash)).decode()

            logger.info('Try new block share, worker : %s, share diff : %s' %
                        (_worker_name, share_diff))
            share_result = self.coin_rpc.submit_block(
                binascii.hexlify(block_hex).decode())

            if share_result is None:
                logger.info('Found Block, result : %s, block hash : %s' %
                            (share_result, block_hash))
                result_hash = Interfaces.block_updater.update_block(
                    repeat=False, block_hash=block_hash)
                if result_hash is not None:
                    block_hash = result_hash
                self.database_ref.insert_accepted_share(
                    username, worker, True, True, _block_template.block_height,
                    share_diff, _block_template.pool_reward, diff, block_hash)
            else:
                logger.error(
                    'undefined share_result %s, block hash %s, coinbase tx %s'
                    % (share_result, block_hash,
                       binascii.hexlify(_block_template.coinbase_tx)))
                self.database_ref.insert_accepted_share(
                    username, worker, False, False,
                    _block_template.block_height, share_diff,
                    _block_template.pool_reward, diff)

                if os.getenv("COIN_TYPE") == 'bitcoin':
                    logger.error('Header : %s' %
                                 binascii.hexlify(header).decode())
                else:
                    logger.error('Header : %s' %
                                 binascii.hexlify(header_soln).decode())
                return {
                    'id': _id,
                    'result': None,
                    'error': [20, 'invalid solution']
                }
        else:
            logger.info('accepted share, worker : %s, share diff : %s' %
                        (_worker_name, '{0:.8f}'.format(share_diff)))
            self.database_ref.insert_accepted_share(
                username, worker, True, False, _block_template.block_height,
                share_diff, _block_template.pool_reward, diff)

        return {'id': _id, 'result': True, 'error': None}