Skip to content

Commit

Permalink
Add device tests for Mintlayer python lib
Browse files Browse the repository at this point in the history
  • Loading branch information
OBorce committed Nov 12, 2024
1 parent 3376107 commit 00d74b1
Show file tree
Hide file tree
Showing 7 changed files with 746 additions and 5 deletions.
10 changes: 5 additions & 5 deletions core/src/apps/mintlayer/sign_tx/signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def __init__(

async def step1_process_inputs(self) -> Dict[str, int]:
tx_info = self.tx_info # local_cache_attribute
totals = {}
totals = {ML_COIN: 0}

for i in range(tx_info.tx.inputs_count):
# STAGE_REQUEST_1_INPUT in legacy
Expand Down Expand Up @@ -232,7 +232,7 @@ async def step1_process_inputs(self) -> Dict[str, int]:
return totals

async def step2_approve_outputs(self) -> Dict[str, int]:
totals = {}
totals = {ML_COIN: 0}

for i in range(self.tx_info.tx.outputs_count):
progress.advance()
Expand Down Expand Up @@ -409,9 +409,9 @@ def serialize_output(self, out: MintlayerTxOutput) -> bytes:
x.name,
x.description,
x.ticker,
x.icon_uri,
x.additional_metadata_uri,
x.media_uri,
x.icon_uri or b"",
x.additional_metadata_uri or b"",
x.media_uri or b"",
x.media_hash,
destination,
)
Expand Down
147 changes: 147 additions & 0 deletions python/src/trezorlib/cli/mintlayer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import base64
import json
from typing import TYPE_CHECKING, Dict, List, Optional, TextIO, Tuple

import click

from .. import messages, mintlayer, protobuf, tools
from . import ChoiceType, with_client

if TYPE_CHECKING:
from ..client import TrezorClient


@click.group(name="mintlayer")
def cli() -> None:
"""Mintalyer coin commands."""


@cli.command()
@click.option("-n", "--address", required=True, help="BIP-32 path")
@click.option("-d", "--show-display", is_flag=True)
@click.option("-C", "--chunkify", is_flag=True)
@with_client
def get_address(
client: "TrezorClient",
address: str,
show_display: bool,
chunkify: bool,
) -> str:
"""Get address for specified path.
\b
$ trezorctl mintlayer get-address -n m/44h/19788h/0h/0/0
"""
address_n = tools.parse_path(address)

return mintlayer.get_address(
client,
address_n,
show_display,
chunkify=chunkify,
)


@cli.command()
@click.option("-n", "--address", required=True, help="BIP-32 path, e.g. m/44h/0h/0h")
@click.option("-d", "--show-display", is_flag=True)
@with_client
def get_public_key(
client: "TrezorClient",
address: str,
show_display: bool,
) -> dict:
"""Get public key with its chain code of given path.
\b
$ trezorctl mintlayer get-public-key -n m/44h/19788h/0h/0/0
"""
address_n = tools.parse_path(address)
result = mintlayer.get_public_key(
client,
address_n,
show_display=show_display,
)
if isinstance(result, messages.MintlayerPublicKey):
return {
"chain_code": result.chain_code.hex(),
"public_key": result.public_key.hex(),
}
else:
return {"error": result}


@cli.command()
@click.option("-n", "--address_n", required=True, help="BIP-32 path")
@click.option("-a", "--address", required=True, help="bech32 encoded address")
@click.argument("message")
@with_client
def sign_message(
client: "TrezorClient",
address_n: str,
address: str,
message: str,
) -> dict:
"""Sign message using address of given path."""
result = mintlayer.sign_message(
client,
address_n=tools.parse_path(address_n),
address=address,
message=message.encode(),
)
if isinstance(result, messages.MessageSignature):
return {
"message": message,
"address": result.address,
"signature": base64.b64encode(result.signature).decode(),
}
else:
return {"error": result}


@cli.command()
@click.option("-C", "--chunkify", is_flag=True)
@click.argument("json_file", type=click.File())
@with_client
def sign_tx(client: "TrezorClient", json_file: TextIO, chunkify: bool) -> None:
"""Sign transaction.
Transaction data must be provided in a JSON file. The structure of the JSON matches the shape of the relevant protobuf messages. See
file [messages-mintlayer.proto] for up-to-date structure
"""
data = json.load(json_file)
details = data.get("details", {})
inputs = [
protobuf.dict_to_proto(messages.MintlayerTxInput, i)
for i in data.get("inputs", ())
]
outputs = [
protobuf.dict_to_proto(messages.MintlayerTxOutput, output)
for output in data.get("outputs", ())
]
prev_txes = {
bytes.fromhex(txid): {
idx: protobuf.dict_to_proto(messages.MintlayerTxOutput, utxo)
for idx, utxo in tx_utxos.items()
}
for txid, tx_utxos in data.get("prev_txes", {}).items()
}

results = mintlayer.sign_tx(
client,
inputs,
outputs,
prev_txs=prev_txes,
chunkify=chunkify,
**details,
)

click.echo()
click.echo("Signed signatures:")
for res in results:
click.echo(f"signature index: {res.signature_index}")
click.echo("signature:")
for sig in res.signatures:
if sig.multisig_idx is not None:
click.echo(f"multisig index: {sig.multisig_idx}")
click.echo(sig.signature.hex())
1 change: 1 addition & 0 deletions tests/REGISTERED_MARKERS
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ decred
eos
ethereum
komodo
mintlayer
monero
multisig
nem
Expand Down
Empty file.
49 changes: 49 additions & 0 deletions tests/device_tests/mintlayer/test_get_public_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# This file is part of the Trezor project.
#
# Copyright (C) 2012-2019 SatoshiLabs and contributors
#
# This library is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License version 3
# as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the License along with this library.
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.

import pytest

from trezorlib import messages, mintlayer
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import parse_path

from ...input_flows import InputFlowShowXpubQRCode

MINTLAYER_PATH = parse_path("m/44h/19788h/0h/0/0")


@pytest.mark.altcoin
@pytest.mark.mintlayer
@pytest.mark.setup_client(
mnemonic="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
)
def test_mintlayer_get_public_key(client: Client):
with client:
IF = InputFlowShowXpubQRCode(client)
client.set_input_flow(IF.get())
result = mintlayer.get_public_key(client, MINTLAYER_PATH, show_display=True)
if isinstance(result, messages.MintlayerPublicKey):
# m/44'/19788'/0'/0/0 for MNEMONIC
assert (
result.public_key.hex()
== "03bf6f8d52dade77f95e9c6c9488fd8492a99c09ff23095caffb2e6409d1746ade"
)
assert (
result.chain_code.hex()
== "0ae454a1024d0ddb9e10d23479cf8ef39fb400727fabd17844bd8362b1c70d7d"
)
else:
assert False
26 changes: 26 additions & 0 deletions tests/device_tests/mintlayer/test_sign_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import pytest

from trezorlib import messages, mintlayer
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.tools import parse_path


@pytest.mark.altcoin
@pytest.mark.mintlayer
@pytest.mark.setup_client(
mnemonic="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
)
def test_mintlayer_sign_message(client: Client):
address = "mtc1qyumjs84s5nqgcp6nw9kwde9mn7akph6hgtulsdk"
result = mintlayer.sign_message(
client,
address_n=parse_path("m/44h/19788h/0h/0/0"),
address=address,
message="Message to sign".encode(),
)
if isinstance(result, messages.MessageSignature):
assert (
result.signature.hex()
== "7d8a743ada09e7ca8e76cf99429385a1651a9738d96a78c6b601c49a7cb20896d076e1c4d4e8a514ad73f4b88fe115cb30b61e1c04fc96d999baeabd32f82fb2"
)
assert result.address == address
Loading

0 comments on commit 00d74b1

Please sign in to comment.