Zcash changes to lib

This commit is contained in:
zebra-lucky 2018-03-11 03:23:24 +02:00
parent 717b3d7df2
commit 9f61882b3a
22 changed files with 130 additions and 388 deletions

View File

@ -43,7 +43,7 @@ if jnius:
script_dir = os.path.dirname(os.path.realpath(__file__))
is_bundle = getattr(sys, 'frozen', False)
is_local = not is_bundle and os.path.exists(os.path.join(script_dir, "electrum.desktop"))
is_local = not is_bundle and os.path.exists(os.path.join(script_dir, "electrum-zcash.desktop"))
is_android = 'ANDROID_DATA' in os.environ
# move this back to gui/kivy/__init.py once plugins are moved
@ -82,22 +82,22 @@ if not is_android:
# load local module as electrum
if is_local or is_android:
import imp
imp.load_module('electrum', *imp.find_module('lib'))
imp.load_module('electrum_gui', *imp.find_module('gui'))
imp.load_module('electrum_plugins', *imp.find_module('plugins'))
imp.load_module('electrum_zcash', *imp.find_module('lib'))
imp.load_module('electrum_zcash_gui', *imp.find_module('gui'))
imp.load_module('electrum_zcash_plugins', *imp.find_module('plugins'))
from electrum import bitcoin
from electrum import SimpleConfig, Network
from electrum.wallet import Wallet, Imported_Wallet
from electrum.storage import WalletStorage
from electrum.util import print_msg, print_stderr, json_encode, json_decode
from electrum.util import set_verbosity, InvalidPassword, check_www_dir
from electrum.commands import get_parser, known_commands, Commands, config_variables
from electrum import daemon
from electrum import keystore
from electrum.mnemonic import Mnemonic
import electrum_plugins
from electrum_zcash import bitcoin
from electrum_zcash import SimpleConfig, Network
from electrum_zcash.wallet import Wallet, Imported_Wallet
from electrum_zcash.storage import WalletStorage
from electrum_zcash.util import print_msg, print_stderr, json_encode, json_decode
from electrum_zcash.util import set_verbosity, InvalidPassword, check_www_dir
from electrum_zcash.commands import get_parser, known_commands, Commands, config_variables
from electrum_zcash import daemon
from electrum_zcash import keystore
from electrum_zcash.mnemonic import Mnemonic
import electrum_zcash_plugins
# get password routine
def prompt_password(prompt, confirm=True):
@ -189,7 +189,7 @@ def init_daemon(config_options):
storage = WalletStorage(config.get_wallet_path())
if 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-zcash create' to create a new wallet, or provide a path to a wallet with the -w option")
sys.exit(0)
if storage.is_encrypted():
if config.get('password'):
@ -224,7 +224,7 @@ def init_cmdline(config_options, server):
if 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-zcash create' to create a new wallet, or provide a path to a wallet with the -w option")
sys.exit(0)
# important warning
@ -292,7 +292,7 @@ def run_offline_command(config, config_options):
return result
def init_plugins(config, gui_name):
from electrum.plugins import Plugins
from electrum_zcash.plugins import Plugins
return Plugins(config, is_local or is_android, gui_name)
if __name__ == '__main__':
@ -351,7 +351,7 @@ if __name__ == '__main__':
# check uri
uri = config_options.get('url')
if uri:
if not uri.startswith('bitcoin:'):
if not uri.startswith('zcash:'):
print_stderr('unknown command:', uri)
sys.exit(1)
config_options['url'] = uri
@ -396,7 +396,7 @@ if __name__ == '__main__':
d = daemon.Daemon(config, fd, False)
d.start()
if config.get('websocket_server'):
from electrum import websockets
from electrum_zcash import websockets
websockets.WebSocketServer(config, d.network).start()
if config.get('requests_dir'):
check_www_dir(config.get('requests_dir'))
@ -420,7 +420,7 @@ if __name__ == '__main__':
else:
cmd = known_commands[cmdname]
if cmd.requires_network:
print_msg("Daemon not running; try 'electrum daemon start'")
print_msg("Daemon not running; try 'electrum-zcash daemon start'")
sys.exit(1)
else:
init_plugins(config, 'cmdline')

View File

@ -19,6 +19,6 @@ fi
export PYTHONPATH="/usr/local/lib/python3.5/site-packages:$PYTHONPATH"
./electrum "$@"
./electrum-zcash "$@"
deactivate

View File

@ -1,7 +1,7 @@
# Configuration file for the electrum client
# Configuration file for the electrum-zcash client
# Settings defined here are shared across wallets
#
# copy this file to /etc/electrum.conf if you want read-only settings
# copy this file to /etc/electrum-zcash.conf if you want read-only settings
[client]
server = electrum.novit.ro:50001:t

17
electrum-zcash.desktop Normal file
View File

@ -0,0 +1,17 @@
# If you want electrum-zcash to appear in a linux app launcher ("start menu"), install this by doing:
# sudo desktop-file-install electrum-zcash.desktop
[Desktop Entry]
Comment=Lightweight Zcash Client
Exec=electrum-zcash %u
GenericName[en_US]=Zcash Wallet
GenericName=Zcash Wallet
Icon=electrum-zcash.png
Name[en_US]=Electrum-Zcash Bitcoin Wallet
Name=Electrum-Zcash Bitcoin Wallet
Categories=Finance;Network;
StartupNotify=false
Terminal=false
Type=Application
MimeType=x-scheme-handler/zcash;

View File

@ -1,17 +0,0 @@
# If you want electrum to appear in a linux app launcher ("start menu"), install this by doing:
# sudo desktop-file-install electrum.desktop
[Desktop Entry]
Comment=Lightweight Bitcoin Client
Exec=electrum %u
GenericName[en_US]=Bitcoin Wallet
GenericName=Bitcoin Wallet
Icon=electrum
Name[en_US]=Electrum Bitcoin Wallet
Name=Electrum Bitcoin Wallet
Categories=Finance;Network;
StartupNotify=false
Terminal=false
Type=Application
MimeType=x-scheme-handler/bitcoin;

View File

@ -79,27 +79,18 @@ class BaseWizard(object):
])
wallet_kinds = [
('standard', _("Standard wallet")),
('2fa', _("Wallet with two-factor authentication")),
('multisig', _("Multi-signature wallet")),
('imported', _("Import Bitcoin addresses or private keys")),
('imported', _("Import Zcash addresses or private keys")),
]
choices = [pair for pair in wallet_kinds if pair[0] in wallet_types]
self.choice_dialog(title=title, message=message, choices=choices, run_next=self.on_wallet_type)
def load_2fa(self):
self.storage.put('wallet_type', '2fa')
self.storage.put('use_trustedcoin', True)
self.plugin = self.plugins.load_plugin('trustedcoin')
def on_wallet_type(self, choice):
self.wallet_type = choice
if choice == 'standard':
action = 'choose_keystore'
elif choice == 'multisig':
action = 'choose_multisig'
elif choice == '2fa':
self.load_2fa()
action = self.storage.get_action()
elif choice == 'imported':
action = 'import_addresses_or_keys'
self.run(action)
@ -138,8 +129,8 @@ class BaseWizard(object):
def import_addresses_or_keys(self):
v = lambda x: keystore.is_address_list(x) or keystore.is_private_key_list(x)
title = _("Import Bitcoin Addresses")
message = _("Enter a list of Bitcoin addresses (this will create a watching-only wallet), or a list of private keys.")
title = _("Import Zcash Addresses")
message = _("Enter a list of Zcash addresses (this will create a watching-only wallet), or a list of private keys.")
self.add_xpub_dialog(title=title, message=message, run_next=self.on_import, is_valid=v)
def on_import(self, text):
@ -160,8 +151,8 @@ class BaseWizard(object):
v = keystore.is_master_key
title = _("Create keystore from a master key")
message = ' '.join([
_("To create a watching-only wallet, please enter your master public key (xpub/ypub/zpub)."),
_("To create a spending wallet, please enter a master private key (xprv/yprv/zprv).")
_("To create a watching-only wallet, please enter your master public key (xpub)."),
_("To create a spending wallet, please enter a master private key (xprv).")
])
self.add_xpub_dialog(title=title, message=message, run_next=self.on_restore_from_key, is_valid=v)
else:
@ -285,13 +276,6 @@ class BaseWizard(object):
self.passphrase_dialog(run_next=f) if is_ext else f('')
elif self.seed_type == 'old':
self.run('create_keystore', seed, '')
elif self.seed_type == '2fa':
if self.is_kivy:
self.show_error('2FA seeds are not supported in this version')
self.run('restore_from_seed')
else:
self.load_2fa()
self.run('on_restore_seed', seed, is_ext)
else:
raise BaseException('Unknown seed type', self.seed_type)
@ -424,5 +408,5 @@ class BaseWizard(object):
self.wallet.synchronize()
self.wallet.storage.write()
self.terminate()
msg = _("Electrum is generating your addresses, please wait.")
msg = _("Electrum-Zcash is generating your addresses, please wait.")
self.waiting_dialog(task, msg)

View File

@ -271,8 +271,6 @@ def seed_type(x):
return 'old'
elif is_new_seed(x):
return 'standard'
elif is_new_seed(x, version.SEED_PREFIX_2FA):
return '2fa'
return ''
is_seed = lambda x: bool(seed_type(x))
@ -558,7 +556,7 @@ from ecdsa.util import string_to_number, number_to_string
def msg_magic(message):
length = bfh(var_int(len(message)))
return b"\x18Bitcoin Signed Message:\n" + length + message
return b"\x18Zcash Signed Message:\n" + length + message
def verify_message(address, sig, message):

View File

@ -81,7 +81,7 @@ def command(s):
wallet = args[0].wallet
password = kwargs.get('password')
if c.requires_wallet and wallet is None:
raise BaseException("wallet not loaded. Use 'electrum daemon load_wallet'")
raise BaseException("wallet not loaded. Use 'electrum-zcash daemon load_wallet'")
if c.requires_password and password is None and wallet.storage.get('use_encryption'):
return {'error': 'Password required' }
return func(*args, **kwargs)
@ -130,8 +130,8 @@ class Commands:
@command('wn')
def restore(self, text):
"""Restore a wallet from text. Text can be a seed phrase, a master
public key, a master private key, a list of bitcoin addresses
or bitcoin private keys. If you want to be prompted for your
public key, a master private key, a list of Zcash addresses
or Zcash private keys. If you want to be prompted for your
seed, type '?' or ':' (concealed) """
raise BaseException('Not a JSON-RPC command')
@ -288,7 +288,7 @@ class Commands:
@command('')
def dumpprivkeys(self):
"""Deprecated."""
return "This command is deprecated. Use a pipe instead: 'electrum listaddresses | electrum getprivatekeys - '"
return "This command is deprecated. Use a pipe instead: 'electrum-zcash listaddresses | electrum-zcash getprivatekeys - '"
@command('')
def validateaddress(self, address):
@ -332,7 +332,7 @@ class Commands:
@command('n')
def getmerkle(self, txid, height):
"""Get Merkle branch of a transaction included in a block. Electrum
"""Get Merkle branch of a transaction included in a block. Electrum-Zcash
uses this to verify transactions (Simple Payment Verification)."""
return self.network.synchronous_get(('blockchain.transaction.get_merkle', [txid, int(height)]))
@ -343,7 +343,7 @@ class Commands:
@command('')
def version(self):
"""Return the version of electrum."""
"""Return the version of electrum-zcash."""
from .version import ELECTRUM_VERSION
return ELECTRUM_VERSION
@ -491,7 +491,7 @@ class Commands:
@command('w')
def setlabel(self, key, label):
"""Assign a label to an item. Item may be a bitcoin address or a
"""Assign a label to an item. Item may be a Zcash address or a
transaction ID"""
self.wallet.set_label(key, label)
@ -569,7 +569,7 @@ class Commands:
PR_PAID: 'Paid',
PR_EXPIRED: 'Expired',
}
out['amount (BTC)'] = format_satoshis(out.get('amount'))
out['amount (ZEC)'] = format_satoshis(out.get('amount'))
out['status'] = pr_str[out.get('status', PR_UNKNOWN)]
return out
@ -679,8 +679,8 @@ class Commands:
param_descriptions = {
'privkey': 'Private key. Type \'?\' to get a prompt.',
'destination': 'Bitcoin address, contact or alias',
'address': 'Bitcoin address',
'destination': 'Zcash address, contact or alias',
'address': 'Zcash address',
'seed': 'Seed phrase',
'txid': 'Transaction ID',
'pos': 'Position',
@ -690,8 +690,8 @@ param_descriptions = {
'pubkey': 'Public key',
'message': 'Clear text message. Use quotes if it contains spaces.',
'encrypted': 'Encrypted message',
'amount': 'Amount to be sent (in BTC). Type \'!\' to send the maximum available.',
'requested_amount': 'Requested amount (in BTC).',
'amount': 'Amount to be sent (in ZEC). Type \'!\' to send the maximum available.',
'requested_amount': 'Requested amount (in ZEC).',
'outputs': 'list of ["address", amount]',
'redeem_script': 'redeem script (hexadecimal)',
}
@ -708,7 +708,7 @@ command_options = {
'labels': ("-l", "Show the labels of listed addresses"),
'nocheck': (None, "Do not verify aliases"),
'imax': (None, "Maximum number of inputs"),
'fee': ("-f", "Transaction fee (in BTC)"),
'fee': ("-f", "Transaction fee (in ZEC)"),
'from_addr': ("-F", "Source address (must be a wallet address; use sweep to spend from non-wallet address)."),
'change_addr': ("-c", "Change address. Default is a spare address, or the source address if it's not in the wallet"),
'nbits': (None, "Number of bits of entropy"),
@ -753,10 +753,10 @@ config_variables = {
'requests_dir': 'directory where a bip70 file will be written.',
'ssl_privkey': 'Path to your SSL private key, needed to sign the request.',
'ssl_chain': 'Chain of SSL certificates, needed for signed requests. Put your certificate at the top and the root CA at the end',
'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of bitcoin: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"',
'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of zcash: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"',
},
'listrequests':{
'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of bitcoin: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"',
'url_rewrite': 'Parameters passed to str.replace(), in order to create the r= part of zcash: URIs. Example: \"(\'file:///var/www/\',\'https://electrum.org/\')\"',
}
}
@ -820,7 +820,7 @@ def add_network_options(parser):
def add_global_options(parser):
group = parser.add_argument_group('global options')
group.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Show debugging information")
group.add_argument("-D", "--dir", dest="electrum_path", help="electrum directory")
group.add_argument("-D", "--dir", dest="electrum_path", help="electrum-zcash directory")
group.add_argument("-P", "--portable", action="store_true", dest="portable", default=False, help="Use local 'electrum_data' directory")
group.add_argument("-w", "--wallet", dest="wallet_path", help="wallet path")
group.add_argument("--testnet", action="store_true", dest="testnet", default=False, help="Use Testnet")
@ -828,12 +828,12 @@ def add_global_options(parser):
def get_parser():
# create main parser
parser = argparse.ArgumentParser(
epilog="Run 'electrum help <command>' to see the help for a command")
epilog="Run 'electrum-zcash help <command>' to see the help for a command")
add_global_options(parser)
subparsers = parser.add_subparsers(dest='cmd', metavar='<command>')
# gui
parser_gui = subparsers.add_parser('gui', description="Run Electrum's Graphical User Interface.", help="Run GUI (default)")
parser_gui.add_argument("url", nargs='?', default=None, help="bitcoin URI (or bip70 file)")
parser_gui = subparsers.add_parser('gui', description="Run Electrum-Zcash Graphical User Interface.", help="Run GUI (default)")
parser_gui.add_argument("url", nargs='?', default=None, help="Zcash URI (or bip70 file)")
parser_gui.add_argument("-g", "--gui", dest="gui", help="select graphical user interface", choices=['qt', 'kivy', 'text', 'stdio'])
parser_gui.add_argument("-o", "--offline", action="store_true", dest="offline", default=False, help="Run offline")
parser_gui.add_argument("-m", action="store_true", dest="hide_gui", default=False, help="hide GUI on startup")

View File

@ -87,13 +87,13 @@ class Contacts(dict):
'type': 'openalias',
'validated': validated
}
raise Exception("Invalid Bitcoin address or alias", k)
raise Exception("Invalid Zcash address or alias", k)
def resolve_openalias(self, url):
# support email-style addresses, per the OA standard
url = url.replace('@', '.')
records, validated = dnssec.query(url, dns.rdatatype.TXT)
prefix = 'btc'
prefix = 'zcash'
for record in records:
string = record.strings[0]
if string.startswith('oa1:' + prefix):

View File

@ -299,6 +299,6 @@ class Daemon(DaemonThread):
gui_name = config.get('gui', 'qt')
if gui_name in ['lite', 'classic']:
gui_name = 'qt'
gui = __import__('electrum_gui.' + gui_name, fromlist=['electrum_gui'])
gui = __import__('electrum_zcash_gui.' + gui_name, fromlist=['electrum_zcash_gui'])
self.gui = gui.ElectrumGui(config, self, plugins)
self.gui.main()

View File

@ -46,8 +46,8 @@ from . import rsakey
from .bitcoin import TYPE_ADDRESS
REQUEST_HEADERS = {'Accept': 'application/bitcoin-paymentrequest', 'User-Agent': 'Electrum'}
ACK_HEADERS = {'Content-Type':'application/bitcoin-payment','Accept':'application/bitcoin-paymentack','User-Agent':'Electrum'}
REQUEST_HEADERS = {'Accept': 'application/zcash-paymentrequest', 'User-Agent': 'Electrum-Zcash'}
ACK_HEADERS = {'Content-Type':'application/zcash-payment','Accept':'application/zcash-paymentack','User-Agent':'Electrum-Zcash'}
ca_path = requests.certs.where()
ca_list = None
@ -75,9 +75,9 @@ def get_payment_request(url):
try:
response = requests.request('GET', url, headers=REQUEST_HEADERS)
response.raise_for_status()
# Guard against `bitcoin:`-URIs with invalid payment request URLs
# Guard against `zcash:`-URIs with invalid payment request URLs
if "Content-Type" not in response.headers \
or response.headers["Content-Type"] != "application/bitcoin-paymentrequest":
or response.headers["Content-Type"] != "application/zcash-paymentrequest":
data = None
error = "payment URL not pointing to a payment request handling server"
else:
@ -266,7 +266,7 @@ class PaymentRequest:
paymnt.transactions.append(bfh(raw_tx))
ref_out = paymnt.refund_to.add()
ref_out.script = util.bfh(transaction.Transaction.pay_script(TYPE_ADDRESS, refund_addr))
paymnt.memo = "Paid using Electrum"
paymnt.memo = "Paid using Electrum-Zcash"
pm = paymnt.SerializeToString()
payurl = urllib.parse.urlparse(pay_det.payment_url)
try:

View File

@ -35,7 +35,7 @@ def plot_history(wallet, history):
plt.subplots_adjust(bottom=0.2)
plt.xticks( rotation=25 )
ax = plt.gca()
plt.ylabel('BTC')
plt.ylabel('ZEC')
plt.xlabel('Month')
xfmt = md.DateFormatter('%Y-%m-%d')
ax.xaxis.set_major_formatter(xfmt)

View File

@ -48,9 +48,9 @@ class Plugins(DaemonThread):
DaemonThread.__init__(self)
if is_local:
find = imp.find_module('plugins')
plugins = imp.load_module('electrum_plugins', *find)
plugins = imp.load_module('electrum_zcash_plugins', *find)
else:
plugins = __import__('electrum_plugins')
plugins = __import__('electrum_zcash_plugins')
self.pkgpath = os.path.dirname(plugins.__file__)
self.config = config
self.hw_wallets = {}
@ -95,7 +95,7 @@ class Plugins(DaemonThread):
def load_plugin(self, name):
if name in self.plugins:
return self.plugins[name]
full_name = 'electrum_plugins.' + name + '.' + self.gui_name
full_name = 'electrum_zcash_plugins.' + name + '.' + self.gui_name
loader = pkgutil.find_loader(full_name)
if not loader:
raise RuntimeError("%s implementation for %s plugin not found"
@ -442,10 +442,10 @@ class DeviceMgr(ThreadJob, PrintError):
# The user input has wrong PIN or passphrase, or cancelled input,
# or it is not pairable
raise DeviceUnpairableError(
_('Electrum cannot pair with your %s.\n\n'
'Before you request bitcoins to be sent to addresses in this '
_('Electrum-Zcash cannot pair with your %s.\n\n'
'Before you request Zcash coins to be sent to addresses in this '
'wallet, ensure you can pair with your device, or that you have '
'its seed (and passphrase, if any). Otherwise all bitcoins you '
'its seed (and passphrase, if any). Otherwise all coins you '
'receive will be unspendable.') % plugin.device)
def unpaired_device_infos(self, handler, plugin, devices=None):

View File

@ -1,228 +1,5 @@
{
"E-X.not.fyi": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"ELECTRUMX.not.fyi": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"ELEX01.blackpole.online": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"VPS.hsmiths.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"bitcoin.freedomnode.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"btc.smsys.me": {
"pruning": "-",
"s": "995",
"version": "1.1"
},
"currentlane.lovebitco.in": {
"pruning": "-",
"t": "50001",
"version": "1.1"
},
"daedalus.bauerj.eu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"de01.hamster.science": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"ecdsa.net": {
"pruning": "-",
"s": "110",
"t": "50001",
"version": "1.1"
},
"elec.luggs.co": {
"pruning": "-",
"s": "443",
"version": "1.1"
},
"electrum.akinbo.org": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.antumbra.se": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.be": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.coinucopia.io": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.cutie.ga": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.festivaldelhumor.org": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.hsmiths.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.qtornado.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum.vom-stausee.de": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrum3.hachre.de": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrumx.bot.nu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"electrumx.westeurope.cloudapp.azure.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"elx01.knas.systems": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"ex-btc.server-on.net": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"helicarrier.bauerj.eu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"mooo.not.fyi": {
"pruning": "-",
"s": "50012",
"t": "50011",
"version": "1.1"
},
"ndnd.selfhost.eu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"node.arihanc.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"node.xbt.eu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"node1.volatilevictory.com": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"noserver4u.de": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"qmebr.spdns.org": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"raspi.hsmiths.com": {
"pruning": "-",
"s": "51002",
"t": "51001",
"version": "1.1"
},
"s2.noip.pl": {
"pruning": "-",
"s": "50102",
"version": "1.1"
},
"s5.noip.pl": {
"pruning": "-",
"s": "50105",
"version": "1.1"
},
"songbird.bauerj.eu": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"us.electrum.be": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
},
"us01.hamster.science": {
"localhost": {
"pruning": "-",
"s": "50002",
"t": "50001",

View File

@ -1,8 +1,8 @@
{
"testnetnode.arihanc.com": {"t":"51001", "s":"51002"},
"testnet1.bauerj.eu": {"t":"51001", "s":"51002"},
"14.3.140.101": {"t":"51001", "s":"51002"},
"testnet.hsmiths.com": {"t":"53011", "s":"53012"},
"electrum.akinbo.org": {"t":"51001", "s":"51002"},
"ELEX05.blackpole.online": {"t":"52011", "s":"52002"}
"localhost": {
"pruning": "-",
"s": "50002",
"t": "50001",
"version": "1.1"
}
}

View File

@ -9,7 +9,7 @@ from .util import user_dir, print_error, print_stderr, PrintError
from .bitcoin import MAX_FEE_RATE, FEE_TARGETS
SYSTEM_CONFIG_PATH = "/etc/electrum.conf"
SYSTEM_CONFIG_PATH = "/etc/electrum-zcash.conf"
config = None
@ -92,10 +92,10 @@ class SimpleConfig(PrintError):
if not os.path.exists(path):
if os.path.islink(path):
raise BaseException('Dangling link: ' + path)
os.mkdir(path)
os.makedirs(path)
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
self.print_error("electrum directory", path)
self.print_error("electrum-zcash directory", path)
return path
def fixup_config_keys(self, config, keypairs):
@ -278,7 +278,7 @@ class SimpleConfig(PrintError):
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-zcash.conf."""
result = {}
if os.path.exists(path):
import configparser
@ -293,7 +293,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-zcash.conf into user_config[]."""
if not path:
return {}
config_path = os.path.join(path, "config")

View File

@ -327,7 +327,7 @@ class WalletStorage(PrintError):
self.put('wallet_type', 'standard')
self.put('keystore', d)
elif (wallet_type == '2fa') or multisig_type(wallet_type):
elif multisig_type(wallet_type):
for key in xpubs.keys():
d = {
'type': 'bip32',

View File

@ -809,7 +809,7 @@ class Transaction:
secexp = pkey.secret
private_key = bitcoin.MySigningKey.from_secret_exponent(secexp, curve = SECP256k1)
public_key = private_key.get_verifying_key()
sig = private_key.sign_digest_deterministic(pre_hash, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der)
sig = private_key.sign_digest_deterministic(pre_hash, hashfunc=hashlib.sha256, sigencode = ecdsa.util.sigencode_der_canonize)
assert public_key.verify_digest(sig, pre_hash, sigdecode = ecdsa.util.sigdecode_der)
txin['signatures'][j] = bh2u(sig) + '01'
#txin['x_pubkeys'][j] = pubkey

View File

@ -40,7 +40,7 @@ def inv_dict(d):
return {v: k for k, v in d.items()}
base_units = {'BTC':8, 'mBTC':5, 'uBTC':2}
base_units = {'ZEC':8, 'mZEC':5, 'uZEC':2}
fee_levels = [_('Within 25 blocks'), _('Within 10 blocks'), _('Within 5 blocks'), _('Within 2 blocks'), _('In the next block')]
def normalize_version(v):
@ -216,6 +216,14 @@ def profiler(func):
return lambda *args, **kw_args: do_profile(func, args, kw_args)
def android_headers_file_name():
from bitcoin import TESTNET
s = 'blockchain_headers'
if TESTNET:
s += '_testnet'
return s
def android_ext_dir():
import jnius
env = jnius.autoclass('android.os.Environment')
@ -227,7 +235,7 @@ def android_data_dir():
return PythonActivity.mActivity.getFilesDir().getPath() + '/data'
def android_headers_dir():
d = android_ext_dir() + '/org.electrum.electrum'
d = android_ext_dir() + '/org.electrum-zcash.electrum-zcash'
if not os.path.exists(d):
os.mkdir(d)
return d
@ -236,11 +244,11 @@ def android_check_data_dir():
""" if needed, move old directory to sandbox """
ext_dir = android_ext_dir()
data_dir = android_data_dir()
old_electrum_dir = ext_dir + '/electrum'
old_electrum_dir = ext_dir + '/electrum-zcash'
if not os.path.exists(data_dir) and os.path.exists(old_electrum_dir):
import shutil
new_headers_path = android_headers_dir() + '/blockchain_headers'
old_headers_path = old_electrum_dir + '/blockchain_headers'
new_headers_path = android_headers_dir() + android_headers_file_name()
old_headers_path = old_electrum_dir + android_headers_file_name()
if not os.path.exists(new_headers_path) and os.path.exists(old_headers_path):
print_error("Moving headers file to", new_headers_path)
shutil.move(old_headers_path, new_headers_path)
@ -317,11 +325,11 @@ def user_dir():
if 'ANDROID_DATA' in os.environ:
return android_check_data_dir()
elif os.name == 'posix':
return os.path.join(os.environ["HOME"], ".electrum")
return os.path.join(os.environ["HOME"], ".electrum-zcash")
elif "APPDATA" in os.environ:
return os.path.join(os.environ["APPDATA"], "Electrum")
return os.path.join(os.environ["APPDATA"], "Electrum-Zcash")
elif "LOCALAPPDATA" in os.environ:
return os.path.join(os.environ["LOCALAPPDATA"], "Electrum")
return os.path.join(os.environ["LOCALAPPDATA"], "Electrum-Zcash")
else:
#raise Exception("No home directory found in environment variables.")
return
@ -421,36 +429,14 @@ def time_difference(distance_in_time, include_seconds):
return "over %d years" % (round(distance_in_minutes / 525600))
mainnet_block_explorers = {
'Biteasy.com': ('https://www.biteasy.com/blockchain',
'blockexplorer.com': ('https://zcash.blockexplorer.com/blocks',
{'tx': 'transactions', 'addr': 'addresses'}),
'Bitflyer.jp': ('https://chainflyer.bitflyer.jp',
{'tx': 'Transaction', 'addr': 'Address'}),
'Blockchain.info': ('https://blockchain.info',
{'tx': 'tx', 'addr': 'address'}),
'blockchainbdgpzk.onion': ('https://blockchainbdgpzk.onion',
{'tx': 'tx', 'addr': 'address'}),
'Blockr.io': ('https://btc.blockr.io',
{'tx': 'tx/info', 'addr': 'address/info'}),
'Blocktrail.com': ('https://www.blocktrail.com/BTC',
{'tx': 'tx', 'addr': 'address'}),
'BTC.com': ('https://chain.btc.com',
{'tx': 'tx', 'addr': 'address'}),
'Chain.so': ('https://www.chain.so',
{'tx': 'tx/BTC', 'addr': 'address/BTC'}),
'Insight.is': ('https://insight.bitpay.com',
{'tx': 'tx', 'addr': 'address'}),
'TradeBlock.com': ('https://tradeblock.com/blockchain',
{'tx': 'tx', 'addr': 'address'}),
'BlockCypher.com': ('https://live.blockcypher.com/btc',
{'tx': 'tx', 'addr': 'address'}),
'Blockchair.com': ('https://blockchair.com/bitcoin',
{'tx': 'transaction', 'addr': 'address'}),
'system default': ('blockchain:',
{'tx': 'tx', 'addr': 'address'}),
}
testnet_block_explorers = {
'Blocktrail.com': ('https://www.blocktrail.com/tBTC',
'testnet.z.cash': ('https://explorer.testnet.z.cash/',
{'tx': 'tx', 'addr': 'address'}),
'system default': ('blockchain:',
{'tx': 'tx', 'addr': 'address'}),
@ -461,7 +447,7 @@ def block_explorer_info():
return testnet_block_explorers if bitcoin.NetworkConstants.TESTNET else mainnet_block_explorers
def block_explorer(config):
return config.get('block_explorer', 'Blocktrail.com')
return config.get('block_explorer', 'blockexplorer.com')
def block_explorer_tuple(config):
return block_explorer_info().get(block_explorer(config))
@ -486,12 +472,12 @@ def parse_URI(uri, on_pr=None):
if ':' not in uri:
if not bitcoin.is_address(uri):
raise BaseException("Not a bitcoin address")
raise BaseException("Not a Zcash address")
return {'address': uri}
u = urllib.parse.urlparse(uri)
if u.scheme != 'bitcoin':
raise BaseException("Not a bitcoin URI")
if u.scheme != 'zcash':
raise BaseException("Not a Zcash URI")
address = u.path
# python for android fails to parse query
@ -508,7 +494,7 @@ def parse_URI(uri, on_pr=None):
out = {k: v[0] for k, v in pq.items()}
if address:
if not bitcoin.is_address(address):
raise BaseException("Invalid bitcoin address:" + address)
raise BaseException("Invalid Zcash address:" + address)
out['address'] = address
if 'amount' in out:
am = out['amount']
@ -558,7 +544,7 @@ def create_URI(addr, amount, message):
query.append('amount=%s'%format_satoshis_plain(amount))
if message:
query.append('message=%s'%urllib.parse.quote(message))
p = urllib.parse.ParseResult(scheme='bitcoin', netloc='', path=addr, params='', query='&'.join(query), fragment='')
p = urllib.parse.ParseResult(scheme='zcash', netloc='', path=addr, params='', query='&'.join(query), fragment='')
return urllib.parse.urlunparse(p)

View File

@ -3,11 +3,8 @@ PROTOCOL_VERSION = '1.1' # protocol version requested
# The hash of the mnemonic seed must begin with this
SEED_PREFIX = '01' # Standard wallet
SEED_PREFIX_2FA = '101' # Two-factor authentication
def seed_prefix(seed_type):
if seed_type == 'standard':
return SEED_PREFIX
elif seed_type == '2fa':
return SEED_PREFIX_2FA

View File

@ -69,8 +69,8 @@ TX_STATUS = [
def relayfee(network):
RELAY_FEE = 5000
MAX_RELAY_FEE = 50000
RELAY_FEE = 1000
MAX_RELAY_FEE = 10000
f = network.relay_fee if network and network.relay_fee else RELAY_FEE
return min(f, MAX_RELAY_FEE)
@ -868,7 +868,7 @@ class Abstract_Wallet(PrintError):
_type, data, value = o
if _type == TYPE_ADDRESS:
if not is_address(data):
raise BaseException("Invalid bitcoin address:" + data)
raise BaseException("Invalid Zcash address:" + data)
if value == '!':
if i_max is not None:
raise BaseException("More than one output set to spend max")
@ -1199,7 +1199,7 @@ class Abstract_Wallet(PrintError):
if not r:
return
out = copy.copy(r)
out['URI'] = 'bitcoin:' + addr + '?amount=' + format_satoshis(out.get('amount'))
out['URI'] = 'zcash:' + addr + '?amount=' + format_satoshis(out.get('amount'))
status, conf = self.get_request_status(addr)
out['status'] = status
if conf is not None:

View File

@ -32,9 +32,9 @@ if (id) {
.done( function(data) {
new QRCode(document.getElementById("qrcode"), data.URI);
$("<p />").text(data.memo).appendTo($("p#reason"));
$("<p />").text(data.amount/100000000 + "BTC").appendTo($("p#amount"));
$("<p />").text(data.amount/100000000 + "ZEC").appendTo($("p#amount"));
$("a").attr("href", data.URI);
$("<p />").text("Powered by Electrum").appendTo($("p#powered"));
$("<p />").text("Powered by Electrum-Zcash").appendTo($("p#powered"));
var websocket_server = data.websocket_server;
var websocket_port = data.websocket_port;
$(function () {
@ -84,10 +84,10 @@ if (id) {
};
// See http://stackoverflow.com/questions/29186154/chrome-clicking-mailto-links-closes-websocket-connection
$(document).on('click', 'a[href^="bitcoin:"]', function (e) {
$(document).on('click', 'a[href^="zcash:"]', function (e) {
e.preventDefault();
var btcWindow = window.open($(e.currentTarget).attr('href'));
btcWindow.close();
var zcashWindow = window.open($(e.currentTarget).attr('href'));
zcashWindow.close();
return false;
});
@ -99,7 +99,7 @@ $(document).on('click', 'a[href^="bitcoin:"]', function (e) {
<p id="reason"></p>
<p id="amount"></p>
<div style="background-color:#7777aa; border-radius: 5px; padding:10px;">
<a style="color:#ffffff; text-decoration:none;" id="paylink" target="_blank">Pay with Bitcoin</a>
<a style="color:#ffffff; text-decoration:none;" id="paylink" target="_blank">Pay with Zcash</a>
</div>
<br/>
<div id="qrcode" align="center"></div>