remove segwit from plugins/gui/RELEASE-NOTES/main
This commit is contained in:
parent
fc0d01ec2c
commit
b4f8cd8746
|
@ -22,10 +22,8 @@ issue #3374. Users should upgrade to 3.0.5.
|
||||||
* Qt GUI: sweeping now uses the Send tab, allowing fees to be set
|
* Qt GUI: sweeping now uses the Send tab, allowing fees to be set
|
||||||
* Windows: if using the installer binary, there is now a separate shortcut
|
* Windows: if using the installer binary, there is now a separate shortcut
|
||||||
for "Electrum Testnet"
|
for "Electrum Testnet"
|
||||||
* Digital Bitbox: added suport for p2sh-segwit
|
|
||||||
* OS notifications for incoming transactions
|
* OS notifications for incoming transactions
|
||||||
* better transaction size estimation:
|
* better transaction size estimation:
|
||||||
- fees for segwit txns were somewhat underestimated (#3347)
|
|
||||||
- some multisig txns were underestimated
|
- some multisig txns were underestimated
|
||||||
- handle uncompressed pubkeys
|
- handle uncompressed pubkeys
|
||||||
* fix #3321: testnet for Windows binaries
|
* fix #3321: testnet for Windows binaries
|
||||||
|
@ -39,7 +37,6 @@ issue #3374. Users should upgrade to 3.0.5.
|
||||||
* sweeping minikeys: search for both compressed and uncompressed
|
* sweeping minikeys: search for both compressed and uncompressed
|
||||||
pubkeys
|
pubkeys
|
||||||
* fix wizard crash when attempting to reset Google Authenticator
|
* fix wizard crash when attempting to reset Google Authenticator
|
||||||
* fix #3248: fix Ledger+segwit signing
|
|
||||||
* fix #3262: fix SSL payment request signing
|
* fix #3262: fix SSL payment request signing
|
||||||
* other minor fixes.
|
* other minor fixes.
|
||||||
|
|
||||||
|
@ -53,55 +50,6 @@ issue #3374. Users should upgrade to 3.0.5.
|
||||||
run "python3 setup.py install" in order to install the new
|
run "python3 setup.py install" in order to install the new
|
||||||
dependencies.
|
dependencies.
|
||||||
|
|
||||||
* Segwit support:
|
|
||||||
|
|
||||||
- Native segwit scripts are supported using a new type of
|
|
||||||
seed. The version number for segwit seeds is 0x100. The install
|
|
||||||
wizard will not create segwit seeds by default; users must
|
|
||||||
opt-in with the segwit option.
|
|
||||||
|
|
||||||
- Native segwit scripts are represented using bech32 addresses,
|
|
||||||
following BIP173. Please note that BIP173 is still in draft
|
|
||||||
status, and that other wallets/websites may not support
|
|
||||||
it. Thus, you should keep a non-segwit wallet in order to be
|
|
||||||
able to receive bitcoins during the transition period. If BIP173
|
|
||||||
ends up being rejected or substantially modified, your wallet
|
|
||||||
may have to be restored from seed. This will not affect funds
|
|
||||||
sent to bech32 addresses, and it will not affect the capacity of
|
|
||||||
Electrum to spend these funds.
|
|
||||||
|
|
||||||
- Segwit scripts embedded in p2sh are supported with hardware
|
|
||||||
wallets or bip39 seeds. To create a segwit-in-p2sh wallet,
|
|
||||||
trezor/ledger users will need to enter a BIP49 derivation path.
|
|
||||||
|
|
||||||
- The BIP32 master keys of segwit wallets are serialized using new
|
|
||||||
version numbers. The new version numbers encode the script type,
|
|
||||||
and they result in the following prefixes:
|
|
||||||
|
|
||||||
* xpub/xprv : p2pkh or p2sh
|
|
||||||
* ypub/yprv : p2wpkh-in-p2sh
|
|
||||||
* Ypub/Yprv : p2wsh-in-p2sh
|
|
||||||
* zpub/zprv : p2wpkh
|
|
||||||
* Zpub/Zprv : p2wsh
|
|
||||||
|
|
||||||
These values are identical for mainnet and testnet; tpub/tprv
|
|
||||||
prefixes are no longer used in testnet wallets.
|
|
||||||
|
|
||||||
- The Wallet Import Format (WIF) is similarly extended for segwit
|
|
||||||
scripts. After a base58-encoded key is decoded to binary, its
|
|
||||||
first byte encodes the script type:
|
|
||||||
|
|
||||||
* 128 + 0: p2pkh
|
|
||||||
* 128 + 1: p2wpkh
|
|
||||||
* 128 + 2: p2wpkh-in-p2sh
|
|
||||||
* 128 + 5: p2sh
|
|
||||||
* 128 + 6: p2wsh
|
|
||||||
* 128 + 7: p2wsh-in-p2sh
|
|
||||||
|
|
||||||
The distinction between p2sh and p2pkh in private key means that
|
|
||||||
it is not possible to import a p2sh private key and associate it
|
|
||||||
to a p2pkh address.
|
|
||||||
|
|
||||||
* A new version of the Electrum protocol is required by the client
|
* A new version of the Electrum protocol is required by the client
|
||||||
(version 1.1). Servers using older versions of the protocol will
|
(version 1.1). Servers using older versions of the protocol will
|
||||||
not be displayed in the GUI.
|
not be displayed in the GUI.
|
||||||
|
@ -184,7 +132,6 @@ issue #3374. Users should upgrade to 3.0.5.
|
||||||
- Dynamic fees are enabled by default.
|
- Dynamic fees are enabled by default.
|
||||||
- Child Pays For Parent (CPFP) dialog in the GUI.
|
- Child Pays For Parent (CPFP) dialog in the GUI.
|
||||||
- RBF is automatically proposed for low fee transactions.
|
- RBF is automatically proposed for low fee transactions.
|
||||||
* Support for Segregated Witness (testnet only).
|
|
||||||
* Support for Digital Bitbox hardware wallet.
|
* Support for Digital Bitbox hardware wallet.
|
||||||
* The GUI shows a blue icon when connected using a proxy.
|
* The GUI shows a blue icon when connected using a proxy.
|
||||||
|
|
||||||
|
|
2
electrum
2
electrum
|
@ -168,7 +168,7 @@ def run_non_RPC(config):
|
||||||
elif cmdname == 'create':
|
elif cmdname == 'create':
|
||||||
password = password_dialog()
|
password = password_dialog()
|
||||||
passphrase = config.get('passphrase', '')
|
passphrase = config.get('passphrase', '')
|
||||||
seed_type = 'segwit' if config.get('segwit') else 'standard'
|
seed_type = 'standard'
|
||||||
seed = Mnemonic('en').make_seed(seed_type)
|
seed = Mnemonic('en').make_seed(seed_type)
|
||||||
k = keystore.from_seed(seed, passphrase, False)
|
k = keystore.from_seed(seed, passphrase, False)
|
||||||
storage.put('keystore', k.dump())
|
storage.put('keystore', k.dump())
|
||||||
|
|
|
@ -1937,8 +1937,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
rds_e = ShowQRTextEdit(text=redeem_script)
|
rds_e = ShowQRTextEdit(text=redeem_script)
|
||||||
rds_e.addCopyButton(self.app)
|
rds_e.addCopyButton(self.app)
|
||||||
vbox.addWidget(rds_e)
|
vbox.addWidget(rds_e)
|
||||||
if xtype in ['p2wpkh', 'p2wsh', 'p2wpkh-p2sh', 'p2wsh-p2sh']:
|
|
||||||
vbox.addWidget(WWLabel(_("Warning: the format of private keys associated to segwit addresses may not be compatible with other wallets")))
|
|
||||||
vbox.addLayout(Buttons(CloseButton(d)))
|
vbox.addLayout(Buttons(CloseButton(d)))
|
||||||
d.setLayout(vbox)
|
d.setLayout(vbox)
|
||||||
d.exec_()
|
d.exec_()
|
||||||
|
@ -1956,7 +1954,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
self.show_message('Invalid Bitcoin address.')
|
self.show_message('Invalid Bitcoin address.')
|
||||||
return
|
return
|
||||||
txin_type = self.wallet.get_txin_type(address)
|
txin_type = self.wallet.get_txin_type(address)
|
||||||
if txin_type not in ['p2pkh', 'p2wpkh', 'p2wpkh-p2sh']:
|
if txin_type not in ['p2pkh']:
|
||||||
self.show_message('Cannot sign messages with this type of address.' + '\n\n' + self.msg_sign)
|
self.show_message('Cannot sign messages with this type of address.' + '\n\n' + self.msg_sign)
|
||||||
return
|
return
|
||||||
if not self.wallet.is_mine(address):
|
if not self.wallet.is_mine(address):
|
||||||
|
|
|
@ -86,7 +86,7 @@ class DigitalBitbox_Client():
|
||||||
|
|
||||||
|
|
||||||
def get_xpub(self, bip32_path, xtype):
|
def get_xpub(self, bip32_path, xtype):
|
||||||
assert xtype in ('standard', 'p2wpkh-p2sh')
|
assert xtype in ('standard')
|
||||||
reply = self._get_xpub(bip32_path)
|
reply = self._get_xpub(bip32_path)
|
||||||
if reply:
|
if reply:
|
||||||
xpub = reply['xpub']
|
xpub = reply['xpub']
|
||||||
|
|
|
@ -4,8 +4,7 @@ from binascii import hexlify, unhexlify
|
||||||
|
|
||||||
from electrum.util import bfh, bh2u
|
from electrum.util import bfh, bh2u
|
||||||
from electrum.bitcoin import (b58_address_to_hash160, xpub_from_pubkey,
|
from electrum.bitcoin import (b58_address_to_hash160, xpub_from_pubkey,
|
||||||
TYPE_ADDRESS, TYPE_SCRIPT, NetworkConstants,
|
TYPE_ADDRESS, TYPE_SCRIPT, NetworkConstants)
|
||||||
is_segwit_address)
|
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.plugins import BasePlugin
|
from electrum.plugins import BasePlugin
|
||||||
from electrum.transaction import deserialize
|
from electrum.transaction import deserialize
|
||||||
|
@ -22,9 +21,6 @@ class KeepKeyCompatibleKeyStore(Hardware_KeyStore):
|
||||||
def get_derivation(self):
|
def get_derivation(self):
|
||||||
return self.derivation
|
return self.derivation
|
||||||
|
|
||||||
def is_segwit(self):
|
|
||||||
return self.derivation.startswith("m/49'/")
|
|
||||||
|
|
||||||
def get_client(self, force_pair=True):
|
def get_client(self, force_pair=True):
|
||||||
return self.plugin.get_client(self, force_pair)
|
return self.plugin.get_client(self, force_pair)
|
||||||
|
|
||||||
|
@ -219,8 +215,8 @@ class KeepKeyCompatiblePlugin(HW_PluginBase):
|
||||||
self.prev_tx = prev_tx
|
self.prev_tx = prev_tx
|
||||||
self.xpub_path = xpub_path
|
self.xpub_path = xpub_path
|
||||||
client = self.get_client(keystore)
|
client = self.get_client(keystore)
|
||||||
inputs = self.tx_inputs(tx, True, keystore.is_segwit())
|
inputs = self.tx_inputs(tx, True)
|
||||||
outputs = self.tx_outputs(keystore.get_derivation(), tx, keystore.is_segwit())
|
outputs = self.tx_outputs(keystore.get_derivation(), tx)
|
||||||
signed_tx = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[1]
|
signed_tx = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[1]
|
||||||
raw = bh2u(signed_tx)
|
raw = bh2u(signed_tx)
|
||||||
tx.update_signatures(raw)
|
tx.update_signatures(raw)
|
||||||
|
@ -234,11 +230,10 @@ class KeepKeyCompatiblePlugin(HW_PluginBase):
|
||||||
derivation = wallet.keystore.derivation
|
derivation = wallet.keystore.derivation
|
||||||
address_path = "%s/%d/%d"%(derivation, change, index)
|
address_path = "%s/%d/%d"%(derivation, change, index)
|
||||||
address_n = client.expand_path(address_path)
|
address_n = client.expand_path(address_path)
|
||||||
segwit = wallet.keystore.is_segwit()
|
script_type = self.types.SPENDADDRESS
|
||||||
script_type = self.types.SPENDP2SHWITNESS if segwit else self.types.SPENDADDRESS
|
|
||||||
client.get_address(self.get_coin_name(), address_n, True, script_type=script_type)
|
client.get_address(self.get_coin_name(), address_n, True, script_type=script_type)
|
||||||
|
|
||||||
def tx_inputs(self, tx, for_sig=False, segwit=False):
|
def tx_inputs(self, tx, for_sig=False):
|
||||||
inputs = []
|
inputs = []
|
||||||
for txin in tx.inputs():
|
for txin in tx.inputs():
|
||||||
txinputtype = self.types.TxInputType()
|
txinputtype = self.types.TxInputType()
|
||||||
|
@ -253,7 +248,7 @@ class KeepKeyCompatiblePlugin(HW_PluginBase):
|
||||||
xpub, s = parse_xpubkey(x_pubkey)
|
xpub, s = parse_xpubkey(x_pubkey)
|
||||||
xpub_n = self.client_class.expand_path(self.xpub_path[xpub])
|
xpub_n = self.client_class.expand_path(self.xpub_path[xpub])
|
||||||
txinputtype.address_n.extend(xpub_n + s)
|
txinputtype.address_n.extend(xpub_n + s)
|
||||||
txinputtype.script_type = self.types.SPENDP2SHWITNESS if segwit else self.types.SPENDADDRESS
|
txinputtype.script_type = self.types.SPENDADDRESS
|
||||||
else:
|
else:
|
||||||
def f(x_pubkey):
|
def f(x_pubkey):
|
||||||
if is_xpubkey(x_pubkey):
|
if is_xpubkey(x_pubkey):
|
||||||
|
@ -269,7 +264,7 @@ class KeepKeyCompatiblePlugin(HW_PluginBase):
|
||||||
signatures=map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures')),
|
signatures=map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures')),
|
||||||
m=txin.get('num_sig'),
|
m=txin.get('num_sig'),
|
||||||
)
|
)
|
||||||
script_type = self.types.SPENDP2SHWITNESS if segwit else self.types.SPENDMULTISIG
|
script_type = self.types.SPENDMULTISIG
|
||||||
txinputtype = self.types.TxInputType(
|
txinputtype = self.types.TxInputType(
|
||||||
script_type=script_type,
|
script_type=script_type,
|
||||||
multisig=multisig
|
multisig=multisig
|
||||||
|
@ -301,7 +296,7 @@ class KeepKeyCompatiblePlugin(HW_PluginBase):
|
||||||
|
|
||||||
return inputs
|
return inputs
|
||||||
|
|
||||||
def tx_outputs(self, derivation, tx, segwit=False):
|
def tx_outputs(self, derivation, tx):
|
||||||
outputs = []
|
outputs = []
|
||||||
has_change = False
|
has_change = False
|
||||||
|
|
||||||
|
@ -312,7 +307,7 @@ class KeepKeyCompatiblePlugin(HW_PluginBase):
|
||||||
addrtype, hash_160 = b58_address_to_hash160(address)
|
addrtype, hash_160 = b58_address_to_hash160(address)
|
||||||
index, xpubs, m = info
|
index, xpubs, m = info
|
||||||
if len(xpubs) == 1:
|
if len(xpubs) == 1:
|
||||||
script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOADDRESS
|
script_type = self.types.PAYTOADDRESS
|
||||||
address_n = self.client_class.expand_path(derivation + "/%d/%d"%index)
|
address_n = self.client_class.expand_path(derivation + "/%d/%d"%index)
|
||||||
txoutputtype = self.types.TxOutputType(
|
txoutputtype = self.types.TxOutputType(
|
||||||
amount = amount,
|
amount = amount,
|
||||||
|
@ -320,7 +315,7 @@ class KeepKeyCompatiblePlugin(HW_PluginBase):
|
||||||
address_n = address_n,
|
address_n = address_n,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOMULTISIG
|
script_type = self.types.PAYTOMULTISIG
|
||||||
address_n = self.client_class.expand_path("/%d/%d"%index)
|
address_n = self.client_class.expand_path("/%d/%d"%index)
|
||||||
nodes = map(self.ckd_public.deserialize, xpubs)
|
nodes = map(self.ckd_public.deserialize, xpubs)
|
||||||
pubkeys = [ self.types.HDNodePathType(node=node, address_n=address_n) for node in nodes]
|
pubkeys = [ self.types.HDNodePathType(node=node, address_n=address_n) for node in nodes]
|
||||||
|
@ -340,16 +335,13 @@ class KeepKeyCompatiblePlugin(HW_PluginBase):
|
||||||
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:
|
||||||
if is_segwit_address(address):
|
addrtype, hash_160 = b58_address_to_hash160(address)
|
||||||
txoutputtype.script_type = self.types.PAYTOWITNESS
|
if addrtype == NetworkConstants.ADDRTYPE_P2PKH:
|
||||||
|
txoutputtype.script_type = self.types.PAYTOADDRESS
|
||||||
|
elif addrtype == NetworkConstants.ADDRTYPE_P2SH:
|
||||||
|
txoutputtype.script_type = self.types.PAYTOSCRIPTHASH
|
||||||
else:
|
else:
|
||||||
addrtype, hash_160 = b58_address_to_hash160(address)
|
raise BaseException('addrtype: ' + str(addrtype))
|
||||||
if addrtype == NetworkConstants.ADDRTYPE_P2PKH:
|
|
||||||
txoutputtype.script_type = self.types.PAYTOADDRESS
|
|
||||||
elif addrtype == NetworkConstants.ADDRTYPE_P2SH:
|
|
||||||
txoutputtype.script_type = self.types.PAYTOSCRIPTHASH
|
|
||||||
else:
|
|
||||||
raise BaseException('addrtype: ' + str(addrtype))
|
|
||||||
txoutputtype.address = address
|
txoutputtype.address = address
|
||||||
|
|
||||||
outputs.append(txoutputtype)
|
outputs.append(txoutputtype)
|
||||||
|
|
|
@ -56,10 +56,6 @@ class Ledger_Client():
|
||||||
# This only happens once so it's bearable
|
# This only happens once so it's bearable
|
||||||
#self.get_client() # prompt for the PIN before displaying the dialog if necessary
|
#self.get_client() # prompt for the PIN before displaying the dialog if necessary
|
||||||
#self.handler.show_message("Computing master public key")
|
#self.handler.show_message("Computing master public key")
|
||||||
if xtype in ['p2wpkh', 'p2wsh'] and not self.supports_native_segwit():
|
|
||||||
raise Exception("Firmware version too old for Segwit support. Please update at https://www.ledgerwallet.com")
|
|
||||||
if xtype in ['p2wpkh-p2sh', 'p2wsh-p2sh'] and not self.supports_segwit():
|
|
||||||
raise Exception("Firmware version too old for Segwit support. Please update at https://www.ledgerwallet.com")
|
|
||||||
splitPath = bip32_path.split('/')
|
splitPath = bip32_path.split('/')
|
||||||
if splitPath[0] == 'm':
|
if splitPath[0] == 'm':
|
||||||
splitPath = splitPath[1:]
|
splitPath = splitPath[1:]
|
||||||
|
@ -103,19 +99,11 @@ class Ledger_Client():
|
||||||
def supports_multi_output(self):
|
def supports_multi_output(self):
|
||||||
return self.multiOutputSupported
|
return self.multiOutputSupported
|
||||||
|
|
||||||
def supports_segwit(self):
|
|
||||||
return self.segwitSupported
|
|
||||||
|
|
||||||
def supports_native_segwit(self):
|
|
||||||
return self.nativeSegwitSupported
|
|
||||||
|
|
||||||
def perform_hw1_preflight(self):
|
def perform_hw1_preflight(self):
|
||||||
try:
|
try:
|
||||||
firmwareInfo = self.dongleObject.getFirmwareVersion()
|
firmwareInfo = self.dongleObject.getFirmwareVersion()
|
||||||
firmware = firmwareInfo['version'].split(".")
|
firmware = firmwareInfo['version'].split(".")
|
||||||
self.multiOutputSupported = int(firmware[0]) >= 1 and int(firmware[1]) >= 1 and int(firmware[2]) >= 4
|
self.multiOutputSupported = int(firmware[0]) >= 1 and int(firmware[1]) >= 1 and int(firmware[2]) >= 4
|
||||||
self.segwitSupported = (int(firmware[0]) >= 1 and int(firmware[1]) >= 1 and int(firmware[2]) >= 10) or (firmwareInfo['specialVersion'] == 0x20 and int(firmware[0]) == 1 and int(firmware[1]) == 0 and int(firmware[2]) >= 4)
|
|
||||||
self.nativeSegwitSupported = int(firmware[0]) >= 1 and int(firmware[1]) >= 1 and int(firmware[2]) >= 10
|
|
||||||
|
|
||||||
if not checkFirmware(firmware):
|
if not checkFirmware(firmware):
|
||||||
self.dongleObject.dongle.close()
|
self.dongleObject.dongle.close()
|
||||||
|
@ -270,7 +258,6 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
||||||
output = None
|
output = None
|
||||||
outputAmount = None
|
outputAmount = None
|
||||||
p2shTransaction = False
|
p2shTransaction = False
|
||||||
segwitTransaction = False
|
|
||||||
pin = ""
|
pin = ""
|
||||||
self.get_client() # prompt for the PIN before displaying the dialog if necessary
|
self.get_client() # prompt for the PIN before displaying the dialog if necessary
|
||||||
|
|
||||||
|
@ -283,16 +270,6 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
||||||
if txin['type'] in ['p2sh']:
|
if txin['type'] in ['p2sh']:
|
||||||
p2shTransaction = True
|
p2shTransaction = True
|
||||||
|
|
||||||
if txin['type'] in ['p2wpkh-p2sh', 'p2wsh-p2sh']:
|
|
||||||
if not self.get_client_electrum().supports_segwit():
|
|
||||||
self.give_error("Firmware version too old to support segwit. Please update at https://www.ledgerwallet.com")
|
|
||||||
segwitTransaction = True
|
|
||||||
|
|
||||||
if txin['type'] in ['p2wpkh', 'p2wsh']:
|
|
||||||
if not self.get_client_electrum().supports_native_segwit():
|
|
||||||
self.give_error("Firmware version too old to support native segwit. Please update at https://www.ledgerwallet.com")
|
|
||||||
segwitTransaction = True
|
|
||||||
|
|
||||||
pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin)
|
pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin)
|
||||||
for i, x_pubkey in enumerate(x_pubkeys):
|
for i, x_pubkey in enumerate(x_pubkeys):
|
||||||
if x_pubkey in derivations:
|
if x_pubkey in derivations:
|
||||||
|
@ -344,14 +321,7 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
||||||
# Get trusted inputs from the original transactions
|
# Get trusted inputs from the original transactions
|
||||||
for utxo in inputs:
|
for utxo in inputs:
|
||||||
sequence = int_to_hex(utxo[5], 4)
|
sequence = int_to_hex(utxo[5], 4)
|
||||||
if segwitTransaction:
|
if not p2shTransaction:
|
||||||
txtmp = bitcoinTransaction(bfh(utxo[0]))
|
|
||||||
tmp = bfh(utxo[3])[::-1]
|
|
||||||
tmp += bfh(int_to_hex(utxo[1], 4))
|
|
||||||
tmp += txtmp.outputs[utxo[1]].amount
|
|
||||||
chipInputs.append({'value' : tmp, 'witness' : True, 'sequence' : sequence})
|
|
||||||
redeemScripts.append(bfh(utxo[2]))
|
|
||||||
elif not p2shTransaction:
|
|
||||||
txtmp = bitcoinTransaction(bfh(utxo[0]))
|
txtmp = bitcoinTransaction(bfh(utxo[0]))
|
||||||
trustedInput = self.get_client().getTrustedInput(txtmp, utxo[1])
|
trustedInput = self.get_client().getTrustedInput(txtmp, utxo[1])
|
||||||
trustedInput['sequence'] = sequence
|
trustedInput['sequence'] = sequence
|
||||||
|
@ -368,12 +338,13 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
||||||
inputIndex = 0
|
inputIndex = 0
|
||||||
rawTx = tx.serialize()
|
rawTx = tx.serialize()
|
||||||
self.get_client().enableAlternate2fa(False)
|
self.get_client().enableAlternate2fa(False)
|
||||||
if segwitTransaction:
|
while inputIndex < len(inputs):
|
||||||
self.get_client().startUntrustedTransaction(True, inputIndex,
|
self.get_client().startUntrustedTransaction(firstTransaction, inputIndex,
|
||||||
chipInputs, redeemScripts[inputIndex])
|
chipInputs, redeemScripts[inputIndex])
|
||||||
outputData = self.get_client().finalizeInputFull(txOutput)
|
outputData = self.get_client().finalizeInputFull(txOutput)
|
||||||
outputData['outputData'] = txOutput
|
outputData['outputData'] = txOutput
|
||||||
transactionOutput = outputData['outputData']
|
if firstTransaction:
|
||||||
|
transactionOutput = outputData['outputData']
|
||||||
if outputData['confirmationNeeded']:
|
if outputData['confirmationNeeded']:
|
||||||
outputData['address'] = output
|
outputData['address'] = output
|
||||||
self.handler.finished()
|
self.handler.finished()
|
||||||
|
@ -382,38 +353,14 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
||||||
raise UserWarning()
|
raise UserWarning()
|
||||||
if pin != 'paired':
|
if pin != 'paired':
|
||||||
self.handler.show_message(_("Confirmed. Signing Transaction..."))
|
self.handler.show_message(_("Confirmed. Signing Transaction..."))
|
||||||
while inputIndex < len(inputs):
|
else:
|
||||||
singleInput = [ chipInputs[inputIndex] ]
|
# Sign input with the provided PIN
|
||||||
self.get_client().startUntrustedTransaction(False, 0,
|
|
||||||
singleInput, redeemScripts[inputIndex])
|
|
||||||
inputSignature = self.get_client().untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime)
|
inputSignature = self.get_client().untrustedHashSign(inputsPaths[inputIndex], pin, lockTime=tx.locktime)
|
||||||
inputSignature[0] = 0x30 # force for 1.4.9+
|
inputSignature[0] = 0x30 # force for 1.4.9+
|
||||||
signatures.append(inputSignature)
|
signatures.append(inputSignature)
|
||||||
inputIndex = inputIndex + 1
|
inputIndex = inputIndex + 1
|
||||||
else:
|
if pin != 'paired':
|
||||||
while inputIndex < len(inputs):
|
firstTransaction = False
|
||||||
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:
|
except UserWarning:
|
||||||
self.handler.show_error(_('Cancelled by user'))
|
self.handler.show_error(_('Cancelled by user'))
|
||||||
return
|
return
|
||||||
|
@ -444,7 +391,6 @@ class LedgerPlugin(HW_PluginBase):
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, parent, config, name):
|
def __init__(self, parent, config, name):
|
||||||
self.segwit = config.get("segwit")
|
|
||||||
HW_PluginBase.__init__(self, parent, config, name)
|
HW_PluginBase.__init__(self, parent, config, name)
|
||||||
if self.libraries_available:
|
if self.libraries_available:
|
||||||
self.device_manager().register_devices(self.DEVICE_IDS)
|
self.device_manager().register_devices(self.DEVICE_IDS)
|
||||||
|
|
|
@ -21,9 +21,6 @@ class TrezorCompatibleKeyStore(Hardware_KeyStore):
|
||||||
def get_derivation(self):
|
def get_derivation(self):
|
||||||
return self.derivation
|
return self.derivation
|
||||||
|
|
||||||
def is_segwit(self):
|
|
||||||
return self.derivation.startswith("m/49'/")
|
|
||||||
|
|
||||||
def get_client(self, force_pair=True):
|
def get_client(self, force_pair=True):
|
||||||
return self.plugin.get_client(self, force_pair)
|
return self.plugin.get_client(self, force_pair)
|
||||||
|
|
||||||
|
@ -231,8 +228,8 @@ class TrezorCompatiblePlugin(HW_PluginBase):
|
||||||
self.prev_tx = prev_tx
|
self.prev_tx = prev_tx
|
||||||
self.xpub_path = xpub_path
|
self.xpub_path = xpub_path
|
||||||
client = self.get_client(keystore)
|
client = self.get_client(keystore)
|
||||||
inputs = self.tx_inputs(tx, True, keystore.is_segwit())
|
inputs = self.tx_inputs(tx, True)
|
||||||
outputs = self.tx_outputs(keystore.get_derivation(), tx, keystore.is_segwit())
|
outputs = self.tx_outputs(keystore.get_derivation(), tx)
|
||||||
signed_tx = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[1]
|
signed_tx = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[1]
|
||||||
raw = bh2u(signed_tx)
|
raw = bh2u(signed_tx)
|
||||||
tx.update_signatures(raw)
|
tx.update_signatures(raw)
|
||||||
|
@ -246,11 +243,10 @@ class TrezorCompatiblePlugin(HW_PluginBase):
|
||||||
derivation = wallet.keystore.derivation
|
derivation = wallet.keystore.derivation
|
||||||
address_path = "%s/%d/%d"%(derivation, change, index)
|
address_path = "%s/%d/%d"%(derivation, change, index)
|
||||||
address_n = client.expand_path(address_path)
|
address_n = client.expand_path(address_path)
|
||||||
segwit = wallet.keystore.is_segwit()
|
script_type = self.types.SPENDADDRESS
|
||||||
script_type = self.types.SPENDP2SHWITNESS if segwit else self.types.SPENDADDRESS
|
|
||||||
client.get_address(self.get_coin_name(), address_n, True, script_type=script_type)
|
client.get_address(self.get_coin_name(), address_n, True, script_type=script_type)
|
||||||
|
|
||||||
def tx_inputs(self, tx, for_sig=False, segwit=False):
|
def tx_inputs(self, tx, for_sig=False):
|
||||||
inputs = []
|
inputs = []
|
||||||
for txin in tx.inputs():
|
for txin in tx.inputs():
|
||||||
txinputtype = self.types.TxInputType()
|
txinputtype = self.types.TxInputType()
|
||||||
|
@ -265,7 +261,7 @@ class TrezorCompatiblePlugin(HW_PluginBase):
|
||||||
xpub, s = parse_xpubkey(x_pubkey)
|
xpub, s = parse_xpubkey(x_pubkey)
|
||||||
xpub_n = self.client_class.expand_path(self.xpub_path[xpub])
|
xpub_n = self.client_class.expand_path(self.xpub_path[xpub])
|
||||||
txinputtype.address_n.extend(xpub_n + s)
|
txinputtype.address_n.extend(xpub_n + s)
|
||||||
txinputtype.script_type = self.types.SPENDP2SHWITNESS if segwit else self.types.SPENDADDRESS
|
txinputtype.script_type = self.types.SPENDADDRESS
|
||||||
else:
|
else:
|
||||||
def f(x_pubkey):
|
def f(x_pubkey):
|
||||||
if is_xpubkey(x_pubkey):
|
if is_xpubkey(x_pubkey):
|
||||||
|
@ -281,7 +277,7 @@ class TrezorCompatiblePlugin(HW_PluginBase):
|
||||||
signatures=map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures')),
|
signatures=map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures')),
|
||||||
m=txin.get('num_sig'),
|
m=txin.get('num_sig'),
|
||||||
)
|
)
|
||||||
script_type = self.types.SPENDP2SHWITNESS if segwit else self.types.SPENDMULTISIG
|
script_type = self.types.SPENDMULTISIG
|
||||||
txinputtype = self.types.TxInputType(
|
txinputtype = self.types.TxInputType(
|
||||||
script_type=script_type,
|
script_type=script_type,
|
||||||
multisig=multisig
|
multisig=multisig
|
||||||
|
@ -313,7 +309,7 @@ class TrezorCompatiblePlugin(HW_PluginBase):
|
||||||
|
|
||||||
return inputs
|
return inputs
|
||||||
|
|
||||||
def tx_outputs(self, derivation, tx, segwit=False):
|
def tx_outputs(self, derivation, tx):
|
||||||
outputs = []
|
outputs = []
|
||||||
has_change = False
|
has_change = False
|
||||||
|
|
||||||
|
@ -324,7 +320,7 @@ class TrezorCompatiblePlugin(HW_PluginBase):
|
||||||
addrtype, hash_160 = b58_address_to_hash160(address)
|
addrtype, hash_160 = b58_address_to_hash160(address)
|
||||||
index, xpubs, m = info
|
index, xpubs, m = info
|
||||||
if len(xpubs) == 1:
|
if len(xpubs) == 1:
|
||||||
script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOADDRESS
|
script_type = self.types.PAYTOADDRESS
|
||||||
address_n = self.client_class.expand_path(derivation + "/%d/%d"%index)
|
address_n = self.client_class.expand_path(derivation + "/%d/%d"%index)
|
||||||
txoutputtype = self.types.TxOutputType(
|
txoutputtype = self.types.TxOutputType(
|
||||||
amount = amount,
|
amount = amount,
|
||||||
|
@ -332,7 +328,7 @@ class TrezorCompatiblePlugin(HW_PluginBase):
|
||||||
address_n = address_n,
|
address_n = address_n,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOMULTISIG
|
script_type = self.types.PAYTOMULTISIG
|
||||||
address_n = self.client_class.expand_path("/%d/%d"%index)
|
address_n = self.client_class.expand_path("/%d/%d"%index)
|
||||||
nodes = map(self.ckd_public.deserialize, xpubs)
|
nodes = map(self.ckd_public.deserialize, xpubs)
|
||||||
pubkeys = [ self.types.HDNodePathType(node=node, address_n=address_n) for node in nodes]
|
pubkeys = [ self.types.HDNodePathType(node=node, address_n=address_n) for node in nodes]
|
||||||
|
|
Loading…
Reference in New Issue