Merge pull request #4148 from SomberNight/hw_wallet_output_ismine_der
trezor/keepkey/dbb: provide derivation info for all is_mine txn outputs
This commit is contained in:
commit
f8f00188ed
@ -1444,7 +1444,7 @@ class Abstract_Wallet(PrintError):
|
|||||||
xpubs = self.get_master_public_keys()
|
xpubs = self.get_master_public_keys()
|
||||||
for txout in tx.outputs():
|
for txout in tx.outputs():
|
||||||
_type, addr, amount = txout
|
_type, addr, amount = txout
|
||||||
if self.is_change(addr):
|
if self.is_mine(addr):
|
||||||
index = self.get_address_index(addr)
|
index = self.get_address_index(addr)
|
||||||
pubkeys = self.get_public_keys(addr)
|
pubkeys = self.get_public_keys(addr)
|
||||||
# sort xpubs using the order of pubkeys
|
# sort xpubs using the order of pubkeys
|
||||||
|
|||||||
@ -303,56 +303,83 @@ class KeepKeyCompatiblePlugin(HW_PluginBase):
|
|||||||
return inputs
|
return inputs
|
||||||
|
|
||||||
def tx_outputs(self, derivation, tx, segwit=False):
|
def tx_outputs(self, derivation, tx, segwit=False):
|
||||||
|
|
||||||
|
def create_output_by_derivation(info):
|
||||||
|
index, xpubs, m = info
|
||||||
|
if len(xpubs) == 1:
|
||||||
|
script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOADDRESS
|
||||||
|
address_n = self.client_class.expand_path(derivation + "/%d/%d" % index)
|
||||||
|
txoutputtype = self.types.TxOutputType(
|
||||||
|
amount=amount,
|
||||||
|
script_type=script_type,
|
||||||
|
address_n=address_n,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOMULTISIG
|
||||||
|
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''] * len(pubkeys),
|
||||||
|
m=m)
|
||||||
|
txoutputtype = self.types.TxOutputType(
|
||||||
|
multisig=multisig,
|
||||||
|
amount=amount,
|
||||||
|
address_n=self.client_class.expand_path(derivation + "/%d/%d" % index),
|
||||||
|
script_type=script_type)
|
||||||
|
return txoutputtype
|
||||||
|
|
||||||
|
def create_output_by_address():
|
||||||
|
txoutputtype = self.types.TxOutputType()
|
||||||
|
txoutputtype.amount = amount
|
||||||
|
if _type == TYPE_SCRIPT:
|
||||||
|
txoutputtype.script_type = self.types.PAYTOOPRETURN
|
||||||
|
txoutputtype.op_return_data = address[2:]
|
||||||
|
elif _type == TYPE_ADDRESS:
|
||||||
|
if is_segwit_address(address):
|
||||||
|
txoutputtype.script_type = self.types.PAYTOWITNESS
|
||||||
|
else:
|
||||||
|
addrtype, hash_160 = b58_address_to_hash160(address)
|
||||||
|
if addrtype == constants.net.ADDRTYPE_P2PKH:
|
||||||
|
txoutputtype.script_type = self.types.PAYTOADDRESS
|
||||||
|
elif addrtype == constants.net.ADDRTYPE_P2SH:
|
||||||
|
txoutputtype.script_type = self.types.PAYTOSCRIPTHASH
|
||||||
|
else:
|
||||||
|
raise BaseException('addrtype: ' + str(addrtype))
|
||||||
|
txoutputtype.address = address
|
||||||
|
return txoutputtype
|
||||||
|
|
||||||
|
def is_any_output_on_change_branch():
|
||||||
|
for _type, address, amount in tx.outputs():
|
||||||
|
info = tx.output_info.get(address)
|
||||||
|
if info is not None:
|
||||||
|
index, xpubs, m = info
|
||||||
|
if index[0] == 1:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
outputs = []
|
outputs = []
|
||||||
has_change = False
|
has_change = False
|
||||||
|
any_output_on_change_branch = is_any_output_on_change_branch()
|
||||||
|
|
||||||
for _type, address, amount in tx.outputs():
|
for _type, address, amount in tx.outputs():
|
||||||
|
use_create_by_derivation = False
|
||||||
|
|
||||||
info = tx.output_info.get(address)
|
info = tx.output_info.get(address)
|
||||||
if info is not None and not has_change:
|
if info is not None and not has_change:
|
||||||
has_change = True # no more than one change address
|
|
||||||
addrtype, hash_160 = b58_address_to_hash160(address)
|
|
||||||
index, xpubs, m = info
|
index, xpubs, m = info
|
||||||
if len(xpubs) == 1:
|
on_change_branch = index[0] == 1
|
||||||
script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOADDRESS
|
# prioritise hiding outputs on the 'change' branch from user
|
||||||
address_n = self.client_class.expand_path(derivation + "/%d/%d"%index)
|
# because no more than one change address allowed
|
||||||
txoutputtype = self.types.TxOutputType(
|
if on_change_branch == any_output_on_change_branch:
|
||||||
amount = amount,
|
use_create_by_derivation = True
|
||||||
script_type = script_type,
|
has_change = True
|
||||||
address_n = address_n,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOMULTISIG
|
|
||||||
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''] * len(pubkeys),
|
|
||||||
m = m)
|
|
||||||
txoutputtype = self.types.TxOutputType(
|
|
||||||
multisig = multisig,
|
|
||||||
amount = amount,
|
|
||||||
address_n = self.client_class.expand_path(derivation + "/%d/%d"%index),
|
|
||||||
script_type = script_type)
|
|
||||||
else:
|
|
||||||
txoutputtype = self.types.TxOutputType()
|
|
||||||
txoutputtype.amount = amount
|
|
||||||
if _type == TYPE_SCRIPT:
|
|
||||||
txoutputtype.script_type = self.types.PAYTOOPRETURN
|
|
||||||
txoutputtype.op_return_data = address[2:]
|
|
||||||
elif _type == TYPE_ADDRESS:
|
|
||||||
if is_segwit_address(address):
|
|
||||||
txoutputtype.script_type = self.types.PAYTOWITNESS
|
|
||||||
else:
|
|
||||||
addrtype, hash_160 = b58_address_to_hash160(address)
|
|
||||||
if addrtype == constants.net.ADDRTYPE_P2PKH:
|
|
||||||
txoutputtype.script_type = self.types.PAYTOADDRESS
|
|
||||||
elif addrtype == constants.net.ADDRTYPE_P2SH:
|
|
||||||
txoutputtype.script_type = self.types.PAYTOSCRIPTHASH
|
|
||||||
else:
|
|
||||||
raise BaseException('addrtype: ' + str(addrtype))
|
|
||||||
txoutputtype.address = address
|
|
||||||
|
|
||||||
|
if use_create_by_derivation:
|
||||||
|
txoutputtype = create_output_by_derivation(info)
|
||||||
|
else:
|
||||||
|
txoutputtype = create_output_by_address()
|
||||||
outputs.append(txoutputtype)
|
outputs.append(txoutputtype)
|
||||||
|
|
||||||
return outputs
|
return outputs
|
||||||
|
|||||||
@ -377,7 +377,8 @@ class Ledger_KeyStore(Hardware_KeyStore):
|
|||||||
for _type, address, amount in tx.outputs():
|
for _type, address, amount in tx.outputs():
|
||||||
assert _type == TYPE_ADDRESS
|
assert _type == TYPE_ADDRESS
|
||||||
info = tx.output_info.get(address)
|
info = tx.output_info.get(address)
|
||||||
if (info is not None) and (len(tx.outputs()) != 1):
|
if (info is not None) and len(tx.outputs()) > 1 \
|
||||||
|
and info[0][0] == 1: # "is on 'change' branch"
|
||||||
index, xpubs, m = info
|
index, xpubs, m = info
|
||||||
changePath = self.get_derivation()[2:] + "/%d/%d"%index
|
changePath = self.get_derivation()[2:] + "/%d/%d"%index
|
||||||
changeAmount = amount
|
changeAmount = amount
|
||||||
|
|||||||
@ -380,56 +380,86 @@ 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, script_gen=SCRIPT_GEN_LEGACY):
|
||||||
|
|
||||||
|
def create_output_by_derivation(info):
|
||||||
|
index, xpubs, m = info
|
||||||
|
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)
|
||||||
|
txoutputtype = self.types.TxOutputType(
|
||||||
|
amount=amount,
|
||||||
|
script_type=script_type,
|
||||||
|
address_n=address_n,
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
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''] * len(pubkeys),
|
||||||
|
m=m)
|
||||||
|
txoutputtype = self.types.TxOutputType(
|
||||||
|
multisig=multisig,
|
||||||
|
amount=amount,
|
||||||
|
address_n=self.client_class.expand_path(derivation + "/%d/%d" % index),
|
||||||
|
script_type=script_type)
|
||||||
|
return txoutputtype
|
||||||
|
|
||||||
|
def create_output_by_address():
|
||||||
|
txoutputtype = self.types.TxOutputType()
|
||||||
|
txoutputtype.amount = amount
|
||||||
|
if _type == TYPE_SCRIPT:
|
||||||
|
txoutputtype.script_type = self.types.OutputScriptType.PAYTOOPRETURN
|
||||||
|
txoutputtype.op_return_data = address[2:]
|
||||||
|
elif _type == TYPE_ADDRESS:
|
||||||
|
txoutputtype.script_type = self.types.OutputScriptType.PAYTOADDRESS
|
||||||
|
txoutputtype.address = address
|
||||||
|
return txoutputtype
|
||||||
|
|
||||||
|
def is_any_output_on_change_branch():
|
||||||
|
for _type, address, amount in tx.outputs():
|
||||||
|
info = tx.output_info.get(address)
|
||||||
|
if info is not None:
|
||||||
|
index, xpubs, m = info
|
||||||
|
if index[0] == 1:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
outputs = []
|
outputs = []
|
||||||
has_change = False
|
has_change = False
|
||||||
|
any_output_on_change_branch = is_any_output_on_change_branch()
|
||||||
|
|
||||||
for _type, address, amount in tx.outputs():
|
for _type, address, amount in tx.outputs():
|
||||||
|
use_create_by_derivation = False
|
||||||
|
|
||||||
info = tx.output_info.get(address)
|
info = tx.output_info.get(address)
|
||||||
if info is not None and not has_change:
|
if info is not None and not has_change:
|
||||||
has_change = True # no more than one change address
|
|
||||||
index, xpubs, m = info
|
index, xpubs, m = info
|
||||||
if len(xpubs) == 1:
|
on_change_branch = index[0] == 1
|
||||||
if script_gen == SCRIPT_GEN_NATIVE_SEGWIT:
|
# prioritise hiding outputs on the 'change' branch from user
|
||||||
script_type = self.types.OutputScriptType.PAYTOWITNESS
|
# because no more than one change address allowed
|
||||||
elif script_gen == SCRIPT_GEN_P2SH_SEGWIT:
|
# note: ^ restriction can be removed once we require fw
|
||||||
script_type = self.types.OutputScriptType.PAYTOP2SHWITNESS
|
# that has https://github.com/trezor/trezor-mcu/pull/306
|
||||||
else:
|
if on_change_branch == any_output_on_change_branch:
|
||||||
script_type = self.types.OutputScriptType.PAYTOADDRESS
|
use_create_by_derivation = True
|
||||||
address_n = self.client_class.expand_path(derivation + "/%d/%d"%index)
|
has_change = True
|
||||||
txoutputtype = self.types.TxOutputType(
|
|
||||||
amount = amount,
|
|
||||||
script_type = script_type,
|
|
||||||
address_n = address_n,
|
|
||||||
)
|
|
||||||
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)
|
|
||||||
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''] * len(pubkeys),
|
|
||||||
m = m)
|
|
||||||
txoutputtype = self.types.TxOutputType(
|
|
||||||
multisig = multisig,
|
|
||||||
amount = amount,
|
|
||||||
address_n = self.client_class.expand_path(derivation + "/%d/%d"%index),
|
|
||||||
script_type = script_type)
|
|
||||||
else:
|
|
||||||
txoutputtype = self.types.TxOutputType()
|
|
||||||
txoutputtype.amount = amount
|
|
||||||
if _type == TYPE_SCRIPT:
|
|
||||||
txoutputtype.script_type = self.types.OutputScriptType.PAYTOOPRETURN
|
|
||||||
txoutputtype.op_return_data = address[2:]
|
|
||||||
elif _type == TYPE_ADDRESS:
|
|
||||||
txoutputtype.script_type = self.types.OutputScriptType.PAYTOADDRESS
|
|
||||||
txoutputtype.address = address
|
|
||||||
|
|
||||||
|
if use_create_by_derivation:
|
||||||
|
txoutputtype = create_output_by_derivation(info)
|
||||||
|
else:
|
||||||
|
txoutputtype = create_output_by_address()
|
||||||
outputs.append(txoutputtype)
|
outputs.append(txoutputtype)
|
||||||
|
|
||||||
return outputs
|
return outputs
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user