mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-29 10:58:21 +00:00
feat(core):: support sortedmulti
This commit is contained in:
parent
5c6198cf13
commit
d19cbfa3cb
1
core/.changelog.d/4351.added
Normal file
1
core/.changelog.d/4351.added
Normal file
@ -0,0 +1 @@
|
|||||||
|
Added support for sortedmulti.
|
@ -1,5 +1,6 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from trezor.enums import MultisigPubkeysOrder
|
||||||
from trezor.wire import DataError
|
from trezor.wire import DataError
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -28,6 +29,7 @@ def multisig_fingerprint(multisig: MultisigRedeemScriptType) -> bytes:
|
|||||||
if len(d.public_key) != 33 or len(d.chain_code) != 32:
|
if len(d.public_key) != 33 or len(d.chain_code) != 32:
|
||||||
raise DataError("Invalid multisig parameters")
|
raise DataError("Invalid multisig parameters")
|
||||||
|
|
||||||
|
if multisig.pubkeys_order == MultisigPubkeysOrder.LEXICOGRAPHIC:
|
||||||
pubnodes = sorted(pubnodes, key=lambda n: n.public_key + n.chain_code)
|
pubnodes = sorted(pubnodes, key=lambda n: n.public_key + n.chain_code)
|
||||||
|
|
||||||
h = HashWriter(sha256())
|
h = HashWriter(sha256())
|
||||||
@ -84,9 +86,14 @@ def multisig_get_pubkey(n: HDNodeType, p: paths.Bip32Path) -> bytes:
|
|||||||
def multisig_get_pubkeys(multisig: MultisigRedeemScriptType) -> list[bytes]:
|
def multisig_get_pubkeys(multisig: MultisigRedeemScriptType) -> list[bytes]:
|
||||||
validate_multisig(multisig)
|
validate_multisig(multisig)
|
||||||
if multisig.nodes:
|
if multisig.nodes:
|
||||||
return [multisig_get_pubkey(hd, multisig.address_n) for hd in multisig.nodes]
|
pubkeys = [multisig_get_pubkey(hd, multisig.address_n) for hd in multisig.nodes]
|
||||||
else:
|
else:
|
||||||
return [multisig_get_pubkey(hd.node, hd.address_n) for hd in multisig.pubkeys]
|
pubkeys = [
|
||||||
|
multisig_get_pubkey(hd.node, hd.address_n) for hd in multisig.pubkeys
|
||||||
|
]
|
||||||
|
if multisig.pubkeys_order == MultisigPubkeysOrder.LEXICOGRAPHIC:
|
||||||
|
pubkeys = sorted(pubkeys)
|
||||||
|
return pubkeys
|
||||||
|
|
||||||
|
|
||||||
def multisig_get_pubkey_count(multisig: MultisigRedeemScriptType) -> int:
|
def multisig_get_pubkey_count(multisig: MultisigRedeemScriptType) -> int:
|
||||||
|
@ -19,6 +19,7 @@ class ChangeDetector:
|
|||||||
from .matchcheck import (
|
from .matchcheck import (
|
||||||
MultisigChecker,
|
MultisigChecker,
|
||||||
MultisigFingerprintChecker,
|
MultisigFingerprintChecker,
|
||||||
|
PubkeysOrderChecker,
|
||||||
ScriptTypeChecker,
|
ScriptTypeChecker,
|
||||||
WalletPathChecker,
|
WalletPathChecker,
|
||||||
)
|
)
|
||||||
@ -29,6 +30,9 @@ class ChangeDetector:
|
|||||||
# Checksum of multisig inputs, used to validate change-output.
|
# Checksum of multisig inputs, used to validate change-output.
|
||||||
self.multisig_fingerprint = MultisigFingerprintChecker()
|
self.multisig_fingerprint = MultisigFingerprintChecker()
|
||||||
|
|
||||||
|
# Whether all inputs use sorted pubkeys or all inputs use unsorted pubkeys, used to validate change-output.
|
||||||
|
self.pubkeys_order = PubkeysOrderChecker()
|
||||||
|
|
||||||
# Common prefix of input paths, used to validate change-output.
|
# Common prefix of input paths, used to validate change-output.
|
||||||
self.wallet_path = WalletPathChecker()
|
self.wallet_path = WalletPathChecker()
|
||||||
|
|
||||||
@ -41,18 +45,24 @@ class ChangeDetector:
|
|||||||
self.script_type.add_input(txi)
|
self.script_type.add_input(txi)
|
||||||
self.multisig_fingerprint.add_input(txi)
|
self.multisig_fingerprint.add_input(txi)
|
||||||
self.multisig.add_input(txi)
|
self.multisig.add_input(txi)
|
||||||
|
self.pubkeys_order.add_input(txi)
|
||||||
|
|
||||||
def check_input(self, txi: TxInput) -> None:
|
def check_input(self, txi: TxInput) -> None:
|
||||||
self.wallet_path.check_input(txi)
|
self.wallet_path.check_input(txi)
|
||||||
self.script_type.check_input(txi)
|
self.script_type.check_input(txi)
|
||||||
self.multisig_fingerprint.check_input(txi)
|
self.multisig_fingerprint.check_input(txi)
|
||||||
self.multisig.check_input(txi)
|
self.multisig.check_input(txi)
|
||||||
|
self.pubkeys_order.check_input(txi)
|
||||||
|
|
||||||
def output_is_change(self, txo: TxOutput) -> bool:
|
def output_is_change(self, txo: TxOutput) -> bool:
|
||||||
if txo.script_type not in common.CHANGE_OUTPUT_SCRIPT_TYPES:
|
if txo.script_type not in common.CHANGE_OUTPUT_SCRIPT_TYPES:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if txo.multisig and not self.multisig_fingerprint.output_matches(txo):
|
if txo.multisig:
|
||||||
|
if not (
|
||||||
|
self.pubkeys_order.output_matches(txo)
|
||||||
|
and self.multisig_fingerprint.output_matches(txo)
|
||||||
|
):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -107,6 +107,13 @@ class MultisigFingerprintChecker(MatchChecker):
|
|||||||
return multisig.multisig_fingerprint(txio.multisig)
|
return multisig.multisig_fingerprint(txio.multisig)
|
||||||
|
|
||||||
|
|
||||||
|
class PubkeysOrderChecker(MatchChecker):
|
||||||
|
def attribute_from_tx(self, txio: TxInput | TxOutput) -> Any:
|
||||||
|
if not txio.multisig:
|
||||||
|
return None
|
||||||
|
return txio.multisig is not None and txio.multisig.pubkeys_order
|
||||||
|
|
||||||
|
|
||||||
class MultisigChecker(MatchChecker):
|
class MultisigChecker(MatchChecker):
|
||||||
def attribute_from_tx(self, txio: TxInput | TxOutput) -> Any:
|
def attribute_from_tx(self, txio: TxInput | TxOutput) -> Any:
|
||||||
return txio.multisig is not None
|
return txio.multisig is not None
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from common import H_, await_result, unittest # isort:skip
|
from common import H_, await_result, unittest # isort:skip
|
||||||
from ubinascii import hexlify, unhexlify
|
from ubinascii import hexlify, unhexlify
|
||||||
|
|
||||||
from trezor.enums import InputScriptType, OutputScriptType
|
from trezor.enums import InputScriptType, OutputScriptType, MultisigPubkeysOrder
|
||||||
|
from trezor.enums.MultisigPubkeysOrder import LEXICOGRAPHIC, PRESERVED
|
||||||
from trezor.messages import (
|
from trezor.messages import (
|
||||||
TxInput,
|
TxInput,
|
||||||
TxOutput,
|
TxOutput,
|
||||||
@ -39,12 +40,13 @@ xpub3 = HDNodeType(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_multisig(path: list[int], xpubs: list[HDNodeType]) -> MultisigRedeemScriptType:
|
def get_multisig(path: list[int], xpubs: list[HDNodeType], pubkeys_order: MultisigPubkeysOrder) -> MultisigRedeemScriptType:
|
||||||
return MultisigRedeemScriptType(
|
return MultisigRedeemScriptType(
|
||||||
nodes=xpubs,
|
nodes=xpubs,
|
||||||
signatures=b"" * len(xpubs),
|
signatures=b"" * len(xpubs),
|
||||||
address_n=path[-2:],
|
address_n=path[-2:],
|
||||||
m=2,
|
m=2,
|
||||||
|
pubkeys_order=pubkeys_order,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -58,23 +60,23 @@ def get_singlesig_input(path: list[int]) -> TxInput:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_multisig_input(path: list[int], xpubs: list[HDNodeType]) -> TxInput:
|
def get_multisig_input(path: list[int], xpubs: list[HDNodeType], pubkeys_order: MultisigPubkeysOrder) -> TxInput:
|
||||||
return TxInput(
|
return TxInput(
|
||||||
address_n=path,
|
address_n=path,
|
||||||
amount=1_000_000,
|
amount=1_000_000,
|
||||||
prev_hash=bytes(32),
|
prev_hash=bytes(32),
|
||||||
prev_index=0,
|
prev_index=0,
|
||||||
script_type=InputScriptType.SPENDMULTISIG,
|
script_type=InputScriptType.SPENDMULTISIG,
|
||||||
multisig=get_multisig(path, xpubs),
|
multisig=get_multisig(path, xpubs, pubkeys_order),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_internal_multisig_output(path: list[int], xpubs: list[HDNodeType]) -> TxOutput:
|
def get_internal_multisig_output(path: list[int], xpubs: list[HDNodeType], pubkeys_order: MultisigPubkeysOrder) -> TxOutput:
|
||||||
return TxOutput(
|
return TxOutput(
|
||||||
address_n=path,
|
address_n=path,
|
||||||
amount=1_000_000,
|
amount=1_000_000,
|
||||||
script_type=OutputScriptType.PAYTOMULTISIG,
|
script_type=OutputScriptType.PAYTOMULTISIG,
|
||||||
multisig=get_multisig(path, xpubs),
|
multisig=get_multisig(path, xpubs, pubkeys_order),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -115,7 +117,8 @@ class TestChangeDetector(unittest.TestCase):
|
|||||||
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 1, 0, 0])) == False
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 1, 0, 0])) == False
|
||||||
|
|
||||||
# Multisig instead of singlesig
|
# Multisig instead of singlesig
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1])) == False
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1], PRESERVED)) == False
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1], LEXICOGRAPHIC)) == False
|
||||||
|
|
||||||
# External output
|
# External output
|
||||||
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
||||||
@ -130,23 +133,24 @@ class TestChangeDetector(unittest.TestCase):
|
|||||||
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 1, 0, 0])) == False
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 1, 0, 0])) == False
|
||||||
|
|
||||||
# Multisig instead of singlesig
|
# Multisig instead of singlesig
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1])) == False
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 1, 0, 0], [xpub1], PRESERVED)) == False
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 1, 0, 0], [xpub1], LEXICOGRAPHIC)) == False
|
||||||
|
|
||||||
# External output
|
# External output
|
||||||
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
||||||
|
|
||||||
def test_multisig(self):
|
def test_unsorted_multisig(self):
|
||||||
# Different change and account index
|
# Different change and account index
|
||||||
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub2]))
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub2], PRESERVED))
|
||||||
self.d.add_input(get_multisig_input([H_(45), 0, 0, 1], [xpub1, xpub2]))
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 1], [xpub1, xpub2], PRESERVED))
|
||||||
self.d.add_input(get_multisig_input([H_(45), 0, 1, 0], [xpub1, xpub2]))
|
self.d.add_input(get_multisig_input([H_(45), 0, 1, 0], [xpub1, xpub2], PRESERVED))
|
||||||
self.d.add_input(get_multisig_input([H_(45), 0, 1, 1], [xpub1, xpub2]))
|
self.d.add_input(get_multisig_input([H_(45), 0, 1, 1], [xpub1, xpub2], PRESERVED))
|
||||||
|
|
||||||
# Same outputs as inputs
|
# Same outputs as inputs
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2])) == True
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], PRESERVED)) == True
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 1], [xpub1, xpub2])) == True
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 1], [xpub1, xpub2], PRESERVED)) == True
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 1, 0], [xpub1, xpub2])) == True
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 1, 0], [xpub1, xpub2], PRESERVED)) == True
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 1, 1], [xpub1, xpub2])) == True
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 1, 1], [xpub1, xpub2], PRESERVED)) == True
|
||||||
|
|
||||||
# Singlesig instead of multisig
|
# Singlesig instead of multisig
|
||||||
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 0, 0, 0])) == False
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 0, 0, 0])) == False
|
||||||
@ -155,22 +159,60 @@ class TestChangeDetector(unittest.TestCase):
|
|||||||
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 1, 0, 0])) == False
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 1, 0, 0])) == False
|
||||||
|
|
||||||
# Different order of xpubs
|
# Different order of xpubs
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub2, xpub1])) == True
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub2, xpub1], PRESERVED)) == False
|
||||||
|
|
||||||
|
# Sorted instead of unsorted
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], LEXICOGRAPHIC)) == False
|
||||||
|
|
||||||
# Different xpubs
|
# Different xpubs
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub3])) == False
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub3], PRESERVED)) == False
|
||||||
|
|
||||||
# External output
|
# External output
|
||||||
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
||||||
|
|
||||||
def test_multisig_different_xpubs_order(self):
|
def test_sorted_multisig(self):
|
||||||
|
# Different change and account index
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub2], LEXICOGRAPHIC))
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 1], [xpub1, xpub2], LEXICOGRAPHIC))
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 1, 0], [xpub1, xpub2], LEXICOGRAPHIC))
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 1, 1], [xpub1, xpub2], LEXICOGRAPHIC))
|
||||||
|
|
||||||
|
# Same outputs as inputs
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], LEXICOGRAPHIC)) == True
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 1], [xpub1, xpub2], LEXICOGRAPHIC)) == True
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 1, 0], [xpub1, xpub2], LEXICOGRAPHIC)) == True
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 1, 1], [xpub1, xpub2], LEXICOGRAPHIC)) == True
|
||||||
|
|
||||||
|
# Singlesig instead of multisig
|
||||||
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 0, 0, 0])) == False
|
||||||
|
|
||||||
|
# Different account index
|
||||||
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 1, 0, 0])) == False
|
||||||
|
|
||||||
# Different order of xpubs
|
# Different order of xpubs
|
||||||
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub2]))
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub2, xpub1], LEXICOGRAPHIC)) == True
|
||||||
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub2, xpub1]))
|
|
||||||
|
# Unsorted instead of sorted
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], PRESERVED)) == False
|
||||||
|
|
||||||
|
# Different xpubs
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub3], LEXICOGRAPHIC)) == False
|
||||||
|
|
||||||
|
# External output
|
||||||
|
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
||||||
|
|
||||||
|
def test_unsorted_multisig_different_xpubs_order(self):
|
||||||
|
# Different order of xpubs
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub2], PRESERVED))
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub2, xpub1], PRESERVED))
|
||||||
|
|
||||||
# Same ouputs as inputs
|
# Same ouputs as inputs
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2])) == True
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], PRESERVED)) == False
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub2, xpub1])) == True
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub2, xpub1], PRESERVED)) == False
|
||||||
|
|
||||||
|
# Sorted instead of unsorted
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], LEXICOGRAPHIC)) == False
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub2, xpub1], LEXICOGRAPHIC)) == False
|
||||||
|
|
||||||
# Singlesig instead of multisig
|
# Singlesig instead of multisig
|
||||||
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 0, 0, 0])) == False
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 0, 0, 0])) == False
|
||||||
@ -178,14 +220,70 @@ class TestChangeDetector(unittest.TestCase):
|
|||||||
# External output
|
# External output
|
||||||
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
||||||
|
|
||||||
def test_multisig_different_xpubs(self):
|
def test_sorted_multisig_different_xpubs_order(self):
|
||||||
# Different xpubs
|
# Different order of xpubs
|
||||||
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub2]))
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub2], LEXICOGRAPHIC))
|
||||||
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub3]))
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub2, xpub1], LEXICOGRAPHIC))
|
||||||
|
|
||||||
# Same ouputs as inputs
|
# Same ouputs as inputs
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2])) == False
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], LEXICOGRAPHIC)) == True
|
||||||
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub3])) == False
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub2, xpub1], LEXICOGRAPHIC)) == True
|
||||||
|
|
||||||
|
# Sorted instead of unsorted
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], PRESERVED)) == False
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub2, xpub1], PRESERVED)) == False
|
||||||
|
|
||||||
|
# Singlesig instead of multisig
|
||||||
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 0, 0, 0])) == False
|
||||||
|
|
||||||
|
# External output
|
||||||
|
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
||||||
|
|
||||||
|
def test_unsorted_multisig_different_xpubs(self):
|
||||||
|
# Different xpubs
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub2], PRESERVED))
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub3], PRESERVED))
|
||||||
|
|
||||||
|
# Same ouputs as inputs
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], PRESERVED)) == False
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub3], PRESERVED)) == False
|
||||||
|
|
||||||
|
# Sorted instead of unsorted
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], LEXICOGRAPHIC)) == False
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub3], LEXICOGRAPHIC)) == False
|
||||||
|
|
||||||
|
# Singlesig instead of multisig
|
||||||
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 0, 0, 0])) == False
|
||||||
|
|
||||||
|
# External output
|
||||||
|
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
||||||
|
|
||||||
|
def test_sorted_multisig_different_xpubs(self):
|
||||||
|
# Different xpubs
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub2], LEXICOGRAPHIC))
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1, xpub3], LEXICOGRAPHIC))
|
||||||
|
|
||||||
|
# Same ouputs as inputs
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], LEXICOGRAPHIC)) == False
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub3], LEXICOGRAPHIC)) == False
|
||||||
|
|
||||||
|
# Sorted instead of unsorted
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub2], PRESERVED)) == False
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1, xpub3], PRESERVED)) == False
|
||||||
|
|
||||||
|
# Singlesig instead of multisig
|
||||||
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 0, 0, 0])) == False
|
||||||
|
|
||||||
|
# External output
|
||||||
|
assert self.d.output_is_change(get_external_singlesig_output()) == False
|
||||||
|
|
||||||
|
def test_mixed_sorted_and_unsorted_multisig_1(self):
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1], PRESERVED))
|
||||||
|
self.d.add_input(get_multisig_input([H_(45), 0, 0, 0], [xpub1], LEXICOGRAPHIC))
|
||||||
|
|
||||||
|
# Same ouputs as inputs
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1], PRESERVED)) == False
|
||||||
|
assert self.d.output_is_change(get_internal_multisig_output([H_(45), 0, 0, 0], [xpub1], LEXICOGRAPHIC)) == False
|
||||||
|
|
||||||
# Singlesig instead of multisig
|
# Singlesig instead of multisig
|
||||||
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 0, 0, 0])) == False
|
assert self.d.output_is_change(get_internal_singlesig_output([H_(45), 0, 0, 0])) == False
|
||||||
|
@ -63,7 +63,7 @@ NODE_INT = bip32.deserialize(
|
|||||||
# m/2 => 038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3
|
# m/2 => 038caebd6f753bbbd2bb1f3346a43cd32140648583673a31d62f2dfb56ad0ab9e3
|
||||||
|
|
||||||
multisig_in1 = messages.MultisigRedeemScriptType(
|
multisig_in1 = messages.MultisigRedeemScriptType(
|
||||||
nodes=[NODE_EXT2, NODE_EXT1, NODE_INT],
|
nodes=[NODE_EXT1, NODE_EXT2, NODE_INT],
|
||||||
address_n=[0, 0],
|
address_n=[0, 0],
|
||||||
signatures=[b"", b"", b""],
|
signatures=[b"", b"", b""],
|
||||||
m=2,
|
m=2,
|
||||||
@ -84,7 +84,7 @@ multisig_in3 = messages.MultisigRedeemScriptType(
|
|||||||
)
|
)
|
||||||
|
|
||||||
prev_hash_1, prev_tx_1 = forge_prevtx(
|
prev_hash_1, prev_tx_1 = forge_prevtx(
|
||||||
[("3HwrvQEfYw4wUvGHpGmixWB15HPgqrvTh1", 50_000_000)]
|
[("3Ltgk5WPUMLcT2QvwRXKj9CWsYuAKqeHJ8", 50_000_000)]
|
||||||
)
|
)
|
||||||
INP1 = messages.TxInputType(
|
INP1 = messages.TxInputType(
|
||||||
address_n=[H_(45), 0, 0, 0],
|
address_n=[H_(45), 0, 0, 0],
|
||||||
|
Loading…
Reference in New Issue
Block a user