SomberNight 7 years ago
parent
commit
88fc62e8f7
No known key found for this signature in database
GPG Key ID: B33B5F232C6271E9
  1. 70
      electrum/plugins/safe_t/safe_t.py
  2. 70
      electrum/plugins/trezor/trezor.py
  3. 3
      electrum/transaction.py
  4. 2
      electrum/wallet.py

70
electrum/plugins/safe_t/safe_t.py

@ -9,7 +9,7 @@ from electrum import constants
from electrum.i18n import _ from electrum.i18n import _
from electrum.plugin import BasePlugin, Device from electrum.plugin import BasePlugin, Device
from electrum.transaction import deserialize, Transaction from electrum.transaction import deserialize, Transaction
from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey, xtype_from_derivation from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
from electrum.base_wizard import ScriptTypeNotSupported from electrum.base_wizard import ScriptTypeNotSupported
from ..hw_wallet import HW_PluginBase from ..hw_wallet import HW_PluginBase
@ -19,9 +19,6 @@ from ..hw_wallet.plugin import is_any_tx_output_on_change_branch, trezor_validat
# Safe-T mini initialization methods # Safe-T mini initialization methods
TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4)
# script "generation"
SCRIPT_GEN_LEGACY, SCRIPT_GEN_P2SH_SEGWIT, SCRIPT_GEN_NATIVE_SEGWIT = range(0, 3)
class SafeTKeyStore(Hardware_KeyStore): class SafeTKeyStore(Hardware_KeyStore):
hw_type = 'safe_t' hw_type = 'safe_t'
@ -30,15 +27,6 @@ class SafeTKeyStore(Hardware_KeyStore):
def get_derivation(self): def get_derivation(self):
return self.derivation return self.derivation
def get_script_gen(self):
xtype = xtype_from_derivation(self.derivation)
if xtype in ('p2wpkh', 'p2wsh'):
return SCRIPT_GEN_NATIVE_SEGWIT
elif xtype in ('p2wpkh-p2sh', 'p2wsh-p2sh'):
return SCRIPT_GEN_P2SH_SEGWIT
else:
return SCRIPT_GEN_LEGACY
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)
@ -294,23 +282,34 @@ class SafeTPlugin(HW_PluginBase):
client.used() client.used()
return xpub return xpub
def get_safet_input_script_type(self, script_gen, is_multisig): def get_safet_input_script_type(self, electrum_txin_type: str):
if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: if electrum_txin_type in ('p2wpkh', 'p2wsh'):
return self.types.InputScriptType.SPENDWITNESS return self.types.InputScriptType.SPENDWITNESS
elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: if electrum_txin_type in ('p2wpkh-p2sh', 'p2wsh-p2sh'):
return self.types.InputScriptType.SPENDP2SHWITNESS return self.types.InputScriptType.SPENDP2SHWITNESS
else: if electrum_txin_type in ('p2pkh', ):
if is_multisig:
return self.types.InputScriptType.SPENDMULTISIG
else:
return self.types.InputScriptType.SPENDADDRESS return self.types.InputScriptType.SPENDADDRESS
if electrum_txin_type in ('p2sh', ):
return self.types.InputScriptType.SPENDMULTISIG
raise ValueError('unexpected txin type: {}'.format(electrum_txin_type))
def get_safet_output_script_type(self, electrum_txin_type: str):
if electrum_txin_type in ('p2wpkh', 'p2wsh'):
return self.types.OutputScriptType.PAYTOWITNESS
if electrum_txin_type in ('p2wpkh-p2sh', 'p2wsh-p2sh'):
return self.types.OutputScriptType.PAYTOP2SHWITNESS
if electrum_txin_type in ('p2pkh', ):
return self.types.OutputScriptType.PAYTOADDRESS
if electrum_txin_type in ('p2sh', ):
return self.types.OutputScriptType.PAYTOMULTISIG
raise ValueError('unexpected txin type: {}'.format(electrum_txin_type))
def sign_transaction(self, keystore, tx, prev_tx, xpub_path): def sign_transaction(self, keystore, tx, prev_tx, xpub_path):
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.get_script_gen()) inputs = self.tx_inputs(tx, True)
outputs = self.tx_outputs(keystore.get_derivation(), tx, keystore.get_script_gen()) outputs = self.tx_outputs(keystore.get_derivation(), tx)
signatures = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[0] signatures = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[0]
signatures = [(bh2u(x) + '01') for x in signatures] signatures = [(bh2u(x) + '01') for x in signatures]
tx.update_signatures(signatures) tx.update_signatures(signatures)
@ -330,8 +329,7 @@ class SafeTPlugin(HW_PluginBase):
address_n = client.expand_path(address_path) address_n = client.expand_path(address_path)
xpubs = wallet.get_master_public_keys() xpubs = wallet.get_master_public_keys()
if len(xpubs) == 1: if len(xpubs) == 1:
script_gen = keystore.get_script_gen() script_type = self.get_safet_input_script_type(wallet.txin_type)
script_type = self.get_safet_input_script_type(script_gen, is_multisig=False)
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)
else: else:
def f(xpub): def f(xpub):
@ -345,11 +343,10 @@ class SafeTPlugin(HW_PluginBase):
signatures=[b''] * wallet.n, signatures=[b''] * wallet.n,
m=wallet.m, m=wallet.m,
) )
script_gen = keystore.get_script_gen() script_type = self.get_safet_input_script_type(wallet.txin_type)
script_type = self.get_safet_input_script_type(script_gen, is_multisig=True)
client.get_address(self.get_coin_name(), address_n, True, multisig=multisig, script_type=script_type) client.get_address(self.get_coin_name(), address_n, True, multisig=multisig, script_type=script_type)
def tx_inputs(self, tx, for_sig=False, script_gen=SCRIPT_GEN_LEGACY): 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()
@ -364,7 +361,7 @@ class SafeTPlugin(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._extend_address_n(xpub_n + s) txinputtype._extend_address_n(xpub_n + s)
txinputtype.script_type = self.get_safet_input_script_type(script_gen, is_multisig=False) txinputtype.script_type = self.get_safet_input_script_type(txin['type'])
else: else:
def f(x_pubkey): def f(x_pubkey):
if is_xpubkey(x_pubkey): if is_xpubkey(x_pubkey):
@ -379,7 +376,7 @@ class SafeTPlugin(HW_PluginBase):
signatures=list(map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures'))), signatures=list(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.get_safet_input_script_type(script_gen, is_multisig=True) script_type = self.get_safet_input_script_type(txin['type'])
txinputtype = self.types.TxInputType( txinputtype = self.types.TxInputType(
script_type=script_type, script_type=script_type,
multisig=multisig multisig=multisig
@ -411,16 +408,11 @@ class SafeTPlugin(HW_PluginBase):
return inputs return inputs
def tx_outputs(self, derivation, tx, script_gen=SCRIPT_GEN_LEGACY): def tx_outputs(self, derivation, tx):
def create_output_by_derivation(): def create_output_by_derivation():
script_type = self.get_trezor_output_script_type(info.script_type)
if len(xpubs) == 1: if len(xpubs) == 1:
if script_gen == SCRIPT_GEN_NATIVE_SEGWIT:
script_type = self.types.OutputScriptType.PAYTOWITNESS
elif script_gen == SCRIPT_GEN_P2SH_SEGWIT:
script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS
else:
script_type = self.types.OutputScriptType.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,
@ -428,12 +420,6 @@ class SafeTPlugin(HW_PluginBase):
address_n=address_n, address_n=address_n,
) )
else: else:
if script_gen == SCRIPT_GEN_NATIVE_SEGWIT:
script_type = self.types.OutputScriptType.PAYTOWITNESS
elif script_gen == SCRIPT_GEN_P2SH_SEGWIT:
script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS
else:
script_type = self.types.OutputScriptType.PAYTOMULTISIG
address_n = self.client_class.expand_path("/%d/%d" % index) address_n = self.client_class.expand_path("/%d/%d" % index)
pubkeys = [self._make_node_path(xpub, address_n) for xpub in xpubs] pubkeys = [self._make_node_path(xpub, address_n) for xpub in xpubs]
multisig = self.types.MultisigRedeemScriptType( multisig = self.types.MultisigRedeemScriptType(

70
electrum/plugins/trezor/trezor.py

@ -9,7 +9,7 @@ from electrum import constants
from electrum.i18n import _ from electrum.i18n import _
from electrum.plugin import BasePlugin, Device from electrum.plugin import BasePlugin, Device
from electrum.transaction import deserialize, Transaction from electrum.transaction import deserialize, Transaction
from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey, xtype_from_derivation from electrum.keystore import Hardware_KeyStore, is_xpubkey, parse_xpubkey
from electrum.base_wizard import ScriptTypeNotSupported from electrum.base_wizard import ScriptTypeNotSupported
from ..hw_wallet import HW_PluginBase from ..hw_wallet import HW_PluginBase
@ -20,9 +20,6 @@ from ..hw_wallet.plugin import is_any_tx_output_on_change_branch, trezor_validat
TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4)
RECOVERY_TYPE_SCRAMBLED_WORDS, RECOVERY_TYPE_MATRIX = range(0, 2) RECOVERY_TYPE_SCRAMBLED_WORDS, RECOVERY_TYPE_MATRIX = range(0, 2)
# script "generation"
SCRIPT_GEN_LEGACY, SCRIPT_GEN_P2SH_SEGWIT, SCRIPT_GEN_NATIVE_SEGWIT = range(0, 3)
class TrezorKeyStore(Hardware_KeyStore): class TrezorKeyStore(Hardware_KeyStore):
hw_type = 'trezor' hw_type = 'trezor'
@ -31,15 +28,6 @@ class TrezorKeyStore(Hardware_KeyStore):
def get_derivation(self): def get_derivation(self):
return self.derivation return self.derivation
def get_script_gen(self):
xtype = xtype_from_derivation(self.derivation)
if xtype in ('p2wpkh', 'p2wsh'):
return SCRIPT_GEN_NATIVE_SEGWIT
elif xtype in ('p2wpkh-p2sh', 'p2wsh-p2sh'):
return SCRIPT_GEN_P2SH_SEGWIT
else:
return SCRIPT_GEN_LEGACY
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)
@ -305,23 +293,34 @@ class TrezorPlugin(HW_PluginBase):
client.used() client.used()
return xpub return xpub
def get_trezor_input_script_type(self, script_gen, is_multisig): def get_trezor_input_script_type(self, electrum_txin_type: str):
if script_gen == SCRIPT_GEN_NATIVE_SEGWIT: if electrum_txin_type in ('p2wpkh', 'p2wsh'):
return self.types.InputScriptType.SPENDWITNESS return self.types.InputScriptType.SPENDWITNESS
elif script_gen == SCRIPT_GEN_P2SH_SEGWIT: if electrum_txin_type in ('p2wpkh-p2sh', 'p2wsh-p2sh'):
return self.types.InputScriptType.SPENDP2SHWITNESS return self.types.InputScriptType.SPENDP2SHWITNESS
else: if electrum_txin_type in ('p2pkh', ):
if is_multisig:
return self.types.InputScriptType.SPENDMULTISIG
else:
return self.types.InputScriptType.SPENDADDRESS return self.types.InputScriptType.SPENDADDRESS
if electrum_txin_type in ('p2sh', ):
return self.types.InputScriptType.SPENDMULTISIG
raise ValueError('unexpected txin type: {}'.format(electrum_txin_type))
def get_trezor_output_script_type(self, electrum_txin_type: str):
if electrum_txin_type in ('p2wpkh', 'p2wsh'):
return self.types.OutputScriptType.PAYTOWITNESS
if electrum_txin_type in ('p2wpkh-p2sh', 'p2wsh-p2sh'):
return self.types.OutputScriptType.PAYTOP2SHWITNESS
if electrum_txin_type in ('p2pkh', ):
return self.types.OutputScriptType.PAYTOADDRESS
if electrum_txin_type in ('p2sh', ):
return self.types.OutputScriptType.PAYTOMULTISIG
raise ValueError('unexpected txin type: {}'.format(electrum_txin_type))
def sign_transaction(self, keystore, tx, prev_tx, xpub_path): def sign_transaction(self, keystore, tx, prev_tx, xpub_path):
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.get_script_gen()) inputs = self.tx_inputs(tx, True)
outputs = self.tx_outputs(keystore.get_derivation(), tx, keystore.get_script_gen()) outputs = self.tx_outputs(keystore.get_derivation(), tx)
signatures = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[0] signatures = client.sign_tx(self.get_coin_name(), inputs, outputs, lock_time=tx.locktime)[0]
signatures = [(bh2u(x) + '01') for x in signatures] signatures = [(bh2u(x) + '01') for x in signatures]
tx.update_signatures(signatures) tx.update_signatures(signatures)
@ -341,8 +340,7 @@ class TrezorPlugin(HW_PluginBase):
address_n = client.expand_path(address_path) address_n = client.expand_path(address_path)
xpubs = wallet.get_master_public_keys() xpubs = wallet.get_master_public_keys()
if len(xpubs) == 1: if len(xpubs) == 1:
script_gen = keystore.get_script_gen() script_type = self.get_trezor_input_script_type(wallet.txin_type)
script_type = self.get_trezor_input_script_type(script_gen, is_multisig=False)
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)
else: else:
def f(xpub): def f(xpub):
@ -356,11 +354,10 @@ class TrezorPlugin(HW_PluginBase):
signatures=[b''] * wallet.n, signatures=[b''] * wallet.n,
m=wallet.m, m=wallet.m,
) )
script_gen = keystore.get_script_gen() script_type = self.get_trezor_input_script_type(wallet.txin_type)
script_type = self.get_trezor_input_script_type(script_gen, is_multisig=True)
client.get_address(self.get_coin_name(), address_n, True, multisig=multisig, script_type=script_type) client.get_address(self.get_coin_name(), address_n, True, multisig=multisig, script_type=script_type)
def tx_inputs(self, tx, for_sig=False, script_gen=SCRIPT_GEN_LEGACY): 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()
@ -375,7 +372,7 @@ class TrezorPlugin(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._extend_address_n(xpub_n + s) txinputtype._extend_address_n(xpub_n + s)
txinputtype.script_type = self.get_trezor_input_script_type(script_gen, is_multisig=False) txinputtype.script_type = self.get_trezor_input_script_type(txin['type'])
else: else:
def f(x_pubkey): def f(x_pubkey):
if is_xpubkey(x_pubkey): if is_xpubkey(x_pubkey):
@ -390,7 +387,7 @@ class TrezorPlugin(HW_PluginBase):
signatures=list(map(lambda x: bfh(x)[:-1] if x else b'', txin.get('signatures'))), signatures=list(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.get_trezor_input_script_type(script_gen, is_multisig=True) script_type = self.get_trezor_input_script_type(txin['type'])
txinputtype = self.types.TxInputType( txinputtype = self.types.TxInputType(
script_type=script_type, script_type=script_type,
multisig=multisig multisig=multisig
@ -422,16 +419,11 @@ class TrezorPlugin(HW_PluginBase):
return inputs return inputs
def tx_outputs(self, derivation, tx, script_gen=SCRIPT_GEN_LEGACY): def tx_outputs(self, derivation, tx):
def create_output_by_derivation(): def create_output_by_derivation():
script_type = self.get_trezor_output_script_type(info.script_type)
if len(xpubs) == 1: if len(xpubs) == 1:
if script_gen == SCRIPT_GEN_NATIVE_SEGWIT:
script_type = self.types.OutputScriptType.PAYTOWITNESS
elif script_gen == SCRIPT_GEN_P2SH_SEGWIT:
script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS
else:
script_type = self.types.OutputScriptType.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,
@ -439,12 +431,6 @@ class TrezorPlugin(HW_PluginBase):
address_n=address_n, address_n=address_n,
) )
else: else:
if script_gen == SCRIPT_GEN_NATIVE_SEGWIT:
script_type = self.types.OutputScriptType.PAYTOWITNESS
elif script_gen == SCRIPT_GEN_P2SH_SEGWIT:
script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS
else:
script_type = self.types.OutputScriptType.PAYTOMULTISIG
address_n = self.client_class.expand_path("/%d/%d" % index) address_n = self.client_class.expand_path("/%d/%d" % index)
pubkeys = [self._make_node_path(xpub, address_n) for xpub in xpubs] pubkeys = [self._make_node_path(xpub, address_n) for xpub in xpubs]
multisig = self.types.MultisigRedeemScriptType( multisig = self.types.MultisigRedeemScriptType(

3
electrum/transaction.py

@ -65,7 +65,8 @@ TxOutput = NamedTuple("TxOutput", [('type', int), ('address', str), ('value', Un
TxOutputHwInfo = NamedTuple("TxOutputHwInfo", [('address_index', Tuple), TxOutputHwInfo = NamedTuple("TxOutputHwInfo", [('address_index', Tuple),
('sorted_xpubs', Iterable[str]), ('sorted_xpubs', Iterable[str]),
('num_sig', Optional[int])]) ('num_sig', Optional[int]),
('script_type', str)])
class BCDataStream(object): class BCDataStream(object):

2
electrum/wallet.py

@ -787,7 +787,7 @@ class Abstract_Wallet(AddressSynchronizer):
# sort xpubs using the order of pubkeys # sort xpubs using the order of pubkeys
sorted_pubkeys, sorted_xpubs = zip(*sorted(zip(pubkeys, xpubs))) sorted_pubkeys, sorted_xpubs = zip(*sorted(zip(pubkeys, xpubs)))
num_sig = self.m if isinstance(self, Multisig_Wallet) else None num_sig = self.m if isinstance(self, Multisig_Wallet) else None
info[addr] = TxOutputHwInfo(index, sorted_xpubs, num_sig) info[addr] = TxOutputHwInfo(index, sorted_xpubs, num_sig, self.txin_type)
tx.output_info = info tx.output_info = info
def sign_transaction(self, tx, password): def sign_transaction(self, tx, password):

Loading…
Cancel
Save