Exemplo n.º 1
0
    def create_transaction(to_address,
                           amount,
                           from_address=None,
                           password=None):
        """
        Created a transaction and saves it.

        :param to_address:
        :param amount:
        :param from_address:
        :param password:
        :return: the transaction stored
        """
        if from_address:
            """
            keystore = Prisma().wallet.decrypt_keystore(from_address, password)
            if not keystore:
                raise Exception('The wallet provided is invalid or is not stored in the system.')
            """
            raise Exception(
                'It\'s not possible to send from another wallet different than the main wallet atm. Sorry!'
            )
        else:
            keystore = Prisma().graph.keystore
        transaction = Prisma().wallet.transaction.form_funds_tx(
            keystore, to_address, amount)
        Prisma().wallet.transaction_buffer_add(transaction)
        return {
            'transaction_stored':
            Prisma().wallet.transaction.unhexlify_transaction(transaction)
        }
Exemplo n.º 2
0
    def add_event(self, blake2hash, ev):
        """
        Save event to database

        :param blake2hash: event hash
        :type blake2hash: str
        :param ev: Event = named tuple containing : d p c t s
        :type ev: named tuple
        :return: True if successfully added and False otherwise
        :rtype: bool
        """
        try:
            Prisma().graph.tbd.add(blake2hash)
            if ev.p == ():
                if not Prisma().db.insert_height({blake2hash: 0}):
                    self.logger.error(
                        "Could not add root event with blake2b hash %s.",
                        str(blake2hash))
                    return False
            else:
                height_list = []
                for p in ev.p:
                    height_list.append(Prisma().db.get_height(p))
                if not Prisma().db.insert_height(
                    {blake2hash: max(height_list) + 1}):
                    self.logger.debug(
                        "Could not add new event with blake2b hash %s",
                        str(blake2hash))
                    return False
            Prisma().db.insert_event({blake2hash: ev})
        except Exception as e:
            self.logger.error("Could not add new event. Reason:", e)
            return False
        return True
Exemplo n.º 3
0
    def get_clean_remote_cg(self, remote_cg):
        """
        Removes events from remote cg we have already signed or know.

        :param: remote cryptograph with events that we might know
        :type remote_cg: tuple
        :returns: remote cg without events that we have already sign or know
        :rtype: dict
        """
        remote_cg = self._event.restore(remote_cg)

        for event_hash in list(remote_cg):
            event_round = Prisma().db.get_round(event_hash)

            if event_round == -1:
                self.logger.error("Could not clean remote cg: get event round ERROR !")
                return False

            if (event_round and event_round <= self.last_signed_state) \
                    or Prisma().db.get_event(event_hash, as_tuple=False):
                self.logger.debug("CLEANING DELETE hash = %s", str(event_hash))
                del remote_cg[event_hash]

        self.logger.debug("Clean remote HG %s", str(remote_cg))
        return remote_cg
Exemplo n.º 4
0
    def insert_processed_transaction(self, ev_hash_list, round, self_pub_key):
        """
        Inserts processed tx (the one, that was included in final tx order) by event hash
        Should be used only in order.py

        :param ev_hash_list: list of events for which final order was found
        :type ev_hash_list: list
        :param round: round of all events, used later to generate state and clean db
        :type round: int
        :param private_key_seed: node private key seed needed to create and afterwards to check verify key
        :type private_key_seed: str
        :return:
        """
        self.logger.debug(
            "insert_processed_transaction input ev_hash_list = %s, round = %s, pub_key = %s",
            str(ev_hash_list), str(round), str(self_pub_key))

        tx_list = []
        for event_hash in ev_hash_list:
            self.logger.debug(
                "insert_processed_transaction for ev with hash %s",
                str(event_hash))
            event = Prisma().db.get_event(event_hash)
            Prisma().db.set_round_handled({event_hash: round})
            self.logger.debug("insert_transaction_by_ev_hash event %s",
                              str(event))
            if not event:
                self.logger.error(
                    "Could not insert tx, event there is no event !")
                return False

            if len(event.d) > 0:
                if event.c != self_pub_key.decode("utf-8"):
                    for tx_hex in event.d:
                        tx = self.parse_transaction_hex(tx_hex)
                        # Money transfer
                        if (tx and 'type' in tx
                                and int(tx['type']) == TYPE_MONEY_TRANSFER
                                and 'amount' in tx and 'senderId' in tx
                                and 'recipientId' in tx):
                            tx['tx_dict_hex'] = tx_hex
                            tx['ev_hash'] = event_hash
                            tx['round'] = round
                            tx_list.append(tx)
                            self.logger.debug("Insert money transfer tx %s",
                                              str(tx))
                        # State signature
                        elif tx and 'type' in tx and int(
                                tx['type']) == TYPE_SIGNED_STATE:
                            # Handle new signatures that was crated by remote node
                            self.logger.debug("Handle remote sign %s", str(tx))
                            Prisma().state_manager.handle_new_sign(tx)
                        # Error
                        else:
                            self.logger.error(
                                "Skipping malformed transaction data for event hash: %s",
                                str(tx))
                else:
                    Prisma().db.set_transaction_round(event_hash, round)
        return Prisma().db.insert_transactions(tx_list)
Exemplo n.º 5
0
    def local_cryptograph_response(self, signed_event_response):
        """
        Based on the get_event_response and the data generated in signed_event_response()
        on the remote peer we calculate a subset of events that the asking node does not
        know about. The two parents and their height are used below. Returns a dict;
        see crypto.py

        :param signed_event_response: signed remote events and last remote event time
        :type signed_event_response: dict
        :returns: signed local events or False if error
        :rtype: dict or bool
        """
        head = Prisma().db.get_head()

        self.logger.debug("signed_event_response %s", str(signed_event_response))
        self.logger.debug("head %s", str(head))
        # cg is a list of event tuples, it should be a dict of tuples

        if head:
            cs = json.loads((self.crypto.verify_concatenated(signed_event_response)).decode('utf-8'))
            # cs are a dict
            subset = {h: Prisma().db.get_event(h)
                      for h in self._cgc.bfs((head,),
                                                   lambda u: (p for p in
                                                              Prisma().db.get_event(u, clear_parent=True).p
                                                              if Prisma().db.get_event(p).c not in cs or
                                                              Prisma().db.get_height(p) > cs[Prisma().db.get_event(p).c]))}
            response = json.dumps((head, subset))
            local_cryptograph_response_res = self.crypto.sign_data(response, self.keystore['privateKeySeed'])
            self.logger.debug("local_cryptograph_response_res %s", str(local_cryptograph_response_res))
            return local_cryptograph_response_res
        return False
Exemplo n.º 6
0
 def sync_genesis(self):
     """
     Insert genesis state if it is not exist
     """
     if not Prisma().db.get_state(-1):
         gen_state = Common().read_genesis_state()
         self.logger.debug("genesis_state: %s", str(gen_state))
         Prisma().db.insert_state(gen_state['state'], gen_state['hash'], gen_state['signed'])
Exemplo n.º 7
0
    def download_state_from_random_peer(self):
        """
        This will get the state of a random peer.
        """
        random_peer = Prisma().db.get_random_peer()

        # if list is empty
        if not random_peer:
            self.logger.info(
                'No peers to connect to. Wait to some peer to connect with you or restart with a peer.'
            )
            self.callLater(2, lambda: self.download_state_from_random_peer())
            return

        random_peer = random_peer.pop()
        host = random_peer['host']
        port = random_peer['port']
        client = TCP4ClientEndpoint(self.reactor, host, port, self.timeout)
        d = client.connect(self.factory)

        # in case of connection ok, add the callbacks for get_state
        def connection_ok(protocol):
            protocol.d = defer.Deferred()

            def get_state_ok(_):
                self.logger.info(
                    'Successfully got the state from {0}:{1}'.format(
                        host, port))
                self.status = STATUS_READY

            protocol.d.addCallback(get_state_ok)

            def get_state_error(reason):
                error_message = reason.getErrorMessage()
                self.logger.error(
                    'Error when getting state from {0}:{1}: {2}'.format(
                        host, port, error_message))
                protocol.close_connection()
                self.callLater(0,
                               lambda: self.download_state_from_random_peer())

            protocol.d.addErrback(get_state_error)

            protocol.send_get_state()

        d.addCallback(connection_ok)

        # in case of connection error show in debug and try again
        def connection_error(reason):
            # in case of error remove the peer from the database
            addr = random_peer['host'] + ':' + str(random_peer['port'])
            self.logger.debug('Error while connecting to {0}: {1}'.format(
                addr, reason.getErrorMessage()))
            Prisma().db.delete_peer(random_peer['_id'])
            # then call later again
            self.callLater(0, lambda: self.download_state_from_random_peer())

        d.addErrback(connection_error)
Exemplo n.º 8
0
    def get_peers_from_random_peer(self):
        """
        Gets a random a peer from the database and connects to it and asks for peers.
        """
        # get a random peer from database
        random_peer = Prisma().db.get_random_peer()

        # if list is empty
        if not random_peer:
            self.logger.info(
                'No peers to connect to. Wait to some peer to connect with you or restart with a peer.'
            )
            return

        random_peer = random_peer.pop()
        host = random_peer['host']
        port = random_peer['port']
        client = TCP4ClientEndpoint(self.reactor, host, port, self.timeout)
        d = client.connect(self.factory)

        # in case of connection ok, add the callbacks for get_peers and call send_get_peers
        def connection_ok(protocol):
            protocol.d = defer.Deferred()

            def get_peers_ok(_):
                self.logger.info('Successfully got peers from {0}:{1}'.format(
                    host, port))

            protocol.d.addCallback(get_peers_ok)

            def get_peers_error(reason):
                error_message = reason.getErrorMessage()
                self.logger.error(
                    'Error when getting peers from {0}:{1}: {2}'.format(
                        host, port, error_message))
                protocol.close_connection()
                self.get_peers_lc.reset()
                self.get_peers_from_random_peer()

            protocol.d.addErrback(get_peers_error)

            protocol.send_get_peers()

        d.addCallback(connection_ok)

        # in case of connection error show in debug and try again
        def connection_error(reason):
            # in case of error remove the peer from the database
            addr = random_peer['host'] + ':' + str(random_peer['port'])
            self.logger.debug('Error while connecting to {0}: {1}'.format(
                addr, reason.getErrorMessage()))
            Prisma().db.delete_peer(random_peer['_id'])
            # then restart timer and try again get_peers_from_random_peer
            self.get_peers_lc.reset()
            self.get_peers_from_random_peer()

        d.addErrback(connection_error)
Exemplo n.º 9
0
    def get_my_balance():
        """
        Get the balance in the current node keystore

        :return: my balance
        """
        address = Prisma().graph.keystore['address']
        my_balance = Prisma().db.get_account_balance(address)
        return {'my_address': address, 'my_balance': my_balance}
Exemplo n.º 10
0
 def _set_up(self):
     self._destroy_db()
     CONFIG.set('general', 'database', self.DATABASE_NAME)
     CONFIG.set('general', 'network', 'testnet')
     CONFIG.set('general', 'wallet_address', '3918807197700602162PR')
     CONFIG.set('bootstrap', 'bootstrap_nodes', '[]')
     CONFIG.set('developer', 'wallet_password', 'test1')
     self.clock = task.Clock()
     self.prisma = Prisma()
     self.prisma.callLater = self.clock.callLater
     self.prisma.start(False)
Exemplo n.º 11
0
    def init_graph(self):
        self.last_signed_state = Prisma().db.get_consensus_last_signed()
        self.logger.debug("INIT last_signed_state: %s", str(self.last_signed_state))

        is_cg_empty = self.init_events()
        self.restore_invariants(is_cg_empty)

        if is_cg_empty:
            self.sync_genesis()

        self.unsent_count = len(Prisma().db.get_consensus_greater_than(
            Prisma().db.get_consensus_last_created_sign()))
Exemplo n.º 12
0
    def higher(a, b):
        """
        Check if height of a bigger than height of b

        :param a: first event hash
        :type a: str
        :param b: second event hash
        :type b: str
        :return: is a higher
        :rtype: bool
        """
        return a is not None and (b is None or Prisma().db.get_height(a) >=
                                  Prisma().db.get_height(b))
Exemplo n.º 13
0
    def send_get_peers(protocol):
        """
        Prepare and send get_peers.

        :param protocol:
        """
        request_data = {
            'method': 'get_peers',
            '_id': Prisma().network.node_id,
            'port': Prisma().network.listen_port,
            'latest_event': Prisma().db.get_latest_event_time()
        }
        protocol.send_data(request_data)
Exemplo n.º 14
0
    def list_transactions():
        """
        Returns a list of buffered transactions.

        :return: the transaction buffer unhexified.
        """
        i = 0
        data = {}
        if len(Prisma().wallet.transaction_buffer) == 0:
            return {'message': 'The buffer is empty.'}
        for transaction in Prisma().wallet.transaction_buffer:
            data[i] = Prisma().wallet.transaction.unhexlify_transaction(
                transaction)
            i += 1
        return data
Exemplo n.º 15
0
    def create_transaction_and_send(to_address, amount):
        """
        Creates a transaction and inserts it to the pool.

        :param to_address: address
        :param amount: int
        """
        transaction = Prisma().wallet.transaction.form_funds_tx(
            Prisma().graph.keystore, to_address, amount)
        Prisma().wallet.transaction.insert_transactions_into_pool(
            [transaction])
        return {
            'transaction':
            Prisma().wallet.transaction.unhexlify_transaction(transaction)
        }
Exemplo n.º 16
0
    def last_event_time():
        """
        Returns the latest event time.

        :return: last event
        """
        return {'latest_event_time': Prisma().db.get_latest_event_time()}
Exemplo n.º 17
0
 def __init__(self):
     self.logger = logging.getLogger('Protocol')
     self.validate = Validator()
     self.callLater = Prisma().callLater
     self.peer = None
     self.host = None
     self.d = None
Exemplo n.º 18
0
    def list_wallets():
        """
        Returns a list of wallet addresses stored.

        :return: a list of wallet addresses
        """
        return {'addresses': Prisma().graph.wallet.list_wallets()}
Exemplo n.º 19
0
    def handle_get_peers_response(protocol, peers):
        """
        Add peers from the response to the database. Then close connection.

        :param protocol:
        :param peers:
        """
        for peer in peers:
            if Prisma().network.node_id != peer[
                    '_id'] and protocol.validate.is_valid_node_ip(
                        peer['host']):
                Prisma().db.insert_peer(peer)

        # everything ok, so do the callback and close connection
        protocol.d.callback(None)
        protocol.close_connection()
Exemplo n.º 20
0
    def peer_count():
        """
        Returns the number of connected peers.

        :return: a list of peers
        """
        return {'peer_count': Prisma().db.count_peers()}
Exemplo n.º 21
0
    def peer_list():
        """
        Returns a list with all the peers in our database.

        :return: a list of peers
        """
        return {'peer_list': Prisma().db.get_peers_many()}
Exemplo n.º 22
0
    def is_client(self):
        """
        If our port is not our listen port then we are the client.

        :return: bool
        """
        return self.host.port != Prisma().network.listen_port
Exemplo n.º 23
0
        def iter_voters():
            """
            For each event round in range (max_c; max_r]
            get witness from db
            (order is from earlier rounds to later)

            :return: witnesses in format (round, witness hash)
            :rtype: generator
            """

            self.logger.debug("MAX_C value = %s", str(max_c))
            for _r in range(max_c + 1, max_r + 1):
                self.logger.debug("X value = %s", str(_r))
                witness = Prisma().db.get_witness(_r)
                for w in witness.values():
                    yield _r, w
Exemplo n.º 24
0
 def __init__(self):
     # prepare websocket client
     self.info_peer_count = 0
     self.info_last_event_time = False
     self.info_my_balance = False
     self.info_my_address = False
     self.block = False
     self.client_factory = ClientFactory(url='ws://127.0.0.1:{}'.format(Prisma().api.port))
     self.client_factory.prompt = self
     self.client_connection = connectWS(self.client_factory)
     # prompt style
     self.print_style_green = style_from_dict({
         Token.Text: '#00cc00',
     })
     self.print_style_red = style_from_dict({
         Token.Text: '#cc0000',
     })
     self.prompt_style = style_from_dict({
         Token.Pound:    '#ffff00',
         Token.Toolbar:  '#00ee00 bg:#333333',
     })
     # prompt autocompletion
     words = []
     for command in self.command_list:
         words.append(command['command'])
     self.completer = WordCompleter(words, ignore_case=True, sentence=True)
     # prompt memory
     self.history = FileHistory(expanduser('~/.prisma/history.txt'))
Exemplo n.º 25
0
    def insert_transactions_into_pool(self, tx_list):
        """
        Prepares and inserts transactions into tx pool.
        They will be inserted into event as soon as
        it will be created.

        :param tx_list: list of finalized transactions
        :type tx_list: list
        :return: insertion result
        :rtype: bool
        """
        if tx_list:
            prepared_tx_list = []
            for tx_hex in tx_list:
                tx = self.parse_transaction_hex(tx_hex)
                if tx:
                    tx['tx_dict_hex'] = tx_hex
                    self.logger.debug("Prepared for pool tx %s", str(tx))
                    prepared_tx_list.append(tx)
                else:
                    self.logger.error(
                        "Skipping inserting malformed transaction %s", str(tx))
                    continue
            return Prisma().db.insert_transactions(prepared_tx_list)
        return False
Exemplo n.º 26
0
 def connection_error(reason):
     # in case of error remove the peer from the database
     addr = random_peer['host'] + ':' + str(random_peer['port'])
     self.logger.debug('Error while connecting to {0}: {1}'.format(
         addr, reason.getErrorMessage()))
     Prisma().db.delete_peer(random_peer['_id'])
     # then call later again
     self.callLater(0, lambda: self.download_state_from_random_peer())
Exemplo n.º 27
0
 def decrypt_wallet(address, password):
     decrypted_wallet = Prisma().graph.wallet.decrypt_keystore(
         address, password)
     return {
         'address': decrypted_wallet['address'],
         'public_key': decrypted_wallet['publicKey'].decode('utf-8'),
         'private_key': decrypted_wallet['privateKeySeed'].decode('utf-8')
     }
Exemplo n.º 28
0
 def stop(self):
     """
     Closes the client connection and stops the manager.
     """
     self.print('Exiting, please wait...')
     self.client_connection.transport.protocol.sendClose()
     sleep(0.1)  # this has to be replaced to a clean way to wait until sendClose() is finished.
     Prisma().stop()
Exemplo n.º 29
0
    def restore_invariants(self, is_cg_empty):
        """
        Initializes cryptograph if it is empty

        :param  is_cg_empty: is cryptograph empty
                (this arg func get from init_events)
        :return: None
        """
        if is_cg_empty:
            h, ev = self._event.new_event([], ())
            self._event.add_event(h, ev)
            Prisma().db.insert_round({h: 0})
            Prisma().db.insert_witness({0: {ev.c: h}})
            Prisma().db.insert_can_see({h: {ev.c: h}})
            Prisma().db.insert_head(h)
        else:
            self.logger.debug("Reconnect")
Exemplo n.º 30
0
    def strongly_see(self, h, r):
        """
        Get nodes that given event can strongly see

        :param h: event hash
        :type h: str
        :param r: round
        :type r: int
        :return: nodes that can strongly see that event
        :rtype: set
        """
        self.logger.debug("strongly_see start h = %s, r = %s", str(h), str(r))
        self.logger.debug("Witneeses on round r %s",
                          str(Prisma().db.get_witness(r)))
        hits = defaultdict(int)
        for c, k in Prisma().db.get_can_see(h).items():
            self.logger.debug("strongly_see k = %s ", str(k))
            self.logger.debug("strongly_see k (round) = %s",
                              str(Prisma().db.get_round(k)))
            if Prisma().db.get_round(k) == r:
                for c_, k_ in Prisma().db.get_can_see(k).items():
                    self.logger.debug("strongly_see k______ = %s ", str(k_))
                    self.logger.debug("strongly_see k______(round) = %s ",
                                      str(Prisma().db.get_round(k_)))
                    if Prisma().db.get_round(k_) == r:
                        # TODO change it to node stake
                        hits[c_] += 1

        self.logger.debug("strongly_see hits = %s", str(hits))
        res = set()
        for c, n in hits.items():
            if n >= self.graph.min_s:
                res.add(c)
        self.logger.debug("strongly_see res %s", str(res))
        return res