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

pull/2352/head
matejcik 2 years ago
parent 60648c903f
commit aaa224a4f7

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

@ -49,6 +49,19 @@ OUTPUT_SCRIPTS = {
"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"
@ -85,6 +98,22 @@ def xpub_deserialize(xpubstr: str) -> Tuple[str, messages.HDNodeType]:
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")
def cli() -> None:
"""Bitcoin and Bitcoin-like coins commands."""
@ -98,7 +127,7 @@ def cli() -> None:
@cli.command()
@click.option("-c", "--coin", default=DEFAULT_COIN)
@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("-x", "--multisig-xpub", multiple=True, help="XPUBs of multisig owners")
@click.option("-m", "--multisig-threshold", type=int, help="Number of signatures")
@ -114,7 +143,7 @@ def get_address(
client: "TrezorClient",
coin: str,
address: str,
script_type: messages.InputScriptType,
script_type: Optional[messages.InputScriptType],
show_display: bool,
multisig_xpub: List[str],
multisig_threshold: Optional[int],
@ -141,6 +170,8 @@ def get_address(
use final xpubs, specify '-N 0'.
"""
address_n = tools.parse_path(address)
if script_type is None:
script_type = guess_script_type_from_path(address_n)
multisig: Optional[messages.MultisigRedeemScriptType]
if multisig_xpub:
@ -171,7 +202,7 @@ def get_address(
@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("-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)
@with_client
def get_public_node(
@ -179,11 +210,13 @@ def get_public_node(
coin: str,
address: str,
curve: Optional[str],
script_type: messages.InputScriptType,
script_type: Optional[messages.InputScriptType],
show_display: bool,
) -> dict:
"""Get public node of given path."""
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(
client,
address_n,
@ -332,7 +365,7 @@ def sign_tx(client: "TrezorClient", json_file: TextIO) -> None:
@cli.command()
@click.option("-c", "--coin", default=DEFAULT_COIN)
@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(
"-e",
"--electrum-compat",
@ -346,11 +379,13 @@ def sign_message(
coin: str,
address: str,
message: str,
script_type: messages.InputScriptType,
script_type: Optional[messages.InputScriptType],
electrum_compat: bool,
) -> Dict[str, str]:
"""Sign message using address of given path."""
address_n = tools.parse_path(address)
if script_type is None:
script_type = guess_script_type_from_path(address_n)
res = btc.sign_message(
client, coin, address_n, message, script_type, electrum_compat
)

Loading…
Cancel
Save