upgrade to type 2 wallet
This commit is contained in:
parent
deaa5745a4
commit
ca32d29a9c
|
@ -19,6 +19,7 @@
|
|||
|
||||
import sys, base64, os, re, hashlib, socket, getpass, copy, operator, ast
|
||||
from decimal import Decimal
|
||||
from ecdsa.util import string_to_number
|
||||
|
||||
try:
|
||||
import ecdsa
|
||||
|
@ -215,8 +216,7 @@ class InvalidPassword(Exception):
|
|||
|
||||
|
||||
|
||||
SEED_VERSION = 3 # bump this everytime the seed generation is modified
|
||||
from version import ELECTRUM_VERSION
|
||||
from version import ELECTRUM_VERSION, SEED_VERSION
|
||||
|
||||
|
||||
class Wallet:
|
||||
|
@ -230,13 +230,13 @@ class Wallet:
|
|||
self.port = 50000
|
||||
self.fee = 50000
|
||||
self.servers = ['ecdsa.org','electrum.novit.ro'] # list of default servers
|
||||
self.master_public_key = None
|
||||
|
||||
# saved fields
|
||||
self.use_encryption = False
|
||||
self.addresses = []
|
||||
self.addresses = [] # receiving addresses visible for user
|
||||
self.change_addresses = [] # addresses used as change
|
||||
self.seed = '' # encrypted
|
||||
self.private_keys = repr([]) # encrypted
|
||||
self.change_addresses = [] # index of addresses used as change
|
||||
self.status = {} # current status of addresses
|
||||
self.history = {}
|
||||
self.labels = {} # labels for addresses and transactions
|
||||
|
@ -262,25 +262,31 @@ class Wallet:
|
|||
elif "LOCALAPPDATA" in os.environ:
|
||||
wallet_dir = os.path.join( os.environ["LOCALAPPDATA"], 'Electrum' )
|
||||
elif "APPDATA" in os.environ:
|
||||
wallet_dir = os.path.join( os.environ["APPDATA"], 'Electrum' )
|
||||
wallet_dir = os.path.join( os.environ["APPDATA"], 'Electrum' )
|
||||
else:
|
||||
raise BaseException("No home directory found in environment variables.")
|
||||
|
||||
if not os.path.exists( wallet_dir ): os.mkdir( wallet_dir )
|
||||
self.path = os.path.join( wallet_dir, 'electrum.dat')
|
||||
self.path = os.path.join( wallet_dir, 'electrum.dat' )
|
||||
|
||||
def new_seed(self, password):
|
||||
seed = "%032x"%ecdsa.util.randrange( pow(2,128) )
|
||||
self.seed = wallet.pw_encode( seed, password)
|
||||
self.init_mpk(seed)
|
||||
# encrypt
|
||||
self.seed = wallet.pw_encode( seed, password )
|
||||
|
||||
def init_mpk(self,seed):
|
||||
# public key
|
||||
curve = SECP256k1
|
||||
secexp = self.stretch_key(seed)
|
||||
master_private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
|
||||
self.master_public_key = master_private_key.get_verifying_key().to_string()
|
||||
|
||||
def is_mine(self, address):
|
||||
return address in self.addresses
|
||||
return address in self.addresses or address in self.change_addresses
|
||||
|
||||
def is_change(self, address):
|
||||
if not self.is_mine(address):
|
||||
return False
|
||||
k = self.addresses.index(address)
|
||||
return k in self.change_addresses
|
||||
return address in self.change_addresses
|
||||
|
||||
def is_valid(self,addr):
|
||||
ADDRESS_RE = re.compile('[1-9A-HJ-NP-Za-km-z]{26,}\\Z')
|
||||
|
@ -288,43 +294,61 @@ class Wallet:
|
|||
h = bc_address_to_hash_160(addr)
|
||||
return addr == hash_160_to_bc_address(h)
|
||||
|
||||
def create_new_address(self, for_change, password):
|
||||
seed = self.pw_decode( self.seed, password)
|
||||
# strenghtening
|
||||
def stretch_key(self,seed):
|
||||
oldseed = seed
|
||||
for i in range(100000):
|
||||
seed = hashlib.sha512(seed + oldseed).digest()
|
||||
i = len( self.addresses ) - len(self.change_addresses) if not for_change else len(self.change_addresses)
|
||||
seed = Hash( "%d:%d:"%(i,for_change) + seed )
|
||||
seed = hashlib.sha256(seed + oldseed).digest()
|
||||
return string_to_number( seed )
|
||||
|
||||
def get_sequence(self,n,for_change):
|
||||
return string_to_number( Hash( "%d:%d:"%(n,for_change) + self.master_public_key ) )
|
||||
|
||||
def get_private_key2(self, address, password):
|
||||
""" Privatekey(type,n) = Master_private_key + H(n|S|type) """
|
||||
if address in self.addresses:
|
||||
n = self.addresses.index(address)
|
||||
for_change = False
|
||||
elif address in self.change_addresses:
|
||||
n = self.change_addresses.index(address)
|
||||
for_change = True
|
||||
else:
|
||||
raise BaseException("unknown address")
|
||||
|
||||
seed = self.pw_decode( self.seed, password)
|
||||
secexp = self.stretch_key(seed)
|
||||
order = generator_secp256k1.order()
|
||||
secexp = ecdsa.util.randrange_from_seed__trytryagain( seed, order )
|
||||
secret = SecretToASecret( ('%064x' % secexp).decode('hex') )
|
||||
private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 )
|
||||
public_key = private_key.get_verifying_key()
|
||||
address = public_key_to_bc_address( '04'.decode('hex') + public_key.to_string() )
|
||||
try:
|
||||
private_keys = ast.literal_eval( self.pw_decode( self.private_keys, password) )
|
||||
private_keys.append(secret)
|
||||
except:
|
||||
raise InvalidPassword("")
|
||||
self.private_keys = self.pw_encode( repr(private_keys), password)
|
||||
self.addresses.append(address)
|
||||
if for_change: self.change_addresses.append( len(self.addresses) - 1 )
|
||||
self.history[address] = []
|
||||
self.status[address] = None
|
||||
privkey_number = ( secexp + self.get_sequence(n,for_change) ) % order
|
||||
private_key = ecdsa.SigningKey.from_secret_exponent( privkey_number, curve = SECP256k1 )
|
||||
# sanity check
|
||||
#public_key = private_key.get_verifying_key()
|
||||
#assert address == public_key_to_bc_address( '04'.decode('hex') + public_key.to_string() )
|
||||
return private_key
|
||||
|
||||
|
||||
def create_new_address2(self, for_change):
|
||||
""" Publickey(type,n) = Master_public_key + H(n|S|type)*point """
|
||||
curve = SECP256k1
|
||||
n = len(self.change_addresses) if for_change else len(self.addresses)
|
||||
z = self.get_sequence(n,for_change)
|
||||
master_public_key = ecdsa.VerifyingKey.from_string( self.master_public_key, curve = SECP256k1 )
|
||||
pubkey_point = master_public_key.pubkey.point + z*curve.generator
|
||||
public_key2 = ecdsa.VerifyingKey.from_public_point( pubkey_point, curve = SECP256k1 )
|
||||
address = public_key_to_bc_address( '04'.decode('hex') + public_key2.to_string() )
|
||||
if for_change:
|
||||
self.change_addresses.append(address)
|
||||
else:
|
||||
self.addresses.append(address)
|
||||
self.save()
|
||||
return address
|
||||
|
||||
|
||||
def recover(self, password):
|
||||
seed = self.pw_decode( self.seed, password)
|
||||
|
||||
def recover(self):
|
||||
# todo: recover receiving addresses from tx
|
||||
is_found = False
|
||||
while True:
|
||||
addr = self.create_new_address(True, password)
|
||||
addr = self.create_new_address2(True)
|
||||
self.history[addr] = h = self.retrieve_history(addr)
|
||||
self.status[addr] = h[-1]['blk_hash'] if h else None
|
||||
#print "recovering", addr
|
||||
print "recovering", addr
|
||||
if self.status[addr] is not None:
|
||||
is_found = True
|
||||
else:
|
||||
|
@ -332,10 +356,10 @@ class Wallet:
|
|||
|
||||
num_gap = 0
|
||||
while True:
|
||||
addr = self.create_new_address(False, password)
|
||||
addr = self.create_new_address2(False)
|
||||
self.history[addr] = h = self.retrieve_history(addr)
|
||||
self.status[addr] = h[-1]['blk_hash'] if h else None
|
||||
#print "recovering", addr
|
||||
print "recovering", addr
|
||||
if self.status[addr] is None:
|
||||
num_gap += 1
|
||||
if num_gap == self.gap_limit: break
|
||||
|
@ -345,12 +369,9 @@ class Wallet:
|
|||
|
||||
if not is_found: return False
|
||||
|
||||
# remove limit-1 addresses. [ this is ok, because change addresses are at the beginning of the list]
|
||||
# remove limit-1 addresses.
|
||||
n = self.gap_limit
|
||||
self.addresses = self.addresses[:-n]
|
||||
private_keys = ast.literal_eval( self.pw_decode( self.private_keys, password))
|
||||
private_keys = private_keys[:-n]
|
||||
self.private_keys = self.pw_encode( repr(private_keys), password)
|
||||
|
||||
# history and addressbook
|
||||
self.update_tx_history()
|
||||
|
@ -364,12 +385,24 @@ class Wallet:
|
|||
return True
|
||||
|
||||
def save(self):
|
||||
s = repr( (self.seed_version, self.use_encryption, self.fee, self.host, self.port, self.blocks,
|
||||
self.seed, self.addresses, self.private_keys,
|
||||
self.change_addresses, self.status, self.history,
|
||||
self.labels, self.addressbook) )
|
||||
s = {
|
||||
'seed_version':self.seed_version,
|
||||
'use_encryption':self.use_encryption,
|
||||
'master_public_key': self.master_public_key,
|
||||
'fee':self.fee,
|
||||
'host':self.host,
|
||||
'port':self.port,
|
||||
'blocks':self.blocks,
|
||||
'seed':self.seed,
|
||||
'addresses':self.addresses,
|
||||
'change_addresses':self.change_addresses,
|
||||
'status':self.status,
|
||||
'history':self.history,
|
||||
'labels':self.labels,
|
||||
'contacts':self.addressbook
|
||||
}
|
||||
f = open(self.path,"w")
|
||||
f.write(s)
|
||||
f.write( repr(s) )
|
||||
f.close()
|
||||
|
||||
def read(self):
|
||||
|
@ -380,32 +413,41 @@ class Wallet:
|
|||
except:
|
||||
return False
|
||||
try:
|
||||
sequence = ast.literal_eval( data )
|
||||
(self.seed_version, self.use_encryption, self.fee, self.host, self.port, self.blocks,
|
||||
self.seed, self.addresses, self.private_keys,
|
||||
self.change_addresses, self.status, self.history,
|
||||
self.labels, self.addressbook) = sequence
|
||||
self.fee = int(self.fee)
|
||||
d = ast.literal_eval( data )
|
||||
self.seed_version = d.get('seed_version')
|
||||
self.master_public_key = d.get('master_public_key')
|
||||
self.use_encryption = d.get('use_encryption')
|
||||
self.fee = int( d.get('fee') )
|
||||
self.host = d.get('host')
|
||||
self.port = d.get('port')
|
||||
self.blocks = d.get('blocks')
|
||||
self.seed = d.get('seed')
|
||||
self.addresses = d.get('addresses')
|
||||
self.change_addresses = d.get('change_addresses')
|
||||
self.status = d.get('status')
|
||||
self.history = d.get('history')
|
||||
self.labels = d.get('labels')
|
||||
self.addressbook = d.get('contacts')
|
||||
except:
|
||||
# it is safer to exit immediately
|
||||
print "Error; could not parse wallet."
|
||||
exit(1)
|
||||
raise BaseException("Error; could not parse wallet. If this is an old wallet format, please use upgrade.py.",0)
|
||||
if self.seed_version != SEED_VERSION:
|
||||
raise BaseException("Seed version mismatch.\nPlease move your balance to a new wallet.\nSee the release notes for more information.")
|
||||
raise BaseException("""Seed version mismatch: your wallet seed is deprecated.
|
||||
Please create a new wallet, and send your coins to the new wallet.
|
||||
We apologize for the inconvenience. We try to keep this kind of upgrades as rare as possible.
|
||||
See the release notes for more information.""",1)
|
||||
|
||||
|
||||
self.update_tx_history()
|
||||
return True
|
||||
|
||||
def get_new_address(self, password):
|
||||
def get_new_address(self):
|
||||
n = 0
|
||||
for addr in self.addresses[-self.gap_limit:]:
|
||||
if self.history[addr] == []:
|
||||
if not self.history.get(addr):
|
||||
n = n + 1
|
||||
if n < self.gap_limit:
|
||||
try:
|
||||
new_address = self.create_new_address(False, password)
|
||||
except InvalidPassword:
|
||||
return False, "wrong password"
|
||||
self.save()
|
||||
new_address = self.create_new_address2(False)
|
||||
self.history[new_address] = [] #get from server
|
||||
return True, new_address
|
||||
else:
|
||||
return False, "The last %d addresses in your list have never been used. You should use them first, or increase the allowed gap size in your preferences. "%self.gap_limit
|
||||
|
@ -516,19 +558,17 @@ class Wallet:
|
|||
inputs = []
|
||||
return inputs, total, fee
|
||||
|
||||
def choose_tx_outputs( self, to_addr, amount, fee, total, password ):
|
||||
def choose_tx_outputs( self, to_addr, amount, fee, total ):
|
||||
outputs = [ (to_addr, amount) ]
|
||||
change_amount = total - ( amount + fee )
|
||||
if change_amount != 0:
|
||||
# first look for unused change addresses
|
||||
for addr in self.addresses:
|
||||
i = self.addresses.index(addr)
|
||||
if i not in self.change_addresses: continue
|
||||
for addr in self.change_addresses:
|
||||
if self.history.get(addr): continue
|
||||
change_address = addr
|
||||
break
|
||||
else:
|
||||
change_address = self.create_new_address(True, password)
|
||||
change_address = self.create_new_address2(True)
|
||||
print "new change address", change_address
|
||||
outputs.append( (change_address, change_amount) )
|
||||
return outputs
|
||||
|
@ -537,7 +577,7 @@ class Wallet:
|
|||
s_inputs = []
|
||||
for i in range(len(inputs)):
|
||||
addr, v, p_hash, p_pos, p_scriptPubKey, _, _ = inputs[i]
|
||||
private_key = self.get_private_key(addr, password)
|
||||
private_key = self.get_private_key2(addr, password)
|
||||
public_key = private_key.get_verifying_key()
|
||||
pubkey = public_key.to_string()
|
||||
tx = filter( raw_tx( inputs, outputs, for_sig = i ) )
|
||||
|
@ -556,24 +596,15 @@ class Wallet:
|
|||
def pw_decode(self, s, password):
|
||||
if password:
|
||||
secret = Hash(password)
|
||||
return DecodeAES(secret, s)
|
||||
d = DecodeAES(secret, s)
|
||||
try:
|
||||
d.decode('hex')
|
||||
except:
|
||||
raise InvalidPassword()
|
||||
return d
|
||||
else:
|
||||
return s
|
||||
|
||||
def get_private_key( self, addr, password ):
|
||||
try:
|
||||
private_keys = ast.literal_eval( self.pw_decode( self.private_keys, password ) )
|
||||
except:
|
||||
raise InvalidPassword("")
|
||||
k = self.addresses.index(addr)
|
||||
secret = private_keys[k]
|
||||
b = ASecretToSecret(secret)
|
||||
secexp = int( b.encode('hex'), 16)
|
||||
private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve=SECP256k1 )
|
||||
public_key = private_key.get_verifying_key()
|
||||
assert addr == public_key_to_bc_address( chr(4) + public_key.to_string() )
|
||||
return private_key
|
||||
|
||||
def get_tx_history(self):
|
||||
lines = self.tx_history.values()
|
||||
lines = sorted(lines, key=operator.itemgetter("nTime"))
|
||||
|
@ -623,7 +654,7 @@ class Wallet:
|
|||
inputs, total, fee = wallet.choose_tx_inputs( amount, fee )
|
||||
if not inputs: return False, "Not enough funds %d %d"%(total, fee)
|
||||
try:
|
||||
outputs = wallet.choose_tx_outputs( to_address, amount, fee, total, password )
|
||||
outputs = wallet.choose_tx_outputs( to_address, amount, fee, total )
|
||||
s_inputs = wallet.sign_inputs( inputs, outputs, password )
|
||||
except InvalidPassword:
|
||||
return False, "Wrong password"
|
||||
|
@ -648,7 +679,7 @@ class Wallet:
|
|||
from optparse import OptionParser
|
||||
|
||||
if __name__ == '__main__':
|
||||
known_commands = ['help', 'validateaddress', 'balance', 'contacts', 'create', 'payto', 'sendtx', 'password', 'newaddress', 'addresses', 'history', 'label', 'gui', 'mktx','seed']
|
||||
known_commands = ['help', 'validateaddress', 'balance', 'contacts', 'create', 'payto', 'sendtx', 'password', 'newaddress', 'addresses', 'history', 'label', 'gui', 'mktx','seed','t2']
|
||||
|
||||
usage = "usage: %prog [options] command args\nCommands: "+ (', '.join(known_commands))
|
||||
|
||||
|
@ -713,7 +744,7 @@ if __name__ == '__main__':
|
|||
gap = raw_input("gap limit (default 5):")
|
||||
if gap: wallet.gap_limit = int(gap)
|
||||
print "recovering wallet..."
|
||||
r = wallet.recover(password)
|
||||
r = wallet.recover()
|
||||
if r:
|
||||
print "recovery successful"
|
||||
wallet.save()
|
||||
|
@ -724,7 +755,7 @@ if __name__ == '__main__':
|
|||
print "Your seed is", wallet.seed
|
||||
print "Please store it safely"
|
||||
# generate first key
|
||||
wallet.create_new_address(False, None)
|
||||
wallet.create_new_address2(False)
|
||||
|
||||
# check syntax
|
||||
if cmd in ['payto', 'mktx']:
|
||||
|
@ -738,13 +769,13 @@ if __name__ == '__main__':
|
|||
cmd = 'help'
|
||||
|
||||
# open session
|
||||
if cmd not in ['password', 'mktx', 'history', 'label','contacts','help','validateaddress']:
|
||||
if cmd not in ['password', 'mktx', 'history', 'label', 'contacts', 'help', 'validateaddress']:
|
||||
wallet.new_session()
|
||||
wallet.update()
|
||||
wallet.save()
|
||||
|
||||
# commands needing password
|
||||
if cmd in ['payto', 'password', 'newaddress','mktx','seed'] or ( cmd=='addresses' and options.show_keys):
|
||||
if cmd in ['payto', 'password', 'mktx', 'seed' ] or ( cmd=='addresses' and options.show_keys):
|
||||
password = getpass.getpass('Password:') if wallet.use_encryption else None
|
||||
|
||||
if cmd=='help':
|
||||
|
@ -790,6 +821,9 @@ if __name__ == '__main__':
|
|||
addr = args[1]
|
||||
print wallet.is_valid(addr)
|
||||
|
||||
elif cmd == 't2':
|
||||
wallet.create_t2_address(password)
|
||||
|
||||
elif cmd == 'balance':
|
||||
c, u = wallet.get_balance()
|
||||
if u:
|
||||
|
@ -861,19 +895,18 @@ if __name__ == '__main__':
|
|||
else:
|
||||
print h
|
||||
|
||||
elif cmd=='sendtx':
|
||||
elif cmd == 'sendtx':
|
||||
tx = args[1]
|
||||
r, h = wallet.sendtx( tx )
|
||||
print h
|
||||
|
||||
elif cmd == 'newaddress':
|
||||
s, a = wallet.get_new_address(password)
|
||||
s, a = wallet.get_new_address()
|
||||
print a
|
||||
|
||||
elif cmd == 'password':
|
||||
try:
|
||||
seed = wallet.pw_decode( wallet.seed, password)
|
||||
private_keys = ast.literal_eval( wallet.pw_decode( wallet.private_keys, password) )
|
||||
except:
|
||||
print "sorry"
|
||||
sys.exit(1)
|
||||
|
@ -881,7 +914,6 @@ if __name__ == '__main__':
|
|||
if new_password == getpass.getpass('Confirm new password:'):
|
||||
wallet.use_encryption = (new_password != '')
|
||||
wallet.seed = wallet.pw_encode( seed, new_password)
|
||||
wallet.private_keys = wallet.pw_encode( repr( private_keys ), new_password)
|
||||
wallet.save()
|
||||
else:
|
||||
print "error: mismatch"
|
||||
|
|
|
@ -64,7 +64,6 @@ def show_seed_dialog(wallet, password, parent):
|
|||
import mnemonic
|
||||
try:
|
||||
seed = wallet.pw_decode( wallet.seed, password)
|
||||
private_keys = ast.literal_eval( wallet.pw_decode( wallet.private_keys, password) )
|
||||
except:
|
||||
show_message("Incorrect password")
|
||||
return
|
||||
|
@ -85,8 +84,13 @@ def init_wallet(wallet):
|
|||
try:
|
||||
found = wallet.read()
|
||||
except BaseException, e:
|
||||
show_message(e.message)
|
||||
show_message(e.args[0])
|
||||
if e.args[1] == 0: exit(1)
|
||||
found = 1
|
||||
except:
|
||||
exit()
|
||||
|
||||
|
||||
|
||||
if not found:
|
||||
# ask if the user wants to create a new wallet, or recover from a seed.
|
||||
|
@ -114,7 +118,7 @@ def init_wallet(wallet):
|
|||
run_settings_dialog(wallet, is_create=True, is_recovery=False, parent=None)
|
||||
|
||||
# generate first key
|
||||
wallet.create_new_address(False, None)
|
||||
wallet.create_new_address2(False)
|
||||
|
||||
# run a dialog indicating the seed, ask the user to remember it
|
||||
show_seed_dialog(wallet, None, None)
|
||||
|
@ -133,13 +137,14 @@ def init_wallet(wallet):
|
|||
message_format = "Please wait..." )
|
||||
dialog.show()
|
||||
|
||||
def recover_thread( wallet, dialog, password ):
|
||||
wallet.is_found = wallet.recover( password )
|
||||
def recover_thread( wallet, dialog ):
|
||||
wallet.init_mpk( wallet.seed ) # not encrypted at this point
|
||||
wallet.is_found = wallet.recover()
|
||||
if wallet.is_found:
|
||||
wallet.save()
|
||||
gobject.idle_add( dialog.destroy )
|
||||
|
||||
thread.start_new_thread( recover_thread, ( wallet, dialog, None ) ) # no password
|
||||
thread.start_new_thread( recover_thread, ( wallet, dialog ) )
|
||||
r = dialog.run()
|
||||
dialog.destroy()
|
||||
if r==gtk.RESPONSE_CANCEL: sys.exit(1)
|
||||
|
@ -354,7 +359,6 @@ def change_password_dialog(wallet, parent, icon):
|
|||
|
||||
try:
|
||||
seed = wallet.pw_decode( wallet.seed, password)
|
||||
private_keys = ast.literal_eval( wallet.pw_decode( wallet.private_keys, password) )
|
||||
except:
|
||||
show_message("Incorrect password")
|
||||
return
|
||||
|
@ -365,7 +369,6 @@ def change_password_dialog(wallet, parent, icon):
|
|||
|
||||
wallet.use_encryption = (new_password != '')
|
||||
wallet.seed = wallet.pw_encode( seed, new_password)
|
||||
wallet.private_keys = wallet.pw_encode( repr( private_keys ), new_password)
|
||||
wallet.save()
|
||||
|
||||
if icon:
|
||||
|
@ -1020,8 +1023,7 @@ class BitcoinGUI:
|
|||
errorDialog.run()
|
||||
errorDialog.destroy()
|
||||
else:
|
||||
password = password_dialog() if self.wallet.use_encryption else None
|
||||
success, ret = self.wallet.get_new_address(password)
|
||||
success, ret = self.wallet.get_new_address()
|
||||
self.update_session = True # we created a new address
|
||||
if success:
|
||||
address = ret
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import electrum, getpass, base64,ast,sys
|
||||
import electrum, getpass, base64,ast,sys,os
|
||||
from version import SEED_VERSION
|
||||
|
||||
|
||||
|
||||
def upgrade_wallet(wallet):
|
||||
if wallet.version == 1 and wallet.use_encryption:
|
||||
print "walet path:",wallet.path
|
||||
print "seed version:", wallet.seed_version
|
||||
if wallet.seed_version == 1 and wallet.use_encryption:
|
||||
# version 1 used pycrypto for wallet encryption
|
||||
import Crypto
|
||||
from Crypto.Cipher import AES
|
||||
|
@ -27,21 +30,65 @@ def upgrade_wallet(wallet):
|
|||
wallet.private_keys = wallet.pw_encode( repr( private_keys ), password)
|
||||
wallet.save()
|
||||
print "upgraded to version 2"
|
||||
if wallet.version < 3:
|
||||
print """
|
||||
Your wallet is deprecated; its generation seed will not work with versions 0.31 and above.
|
||||
In order to upgrade, you need to create a new wallet (you may use your current seed), and
|
||||
to send your bitcoins to the new wallet.
|
||||
exit(1)
|
||||
|
||||
We apologize for the inconvenience. We try to keep this kind of upgrades as rare as possible.
|
||||
"""
|
||||
if wallet.seed_version < SEED_VERSION:
|
||||
print """Note: your wallet seed is deprecated. Please create a new wallet, and move your coins to the new wallet."""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
path = sys.argv[1]
|
||||
except:
|
||||
path = None
|
||||
# backward compatibility: look for wallet file in the default data directory
|
||||
if "HOME" in os.environ:
|
||||
wallet_dir = os.path.join( os.environ["HOME"], '.electrum')
|
||||
elif "LOCALAPPDATA" in os.environ:
|
||||
wallet_dir = os.path.join( os.environ["LOCALAPPDATA"], 'Electrum' )
|
||||
elif "APPDATA" in os.environ:
|
||||
wallet_dir = os.path.join( os.environ["APPDATA"], 'Electrum' )
|
||||
else:
|
||||
raise BaseException("No home directory found in environment variables.")
|
||||
path = os.path.join( wallet_dir, 'electrum.dat')
|
||||
|
||||
try:
|
||||
f = open(path,"r")
|
||||
data = f.read()
|
||||
f.close()
|
||||
except:
|
||||
print "file not found", path
|
||||
exit(1)
|
||||
|
||||
try:
|
||||
x = ast.literal_eval(data)
|
||||
except:
|
||||
print "error: could not parse wallet"
|
||||
exit(1)
|
||||
|
||||
if type(x) == tuple:
|
||||
seed_version, use_encryption, fee, host, port, blocks, seed, addresses, private_keys, change_addresses, status, history, labels, addressbook = x
|
||||
s = {
|
||||
'seed_version':seed_version,
|
||||
'use_encryption':use_encryption,
|
||||
'master_public_key':None,
|
||||
'fee':fee,
|
||||
'host':host,
|
||||
'port':port,
|
||||
'blocks':blocks,
|
||||
'seed':seed,
|
||||
'addresses':addresses,
|
||||
'change_addresses':change_addresses,
|
||||
'status':status,
|
||||
'history':history,
|
||||
'labels':labels,
|
||||
'contacts':addressbook
|
||||
}
|
||||
f = open(path,"w")
|
||||
f.write( repr(s) )
|
||||
f.close()
|
||||
print "wallet format was upgraded."
|
||||
exit(1)
|
||||
|
||||
wallet = electrum.Wallet(path)
|
||||
try:
|
||||
found = wallet.read()
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
ELECTRUM_VERSION = "0.33"
|
||||
ELECTRUM_VERSION = "0.34"
|
||||
SEED_VERSION = 4 # bump this everytime the seed generation is modified
|
||||
|
|
Loading…
Reference in New Issue