Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
romanornr committed Mar 14, 2018
2 parents cb57d87 + a49f72e commit 04d8d6c
Show file tree
Hide file tree
Showing 24 changed files with 126 additions and 69 deletions.
16 changes: 15 additions & 1 deletion RELEASE-NOTES
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@

# Release 3.1 - (March 5, 2018)
# Release 3.1.1 - (March 12, 2018)

* fix #4031: Trezor T support
* partial fix #4060: proxy and hardware wallet can't be used together
* fix #4039: can't set address labels
* fix crash related to coinbase transactions
* MacOS: use internal graphics card
* fix openalias related crashes
* speed-up capital gains calculations
* hw wallet encryption: re-prompt for passphrase if incorrect
* other minor fixes.



# Release 3.1.0 - (March 5, 2018)

* Memory-pool based fee estimation. Dynamic fees can target a desired
depth in the memory pool. This feature is optional, and ETA-based
Expand Down
7 changes: 7 additions & 0 deletions contrib/build-osx/make_osx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ fail "Could not install hardware wallet requirements"
info "Building $PACKAGE..."
python3 setup.py install --user > /dev/null || fail "Could not build $PACKAGE"

info "Faking timestamps..."
for d in ~/Library/Python/ ~/.pyenv .; do
pushd $d
find . -exec touch -t '200101220000' {} +
popd
done

info "Building binary"
pyinstaller --noconfirm --ascii --name $VERSION contrib/build-osx/osx.spec || fail "Could not build binary"

Expand Down
13 changes: 7 additions & 6 deletions contrib/make_locale
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ os.system(cmd)
os.chdir('lib')

crowdin_identifier = 'electrum'
crowdin_file_name = 'electrum-client/messages.pot'
crowdin_file_name = 'files[electrum-client/messages.pot]'
locale_file_name = 'locale/messages.pot'
crowdin_api_key = None

filename = '~/.crowdin_api_key'
filename = os.path.expanduser('~/.crowdin_api_key')
if os.path.exists(filename):
with open(filename) as f:
crowdin_api_key = f.read().strip()
Expand All @@ -44,13 +44,14 @@ if crowdin_api_key:
# Push to Crowdin
print('Push to Crowdin')
url = ('https://api.crowdin.com/api/project/' + crowdin_identifier + '/update-file?key=' + crowdin_api_key)
with open(locale_file_name,'rb') as f:
with open(locale_file_name, 'rb') as f:
files = {crowdin_file_name: f}
requests.request('POST', url, files=files)
response = requests.request('POST', url, files=files)
print("", "update-file:", "-"*20, response.text, "-"*20, sep="\n")
# Build translations
print('Build translations')
response = requests.request('GET', 'https://api.crowdin.com/api/project/' + crowdin_identifier + '/export?key=' + crowdin_api_key).content
print(response)
response = requests.request('GET', 'https://api.crowdin.com/api/project/' + crowdin_identifier + '/export?key=' + crowdin_api_key)
print("", "export:", "-" * 20, response.text, "-" * 20, sep="\n")

# Download & unzip
print('Download translations')
Expand Down
1 change: 0 additions & 1 deletion gui/kivy/uix/screens.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,6 @@ def save_request(self):
self.app.update_tab('requests')

def on_amount_or_message(self):
self.save_request()
Clock.schedule_once(lambda dt: self.update_qr())

def do_new(self):
Expand Down
5 changes: 2 additions & 3 deletions gui/qt/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,13 +409,12 @@ def backup_wallet(self):
filename, __ = QFileDialog.getSaveFileName(self, _('Enter a filename for the copy of your wallet'), wallet_folder)
if not filename:
return

new_path = os.path.join(wallet_folder, filename)
if new_path != path:
try:
shutil.copy2(path, new_path)
self.show_message(_("A copy of your wallet file was created in")+" '%s'" % str(new_path), title=_("Wallet backup created"))
except (IOError, os.error) as reason:
except BaseException as reason:
self.show_critical(_("Electrum was unable to copy your wallet file to the specified location.") + "\n" + str(reason), title=_("Unable to create backup"))

def update_recently_visited(self, filename):
Expand Down Expand Up @@ -1182,7 +1181,7 @@ def feerounding_onclick():
self.fee_adv_controls.setVisible(False)

self.preview_button = EnterButton(_("Preview"), self.do_preview)
self.preview_button.setToolTip(_('Display the details of your transactions before signing it.'))
self.preview_button.setToolTip(_('Display the details of your transaction before signing it.'))
self.send_button = EnterButton(_("Send"), self.do_send)
self.clear_button = EnterButton(_("Clear"), self.do_clear)
buttons = QHBoxLayout()
Expand Down
5 changes: 3 additions & 2 deletions gui/qt/transaction_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ def show_qr(self):

def sign(self):
def sign_done(success):
if success:
# note: with segwit we could save partially signed tx, because they have a txid
if self.tx.is_complete():
self.prompt_if_unsaved = True
self.saved = False
self.save_button.setDisabled(False)
Expand Down Expand Up @@ -289,7 +290,7 @@ def format_amount(amt):
cursor.insertText(prevout_hash[-8:] + ":%-4d " % prevout_n, ext)
addr = x.get('address')
if addr == "(pubkey)":
_addr = self.wallet.find_pay_to_pubkey_address(prevout_hash, prevout_n)
_addr = self.wallet.get_txin_address(x)
if _addr:
addr = _addr
if addr is None:
Expand Down
2 changes: 1 addition & 1 deletion lib/base_wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def on_import(self, text):
k = keystore.Imported_KeyStore({})
self.storage.put('keystore', k.dump())
w = Imported_Wallet(self.storage)
for x in text.split():
for x in keystore.get_private_keys(text):
w.import_private_key(x, None)
self.keystores.append(w.keystore)
else:
Expand Down
19 changes: 15 additions & 4 deletions lib/bitcoin.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ def rev_hex(s):

def int_to_hex(i, length=1):
assert isinstance(i, int)
if i < 0:
# two's complement
i = pow(256, length) + i
s = hex(i)[2:].rstrip('L')
s = "0"*(2*length - len(s)) + s
return rev_hex(s)
Expand Down Expand Up @@ -408,7 +411,10 @@ def base_decode(v, length, base):
chars = __b43chars
long_value = 0
for (i, c) in enumerate(v[::-1]):
long_value += chars.find(bytes([c])) * (base**i)
digit = chars.find(bytes([c]))
if digit == -1:
raise ValueError('Forbidden character {} for base {}'.format(c, base))
long_value += digit * (base**i)
result = bytearray()
while long_value >= 256:
div, mod = divmod(long_value, 256)
Expand All @@ -428,6 +434,10 @@ def base_decode(v, length, base):
return bytes(result)


class InvalidChecksum(Exception):
pass


def EncodeBase58Check(vchIn):
hash = Hash(vchIn)
return base_encode(vchIn + hash[0:4], base=58)
Expand All @@ -440,7 +450,7 @@ def DecodeBase58Check(psz):
hash = Hash(key)
cs32 = hash[0:4]
if cs32 != csum:
return None
raise InvalidChecksum('expected {}, actual {}'.format(bh2u(cs32), bh2u(csum)))
else:
return key

Expand Down Expand Up @@ -479,8 +489,9 @@ def deserialize_privkey(key):
if ':' in key:
txin_type, key = key.split(sep=':', maxsplit=1)
assert txin_type in SCRIPT_TYPES
vch = DecodeBase58Check(key)
if not vch:
try:
vch = DecodeBase58Check(key)
except BaseException:
neutered_privkey = str(key)[:3] + '..' + str(key)[-2:]
raise BaseException("cannot deserialize", neutered_privkey)

Expand Down
12 changes: 2 additions & 10 deletions lib/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,19 +159,13 @@ def setconfig(self, key, value):
return True

@command('')
def make_seed(self, nbits=132, entropy=1, language=None, segwit=False):
def make_seed(self, nbits=132, language=None, segwit=False):
"""Create a seed"""
from .mnemonic import Mnemonic
t = 'segwit' if segwit else 'standard'
s = Mnemonic(language).make_seed(t, nbits, custom_entropy=entropy)
s = Mnemonic(language).make_seed(t, nbits)
return s

@command('')
def check_seed(self, seed, entropy=1, language=None):
"""Check that a seed was generated with given entropy"""
from .mnemonic import Mnemonic
return Mnemonic(language).check_seed(seed, entropy)

@command('n')
def getaddresshistory(self, address):
"""Return the transaction history of any address. Note: This is a
Expand Down Expand Up @@ -697,7 +691,6 @@ def help(self):
'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"),
'entropy': (None, "Custom entropy"),
'segwit': (None, "Create segwit seed"),
'language': ("-L", "Default language for wordlist"),
'privkey': (None, "Private key. Set to '?' to get a prompt."),
Expand Down Expand Up @@ -726,7 +719,6 @@ def help(self):
'nbits': int,
'imax': int,
'year': int,
'entropy': int,
'tx': tx_from_str,
'pubkeys': json_loads,
'jsontx': json_loads,
Expand Down
2 changes: 2 additions & 0 deletions lib/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ def get_socket(self):
temporary_path = cert_path + '.temp'
with open(temporary_path,"w") as f:
f.write(cert)
f.flush()
os.fsync(f.fileno())
else:
is_new = False

Expand Down
23 changes: 8 additions & 15 deletions lib/mnemonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,28 +157,21 @@ def mnemonic_decode(self, seed):
i = i*n + k
return i

def check_seed(self, seed, custom_entropy):
assert is_new_seed(seed)
i = self.mnemonic_decode(seed)
return i % custom_entropy == 0

def make_seed(self, seed_type='standard', num_bits=132, custom_entropy=1):
def make_seed(self, seed_type='standard', num_bits=132):
prefix = version.seed_prefix(seed_type)
# increase num_bits in order to obtain a uniform distibution for the last word
bpw = math.log(len(self.wordlist), 2)
num_bits = int(math.ceil(num_bits/bpw) * bpw)
# handle custom entropy; make sure we add at least 16 bits
n_custom = int(math.ceil(math.log(custom_entropy, 2)))
n = max(16, num_bits - n_custom)
print_error("make_seed", prefix, "adding %d bits"%n)
my_entropy = 1
while my_entropy < pow(2, n - bpw):
# rounding
n = int(math.ceil(num_bits/bpw) * bpw)
print_error("make_seed. prefix: '%s'"%prefix, "entropy: %d bits"%n)
entropy = 1
while entropy < pow(2, n - bpw):
# try again if seed would not contain enough words
my_entropy = ecdsa.util.randrange(pow(2, n))
entropy = ecdsa.util.randrange(pow(2, n))
nonce = 0
while True:
nonce += 1
i = custom_entropy * (my_entropy + nonce)
i = entropy + nonce
seed = self.mnemonic_encode(i)
assert i == self.mnemonic_decode(seed)
if is_old_seed(seed):
Expand Down
4 changes: 3 additions & 1 deletion lib/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
def multisig_type(wallet_type):
'''If wallet_type is mofn multi-sig, return [m, n],
otherwise return None.'''
if not wallet_type:
return None
match = re.match('(\d+)of(\d+)', wallet_type)
if match:
match = [int(x) for x in match.group(1, 2)]
Expand Down Expand Up @@ -417,7 +419,7 @@ def convert_wallet_type(self):
d['seed'] = seed
self.put(key, d)
else:
raise
raise Exception('Unable to tell wallet type. Is this even a wallet file?')
# remove junk
self.put('master_public_key', None)
self.put('master_public_keys', None)
Expand Down
5 changes: 5 additions & 0 deletions lib/tests/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,11 @@ def test_txid_regression_issue_3899(self):
txid = 'f570d5d1e965ee61bcc7005f8fefb1d3abbed9d7ddbe035e2a68fa07e5fc4a0d'
self._run_naive_tests_on_tx(raw_tx, txid)

def test_txid_negative_version_num(self):
raw_tx = 'f0b47b9a01ecf5e5c3bbf2cf1f71ecdc7f708b0b222432e914b394e24aad1494a42990ddfc000000008b483045022100852744642305a99ad74354e9495bf43a1f96ded470c256cd32e129290f1fa191022030c11d294af6a61b3da6ed2c0c296251d21d113cfd71ec11126517034b0dcb70014104a0fe6e4a600f859a0932f701d3af8e0ecd4be886d91045f06a5a6b931b95873aea1df61da281ba29cadb560dad4fc047cf47b4f7f2570da4c0b810b3dfa7e500ffffffff0240420f00000000001976a9147eeacb8a9265cd68c92806611f704fc55a21e1f588ac05f00d00000000001976a914eb3bd8ccd3ba6f1570f844b59ba3e0a667024a6a88acff7f0000'
txid = 'c659729a7fea5071361c2c1a68551ca2bf77679b27086cc415adeeb03852e369'
self._run_naive_tests_on_tx(raw_tx, txid)


# these transactions are from Bitcoin Core unit tests --->
# https://github.com/bitcoin/bitcoin/blob/11376b5583a283772c82f6d32d0007cdbf5b8ef0/src/test/data/tx_valid.json
Expand Down
22 changes: 13 additions & 9 deletions lib/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ def remove_transaction(self, tx_hash):
# undo spent_outpoints that are in pruned_txo
for ser, hh in list(self.pruned_txo.items()):
if hh == tx_hash:
self.spent_outpoints.pop(ser)
self.spent_outpoints.pop(ser, None)
self.pruned_txo.pop(ser)

# add tx to pruned_txo, and undo the txi addition
Expand Down Expand Up @@ -1628,13 +1628,14 @@ def remove_payment_request(self, addr, config):
return True

def get_sorted_requests(self, config):
def f(x):
def f(addr):
try:
addr = x.get('address')
return self.get_address_index(addr) or addr
return self.get_address_index(addr)
except:
return addr
return sorted(map(lambda x: self.get_payment_request(x, config), self.receive_requests.keys()), key=f)
return
keys = map(lambda x: (f(x), x), self.receive_requests.keys())
sorted_keys = sorted(filter(lambda x: x[0] is not None, keys))
return [self.get_payment_request(x[1], config) for x in sorted_keys]

def get_fingerprint(self):
raise NotImplementedError()
Expand Down Expand Up @@ -1737,11 +1738,12 @@ def get_depending_transactions(self, tx_hash):
def txin_value(self, txin):
txid = txin['prevout_hash']
prev_n = txin['prevout_n']
for address, d in self.txo[txid].items():
for address, d in self.txo.get(txid, {}).items():
for n, v, cb in d:
if n == prev_n:
return v
raise BaseException('unknown txin value')
# may occur if wallet is not synchronized
return None

def price_at_timestamp(self, txid, price_func):
height, conf, timestamp = self.get_tx_height(txid)
Expand Down Expand Up @@ -1770,6 +1772,8 @@ def coin_price(self, txid, price_func, ccy, txin_value):
Acquisition price of a coin.
This assumes that either all inputs are mine, or no input is mine.
"""
if txin_value is None:
return Decimal('NaN')
cache_key = "{}:{}:{}".format(str(txid), str(ccy), str(txin_value))
result = self.coin_price_cache.get(cache_key, None)
if result is not None:
Expand Down Expand Up @@ -2301,5 +2305,5 @@ def wallet_class(wallet_type):
return Multisig_Wallet
if wallet_type in wallet_constructors:
return wallet_constructors[wallet_type]
raise RuntimeError("Unknown wallet type: " + wallet_type)
raise RuntimeError("Unknown wallet type: " + str(wallet_type))

3 changes: 2 additions & 1 deletion plugins/cosigner_pool/qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,8 @@ def do_send(self, tx):
for window, xpub, K, _hash in self.cosigner_list:
if not self.cosigner_can_sign(tx, xpub):
continue
message = bitcoin.encrypt_message(bfh(tx.raw), bh2u(K)).decode('ascii')
raw_tx_bytes = bfh(str(tx))
message = bitcoin.encrypt_message(raw_tx_bytes, bh2u(K)).decode('ascii')
try:
server.put(_hash, message)
except Exception as e:
Expand Down
4 changes: 2 additions & 2 deletions plugins/digitalbitbox/digitalbitbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,12 @@ def check_device_dialog(self):
self.password = None
if reply['error']['code'] == 109:
msg = _("Incorrect password entered.") + "\n\n" + \
+ reply['error']['message'] + "\n\n" + \
reply['error']['message'] + "\n\n" + \
_("Enter your Digital Bitbox password:")
else:
# Should never occur
msg = _("Unexpected error occurred.") + "\n\n" + \
+ reply['error']['message'] + "\n\n" + \
reply['error']['message'] + "\n\n" + \
_("Enter your Digital Bitbox password:")

# Initialize device if not yet initialized
Expand Down
3 changes: 3 additions & 0 deletions plugins/hw_wallet/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ def stop(self):
def show_message(self, msg, on_cancel=None):
print_msg(msg)

def show_error(self, msg):
print_msg(msg)

def update_status(self, b):
print_error('trezor status', b)

Expand Down
Loading

0 comments on commit 04d8d6c

Please sign in to comment.