Ejemplo n.º 1
0
    def update_pool(conn):
        try:
            # request local memory pool and load it in
            bt = conn.getblocktemplate({'capabilities': [
                'coinbasevalue',
                'coinbase/append',
                'coinbase',
                'generation',
                'time',
                'transactions/remove',
                'prevblock',
            ]})
        except Exception:
            logger.warn("Failed to fetch new job, RPC must be down..")
            down_connection(conn, net_state)
            return False
        dirty = 0   # track a change in the transaction pool
        for trans in bt['transactions']:
            if trans['hash'] not in net_state['transactions']:
                dirty += 1
                new_trans = Transaction(unhexlify(trans['data']),
                                        fees=trans['fee'])
                assert trans['hash'] == new_trans.lehexhash
                net_state['transactions'][trans['hash']] = new_trans

        if dirty or len(net_state['jobs']) == 0:
            # here we recalculate the current merkle branch and partial
            # coinbases for passing to the mining clients
            coinbase = Transaction()
            coinbase.version = 2
            # create a coinbase input with encoded height and padding for the
            # extranonces so script length is accurate
            extranonce_length = (config['extranonce_size'] +
                                 config['extranonce_serv_size'])
            coinbase.inputs.append(
                Input.coinbase(bt['height'], b'\0' * extranonce_length))
            # simple output to the proper address and value
            fees = 0
            for t in net_state['transactions'].itervalues():
                fees += t.fees
            coinbase.outputs.append(
                Output.to_address(bt['coinbasevalue'] - fees, config['pool_address']))
            job_id = hexlify(pack(str("I"), net_state['job_counter']))
            logger.info("Generating new block template with {} trans"
                        .format(len(net_state['transactions'])))
            bt_obj = BlockTemplate.from_gbt(bt, coinbase, extranonce_length, [])
            bt_obj.job_id = job_id
            bt_obj.block_height = bt['height']
            bt_obj.acc_shares = set()
            net_state['job_counter'] += 1
            net_state['jobs'][job_id] = bt_obj
            net_state['latest_job'] = job_id
            logger.debug("Adding {} new transactions to transaction pool, "
                         "created job {}".format(dirty, job_id))

            return bt_obj
Ejemplo n.º 2
0
    def test_coinbase(self):
        coinbase = Transaction()
        coinbase.version = 2
        coinbase.inputs.append(Input.coinbase(12000, b'\0' * 6))
        coinbase.outputs.append(
            Output.to_address(50000, 'D7QJyeBNuwEqxsyVCLJi3pHs64uPdMDuBa'))
        one, two = coinbase.assemble(split=True)
        one = one[:-6]

        test = Transaction(one + unhexlify('0abcdef01012') + two)
        test.disassemble()
Ejemplo n.º 3
0
    def test_coinbase(self):
        coinbase = Transaction()
        coinbase.version = 2
        coinbase.inputs.append(Input.coinbase(12000, b'\0' * 6))
        coinbase.outputs.append(
            Output.to_address(50000, 'D7QJyeBNuwEqxsyVCLJi3pHs64uPdMDuBa'))
        one, two = coinbase.assemble(split=True)
        one = one[:-6]

        test = Transaction(one + unhexlify('0abcdef01012') + two)
        test.disassemble()
Ejemplo n.º 4
0
def test_block_template():
    gbt = {u'coinbaseaux': {u'flags': u''}, u'vbavailable': {}, u'previousblockhash': u'00000061786317587bcfe97516cd00a541962334779d60efdb7c4efeb670ac77', u'target': u'7fffff0000000000000000000000000000000000000000000000000000000000', u'noncerange': u'00000000ffffffff', u'transactions': [], u'rules': [], u'vbrequired': 0, u'curtime': 1500584586, u'capabilities': [u'proposal'], u'height': 16, 'update_time': 1500584586.899153, u'mintime': 1500584329, u'version': 536870912, u'bits': u'207fffff', u'coinbasevalue': 5000000000, u'sigoplimit': 20000, u'sizelimit': 1000000, u'mutable': [u'time', u'transactions', u'prevblock'], u'longpollid': u'00000061786317587bcfe97516cd00a541962334779d60efdb7c4efeb670ac7718'}
    extranonce_length = 4
    coinbase = Transaction()
    coinbase.version = 2

    coinbase.inputs.append(
        Input.coinbase(gbt['height'], [], extra_script_sig=b'\0' * extranonce_length))

    coinbase_value = 10000000
    coinbase.outputs.append(Output.to_address(coinbase_value, "1F1tAaz5x1HUXrCNLbtMDqcw6o5GNn4xqX"))

    bt_obj = BlockTemplate.from_gbt(gbt, coinbase, extranonce_length, [])
Ejemplo n.º 5
0
    def test_stratum_confirm(self):
        """ Test some raw data from cgminer submitting a share, confirm
        hashes come out the same as cgminer.
        Raw stratum params:
        """
        gbt = {u'bits': u'1e00e92b',
               u'coinbaseaux': {u'flags': u'062f503253482f'},
               u'coinbasevalue': 5000000000,
               u'curtime': 1392509565,
               u'height': 203588,
               u'mintime': 1392508633,
               u'mutable': [u'time', u'transactions', u'prevblock'],
               u'noncerange': u'00000000ffffffff',
               u'previousblockhash': u'b0f5ecb62774f2f07fdc0f72fa0585ae3e8ca78ad8692209a355d12bc690fb73',
               u'sigoplimit': 20000,
               u'sizelimit': 1000000,
               u'target': u'000000e92b000000000000000000000000000000000000000000000000000000',
               u'transactions': [],
               u'version': 2}

        extra1 = '0000000000000000'
        submit = {'extra2': '00000000', 'nonce': 'd5160000',
                  'result': '000050ccfe8a3efe93b2ee33d2aecf4a60c809995c7dd19368a7d00c86880f30'}

        # build a block template object from the raw data
        coinbase = Transaction()
        coinbase.version = 2
        coinbase.inputs.append(Input.coinbase(gbt['height'], b'\0' * 12))
        coinbase.outputs.append(Output.to_address(gbt['coinbasevalue'], 'D7QJyeBNuwEqxsyVCLJi3pHs64uPdMDuBa'))

        transactions = []
        for trans in gbt['transactions']:
            new_trans = Transaction(unhexlify(trans['data']), fees=trans['fee'])
            assert trans['hash'] == new_trans.lehexhash
            transactions.append(new_trans)
        bt = BlockTemplate.from_gbt(gbt, coinbase, 12, transactions)
        send_params = bt.stratum_params()
        print("job_id: {0}\nprevhash: {1}\ncoinbase1: {2}\ncoinbase2: {3}"
              "\nmerkle_branch: {4}\nversion: {5}\nnbits: {6}\nntime: {7}"
              .format(*send_params))

        header = bt.block_header(submit['nonce'], extra1, submit['extra2'])
        hash_bin = scrypt(header)
        target = target_from_diff(1, 0x0000FFFF00000000000000000000000000000000000000000000000000000000)

        hash_int = uint256_from_str(hash_bin)
        hash_hex = "%064x" % hash_int
        self.assertEquals(hash_hex, submit['result'])
        assert hash_int < target
Ejemplo n.º 6
0
    def generate_job(self, push=False, flush=False, new_block=False):
        """ Creates a new job for miners to work on. Push will trigger an
        event that sends new work but doesn't force a restart. If flush is
        true a job restart will be triggered. """

        # aux monitors will often call this early when not needed at startup
        if not self._last_gbt:
            self.logger.warn("Cannot generate new job, missing last GBT info")
            return

        if self.merged_work:
            tree, size = bitcoin_data.make_auxpow_tree(self.merged_work)
            mm_hashes = [
                self.merged_work.get(tree.get(i), dict(hash=0))['hash']
                for i in xrange(size)
            ]
            mm_data = '\xfa\xbemm'
            mm_data += bitcoin_data.aux_pow_coinbase_type.pack(
                dict(
                    merkle_root=bitcoin_data.merkle_hash(mm_hashes),
                    size=size,
                    nonce=0,
                ))
            merged_data = {}
            for aux_work in self.merged_work.itervalues():
                data = dict(target=aux_work['target'],
                            hash=aux_work['hash'],
                            height=aux_work['height'],
                            index=mm_hashes.index(aux_work['hash']),
                            type=aux_work['type'],
                            hashes=mm_hashes)
                merged_data[aux_work['type']] = data
        else:
            merged_data = {}
            mm_data = None

        self.logger.info("Generating new block template with {} trans. "
                         "Diff {:,.4f}. Subsidy {:,.2f}. Height {:,}. "
                         "Merged chains: {}".format(
                             len(self._last_gbt['transactions']),
                             bits_to_difficulty(self._last_gbt['bits']),
                             self._last_gbt['coinbasevalue'] / 100000000.0,
                             self._last_gbt['height'],
                             ', '.join(merged_data.keys())))

        # here we recalculate the current merkle branch and partial
        # coinbases for passing to the mining clients
        coinbase = Transaction()
        coinbase.version = 2
        # create a coinbase input with encoded height and padding for the
        # extranonces so script length is accurate
        extranonce_length = (self.config['extranonce_size'] +
                             self.config['extranonce_serv_size'])
        coinbase.inputs.append(
            Input.coinbase(self._last_gbt['height'],
                           addtl_push=[mm_data] if mm_data else [],
                           extra_script_sig=b'\0' * extranonce_length))

        # Darkcoin payee amount
        if self._last_gbt.get('payee', '') != '':
            payout = self._last_gbt['coinbasevalue'] / 5
            self._last_gbt['coinbasevalue'] -= payout
            coinbase.outputs.append(
                Output.to_address(payout, self._last_gbt['payee']))
            self.logger.info(
                "Paying out masternode at addr {}. Payout {}. Blockval reduced to {}"
                .format(self._last_gbt['payee'], payout,
                        self._last_gbt['coinbasevalue']))

        # simple output to the proper address and value
        coinbase.outputs.append(
            Output.to_address(self._last_gbt['coinbasevalue'],
                              self.config['pool_address']))

        job_id = hexlify(struct.pack(str("I"), self._job_counter))
        bt_obj = BlockTemplate.from_gbt(
            self._last_gbt, coinbase, extranonce_length, [
                Transaction(unhexlify(t['data']), fees=t['fee'])
                for t in self._last_gbt['transactions']
            ])
        # add in our merged mining data
        if mm_data:
            hashes = [
                bitcoin_data.hash256(tx.raw) for tx in bt_obj.transactions
            ]
            bt_obj.merkle_link = bitcoin_data.calculate_merkle_link([None] +
                                                                    hashes, 0)
        bt_obj.merged_data = merged_data
        bt_obj.job_id = job_id
        bt_obj.diff1 = self.config['diff1']
        bt_obj.algo = self.config['algo']
        bt_obj.pow_block_hash = self.config['pow_block_hash']
        bt_obj.block_height = self._last_gbt['height']
        bt_obj.acc_shares = set()

        if push:
            if flush:
                self.logger.info("New work announced! Wiping previous jobs...")
                self.jobs.clear()
                self.latest_job = None
            else:
                self.logger.info("New work announced!")

        self._job_counter += 1
        self.jobs[job_id] = bt_obj
        self.latest_job = job_id
        if push:
            t = time.time()
            bt_obj.stratum_string()
            for idx, client in viewitems(self.stratum_manager.clients):
                try:
                    if client.authenticated:
                        client._push(bt_obj, flush=flush)
                except AttributeError:
                    pass
            self.logger.info(
                "New job enqueued for transmission to {} users in {}".format(
                    len(self.stratum_manager.clients),
                    time_format(time.time() - t)))
            if flush:
                self.server['work_restarts'].incr()
            self.server['work_pushes'].incr()

        self.server['new_jobs'].incr()

        if new_block:
            hex_bits = hexlify(bt_obj.bits)
            self.current_net['difficulty'] = bits_to_difficulty(hex_bits)
            self.current_net['subsidy'] = bt_obj.total_value
            self.current_net['height'] = bt_obj.block_height - 1
            self.current_net['prev_hash'] = bt_obj.hashprev_be_hex
            self.current_net['transactions'] = len(bt_obj.transactions)
Ejemplo n.º 7
0
    def generate_job(self,
                     push=False,
                     flush=False,
                     new_block=False,
                     network='main'):
        """ Creates a new job for miners to work on. Push will trigger an
        event that sends new work but doesn't force a restart. If flush is
        true a job restart will be triggered. """

        # aux monitors will often call this early when not needed at startup
        if not self._last_gbt:
            self.logger.warn("Cannot generate new job, missing last GBT info")
            return

        if self.auxmons:
            merged_work = {}
            auxdata = {}
            for auxmon in self.auxmons:
                # If this network hasn't pushed a job yet, skip it
                if auxmon.last_work['hash'] is None:
                    continue
                merged_work[auxmon.last_work['chainid']] = dict(
                    hash=auxmon.last_work['hash'],
                    target=auxmon.last_work['type'])

            tree, size = bitcoin_data.make_auxpow_tree(merged_work)
            mm_hashes = [
                merged_work.get(tree.get(i), dict(hash=0))['hash']
                for i in xrange(size)
            ]
            mm_data = '\xfa\xbemm'
            mm_data += bitcoin_data.aux_pow_coinbase_type.pack(
                dict(
                    merkle_root=bitcoin_data.merkle_hash(mm_hashes),
                    size=size,
                    nonce=0,
                ))

            for auxmon in self.auxmons:
                if auxmon.last_work['hash'] is None:
                    continue
                data = dict(target=auxmon.last_work['target'],
                            hash=auxmon.last_work['hash'],
                            height=auxmon.last_work['height'],
                            found_block=auxmon.found_block,
                            index=mm_hashes.index(auxmon.last_work['hash']),
                            type=auxmon.last_work['type'],
                            hashes=mm_hashes)
                auxdata[auxmon.config['currency']] = data
        else:
            auxdata = {}
            mm_data = None

        # here we recalculate the current merkle branch and partial
        # coinbases for passing to the mining clients
        coinbase = Transaction()
        coinbase.version = 2
        # create a coinbase input with encoded height and padding for the
        # extranonces so script length is accurate
        extranonce_length = (self.manager.config['extranonce_size'] +
                             self.manager.config['extranonce_serv_size'])
        coinbase.inputs.append(
            Input.coinbase(self._last_gbt['height'],
                           addtl_push=[mm_data] if mm_data else [],
                           extra_script_sig=b'\0' * extranonce_length))

        coinbase_value = self._last_gbt['coinbasevalue']

        # Payout Darkcoin masternodes
        mn_enforcement = self._last_gbt.get('enforce_masternode_payments',
                                            True)
        if (self.config['payout_drk_mn'] is True or mn_enforcement is True) \
                and self._last_gbt.get('payee', '') != '':
            # Grab the darkcoin payout amount, default to 20%
            payout = self._last_gbt.get('payee_amount', coinbase_value / 5)
            coinbase_value -= payout
            coinbase.outputs.append(
                Output.to_address(payout, self._last_gbt['payee']))
            self.logger.debug(
                "Created TX output for masternode at ({}:{}). Coinbase value "
                "reduced to {}".format(self._last_gbt['payee'], payout,
                                       coinbase_value))

        # simple output to the proper address and value
        coinbase.outputs.append(
            Output.to_address(coinbase_value, self.config['pool_address']))

        job_id = hexlify(struct.pack(str("I"), self._job_counter))

        bt_obj = BlockTemplate.from_gbt(
            self._last_gbt, coinbase, extranonce_length, [
                Transaction(unhexlify(t['data']), fees=t['fee'])
                for t in self._last_gbt['transactions']
            ])
        # add in our merged mining data
        if mm_data:
            hashes = [
                bitcoin_data.hash256(tx.raw) for tx in bt_obj.transactions
            ]
            bt_obj.merkle_link = bitcoin_data.calculate_merkle_link([None] +
                                                                    hashes, 0)
        bt_obj.merged_data = auxdata
        bt_obj.job_id = job_id
        bt_obj.diff1 = self.config['diff1']
        bt_obj.algo = self.config['algo']
        bt_obj.currency = self.config['currency']
        bt_obj.pow_block_hash = self.config['pow_block_hash']
        bt_obj.block_height = self._last_gbt['height']
        bt_obj.acc_shares = set()
        if flush:
            bt_obj.type = 0
        elif push:
            bt_obj.type = 1
        else:
            bt_obj.type = 2
        bt_obj.found_block = self.found_block

        # Push the fresh job to users after updating details
        self._job_counter += 1
        if flush:
            self.jobs.clear()
        self.jobs[job_id] = bt_obj
        self.latest_job = bt_obj

        self.new_job.job = bt_obj
        self.new_job.set()
        self.new_job.clear()
        event = ("{name}.jobmanager.new_job:1|c\n".format(
            name=self.manager.config['procname']))
        if push or flush:
            self.logger.info(
                "{}: New block template with {:,} trans. "
                "Diff {:,.4f}. Subsidy {:,.2f}. Height {:,}. Merged: {}".
                format("FLUSH" if flush else "PUSH",
                       len(self._last_gbt['transactions']),
                       bits_to_difficulty(self._last_gbt['bits']),
                       self._last_gbt['coinbasevalue'] / 100000000.0,
                       self._last_gbt['height'], ', '.join(auxdata.keys())))
            event += ("{name}.jobmanager.work_push:1|c\n".format(
                name=self.manager.config['procname']))

        # Stats and notifications now that it's pushed
        if flush:
            event += ("{name}.jobmanager.work_restart:1|c\n".format(
                name=self.manager.config['procname']))
            self.logger.info("New {} network block announced! Wiping previous"
                             " jobs and pushing".format(network))
        elif push:
            self.logger.info(
                "New {} network block announced, pushing new job!".format(
                    network))

        if new_block:
            hex_bits = hexlify(bt_obj.bits)
            self.current_net['difficulty'] = bits_to_difficulty(hex_bits)
            self.current_net['subsidy'] = bt_obj.total_value
            self.current_net['height'] = bt_obj.block_height - 1
            self.current_net['last_block'] = time.time()
            self.current_net['prev_hash'] = bt_obj.hashprev_be_hex
            self.current_net['transactions'] = len(bt_obj.transactions)

            event += ("{name}.{curr}.difficulty:{diff}|g\n"
                      "{name}.{curr}.subsidy:{subsidy}|g\n"
                      "{name}.{curr}.job_generate:{t}|g\n"
                      "{name}.{curr}.height:{height}|g".format(
                          name=self.manager.config['procname'],
                          curr=self.config['currency'],
                          diff=self.current_net['difficulty'],
                          subsidy=bt_obj.total_value,
                          height=bt_obj.block_height - 1,
                          t=(time.time() - self._last_gbt['update_time']) *
                          1000))
        self.manager.log_event(event)
Ejemplo n.º 8
0
    def generate_job(self, push=False, flush=False, new_block=False, network='main'):
        """ Creates a new job for miners to work on. Push will trigger an
        event that sends new work but doesn't force a restart. If flush is
        true a job restart will be triggered. """

        # aux monitors will often call this early when not needed at startup
        if not self._last_gbt:
            self.logger.warn("Cannot generate new job, missing last GBT info")
            return

        if self.auxmons:
            merged_work = {}
            auxdata = {}
            for auxmon in self.auxmons:
                if auxmon.last_work['hash'] is None:
                    continue
                merged_work[auxmon.last_work['chainid']] = dict(
                    hash=auxmon.last_work['hash'],
                    target=auxmon.last_work['type']
                )

            tree, size = bitcoin_data.make_auxpow_tree(merged_work)
            mm_hashes = [merged_work.get(tree.get(i), dict(hash=0))['hash']
                         for i in xrange(size)]
            mm_data = '\xfa\xbemm'
            mm_data += bitcoin_data.aux_pow_coinbase_type.pack(dict(
                merkle_root=bitcoin_data.merkle_hash(mm_hashes),
                size=size,
                nonce=0,
            ))

            for auxmon in self.auxmons:
                if auxmon.last_work['hash'] is None:
                    continue
                data = dict(target=auxmon.last_work['target'],
                            hash=auxmon.last_work['hash'],
                            height=auxmon.last_work['height'],
                            found_block=auxmon.found_block,
                            index=mm_hashes.index(auxmon.last_work['hash']),
                            type=auxmon.last_work['type'],
                            hashes=mm_hashes)
                auxdata[auxmon.config['currency']] = data
        else:
            auxdata = {}
            mm_data = None

        # here we recalculate the current merkle branch and partial
        # coinbases for passing to the mining clients
        coinbase = Transaction()
        coinbase.version = 2
        # create a coinbase input with encoded height and padding for the
        # extranonces so script length is accurate
        extranonce_length = (self.manager.config['extranonce_size'] +
                             self.manager.config['extranonce_serv_size'])
        coinbase.inputs.append(
            Input.coinbase(self._last_gbt['height'],
                           addtl_push=[mm_data] if mm_data else [],
                           extra_script_sig=b'\0' * extranonce_length))

        coinbase_value = self._last_gbt['coinbasevalue']

        # Payout Darkcoin masternodes
        mn_enforcement = self._last_gbt.get('enforce_masternode_payments', True)
        if (self.config['payout_drk_mn'] is True or mn_enforcement is True) \
                and self._last_gbt.get('payee', '') != '':
            # Grab the darkcoin payout amount, default to 20%
            payout = self._last_gbt.get('payee_amount', coinbase_value / 5)
            coinbase_value -= payout
            coinbase.outputs.append(
                Output.to_address(payout, self._last_gbt['payee']))
            self.logger.debug(
                "Created TX output for masternode at ({}:{}). Coinbase value "
                "reduced to {}".format(self._last_gbt['payee'], payout,
                                       coinbase_value))

        # simple output to the proper address and value
        coinbase.outputs.append(
            Output.to_address(coinbase_value, self.config['pool_address']))

        job_id = hexlify(struct.pack(str("I"), self._job_counter))
        bt_obj = BlockTemplate.from_gbt(self._last_gbt,
                                        coinbase,
                                        extranonce_length,
                                        [Transaction(unhexlify(t['data']), fees=t['fee'])
                                         for t in self._last_gbt['transactions']])
        # add in our merged mining data
        if mm_data:
            hashes = [bitcoin_data.hash256(tx.raw) for tx in bt_obj.transactions]
            bt_obj.merkle_link = bitcoin_data.calculate_merkle_link([None] + hashes, 0)
        bt_obj.merged_data = auxdata
        bt_obj.job_id = job_id
        bt_obj.diff1 = self.config['diff1']
        bt_obj.algo = self.config['algo']
        bt_obj.currency = self.config['currency']
        bt_obj.pow_block_hash = self.config['pow_block_hash']
        bt_obj.block_height = self._last_gbt['height']
        bt_obj.acc_shares = set()
        if flush:
            bt_obj.type = 0
        elif push:
            bt_obj.type = 1
        else:
            bt_obj.type = 2
        bt_obj.found_block = self.found_block

        # Push the fresh job to users after updating details
        self._job_counter += 1
        if flush:
            self.jobs.clear()
        self.jobs[job_id] = bt_obj
        self.latest_job = bt_obj

        self.new_job.job = bt_obj
        self.new_job.set()
        self.new_job.clear()
        event = ("{name}.jobmanager.new_job:1|c\n"
                 .format(name=self.manager.config['procname']))
        if push or flush:
            self.logger.info(
                "{}: New block template with {:,} trans. "
                "Diff {:,.4f}. Subsidy {:,.2f}. Height {:,}. Merged: {}"
                .format("FLUSH" if flush else "PUSH",
                        len(self._last_gbt['transactions']),
                        bits_to_difficulty(self._last_gbt['bits']),
                        self._last_gbt['coinbasevalue'] / 100000000.0,
                        self._last_gbt['height'],
                        ', '.join(auxdata.keys())))
            event += ("{name}.jobmanager.work_push:1|c\n"
                      .format(name=self.manager.config['procname']))

        # Stats and notifications now that it's pushed
        if flush:
            event += ("{name}.jobmanager.work_restart:1|c\n"
                      .format(name=self.manager.config['procname']))
            self.logger.info("New {} network block announced! Wiping previous"
                             " jobs and pushing".format(network))
        elif push:
            self.logger.info("New {} network block announced, pushing new job!"
                             .format(network))

        if new_block:
            hex_bits = hexlify(bt_obj.bits)
            self.current_net['difficulty'] = bits_to_difficulty(hex_bits)
            self.current_net['subsidy'] = bt_obj.total_value
            self.current_net['height'] = bt_obj.block_height - 1
            self.current_net['last_block'] = time.time()
            self.current_net['prev_hash'] = bt_obj.hashprev_be_hex
            self.current_net['transactions'] = len(bt_obj.transactions)

            event += (
                "{name}.{curr}.difficulty:{diff}|g\n"
                "{name}.{curr}.subsidy:{subsidy}|g\n"
                "{name}.{curr}.job_generate:{t}|g\n"
                "{name}.{curr}.height:{height}|g"
                .format(name=self.manager.config['procname'],
                        curr=self.config['currency'],
                        diff=self.current_net['difficulty'],
                        subsidy=bt_obj.total_value,
                        height=bt_obj.block_height - 1,
                        t=(time.time() - self._last_gbt['update_time']) * 1000))
        self.manager.log_event(event)
Ejemplo n.º 9
0
    def generate_job(self, push=False, flush=False, new_block=False):
        """ Creates a new job for miners to work on. Push will trigger an
        event that sends new work but doesn't force a restart. If flush is
        true a job restart will be triggered. """

        # aux monitors will often call this early when not needed at startup
        if not self._last_gbt:
            self.logger.warn("Cannot generate new job, missing last GBT info")
            return

        if self.merged_work:
            tree, size = bitcoin_data.make_auxpow_tree(self.merged_work)
            mm_hashes = [self.merged_work.get(tree.get(i), dict(hash=0))['hash']
                         for i in xrange(size)]
            mm_data = '\xfa\xbemm'
            mm_data += bitcoin_data.aux_pow_coinbase_type.pack(dict(
                merkle_root=bitcoin_data.merkle_hash(mm_hashes),
                size=size,
                nonce=0,
            ))
            merged_data = {}
            for aux_work in self.merged_work.itervalues():
                data = dict(target=aux_work['target'],
                            hash=aux_work['hash'],
                            height=aux_work['height'],
                            index=mm_hashes.index(aux_work['hash']),
                            type=aux_work['type'],
                            hashes=mm_hashes)
                merged_data[aux_work['type']] = data
        else:
            merged_data = {}
            mm_data = None

        self.logger.info("Generating new block template with {} trans. "
                         "Diff {:,.4f}. Subsidy {:,.2f}. Height {:,}. "
                         "Merged chains: {}"
                         .format(len(self._last_gbt['transactions']),
                                 bits_to_difficulty(self._last_gbt['bits']),
                                 self._last_gbt['coinbasevalue'] / 100000000.0,
                                 self._last_gbt['height'],
                                 ', '.join(merged_data.keys())))

        # here we recalculate the current merkle branch and partial
        # coinbases for passing to the mining clients
        coinbase = Transaction()
        coinbase.version = 2
        # create a coinbase input with encoded height and padding for the
        # extranonces so script length is accurate
        extranonce_length = (self.config['extranonce_size'] +
                             self.config['extranonce_serv_size'])
        coinbase.inputs.append(
            Input.coinbase(self._last_gbt['height'],
                           addtl_push=[mm_data] if mm_data else [],
                           extra_script_sig=b'\0' * extranonce_length))

        # Darkcoin payee amount
        if self._last_gbt.get('payee', '') != '':
            payout = self._last_gbt['coinbasevalue'] / 5
            self._last_gbt['coinbasevalue'] -= payout
            coinbase.outputs.append(
                Output.to_address(payout, self._last_gbt['payee']))
            self.logger.info("Paying out masternode at addr {}. Payout {}. Blockval reduced to {}"
                             .format(self._last_gbt['payee'], payout, self._last_gbt['coinbasevalue']))

        # simple output to the proper address and value
        coinbase.outputs.append(
            Output.to_address(self._last_gbt['coinbasevalue'], self.config['pool_address']))

        job_id = hexlify(struct.pack(str("I"), self._job_counter))
        bt_obj = BlockTemplate.from_gbt(self._last_gbt,
                                        coinbase,
                                        extranonce_length,
                                        [Transaction(unhexlify(t['data']), fees=t['fee'])
                                         for t in self._last_gbt['transactions']])
        # add in our merged mining data
        if mm_data:
            hashes = [bitcoin_data.hash256(tx.raw) for tx in bt_obj.transactions]
            bt_obj.merkle_link = bitcoin_data.calculate_merkle_link([None] + hashes, 0)
        bt_obj.merged_data = merged_data
        bt_obj.job_id = job_id
        bt_obj.diff1 = self.config['diff1']
        bt_obj.algo = self.config['algo']
        bt_obj.pow_block_hash = self.config['pow_block_hash']
        bt_obj.block_height = self._last_gbt['height']
        bt_obj.acc_shares = set()

        if push:
            if flush:
                self.logger.info("New work announced! Wiping previous jobs...")
                self.jobs.clear()
                self.latest_job = None
            else:
                self.logger.info("New work announced!")

        self._job_counter += 1
        self.jobs[job_id] = bt_obj
        self.latest_job = job_id
        if push:
            t = time.time()
            bt_obj.stratum_string()
            for idx, client in viewitems(self.stratum_manager.clients):
                try:
                    if client.authenticated:
                        client._push(bt_obj, flush=flush)
                except AttributeError:
                    pass
            self.logger.info("New job enqueued for transmission to {} users in {}"
                             .format(len(self.stratum_manager.clients),
                                     time_format(time.time() - t)))
            if flush:
                self.server['work_restarts'].incr()
            self.server['work_pushes'].incr()

        self.server['new_jobs'].incr()

        if new_block:
            hex_bits = hexlify(bt_obj.bits)
            self.current_net['difficulty'] = bits_to_difficulty(hex_bits)
            self.current_net['subsidy'] = bt_obj.total_value
            self.current_net['height'] = bt_obj.block_height - 1
            self.current_net['prev_hash'] = bt_obj.hashprev_be_hex
            self.current_net['transactions'] = len(bt_obj.transactions)
Ejemplo n.º 10
0
    def test_stratum_confirm(self):
        """ Test some raw data from cgminer submitting a share, confirm
        hashes come out the same as cgminer.
        Raw stratum params:
        """
        gbt = {
            u'bits': u'1e00e92b',
            u'coinbaseaux': {
                u'flags': u'062f503253482f'
            },
            u'coinbasevalue': 5000000000,
            u'curtime': 1392509565,
            u'height': 203588,
            u'mintime': 1392508633,
            u'mutable': [u'time', u'transactions', u'prevblock'],
            u'noncerange': u'00000000ffffffff',
            u'previousblockhash':
            u'b0f5ecb62774f2f07fdc0f72fa0585ae3e8ca78ad8692209a355d12bc690fb73',
            u'sigoplimit': 20000,
            u'sizelimit': 1000000,
            u'target':
            u'000000e92b000000000000000000000000000000000000000000000000000000',
            u'transactions': [],
            u'version': 2
        }

        extra1 = '0000000000000000'
        submit = {
            'extra2':
            '00000000',
            'nonce':
            'd5160000',
            'result':
            '000050ccfe8a3efe93b2ee33d2aecf4a60c809995c7dd19368a7d00c86880f30'
        }

        # build a block template object from the raw data
        coinbase = Transaction()
        coinbase.version = 2
        coinbase.inputs.append(Input.coinbase(gbt['height'], [b'\0' * 12]))
        coinbase.outputs.append(
            Output.to_address(gbt['coinbasevalue'],
                              'D7QJyeBNuwEqxsyVCLJi3pHs64uPdMDuBa'))

        transactions = []
        for trans in gbt['transactions']:
            new_trans = Transaction(unhexlify(trans['data']),
                                    fees=trans['fee'])
            assert trans['hash'] == new_trans.lehexhash
            transactions.append(new_trans)
        bt = BlockTemplate.from_gbt(gbt, coinbase, 12, transactions)
        send_params = bt.stratum_params()
        print(
            "job_id: {0}\nprevhash: {1}\ncoinbase1: {2}\ncoinbase2: {3}"
            "\nmerkle_branch: {4}\nversion: {5}\nnbits: {6}\nntime: {7}".
            format(*send_params))

        header = bt.block_header(submit['nonce'], extra1, submit['extra2'])
        target = target_from_diff(
            1,
            0x0000FFFF00000000000000000000000000000000000000000000000000000000)
        self.assertEquals(
            hexlify(sha256d(header)[::-1]).decode('ascii'), submit['result'])
        assert hash_int < target
Ejemplo n.º 11
0
    def generate_job(self, push=False, flush=False, new_block=False):
        """ Creates a new job for miners to work on. Push will trigger an
        event that sends new work but doesn't force a restart. If flush is
        true a job restart will be triggered. """

        # aux monitors will often call this early when not needed at startup
        if self.last_gbt is None:
            return

        merged_work = self.net_state['merged_work']
        if self.net_state['merged_work']:
            tree, size = bitcoin_data.make_auxpow_tree(merged_work)
            mm_hashes = [merged_work.get(tree.get(i), dict(hash=0))['hash']
                         for i in xrange(size)]
            mm_data = '\xfa\xbemm'
            mm_data += bitcoin_data.aux_pow_coinbase_type.pack(dict(
                merkle_root=bitcoin_data.merkle_hash(mm_hashes),
                size=size,
                nonce=0,
            ))
            mm_later = [(aux_work, mm_hashes.index(aux_work['hash']), mm_hashes)
                        for chain_id, aux_work in merged_work.iteritems()]
        else:
            mm_later = []
            mm_data = None

        with self.job_lock:
            # here we recalculate the current merkle branch and partial
            # coinbases for passing to the mining clients
            coinbase = Transaction()
            coinbase.version = 2
            # create a coinbase input with encoded height and padding for the
            # extranonces so script length is accurate
            extranonce_length = (self.config['extranonce_size'] +
                                 self.config['extranonce_serv_size'])
            coinbase.inputs.append(
                Input.coinbase(self.last_gbt['height'],
                               addtl_push=[mm_data] if mm_data else [],
                               extra_script_sig=b'\0' * extranonce_length))
            # simple output to the proper address and value
            coinbase.outputs.append(
                Output.to_address(self.last_gbt['coinbasevalue'] - self.last_gbt['fees'], self.config['pool_address']))
            job_id = hexlify(struct.pack(str("I"), self.net_state['job_counter']))
            logger.info("Generating new block template with {} trans. Diff {}. Subsidy {}. Fees {}."
                        .format(len(self.net_state['transactions']),
                                bits_to_difficulty(self.last_gbt['bits']),
                                self.last_gbt['coinbasevalue'],
                                self.last_gbt['fees']))
            bt_obj = BlockTemplate.from_gbt(self.last_gbt, coinbase, extranonce_length, [])
            bt_obj.mm_later = copy(mm_later)
            # hashes = [bitcoin_data.hash256(tx.raw) for tx in bt_obj.transactions]
            bt_obj.merkle_link = bitcoin_data.calculate_merkle_link([None], 0)
            bt_obj.job_id = job_id
            bt_obj.block_height = self.last_gbt['height']
            bt_obj.acc_shares = set()

        if push:
            if flush:
                logger.info("New work announced! Wiping previous jobs...")
                self.net_state['jobs'].clear()
                self.net_state['latest_job'] = None
            else:
                logger.info("New work announced!")

        self.net_state['job_counter'] += 1
        self.net_state['jobs'][job_id] = bt_obj
        self.net_state['latest_job'] = job_id
        if push:
            for idx, client in viewitems(self.stratum_clients):
                try:
                    if flush:
                        client.new_block_event.set()
                    else:
                        client.new_work_event.set()
                except AttributeError:
                    pass

        if new_block:
            if self.config['send_new_block']:
                hex_bits = hexlify(bt_obj.bits)
                self.celery.send_task_pp('new_block',
                                         bt_obj.block_height,
                                         hex_bits,
                                         bt_obj.total_value)
            self.net_state['difficulty'] = bits_to_difficulty(hex_bits)
Ejemplo n.º 12
0
    def generate_job(self, push=False, flush=False, new_block=False):
        """ Creates a new job for miners to work on. Push will trigger an
        event that sends new work but doesn't force a restart. If flush is
        true a job restart will be triggered. """

        # aux monitors will often call this early when not needed at startup
        if self.last_gbt is None:
            return

        merged_work = self.net_state['merged_work']
        if self.net_state['merged_work']:
            tree, size = bitcoin_data.make_auxpow_tree(merged_work)
            mm_hashes = [
                merged_work.get(tree.get(i), dict(hash=0))['hash']
                for i in xrange(size)
            ]
            mm_data = '\xfa\xbemm'
            mm_data += bitcoin_data.aux_pow_coinbase_type.pack(
                dict(
                    merkle_root=bitcoin_data.merkle_hash(mm_hashes),
                    size=size,
                    nonce=0,
                ))
            mm_later = [(aux_work, mm_hashes.index(aux_work['hash']),
                         mm_hashes)
                        for chain_id, aux_work in merged_work.iteritems()]
        else:
            mm_later = []
            mm_data = None

        # here we recalculate the current merkle branch and partial
        # coinbases for passing to the mining clients
        coinbase = Transaction()
        coinbase.version = 2
        # create a coinbase input with encoded height and padding for the
        # extranonces so script length is accurate
        extranonce_length = (self.config['extranonce_size'] +
                             self.config['extranonce_serv_size'])
        coinbase.inputs.append(
            Input.coinbase(self.last_gbt['height'],
                           addtl_push=[mm_data] if mm_data else [],
                           extra_script_sig=b'\0' * extranonce_length))
        # simple output to the proper address and value
        coinbase.outputs.append(
            Output.to_address(self.last_gbt['coinbasevalue'],
                              self.config['pool_address']))
        job_id = hexlify(struct.pack(str("I"), self.net_state['job_counter']))
        logger.info(
            "Generating new block template with {} trans. Diff {}. Subsidy {}."
            .format(len(self.last_gbt['transactions']),
                    bits_to_difficulty(self.last_gbt['bits']),
                    self.last_gbt['coinbasevalue']))
        bt_obj = BlockTemplate.from_gbt(
            self.last_gbt, coinbase, extranonce_length, [
                Transaction(unhexlify(t['data']), fees=t['fee'])
                for t in self.last_gbt['transactions']
            ])
        bt_obj.mm_later = copy(mm_later)
        hashes = [bitcoin_data.hash256(tx.raw) for tx in bt_obj.transactions]
        bt_obj.merkle_link = bitcoin_data.calculate_merkle_link([None] +
                                                                hashes, 0)
        bt_obj.job_id = job_id
        bt_obj.block_height = self.last_gbt['height']
        bt_obj.acc_shares = set()

        if push:
            if flush:
                logger.info("New work announced! Wiping previous jobs...")
                self.net_state['jobs'].clear()
                self.net_state['latest_job'] = None
            else:
                logger.info("New work announced!")

        self.net_state['job_counter'] += 1
        self.net_state['jobs'][job_id] = bt_obj
        self.net_state['latest_job'] = job_id
        if push:
            for idx, client in viewitems(self.stratum_clients):
                try:
                    if flush:
                        client.new_block_event.set()
                    else:
                        client.new_work_event.set()
                except AttributeError:
                    pass

        if new_block:
            hex_bits = hexlify(bt_obj.bits)
            self.net_state['work']['difficulty'] = bits_to_difficulty(hex_bits)
            if self.config['send_new_block']:
                self.celery.send_task_pp('new_block', bt_obj.block_height,
                                         hex_bits, bt_obj.total_value)