From: CryptoManiac Date: Tue, 22 Jul 2014 19:20:58 +0000 (+0400) Subject: Initial novacoin support X-Git-Url: https://git.novaco.in/?p=electrum-nvc.git;a=commitdiff_plain;h=3cbe11a42473af52e7c5e002c36aaaf32646f627 Initial novacoin support * New satoshi-per-coin constant value; * New address versions; * Fee calculation adjustment; * Fix pubkey outputs spending issue; * Change titles from bitcoin to novacoin; * Handle coinstake and coinstake transactions properly; * Add scrypt hash function for headers verification; * Remove block header bits verification for now; * Remove exchange ratio, coinbase and other bitcoin related plugins; --- diff --git a/MANIFEST.in b/MANIFEST.in index 515844d..75ed22a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,8 +1,8 @@ include README LICENCE RELEASE-NOTES AUTHORS -include electrum.conf.sample -include electrum.desktop +include electrum-nvc.conf.sample +include electrum-nvc.desktop include *.py -include electrum +include electrum-nvc recursive-include lib *.py recursive-include gui *.py recursive-include plugins *.py diff --git a/README b/README index 1fffb66..c1b49a4 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -Electrum - lightweight Bitcoin client +Electrum - lightweight Novacoin client Licence: GNU GPL v3 Author: Thomas Voegtlin @@ -11,13 +11,13 @@ Homepage: https://electrum.org/ To run Electrum from this directory, just do: - ./electrum + ./electrum-nvc If you install Electrum on your system, you can run it from any directory: sudo python setup.py install - electrum + electrum-nvc To start Electrum from your web browser, see @@ -40,6 +40,6 @@ On Mac OS X: # On brew installs ARCHFLAGS="-arch i386 -arch x86_64" sudo python setup-release.py py2app --includes sip - sudo hdiutil create -fs HFS+ -volname "Electrum" -srcfolder dist/Electrum.app dist/electrum-VERSION-macosx.dmg + sudo hdiutil create -fs HFS+ -volname "Electrum-NVC" -srcfolder dist/Electrum-NVC.app dist/electrum-nvc-VERSION-macosx.dmg diff --git a/contrib/build-wine/electrum.nsi b/contrib/build-wine/electrum.nsi index 4a41c8f..59761b8 100644 --- a/contrib/build-wine/electrum.nsi +++ b/contrib/build-wine/electrum.nsi @@ -7,14 +7,14 @@ ;General ;Name and file - Name "Electrum" + Name "Electrum-NVC" OutFile "dist/electrum-setup.exe" ;Default installation folder - InstallDir "$PROGRAMFILES\Electrum" + InstallDir "$PROGRAMFILES\Electrum-NVC" ;Get installation folder from registry if available - InstallDirRegKey HKCU "Software\Electrum" "" + InstallDirRegKey HKCU "Software\Electrum-NVC" "" ;Request application privileges for Windows Vista RequestExecutionLevel admin @@ -36,7 +36,7 @@ ;Start Menu Folder Page Configuration !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" - !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Electrum" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Electrum-NVC" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" ;!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder @@ -62,7 +62,7 @@ Section file /r dist\electrum\*.* ;Store installation folder - WriteRegStr HKCU "Software\Electrum" "" $INSTDIR + WriteRegStr HKCU "Software\Electrum-NVC" "" $INSTDIR ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" @@ -71,7 +71,7 @@ Section CreateShortCut "$DESKTOP\Electrum.lnk" "$INSTDIR\electrum.exe" "" ;create start-menu items - CreateDirectory "$SMPROGRAMS\Electrum" + CreateDirectory "$SMPROGRAMS\Electrum-NVC" CreateShortCut "$SMPROGRAMS\Electrum\Uninstall.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 CreateShortCut "$SMPROGRAMS\Electrum\Electrum.lnk" "$INSTDIR\electrum.exe" "" "$INSTDIR\electrum.exe" 0 @@ -97,8 +97,8 @@ Section "Uninstall" Delete "$DESKTOP\Electrum.lnk" Delete "$SMPROGRAMS\Electrum\*.*" - RmDir "$SMPROGRAMS\Electrum" + RmDir "$SMPROGRAMS\Electrum-NVC" - DeleteRegKey /ifempty HKCU "Software\Electrum" + DeleteRegKey /ifempty HKCU "Software\Electrum-NVC" SectionEnd diff --git a/electrum b/electrum index 1e4acec..97f66d7 100755 --- a/electrum +++ b/electrum @@ -36,15 +36,15 @@ __builtin__.use_local_modules = is_local or is_android # load local module as electrum if __builtin__.use_local_modules: import imp - imp.load_module('electrum', *imp.find_module('lib')) - imp.load_module('electrum_gui', *imp.find_module('gui')) + imp.load_module('electrum_nvc', *imp.find_module('lib')) + imp.load_module('electrum_nvc_gui', *imp.find_module('gui')) if is_local: sys.path.append('packages') -from electrum import SimpleConfig, Network, Wallet, WalletStorage, NetworkProxy, Commands, known_commands, pick_random_server -from electrum.util import print_msg, print_stderr, print_json, set_verbosity +from electrum_nvc import SimpleConfig, Network, Wallet, WalletStorage, NetworkProxy, Commands, known_commands, pick_random_server +from electrum_nvc.util import print_msg, print_stderr, print_json, set_verbosity # get password routine def prompt_password(prompt, confirm=True): @@ -67,7 +67,7 @@ def arg_parser(): parser = optparse.OptionParser(usage=usage, add_help_option=False) parser.add_option("-h", "--help", action="callback", callback=print_help_cb, help="show this help text") parser.add_option("-g", "--gui", dest="gui", help="User interface: qt, lite, gtk, text or stdio") - parser.add_option("-w", "--wallet", dest="wallet_path", help="wallet path (default: electrum.dat)") + parser.add_option("-w", "--wallet", dest="wallet_path", help="wallet path (default: electrum-nvc.dat)") parser.add_option("-o", "--offline", action="store_true", dest="offline", default=False, help="remain offline") parser.add_option("-C", "--concealed", action="store_true", dest="concealed", default=False, help="don't echo seed to console when restoring") parser.add_option("-a", "--all", action="store_true", dest="show_all", default=False, help="show all addresses") @@ -93,8 +93,8 @@ def arg_parser(): def print_help(parser): parser.print_help() - print_msg("Type 'electrum help ' to see the help for a specific command") - print_msg("Type 'electrum --help' to see the list of options") + print_msg("Type 'electrum-nvc help ' to see the help for a specific command") + print_msg("Type 'electrum-nvc --help' to see the list of options") run_command(known_commands['help']) @@ -151,7 +151,7 @@ if __name__ == '__main__': parser = arg_parser() options, args = parser.parse_args() if options.portable and options.wallet_path is None: - options.electrum_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'electrum_data') + options.electrum_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'electrum-nvc_data') # config is an object passed to the various constructors (wallet, interface, gui) if is_android: @@ -174,7 +174,7 @@ if __name__ == '__main__': if len(args) == 0: url = None cmd = 'gui' - elif len(args) == 1 and re.match('^bitcoin:', args[0]): + elif len(args) == 1 and re.match('^novacoin:', args[0]): url = args[0] cmd = 'gui' else: @@ -185,7 +185,7 @@ if __name__ == '__main__': if gui_name in ['lite', 'classic']: gui_name = 'qt' try: - gui = __import__('electrum_gui.' + gui_name, fromlist=['electrum_gui']) + gui = __import__('electrum_nvc_gui.' + gui_name, fromlist=['electrum_nvc_gui']) except ImportError: traceback.print_exc(file=sys.stdout) sys.exit() @@ -293,7 +293,7 @@ if __name__ == '__main__': if cmd.name not in ['create', 'restore'] and cmd.requires_wallet and not storage.file_exists: print_msg("Error: Wallet file not found.") - print_msg("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option") + print_msg("Type 'electrum-nvc create' to create a new wallet, or provide a path to a wallet with the -w option") sys.exit(0) diff --git a/electrum.conf.sample b/electrum.conf.sample index eb84db0..b3b270b 100644 --- a/electrum.conf.sample +++ b/electrum.conf.sample @@ -1,12 +1,12 @@ # Configuration file for the electrum client # Settings defined here are shared across wallets # -# copy this file to /etc/electrum.conf if you want read-only settings -# copy it into your ~/.electrum/ directory if you want global settings +# copy this file to /etc/electrum-nvc.conf if you want read-only settings +# copy it into your ~/.electrum-nvc/ directory if you want global settings # that can be rewritten by the client [client] -server = electrum.novit.ro:50001:t +server = 127.0.0.1:50001:t proxy = None gap_limit = 5 # booleans use python syntax @@ -14,5 +14,5 @@ use_change = True gui = qt num_zeros = 2 # default transaction fee is in Satoshis -fee = 10000 +fee = 1000 winpos-qt = [799, 226, 877, 435] diff --git a/electrum.desktop b/electrum.desktop index 1b0c5ab..a14b238 100644 --- a/electrum.desktop +++ b/electrum.desktop @@ -2,16 +2,16 @@ # sudo desktop-file-install electrum.desktop [Desktop Entry] -Comment=Lightweight Bitcoin Client +Comment=Lightweight Novacoin Client Exec=electrum %u GenericName[en_US]=Electrum GenericName=Electrum Icon=/usr/share/app-install/icons/electrum.png -Name[en_US]=Electrum Bitcoin Wallet -Name=Electrum Bitcoin Wallet +Name[en_US]=Electrum Novacoin Wallet +Name=Electrum Novacoin Wallet Categories=Network; StartupNotify=false Terminal=false Type=Application -MimeType=x-scheme-handler/bitcoin +MimeType=x-scheme-handler/novacoin diff --git a/gui/android.py b/gui/android.py index a89673c..51af1d7 100644 --- a/gui/android.py +++ b/gui/android.py @@ -22,9 +22,9 @@ from __future__ import absolute_import import android -from electrum import SimpleConfig, Wallet, WalletStorage, format_satoshis, mnemonic_encode, mnemonic_decode -from electrum.bitcoin import is_valid -from electrum import util +from electrum_nvc import SimpleConfig, Wallet, WalletStorage, format_satoshis, mnemonic_encode, mnemonic_decode +from electrum_nvc.bitcoin import is_valid +from electrum_nvc import util from decimal import Decimal import datetime, re @@ -166,7 +166,7 @@ def make_layout(s, scrollable = False): . import sys, time, datetime, re, threading -from electrum.i18n import _, set_language -from electrum.util import print_error, print_msg -from electrum.plugins import run_hook +from electrum_nvc.i18n import _, set_language +from electrum_nvc.util import print_error, print_msg +from electrum_nvc.plugins import run_hook import os.path, json, ast, traceback import shutil @@ -33,9 +33,9 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * import PyQt4.QtCore as QtCore -from electrum import WalletStorage, Wallet -from electrum.i18n import _ -from electrum.bitcoin import MIN_RELAY_TX_FEE +from electrum_nvc import WalletStorage, Wallet +from electrum_nvc.i18n import _ +from electrum_nvc.bitcoin import MIN_RELAY_TX_FEE try: import icons_rc @@ -44,7 +44,7 @@ except Exception: from util import * from main_window import ElectrumWindow -from electrum.plugins import init_plugins +from electrum_nvc.plugins import init_plugins class OpenFileEventFilter(QObject): diff --git a/gui/qt/amountedit.py b/gui/qt/amountedit.py index edac456..439e6f3 100644 --- a/gui/qt/amountedit.py +++ b/gui/qt/amountedit.py @@ -24,7 +24,7 @@ class AmountEdit(MyLineEdit): self.help_palette = QPalette() def decimal_point(self): - return 8 + return 6 def numbify(self): text = unicode(self.text()).strip() @@ -69,11 +69,11 @@ class BTCAmountEdit(AmountEdit): def _base_unit(self): p = self.decimal_point() - assert p in [2, 5, 8] - if p == 8: - return 'BTC' - if p == 5: - return 'mBTC' + assert p in [2, 3, 6] + if p == 6: + return 'NVC' + if p == 3: + return 'mNVC' if p == 2: return 'bits' raise Exception('Unknown base unit') diff --git a/gui/qt/console.py b/gui/qt/console.py index e7d05e9..c0b08c5 100644 --- a/gui/qt/console.py +++ b/gui/qt/console.py @@ -4,7 +4,7 @@ import sys, os, re import traceback, platform from PyQt4 import QtCore from PyQt4 import QtGui -from electrum import util +from electrum_nvc import util if platform.system() == 'Windows': diff --git a/gui/qt/history_widget.py b/gui/qt/history_widget.py index c218c3a..ca0d8c9 100644 --- a/gui/qt/history_widget.py +++ b/gui/qt/history_widget.py @@ -1,5 +1,5 @@ from PyQt4.QtGui import * -from electrum.i18n import _ +from electrum_nvc.i18n import _ class HistoryWidget(QTreeWidget): diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py index 2b074f8..f3b30a4 100644 --- a/gui/qt/installwizard.py +++ b/gui/qt/installwizard.py @@ -2,10 +2,10 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * import PyQt4.QtCore as QtCore -from electrum.i18n import _ -from electrum import Wallet, Wallet_2of2, Wallet_2of3 -from electrum import bitcoin -from electrum import util +from electrum_nvc.i18n import _ +from electrum_nvc import Wallet, Wallet_2of2, Wallet_2of3 +from electrum_nvc import bitcoin +from electrum_nvc import util import seed_dialog from network_dialog import NetworkDialog @@ -14,10 +14,10 @@ from amountedit import AmountEdit import sys import threading -from electrum.plugins import run_hook +from electrum_nvc.plugins import run_hook -MSG_ENTER_ANYTHING = _("Please enter a wallet seed, a master public key, a list of Bitcoin addresses, or a list of private keys") +MSG_ENTER_ANYTHING = _("Please enter a wallet seed, a master public key, a list of Novacoin addresses, or a list of private keys") MSG_SHOW_MPK = _("This is your master public key") MSG_ENTER_MPK = _("Please enter your master public key") MSG_ENTER_COLD_MPK = _("Please enter the master public key of your cosigner wallet") diff --git a/gui/qt/lite_window.py b/gui/qt/lite_window.py index 4ddc2bc..4d7997a 100644 --- a/gui/qt/lite_window.py +++ b/gui/qt/lite_window.py @@ -13,31 +13,31 @@ except ImportError: sys.exit(0) from decimal import Decimal as D -from electrum.util import get_resource_path as rsrc -from electrum.bitcoin import is_valid -from electrum.i18n import _ +from electrum_nvc.util import get_resource_path as rsrc +from electrum_nvc.bitcoin import is_valid +from electrum_nvc.i18n import _ import decimal import json import os.path import random import re import time -from electrum.wallet import Wallet, WalletStorage +from electrum_nvc.wallet import Wallet, WalletStorage import webbrowser import history_widget import receiving_widget -from electrum import util +from electrum_nvc import util import datetime -from electrum.version import ELECTRUM_VERSION as electrum_version -from electrum.util import format_satoshis, age +from electrum_nvc.version import ELECTRUM_VERSION as electrum_version +from electrum_nvc.util import format_satoshis, age from main_window import ElectrumWindow import shutil from util import * -bitcoin = lambda v: v * 100000000 +bitcoin = lambda v: v * 1000000 def IconButton(filename, parent=None): pixmap = QPixmap(filename) @@ -142,14 +142,14 @@ class MiniWindow(QDialog): # Bitcoin address code self.address_input = QLineEdit() - self.address_input.setPlaceholderText(_("Enter a Bitcoin address or contact")) + self.address_input.setPlaceholderText(_("Enter a Novacoin address or contact")) self.address_input.setObjectName("address_input") self.address_input.setFocusPolicy(Qt.ClickFocus) self.address_input.textChanged.connect(self.address_field_changed) resize_line_edit_width(self.address_input, - "1BtaFUr3qVvAmwrsuDuu5zk6e4s2rxd2Gy") + "4LJgtjeXMjLA6nVzYMJh1LEkwxMFsRtnP4") self.address_completions = QStringListModel() address_completer = QCompleter(self.address_input) @@ -254,7 +254,7 @@ class MiniWindow(QDialog): self.toggle_receiving_layout(show_hist) self.setWindowIcon(QIcon(":icons/electrum.png")) - self.setWindowTitle("Electrum") + self.setWindowTitle("Electrum-NVC") self.setWindowFlags(Qt.Window|Qt.MSWindowsFixedSizeDialogHint) self.layout().setSizeConstraint(QLayout.SetFixedSize) self.setObjectName("main_window") @@ -388,7 +388,7 @@ class MiniWindow(QDialog): def create_quote_text(self, btc_balance): """Return a string copy of the amount fiat currency the user has in bitcoins.""" - from electrum.plugins import run_hook + from electrum_nvc.plugins import run_hook r = {} run_hook('get_fiat_balance_text', btc_balance, r) return r.get(0,'') @@ -575,7 +575,7 @@ class ReceivePopup(QDialog): self.close() def setup(self, address): - label = QLabel(_("Copied your Bitcoin address to the clipboard!")) + label = QLabel(_("Copied your Novacoin address to the clipboard!")) address_display = QLineEdit(address) address_display.setReadOnly(True) resize_line_edit_width(address_display, address) @@ -585,7 +585,7 @@ class ReceivePopup(QDialog): main_layout.addWidget(address_display) self.setMouseTracking(True) - self.setWindowTitle("Electrum - " + _("Receive Bitcoin payment")) + self.setWindowTitle("Electrum - " + _("Receive Novacoin payment")) self.setWindowFlags(Qt.Window|Qt.FramelessWindowHint| Qt.MSWindowsFixedSizeDialogHint) self.layout().setSizeConstraint(QLayout.SetFixedSize) @@ -697,7 +697,7 @@ class MiniActuator: if dest_address is None or not is_valid(dest_address): QMessageBox.warning(parent_window, _('Error'), - _('Invalid Bitcoin Address') + ':\n' + address, _('OK')) + _('Invalid Novacoin Address') + ':\n' + address, _('OK')) return False amount = D(unicode(amount)) * (10*self.g.decimal_point) @@ -713,9 +713,9 @@ class MiniActuator: password = None fee = 0 - # 0.1 BTC = 10000000 + # 0.1 NVC = 100000 if amount < bitcoin(1) / 10: - # 0.001 BTC + # 0.001 NVC fee = bitcoin(1) / 1000 try: diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py index e8e9e66..d4217f1 100644 --- a/gui/qt/main_window.py +++ b/gui/qt/main_window.py @@ -17,8 +17,8 @@ # along with this program. If not, see . import sys, time, datetime, re, threading -from electrum.i18n import _, set_language -from electrum.util import print_error, print_msg +from electrum_nvc.i18n import _, set_language +from electrum_nvc.util import print_error, print_msg import os.path, json, ast, traceback import webbrowser import shutil @@ -30,17 +30,17 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * import PyQt4.QtCore as QtCore -from electrum.bitcoin import MIN_RELAY_TX_FEE, is_valid -from electrum.plugins import run_hook +from electrum_nvc.bitcoin import MIN_RELAY_TX_FEE, is_valid +from electrum_nvc.plugins import run_hook import icons_rc -from electrum.util import format_satoshis -from electrum import Transaction -from electrum import mnemonic -from electrum import util, bitcoin, commands, Interface, Wallet -from electrum import SimpleConfig, Wallet, WalletStorage -from electrum import Imported_Wallet +from electrum_nvc.util import format_satoshis +from electrum_nvc import Transaction +from electrum_nvc import mnemonic +from electrum_nvc import util, bitcoin, commands, Interface, Wallet +from electrum_nvc import SimpleConfig, Wallet, WalletStorage +from electrum_nvc import Imported_Wallet from amountedit import AmountEdit, BTCAmountEdit, MyLineEdit from network_dialog import NetworkDialog @@ -72,7 +72,7 @@ PR_PAID = 3 # send and propagated PR_ERROR = 4 # could not parse -from electrum import ELECTRUM_VERSION +from electrum_nvc import ELECTRUM_VERSION import re from util import MyTreeWidget, HelpButton, EnterButton, line_dialog, text_dialog, ok_cancel_buttons, close_button, WaitingDialog @@ -129,7 +129,7 @@ class ElectrumWindow(QMainWindow): self.create_status_bar() self.need_update = threading.Event() - self.decimal_point = config.get('decimal_point', 5) + self.decimal_point = config.get('decimal_point', 6) self.num_zeros = int(config.get('num_zeros',0)) self.invoices = {} @@ -202,7 +202,7 @@ class ElectrumWindow(QMainWindow): def load_wallet(self, wallet): - import electrum + import electrum_nvc self.wallet = wallet self.update_wallet_format() @@ -373,8 +373,8 @@ class ElectrumWindow(QMainWindow): self.setMenuBar(menubar) def show_about(self): - QMessageBox.about(self, "Electrum", - _("Version")+" %s" % (self.wallet.electrum_version) + "\n\n" + _("Electrum's focus is speed, with low resource usage and simplifying Bitcoin. You do not need to perform regular backups, because your wallet can be recovered from a secret phrase that you can memorize or write on paper. Startup times are instant because it operates in conjunction with high-performance servers that handle the most complicated parts of the Bitcoin system.")) + QMessageBox.about(self, "Electrum-NVC", + _("Version")+" %s" % (self.wallet.electrum_version) + "\n\n" + _("Electrum's focus is speed, with low resource usage and simplifying Bitcoin. You do not need to perform regular backups, because your wallet can be recovered from a secret phrase that you can memorize or write on paper. Startup times are instant because it operates in conjunction with high-performance servers that handle the most complicated parts of the Novacoin system.")) def show_report_bug(self): QMessageBox.information(self, "Electrum - " + _("Reporting Bugs"), @@ -409,7 +409,7 @@ class ElectrumWindow(QMainWindow): self.notify(_("New transaction received. %(amount)s %(unit)s") % { 'amount' : self.format_amount(v), 'unit' : self.base_unit()}) def notify(self, message): - self.tray.showMessage("Electrum", message, QSystemTrayIcon.Information, 20000) + self.tray.showMessage("Electrum-NVC", message, QSystemTrayIcon.Information, 20000) @@ -453,13 +453,13 @@ class ElectrumWindow(QMainWindow): def base_unit(self): - assert self.decimal_point in [2, 5, 8] + assert self.decimal_point in [2, 3, 6] if self.decimal_point == 2: return 'bits' - if self.decimal_point == 5: - return 'mBTC' - if self.decimal_point == 8: - return 'BTC' + if self.decimal_point == 3: + return 'mNVC' + if self.decimal_point == 6: + return 'NVC' raise Exception('Unknown base unit') def update_status(self): @@ -522,21 +522,20 @@ class ElectrumWindow(QMainWindow): def create_history_menu(self, position): self.history_list.selectedIndexes() item = self.history_list.currentItem() - be = self.config.get('block_explorer', 'Blockchain.info') - if be == 'Blockchain.info': - block_explorer = 'https://blockchain.info/tx/' - elif be == 'Blockr.io': - block_explorer = 'https://blockr.io/tx/info/' - elif be == 'Insight.is': - block_explorer = 'http://live.insight.is/tx/' + be = self.config.get('block_explorer', 'explorer.novaco.in') + if be == 'explorer.novaco.in': + block_explorer = 'https://explorer.novaco.in/tx/' + elif be == 'novacoin.su': + block_explorer = 'http://novacoin.su/tx/' if not item: return + tx_hash = str(item.data(0, Qt.UserRole).toString()) if not tx_hash: return menu = QMenu() menu.addAction(_("Copy ID to Clipboard"), lambda: self.app.clipboard().setText(tx_hash)) menu.addAction(_("Details"), lambda: self.show_transaction(self.wallet.transactions.get(tx_hash))) menu.addAction(_("Edit description"), lambda: self.tx_label_clicked(item,2)) - menu.addAction(_("View on block explorer"), lambda: webbrowser.open(block_explorer + tx_hash)) + menu.addAction(_("View on explorer"), lambda: webbrowser.open(block_explorer + tx_hash)) menu.exec_(self.contacts_list.viewport().mapToGlobal(position)) @@ -834,7 +833,7 @@ class ElectrumWindow(QMainWindow): from paytoedit import PayToEdit self.amount_e = BTCAmountEdit(self.get_decimal_point) self.payto_e = PayToEdit(self) - self.payto_help = HelpButton(_('Recipient of the funds.') + '\n\n' + _('You may enter a Bitcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Bitcoin address)')) + self.payto_help = HelpButton(_('Recipient of the funds.') + '\n\n' + _('You may enter a Novacoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Novacoin address)')) grid.addWidget(QLabel(_('Pay to')), 1, 0) grid.addWidget(self.payto_e, 1, 1, 1, 3) grid.addWidget(self.payto_help, 1, 4) @@ -874,7 +873,7 @@ class ElectrumWindow(QMainWindow): grid.addWidget(QLabel(_('Fee')), 5, 0) grid.addWidget(self.fee_e, 5, 1, 1, 2) grid.addWidget(HelpButton( - _('Bitcoin transactions are in general not free. A transaction fee is paid by the sender of the funds.') + '\n\n'\ + _('Novacoin transactions are in general not free. A transaction fee is paid by the sender of the funds.') + '\n\n'\ + _('The amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed.') + '\n\n'\ + _('A suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction.')), 5, 3) @@ -1002,12 +1001,12 @@ class ElectrumWindow(QMainWindow): for type, addr, amount in outputs: if addr is None: - QMessageBox.warning(self, _('Error'), _('Bitcoin Address is None'), _('OK')) + QMessageBox.warning(self, _('Error'), _('Novacoin Address is None'), _('OK')) return if type == 'op_return': continue if type == 'address' and not bitcoin.is_address(addr): - QMessageBox.warning(self, _('Error'), _('Invalid Bitcoin Address'), _('OK')) + QMessageBox.warning(self, _('Error'), _('Invalid Novacoin Address'), _('OK')) return if amount is None: QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK')) @@ -1020,13 +1019,13 @@ class ElectrumWindow(QMainWindow): QMessageBox.warning(self, _('Error'), _('Invalid Fee'), _('OK')) return - confirm_amount = self.config.get('confirm_amount', 100000000) + confirm_amount = self.config.get('confirm_amount', 10000) if amount >= confirm_amount: o = '\n'.join(map(lambda x:x[1], outputs)) if not self.question(_("send %(amount)s to %(address)s?")%{ 'amount' : self.format_amount(amount) + ' '+ self.base_unit(), 'address' : o}): return - confirm_fee = self.config.get('confirm_fee', 100000) + confirm_fee = self.config.get('confirm_fee', 10000) if fee >= confirm_fee: if not self.question(_("The fee for this transaction seems unusually high.\nAre you really sure you want to pay %(fee)s in fees?")%{ 'fee' : self.format_amount(fee) + ' '+ self.base_unit()}): return @@ -1189,7 +1188,7 @@ class ElectrumWindow(QMainWindow): try: address, amount, label, message, request_url = util.parse_URI(URI) except Exception as e: - QMessageBox.warning(self, _('Error'), _('Invalid bitcoin URI:') + '\n' + str(e), _('OK')) + QMessageBox.warning(self, _('Error'), _('Invalid novacoin URI:') + '\n' + str(e), _('OK')) return self.tabs.setCurrentIndex(1) @@ -1211,7 +1210,7 @@ class ElectrumWindow(QMainWindow): self.amount_e.setAmount(amount) return - from electrum import paymentrequest + from electrum_nvc import paymentrequest def payment_request(): self.payment_request = paymentrequest.PaymentRequest(self.config) self.payment_request.read(request_url) @@ -1475,7 +1474,7 @@ class ElectrumWindow(QMainWindow): payto_addr = item.data(0,33).toString() menu.addAction(_("Copy to Clipboard"), lambda: self.app.clipboard().setText(addr)) menu.addAction(_("Pay to"), lambda: self.payto(payto_addr)) - menu.addAction(_("QR code"), lambda: self.show_qrcode("bitcoin:" + addr, _("Address"))) + menu.addAction(_("QR code"), lambda: self.show_qrcode("novacoin:" + addr, _("Address"))) if is_editable: menu.addAction(_("Edit label"), lambda: self.edit_label(False)) menu.addAction(_("Delete"), lambda: self.delete_contact(addr)) @@ -1489,7 +1488,7 @@ class ElectrumWindow(QMainWindow): self.update_invoices_tab() def show_invoice(self, key): - from electrum.paymentrequest import PaymentRequest + from electrum_nvc.paymentrequest import PaymentRequest domain, memo, value, expiration, status, tx_hash = self.invoices[key] pr = PaymentRequest(self.config) pr.read_file(key) @@ -1508,7 +1507,7 @@ class ElectrumWindow(QMainWindow): QMessageBox.information(self, 'Invoice', msg , 'OK') def do_pay_invoice(self, key): - from electrum.paymentrequest import PaymentRequest + from electrum_nvc.paymentrequest import PaymentRequest domain, memo, value, expiration, status, tx_hash = self.invoices[key] pr = PaymentRequest(self.config) pr.read_file(key) @@ -1769,7 +1768,7 @@ class ElectrumWindow(QMainWindow): vbox.addWidget(QLabel(_('Account name')+':')) e = QLineEdit() vbox.addWidget(e) - msg = _("Note: Newly created accounts are 'pending' until they receive bitcoins.") + " " \ + msg = _("Note: Newly created accounts are 'pending' until they receive novacoins.") + " " \ + _("You will need to wait for 2 confirmations until the correct balance is displayed and more addresses are created for that account.") l = QLabel(msg) l.setWordWrap(True) @@ -2143,7 +2142,7 @@ class ElectrumWindow(QMainWindow): self.show_transaction(tx) def do_process_from_txid(self): - from electrum import transaction + from electrum_nvc import transaction txid, ok = QInputDialog.getText(self, _('Lookup transaction'), _('Transaction ID') + ':') if ok and txid: r = self.network.synchronous_get([ ('blockchain.transaction.get',[str(txid)]) ])[0] @@ -2165,7 +2164,7 @@ class ElectrumWindow(QMainWindow): errors.append((position, address)) continue amount = Decimal(row[1]) - amount = int(100000000*amount) + amount = int(1000000*amount) outputs.append(('address', address, amount)) except (ValueError, IOError, os.error), reason: QMessageBox.critical(None, _("Unable to read file or no transaction found"), _("Electrum was unable to open your transaction file") + "\n" + str(reason)) @@ -2323,7 +2322,7 @@ class ElectrumWindow(QMainWindow): d.setMinimumSize(400, 200) vbox = QVBoxLayout(d) - defaultname = os.path.expanduser('~/electrum-history.csv') + defaultname = os.path.expanduser('~/electrum-nvc-history.csv') select_msg = _('Select file to export your wallet transactions to') hbox, filename_e, csv_button = filename_field(self, self.config, defaultname, select_msg) @@ -2494,7 +2493,7 @@ class ElectrumWindow(QMainWindow): lang_label=QLabel(_('Language') + ':') grid.addWidget(lang_label, 1, 0) lang_combo = QComboBox() - from electrum.i18n import languages + from electrum_nvc.i18n import languages lang_combo.addItems(languages.values()) try: index = languages.keys().index(self.config.get("language",'')) @@ -2513,12 +2512,12 @@ class ElectrumWindow(QMainWindow): fee_e.setAmount(self.wallet.fee) grid.addWidget(fee_e, 2, 1) msg = _('Fee per kilobyte of transaction.') + '\n' \ - + _('Recommended value') + ': ' + self.format_amount(10000) + ' ' + self.base_unit() + + _('Recommended value') + ': ' + self.format_amount(1000) + ' ' + self.base_unit() grid.addWidget(HelpButton(msg), 2, 2) if not self.config.is_modifiable('fee_per_kb'): for w in [fee_e, fee_label]: w.setEnabled(False) - units = ['BTC', 'mBTC', 'bits'] + units = ['NVC', 'mNVC', 'bits'] unit_label = QLabel(_('Base unit') + ':') grid.addWidget(unit_label, 3, 0) unit_combo = QComboBox() @@ -2526,7 +2525,7 @@ class ElectrumWindow(QMainWindow): unit_combo.setCurrentIndex(units.index(self.base_unit())) grid.addWidget(unit_combo, 3, 1) grid.addWidget(HelpButton(_('Base unit of your wallet.')\ - + '\n1BTC=1000mBTC.\n' \ + + '\n1NVC=1000mNVC.\n' \ + _(' These settings affects the fields in the Send tab')+' '), 3, 2) usechange_cb = QCheckBox(_('Use change addresses')) @@ -2535,12 +2534,12 @@ class ElectrumWindow(QMainWindow): grid.addWidget(HelpButton(_('Using change addresses makes it more difficult for other people to track your transactions.')+' '), 4, 2) if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False) - block_explorers = ['Blockchain.info', 'Blockr.io', 'Insight.is'] + block_explorers = ['explorer.novaco.in', 'novacoin.su'] block_ex_label = QLabel(_('Online Block Explorer') + ':') grid.addWidget(block_ex_label, 5, 0) block_ex_combo = QComboBox() block_ex_combo.addItems(block_explorers) - block_ex_combo.setCurrentIndex(block_explorers.index(self.config.get('block_explorer', 'Blockchain.info'))) + block_ex_combo.setCurrentIndex(block_explorers.index(self.config.get('block_explorer', 'explorer.novaco.in'))) grid.addWidget(block_ex_combo, 5, 1) grid.addWidget(HelpButton(_('Choose which online block explorer to use for functions that open a web browser')+' '), 5, 2) @@ -2589,10 +2588,10 @@ class ElectrumWindow(QMainWindow): unit_result = units[unit_combo.currentIndex()] if self.base_unit() != unit_result: - if unit_result == 'BTC': - self.decimal_point = 8 - elif unit_result == 'mBTC': - self.decimal_point = 5 + if unit_result == 'NVC': + self.decimal_point = 6 + elif unit_result == 'mNVC': + self.decimal_point = 3 elif unit_result == 'bits': self.decimal_point = 2 else: @@ -2635,7 +2634,7 @@ class ElectrumWindow(QMainWindow): def plugins_dialog(self): - from electrum.plugins import plugins + from electrum_nvc.plugins import plugins d = QDialog(self) d.setWindowTitle(_('Electrum Plugins')) diff --git a/gui/qt/network_dialog.py b/gui/qt/network_dialog.py index 11da1a6..c664993 100644 --- a/gui/qt/network_dialog.py +++ b/gui/qt/network_dialog.py @@ -17,13 +17,13 @@ # along with this program. If not, see . import sys, time, datetime, re, threading -from electrum.i18n import _ -from electrum.util import print_error, print_msg +from electrum_nvc.i18n import _ +from electrum_nvc.util import print_error, print_msg import os.path, json, ast, traceback from PyQt4.QtGui import * from PyQt4.QtCore import * -from electrum import DEFAULT_SERVERS, DEFAULT_PORTS +from electrum_nvc import DEFAULT_SERVERS, DEFAULT_PORTS from util import * diff --git a/gui/qt/password_dialog.py b/gui/qt/password_dialog.py index d56f09e..0e0f4b3 100644 --- a/gui/qt/password_dialog.py +++ b/gui/qt/password_dialog.py @@ -18,7 +18,7 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * -from electrum.i18n import _ +from electrum_nvc.i18n import _ from util import * diff --git a/gui/qt/paytoedit.py b/gui/qt/paytoedit.py index 8b3e24c..19ed582 100644 --- a/gui/qt/paytoedit.py +++ b/gui/qt/paytoedit.py @@ -22,7 +22,7 @@ from qrtextedit import QRTextEdit import re from decimal import Decimal -from electrum import bitcoin +from electrum_nvc import bitcoin RE_ADDRESS = '[1-9A-HJ-NP-Za-km-z]{26,}' RE_ALIAS = '(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>' diff --git a/gui/qt/qrcodewidget.py b/gui/qt/qrcodewidget.py index 6d13306..c2ef8b1 100644 --- a/gui/qt/qrcodewidget.py +++ b/gui/qt/qrcodewidget.py @@ -6,9 +6,9 @@ import PyQt4.QtGui as QtGui import os import qrcode -import electrum -from electrum import bmp -from electrum.i18n import _ +import electrum_nvc +from electrum_nvc import bmp +from electrum_nvc.i18n import _ class QRCodeWidget(QWidget): @@ -104,7 +104,7 @@ class QRDialog(QDialog): hbox = QHBoxLayout() hbox.addStretch(1) - config = electrum.get_config() + config = electrum_nvc.get_config() if config: filename = os.path.join(config.path, "qrcode.bmp") diff --git a/gui/qt/qrtextedit.py b/gui/qt/qrtextedit.py index d6b20f3..596a501 100644 --- a/gui/qt/qrtextedit.py +++ b/gui/qt/qrtextedit.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_nvc.i18n import _ from PyQt4.QtGui import * from PyQt4.QtCore import * @@ -34,7 +34,7 @@ class QRTextEdit(QPlainTextEdit): QRDialog(str(self.toPlainText())).exec_() def qr_input(self): - from electrum.plugins import run_hook + from electrum_nvc.plugins import run_hook data = run_hook('scan_qr_hook') if type(data) != str: return diff --git a/gui/qt/receiving_widget.py b/gui/qt/receiving_widget.py index c35fc51..70ab80d 100644 --- a/gui/qt/receiving_widget.py +++ b/gui/qt/receiving_widget.py @@ -1,6 +1,6 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * -from electrum.i18n import _ +from electrum_nvc.i18n import _ class ReceivingWidget(QTreeWidget): diff --git a/gui/qt/seed_dialog.py b/gui/qt/seed_dialog.py index 3d446db..6d1948f 100644 --- a/gui/qt/seed_dialog.py +++ b/gui/qt/seed_dialog.py @@ -19,8 +19,8 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * import PyQt4.QtCore as QtCore -from electrum.i18n import _ -from electrum import mnemonic +from electrum_nvc.i18n import _ +from electrum_nvc import mnemonic from qrcodewidget import QRCodeWidget, QRDialog from util import close_button from qrtextedit import QRTextEdit diff --git a/gui/qt/transaction_dialog.py b/gui/qt/transaction_dialog.py index a2bd33b..5fbd1b8 100644 --- a/gui/qt/transaction_dialog.py +++ b/gui/qt/transaction_dialog.py @@ -17,8 +17,8 @@ # along with this program. If not, see . import sys, time, datetime, re, threading -from electrum.i18n import _, set_language -from electrum.util import print_error, print_msg +from electrum_nvc.i18n import _, set_language +from electrum_nvc.util import print_error, print_msg import os.path, json, ast, traceback import shutil import StringIO @@ -33,8 +33,8 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * import PyQt4.QtCore as QtCore -from electrum import transaction -from electrum.plugins import run_hook +from electrum_nvc import transaction +from electrum_nvc.plugins import run_hook from util import MyTreeWidget @@ -212,7 +212,7 @@ class TxDialog(QDialog): vbox.addWidget(i_text) vbox.addWidget(QLabel(_("Outputs"))) - lines = map(lambda x: x[0] + u'\t\t' + self.parent.format_amount(x[1]), self.tx.get_outputs()) + lines = map(lambda x: x[1] + u'\t\t' + self.parent.format_amount(x[2]), self.tx.get_outputs()) o_text = QTextEdit() o_text.setText('\n'.join(lines)) o_text.setReadOnly(True) diff --git a/gui/qt/util.py b/gui/qt/util.py index c021e8b..c61c022 100644 --- a/gui/qt/util.py +++ b/gui/qt/util.py @@ -1,4 +1,4 @@ -from electrum.i18n import _ +from electrum_nvc.i18n import _ from PyQt4.QtGui import * from PyQt4.QtCore import * import os.path diff --git a/gui/qt/version_getter.py b/gui/qt/version_getter.py index 855f279..dca4886 100644 --- a/gui/qt/version_getter.py +++ b/gui/qt/version_getter.py @@ -22,8 +22,8 @@ from PyQt4.QtGui import * from PyQt4.QtCore import * import PyQt4.QtCore as QtCore -from electrum.i18n import _ -from electrum import ELECTRUM_VERSION, print_error +from electrum_nvc.i18n import _ +from electrum_nvc import ELECTRUM_VERSION, print_error class VersionGetter(threading.Thread): diff --git a/gui/stdio.py b/gui/stdio.py index 54067d5..8b0360e 100644 --- a/gui/stdio.py +++ b/gui/stdio.py @@ -1,10 +1,10 @@ from decimal import Decimal _ = lambda x:x #from i18n import _ -from electrum import mnemonic_encode, WalletStorage, Wallet -from electrum.util import format_satoshis, set_verbosity -from electrum.bitcoin import is_valid -from electrum.network import filter_protocol +from electrum_nvc import mnemonic_encode, WalletStorage, Wallet +from electrum_nvc.util import format_satoshis, set_verbosity +from electrum_nvc.bitcoin import is_valid +from electrum_nvc.network import filter_protocol import sys, getpass, datetime # minimal fdisk like gui for console usage @@ -17,7 +17,7 @@ class ElectrumGui: self.config = config storage = WalletStorage(config) if not storage.file_exists: - print "Wallet not found. try 'electrum create'" + print "Wallet not found. try 'electrum-nvc create'" exit() self.done = 0 @@ -124,8 +124,8 @@ class ElectrumGui: msg = _( "Synchronizing..." ) else: c, u = self.wallet.get_balance() - msg = _("Balance")+": %f "%(Decimal( c ) / 100000000) - if u: msg += " [%f unconfirmed]"%(Decimal( u ) / 100000000) + msg = _("Balance")+": %f "%(Decimal( c ) / 1000000) + if u: msg += " [%f unconfirmed]"%(Decimal( u ) / 1000000) else: msg = _( "Not connected" ) @@ -171,15 +171,15 @@ class ElectrumGui: def do_send(self): if not is_valid(self.str_recipient): - print(_('Invalid Bitcoin address')) + print(_('Invalid Novacoin address')) return try: - amount = int( Decimal( self.str_amount) * 100000000 ) + amount = int( Decimal( self.str_amount) * 1000000 ) except Exception: print(_('Invalid Amount')) return try: - fee = int( Decimal( self.str_fee) * 100000000 ) + fee = int( Decimal( self.str_fee) * 1000000 ) except Exception: print(_('Invalid Fee')) return @@ -218,12 +218,12 @@ class ElectrumGui: print(_('Error')) def network_dialog(self): - print("use 'electrum setconfig server/proxy' to change your network settings") + print("use 'electrum-nvc setconfig server/proxy' to change your network settings") return True def settings_dialog(self): - print("use 'electrum setconfig' to change your settings") + print("use 'electrum-nvc setconfig' to change your settings") return True def password_dialog(self): diff --git a/gui/text.py b/gui/text.py index 0c6a148..4cf9a9f 100644 --- a/gui/text.py +++ b/gui/text.py @@ -2,10 +2,10 @@ import curses, datetime, locale from decimal import Decimal _ = lambda x:x #from i18n import _ -from electrum.util import format_satoshis, set_verbosity -from electrum.bitcoin import is_valid +from electrum_nvc.util import format_satoshis, set_verbosity +from electrum_nvc.bitcoin import is_valid -from electrum import Wallet, WalletStorage +from electrum_nvc import Wallet, WalletStorage import tty, sys @@ -18,7 +18,7 @@ class ElectrumGui: self.network = network storage = WalletStorage(config) if not storage.file_exists: - print "Wallet not found. try 'electrum create'" + print "Wallet not found. try 'electrum-nvc create'" exit() self.wallet = Wallet(storage) @@ -129,8 +129,8 @@ class ElectrumGui: msg = _("Synchronizing...") else: c, u = self.wallet.get_balance() - msg = _("Balance")+": %f "%(Decimal( c ) / 100000000) - if u: msg += " [%f unconfirmed]"%(Decimal( u ) / 100000000) + msg = _("Balance")+": %f "%(Decimal( c ) / 1000000) + if u: msg += " [%f unconfirmed]"%(Decimal( u ) / 1000000) else: msg = _("Not connected") @@ -287,15 +287,15 @@ class ElectrumGui: def do_send(self): if not is_valid(self.str_recipient): - self.show_message(_('Invalid Bitcoin address')) + self.show_message(_('Invalid Novacoin address')) return try: - amount = int( Decimal( self.str_amount) * 100000000 ) + amount = int( Decimal( self.str_amount) * 1000000 ) except Exception: self.show_message(_('Invalid Amount')) return try: - fee = int( Decimal( self.str_fee) * 100000000 ) + fee = int( Decimal( self.str_fee) * 1000000 ) except Exception: self.show_message(_('Invalid Fee')) return diff --git a/lib/account.py b/lib/account.py index 9a9d86e..7e51cb8 100644 --- a/lib/account.py +++ b/lib/account.py @@ -355,7 +355,7 @@ class BIP32_Account_2of2(BIP32_Account): def pubkeys_to_address(self, pubkeys): redeem_script = Transaction.multisig_script(sorted(pubkeys), 2) - address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 5) + address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 20) return address def get_address(self, for_change, n): diff --git a/lib/bitcoin.py b/lib/bitcoin.py index 8a958c5..0d49942 100644 --- a/lib/bitcoin.py +++ b/lib/bitcoin.py @@ -205,7 +205,7 @@ def public_key_to_bc_address(public_key): h160 = hash_160(public_key) return hash_160_to_bc_address(h160) -def hash_160_to_bc_address(h160, addrtype = 0): +def hash_160_to_bc_address(h160, addrtype = 8): vh160 = chr(addrtype) + h160 h = Hash(vh160) addr = vh160 + h[0:4] @@ -290,12 +290,12 @@ def PrivKeyToSecret(privkey): return privkey[9:9+32] -def SecretToASecret(secret, compressed=False, addrtype=0): +def SecretToASecret(secret, compressed=False, addrtype=8): vchIn = chr((addrtype+128)&255) + secret if compressed: vchIn += '\01' return EncodeBase58Check(vchIn) -def ASecretToSecret(key, addrtype=0): +def ASecretToSecret(key, addrtype=8): vch = DecodeBase58Check(key) if vch and vch[0] == chr((addrtype+128)&255): return vch[1:] @@ -379,7 +379,7 @@ from ecdsa.util import string_to_number, number_to_string def msg_magic(message): varint = var_int(len(message)) encoded_varint = "".join([chr(int(varint[i:i+2], 16)) for i in xrange(0, len(varint), 2)]) - return "\x18Bitcoin Signed Message:\n" + encoded_varint + message + return "\x18Novacoin Signed Message:\n" + encoded_varint + message def verify_message(address, signature, message): @@ -478,7 +478,7 @@ class EC_KEY(object): def sign_message(self, message, compressed, address): private_key = ecdsa.SigningKey.from_secret_exponent( self.secret, curve = SECP256k1 ) public_key = private_key.get_verifying_key() - signature = private_key.sign_digest_deterministic( Hash( msg_magic(message) ), hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_string ) + signature = private_key.sign_digest_deterministic( Hash( msg_magic(message) ), hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_string_canonize ) assert public_key.verify_digest( signature, Hash( msg_magic(message) ), sigdecode = ecdsa.util.sigdecode_string) for i in range(4): sig = base64.b64encode( chr(27 + i + (4 if compressed else 0)) + signature ) @@ -710,7 +710,7 @@ def bip32_root(seed, testnet=False): import hmac header_pub, header_priv = _get_headers(testnet) seed = seed.decode('hex') - I = hmac.new("Bitcoin seed", seed, hashlib.sha512).digest() + I = hmac.new("Novacoin seed", seed, hashlib.sha512).digest() master_k = I[0:32] master_c = I[32:] K, cK = get_pubkeys_from_secret(master_k) diff --git a/lib/blockchain.py b/lib/blockchain.py index ac5ea14..aa4880c 100644 --- a/lib/blockchain.py +++ b/lib/blockchain.py @@ -21,6 +21,11 @@ import threading, time, Queue, os, sys, shutil from util import user_dir, appdata_dir, print_error from bitcoin import * +try: + from ltc_scrypt import getPoWHash +except ImportError: + print_msg("Warning: scrypt not available, using fallback") + from scrypt import scrypt_1024_1_1_80 as getPoWHash class Blockchain(threading.Thread): @@ -32,7 +37,7 @@ class Blockchain(threading.Thread): self.lock = threading.Lock() self.local_height = 0 self.running = False - self.headers_url = 'http://headers.electrum.org/blockchain_headers' + self.headers_url = 'http://novacoin.su/static/blockchain_headers' self.set_local_height() self.queue = Queue.Queue() @@ -102,7 +107,15 @@ class Blockchain(threading.Thread): - + def calculate_target(self, bits): + # convert to bignum + MM = 256*256*256 + a = bits%MM + if a < 0x8000: + a *= 256 + return (a) * pow(2, 8 * (bits/MM - 3)) + + def verify_chain(self, chain): first_header = chain[0] @@ -113,12 +126,12 @@ class Blockchain(threading.Thread): height = header.get('block_height') prev_hash = self.hash_header(prev_header) - bits, target = self.get_target(height/2016, chain) - _hash = self.hash_header(header) + header_hash = self.hash_header(header) + try: assert prev_hash == header.get('prev_block_hash') - assert bits == header.get('bits') - assert int('0x'+_hash,16) < target + if header.get('nonce') != 0: + assert int('0x'+_hash,16) < self.calculate_target(header.get('bits')) except Exception: return False @@ -138,21 +151,20 @@ class Blockchain(threading.Thread): else: prev_header = self.read_header(index*2016-1) if prev_header is None: raise - previous_hash = self.hash_header(prev_header) - - bits, target = self.get_target(index) + _hash = self.hash_header(prev_header) for i in range(num): height = index*2016 + i raw_header = data[i*80:(i+1)*80] header = self.header_from_string(raw_header) - _hash = self.hash_header(header) + header_hash = self.hash_header(header) + assert previous_hash == header.get('prev_block_hash') - assert bits == header.get('bits') - assert int('0x'+_hash,16) < target + if header.get('nonce') != 0: + assert int('0x'+header_hash,16) < calculate_target(header.get('bits')) previous_header = header - previous_hash = _hash + previous_hash = header_hash self.save_chunk(index, data) print_error("validated chunk %d"%height) @@ -181,7 +193,7 @@ class Blockchain(threading.Thread): return h def hash_header(self, header): - return rev_hex(Hash(self.header_to_string(header).decode('hex')).encode('hex')) + return rev_hex(getPoWHash(self.header_to_string(header).decode('hex')).encode('hex')) def path(self): return os.path.join( self.config.path, 'blockchain_headers') @@ -240,53 +252,6 @@ class Blockchain(threading.Thread): h = self.header_from_string(h) return h - - def get_target(self, index, chain=None): - if chain is None: - chain = [] # Do not use mutables as default values! - - max_target = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 - if index == 0: return 0x1d00ffff, max_target - - first = self.read_header((index-1)*2016) - last = self.read_header(index*2016-1) - if last is None: - for h in chain: - if h.get('block_height') == index*2016-1: - last = h - - nActualTimespan = last.get('timestamp') - first.get('timestamp') - nTargetTimespan = 14*24*60*60 - nActualTimespan = max(nActualTimespan, nTargetTimespan/4) - nActualTimespan = min(nActualTimespan, nTargetTimespan*4) - - bits = last.get('bits') - # convert to bignum - MM = 256*256*256 - a = bits%MM - if a < 0x8000: - a *= 256 - target = (a) * pow(2, 8 * (bits/MM - 3)) - - # new target - new_target = min( max_target, (target * nActualTimespan)/nTargetTimespan ) - - # convert it to bits - c = ("%064X"%new_target)[2:] - i = 31 - while c[0:2]=="00": - c = c[2:] - i -= 1 - - c = int('0x'+c[0:6],16) - if c >= 0x800000: - c /= 256 - i += 1 - - new_bits = c + MM * i - return new_bits, new_target - - def request_header(self, i, h, queue): print_error("requesting header %d from %s"%(h, i.server)) i.send([ ('blockchain.block.get_header',[h])], lambda i,r: queue.put((i,r))) diff --git a/lib/commands.py b/lib/commands.py index 5cb030e..30a38b3 100644 --- a/lib/commands.py +++ b/lib/commands.py @@ -53,8 +53,8 @@ payto_options = ' --fee, -f: set transaction fee\n --fromaddr, -F: send from add listaddr_options = " -a: show all addresses, including change addresses\n -l: include labels in results" restore_options = " accepts a seed or master public key." mksendmany_syntax = 'mksendmanytx [ ...]' -payto_syntax = "payto [label]\n can be a bitcoin address or a label" -paytomany_syntax = "paytomany [ ...]\n can be a bitcoin address or a label" +payto_syntax = "payto [label]\n can be a novacoin address or a label" +paytomany_syntax = "paytomany [ ...]\n can be a novacoin address or a label" signmessage_syntax = 'signmessage
\nIf you want to lead or end a message with spaces, or want double spaces inside the message make sure you quote the string. I.e. " Hello This is a weird String "' verifymessage_syntax = 'verifymessage
\nIf you want to lead or end a message with spaces, or want double spaces inside the message make sure you quote the string. I.e. " Hello This is a weird String "' @@ -65,11 +65,11 @@ verifymessage_syntax = 'verifymessage
\nIf you wa # requires_password register_command('contacts', 0, 0, False, True, False, 'Show your list of contacts') register_command('create', 0, 0, False, True, False, 'Create a new wallet') -register_command('createmultisig', 2, 2, False, True, False, 'similar to bitcoind\'s command') -register_command('createrawtransaction', 2, 2, False, True, False, 'similar to bitcoind\'s command') +register_command('createmultisig', 2, 2, False, True, False, 'similar to novacoind\'s command') +register_command('createrawtransaction', 2, 2, False, True, False, 'similar to novacoind\'s command') register_command('deseed', 0, 0, False, True, False, 'Remove seed from wallet, creating a seedless, watching-only wallet.') -register_command('decoderawtransaction', 1, 1, False, False, False, 'similar to bitcoind\'s command') -register_command('getprivatekeys', 1, 1, False, True, True, 'Get the private keys of a given address', 'getprivatekeys ') +register_command('decoderawtransaction', 1, 1, False, False, False, 'similar to novacoind\'s command') +register_command('getprivatekeys', 1, 1, False, True, True, 'Get the private keys of a given address', 'getprivatekeys ') register_command('dumpprivkeys', 0, 0, False, True, True, 'Dump all private keys in your wallet') register_command('freeze', 1, 1, False, True, True, 'Freeze the funds at one of your wallet\'s addresses', 'freeze
') register_command('getbalance', 0, 1, True, True, False, 'Return the balance of your wallet, or of one account in your wallet', 'getbalance []') @@ -78,7 +78,7 @@ register_command('getversion', 0, 0, False, False, False, 'Return the register_command('getaddressbalance', 1, 1, True, False, False, 'Return the balance of an address', 'getaddressbalance
') register_command('getaddresshistory', 1, 1, True, False, False, 'Return the transaction history of a wallet address', 'getaddresshistory
') register_command('getconfig', 1, 1, False, False, False, 'Return a configuration variable', 'getconfig ') -register_command('getpubkeys', 1, 1, False, True, False, 'Return the public keys for a wallet address', 'getpubkeys ') +register_command('getpubkeys', 1, 1, False, True, False, 'Return the public keys for a wallet address', 'getpubkeys ') register_command('getrawtransaction', 1, 1, True, False, False, 'Retrieve a transaction', 'getrawtransaction ') register_command('getseed', 0, 0, False, True, True, 'Print the generation seed of your wallet.') register_command('getmpk', 0, 0, False, True, False, 'Return your wallet\'s master public key', 'getmpk') @@ -146,7 +146,7 @@ class Commands: def listunspent(self): l = copy.deepcopy(self.wallet.get_unspent_coins()) - for i in l: i["value"] = str(Decimal(i["value"])/100000000) + for i in l: i["value"] = str(Decimal(i["value"])/1000000) return l def getaddressunspent(self, addr): @@ -162,7 +162,7 @@ class Commands: i['prevout_hash'] = i['txid'] i['prevout_n'] = i['vout'] outputs = map(lambda x: (x[0],int(1e8*x[1])), outputs.items()) - tx = Transaction(inputs, outputs) + tx = Transaction(int(time.time()), inputs, outputs) return tx def signrawtransaction(self, raw_tx, private_keys): @@ -181,7 +181,7 @@ class Commands: def createmultisig(self, num, pubkeys): assert isinstance(pubkeys, list) redeem_script = Transaction.multisig_script(pubkeys, num) - address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 5) + address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 20) return {'address':address, 'redeemScript':redeem_script} def freeze(self,addr): @@ -216,14 +216,14 @@ class Commands: else: c, u = self.wallet.get_account_balance(account) - out = { "confirmed": str(Decimal(c)/100000000) } - if u: out["unconfirmed"] = str(Decimal(u)/100000000) + out = { "confirmed": str(Decimal(c)/1000000) } + if u: out["unconfirmed"] = str(Decimal(u)/1000000) return out def getaddressbalance(self, addr): out = self.network.synchronous_get([ ('blockchain.address.get_balance',[addr]) ])[0] - out["confirmed"] = str(Decimal(out["confirmed"])/100000000) - out["unconfirmed"] = str(Decimal(out["unconfirmed"])/100000000) + out["confirmed"] = str(Decimal(out["confirmed"])/1000000) + out["unconfirmed"] = str(Decimal(out["unconfirmed"])/1000000) return out def getproof(self, addr): @@ -239,7 +239,7 @@ class Commands: return self.network.get_servers() def getversion(self): - import electrum # Needs to stay here to prevent ciruclar imports + import electrum_nvc # Needs to stay here to prevent ciruclar imports return electrum.ELECTRUM_VERSION def getmpk(self): @@ -258,7 +258,7 @@ class Commands: return out def sweep(self, privkey, to_address, fee = 0.0001): - fee = int(Decimal(fee)*100000000) + fee = int(Decimal(fee)*1000000) return Transaction.sweep([privkey], self.network, to_address, fee) def signmessage(self, address, message): @@ -270,16 +270,16 @@ class Commands: def _mktx(self, outputs, fee = None, change_addr = None, domain = None): for to_address, amount in outputs: if not is_valid(to_address): - raise Exception("Invalid Bitcoin address", to_address) + raise Exception("Invalid Novacoin address", to_address) if change_addr: if not is_valid(change_addr): - raise Exception("Invalid Bitcoin address", change_addr) + raise Exception("Invalid Novacoin address", change_addr) if domain is not None: for addr in domain: if not is_valid(addr): - raise Exception("invalid Bitcoin address", addr) + raise Exception("invalid Novacoin address", addr) if not self.wallet.is_mine(addr): raise Exception("address not in wallet", addr) @@ -296,10 +296,10 @@ class Commands: print_msg("alias", to_address) break - amount = int(100000000*amount) + amount = int(1000000*amount) final_outputs.append(('address', to_address, amount)) - if fee: fee = int(100000000*fee) + if fee: fee = int(1000000*fee) return self.wallet.mktx(final_outputs, self.password, fee , change_addr, domain) def mktx(self, to_address, amount, fee = None, change_addr = None, domain = None): diff --git a/lib/i18n.py b/lib/i18n.py index 2ed1ddb..1d2efa6 100644 --- a/lib/i18n.py +++ b/lib/i18n.py @@ -27,7 +27,13 @@ language = gettext.translation('electrum', LOCALE_DIR, fallback = True) def _(x): global language - return language.ugettext(x) + dic = [('Bitcoin', 'Novacoin'), ('bitcoin', 'novacoin')] + for b, l in dic: + x = x.replace(l, b) + t = language.ugettext(x) + for b, l in dic: + t = t.replace(b, l) + return t def set_language(x): global language diff --git a/lib/network.py b/lib/network.py index f07846a..6a3aee1 100644 --- a/lib/network.py +++ b/lib/network.py @@ -7,20 +7,7 @@ from blockchain import Blockchain DEFAULT_PORTS = {'t':'50001', 's':'50002', 'h':'8081', 'g':'8082'} DEFAULT_SERVERS = { - 'ecdsa.org': DEFAULT_PORTS, - 'ecdsa.net': DEFAULT_PORTS, - 'electrum.hachre.de': DEFAULT_PORTS, - 'electrum.novit.ro': DEFAULT_PORTS, - 'electrum.coinwallet.me': DEFAULT_PORTS, - 'cube.l0g.in': DEFAULT_PORTS, - 'bitcoin.epicinet.net': DEFAULT_PORTS, - 'h.1209k.com': DEFAULT_PORTS, - 'electrum.electricnewyear.net': DEFAULT_PORTS, - 'erbium.sytes.net': DEFAULT_PORTS, - 'e2.pdmc.net':DEFAULT_PORTS, - 'electrum.no-ip.org':{'h': '80', 's': '50002', 't': '50001', 'g': '443'}, - 'electrum.thwg.org':DEFAULT_PORTS, - 'electrum.stepkrav.pw':DEFAULT_PORTS, + '127.0.0.1': DEFAULT_PORTS, } diff --git a/lib/paymentrequest.py b/lib/paymentrequest.py index 6e97e21..91cd0ac 100644 --- a/lib/paymentrequest.py +++ b/lib/paymentrequest.py @@ -329,7 +329,7 @@ if __name__ == "__main__": uri = sys.argv[1] except: print "usage: %s url"%sys.argv[0] - print "example url: \"bitcoin:17KjQgnXC96jakzJe9yo8zxqerhqNptmhq?amount=0.0018&r=https%3A%2F%2Fbitpay.com%2Fi%2FMXc7qTM5f87EC62SWiS94z\"" + print "example url: \"novacoin:4LJgtjeXMjLA6nVzYMJh1LEkwxMFsRtnP4?amount=0.0018&r=https%3A%2F%2Fsite.com%2F\"" sys.exit(1) address, amount, label, message, request_url = util.parse_URI(uri) diff --git a/lib/plugins.py b/lib/plugins.py index feea2fc..e1ed3c3 100644 --- a/lib/plugins.py +++ b/lib/plugins.py @@ -14,12 +14,12 @@ def init_plugins(self): fp, pathname, description = imp.find_module('plugins') plugin_names = [name for a, name, b in pkgutil.iter_modules([pathname])] plugin_names = filter( lambda name: os.path.exists(os.path.join(pathname,name+'.py')), plugin_names) - imp.load_module('electrum_plugins', fp, pathname, description) - plugin_modules = map(lambda name: imp.load_source('electrum_plugins.'+name, os.path.join(pathname,name+'.py')), plugin_names) + imp.load_module('electrum_nvc_plugins', fp, pathname, description) + plugin_modules = map(lambda name: imp.load_source('electrum_nvc_plugins.'+name, os.path.join(pathname,name+'.py')), plugin_names) else: - import electrum_plugins - plugin_names = [name for a, name, b in pkgutil.iter_modules(electrum_plugins.__path__)] - plugin_modules = [ __import__('electrum_plugins.'+name, fromlist=['electrum_plugins']) for name in plugin_names] + import electrum_nvc_plugins + plugin_names = [name for a, name, b in pkgutil.iter_modules(electrum_nvc_plugins.__path__)] + plugin_modules = [ __import__('electrum_nvc_plugins.'+name, fromlist=['electrum_nvc_plugins']) for name in plugin_names] for name, p in zip(plugin_names, plugin_modules): try: diff --git a/lib/simple_config.py b/lib/simple_config.py index 0824c04..b1dce60 100644 --- a/lib/simple_config.py +++ b/lib/simple_config.py @@ -4,7 +4,7 @@ import os from util import user_dir, print_error, print_msg -SYSTEM_CONFIG_PATH = "/etc/electrum.conf" +SYSTEM_CONFIG_PATH = "/etc/electrum-nvc.conf" config = None @@ -96,7 +96,7 @@ class SimpleConfig(object): def set_key(self, key, value, save = True): if not self.is_modifiable(key): print "Warning: not changing key '%s' because it is not modifiable" \ - " (passed as command line option or defined in /etc/electrum.conf)"%key + " (passed as command line option or defined in /etc/electrum-nvc.conf)"%key return with self.lock: @@ -134,13 +134,13 @@ class SimpleConfig(object): os.chmod(path, stat.S_IREAD | stat.S_IWRITE) def read_system_config(path=SYSTEM_CONFIG_PATH): - """Parse and return the system config settings in /etc/electrum.conf.""" + """Parse and return the system config settings in /etc/electrum-nvc.conf.""" result = {} if os.path.exists(path): try: import ConfigParser except ImportError: - print "cannot parse electrum.conf. please install ConfigParser" + print "cannot parse electrum-nvc.conf. please install ConfigParser" return p = ConfigParser.ConfigParser() @@ -154,7 +154,7 @@ def read_system_config(path=SYSTEM_CONFIG_PATH): return result def read_user_config(path): - """Parse and store the user config settings in electrum.conf into user_config[].""" + """Parse and store the user config settings in electrum-nvc.conf into user_config[].""" if not path: return {} # Return a dict, since we will call update() on it. config_path = os.path.join(path, "config") diff --git a/lib/tests/test_simple_config.py b/lib/tests/test_simple_config.py index a800629..54fe20c 100644 --- a/lib/tests/test_simple_config.py +++ b/lib/tests/test_simple_config.py @@ -174,7 +174,7 @@ everything = 42 os.remove(self.thefile) def test_read_system_config_file_does_not_exist(self): - somefile = "/foo/I/do/not/exist/electrum.conf" + somefile = "/foo/I/do/not/exist/electrum-nvc.conf" result = read_system_config(somefile) self.assertEqual({}, result) diff --git a/lib/transaction.py b/lib/transaction.py index f15aa23..595ac7f 100644 --- a/lib/transaction.py +++ b/lib/transaction.py @@ -404,7 +404,7 @@ def parse_scriptSig(d, bytes): d['pubkeys'] = pubkeys redeemScript = Transaction.multisig_script(pubkeys,2) d['redeemScript'] = redeemScript - d['address'] = hash_160_to_bc_address(hash_160(redeemScript.decode('hex')), 5) + d['address'] = hash_160_to_bc_address(hash_160(redeemScript.decode('hex')), 20) @@ -427,7 +427,7 @@ def get_address_from_output_script(bytes): # p2sh match = [ opcodes.OP_HASH160, opcodes.OP_PUSHDATA4, opcodes.OP_EQUAL ] if match_decoded(decoded, match): - return 'address', hash_160_to_bc_address(decoded[1][1],5) + return 'address', hash_160_to_bc_address(decoded[1][1],20) return "(None)", "(None)" @@ -474,6 +474,7 @@ def deserialize(raw): d = {} start = vds.read_cursor d['version'] = vds.read_int32() + d['timestamp'] = vds.read_int32() n_vin = vds.read_compact_size() d['inputs'] = [] for i in xrange(n_vin): @@ -492,10 +493,11 @@ class Transaction: def __str__(self): if self.raw is None: - self.raw = self.serialize(self.inputs, self.outputs, for_sig = None) # for_sig=-1 means do not sign + self.raw = self.serialize(self.timestamp, self.inputs, self.outputs, for_sig = None) # for_sig=-1 means do not sign return self.raw - def __init__(self, inputs, outputs, locktime=0): + def __init__(self, timestamp, inputs, outputs, locktime=0): + self.timestamp = timestamp self.inputs = inputs self.outputs = outputs self.locktime = locktime @@ -503,18 +505,18 @@ class Transaction: @classmethod def deserialize(klass, raw): - self = klass([],[]) + self = klass(0, [],[]) self.update(raw) return self def update(self, raw): d = deserialize(raw) self.raw = raw + self.timestamp = d['timestamp'] self.inputs = d['inputs'] self.outputs = map(lambda x: (x['type'], x['address'], x['value']), d['outputs']) self.locktime = d['lockTime'] - @classmethod def sweep(klass, privkeys, network, to_address, fee): inputs = [] @@ -569,30 +571,35 @@ class Transaction: @classmethod - def pay_script(self, type, addr): + def pay_script(self, type, payto): + assert type == 'address' or type == 'pubkey' or type == 'op_return' + if type == 'op_return': - h = addr.encode('hex') + h = payto.encode('hex') return '6a' + push_script(h) + elif type == 'pubkey': + script = push_script(payto) + script += 'ac' # op_checksig + return script else: - assert type == 'address' - addrtype, hash_160 = bc_address_to_hash_160(addr) - if addrtype == 0: - script = '76a9' # op_dup, op_hash_160 - script += push_script(hash_160.encode('hex')) - script += '88ac' # op_equalverify, op_checksig - elif addrtype == 5: - script = 'a9' # op_hash_160 - script += push_script(hash_160.encode('hex')) - script += '87' # op_equal - else: - raise - return script + addrtype, hash_160 = bc_address_to_hash_160(payto) + if addrtype == 8: + script = '76a9' # op_dup, op_hash_160 + script += push_script(hash_160.encode('hex')) + script += '88ac' # op_equalverify, op_checksig + elif addrtype == 20: + script = 'a9' # op_hash_160 + script += push_script(hash_160.encode('hex')) + script += '87' # op_equal + else: + raise + return script @classmethod - def serialize(klass, inputs, outputs, for_sig = None ): - + def serialize(klass, timestamp, inputs, outputs, for_sig = None ): s = int_to_hex(1,4) # version + s += int_to_hex(timestamp, 4) # timestamp s += var_int( len(inputs) ) # number of inputs for i in range(len(inputs)): txin = inputs[i] @@ -602,7 +609,7 @@ class Transaction: p2sh = txin.get('redeemScript') is not None num_sig = txin['num_sig'] - address = txin['address'] + payto = txin['address'] if txin["type"] == 'address' else txin['pubkeys'][0] x_signatures = txin['signatures'] signatures = filter(lambda x: x is not None, x_signatures) @@ -624,7 +631,8 @@ class Transaction: sig_list = ''.join( map( lambda x: push_script(x), sig_list)) if not p2sh: script = sig_list - script += push_script(pubkeys[0]) + if txin["type"] != 'pubkey': + script += push_script(pubkeys[0]) else: script = '00' # op_0 script += sig_list @@ -632,7 +640,8 @@ class Transaction: script += push_script(redeem_script) elif for_sig==i: - script = txin['redeemScript'] if p2sh else klass.pay_script('address', address) + script = txin['redeemScript'] if p2sh else klass.pay_script(txin["type"], payto) + print script else: script = '' s += var_int( len(script)/2 ) # script length @@ -653,7 +662,7 @@ class Transaction: def tx_for_sig(self,i): - return self.serialize(self.inputs, self.outputs, for_sig = i) + return self.serialize(self.timestamp, self.inputs, self.outputs, for_sig = i) def hash(self): @@ -667,7 +676,7 @@ class Transaction: txin['signatures'][ii] = sig txin['x_pubkeys'][ii] = pubkey self.inputs[i] = txin - self.raw = self.serialize(self.inputs, self.outputs) + self.raw = self.serialize(self.timestamp, self.inputs, self.outputs) def signature_count(self): @@ -736,23 +745,25 @@ class Transaction: secexp = pkey.secret private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 ) public_key = private_key.get_verifying_key() - sig = private_key.sign_digest_deterministic( for_sig, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der ) + sig = private_key.sign_digest_deterministic( for_sig, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der_canonize ) + assert public_key.verify_digest( sig, for_sig, sigdecode = ecdsa.util.sigdecode_der) self.add_signature(i, pubkey, sig.encode('hex')) - print_error("is_complete", self.is_complete()) - self.raw = self.serialize( self.inputs, self.outputs ) + self.raw = self.serialize( self.timestamp, self.inputs, self.outputs ) def add_pubkey_addresses(self, txlist): for i in self.inputs: + i["pubkey"] = False if i.get("address") == "(pubkey)": prev_tx = txlist.get(i.get('prevout_hash')) if prev_tx: - address, value = prev_tx.get_outputs()[i.get('prevout_n')] + type, address, value = prev_tx.get_outputs()[i.get('prevout_n')] print_error("found pay-to-pubkey address:", address) i["address"] = address + i["type"] = type def get_outputs(self): @@ -765,11 +776,12 @@ class Transaction: addr = public_key_to_bc_address(x.decode('hex')) else: addr = "(None)" - o.append((addr,v)) + o.append((type,addr,v)) +# print o return o def get_output_addresses(self): - return map(lambda x:x[0], self.get_outputs()) + return map(lambda x:x[1], self.get_outputs()) def has_address(self, addr): @@ -808,7 +820,7 @@ class Transaction: if not is_send: is_partial = False - for addr, value in self.get_outputs(): + for type, addr, value in self.get_outputs(): v_out += value if addr in addresses: v_out_mine += value @@ -847,15 +859,14 @@ class Transaction: def requires_fee(self, verifier): - # see https://en.bitcoin.it/wiki/Transaction_fees threshold = 57600000 size = len(self.raw)/2 - if size >= 10000: + if size >= 1000: return True for o in self.get_outputs(): - value = o[1] - if value < 1000000: + value = o[2] + if value < 10000: return True sum = 0 for i in self.inputs: diff --git a/lib/util.py b/lib/util.py index d796ae4..0415b1c 100644 --- a/lib/util.py +++ b/lib/util.py @@ -43,11 +43,11 @@ def print_json(obj): def user_dir(): if "HOME" in os.environ: - return os.path.join(os.environ["HOME"], ".electrum") + return os.path.join(os.environ["HOME"], ".electrum-nvc") elif "APPDATA" in os.environ: - return os.path.join(os.environ["APPDATA"], "Electrum") + return os.path.join(os.environ["APPDATA"], "Electrum-NVC") elif "LOCALAPPDATA" in os.environ: - return os.path.join(os.environ["LOCALAPPDATA"], "Electrum") + return os.path.join(os.environ["LOCALAPPDATA"], "Electrum-NVC") elif 'ANDROID_DATA' in os.environ: return "/sdcard/electrum/" else: @@ -57,15 +57,15 @@ def user_dir(): def appdata_dir(): """Find the path to the application data directory; add an electrum folder and return path.""" if platform.system() == "Windows": - return os.path.join(os.environ["APPDATA"], "Electrum") + return os.path.join(os.environ["APPDATA"], "Electrum-NVC") elif platform.system() == "Linux": - return os.path.join(sys.prefix, "share", "electrum") + return os.path.join(sys.prefix, "share", "electrum-nvc") elif (platform.system() == "Darwin" or platform.system() == "DragonFly" or platform.system() == "OpenBSD" or platform.system() == "FreeBSD" or platform.system() == "NetBSD"): - return "/Library/Application Support/Electrum" + return "/Library/Application Support/Electrum-NVC" else: raise Exception("Unknown system") @@ -82,7 +82,7 @@ def local_data_dir(): return local_data -def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 8, whitespaces=False): +def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 6, whitespaces=False): from decimal import Decimal s = Decimal(x) sign, digits, exp = s.as_tuple() @@ -186,7 +186,7 @@ def parse_URI(uri): k = int(m.group(2)) - 8 amount = Decimal(m.group(1)) * pow( Decimal(10) , k) else: - amount = Decimal(am) * 100000000 + amount = Decimal(am) * 1000000 if 'message' in pq: message = pq['message'][0] if 'label' in pq: diff --git a/lib/wallet.py b/lib/wallet.py index df3efa8..169d008 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -36,8 +36,8 @@ from plugins import run_hook import bitcoin from synchronizer import WalletSynchronizer -COINBASE_MATURITY = 100 -DUST_THRESHOLD = 5430 +COINBASE_MATURITY = 500 +DUST_THRESHOLD = 1000 # internal ID for imported account IMPORTED_ACCOUNT = '/x' @@ -76,7 +76,7 @@ class WalletStorage(object): new_path = os.path.join(config.path, "wallets", "default_wallet") # default path in pre 1.9 versions - old_path = os.path.join(config.path, "electrum.dat") + old_path = os.path.join(config.path, "electrum-nvc.dat") if os.path.exists(old_path) and not os.path.exists(new_path): os.rename(old_path, new_path) @@ -146,7 +146,7 @@ class Abstract_Wallet(object): self.history = storage.get('addr_history',{}) # address -> list(txid, height) - self.fee = int(storage.get('fee_per_kb', 10000)) + self.fee = int(storage.get('fee_per_kb', 1000)) self.next_addresses = storage.get('next_addresses',{}) @@ -181,7 +181,7 @@ class Abstract_Wallet(object): for k, raw in tx_list.items(): try: tx = Transaction.deserialize(raw) - except Exception: + except Exception, e: print_msg("Warning: Cannot deserialize transactions. skipping") continue self.add_pubkey_addresses(tx) @@ -445,7 +445,7 @@ class Abstract_Wallet(object): def update_tx_outputs(self, tx_hash): tx = self.transactions.get(tx_hash) - for i, (addr, value) in enumerate(tx.get_outputs()): + for i, (type, addr, value) in enumerate(tx.get_outputs()): key = tx_hash+ ':%d'%i self.prevout_values[key] = value @@ -465,7 +465,7 @@ class Abstract_Wallet(object): tx = self.transactions.get(tx_hash) if not tx: continue - for i, (addr, value) in enumerate(tx.get_outputs()): + for i, (type, addr, value) in enumerate(tx.get_outputs()): if addr == address: key = tx_hash + ':%d'%i received_coins.append(key) @@ -483,7 +483,7 @@ class Abstract_Wallet(object): if key in received_coins: v -= value - for i, (addr, value) in enumerate(tx.get_outputs()): + for i, (type, addr, value) in enumerate(tx.get_outputs()): key = tx_hash + ':%d'%i if addr == address: v += value @@ -536,8 +536,14 @@ class Abstract_Wallet(object): for tx_hash, tx_height in h: tx = self.transactions.get(tx_hash) if tx is None: raise Exception("Wallet not synchronized") + outputs = tx.get_outputs() + is_coinbase = tx.inputs[0].get('prevout_hash') == '0'*64 - for i, (address, value) in enumerate(tx.get_outputs()): + is_coinstake = outputs[0][2] == 0 + + #print is_coinstake + + for i, (type, address, value) in enumerate(outputs): output = {'address':address, 'value':value, 'prevout_n':i} if address != addr: continue key = tx_hash + ":%d"%i @@ -545,6 +551,8 @@ class Abstract_Wallet(object): output['prevout_hash'] = tx_hash output['height'] = tx_height output['coinbase'] = is_coinbase + output['coinstake'] = is_coinstake + output["type"] = type coins.append((tx_height, output)) # sort by age @@ -570,7 +578,7 @@ class Abstract_Wallet(object): inputs = [] for item in coins: - if item.get('coinbase') and item.get('height') + COINBASE_MATURITY > self.network.get_local_height(): + if (item.get('coinbase') or item.get('coinstake')) and item.get('height') + COINBASE_MATURITY < self.network.get_local_height(): continue v = item.get('value') total += v @@ -745,7 +753,7 @@ class Abstract_Wallet(object): for txin in inputs: self.add_input_info(txin) outputs = self.add_tx_change(inputs, outputs, amount, fee, total, change_addr) - return Transaction(inputs, outputs) + return Transaction(int(time.time()), inputs, outputs) def mktx(self, outputs, password, fee=None, change_addr=None, domain= None, coins = None ): tx = self.make_unsigned_transaction(outputs, fee, change_addr, domain, coins) diff --git a/make_packages b/make_packages index 22e01a3..55f6863 100755 --- a/make_packages +++ b/make_packages @@ -13,28 +13,28 @@ if __name__ == '__main__': os.system("pyrcc4 icons.qrc -o gui/qt/icons_rc.py") os.system("python setup.py sdist --format=zip,gztar") - _tgz="Electrum-%s.tar.gz"%version - _zip="Electrum-%s.zip"%version + _tgz="Electrum-NVC-%s.tar.gz"%version + _zip="Electrum-NVC-%s.zip"%version # android - os.system('rm -rf dist/e4a-%s'%version) - os.mkdir('dist/e4a-%s'%version) - shutil.copyfile("electrum",'dist/e4a-%s/e4a.py'%version) - shutil.copytree("packages",'dist/e4a-%s/packages'%version) - shutil.copytree("lib",'dist/e4a-%s/lib'%version) - os.mkdir('dist/e4a-%s/gui'%version) + os.system('rm -rf dist/en4a-%s'%version) + os.mkdir('dist/en4a-%s'%version) + shutil.copyfile("electrum-nvc",'dist/en4a-%s/en4a.py'%version) + shutil.copytree("packages",'dist/en4a-%s/packages'%version) + shutil.copytree("lib",'dist/en4a-%s/lib'%version) + os.mkdir('dist/en4a-%s/gui'%version) for n in ['android.py']: - shutil.copy("gui/%s"%n,'dist/e4a-%s/gui'%version) - open('dist/e4a-%s/gui/__init__.py'%version,'w').close() + shutil.copy("gui/%s"%n,'dist/en4a-%s/gui'%version) + open('dist/en4a-%s/gui/__init__.py'%version,'w').close() os.chdir("dist") # create the zip file - os.system( "zip -r e4a-%s.zip e4a-%s"%(version, version) ) - os.system( "rm -rf e4a-%s"%(version) ) + os.system( "zip -r e4na-%s.zip en4a-%s"%(version, version) ) + os.system( "rm -rf en4a-%s"%(version) ) # change filename because some 3G carriers do not allow users to download a zip file... - e4a_name = "e4a-%s.zip"%version + e4a_name = "en4a-%s.zip"%version e4a_name2 = e4a_name.replace(".","") os.system( "mv %s %s"%(e4a_name, e4a_name2) ) diff --git a/plugins/coinbase_buyback.py b/plugins/coinbase_buyback.py deleted file mode 100644 index 04c3cff..0000000 --- a/plugins/coinbase_buyback.py +++ /dev/null @@ -1,316 +0,0 @@ -import PyQt4 -import sys - -import PyQt4.QtCore as QtCore -import base64 -import urllib -import re -import time -import os -import httplib -import datetime -import json -import string - -from urllib import urlencode - -from PyQt4.QtGui import * -from PyQt4.QtCore import * -try: - from PyQt4.QtWebKit import QWebView - loaded_qweb = True -except ImportError as e: - loaded_qweb = False - -from electrum import BasePlugin -from electrum.i18n import _, set_language -from electrum.util import user_dir -from electrum.util import appdata_dir -from electrum.util import format_satoshis -from electrum_gui.qt import ElectrumGui - -SATOSHIS_PER_BTC = float(100000000) -COINBASE_ENDPOINT = 'https://coinbase.com' -SCOPE = 'buy' -REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob' -TOKEN_URI = 'https://coinbase.com/oauth/token' -CLIENT_ID = '0a930a48b5a6ea10fb9f7a9fec3d093a6c9062ef8a7eeab20681274feabdab06' -CLIENT_SECRET = 'f515989e8819f1822b3ac7a7ef7e57f755c9b12aee8f22de6b340a99fd0fd617' -# Expiry is stored in RFC3339 UTC format -EXPIRY_FORMAT = '%Y-%m-%dT%H:%M:%SZ' - -class Plugin(BasePlugin): - - def fullname(self): return 'Coinbase BuyBack' - - def description(self): return 'After sending bitcoin, prompt the user with the option to rebuy them via Coinbase.\n\nMarcell Ortutay, 1FNGQvm29tKM7y3niq63RKi7Qbg7oZ3jrB' - - def __init__(self, gui, name): - BasePlugin.__init__(self, gui, name) - self._is_available = self._init() - - def _init(self): - return loaded_qweb - - def is_available(self): - return self._is_available - - def enable(self): - return BasePlugin.enable(self) - - def receive_tx(self, tx, wallet): - domain = wallet.get_account_addresses(None) - is_relevant, is_send, v, fee = tx.get_value(domain, wallet.prevout_values) - if isinstance(self.gui, ElectrumGui): - try: - web = propose_rebuy_qt(abs(v)) - except OAuth2Exception as e: - rm_local_oauth_credentials() - # TODO(ortutay): android flow - - -def propose_rebuy_qt(amount): - web = QWebView() - box = QMessageBox() - box.setFixedSize(200, 200) - - credentials = read_local_oauth_credentials() - questionText = _('Rebuy ') + format_satoshis(amount) + _(' BTC?') - if credentials: - credentials.refresh() - if credentials and not credentials.invalid: - credentials.store_locally() - totalPrice = get_coinbase_total_price(credentials, amount) - questionText += _('\n(Price: ') + totalPrice + _(')') - - if not question(box, questionText): - return - - if credentials: - do_buy(credentials, amount) - else: - do_oauth_flow(web, amount) - return web - -def do_buy(credentials, amount): - conn = httplib.HTTPSConnection('coinbase.com') - credentials.authorize(conn) - params = { - 'qty': float(amount)/SATOSHIS_PER_BTC, - 'agree_btc_amount_varies': False - } - resp = conn.auth_request('POST', '/api/v1/buys', urlencode(params), None) - - if resp.status != 200: - message(_('Error, could not buy bitcoin')) - return - content = json.loads(resp.read()) - if content['success']: - message(_('Success!\n') + content['transfer']['description']) - else: - if content['errors']: - message(_('Error: ') + string.join(content['errors'], '\n')) - else: - message(_('Error, could not buy bitcoin')) - -def get_coinbase_total_price(credentials, amount): - conn = httplib.HTTPSConnection('coinbase.com') - params={'qty': amount/SATOSHIS_PER_BTC} - conn.request('GET', '/api/v1/prices/buy?' + urlencode(params)) - resp = conn.getresponse() - if resp.status != 200: - return 'unavailable' - content = json.loads(resp.read()) - return '$' + content['total']['amount'] - -def do_oauth_flow(web, amount): - # QT expects un-escaped URL - auth_uri = step1_get_authorize_url() - web.load(QUrl(auth_uri)) - web.setFixedSize(500, 700) - web.show() - web.titleChanged.connect(lambda(title): complete_oauth_flow(title, web, amount) if re.search('^[a-z0-9]+$', title) else False) - -def complete_oauth_flow(token, web, amount): - web.close() - credentials = step2_exchange(str(token)) - credentials.store_locally() - do_buy(credentials, amount) - -def token_path(): - dir = user_dir() + '/coinbase_buyback' - if not os.access(dir, os.F_OK): - os.mkdir(dir) - return dir + '/token' - -def read_local_oauth_credentials(): - if not os.access(token_path(), os.F_OK): - return None - f = open(token_path(), 'r') - data = f.read() - f.close() - try: - credentials = Credentials.from_json(data) - return credentials - except Exception as e: - return None - -def rm_local_oauth_credentials(): - os.remove(token_path()) - -def step1_get_authorize_url(): - return ('https://coinbase.com/oauth/authorize' - + '?scope=' + SCOPE - + '&redirect_uri=' + REDIRECT_URI - + '&response_type=code' - + '&client_id=' + CLIENT_ID - + '&access_type=offline') - -def step2_exchange(code): - body = urllib.urlencode({ - 'grant_type': 'authorization_code', - 'client_id': CLIENT_ID, - 'client_secret': CLIENT_SECRET, - 'code': code, - 'redirect_uri': REDIRECT_URI, - 'scope': SCOPE, - }) - headers = { - 'content-type': 'application/x-www-form-urlencoded', - } - - conn = httplib.HTTPSConnection('coinbase.com') - conn.request('POST', TOKEN_URI, body, headers) - resp = conn.getresponse() - if resp.status == 200: - d = json.loads(resp.read()) - access_token = d['access_token'] - refresh_token = d.get('refresh_token', None) - token_expiry = None - if 'expires_in' in d: - token_expiry = datetime.datetime.utcnow() + datetime.timedelta( - seconds=int(d['expires_in'])) - return Credentials(access_token, refresh_token, token_expiry) - else: - raise OAuth2Exception(content) - -class OAuth2Exception(Exception): - """An error related to OAuth2""" - -class Credentials(object): - def __init__(self, access_token, refresh_token, token_expiry): - self.access_token = access_token - self.refresh_token = refresh_token - self.token_expiry = token_expiry - - # Indicates a failed refresh - self.invalid = False - - def to_json(self): - token_expiry = self.token_expiry - if (token_expiry and isinstance(token_expiry, datetime.datetime)): - token_expiry = token_expiry.strftime(EXPIRY_FORMAT) - - d = { - 'access_token': self.access_token, - 'refresh_token': self.refresh_token, - 'token_expiry': token_expiry, - } - return json.dumps(d) - - def store_locally(self): - f = open(token_path(), 'w') - f.write(self.to_json()) - f.close() - - @classmethod - def from_json(cls, s): - data = json.loads(s) - if ('token_expiry' in data - and not isinstance(data['token_expiry'], datetime.datetime)): - try: - data['token_expiry'] = datetime.datetime.strptime( - data['token_expiry'], EXPIRY_FORMAT) - except: - data['token_expiry'] = None - retval = Credentials( - data['access_token'], - data['refresh_token'], - data['token_expiry']) - return retval - - def apply(self, headers): - headers['Authorization'] = 'Bearer ' + self.access_token - - def authorize(self, conn): - request_orig = conn.request - - def new_request(method, uri, params, headers): - if headers == None: - headers = {} - self.apply(headers) - request_orig(method, uri, params, headers) - resp = conn.getresponse() - if resp.status == 401: - # Refresh and try again - self._refresh(request_orig) - self.store_locally() - self.apply(headers) - request_orig(method, uri, params, headers) - return conn.getresponse() - else: - return resp - - conn.auth_request = new_request - return conn - - def refresh(self): - try: - self._refresh() - except OAuth2Exception as e: - rm_local_oauth_credentials() - self.invalid = True - raise e - - def _refresh(self): - conn = httplib.HTTPSConnection('coinbase.com') - body = urllib.urlencode({ - 'grant_type': 'refresh_token', - 'refresh_token': self.refresh_token, - 'client_id': CLIENT_ID, - 'client_secret': CLIENT_SECRET, - }) - headers = { - 'content-type': 'application/x-www-form-urlencoded', - } - conn.request('POST', TOKEN_URI, body, headers) - resp = conn.getresponse() - if resp.status == 200: - d = json.loads(resp.read()) - self.token_response = d - self.access_token = d['access_token'] - self.refresh_token = d.get('refresh_token', self.refresh_token) - if 'expires_in' in d: - self.token_expiry = datetime.timedelta( - seconds=int(d['expires_in'])) + datetime.datetime.utcnow() - else: - raise OAuth2Exception('Refresh failed, ' + content) - -def message(msg): - box = QMessageBox() - box.setFixedSize(200, 200) - return QMessageBox.information(box, _('Message'), msg) - -def question(widget, msg): - return (QMessageBox.question( - widget, _('Message'), msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) - == QMessageBox.Yes) - -def main(): - app = QApplication(sys.argv) - print sys.argv[1] - propose_rebuy_qt(int(sys.argv[1])) - sys.exit(app.exec_()) - -if __name__ == "__main__": - main() diff --git a/plugins/exchange_rate.py b/plugins/exchange_rate.py deleted file mode 100644 index f8713a7..0000000 --- a/plugins/exchange_rate.py +++ /dev/null @@ -1,665 +0,0 @@ -from PyQt4.QtGui import * -from PyQt4.QtCore import * - -import datetime -import decimal -import httplib -import json -import threading -import time -import re -from decimal import Decimal -from electrum.plugins import BasePlugin -from electrum.i18n import _ -from electrum_gui.qt.util import * -from electrum_gui.qt.amountedit import AmountEdit - - -EXCHANGES = ["BitcoinAverage", - "BitcoinVenezuela", - "Bitcurex", - "Bitmarket", - "BitPay", - "Blockchain", - "BTCChina", - "CaVirtEx", - "Coinbase", - "CoinDesk", - "LocalBitcoins", - "Winkdex"] - - -class Exchanger(threading.Thread): - - def __init__(self, parent): - threading.Thread.__init__(self) - self.daemon = True - self.parent = parent - self.quote_currencies = None - self.lock = threading.Lock() - self.query_rates = threading.Event() - self.use_exchange = self.parent.config.get('use_exchange', "Blockchain") - self.parent.exchanges = EXCHANGES - self.parent.currencies = ["EUR","GBP","USD","PLN"] - self.parent.win.emit(SIGNAL("refresh_exchanges_combo()")) - self.parent.win.emit(SIGNAL("refresh_currencies_combo()")) - self.is_running = False - - def get_json(self, site, get_string): - try: - connection = httplib.HTTPSConnection(site) - connection.request("GET", get_string) - except Exception: - raise - resp = connection.getresponse() - if resp.reason == httplib.responses[httplib.NOT_FOUND]: - raise - try: - json_resp = json.loads(resp.read()) - except Exception: - raise - return json_resp - - - def exchange(self, btc_amount, quote_currency): - with self.lock: - if self.quote_currencies is None: - return None - quote_currencies = self.quote_currencies.copy() - if quote_currency not in quote_currencies: - return None - if self.use_exchange == "CoinDesk": - try: - resp_rate = self.get_json('api.coindesk.com', "/v1/bpi/currentprice/" + str(quote_currency) + ".json") - except Exception: - return - return btc_amount * decimal.Decimal(str(resp_rate["bpi"][str(quote_currency)]["rate_float"])) - return btc_amount * decimal.Decimal(str(quote_currencies[quote_currency])) - - def stop(self): - self.is_running = False - - def update_rate(self): - self.use_exchange = self.parent.config.get('use_exchange', "Blockchain") - update_rates = { - "BitcoinAverage": self.update_ba, - "BitcoinVenezuela": self.update_bv, - "Bitcurex": self.update_bx, - "Bitmarket": self.update_bm, - "BitPay": self.update_bp, - "Blockchain": self.update_bc, - "BTCChina": self.update_CNY, - "CaVirtEx": self.update_cv, - "CoinDesk": self.update_cd, - "Coinbase": self.update_cb, - "LocalBitcoins": self.update_lb, - "Winkdex": self.update_wd, - } - try: - update_rates[self.use_exchange]() - except KeyError: - return - - def run(self): - self.is_running = True - while self.is_running: - self.query_rates.clear() - self.update_rate() - self.query_rates.wait(150) - - - def update_cd(self): - try: - resp_currencies = self.get_json('api.coindesk.com', "/v1/bpi/supported-currencies.json") - except Exception: - return - - quote_currencies = {} - for cur in resp_currencies: - quote_currencies[str(cur["currency"])] = 0.0 - with self.lock: - self.quote_currencies = quote_currencies - self.parent.set_currencies(quote_currencies) - - def update_wd(self): - try: - winkresp = self.get_json('winkdex.com', "/static/data/0_600_288.json") - ####could need nonce value in GET, no Docs available - except Exception: - return - quote_currencies = {"USD": 0.0} - ####get y of highest x in "prices" - lenprices = len(winkresp["prices"]) - usdprice = winkresp["prices"][lenprices-1]["y"] - try: - quote_currencies["USD"] = decimal.Decimal(str(usdprice)) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - - def update_cv(self): - try: - jsonresp = self.get_json('www.cavirtex.com', "/api/CAD/ticker.json") - except Exception: - return - quote_currencies = {"CAD": 0.0} - cadprice = jsonresp["last"] - try: - quote_currencies["CAD"] = decimal.Decimal(str(cadprice)) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - - def update_bm(self): - try: - jsonresp = self.get_json('www.bitmarket.pl', "/json/BTCPLN/ticker.json") - except Exception: - return - quote_currencies = {"PLN": 0.0} - pln_price = jsonresp["last"] - try: - quote_currencies["PLN"] = decimal.Decimal(str(pln_price)) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - - def update_bx(self): - try: - jsonresp = self.get_json('pln.bitcurex.com', "/data/ticker.json") - except Exception: - return - quote_currencies = {"PLN": 0.0} - pln_price = jsonresp["last"] - try: - quote_currencies["PLN"] = decimal.Decimal(str(pln_price)) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - - def update_CNY(self): - try: - jsonresp = self.get_json('data.btcchina.com', "/data/ticker") - except Exception: - return - quote_currencies = {"CNY": 0.0} - cnyprice = jsonresp["ticker"]["last"] - try: - quote_currencies["CNY"] = decimal.Decimal(str(cnyprice)) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - - def update_bp(self): - try: - jsonresp = self.get_json('bitpay.com', "/api/rates") - except Exception: - return - quote_currencies = {} - try: - for r in jsonresp: - quote_currencies[str(r["code"])] = decimal.Decimal(r["rate"]) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - - def update_cb(self): - try: - jsonresp = self.get_json('coinbase.com', "/api/v1/currencies/exchange_rates") - except Exception: - return - - quote_currencies = {} - try: - for r in jsonresp: - if r[:7] == "btc_to_": - quote_currencies[r[7:].upper()] = self._lookup_rate_cb(jsonresp, r) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - - - def update_bc(self): - try: - jsonresp = self.get_json('blockchain.info', "/ticker") - except Exception: - return - quote_currencies = {} - try: - for r in jsonresp: - quote_currencies[r] = self._lookup_rate(jsonresp, r) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - # print "updating exchange rate", self.quote_currencies["USD"] - - def update_lb(self): - try: - jsonresp = self.get_json('localbitcoins.com', "/bitcoinaverage/ticker-all-currencies/") - except Exception: - return - quote_currencies = {} - try: - for r in jsonresp: - quote_currencies[r] = self._lookup_rate_lb(jsonresp, r) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - - - def update_bv(self): - try: - jsonresp = self.get_json('api.bitcoinvenezuela.com', "/") - except Exception: - return - quote_currencies = {} - try: - for r in jsonresp["BTC"]: - quote_currencies[r] = Decimal(jsonresp["BTC"][r]) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - - - def update_ba(self): - try: - jsonresp = self.get_json('api.bitcoinaverage.com', "/ticker/global/all") - except Exception: - return - quote_currencies = {} - try: - for r in jsonresp: - if not r == "timestamp": - quote_currencies[r] = self._lookup_rate_ba(jsonresp, r) - with self.lock: - self.quote_currencies = quote_currencies - except KeyError: - pass - self.parent.set_currencies(quote_currencies) - - - def get_currencies(self): - return [] if self.quote_currencies == None else sorted(self.quote_currencies.keys()) - - def _lookup_rate(self, response, quote_id): - return decimal.Decimal(str(response[str(quote_id)]["15m"])) - def _lookup_rate_cb(self, response, quote_id): - return decimal.Decimal(str(response[str(quote_id)])) - def _lookup_rate_ba(self, response, quote_id): - return decimal.Decimal(response[str(quote_id)]["last"]) - def _lookup_rate_lb(self, response, quote_id): - return decimal.Decimal(response[str(quote_id)]["rates"]["last"]) - - -class Plugin(BasePlugin): - - def fullname(self): - return "Exchange rates" - - def description(self): - return """exchange rates, retrieved from blockchain.info, CoinDesk, or Coinbase""" - - - def __init__(self,a,b): - BasePlugin.__init__(self,a,b) - self.currencies = [self.fiat_unit()] - self.exchanges = [self.config.get('use_exchange', "Blockchain")] - - def init(self): - self.win = self.gui.main_window - self.win.connect(self.win, SIGNAL("refresh_currencies()"), self.win.update_status) - self.btc_rate = Decimal("0.0") - # Do price discovery - self.exchanger = Exchanger(self) - self.exchanger.start() - self.gui.exchanger = self.exchanger # - self.add_fiat_edit() - - def set_currencies(self, currency_options): - self.currencies = sorted(currency_options) - self.win.emit(SIGNAL("refresh_currencies()")) - self.win.emit(SIGNAL("refresh_currencies_combo()")) - - def get_fiat_balance_text(self, btc_balance, r): - # return balance as: 1.23 USD - r[0] = self.create_fiat_balance_text(Decimal(btc_balance) / 100000000) - - def get_fiat_price_text(self, r): - # return BTC price as: 123.45 USD - r[0] = self.create_fiat_balance_text(1) - quote = r[0] - if quote: - r[0] = "%s"%quote - - def get_fiat_status_text(self, btc_balance, r2): - # return status as: (1.23 USD) 1 BTC~123.45 USD - text = "" - r = {} - self.get_fiat_price_text(r) - quote = r.get(0) - if quote: - price_text = "1 BTC~%s"%quote - fiat_currency = quote[-3:] - btc_price = self.btc_rate - fiat_balance = Decimal(btc_price) * (Decimal(btc_balance)/100000000) - balance_text = "(%.2f %s)" % (fiat_balance,fiat_currency) - text = " " + balance_text + " " + price_text + " " - r2[0] = text - - def create_fiat_balance_text(self, btc_balance): - quote_currency = self.fiat_unit() - self.exchanger.use_exchange = self.config.get("use_exchange", "Blockchain") - cur_rate = self.exchanger.exchange(Decimal("1.0"), quote_currency) - if cur_rate is None: - quote_text = "" - else: - quote_balance = btc_balance * Decimal(cur_rate) - self.btc_rate = cur_rate - quote_text = "%.2f %s" % (quote_balance, quote_currency) - return quote_text - - def load_wallet(self, wallet): - self.wallet = wallet - tx_list = {} - for item in self.wallet.get_tx_history(self.wallet.storage.get("current_account", None)): - tx_hash, conf, is_mine, value, fee, balance, timestamp = item - tx_list[tx_hash] = {'value': value, 'timestamp': timestamp, 'balance': balance} - - self.tx_list = tx_list - - - def requires_settings(self): - return True - - - def toggle(self): - enabled = BasePlugin.toggle(self) - self.win.update_status() - self.win.tabs.removeTab(1) - new_send_tab = self.gui.main_window.create_send_tab() - self.win.tabs.insertTab(1, new_send_tab, _('Send')) - if enabled: - self.add_fiat_edit() - return enabled - - - def close(self): - self.exchanger.stop() - - def history_tab_update(self): - if self.config.get('history_rates', 'unchecked') == "checked": - cur_exchange = self.config.get('use_exchange', "Blockchain") - try: - tx_list = self.tx_list - except Exception: - return - - try: - mintimestr = datetime.datetime.fromtimestamp(int(min(tx_list.items(), key=lambda x: x[1]['timestamp'])[1]['timestamp'])).strftime('%Y-%m-%d') - except Exception: - return - maxtimestr = datetime.datetime.now().strftime('%Y-%m-%d') - - if cur_exchange == "CoinDesk": - try: - resp_hist = self.exchanger.get_json('api.coindesk.com', "/v1/bpi/historical/close.json?start=" + mintimestr + "&end=" + maxtimestr) - except Exception: - return - elif cur_exchange == "Winkdex": - try: - resp_hist = self.exchanger.get_json('winkdex.com', "/static/data/0_86400_730.json")['prices'] - except Exception: - return - elif cur_exchange == "BitcoinVenezuela": - cur_currency = self.fiat_unit() - if cur_currency == "VEF": - try: - resp_hist = self.exchanger.get_json('api.bitcoinvenezuela.com', "/historical/index.php?coin=BTC")['VEF_BTC'] - except Exception: - return - elif cur_currency == "ARS": - try: - resp_hist = self.exchanger.get_json('api.bitcoinvenezuela.com', "/historical/index.php?coin=BTC")['ARS_BTC'] - except Exception: - return - else: - return - - self.gui.main_window.is_edit = True - self.gui.main_window.history_list.setColumnCount(6) - self.gui.main_window.history_list.setHeaderLabels( [ '', _('Date'), _('Description') , _('Amount'), _('Balance'), _('Fiat Amount')] ) - root = self.gui.main_window.history_list.invisibleRootItem() - childcount = root.childCount() - for i in range(childcount): - item = root.child(i) - try: - tx_info = tx_list[str(item.data(0, Qt.UserRole).toPyObject())] - except Exception: - newtx = self.wallet.get_tx_history() - v = newtx[[x[0] for x in newtx].index(str(item.data(0, Qt.UserRole).toPyObject()))][3] - - tx_info = {'timestamp':int(time.time()), 'value': v } - pass - tx_time = int(tx_info['timestamp']) - if cur_exchange == "CoinDesk": - tx_time_str = datetime.datetime.fromtimestamp(tx_time).strftime('%Y-%m-%d') - try: - tx_USD_val = "%.2f %s" % (Decimal(str(tx_info['value'])) / 100000000 * Decimal(resp_hist['bpi'][tx_time_str]), "USD") - except KeyError: - tx_USD_val = "%.2f %s" % (self.btc_rate * Decimal(str(tx_info['value']))/100000000 , "USD") - elif cur_exchange == "Winkdex": - tx_time_str = int(tx_time) - (int(tx_time) % (60 * 60 * 24)) - try: - tx_rate = resp_hist[[x['x'] for x in resp_hist].index(tx_time_str)]['y'] - tx_USD_val = "%.2f %s" % (Decimal(tx_info['value']) / 100000000 * Decimal(tx_rate), "USD") - except ValueError: - tx_USD_val = "%.2f %s" % (self.btc_rate * Decimal(tx_info['value'])/100000000 , "USD") - elif cur_exchange == "BitcoinVenezuela": - tx_time_str = datetime.datetime.fromtimestamp(tx_time).strftime('%Y-%m-%d') - try: - num = resp_hist[tx_time_str].replace(',','') - tx_BTCVEN_val = "%.2f %s" % (Decimal(str(tx_info['value'])) / 100000000 * Decimal(num), cur_currency) - except KeyError: - tx_BTCVEN_val = _("No data") - - if cur_exchange == "CoinDesk" or cur_exchange == "Winkdex": - item.setText(5, tx_USD_val) - elif cur_exchange == "BitcoinVenezuela": - item.setText(5, tx_BTCVEN_val) - if Decimal(str(tx_info['value'])) < 0: - item.setForeground(5, QBrush(QColor("#BC1E1E"))) - - for i, width in enumerate(self.gui.main_window.column_widths['history']): - self.gui.main_window.history_list.setColumnWidth(i, width) - self.gui.main_window.history_list.setColumnWidth(4, 140) - self.gui.main_window.history_list.setColumnWidth(5, 120) - self.gui.main_window.is_edit = False - - - def settings_widget(self, window): - return EnterButton(_('Settings'), self.settings_dialog) - - def settings_dialog(self): - d = QDialog() - d.setWindowTitle("Settings") - layout = QGridLayout(d) - layout.addWidget(QLabel(_('Exchange rate API: ')), 0, 0) - layout.addWidget(QLabel(_('Currency: ')), 1, 0) - layout.addWidget(QLabel(_('History Rates: ')), 2, 0) - combo = QComboBox() - combo_ex = QComboBox() - hist_checkbox = QCheckBox() - hist_checkbox.setEnabled(False) - if self.config.get('history_rates', 'unchecked') == 'unchecked': - hist_checkbox.setChecked(False) - else: - hist_checkbox.setChecked(True) - ok_button = QPushButton(_("OK")) - - def on_change(x): - try: - cur_request = str(self.currencies[x]) - except Exception: - return - if cur_request != self.fiat_unit(): - self.config.set_key('currency', cur_request, True) - cur_exchange = self.config.get('use_exchange', "Blockchain") - if cur_request == "USD" and (cur_exchange == "CoinDesk" or cur_exchange == "Winkdex"): - hist_checkbox.setEnabled(True) - elif cur_request == "VEF" and (cur_exchange == "BitcoinVenezuela"): - hist_checkbox.setEnabled(True) - elif cur_request == "ARS" and (cur_exchange == "BitcoinVenezuela"): - hist_checkbox.setEnabled(True) - else: - hist_checkbox.setChecked(False) - hist_checkbox.setEnabled(False) - self.win.update_status() - try: - self.fiat_button - except: - pass - else: - self.fiat_button.setText(cur_request) - - def disable_check(): - hist_checkbox.setChecked(False) - hist_checkbox.setEnabled(False) - - def on_change_ex(x): - cur_request = str(self.exchanges[x]) - if cur_request != self.config.get('use_exchange', "Blockchain"): - self.config.set_key('use_exchange', cur_request, True) - self.currencies = [] - combo.clear() - self.exchanger.query_rates.set() - cur_currency = self.fiat_unit() - if cur_request == "CoinDesk" or cur_request == "Winkdex": - if cur_currency == "USD": - hist_checkbox.setEnabled(True) - else: - disable_check() - elif cur_request == "BitcoinVenezuela": - if cur_currency == "VEF" or cur_currency == "ARS": - hist_checkbox.setEnabled(True) - else: - disable_check() - else: - disable_check() - set_currencies(combo) - self.win.update_status() - - def on_change_hist(checked): - if checked: - self.config.set_key('history_rates', 'checked') - self.history_tab_update() - else: - self.config.set_key('history_rates', 'unchecked') - self.gui.main_window.history_list.setHeaderLabels( [ '', _('Date'), _('Description') , _('Amount'), _('Balance')] ) - self.gui.main_window.history_list.setColumnCount(5) - for i,width in enumerate(self.gui.main_window.column_widths['history']): - self.gui.main_window.history_list.setColumnWidth(i, width) - - def set_hist_check(hist_checkbox): - cur_exchange = self.config.get('use_exchange', "Blockchain") - if cur_exchange == "CoinDesk" or cur_exchange == "Winkdex": - hist_checkbox.setEnabled(True) - elif cur_exchange == "BitcoinVenezuela": - hist_checkbox.setEnabled(True) - else: - hist_checkbox.setEnabled(False) - - def set_currencies(combo): - current_currency = self.fiat_unit() - try: - combo.clear() - except Exception: - return - combo.addItems(self.currencies) - try: - index = self.currencies.index(current_currency) - except Exception: - index = 0 - combo.setCurrentIndex(index) - - def set_exchanges(combo_ex): - try: - combo_ex.clear() - except Exception: - return - combo_ex.addItems(self.exchanges) - try: - index = self.exchanges.index(self.config.get('use_exchange', "Blockchain")) - except Exception: - index = 0 - combo_ex.setCurrentIndex(index) - - def ok_clicked(): - d.accept(); - - set_exchanges(combo_ex) - set_currencies(combo) - set_hist_check(hist_checkbox) - combo.currentIndexChanged.connect(on_change) - combo_ex.currentIndexChanged.connect(on_change_ex) - hist_checkbox.stateChanged.connect(on_change_hist) - combo.connect(self.win, SIGNAL('refresh_currencies_combo()'), lambda: set_currencies(combo)) - combo_ex.connect(d, SIGNAL('refresh_exchanges_combo()'), lambda: set_exchanges(combo_ex)) - ok_button.clicked.connect(lambda: ok_clicked()) - layout.addWidget(combo,1,1) - layout.addWidget(combo_ex,0,1) - layout.addWidget(hist_checkbox,2,1) - layout.addWidget(ok_button,3,1) - - if d.exec_(): - return True - else: - return False - - def fiat_unit(self): - return self.config.get("currency", "EUR") - - def add_fiat_edit(self): - self.fiat_e = AmountEdit(self.fiat_unit) - self.btc_e = self.win.amount_e - grid = self.btc_e.parent() - def fiat_changed(): - try: - fiat_amount = Decimal(str(self.fiat_e.text())) - except: - self.btc_e.setText("") - return - exchange_rate = self.exchanger.exchange(Decimal("1.0"), self.fiat_unit()) - if exchange_rate is not None: - btc_amount = fiat_amount/exchange_rate - self.btc_e.setAmount(int(btc_amount*Decimal(100000000))) - self.fiat_e.textEdited.connect(fiat_changed) - def btc_changed(): - btc_amount = self.btc_e.get_amount() - if btc_amount is None: - self.fiat_e.setText("") - return - fiat_amount = self.exchanger.exchange(Decimal(btc_amount)/Decimal(100000000), self.fiat_unit()) - if fiat_amount is not None: - self.fiat_e.setText("%.2f"%fiat_amount) - self.btc_e.textEdited.connect(btc_changed) - self.btc_e.frozen.connect(lambda: self.fiat_e.setFrozen(self.btc_e.isReadOnly())) - self.win.send_grid.addWidget(self.fiat_e, 4, 3, Qt.AlignHCenter) diff --git a/plugins/labels.py b/plugins/labels.py deleted file mode 100644 index 83609b0..0000000 --- a/plugins/labels.py +++ /dev/null @@ -1,231 +0,0 @@ -from electrum.util import print_error - -import httplib, urllib -import socket -import hashlib -import json -from urlparse import urlparse, parse_qs -try: - import PyQt4 -except Exception: - sys.exit("Error: Could not import PyQt4 on Linux systems, you may try 'sudo apt-get install python-qt4'") - -from PyQt4.QtGui import * -from PyQt4.QtCore import * -import PyQt4.QtCore as QtCore -import PyQt4.QtGui as QtGui -import aes -import base64 -from electrum.plugins import BasePlugin -from electrum.i18n import _ - -from electrum_gui.qt import HelpButton, EnterButton - -class Plugin(BasePlugin): - - def fullname(self): - return _('Label Sync') - - def description(self): - return '%s\n\n%s%s%s' % (_("This plugin can sync your labels across multiple Electrum installs by using a remote database to save your data. Labels, transactions and addresses are all sent and stored encrypted on the remote server. This code might increase the load of your wallet with a few microseconds as it will sync labels on each startup."), _("To get started visit"), " http://labelectrum.herokuapp.com/ ", _(" to sign up for an account.")) - - def version(self): - return "0.2.1" - - def encode(self, message): - encrypted = aes.encryptData(self.encode_password, unicode(message)) - encoded_message = base64.b64encode(encrypted) - - return encoded_message - - def decode(self, message): - decoded_message = aes.decryptData(self.encode_password, base64.b64decode(unicode(message)) ) - - return decoded_message - - - def init(self): - self.target_host = 'labelectrum.herokuapp.com' - self.window = self.gui.main_window - - def load_wallet(self, wallet): - self.wallet = wallet - if self.wallet.get_master_public_key(): - mpk = self.wallet.get_master_public_key() - else: - mpk = self.wallet.master_public_keys["m/0'/"][1] - self.encode_password = hashlib.sha1(mpk).digest().encode('hex')[:32] - self.wallet_id = hashlib.sha256(mpk).digest().encode('hex') - - addresses = [] - for account in self.wallet.accounts.values(): - for address in account.get_addresses(0): - addresses.append(address) - - self.addresses = addresses - - if self.auth_token(): - # If there is an auth token we can try to actually start syncing - self.full_pull() - - def auth_token(self): - return self.config.get("plugin_label_api_key") - - def is_available(self): - return True - - def requires_settings(self): - return True - - def set_label(self, item,label, changed): - if not changed: - return - try: - bundle = {"label": {"external_id": self.encode(item), "text": self.encode(label)}} - params = json.dumps(bundle) - connection = httplib.HTTPConnection(self.target_host) - connection.request("POST", ("/api/wallets/%s/labels.json?auth_token=%s" % (self.wallet_id, self.auth_token())), params, {'Content-Type': 'application/json'}) - - response = connection.getresponse() - if response.reason == httplib.responses[httplib.NOT_FOUND]: - return - response = json.loads(response.read()) - except socket.gaierror as e: - print_error('Error connecting to service: %s ' % e) - return False - - def settings_widget(self, window): - return EnterButton(_('Settings'), self.settings_dialog) - - def settings_dialog(self): - def check_for_api_key(api_key): - if api_key and len(api_key) > 12: - self.config.set_key("plugin_label_api_key", str(self.auth_token_edit.text())) - self.upload.setEnabled(True) - self.download.setEnabled(True) - self.accept.setEnabled(True) - else: - self.upload.setEnabled(False) - self.download.setEnabled(False) - self.accept.setEnabled(False) - - d = QDialog() - layout = QGridLayout(d) - layout.addWidget(QLabel("API Key: "),0,0) - - self.auth_token_edit = QLineEdit(self.auth_token()) - self.auth_token_edit.textChanged.connect(check_for_api_key) - - layout.addWidget(QLabel("Label sync options: "),2,0) - layout.addWidget(self.auth_token_edit, 0,1,1,2) - - decrypt_key_text = QLineEdit(self.encode_password) - decrypt_key_text.setReadOnly(True) - layout.addWidget(decrypt_key_text, 1,1) - layout.addWidget(QLabel("Decryption key: "),1,0) - layout.addWidget(HelpButton("This key can be used on the LabElectrum website to decrypt your data in case you want to review it online."),1,2) - - self.upload = QPushButton("Force upload") - self.upload.clicked.connect(self.full_push) - layout.addWidget(self.upload, 2,1) - - self.download = QPushButton("Force download") - self.download.clicked.connect(lambda: self.full_pull(True)) - layout.addWidget(self.download, 2,2) - - c = QPushButton(_("Cancel")) - c.clicked.connect(d.reject) - - self.accept = QPushButton(_("Done")) - self.accept.clicked.connect(d.accept) - - layout.addWidget(c,3,1) - layout.addWidget(self.accept,3,2) - - check_for_api_key(self.auth_token()) - - if d.exec_(): - return True - else: - return False - - def enable(self): - if not self.auth_token(): # First run, throw plugin settings in your face - self.init() - self.load_wallet(self.gui.main_window.wallet) - if self.settings_dialog(): - self.set_enabled(True) - return True - else: - self.set_enabled(False) - return False - - self.set_enabled(True) - return True - - - def full_push(self): - if self.do_full_push(): - QMessageBox.information(None, _("Labels uploaded"), _("Your labels have been uploaded.")) - - def full_pull(self, force = False): - if self.do_full_pull(force) and force: - QMessageBox.information(None, _("Labels synchronized"), _("Your labels have been synchronized.")) - self.window.update_history_tab() - self.window.update_completions() - self.window.update_receive_tab() - self.window.update_contacts_tab() - - def do_full_push(self): - try: - bundle = {"labels": {}} - for key, value in self.wallet.labels.iteritems(): - encoded = self.encode(key) - bundle["labels"][encoded] = self.encode(value) - - params = json.dumps(bundle) - connection = httplib.HTTPConnection(self.target_host) - connection.request("POST", ("/api/wallets/%s/labels/batch.json?auth_token=%s" % (self.wallet_id, self.auth_token())), params, {'Content-Type': 'application/json'}) - - response = connection.getresponse() - if response.reason == httplib.responses[httplib.NOT_FOUND]: - return - try: - response = json.loads(response.read()) - except ValueError as e: - return False - - if "error" in response: - QMessageBox.warning(None, _("Error"),_("Could not sync labels: %s" % response["error"])) - return False - - return True - except socket.gaierror as e: - print_error('Error connecting to service: %s ' % e) - return False - - def do_full_pull(self, force = False): - try: - connection = httplib.HTTPConnection(self.target_host) - connection.request("GET", ("/api/wallets/%s/labels.json?auth_token=%s" % (self.wallet_id, self.auth_token())),"", {'Content-Type': 'application/json'}) - response = connection.getresponse() - if response.reason == httplib.responses[httplib.NOT_FOUND]: - return - try: - response = json.loads(response.read()) - except ValueError as e: - return False - - if "error" in response: - QMessageBox.warning(None, _("Error"),_("Could not sync labels: %s" % response["error"])) - return False - - for label in response: - decoded_key = self.decode(label["external_id"]) - decoded_label = self.decode(label["text"]) - if force or not self.wallet.labels.get(decoded_key): - self.wallet.labels[decoded_key] = decoded_label - return True - except socket.gaierror as e: - print_error('Error connecting to service: %s ' % e) - return False diff --git a/plugins/pointofsale.py b/plugins/pointofsale.py deleted file mode 100644 index a153655..0000000 --- a/plugins/pointofsale.py +++ /dev/null @@ -1,121 +0,0 @@ -import re -import platform -from decimal import Decimal -from urllib import quote - -from PyQt4.QtGui import * -from PyQt4.QtCore import * -import PyQt4.QtCore as QtCore -import PyQt4.QtGui as QtGui - -from electrum_gui.qt.qrcodewidget import QRCodeWidget -from electrum import BasePlugin -from electrum.i18n import _ - - -if platform.system() == 'Windows': - MONOSPACE_FONT = 'Lucida Console' -elif platform.system() == 'Darwin': - MONOSPACE_FONT = 'Monaco' -else: - MONOSPACE_FONT = 'monospace' - -column_index = 4 - -class QR_Window(QWidget): - - def __init__(self, win): - QWidget.__init__(self) - self.win = win - self.setWindowTitle('Electrum - '+_('Invoice')) - self.setMinimumSize(800, 250) - self.address = '' - self.label = '' - self.amount = 0 - self.setFocusPolicy(QtCore.Qt.NoFocus) - - main_box = QHBoxLayout() - - self.qrw = QRCodeWidget() - main_box.addWidget(self.qrw, 1) - - vbox = QVBoxLayout() - main_box.addLayout(vbox) - - self.address_label = QLabel("") - #self.address_label.setFont(QFont(MONOSPACE_FONT)) - vbox.addWidget(self.address_label) - - self.label_label = QLabel("") - vbox.addWidget(self.label_label) - - self.amount_label = QLabel("") - vbox.addWidget(self.amount_label) - - vbox.addStretch(1) - self.setLayout(main_box) - - - def set_content(self, address, amount, message, url): - address_text = "%s" % address if address else "" - self.address_label.setText(address_text) - if amount: - amount = self.win.format_amount(amount) - amount_text = "%s %s " % (amount, self.win.base_unit()) - else: - amount_text = '' - self.amount_label.setText(amount_text) - label_text = "%s" % message if message else "" - self.label_label.setText(label_text) - self.qrw.setData(url) - - - - -class Plugin(BasePlugin): - - def fullname(self): - return 'Point of Sale' - - - def description(self): - return _('Show payment requests in a large, separate window.') - - - def init(self): - self.window = self.gui.main_window - self.qr_window = None - self.toggle_QR_window(True) - - - def close(self): - self.toggle_QR_window(False) - - - def close_main_window(self): - if self.qr_window: - self.qr_window.close() - self.qr_window = None - - - def update_receive_qr(self, address, amount, message, url): - self.qr_window.set_content( address, amount, message, url ) - - - def toggle_QR_window(self, show): - if show and not self.qr_window: - self.qr_window = QR_Window(self.gui.main_window) - self.qr_window.setVisible(True) - self.qr_window_geometry = self.qr_window.geometry() - - elif show and self.qr_window and not self.qr_window.isVisible(): - self.qr_window.setVisible(True) - self.qr_window.setGeometry(self.qr_window_geometry) - - elif not show and self.qr_window and self.qr_window.isVisible(): - self.qr_window_geometry = self.qr_window.geometry() - self.qr_window.setVisible(False) - - - - diff --git a/plugins/qrscanner.py b/plugins/qrscanner.py index 0ff1fe9..01a048f 100644 --- a/plugins/qrscanner.py +++ b/plugins/qrscanner.py @@ -1,16 +1,16 @@ -from electrum.util import print_error +from electrum_nvc.util import print_error from urlparse import urlparse, parse_qs from PyQt4.QtGui import QPushButton, QMessageBox, QDialog, QVBoxLayout, QHBoxLayout, QGridLayout, QLabel, QLineEdit, QComboBox from PyQt4.QtCore import Qt -from electrum.i18n import _ +from electrum_nvc.i18n import _ import re import os -from electrum import Transaction -from electrum.bitcoin import MIN_RELAY_TX_FEE, is_valid -from electrum_gui.qt.qrcodewidget import QRCodeWidget -from electrum import bmp -from electrum_gui.qt import HelpButton, EnterButton +from electrum_nvc import Transaction +from electrum_nvc.bitcoin import MIN_RELAY_TX_FEE, is_valid +from electrum_nvc_gui.qt.qrcodewidget import QRCodeWidget +from electrum_nvc import bmp +from electrum_nvc_gui.qt import HelpButton, EnterButton import json try: @@ -18,7 +18,7 @@ try: except ImportError: zbar = None -from electrum import BasePlugin +from electrum_nvc import BasePlugin class Plugin(BasePlugin): def fullname(self): return 'QR scans' @@ -40,7 +40,6 @@ class Plugin(BasePlugin): except zbar.SystemError: # Cannot open video device pass - #return False return True diff --git a/plugins/virtualkeyboard.py b/plugins/virtualkeyboard.py index be02e36..eadaebe 100644 --- a/plugins/virtualkeyboard.py +++ b/plugins/virtualkeyboard.py @@ -1,6 +1,6 @@ from PyQt4.QtGui import * -from electrum import BasePlugin -from electrum.i18n import _ +from electrum_nvc import BasePlugin +from electrum_nvc.i18n import _ class Plugin(BasePlugin): diff --git a/scripts/get_history b/scripts/get_history index 4801e02..871ab71 100755 --- a/scripts/get_history +++ b/scripts/get_history @@ -1,12 +1,12 @@ #!/usr/bin/env python import sys -from electrum import NetworkProxy, print_json +from electrum_nvc import NetworkProxy, print_json try: addr = sys.argv[1] except Exception: - print "usage: get_history " + print "usage: get_history " sys.exit(1) n = NetworkProxy() diff --git a/scripts/merchant/merchant.py b/scripts/merchant/merchant.py index 79624ea..9456f10 100644 --- a/scripts/merchant/merchant.py +++ b/scripts/merchant/merchant.py @@ -21,7 +21,7 @@ import time, thread, sys, socket, os import urllib2,json import Queue import sqlite3 -from electrum import Wallet, WalletStorage, SimpleConfig, Network, set_verbosity +from electrum_nvc import Wallet, WalletStorage, SimpleConfig, Network, set_verbosity set_verbosity(False) import ConfigParser diff --git a/scripts/peers b/scripts/peers index ef71fff..af4eb48 100755 --- a/scripts/peers +++ b/scripts/peers @@ -1,12 +1,12 @@ #!/usr/bin/env python -import time, electrum, Queue -from electrum import Interface, SimpleConfig -from electrum.network import filter_protocol, parse_servers +import time, electrum_nvc, Queue +from electrum_nvc import Interface, SimpleConfig +from electrum_nvc.network import filter_protocol, parse_servers from collections import defaultdict # 1. start interface and wait for connection -interface = electrum.Interface('ecdsa.net:50002:s') +interface = electrum.Interface('127.0.0.1:50002:s') interface.start(wait = True) if not interface.is_connected: print "not connected" diff --git a/scripts/servers b/scripts/servers index 3525dc3..9e0ce15 100755 --- a/scripts/servers +++ b/scripts/servers @@ -1,7 +1,7 @@ #!/usr/bin/env python -from electrum import Interface, SimpleConfig, set_verbosity -from electrum.network import DEFAULT_SERVERS, filter_protocol +from electrum_nvc import Interface, SimpleConfig, set_verbosity +from electrum_nvc.network import DEFAULT_SERVERS, filter_protocol import time, Queue from collections import defaultdict diff --git a/scripts/watch_address b/scripts/watch_address index ab9365e..d992699 100755 --- a/scripts/watch_address +++ b/scripts/watch_address @@ -1,6 +1,6 @@ #!/usr/bin/env python -import sys, time, electrum +import sys, time, electrum_nvc try: addr = sys.argv[1] diff --git a/setup-release.py b/setup-release.py index 62f9a87..a598fec 100644 --- a/setup-release.py +++ b/setup-release.py @@ -1,5 +1,5 @@ """ -py2app/py2exe build script for Electrum Litecoin +py2app/py2exe build script for Electrum Novacoin Usage (Mac OS X): python setup.py py2app @@ -18,8 +18,8 @@ from lib.util import print_error from lib.version import ELECTRUM_VERSION as version -name = "Electrum" -mainscript = 'electrum' +name = "Electrum-NVC" +mainscript = 'electrum-nvc' if sys.version_info[:3] < (2, 6, 0): print_error("Error: " + name + " requires Python version >= 2.6.0...") diff --git a/setup.py b/setup.py index 7b6348f..cecc812 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ data_files = [] if (len(sys.argv) > 1 and (sys.argv[1] == "sdist")) or (platform.system() != 'Windows' and platform.system() != 'Darwin'): print "Including all files" data_files += [ - (os.path.join(usr_share, 'applications/'), ['electrum.desktop']), + (os.path.join(usr_share, 'applications/'), ['electrum-nvc.desktop']), (os.path.join(usr_share, 'app-install', 'icons/'), ['icons/electrum.png']) ] if not os.path.exists('locale'): @@ -34,7 +34,7 @@ if (len(sys.argv) > 1 and (sys.argv[1] == "sdist")) or (platform.system() != 'Wi appdata_dir = util.appdata_dir() if not os.access(appdata_dir, os.W_OK): - appdata_dir = os.path.join(usr_share, "electrum") + appdata_dir = os.path.join(usr_share, "electrum-nvc") data_files += [ (appdata_dir, ["data/README"]), @@ -54,74 +54,70 @@ data_files += [ setup( - name="Electrum", + name="Electrum-NVC", version=version.ELECTRUM_VERSION, - install_requires=['slowaes', 'ecdsa>=0.9', 'pbkdf2', 'requests', 'pyasn1', 'pyasn1-modules', 'tlslite>=0.4.5', 'qrcode'], + install_requires=['slowaes', 'ecdsa>=0.9', 'pbkdf2', 'requests', 'pyasn1', 'pyasn1-modules', 'tlslite>=0.4.5', 'qrcode', 'ltc_scrypt'], package_dir={ - 'electrum': 'lib', - 'electrum_gui': 'gui', - 'electrum_plugins': 'plugins', + 'electrum_nvc': 'lib', + 'electrum_nvc_gui': 'gui', + 'electrum_nvc_plugins': 'plugins', }, scripts=['electrum'], data_files=data_files, py_modules=[ - 'electrum.account', - 'electrum.bitcoin', - 'electrum.blockchain', - 'electrum.bmp', - 'electrum.commands', - 'electrum.daemon', - 'electrum.i18n', - 'electrum.interface', - 'electrum.mnemonic', - 'electrum.msqr', - 'electrum.network', - 'electrum.paymentrequest', - 'electrum.paymentrequest_pb2', - 'electrum.plugins', - 'electrum.simple_config', - 'electrum.socks', - 'electrum.synchronizer', - 'electrum.transaction', - 'electrum.util', - 'electrum.verifier', - 'electrum.version', - 'electrum.wallet', - 'electrum.wallet_bitkey', - 'electrum.x509', - 'electrum_gui.gtk', - 'electrum_gui.qt.__init__', - 'electrum_gui.qt.amountedit', - 'electrum_gui.qt.console', - 'electrum_gui.qt.history_widget', - 'electrum_gui.qt.icons_rc', - 'electrum_gui.qt.installwizard', - 'electrum_gui.qt.lite_window', - 'electrum_gui.qt.main_window', - 'electrum_gui.qt.network_dialog', - 'electrum_gui.qt.password_dialog', - 'electrum_gui.qt.paytoedit', - 'electrum_gui.qt.qrcodewidget', - 'electrum_gui.qt.qrtextedit', - 'electrum_gui.qt.receiving_widget', - 'electrum_gui.qt.seed_dialog', - 'electrum_gui.qt.transaction_dialog', - 'electrum_gui.qt.util', - 'electrum_gui.qt.version_getter', - 'electrum_gui.stdio', - 'electrum_gui.text', - 'electrum_plugins.aliases', - 'electrum_plugins.coinbase_buyback', - 'electrum_plugins.exchange_rate', - 'electrum_plugins.labels', - 'electrum_plugins.pointofsale', - 'electrum_plugins.qrscanner', - 'electrum_plugins.virtualkeyboard', + 'electrum_nvc.account', + 'electrum_nvc.bitcoin', + 'electrum_nvc.blockchain', + 'electrum_nvc.bmp', + 'electrum_nvc.commands', + 'electrum_nvc.daemon', + 'electrum_nvc.i18n', + 'electrum_nvc.interface', + 'electrum_nvc.mnemonic', + 'electrum_nvc.msqr', + 'electrum_nvc.network', + 'electrum_nvc.paymentrequest', + 'electrum_nvc.paymentrequest_pb2', + 'electrum_nvc.plugins', + 'electrum_nvc.scrypt', + 'electrum_nvc.simple_config', + 'electrum_nvc.socks', + 'electrum_nvc.synchronizer', + 'electrum_nvc.transaction', + 'electrum_nvc.util', + 'electrum_nvc.verifier', + 'electrum_nvc.version', + 'electrum_nvc.wallet', + 'electrum_nvc.wallet_bitkey', + 'electrum_nvc.x509', + 'electrum_nvc_gui.gtk', + 'electrum_nvc_gui.qt.__init__', + 'electrum_nvc_gui.qt.amountedit', + 'electrum_nvc_gui.qt.console', + 'electrum_nvc_gui.qt.history_widget', + 'electrum_nvc_gui.qt.icons_rc', + 'electrum_nvc_gui.qt.installwizard', + 'electrum_nvc_gui.qt.lite_window', + 'electrum_nvc_gui.qt.main_window', + 'electrum_nvc_gui.qt.network_dialog', + 'electrum_nvc_gui.qt.password_dialog', + 'electrum_nvc_gui.qt.paytoedit', + 'electrum_nvc_gui.qt.qrcodewidget', + 'electrum_nvc_gui.qt.qrtextedit', + 'electrum_nvc_gui.qt.receiving_widget', + 'electrum_nvc_gui.qt.seed_dialog', + 'electrum_nvc_gui.qt.transaction_dialog', + 'electrum_nvc_gui.qt.util', + 'electrum_nvc_gui.qt.version_getter', + 'electrum_nvc_gui.stdio', + 'electrum_nvc_gui.text', + 'electrum_nvc_plugins.qrscanner', + 'electrum_nvc_plugins.virtualkeyboard', ], - description="Lightweight Bitcoin Wallet", + description="Lightweight Novacoin Wallet", author="Thomas Voegtlin", author_email="thomasv1@gmx.de", license="GNU GPLv3", url="https://electrum.org", - long_description="""Lightweight Bitcoin Wallet""" + long_description="""Lightweight Novacoin Wallet""" )