Exemplo n.º 1
0
    def nodes_block_submit(self, block_send):
        for k, v in self.peer_dict.items():
            peer_ip = k
            # app_log.info(HOST)
            peer_port = int(v)
            # app_log.info(PORT)
            # connect to all nodes

            try:
                s_peer = socks.socksocket()
                s_peer.settimeout(0.3)
                if self.tor_conf == 1:
                    s_peer.setproxy(socks.PROXY_TYPE_SOCKS5, "127.0.0.1", 9050)
                s_peer.connect(
                    (peer_ip, int(peer_port)))  # connect to node in peerlist
                print("Connected")

                print("Miner: Proceeding to submit mined block to node")

                connections.send(s_peer, "block", 10)
                connections.send(s_peer, block_send, 10)

                print("Miner: Block submitted to node {}".format(peer_ip))
            except Exception as e:
                print("Miner: Could not submit block to node {} because {}".
                      format(peer_ip, e))
                pass
Exemplo n.º 2
0
 def api_listreceived(self, socket_handler, ledger_db, peers):
     """
     Returns the total amount received for each given address with minconf, including empty addresses or not.
     :param socket_handler:
     :param ledger_db:
     :param peers:
     :return:
     """
     received = {}
     # TODO: this is temporary.
     # Will need more work to send full featured info needed for https://bitcoin.org/en/developer-reference#listreceivedbyaddress
     # (confirmations and tx list)
     try:
         # get the addresses (it's a list, even if a single address)
         addresses = connections.receive(socket_handler)
         minconf = connections.receive(socket_handler)
         if minconf < 1:
             minconf = 1
         include_empty = connections.receive(socket_handler)
         for address in addresses:
             temp = self._get_received(ledger_db, address, minconf)
             if include_empty or temp > 0:
                 received[address] = temp
         print('api_listreceived', addresses, minconf, ':', received)
         connections.send(socket_handler, received)
     except Exception as e:
         raise
Exemplo n.º 3
0
 def api_listbalance(self, socket_handler, ledger_db, peers):
     """
     Returns the total amount received for each given address with minconf, including empty addresses or not.
     :param socket_handler:
     :param ledger_db:
     :param peers:
     :return:
     """
     balances = {}
     try:
         # get the addresses (it's a list, even if a single address)
         addresses = connections.receive(socket_handler)
         minconf = connections.receive(socket_handler)
         if minconf < 1:
             minconf = 1
         include_empty = connections.receive(socket_handler)
         # TODO: Better to use a single sql query with all addresses listed?
         for address in addresses:
             temp = self._get_balance(ledger_db, address, minconf)
             if include_empty or temp > 0:
                 balances[address] = temp
         print('api_listbalance', addresses, minconf, ':', balances)
         connections.send(socket_handler, balances)
     except Exception as e:
         raise
Exemplo n.º 4
0
    def calculate_difficulty(self):
        # calculate difficulty
        s_node = socks.socksocket()
        if self.tor_conf == 1:
            s_node.setproxy(socks.PROXY_TYPE_SOCKS5, "127.0.0.1", 9050)
        s_node.connect(
            (self.node_ip_conf, int(self.port)))  # connect to local node

        connections.send(s_node, "blocklast", 10)
        blocklast = connections.receive(s_node, 10)
        db_block_hash = blocklast[7]

        connections.send(s_node, "diffget", 10)
        diff = connections.receive(s_node, 10)
        s_node.close()

        diff = int(diff[1])

        diff_real = int(diff)

        if self.pool_conf == 0:
            diff = int(diff)
        else:  # if pooled
            diff_pool = diff_real
            diff = self.percentage(self.pool_diff_percentage, diff_real)

            if diff > diff_pool:
                diff = diff_pool

        mining_condition = bin_convert(db_block_hash)[0:diff]

        return db_block_hash, diff, diff_real, mining_condition
Exemplo n.º 5
0
 def api_ping(self, socket_handler, ledger_db, peers):
     """
     Void, just to allow the client to keep the socket open (avoids timeout)
     :param socket_handler:
     :param ledger_db:
     :param peers:
     :return: 'api_pong'
     """
     connections.send(socket_handler, 'api_pong')
Exemplo n.º 6
0
    def api_gettransaction(self, socket_handler, ledger_db, peers):
        """
        returns total balance for a list of addresses and minconf
        BEWARE: this is NOT the json rpc getbalance (that get balance for an account, not an address)
        :param socket_handler:
        :param ledger_db:
        :param peers:
        :return:
        """
        transaction = {}
        try:
            # get the txid
            transaction_id = connections.receive(socket_handler)
            # and format
            format = connections.receive(socket_handler)
            # raw tx details
            dbhandler.execute_param(
                self.app_log, ledger_db,
                "SELECT * FROM transactions WHERE signature like ?",
                (transaction_id + '%', ))
            raw = ledger_db.fetchone()
            if not format:
                connections.send(socket_handler, raw)
                print('api_gettransaction', format, raw)
                return

            # current block height, needed for confirmations #
            dbhandler.execute(self.app_log, ledger_db,
                              "SELECT MAX(block_height) FROM transactions")
            block_height = ledger_db.fetchone()[0]
            transaction['txid'] = transaction_id
            transaction['time'] = raw[1]
            transaction['hash'] = raw[5]
            transaction['address'] = raw[2]
            transaction['recipient'] = raw[3]
            transaction['amount'] = raw[4]
            transaction['fee'] = raw[8]
            transaction['reward'] = raw[9]
            transaction['keep'] = raw[10]
            transaction['openfield'] = raw[11]
            transaction['pubkey'] = base64.b64decode(raw[6]).decode('utf-8')
            transaction['blockhash'] = raw[7]
            transaction['blockheight'] = raw[0]
            transaction['confirmations'] = block_height - raw[0]
            # Get more info on the block the tx is in.
            dbhandler.execute_param(
                self.app_log, ledger_db,
                "SELECT timestamp, recipient FROM transactions WHERE block_height= ? AND reward > 0",
                (raw[0], ))
            block_data = ledger_db.fetchone()
            transaction['blocktime'] = block_data[0]
            transaction['blockminer'] = block_data[1]
            print('api_gettransaction', format, transaction)
            connections.send(socket_handler, transaction)
        except Exception as e:
            raise
Exemplo n.º 7
0
 def api_clearmempool(self, socket_handler, ledger_db, peers):
     """
     Empty the current mempool
     :param socket_handler:
     :param ledger_db:
     :param peers:
     :return: 'ok'
     """
     mp.MEMPOOL.clear()
     connections.send(socket_handler, 'ok')
Exemplo n.º 8
0
 def api_mempool(self, socket_handler, ledger_db, peers):
     """
     Returns all the TX from mempool
     :param socket_handler:
     :param ledger_db:
     :param peers:
     :return: list of mempool tx
     """
     txs = mp.MEMPOOL.fetchall(mp.SQL_SELECT_TX_TO_SEND)
     connections.send(socket_handler, txs)
Exemplo n.º 9
0
    def api_getblocksincewhere(self, socket_handler, ledger_db, peers):
        """
        Returns the full transactions following a given block_height and with specific conditions
        Returns at most transactions from 720 blocks at a time (the most *older* ones if it truncates) so about 12 hours worth of data.
        Maybe huge, use with caution and restrictive queries only.
        :param socket_handler:
        :param ledger_db:
        :param peers:
        :return:
        """
        info = []
        # get the last known block
        since_height = connections.receive(socket_handler)
        where_conditions = connections.receive(socket_handler)
        print('api_getblocksincewhere', since_height, where_conditions)
        # TODO: feed as array to have a real control and avoid sql injection !important
        # Do *NOT* use in production until it's done.
        raise ValueError("Unsafe, do not use yet")
        """
        [
        ['','openfield','like','egg%']
        ]

        [
        ['', '('],
        ['','reward','>','0']
        ['and','recipient','in',['','','']]
        ['', ')'],
        ]
        """
        where_assembled = where_conditions
        conditions_assembled = ()
        try:
            try:
                dbhandler.execute(
                    self.app_log, ledger_db,
                    "SELECT MAX(block_height) FROM transactions")
                # what is the max block height to consider ?
                block_height = min(ledger_db.fetchone()[0], since_height + 720)
                #print("block_height",block_height)
                dbhandler.execute_param(self.app_log, ledger_db, (
                    'SELECT * FROM transactions WHERE block_height > ? and block_height <= ? and ( '
                    + where_assembled + ')'), (since_height, block_height) +
                                        conditions_assembled)
                info = ledger_db.fetchall()
                # it's a list of tuples, send as is.
                #print(all)
            except Exception as e:
                print(e)
                raise
            # print("info", info)
            connections.send(socket_handler, info)
        except Exception as e:
            print(e)
            raise
Exemplo n.º 10
0
    def connect_to_pool(self):
        s_pool = socks.socksocket()
        s_pool.settimeout(0.3)
        if self.tor_conf == 1:
            s_pool.setproxy(socks.PROXY_TYPE_SOCKS5, "127.0.0.1", 9050)
        s_pool.connect((self.pool_ip_conf, 8525))  # connect to pool
        print("Connected")

        print(
            "Miner: Asking pool for share qualification difficulty requirement"
        )
        connections.send(s_pool, "diffp", 10)
        self.pool_diff_percentage = int(connections.receive(s_pool, 10))
        print(
            "Miner: Received pool for share qualification difficulty requirement: {}%"
            .format(self.pool_diff_percentage))
        s_pool.close()
        return self
Exemplo n.º 11
0
 def api_getblockswhereoflike(self, socket_handler, ledger_db, peers):
     """
     Returns the full transactions following a given block_height and with openfield begining by the given string
     Returns at most transactions from 1440 blocks at a time (the most *older* ones if it truncates) so about 1 day worth of data.
     Maybe huge, use with caution and on restrictive queries only.
     :param socket_handler:
     :param ledger_db:
     :param peers:
     :return:
     """
     info = []
     # get the last known block
     since_height = int(connections.receive(socket_handler))
     where_openfield_like = connections.receive(socket_handler) + '%'
     #print('api_getblockswhereoflike', since_height, where_openfield_like)
     try:
         try:
             dbhandler.execute(
                 self.app_log, ledger_db,
                 "SELECT MAX(block_height) FROM transactions")
             # what is the max block height to consider ?
             block_height = min(ledger_db.fetchone()[0],
                                since_height + 1440)
             #print("block_height", since_height, block_height)
             dbhandler.execute_param(
                 self.app_log, ledger_db,
                 'SELECT * FROM transactions WHERE block_height > ? and block_height <= ? and openfield like ?',
                 (since_height, block_height, where_openfield_like))
             info = ledger_db.fetchall()
             # it's a list of tuples, send as is.
             #print("info", info)
         except Exception as e:
             print("error", e)
             raise
         # Add the last fetched block so the client will be able to fetch the next block
         info.append([block_height])
         connections.send(socket_handler, info)
     except Exception as e:
         print(e)
         exc_type, exc_obj, exc_tb = sys.exc_info()
         fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
         print(exc_type, fname, exc_tb.tb_lineno)
         raise
Exemplo n.º 12
0
 def api_getaddressinfo(self, socket_handler, ledger_db, peers):
     """
     Returns a dict with
     known: Did that address appear on a transaction?
     pubkey: The pubkey of the address if it signed a transaction,
     :param address: The bismuth address to examine
     :return: dict
     """
     info = {'known': False, 'pubkey': ''}
     # get the address
     address = connections.receive(socket_handler)
     # print('api_getaddressinfo', address)
     try:
         # format check
         if not re.match('[abcdef0123456789]{56}', address):
             self.app_log.info("Bad address format <{}>".format(address))
             connections.send(socket_handler, info)
             return
         try:
             dbhandler.execute_param(self.app_log, ledger_db, (
                 'SELECT block_height FROM transactions WHERE address= ? or recipient= ? LIMIT 1;'
             ), (address, address))
             ledger_db.fetchone()[0]
             # no exception? then we have at least one known tx
             info['known'] = True
             dbhandler.execute_param(self.app_log, ledger_db, (
                 'SELECT public_key FROM transactions WHERE address= ? and reward = 0 LIMIT 1;'
             ), (address, ))
             try:
                 info['pubkey'] = ledger_db.fetchone()[0]
                 info['pubkey'] = base64.b64decode(
                     info['pubkey']).decode('utf-8')
             except Exception as e:
                 print(e)
                 pass
         except Exception as e:
             pass
         # returns info
         # print("info", info)
         connections.send(socket_handler, info)
     except Exception as e:
         pass
Exemplo n.º 13
0
 def api_getpeerinfo(self, socket_handler, ledger_db, peers):
     """
     Returns a list of connected peers
     See https://bitcoin.org/en/developer-reference#getpeerinfo
     To be adjusted
     :return: list(dict)
     """
     print('api_getpeerinfo')
     # TODO: Get what we can from peers, more will come when connections and connection stats will be modular, too.
     try:
         info = [{
             'id': id,
             'addr': ip,
             'inbound': True
         } for id, ip in enumerate(peers.consensus)]
         # TODO: peers will keep track of extra info, like port, last time, block_height aso.
         # TODO: add outbound connection
         connections.send(socket_handler, info)
     except Exception as e:
         pass
Exemplo n.º 14
0
 def api_getreceived(self, socket_handler, ledger_db, peers):
     """
     returns total received amount for a *list* of addresses and minconf
     :param socket_handler:
     :param ledger_db:
     :param peers:
     :return:
     """
     received = 0
     try:
         # get the addresses (it's a list, even if a single address)
         addresses = connections.receive(socket_handler)
         minconf = connections.receive(socket_handler)
         if minconf < 1:
             minconf = 1
         # TODO: Better to use a single sql query with all addresses listed?
         for address in addresses:
             received += self._get_received(ledger_db, address, minconf)
         print('api_getreceived', addresses, minconf, ':', received)
         connections.send(socket_handler, received)
     except Exception as e:
         raise
Exemplo n.º 15
0
 def api_getbalance(self, socket_handler, ledger_db, peers):
     """
     returns total balance for a list of addresses and minconf
     BEWARE: this is NOT the json rpc getbalance (that get balance for an account, not an address)
     :param socket_handler:
     :param ledger_db:
     :param peers:
     :return:
     """
     balance = 0
     try:
         # get the addresses (it's a list, even if a single address)
         addresses = connections.receive(socket_handler)
         minconf = connections.receive(socket_handler)
         if minconf < 1:
             minconf = 1
         # TODO: Better to use a single sql query with all addresses listed?
         for address in addresses:
             balance += self._get_balance(ledger_db, address, minconf)
         #print('api_getbalance', addresses, minconf,':', balance)
         connections.send(socket_handler, balance)
     except Exception as e:
         raise
Exemplo n.º 16
0
 def api_getblocksince(self, socket_handler, ledger_db, peers):
     """
     Returns the full blocks and transactions following a given block_height
     Returns at most transactions from 10 blocks (the most recent ones if it truncates)
     Used by the json-rpc server to poll and be notified of tx and new blocks.
     :param socket_handler:
     :param ledger_db:
     :param peers:
     :return:
     """
     info = []
     # get the last known block
     since_height = connections.receive(socket_handler)
     #print('api_getblocksince', since_height)
     try:
         try:
             dbhandler.execute(
                 self.app_log, ledger_db,
                 "SELECT MAX(block_height) FROM transactions")
             # what is the min block height to consider ?
             block_height = max(ledger_db.fetchone()[0] - 11, since_height)
             #print("block_height",block_height)
             dbhandler.execute_param(
                 self.app_log, ledger_db,
                 ('SELECT * FROM transactions WHERE block_height > ?;'),
                 (block_height, ))
             info = ledger_db.fetchall()
             # it's a list of tuples, send as is.
             #print(all)
         except Exception as e:
             print(e)
             raise
         # print("info", info)
         connections.send(socket_handler, info)
     except Exception as e:
         print(e)
         raise
Exemplo n.º 17
0
    def mine(self, q, privatekey_readable, public_key_hashed, address):
        Random.atfork()
        rndfile = Random.new()
        tries = 0
        key = RSA.importKey(privatekey_readable)

        if self.pool_conf == 1:
            #do not use pools public key to sign, signature will be invalid
            self_address = address
            address = self.pool_address
            self.connect_to_pool()

        while True:
            try:
                # block_hash = hashlib.sha224(str(block_send) + db_block_hash).hexdigest()
                db_block_hash, diff, diff_real, mining_condition = self.calculate_difficulty(
                )

                while tries < self.diff_recalc_conf:
                    start = time.time()

                    nonce = hashlib.sha224(rndfile.read(16)).hexdigest()[:32]
                    mining_hash = bin_convert(
                        hashlib.sha224(
                            (address + nonce +
                             db_block_hash).encode("utf-8")).hexdigest())

                    end = time.time()
                    if tries % 2500 == 0:  #limit output
                        try:
                            cycles_per_second = 1 / (end - start)
                            print(
                                "Thread{} {} @ {:.2f} cycles/second, difficulty: {}({}), iteration: {}"
                                .format(q, db_block_hash[:10],
                                        cycles_per_second, diff, diff_real,
                                        tries))
                        except:
                            pass
                    tries += 1

                    if mining_condition in mining_hash:
                        tries = 0

                        print("Thread {} found a good block hash in {} cycles".
                              format(q, tries))

                        # serialize txs

                        block_send = []
                        del block_send[:]  # empty
                        removal_signature = []
                        del removal_signature[:]  # empty

                        s_node = socks.socksocket()
                        if self.tor_conf == 1:
                            s_node.setproxy(socks.PROXY_TYPE_SOCKS5,
                                            "127.0.0.1", 9050)
                        s_node.connect(
                            (self.node_ip_conf,
                             int(self.port)))  # connect to config.txt node
                        connections.send(s_node, "mpget", 10)
                        data = connections.receive(s_node, 10)
                        s_node.close()

                        if data != "[]":
                            mempool = data

                            for mpdata in mempool:
                                transaction = (str(mpdata[0]),
                                               str(mpdata[1][:56]),
                                               str(mpdata[2][:56]),
                                               '%.8f' % float(mpdata[3]),
                                               str(mpdata[4]), str(mpdata[5]),
                                               str(mpdata[6]), str(mpdata[7])
                                               )  # create tuple
                                # print transaction
                                block_send.append(
                                    transaction
                                )  # append tuple to list for each run
                                removal_signature.append(
                                    str(mpdata[4])
                                )  # for removal after successful mining

                        # claim reward
                        block_timestamp = '%.2f' % time.time()
                        transaction_reward = (
                            str(block_timestamp), str(address[:56]),
                            str(address[:56]), '%.8f' % float(0), "0",
                            str(nonce))  # only this part is signed!
                        # print transaction_reward

                        h = SHA.new(str(transaction_reward).encode("utf-8"))
                        signer = PKCS1_v1_5.new(key)
                        signature = signer.sign(h)
                        signature_enc = base64.b64encode(signature)

                        if signer.verify(h, signature):
                            print("Signature valid")

                            block_send.append(
                                (str(block_timestamp), str(address[:56]),
                                 str(address[:56]), '%.8f' % float(0),
                                 str(signature_enc.decode("utf-8")),
                                 str(public_key_hashed.decode("utf-8")), "0",
                                 str(nonce)))  # mining reward tx
                            print("Block to send: {}".format(block_send))

                            if not any(
                                    isinstance(el, list) for el in block_send
                            ):  # if it's not a list of lists (only the mining tx and no others)
                                new_list = []
                                new_list.append(block_send)
                                block_send = new_list  # make it a list of lists

                            #  claim reward
                            # include data

                            tries = 0

                            # submit mined block to node

                            if self.sync_conf == 1:
                                self.check_uptodate(300)

                            if self.pool_conf == 1:
                                mining_condition = bin_convert(
                                    db_block_hash)[0:diff_real]
                                if mining_condition in mining_hash:
                                    print(
                                        "Miner: Submitting block to all nodes, because it satisfies real difficulty too"
                                    )
                                    self.nodes_block_submit(block_send)

                                try:
                                    s_pool = socks.socksocket()
                                    s_pool.settimeout(0.3)
                                    if self.tor_conf == 1:
                                        s_pool.setproxy(
                                            socks.PROXY_TYPE_SOCKS5,
                                            "127.0.0.1", 9050)
                                    s_pool.connect((self.pool_ip_conf,
                                                    8525))  # connect to pool
                                    print("Connected")

                                    print(
                                        "Miner: Proceeding to submit mined block to pool"
                                    )

                                    connections.send(s_pool, "block", 10)
                                    connections.send(s_pool, self_address, 10)
                                    connections.send(s_pool, block_send, 10)
                                    s_pool.close()

                                    print("Miner: Block submitted to pool")

                                except Exception as e:
                                    print(
                                        "Miner: Could not submit block to pool"
                                    )
                                    pass

                            if self.pool_conf == 0:
                                self.nodes_block_submit(block_send)
                        else:
                            print("Invalid signature")
                tries = 0

            except Exception as e:
                print(e)
                time.sleep(0.1)
                if self.debug_conf == 1:
                    raise
                else:
                    pass