From 90050934355b71c7be5c6c60fd385cae83e0b0cc Mon Sep 17 00:00:00 2001 From: matejcik Date: Thu, 30 Apr 2020 16:36:38 +0200 Subject: [PATCH] core/sign_tx: improve documentation on MatchCheckers --- core/src/apps/wallet/sign_tx/matchcheck.py | 33 +++++++++++++++------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/core/src/apps/wallet/sign_tx/matchcheck.py b/core/src/apps/wallet/sign_tx/matchcheck.py index e816235e6..b813a43bb 100644 --- a/core/src/apps/wallet/sign_tx/matchcheck.py +++ b/core/src/apps/wallet/sign_tx/matchcheck.py @@ -9,7 +9,7 @@ from apps.wallet.sign_tx import multisig from apps.wallet.sign_tx.common import SigningError if False: - from typing import Union + from typing import Any, Union # the number of bip32 levels used in a wallet (chain and address) _BIP32_WALLET_DEPTH = const(2) @@ -17,21 +17,34 @@ _BIP32_WALLET_DEPTH = const(2) class MatchChecker: """ - MatchCheckers are used to identify the change-output in a transaction. An output is a change-output - if it has certain matching attributes with all inputs. - 1. When inputs are first processed, add_input() is called on each one to determine if they all match. - 2. Outputs are tested using output_matches() to tell whether they are admissible as a change-output. - 3. Before signing each input, check_input() is used to ensure that the attribute has not changed. + MatchCheckers are used to identify the change-output in a transaction. An output is + a change-output if it has a certain matching attribute with all inputs. + 1. When inputs are first processed, add_input() is called on each one to determine + if they all match. + 2. Outputs are tested using output_matches() to tell whether they are admissible as + a change-output. + 3. Before signing each input, check_input() is used to ensure that the attribute has + not changed. + + There are two possible paths: + + (a) If all inputs match on the attribute, the matching value is stored. Every output + that matches the stored value is admissible as a change-output. + + (b) If some inputs do not match, a special value MISMATCH is stored. When the + matcher is in this state, _no outputs_ are admissible as change-outputs. + check_input() is a no-op in this case: if there is no matching attribute to + check against, we cannot detect modifications. """ MISMATCH = object() UNDEFINED = object() def __init__(self) -> None: - self.attribute = self.UNDEFINED # type: object + self.attribute = self.UNDEFINED # type: Any self.read_only = False # Failsafe to ensure that add_input() is not accidentally called after output_matches(). - def attribute_from_tx(self, txio: Union[TxInputType, TxOutputType]) -> object: + def attribute_from_tx(self, txio: Union[TxInputType, TxOutputType]) -> Any: # Return the attribute from the txio, which is to be used for matching. # If the txio is invalid for matching, then return an object which # evaluates as a boolean False. @@ -72,14 +85,14 @@ class MatchChecker: class WalletPathChecker(MatchChecker): - def attribute_from_tx(self, txio: Union[TxInputType, TxOutputType]) -> object: + def attribute_from_tx(self, txio: Union[TxInputType, TxOutputType]) -> Any: if not txio.address_n: return None return txio.address_n[:-_BIP32_WALLET_DEPTH] class MultisigFingerprintChecker(MatchChecker): - def attribute_from_tx(self, txio: Union[TxInputType, TxOutputType]) -> object: + def attribute_from_tx(self, txio: Union[TxInputType, TxOutputType]) -> Any: if not txio.multisig: return None return multisig.multisig_fingerprint(txio.multisig)