From 419a1b5c061f7ba8b305460295a6ae7fb7dce565 Mon Sep 17 00:00:00 2001 From: Inso <insomniak.fr@gmail.com> Date: Thu, 18 Dec 2014 22:50:56 +0100 Subject: [PATCH] Transactions : OK --- lib/ucoinpy/api/bma/tx/__init__.py | 1 - lib/ucoinpy/documents/transaction.py | 3 - res/ui/transferDialog.ui | 123 ++++++++++++++++++++++-- src/cutecoin/core/community.py | 6 +- src/cutecoin/core/wallet.py | 62 +++++++++++- src/cutecoin/gui/transferMoneyDialog.py | 64 +++++++++--- src/cutecoin/tools/exceptions.py | 15 +++ 7 files changed, 245 insertions(+), 29 deletions(-) diff --git a/lib/ucoinpy/api/bma/tx/__init__.py b/lib/ucoinpy/api/bma/tx/__init__.py index 10ea07a5..0242efae 100644 --- a/lib/ucoinpy/api/bma/tx/__init__.py +++ b/lib/ucoinpy/api/bma/tx/__init__.py @@ -31,7 +31,6 @@ class Process(Tx): def __post__(self, **kwargs): assert 'transaction' in kwargs - assert 'signature' in kwargs return self.requests_post('/process', **kwargs).json() diff --git a/lib/ucoinpy/documents/transaction.py b/lib/ucoinpy/documents/transaction.py index 251c6b89..ce7d84a0 100644 --- a/lib/ucoinpy/documents/transaction.py +++ b/lib/ucoinpy/documents/transaction.py @@ -183,9 +183,6 @@ Issuers: doc += "{0}".format(self.comment) doc += "\n" - for signature in self.signatures: - doc += "{0}\n".format(signature) - return doc def compact(self): diff --git a/res/ui/transferDialog.ui b/res/ui/transferDialog.ui index 1f08eac3..b7676c86 100644 --- a/res/ui/transferDialog.ui +++ b/res/ui/transferDialog.ui @@ -6,14 +6,26 @@ <rect> <x>0</x> <y>0</y> - <width>400</width> - <height>486</height> + <width>399</width> + <height>402</height> </rect> </property> <property name="windowTitle"> <string>Transfer money</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Community</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QComboBox" name="combo_community"/> + </item> + </layout> + </widget> + </item> <item> <widget class="QGroupBox" name="groupBox"> <property name="title"> @@ -46,7 +58,7 @@ <item> <widget class="QRadioButton" name="radio_key_fingerprint"> <property name="text"> - <string>Recipient fingerprint</string> + <string>Recipient public key</string> </property> <property name="checked"> <bool>false</bool> @@ -65,7 +77,7 @@ <string/> </property> <property name="placeholderText"> - <string>Key fingerprint</string> + <string>Key</string> </property> </widget> </item> @@ -107,6 +119,56 @@ </item> </layout> </item> + <item> + <widget class="QLabel" name="label_total"> + <property name="text"> + <string>Availalble currency : </string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Amount :</string> + </property> + </widget> + </item> + <item> + <widget class="QDoubleSpinBox" name="spinbox_amount"> + <property name="suffix"> + <string/> + </property> + <property name="maximum"> + <double>99999999.000000000000000</double> + </property> + </widget> + </item> + <item> + <widget class="QDoubleSpinBox" name="spinbox_relative"> + <property name="suffix"> + <string> UD</string> + </property> + <property name="maximum"> + <double>9999999.000000000000000</double> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>Transaction message</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QLineEdit" name="edit_message"/> + </item> </layout> </widget> </item> @@ -188,13 +250,62 @@ </hint> </hints> </connection> + <connection> + <sender>combo_community</sender> + <signal>currentIndexChanged(int)</signal> + <receiver>TransferMoneyDialog</receiver> + <slot>change_current_community(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>199</x> + <y>50</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>165</y> + </hint> + </hints> + </connection> + <connection> + <sender>spinbox_amount</sender> + <signal>valueChanged(double)</signal> + <receiver>TransferMoneyDialog</receiver> + <slot>amount_changed()</slot> + <hints> + <hint type="sourcelabel"> + <x>199</x> + <y>269</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>165</y> + </hint> + </hints> + </connection> + <connection> + <sender>spinbox_relative</sender> + <signal>valueChanged(double)</signal> + <receiver>TransferMoneyDialog</receiver> + <slot>relative_amount_changed()</slot> + <hints> + <hint type="sourcelabel"> + <x>320</x> + <y>269</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>165</y> + </hint> + </hints> + </connection> </connections> <slots> - <slot>add_coins_to_transfer()</slot> - <slot>remove_coins_from_transfer()</slot> <slot>open_manage_wallet_coins()</slot> <slot>change_displayed_wallet(int)</slot> <slot>transfer_mode_changed(bool)</slot> <slot>recipient_mode_changed(bool)</slot> + <slot>change_current_community(int)</slot> + <slot>amount_changed()</slot> + <slot>relative_amount_changed()</slot> </slots> </ui> diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py index 03402876..3561dc67 100644 --- a/src/cutecoin/core/community.py +++ b/src/cutecoin/core/community.py @@ -53,7 +53,11 @@ class Community(object): return (other.currency == self.currency) def dividend(self): - return 100 + ud = self.request(bma.blockchain.UD) + block_number = ud['result']['blocks'][-1] + block = self.request(bma.blockchain.Block, + req_args={'number': block_number}) + return block['dividend'] def send_pubkey(self, account): pass diff --git a/src/cutecoin/core/wallet.py b/src/cutecoin/core/wallet.py index 8d61ed0c..e94bb7a7 100644 --- a/src/cutecoin/core/wallet.py +++ b/src/cutecoin/core/wallet.py @@ -4,9 +4,14 @@ Created on 1 févr. 2014 @author: inso ''' +from ucoinpy import PROTOCOL_VERSION from ucoinpy.api import bma -from ucoinpy.documents.transaction import InputSource +from nacl.encoding import Base64Encoder +from ucoinpy.documents.transaction import InputSource, OutputSource, Transaction from ucoinpy.key import SigningKey +from ..tools.exceptions import NotEnoughMoneyError +import logging +import base64 class Wallet(object): @@ -53,8 +58,59 @@ class Wallet(object): value += s.amount return value - def send_money(self, recipient, amount, message): - pass + def tx_inputs(self, amount, community): + value = 0 + inputs = [] + for s in self.sources(community): + value += s.amount + s.index = 0 + inputs.append(s) + if value >= amount: + return inputs + raise NotEnoughMoneyError(amount, value) + return [] + + def tx_outputs(self, pubkey, amount, inputs): + outputs = [] + inputs_value = 0 + for i in inputs: + logging.debug(i) + inputs_value += i.amount + + overhead = inputs_value - int(amount) + outputs.append(OutputSource(pubkey, int(amount))) + if overhead != 0: + outputs.append(OutputSource(self.pubkey, overhead)) + return outputs + + def send_money(self, salt, password, community, + recipient, amount, message): + + inputs = self.tx_inputs(int(amount), community) + logging.debug("Inputs : {0}".format(inputs)) + outputs = self.tx_outputs(recipient, amount, inputs) + logging.debug("Outputs : {0}".format(outputs)) + tx = Transaction(PROTOCOL_VERSION, community.currency, + [self.pubkey], inputs, + outputs, message, None) + logging.debug("TX : {0}".format(tx.raw())) + key = None + logging.debug("Key : {0} : {1}".format(salt, password)) + if self.walletid == 0: + key = SigningKey(salt, password) + else: + key = SigningKey("{0}{1}".format(salt, self.walletid), password) + logging.debug("Sender pubkey:{0}".format(key.pubkey)) + + signing = key.sign(bytes(tx.raw(), 'ascii'), Base64Encoder) + logging.debug("Signature : {0}".format(str(signing.signature))) + tx.signatures = [str(signing.signature, 'ascii')] + logging.debug("Transaction : {0}".format(tx.signed_raw())) + try: + community.post(bma.tx.Process, + post_args={'transaction': tx.signed_raw()}) + except ValueError as e: + logging.debug("Error : {0}".format(e)) def sources(self, community): data = community.request(bma.tx.Sources, req_args={'pubkey': self.pubkey}) diff --git a/src/cutecoin/gui/transferMoneyDialog.py b/src/cutecoin/gui/transferMoneyDialog.py index 7bc8eb56..7af71709 100644 --- a/src/cutecoin/gui/transferMoneyDialog.py +++ b/src/cutecoin/gui/transferMoneyDialog.py @@ -3,8 +3,7 @@ Created on 2 févr. 2014 @author: inso ''' -from PyQt5.QtWidgets import QDialog, QErrorMessage - +from PyQt5.QtWidgets import QDialog, QErrorMessage, QInputDialog, QLineEdit from cutecoin.core.person import Person @@ -25,31 +24,66 @@ class TransferMoneyDialog(QDialog, Ui_TransferMoneyDialog): 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()) + self.wallet = None + self.community = self.sender.communities[0] + self.wallet = self.sender.wallets[0] + self.dividend = self.community.dividend() + + for community in self.sender.communities: + self.combo_community.addItem(community.currency) + + for wallet in self.sender.wallets: + self.combo_wallets.addItem(wallet.name) for contact in sender.contacts: self.combo_contact.addItem(contact.name) - def refresh_total(self): - dividend = self.wallet.get_block()['dividend'] - total = self.list_coins_sent.model().total() - relative_total = total / int(dividend) - self.label_total.setText("Total : \n \ -%d %s \n \ -%.2f UD" % (total, self.wallet.currency, relative_total)) - def accept(self): message = self.edit_message.text() - #error = self.wallet.send_money(recipient, amount, message) + recipient = self.edit_key_fingerprint.text() + amount = self.spinbox_amount.value() + password = QInputDialog.getText(self, "Wallet password", + "Please enter your password", + QLineEdit.Password) + if password[1] is True: + password = password[0] + else: + return + + error = self.wallet.send_money(self.sender.salt, password, self.community, + recipient, amount, message) self.accepted.emit() self.close() + def amount_changed(self): + amount = self.spinbox_amount.value() + dividend = self.community.dividend() + relative = amount / self.dividend + self.spinbox_relative.blockSignals(True) + self.spinbox_relative.setValue(relative) + self.spinbox_relative.blockSignals(False) + + def relative_amount_changed(self): + relative = self.spinbox_relative.value() + amount = relative * self.dividend + self.spinbox_amount.blockSignals(True) + self.spinbox_amount.setValue(amount) + self.spinbox_amount.blockSignals(False) + + def change_current_community(self, index): + self.community = self.sender.communities[index] + self.dividend = self.community.dividend() + self.label_total.setText(self.wallet.get_text(self.community)) + self.spinbox_amount.setSuffix(" " + self.community.currency) + self.spinbox_amount.setValue(0) + self.spinbox_amount.setMaximum(self.wallet.value(self.community)) + def change_displayed_wallet(self, index): self.wallet = self.sender.wallets[index] - self.refresh_transaction() + self.label_total.setText(self.wallet.get_text(self.community)) + self.spinbox_amount.setValue(0) + self.spinbox_amount.setMaximum(self.wallet.value(self.community)) def recipient_mode_changed(self, fingerprint_toggled): self.edit_key_fingerprint.setEnabled(fingerprint_toggled) diff --git a/src/cutecoin/tools/exceptions.py b/src/cutecoin/tools/exceptions.py index 31613389..110da3da 100644 --- a/src/cutecoin/tools/exceptions.py +++ b/src/cutecoin/tools/exceptions.py @@ -111,3 +111,18 @@ class BadAccountFile(Error): ''' super() .__init__( "File " + path + " is not an account file") + + +class NotEnoughMoneyError(Error): + + ''' + Exception raised trying to add an account using + a key already used for another account. + ''' + + def __init__(self, available, requested): + ''' + Constructor + ''' + super() .__init__( + "Key owns only {0} money, needs {1}".format(available, requested)) -- GitLab