1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 04:18:10 +00:00

feat(python/trezorctl): detect script type from path (fixes #2159)

This commit is contained in:
matejcik 2022-06-22 15:19:39 +02:00
parent 60648c903f
commit aaa224a4f7
2 changed files with 42 additions and 6 deletions

View File

@ -0,0 +1 @@
trezorctl: Bitcoin commands can detect script type from derivation path.

View File

@ -49,6 +49,19 @@ OUTPUT_SCRIPTS = {
"tr": messages.OutputScriptType.PAYTOTAPROOT, "tr": messages.OutputScriptType.PAYTOTAPROOT,
} }
BIP_PURPOSE_TO_SCRIPT_TYPE = {
tools.H_(44): messages.InputScriptType.SPENDADDRESS,
tools.H_(49): messages.InputScriptType.SPENDP2SHWITNESS,
tools.H_(84): messages.InputScriptType.SPENDWITNESS,
tools.H_(86): messages.InputScriptType.SPENDTAPROOT,
}
BIP48_SCRIPT_TYPES = {
tools.H_(0): messages.InputScriptType.SPENDMULTISIG,
tools.H_(1): messages.InputScriptType.SPENDP2SHWITNESS,
tools.H_(2): messages.InputScriptType.SPENDWITNESS,
}
DEFAULT_COIN = "Bitcoin" DEFAULT_COIN = "Bitcoin"
@ -85,6 +98,22 @@ def xpub_deserialize(xpubstr: str) -> Tuple[str, messages.HDNodeType]:
return data.version, node return data.version, node
def guess_script_type_from_path(address_n: List[int]) -> messages.InputScriptType:
if len(address_n) < 1:
return messages.InputScriptType.SPENDADDRESS
purpose = address_n[0]
if purpose in BIP_PURPOSE_TO_SCRIPT_TYPE:
return BIP_PURPOSE_TO_SCRIPT_TYPE[purpose]
if purpose == tools.H_(48) and len(address_n) >= 4:
script_type_field = address_n[3]
if script_type_field in BIP48_SCRIPT_TYPES:
return BIP48_SCRIPT_TYPES[script_type_field]
return messages.InputScriptType.SPENDADDRESS
@click.group(name="btc") @click.group(name="btc")
def cli() -> None: def cli() -> None:
"""Bitcoin and Bitcoin-like coins commands.""" """Bitcoin and Bitcoin-like coins commands."""
@ -98,7 +127,7 @@ def cli() -> None:
@cli.command() @cli.command()
@click.option("-c", "--coin", default=DEFAULT_COIN) @click.option("-c", "--coin", default=DEFAULT_COIN)
@click.option("-n", "--address", required=True, help="BIP-32 path") @click.option("-n", "--address", required=True, help="BIP-32 path")
@click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS), default="address") @click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS))
@click.option("-d", "--show-display", is_flag=True) @click.option("-d", "--show-display", is_flag=True)
@click.option("-x", "--multisig-xpub", multiple=True, help="XPUBs of multisig owners") @click.option("-x", "--multisig-xpub", multiple=True, help="XPUBs of multisig owners")
@click.option("-m", "--multisig-threshold", type=int, help="Number of signatures") @click.option("-m", "--multisig-threshold", type=int, help="Number of signatures")
@ -114,7 +143,7 @@ def get_address(
client: "TrezorClient", client: "TrezorClient",
coin: str, coin: str,
address: str, address: str,
script_type: messages.InputScriptType, script_type: Optional[messages.InputScriptType],
show_display: bool, show_display: bool,
multisig_xpub: List[str], multisig_xpub: List[str],
multisig_threshold: Optional[int], multisig_threshold: Optional[int],
@ -141,6 +170,8 @@ def get_address(
use final xpubs, specify '-N 0'. use final xpubs, specify '-N 0'.
""" """
address_n = tools.parse_path(address) address_n = tools.parse_path(address)
if script_type is None:
script_type = guess_script_type_from_path(address_n)
multisig: Optional[messages.MultisigRedeemScriptType] multisig: Optional[messages.MultisigRedeemScriptType]
if multisig_xpub: if multisig_xpub:
@ -171,7 +202,7 @@ def get_address(
@click.option("-c", "--coin", default=DEFAULT_COIN) @click.option("-c", "--coin", default=DEFAULT_COIN)
@click.option("-n", "--address", required=True, help="BIP-32 path, e.g. m/44'/0'/0'") @click.option("-n", "--address", required=True, help="BIP-32 path, e.g. m/44'/0'/0'")
@click.option("-e", "--curve") @click.option("-e", "--curve")
@click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS), default="address") @click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS))
@click.option("-d", "--show-display", is_flag=True) @click.option("-d", "--show-display", is_flag=True)
@with_client @with_client
def get_public_node( def get_public_node(
@ -179,11 +210,13 @@ def get_public_node(
coin: str, coin: str,
address: str, address: str,
curve: Optional[str], curve: Optional[str],
script_type: messages.InputScriptType, script_type: Optional[messages.InputScriptType],
show_display: bool, show_display: bool,
) -> dict: ) -> dict:
"""Get public node of given path.""" """Get public node of given path."""
address_n = tools.parse_path(address) address_n = tools.parse_path(address)
if script_type is None:
script_type = guess_script_type_from_path(address_n)
result = btc.get_public_node( result = btc.get_public_node(
client, client,
address_n, address_n,
@ -332,7 +365,7 @@ def sign_tx(client: "TrezorClient", json_file: TextIO) -> None:
@cli.command() @cli.command()
@click.option("-c", "--coin", default=DEFAULT_COIN) @click.option("-c", "--coin", default=DEFAULT_COIN)
@click.option("-n", "--address", required=True, help="BIP-32 path") @click.option("-n", "--address", required=True, help="BIP-32 path")
@click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS), default="address") @click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS))
@click.option( @click.option(
"-e", "-e",
"--electrum-compat", "--electrum-compat",
@ -346,11 +379,13 @@ def sign_message(
coin: str, coin: str,
address: str, address: str,
message: str, message: str,
script_type: messages.InputScriptType, script_type: Optional[messages.InputScriptType],
electrum_compat: bool, electrum_compat: bool,
) -> Dict[str, str]: ) -> Dict[str, str]:
"""Sign message using address of given path.""" """Sign message using address of given path."""
address_n = tools.parse_path(address) address_n = tools.parse_path(address)
if script_type is None:
script_type = guess_script_type_from_path(address_n)
res = btc.sign_message( res = btc.sign_message(
client, coin, address_n, message, script_type, electrum_compat client, coin, address_n, message, script_type, electrum_compat
) )