diff --git a/lib/ucoin/wrappers/transactions.py b/lib/ucoin/wrappers/transactions.py index f7878f0c2281bff870b01c82ad82eb13f1c1f93a..b16db9d7ecc93dab9ff86d0521bc1e1ab5bcd27b 100644 --- a/lib/ucoin/wrappers/transactions.py +++ b/lib/ucoin/wrappers/transactions.py @@ -24,15 +24,26 @@ logger = logging.getLogger("transactions") class Transaction(Wrapper): - def __init__(self, pgp_fingerprint, message='', keyid=None, peering=None, server=None, port=None): + def __init__(self, pgp_fingerprint, recipient, coins, message='', keyid=None, peering=None, server=None, port=None): super().__init__(server, port) self.keyid = keyid self.pgp_fingerprint = pgp_fingerprint self.message = message self.error = None self.peering = peering + self.recipient = recipient + self.coins = coins + self.coins.sort() def __call__(self): + tx = self.get_message() + txs = settings['gpg'].sign(tx, keyid=self.keyid, detach=True) + return {'transaction':tx, 'signature':txs} + + def get_context_data(self): + return {} + + def get_message(self): try: last_tx = hdc.transactions.sender.Last(count=1, pgp_fingerprint=self.pgp_fingerprint, server=self.server, port=self.port).get() @@ -55,6 +66,7 @@ class Transaction(Wrapper): context_data['previousHash'] = previous_hash context_data['message'] = self.message context_data['fingerprint'] = self.pgp_fingerprint + context_data['recipient'] = self.recipient context_data.update(self.get_context_data()) tx = """\ @@ -66,56 +78,6 @@ Number: %(number)d if last_tx: tx += "PreviousHash: %(previousHash)s\n" % context_data - try: - tx += self.get_message(context_data) - except ValueError as e: - self.error = e - return False - - tx += """\ -Comment: -%(message)s""" % context_data - - tx = tx.replace("\n", "\r\n") - print(self.keyid) - print(tx) - txs = settings['gpg'].sign(tx, keyid=self.keyid, detach=True) - print(txs) - print(tx) - return self.process(tx, txs) - - def get_context_data(self): - return {} - - def get_message(self, context_data, tx=''): - return tx - - def get_error(self): - return self.error - - def process(self, tx, txs): - try: - hdc.transactions.Process(self.server, self.port).post(transaction=tx, signature=txs) - except ValueError as e: - self.error = str(e) - else: - return True - - return False - - -class RawTransfer(Transaction): - def __init__(self, pgp_fingerprint, recipient, coins, message='', - keyid=None, server=None, port=None): - super().__init__(pgp_fingerprint, message, - keyid=keyid, server=server, port=port) - - self.recipient = recipient - self.coins = coins - self.coins.sort() - - def get_message(self, context_data, tx=''): - context_data['recipient'] = self.recipient tx += """\ Recipient: %(recipient)s @@ -130,5 +92,9 @@ Coins: else: tx += "\n" - return tx + tx += """\ +Comment: +%(message)s""" % context_data + tx = tx.replace("\n", "\r\n") + return tx diff --git a/res/ui/transferDialog.ui b/res/ui/transferDialog.ui index 9fdd70afcbc953e52783a4038f05d491baa99db8..2ac25e29a4e9d9350d8b730240ea3224aa1fb85c 100644 --- a/res/ui/transferDialog.ui +++ b/res/ui/transferDialog.ui @@ -69,80 +69,10 @@ </property> </widget> </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox_2"> - <property name="title"> - <string>Transfer using node</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QRadioButton" name="radio_trusted_node"> - <property name="text"> - <string>Trusted node</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="combo_trusted_node"> - <property name="enabled"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QRadioButton" name="radio_node_address"> - <property name="text"> - <string>Node</string> - </property> - <property name="checked"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="edit_node_address"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="inputMask"> - <string/> - </property> - <property name="placeholderText"> - <string>Node address</string> - </property> - </widget> - </item> <item> - <widget class="QLabel" name="label"> + <widget class="QPushButton" name="button_get_trusts"> <property name="text"> - <string>:</string> - </property> - </widget> - </item> - <item> - <widget class="QSpinBox" name="spinbox_port"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="maximum"> - <number>99999</number> - </property> - <property name="value"> - <number>8081</number> + <string>Get trusts nodes</string> </property> </widget> </item> @@ -152,105 +82,131 @@ </widget> </item> <item> - <widget class="QGroupBox" name="groupBox_3"> - <property name="title"> - <string>Coins</string> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> </property> - <layout class="QVBoxLayout" name="verticalLayout_5"> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout_8"> <item> - <layout class="QHBoxLayout" name="horizontalLayout_5"> + <layout class="QHBoxLayout" name="horizontalLayout_7"> <property name="topMargin"> <number>5</number> </property> <item> - <layout class="QVBoxLayout" name="verticalLayout_6"> - <property name="leftMargin"> - <number>6</number> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Wallet :</string> </property> - <item> - <widget class="QComboBox" name="combo_wallets"/> - </item> - <item> - <widget class="QListView" name="list_wallet"/> - </item> - </layout> + </widget> </item> <item> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <property name="rightMargin"> - <number>0</number> - </property> - <item> - <widget class="QPushButton" name="button_add"> - <property name="text"> - <string>>></string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="button_remove"> - <property name="text"> - <string><<</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QVBoxLayout" name="verticalLayout_7"> - <property name="spacing"> - <number>0</number> - </property> - <property name="leftMargin"> - <number>0</number> - </property> - <item> - <widget class="QLineEdit" name="edit_message"> - <property name="placeholderText"> - <string>A message</string> - </property> - </widget> - </item> - <item> - <widget class="QListView" name="list_coins_sent"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>8</verstretch> - </sizepolicy> - </property> - </widget> - </item> - </layout> + <widget class="QComboBox" name="combo_wallets"/> </item> </layout> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_6"> - <property name="topMargin"> - <number>5</number> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>Coins</string> </property> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="label_total"> - <property name="text"> - <string>Total money transfered : 0 </string> - </property> - </widget> - </item> - </layout> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <property name="topMargin"> + <number>5</number> + </property> + <item> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <property name="leftMargin"> + <number>6</number> + </property> + <item> + <widget class="QListView" name="list_wallet"/> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <property name="rightMargin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="button_add"> + <property name="text"> + <string>>></string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="button_remove"> + <property name="text"> + <string><<</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <property name="spacing"> + <number>0</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <item> + <widget class="QLineEdit" name="edit_message"> + <property name="placeholderText"> + <string>A message</string> + </property> + </widget> + </item> + <item> + <widget class="QListView" name="list_coins_sent"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>8</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <property name="topMargin"> + <number>5</number> + </property> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_total"> + <property name="text"> + <string>Total money transfered : 0 </string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> </item> </layout> </widget> @@ -365,22 +321,6 @@ </hint> </hints> </connection> - <connection> - <sender>radio_node_address</sender> - <signal>toggled(bool)</signal> - <receiver>TransferMoneyDialog</receiver> - <slot>transfer_mode_changed(bool)</slot> - <hints> - <hint type="sourcelabel"> - <x>70</x> - <y>155</y> - </hint> - <hint type="destinationlabel"> - <x>199</x> - <y>244</y> - </hint> - </hints> - </connection> </connections> <slots> <slot>add_coins_to_transfer()</slot> diff --git a/src/cutecoin/gui/transferMoneyDialog.py b/src/cutecoin/gui/transferMoneyDialog.py index 4b89558d34b8d9948c3c1b8e7e01c071eacbf8f7..173e375d5cac96698d5e76e4f3216af893e60d00 100644 --- a/src/cutecoin/gui/transferMoneyDialog.py +++ b/src/cutecoin/gui/transferMoneyDialog.py @@ -6,6 +6,7 @@ Created on 2 févr. 2014 from PyQt5.QtWidgets import QDialog, QErrorMessage +import ucoin from cutecoin.models.person import Person from cutecoin.models.node import Node from cutecoin.models.coin.listModel import CoinsListModel @@ -26,13 +27,11 @@ class TransferMoneyDialog(QDialog, Ui_TransferMoneyDialog): super(TransferMoneyDialog, self).__init__() self.setupUi(self) self.sender = sender + self.recipient_trusts = [] self.wallet = sender.wallets[0] for wallet in sender.wallets: self.combo_wallets.addItem(wallet.get_text()) - for trust in wallet.trusts(): - self.combo_trusted_node.addItem(trust.get_text()) - for contact in sender.contacts: self.combo_contact.addItem(contact.name) @@ -64,17 +63,9 @@ class TransferMoneyDialog(QDialog, Ui_TransferMoneyDialog): recipient = self.sender.contacts[ self.combo_contact.currentIndex()] - if self.radio_node_address.isChecked(): - node = Node.create( - self.edit_node_address.text(), int( - self.spinbox_port.text())) - else: - # TODO: Manage trusted nodes - node = self.wallet.trusts()[self.combo_trusted_node.currentIndex()] - message = self.edit_message.text() - # TODO: Transfer money, and validate the window if no error happened - error = self.wallet.transfer_coins(node, recipient, sent_coins, message) + # TODO: All nodes trusted by recipient + error = self.wallet.transfer_coins(recipient, sent_coins, message) if error: QErrorMessage(self).showMessage("Cannot transfer coins " + error) else: diff --git a/src/cutecoin/models/node/__init__.py b/src/cutecoin/models/node/__init__.py index bfba556a71df6bfcc3109a3b5c6da9b0a8f290db..eaae103b1974e92cecfad73a9b5d744962f7d0b4 100644 --- a/src/cutecoin/models/node/__init__.py +++ b/src/cutecoin/models/node/__init__.py @@ -46,7 +46,9 @@ class Node(object): return cls(server, port, trust, hoster) def __eq__(self, other): - return (self.server == other.server and self.port == other.port) + hash = ucoin.network.Peering(self.server, self.port).get()['fingerprint'] + other_hash = ucoin.network.Peering(other.server, other.port).get()['fingerprint'] + return (self.hash == other.hash) def get_text(self): return self.server + ":" + str(self.port) diff --git a/src/cutecoin/models/wallet/__init__.py b/src/cutecoin/models/wallet/__init__.py index 47001b58afefb04dbc14a6ea0b723a6cba77b606..bcbf136471199270fe8afbf87b679db4b9b5c1f6 100644 --- a/src/cutecoin/models/wallet/__init__.py +++ b/src/cutecoin/models/wallet/__init__.py @@ -74,19 +74,25 @@ class Wallet(object): coin = Coin.from_id(self, coin_data) self.coins.append(coin) - def transfer_coins(self, node, recipient, coins, message): - transfer = ucoin.wrappers.transactions.RawTransfer( + def transfer_coins(self, recipient, coins, message): + #TODO: Do my own wrapper + transfer = ucoin.wrappers.transactions.Transaction( self.fingerprint(), recipient.fingerprint, coins, message, keyid=self.keyid, - server=node.server, - port=node.port) - - result = transfer() - if result is False: - return transfer.error + server=self.trusts()[0].server, + port=self.trusts()[0].port) + + wht_request = ucoin.network.Wallet(recipient.fingerprint) + recipient_wht = self.request(wht_request) + nodes = self.get_nodes_in_peering(recipient_wht['entry']['trusts']) + nodes += [h for h in self.hosters() if h not in nodes] + result = self.broadcast(nodes, + ucoin.hdc.transactions.Process(), transfer()) + if result: + return result def transactions_received(self): received = [] @@ -160,6 +166,7 @@ Hosters: # TODO: Check if its working def _search_node_by_fingerprint(self, node_fg, next_node, traversed_nodes=[]): next_fg = next_node.peering()['fingerprint'] + print(traversed_nodes) if next_fg not in traversed_nodes: traversed_nodes.append(next_fg) if node_fg == next_fg: @@ -180,35 +187,53 @@ Hosters: for node_fg in fingerprints: node = self._search_node_by_fingerprint( node_fg, - self.trusts()[0]) + self.trusts()[0], + []) if node is not None: nodes.append(node) #TODO: Check that one trust exists return nodes def request(self, request, get_args={}): - data = None + error = None for node in self.trusts(): logging.debug("Trying to connect to : " + node.get_text()) node.use(request) try: data = request.get(**get_args) + return data + except ValueError as e: + error = str(e) except: continue - return data - return None + return error def post(self, request, get_args={}): - data = None + error = None for node in self.hosters(): logging.debug("Trying to connect to : " + node.get_text()) node.use(request) try: data = request.post(**get_args) + except ValueError as e: + error = str(e) except: continue return data - return None + return error + + def broadcast(self, nodes, request, get_args={}): + error = None + for node in nodes: + logging.debug("Trying to connect to : " + node.get_text()) + node.use(request) + try: + request.post(**get_args) + except ValueError as e: + error = str(e) + except: + continue + return error def trusts(self): return [node for node in self.nodes if node.trust]