mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
fix pubkey ordering in multisig wallets. fix #1975
This commit is contained in:
parent
11ba5c441a
commit
5e92e09044
3 changed files with 60 additions and 41 deletions
|
@ -1667,27 +1667,23 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
|
|
||||||
def show_master_public_keys(self):
|
def show_master_public_keys(self):
|
||||||
dialog = WindowModalDialog(self, "Master Public Keys")
|
dialog = WindowModalDialog(self, "Master Public Keys")
|
||||||
mpk_dict = self.wallet.get_master_public_keys()
|
mpk_list = self.wallet.get_master_public_keys()
|
||||||
vbox = QVBoxLayout()
|
vbox = QVBoxLayout()
|
||||||
mpk_text = ShowQRTextEdit()
|
mpk_text = ShowQRTextEdit()
|
||||||
mpk_text.setMaximumHeight(100)
|
mpk_text.setMaximumHeight(100)
|
||||||
mpk_text.addCopyButton(self.app)
|
mpk_text.addCopyButton(self.app)
|
||||||
sorted_keys = sorted(mpk_dict.keys())
|
|
||||||
def show_mpk(index):
|
def show_mpk(index):
|
||||||
mpk_text.setText(mpk_dict[sorted_keys[index]])
|
mpk_text.setText(mpk_list[index])
|
||||||
|
|
||||||
# only show the combobox in case multiple accounts are available
|
# only show the combobox in case multiple accounts are available
|
||||||
if len(mpk_dict) > 1:
|
if len(mpk_list) > 1:
|
||||||
def label(key):
|
def label(key):
|
||||||
if isinstance(self.wallet, Multisig_Wallet):
|
if isinstance(self.wallet, Multisig_Wallet):
|
||||||
is_mine = False#self.wallet.master_private_keys.has_key(key)
|
return _("cosigner") + ' ' + str(i+1)
|
||||||
mine_text = [_("cosigner"), _("self")]
|
return ''
|
||||||
return "%s (%s)" % (key, mine_text[is_mine])
|
labels = [ label(i) for i in range(len(mpk_list))]
|
||||||
return key
|
|
||||||
labels = list(map(label, sorted_keys))
|
|
||||||
on_click = lambda clayout: show_mpk(clayout.selected_index())
|
on_click = lambda clayout: show_mpk(clayout.selected_index())
|
||||||
labels_clayout = ChoicesLayout(_("Master Public Keys"), labels,
|
labels_clayout = ChoicesLayout(_("Master Public Keys"), labels, on_click)
|
||||||
on_click)
|
|
||||||
vbox.addLayout(labels_clayout.layout())
|
vbox.addLayout(labels_clayout.layout())
|
||||||
|
|
||||||
show_mpk(0)
|
show_mpk(0)
|
||||||
|
|
|
@ -1063,11 +1063,17 @@ class Abstract_Wallet(PrintError):
|
||||||
txin['prev_tx'] = self.get_input_tx(tx_hash)
|
txin['prev_tx'] = self.get_input_tx(tx_hash)
|
||||||
|
|
||||||
# add output info for hw wallets
|
# add output info for hw wallets
|
||||||
tx.output_info = []
|
info = {}
|
||||||
for i, txout in enumerate(tx.outputs()):
|
xpubs = self.get_master_public_keys()
|
||||||
|
for txout in tx.outputs():
|
||||||
_type, addr, amount = txout
|
_type, addr, amount = txout
|
||||||
change, address_index = self.get_address_index(addr) if self.is_change(addr) else (None, None)
|
if self.is_change(addr):
|
||||||
tx.output_info.append((change, address_index))
|
index = self.get_address_index(addr)
|
||||||
|
pubkeys = self.get_public_keys(addr)
|
||||||
|
# sort xpubs using the order of pubkeys
|
||||||
|
sorted_pubkeys, sorted_xpubs = zip(*sorted(zip(pubkeys, xpubs)))
|
||||||
|
info[addr] = index, sorted_xpubs, self.m if isinstance(self, Multisig_Wallet) else None
|
||||||
|
tx.output_info = info
|
||||||
|
|
||||||
# sign
|
# sign
|
||||||
for k in self.get_keystores():
|
for k in self.get_keystores():
|
||||||
|
@ -1301,7 +1307,7 @@ class Imported_Wallet(Abstract_Wallet):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_master_public_keys(self):
|
def get_master_public_keys(self):
|
||||||
return {}
|
return []
|
||||||
|
|
||||||
def is_beyond_limit(self, address, is_change):
|
def is_beyond_limit(self, address, is_change):
|
||||||
return False
|
return False
|
||||||
|
@ -1506,7 +1512,7 @@ class Deterministic_Wallet(Abstract_Wallet):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_master_public_keys(self):
|
def get_master_public_keys(self):
|
||||||
return {'x':self.get_master_public_key()}
|
return [self.get_master_public_key()]
|
||||||
|
|
||||||
def get_fingerprint(self):
|
def get_fingerprint(self):
|
||||||
return self.get_master_public_key()
|
return self.get_master_public_key()
|
||||||
|
@ -1599,7 +1605,7 @@ class Multisig_Wallet(Deterministic_Wallet):
|
||||||
return address
|
return address
|
||||||
|
|
||||||
def new_pubkeys(self, c, i):
|
def new_pubkeys(self, c, i):
|
||||||
return [k.derive_pubkey(c, i) for k in self.keystores.values()]
|
return [k.derive_pubkey(c, i) for k in self.get_keystores()]
|
||||||
|
|
||||||
def load_keystore(self):
|
def load_keystore(self):
|
||||||
self.keystores = {}
|
self.keystores = {}
|
||||||
|
@ -1616,7 +1622,7 @@ class Multisig_Wallet(Deterministic_Wallet):
|
||||||
return self.keystores.get('x1/')
|
return self.keystores.get('x1/')
|
||||||
|
|
||||||
def get_keystores(self):
|
def get_keystores(self):
|
||||||
return self.keystores.values()
|
return [self.keystores[i] for i in sorted(self.keystores.keys())]
|
||||||
|
|
||||||
def update_password(self, old_pw, new_pw):
|
def update_password(self, old_pw, new_pw):
|
||||||
for name, keystore in self.keystores.items():
|
for name, keystore in self.keystores.items():
|
||||||
|
@ -1640,7 +1646,7 @@ class Multisig_Wallet(Deterministic_Wallet):
|
||||||
return self.keystore.get_master_public_key()
|
return self.keystore.get_master_public_key()
|
||||||
|
|
||||||
def get_master_public_keys(self):
|
def get_master_public_keys(self):
|
||||||
return dict(map(lambda x: (x[0], x[1].get_master_public_key()), self.keystores.items()))
|
return [k.get_master_public_key() for k in self.get_keystores()]
|
||||||
|
|
||||||
def get_fingerprint(self):
|
def get_fingerprint(self):
|
||||||
return ''.join(sorted(self.get_master_public_keys()))
|
return ''.join(sorted(self.get_master_public_keys()))
|
||||||
|
|
|
@ -312,31 +312,48 @@ class TrezorCompatiblePlugin(HW_PluginBase):
|
||||||
def tx_outputs(self, derivation, tx):
|
def tx_outputs(self, derivation, tx):
|
||||||
outputs = []
|
outputs = []
|
||||||
has_change = False
|
has_change = False
|
||||||
for i, (_type, address, amount) in enumerate(tx.outputs()):
|
|
||||||
|
for _type, address, amount in tx.outputs():
|
||||||
|
info = tx.output_info.get(address)
|
||||||
|
if info is not None and not has_change:
|
||||||
|
has_change = True # no more than one change address
|
||||||
|
addrtype, hash_160 = bc_address_to_hash_160(address)
|
||||||
|
index, xpubs, m = info
|
||||||
|
if addrtype == 0:
|
||||||
|
address_n = self.client_class.expand_path(derivation + "/%d/%d"%index)
|
||||||
|
txoutputtype = self.types.TxOutputType(
|
||||||
|
amount = amount,
|
||||||
|
script_type = self.types.PAYTOADDRESS,
|
||||||
|
address_n = address_n,
|
||||||
|
)
|
||||||
|
elif addrtype == 5:
|
||||||
|
address_n = self.client_class.expand_path("/%d/%d"%index)
|
||||||
|
nodes = map(self.ckd_public.deserialize, xpubs)
|
||||||
|
pubkeys = [ self.types.HDNodePathType(node=node, address_n=address_n) for node in nodes]
|
||||||
|
multisig = self.types.MultisigRedeemScriptType(
|
||||||
|
pubkeys = pubkeys,
|
||||||
|
signatures = [b'', b'', b''],
|
||||||
|
m = m)
|
||||||
|
txoutputtype = self.types.TxOutputType(
|
||||||
|
multisig = multisig,
|
||||||
|
amount = amount,
|
||||||
|
script_type = self.types.PAYTOMULTISIG)
|
||||||
|
else:
|
||||||
txoutputtype = self.types.TxOutputType()
|
txoutputtype = self.types.TxOutputType()
|
||||||
txoutputtype.amount = amount
|
txoutputtype.amount = amount
|
||||||
change, index = tx.output_info[i]
|
|
||||||
if _type == TYPE_SCRIPT:
|
if _type == TYPE_SCRIPT:
|
||||||
txoutputtype.script_type = self.types.PAYTOOPRETURN
|
txoutputtype.script_type = self.types.PAYTOOPRETURN
|
||||||
txoutputtype.op_return_data = address[2:]
|
txoutputtype.op_return_data = address[2:]
|
||||||
elif _type == TYPE_ADDRESS:
|
elif _type == TYPE_ADDRESS:
|
||||||
addrtype, hash_160 = bc_address_to_hash_160(address)
|
addrtype, hash_160 = bc_address_to_hash_160(address)
|
||||||
if addrtype == 0 and change is not None and not has_change:
|
|
||||||
address_path = "%s/%d/%d"%(derivation, change, index)
|
|
||||||
address_n = self.client_class.expand_path(address_path)
|
|
||||||
txoutputtype.address_n.extend(address_n)
|
|
||||||
# do not show more than one change address to device
|
|
||||||
has_change = True
|
|
||||||
else:
|
|
||||||
txoutputtype.address = address
|
|
||||||
if addrtype == 0:
|
if addrtype == 0:
|
||||||
txoutputtype.script_type = self.types.PAYTOADDRESS
|
txoutputtype.script_type = self.types.PAYTOADDRESS
|
||||||
elif addrtype == 5:
|
elif addrtype == 5:
|
||||||
txoutputtype.script_type = self.types.PAYTOSCRIPTHASH
|
txoutputtype.script_type = self.types.PAYTOSCRIPTHASH
|
||||||
else:
|
else:
|
||||||
raise BaseException('addrtype')
|
raise BaseException('addrtype')
|
||||||
else:
|
txoutputtype.address = address
|
||||||
raise BaseException('addrtype')
|
|
||||||
outputs.append(txoutputtype)
|
outputs.append(txoutputtype)
|
||||||
|
|
||||||
return outputs
|
return outputs
|
||||||
|
|
Loading…
Add table
Reference in a new issue