def show_qr(self): text = bfh(str(self.tx)) text = base_encode(text, base=43) try: self.main_window.show_qrcode(text, 'Transaction', parent=self) except Exception as e: self.show_message(str(e))
def f(x_pubkey): if is_xpubkey(x_pubkey): xpub, s = parse_xpubkey(x_pubkey) else: xpub = xpub_from_pubkey(0, bfh(x_pubkey)) s = [] node = self.ckd_public.deserialize(xpub) return self.types.HDNodePathType(node=node, address_n=s)
def electrum_tx_to_txtype(self, tx): t = self.types.TransactionType() d = deserialize(tx.raw) t.version = d['version'] t.lock_time = d['lockTime'] inputs = self.tx_inputs(tx) t.inputs.extend(inputs) for vout in d['outputs']: o = t.bin_outputs.add() o.amount = vout['value'] o.script_pubkey = bfh(vout['scriptPubKey']) return t
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') try: server.put(_hash, message) except Exception as e: traceback.print_exc(file=sys.stdout) window.show_message( "Failed to send transaction to cosigning pool.") return window.show_message( "Your transaction was sent to the cosigning pool.\nOpen your cosigner wallet to retrieve it." )
def on_receive(self, keyhash, message): self.print_error("signal arrived for", keyhash) for key, _hash, window in self.keys: if _hash == keyhash: break else: self.print_error("keyhash not found") return wallet = window.wallet if wallet.has_password(): password = window.password_dialog( 'An encrypted transaction was retrieved from cosigning pool.\nPlease enter your password to decrypt it.' ) if not password: return else: password = None if not window.question( _("An encrypted transaction was retrieved from cosigning pool.\nDo you want to open it now?" )): return xprv = wallet.keystore.get_master_private_key(password) if not xprv: return try: k = bh2u(bitcoin.deserialize_xprv(xprv)[-1]) EC = bitcoin.EC_KEY(bfh(k)) message = bh2u(EC.decrypt_message(message)) except Exception as e: traceback.print_exc(file=sys.stdout) window.show_message(str(e)) return self.listener.clear(keyhash) tx = transaction.Transaction(message) show_transaction(tx, window, prompt_if_unsaved=True)
def tx_inputs(self, tx, for_sig=False): inputs = [] for txin in tx.inputs(): txinputtype = self.types.TxInputType() if txin['type'] == 'coinbase': prev_hash = "\0" * 32 prev_index = 0xffffffff # signed int -1 else: if for_sig: x_pubkeys = txin['x_pubkeys'] if len(x_pubkeys) == 1: x_pubkey = x_pubkeys[0] xpub, s = parse_xpubkey(x_pubkey) xpub_n = self.client_class.expand_path( self.xpub_path[xpub]) txinputtype.address_n.extend(xpub_n + s) txinputtype.script_type = self.types.SPENDADDRESS else: def f(x_pubkey): if is_xpubkey(x_pubkey): xpub, s = parse_xpubkey(x_pubkey) else: xpub = xpub_from_pubkey(0, bfh(x_pubkey)) s = [] node = self.ckd_public.deserialize(xpub) return self.types.HDNodePathType(node=node, address_n=s) pubkeys = map(f, x_pubkeys) multisig = self.types.MultisigRedeemScriptType( pubkeys=pubkeys, signatures=map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures')), m=txin.get('num_sig'), ) script_type = self.types.SPENDMULTISIG txinputtype = self.types.TxInputType( script_type=script_type, multisig=multisig) # find which key is mine for x_pubkey in x_pubkeys: if is_xpubkey(x_pubkey): xpub, s = parse_xpubkey(x_pubkey) if xpub in self.xpub_path: xpub_n = self.client_class.expand_path( self.xpub_path[xpub]) txinputtype.address_n.extend(xpub_n + s) break prev_hash = unhexlify(txin['prevout_hash']) prev_index = txin['prevout_n'] if 'value' in txin: txinputtype.amount = txin['value'] txinputtype.prev_hash = prev_hash txinputtype.prev_index = prev_index if 'scriptSig' in txin: script_sig = bfh(txin['scriptSig']) txinputtype.script_sig = script_sig txinputtype.sequence = txin.get('sequence', 0xffffffff - 1) inputs.append(txinputtype) return inputs
def data(self, index, role=Qt.DisplayRole): data = None if not index.isValid(): return QVariant(data) if role not in [ Qt.DisplayRole, Qt.EditRole, Qt.ToolTipRole, Qt.FontRole, Qt.BackgroundRole ]: return None mn = self.masternodes[index.row()] i = index.column() if i == self.ALIAS: data = mn.alias elif i == self.STATUS: status = self.manager.masternode_statuses.get( mn.get_collateral_str()) data = masternode_status(status) if role == Qt.BackgroundRole: data = QBrush( QColor(ENABLED_MASTERNODE_BG)) if data[0] else None # Return the long description for data widget mappers. elif role == Qt.EditRole: data = data[2] else: data = data[1] elif i == self.VIN: txid = mn.vin.get('prevout_hash', '') out_n = str(mn.vin.get('prevout_n', '')) addr = mn.vin.get('address', '') value = str(mn.vin.get('value', '')) scriptsig = mn.vin.get('scriptSig', '') if role == Qt.EditRole: data = ':'.join([txid, out_n, addr, value, scriptsig]) elif role == Qt.FontRole: data = util.MONOSPACE_FONT else: if all(attr for attr in [txid, out_n, addr]): data = '%s:%s' % (txid, out_n) else: data = '' elif i == self.COLLATERAL: data = mn.collateral_key if role in [Qt.EditRole, Qt.DisplayRole, Qt.ToolTipRole] and data: data = bitcoin.public_key_to_p2pkh(bfh(data)) elif role == Qt.FontRole: data = util.MONOSPACE_FONT elif i == self.DELEGATE: data = mn.delegate_key if role in [Qt.EditRole, Qt.DisplayRole, Qt.ToolTipRole] and data: data = self.manager.get_delegate_privkey(data) elif role == Qt.FontRole: data = util.MONOSPACE_FONT elif i == self.ADDR: data = '' if mn.addr.ip: data = str(mn.addr) elif i == self.PROTOCOL_VERSION: data = mn.protocol_version return QVariant(data)
def sign_transaction(self, tx, password): if tx.is_complete(): return client = self.get_client() self.signing = True inputs = [] inputsPaths = [] pubKeys = [] chipInputs = [] redeemScripts = [] signatures = [] preparedTrustedInputs = [] changePath = "" changeAmount = None output = None outputAmount = None p2shTransaction = False pin = "" self.get_client() # prompt for the PIN before displaying the dialog if necessary # Fetch inputs of the transaction to sign derivations = self.get_tx_derivations(tx) for txin in tx.inputs(): if txin['type'] == 'coinbase': self.give_error("Coinbase not supported") # should never happen if txin['type'] in ['p2sh']: p2shTransaction = True pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin) for i, x_pubkey in enumerate(x_pubkeys): if x_pubkey in derivations: signingPos = i s = derivations.get(x_pubkey) hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], s[0], s[1]) break else: self.give_error("No matching x_key for sign_transaction") # should never happen redeemScript = Transaction.get_preimage_script(txin) inputs.append([txin['prev_tx'].raw, txin['prevout_n'], redeemScript, txin['prevout_hash'], signingPos, txin.get('sequence', 0xffffffff - 1) ]) inputsPaths.append(hwAddress) pubKeys.append(pubkeys) # Sanity check if p2shTransaction: for txin in tx.inputs(): if txin['type'] != 'p2sh': self.give_error("P2SH / regular input mixed in same transaction not supported") # should never happen txOutput = var_int(len(tx.outputs())) for txout in tx.outputs(): output_type, addr, amount = txout txOutput += int_to_hex(amount, 8) script = tx.pay_script(output_type, addr) txOutput += var_int(len(script)//2) txOutput += script txOutput = bfh(txOutput) # Recognize outputs - only one output and one change is authorized if not p2shTransaction: if not self.get_client_electrum().supports_multi_output(): if len(tx.outputs()) > 2: self.give_error("Transaction with more than 2 outputs not supported") for _type, address, amount in tx.outputs(): assert _type == TYPE_ADDRESS info = tx.output_info.get(address) if (info is not None) and (len(tx.outputs()) != 1): index, xpubs, m = info changePath = self.get_derivation()[2:] + "/%d/%d"%index changeAmount = amount else: output = address if not self.get_client_electrum().canAlternateCoinVersions: v, h = b58_address_to_hash160(address) if v == NetworkConstants.ADDRTYPE_P2PKH: output = hash160_to_b58_address(h, 0) outputAmount = amount self.handler.show_message(_("Confirm Transaction on your Ledger device...")) try: # Get trusted inputs from the original transactions for utxo in inputs: sequence = int_to_hex(utxo[5], 4) if not p2shTransaction: txtmp = bitcoinTransaction(bfh(utxo[0])) trustedInput = self.get_client().getTrustedInput(txtmp, utxo[1]) trustedInput['sequence'] = sequence chipInputs.append(trustedInput) redeemScripts.append(txtmp.outputs[utxo[1]].script) else: tmp = bfh(utxo[3])[::-1] tmp += bfh(int_to_hex(utxo[1], 4)) chipInputs.append({'value' : tmp, 'sequence' : sequence}) redeemScripts.append(bfh(utxo[2])) # Sign all inputs firstTransaction = True inputIndex = 0 rawTx = tx.serialize() self.get_client().enableAlternate2fa(False) while inputIndex < len(inputs): self.get_client().startUntrustedTransaction(firstTransaction, inputIndex, chipInputs, redeemScripts[inputIndex]) outputData = self.get_client().finalizeInputFull(txOutput) outputData['outputData'] = txOutput if firstTransaction: transactionOutput = outputData['outputData'] if outputData['confirmationNeeded']: outputData['address'] = output self.handler.finished() pin = self.handler.get_auth( outputData ) # does the authenticate dialog and returns pin if not pin: raise UserWarning() if pin != 'paired': self.handler.show_message(_("Confirmed. Signing Transaction...")) else: # Sign input with the provided PIN inputSignature = self.get_client().untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime) inputSignature[0] = 0x30 # force for 1.4.9+ signatures.append(inputSignature) inputIndex = inputIndex + 1 if pin != 'paired': firstTransaction = False except UserWarning: self.handler.show_error(_('Cancelled by user')) return except BaseException as e: traceback.print_exc(file=sys.stdout) self.give_error(e, True) finally: self.handler.finished() for i, txin in enumerate(tx.inputs()): signingPos = inputs[i][4] txin['signatures'][signingPos] = bh2u(signatures[i]) tx.raw = tx.serialize() self.signing = False