Browse Source

trustedcoin: p2wpkh billing addresses

3.3.3.1
SomberNight 6 years ago
committed by ThomasV
parent
commit
7b90d69443
  1. 12
      electrum/plugins/trustedcoin/qt.py
  2. 62
      electrum/plugins/trustedcoin/trustedcoin.py
  3. 12
      electrum/storage.py

12
electrum/plugins/trustedcoin/qt.py

@ -195,18 +195,6 @@ class Plugin(TrustedCoinPlugin):
vbox.addLayout(Buttons(CloseButton(d)))
d.exec_()
def on_buy(self, window, k, v, d):
d.close()
if window.pluginsdialog:
window.pluginsdialog.close()
wallet = window.wallet
uri = "bitcoin:" + wallet.billing_info['billing_address'] + "?message=TrustedCoin %d Prepaid Transactions&amount="%k + str(Decimal(v)/100000000)
wallet.is_billing = True
window.pay_to_URI(uri)
window.payto_e.setFrozen(True)
window.message_e.setFrozen(True)
window.amount_e.setFrozen(True)
def go_online_dialog(self, wizard):
msg = [
_("Your wallet file is: {}.").format(os.path.abspath(wizard.storage.path)),

62
electrum/plugins/trustedcoin/trustedcoin.py

@ -28,13 +28,15 @@ import json
import base64
import time
import hashlib
from collections import defaultdict
from typing import Dict
from urllib.parse import urljoin
from urllib.parse import quote
from aiohttp import ClientResponse
from electrum import ecc, constants, keystore, version, bip32
from electrum.bitcoin import TYPE_ADDRESS, is_new_seed, public_key_to_p2pkh, seed_type, is_any_2fa_seed_type
from electrum import ecc, constants, keystore, version, bip32, bitcoin
from electrum.bitcoin import TYPE_ADDRESS, is_new_seed, seed_type, is_any_2fa_seed_type
from electrum.bip32 import (deserialize_xpub, deserialize_xprv, bip32_private_key, CKD_pub,
serialize_xpub, bip32_root, bip32_private_derivation, xpub_type)
from electrum.crypto import sha256
@ -244,14 +246,18 @@ class Wallet_2fa(Multisig_Wallet):
self.is_billing = False
self.billing_info = None
self._load_billing_addresses()
self.plugin = None # type: TrustedCoinPlugin
def _load_billing_addresses(self):
billing_addresses = self.storage.get('trustedcoin_billing_addresses', {})
self._billing_addresses = {} # index -> addr
# convert keys from str to int
for index, addr in list(billing_addresses.items()):
self._billing_addresses[int(index)] = addr
self._billing_addresses_set = set(self._billing_addresses.values()) # set of addrs
self._billing_addresses = defaultdict(dict) # type: Dict[str, Dict[int, str]] # addr_type -> index -> addr
self._billing_addresses_set = set() # set of addrs
for addr_type, d in list(billing_addresses.items()):
self._billing_addresses[addr_type] = {}
# convert keys from str to int
for index, addr in d.items():
self._billing_addresses[addr_type][int(index)] = addr
self._billing_addresses_set.add(addr)
def can_sign_without_server(self):
return not self.keystores['x2/'].is_watching_only()
@ -291,7 +297,7 @@ class Wallet_2fa(Multisig_Wallet):
self, coins, o, config, fixed_fee, change_addr)
fee = self.extra_fee(config) if not is_sweep else 0
if fee:
address = self.billing_info['billing_address']
address = self.billing_info['billing_address_segwit']
fee_output = TxOutput(TYPE_ADDRESS, address, fee)
try:
tx = mk_tx(outputs + [fee_output])
@ -322,8 +328,9 @@ class Wallet_2fa(Multisig_Wallet):
self.billing_info = None
self.plugin.start_request_thread(self)
def add_new_billing_address(self, billing_index: int, address: str):
saved_addr = self._billing_addresses.get(billing_index)
def add_new_billing_address(self, billing_index: int, address: str, addr_type: str):
billing_addresses_of_this_type = self._billing_addresses[addr_type]
saved_addr = billing_addresses_of_this_type.get(billing_index)
if saved_addr is not None:
if saved_addr == address:
return # already saved this address
@ -332,15 +339,16 @@ class Wallet_2fa(Multisig_Wallet):
'for index {}, already saved {}, now got {}'
.format(billing_index, saved_addr, address))
# do we have all prior indices? (are we synced?)
largest_index_we_have = max(self._billing_addresses) if self._billing_addresses else -1
largest_index_we_have = max(billing_addresses_of_this_type) if billing_addresses_of_this_type else -1
if largest_index_we_have + 1 < billing_index: # need to sync
for i in range(largest_index_we_have + 1, billing_index):
addr = make_billing_address(self, i)
self._billing_addresses[i] = addr
addr = make_billing_address(self, i, addr_type=addr_type)
billing_addresses_of_this_type[i] = addr
self._billing_addresses_set.add(addr)
# save this address; and persist to disk
self._billing_addresses[billing_index] = address
billing_addresses_of_this_type[billing_index] = address
self._billing_addresses_set.add(address)
self._billing_addresses[addr_type] = billing_addresses_of_this_type
self.storage.put('trustedcoin_billing_addresses', self._billing_addresses)
# FIXME this often runs in a daemon thread, where storage.write will fail
self.storage.write()
@ -365,12 +373,17 @@ def make_xpub(xpub, s):
cK2, c2 = bip32._CKD_pub(cK, c, s)
return serialize_xpub(version, c2, cK2)
def make_billing_address(wallet, num):
def make_billing_address(wallet, num, addr_type):
long_id, short_id = wallet.get_user_id()
xpub = make_xpub(get_billing_xpub(), long_id)
version, _, _, _, c, cK = deserialize_xpub(xpub)
cK, c = CKD_pub(cK, c, num)
return public_key_to_p2pkh(cK)
if addr_type == 'legacy':
return bitcoin.public_key_to_p2pkh(cK)
elif addr_type == 'segwit':
return bitcoin.public_key_to_p2wpkh(cK)
else:
raise ValueError(f'unexpected billing type: {addr_type}')
class TrustedCoinPlugin(BasePlugin):
@ -428,7 +441,7 @@ class TrustedCoinPlugin(BasePlugin):
return f
@finish_requesting
def request_billing_info(self, wallet):
def request_billing_info(self, wallet: 'Wallet_2fa'):
if wallet.can_sign_without_server():
return
self.print_error("request billing info")
@ -438,11 +451,16 @@ class TrustedCoinPlugin(BasePlugin):
self.print_error('cannot connect to TrustedCoin server: {}'.format(repr(e)))
return
billing_index = billing_info['billing_index']
billing_address = make_billing_address(wallet, billing_index)
if billing_address != billing_info['billing_address']:
raise Exception('unexpected trustedcoin billing address: expected {}, received {}'
.format(billing_address, billing_info['billing_address']))
wallet.add_new_billing_address(billing_index, billing_address)
# add segwit billing address; this will be used for actual billing
billing_address = make_billing_address(wallet, billing_index, addr_type='segwit')
if billing_address != billing_info['billing_address_segwit']:
raise Exception(f'unexpected trustedcoin billing address: '
f'calculated {billing_address}, received {billing_info["billing_address_segwit"]}')
wallet.add_new_billing_address(billing_index, billing_address, addr_type='segwit')
# also add legacy billing address; only used for detecting past payments in GUI
billing_address = make_billing_address(wallet, billing_index, addr_type='legacy')
wallet.add_new_billing_address(billing_index, billing_address, addr_type='legacy')
wallet.billing_info = billing_info
wallet.price_per_tx = dict(billing_info['price_per_tx'])
wallet.price_per_tx.pop(1, None)

12
electrum/storage.py

@ -44,7 +44,7 @@ from .keystore import bip44_derivation
OLD_SEED_VERSION = 4 # electrum versions < 2.0
NEW_SEED_VERSION = 11 # electrum versions >= 2.0
FINAL_SEED_VERSION = 18 # electrum >= 2.7 will set this to prevent
FINAL_SEED_VERSION = 19 # electrum >= 2.7 will set this to prevent
# old versions from overwriting new format
@ -354,6 +354,7 @@ class WalletStorage(JsonDB):
self.convert_version_16()
self.convert_version_17()
self.convert_version_18()
self.convert_version_19()
self.put('seed_version', FINAL_SEED_VERSION) # just to be sure
self.write()
@ -572,11 +573,16 @@ class WalletStorage(JsonDB):
# delete verified_tx3 as its structure changed
if not self._is_upgrade_method_needed(17, 17):
return
self.put('verified_tx3', None)
self.put('seed_version', 18)
def convert_version_19(self):
# delete trustedcoin_billing_addresses
if not self._is_upgrade_method_needed(18, 18):
return
self.put('trustedcoin_billing_addresses', None)
self.put('seed_version', 19)
def convert_imported(self):
if not self._is_upgrade_method_needed(0, 13):
return

Loading…
Cancel
Save