Skip to content

Commit

Permalink
Merge pull request #10 from trilitech/main
Browse files Browse the repository at this point in the history
Fix flex/stax bug for signing Michelin messages
  • Loading branch information
lpascal-ledger authored Dec 18, 2024
2 parents 036ffa6 + 553d3a8 commit ec5813a
Show file tree
Hide file tree
Showing 585 changed files with 2,246 additions and 1,017 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ jobs:
apk add gmp-dev curl jq libsodium-dev git xxd procps
python3 -m venv tezos_test_env --system-site-package
source ./tezos_test_env/bin/activate
python3 -m pip install --upgrade pip -q
python3 -m pip install -r ./tests/requirements.txt -q
TMP_DIR=$(mktemp -d /tmp/foo-XXXXXX)
tar xfz app_${{ matrix.device }}_dbg.tgz -C $TMP_DIR
Expand Down Expand Up @@ -192,6 +193,7 @@ jobs:
apk add gmp-dev curl jq libsodium-dev git xxd procps
python3 -m venv tezos_test_env --system-site-package
source ./tezos_test_env/bin/activate
python3 -m pip install --upgrade pip -q
python3 -m pip install -r ./tests/requirements.txt -q
./tests/integration/run_test_local.sh -T100 -F -m ${{ matrix.device }} tests
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/coding_style_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,20 @@ jobs:
source: './app/src'
extensions: 'h,c'
version: 15

pylint_check:
name: Python Lint Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'

- name: Install pylint
run: pip install pylint -r tests/requirements.txt

- name: Run pylint with .pylintrc
run: pylint --errors-only --rcfile=tests/integration/.pylintrc tests/integration/nano/
2 changes: 1 addition & 1 deletion .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ jobs:
python-version: '3.10'
- run: python -m pip install pre-commit
- run: python -m pip freeze --local
- run: SKIP=clang-format pre-commit run --all-files
- run: SKIP=clang-format,pylint pre-commit run --all-files
9 changes: 9 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,12 @@ repos:
language: system
files: ^
types: [file, c]

- id: pylint
name: pylint
description: Run pylint with custom .pylintrc configuration
entry: pylint
language: system
pass_filenames: false
args: ["--errors-only", "--rcfile=tests/integration/.pylintrc", "tests/integration/nano/"]
types: [python]
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ integration_tests_basic_%: app_%.tgz \
apk add gmp-dev curl jq libsodium-dev git xxd procps; \
python3 -m venv tezos_test_env --system-site-package; \
source ./tezos_test_env/bin/activate; \
python3 -m pip install --upgrade pip -q; \
python3 -m pip install -r tests/requirements.txt -q ; \
python3 -m pytest -n 32 tests/integration/nano/ --tb=no \
--device $* --app \$$TMP_DIR/app.elf \
Expand Down
2 changes: 1 addition & 1 deletion app/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ APPNAME = "Tezos Wallet"
# Application version
APPVERSION_M=3
APPVERSION_N=0
APPVERSION_P=5
APPVERSION_P=6
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)

# COMMIT
Expand Down
2 changes: 1 addition & 1 deletion app/src/ui_stream_nbgl.c
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ tz_ui_nav_cb(void)
tz_parser_state *st = &global.keys.apdu.sign.u.clear.parser_state;

// Continue receiving data from the apdu until s->full is true.
while (((s->total < 0) || ((s->current == s->total) && !s->full))
while (((s->total < 0) || (s->current == s->total)) && !s->full
&& (st->errno < TZ_ERR_INVALID_TAG)) {
PRINTF("tz_ui_nav_cb: Looping...\n");
tz_ui_continue();
Expand Down
3 changes: 2 additions & 1 deletion scripts/test_swap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ run_tests() {
--rm -v "$(realpath .):/app" \
ledger-app-tezos-integration-tests -c \
"cd /app && \
pip install -r test/python/requirements.txt -q && \
pip install --upgrade pip -q && \
pip install -r test/python/requirements.txt -q && \
pip install protobuf==3.20.3 && pytest test/python $*"
)
}
Expand Down
13 changes: 13 additions & 0 deletions tests/integration/.pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[MESSAGES CONTROL]
disable=
broad-exception-caught,
dangerous-default-value,
global-statement,
line-too-long,
protected-access,
redefined-outer-name,
too-few-public-methods,
too-many-arguments,
too-many-instance-attributes,
too-many-positional-arguments,
too-many-statements,
2 changes: 1 addition & 1 deletion tests/integration/app_vars.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ export COMMIT_BYTES=$(printf '%s' "$COMMIT" | xxd -p -c 256)
export VERSION_WALLET_TAG="00"
export APPVERSION_M=3
export APPVERSION_N=0
export APPVERSION_P=5
export APPVERSION_P=6
export APPVERSION=$APPVERSION_M.$APPVERSION_N.$APPVERSION_P
export VERSION_BYTES=$(printf "%02x%02x%02x%02x" "$VERSION_WALLET_TAG" "$APPVERSION_M" "$APPVERSION_N" "$APPVERSION_P")
51 changes: 42 additions & 9 deletions tests/integration/nano/conftest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import pytest
# Copyright 2024 Trilitech <[email protected]>
# Copyright 2024 Functori <[email protected]>

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Conftest base on `ragger` conftest."""


from pathlib import Path
from typing import Dict, Generator, List, Union

import pytest
from ragger.firmware import Firmware
from typing import Dict, Callable, Generator, List, Optional, Tuple, Union

from utils.app import TezosAppScreen, SpeculosTezosBackend, DEFAULT_SEED
from utils.backend import TezosBackend, APP_KIND
from utils.backend import AppKind

FIRMWARES: List[Firmware] = [
Firmware.NANOS,
Expand All @@ -16,6 +34,7 @@
DEVICES: List[str] = list(map(lambda fw: fw.device, FIRMWARES))

def pytest_addoption(parser):
"""Register argparse-style options for pytest."""
parser.addoption("-D", "--device",
type=str,
choices=DEVICES,
Expand Down Expand Up @@ -49,6 +68,7 @@ def pytest_addoption(parser):
global_log_dir: Union[Path, None] = None

def pytest_configure(config):
"""Configure pytest."""
global global_log_dir
log_dir = config.getoption("log_dir")
if log_dir is not None:
Expand All @@ -57,21 +77,24 @@ def pytest_configure(config):
logs : Dict[str, List[pytest.TestReport]] = {}

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_logstart(nodeid, location):
def pytest_runtest_logstart(location):
"""Called at the start of running the runtest protocol for a single item."""
logs[location[2]] = []

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_logreport(report):
"""Called at the end of running the runtest protocol for a single test."""
logs[report.head_line].append(report)

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_logfinish(nodeid, location):
def pytest_runtest_logfinish(location):
"""Called at the end of running the runtest protocol for a single item."""
if global_log_dir is not None:
log_dir = global_log_dir / Path(location[0]).stem
log_dir.mkdir(parents=True, exist_ok=True)
head_line = location[2]
log_file = log_dir / f"{head_line.replace(' ', '_')}.log"
with open(log_file, 'w') as writer:
with open(log_file, 'w', encoding="utf-8") as writer:
for report in logs[head_line]:
writer.write(f"============================== {report.when.capitalize()} {report.outcome} ==============================\n")
writer.write(f"{report.longreprtext}\n")
Expand All @@ -84,37 +107,44 @@ def pytest_runtest_logfinish(nodeid, location):

@pytest.fixture(scope="session")
def firmware(pytestconfig) -> Firmware :
"""Get `firware` for pytest."""
device = pytestconfig.getoption("device")
return next(fw for fw in FIRMWARES if fw.device == device)

@pytest.fixture(scope="session")
def port(pytestconfig, request, worker_id) -> int :
def port(pytestconfig, worker_id) -> int :
"""Get `port` for pytest."""
if worker_id == "master":
return pytestconfig.getoption("port")
# worker_id = gw0, gw1, ...
return 5000 + int(worker_id[2:])

@pytest.fixture(scope="session")
def display(pytestconfig) -> bool :
"""Get `display` for pytest."""
return pytestconfig.getoption("display")

@pytest.fixture(scope="session")
def golden_run(pytestconfig) -> bool:
"""Get `golden_run` for pytest."""
return pytestconfig.getoption("golden_run")

@pytest.fixture(scope="session")
def app_path(pytestconfig) -> Path:
"""Get `app_path` for pytest."""
return Path(pytestconfig.getoption("app"))

@pytest.fixture(scope="session")
def speculos_args(pytestconfig) -> List[str]:
"""Get `app_path` for pytest."""
speculos_args = pytestconfig.getoption("speculos_args")
if speculos_args is None:
return []
return speculos_args.split()

@pytest.fixture(scope="function")
def seed(request) -> str:
"""Get `seed` for pytest."""
param = getattr(request, "param", None)
return param.get("seed", DEFAULT_SEED) if param else DEFAULT_SEED

Expand All @@ -125,6 +155,7 @@ def backend(app_path: Path,
display: bool,
seed: str,
speculos_args: List[str]) -> Generator[SpeculosTezosBackend, None, None]:
"""Get `backend` for pytest."""

if display:
speculos_args += ["--display", "qt"]
Expand All @@ -143,10 +174,12 @@ def backend(app_path: Path,
yield b

@pytest.fixture(scope="function")
def app(backend: SpeculosTezosBackend, golden_run: bool):
return TezosAppScreen(backend, APP_KIND.WALLET, golden_run)
def app(backend: SpeculosTezosBackend, golden_run: bool) -> TezosAppScreen:
"""Get `app` for pytest."""
return TezosAppScreen(backend, AppKind.WALLET, golden_run)

def requires_device(device):
"""Wrapper to run the pytest test only with the provided device."""
return pytest.mark.skipif(
f"config.getvalue('device') != '{ device }'",
reason=f"Test requires device to be { device }."
Expand Down
Empty file.
53 changes: 28 additions & 25 deletions tests/integration/nano/nanos/test_nanos_regression_batched_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,44 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys
"""Check signing batch operation"""

file_path=os.path.abspath(__file__)
dir_path=os.path.dirname(file_path)
root_path=os.path.dirname(dir_path)
sys.path.append(root_path)
from pathlib import Path

from conftest import requires_device

from pathlib import Path

from utils.app import Screen, DEFAULT_ACCOUNT
from utils.message import Message

# Operation (0): Transaction
# Fee: 0.39 XTZ
# Storage limit: 6
# Amount: 0.02 XTZ
# Destination: tz1cfdVKpBb9VRBdny8BQ5RSK82UudAp2miM
# Entrypoint: jean_bob
# Parameter: {Pair {} (Right -76723569314251090535296646);Pair {Elt Unit (Pair {Left Unit} (Pair (Left 0x03F01167865DC63DFEE0E31251329CEAB660D94606) (Pair 0x0107B21FCA96C5763F67B286752C7AAEFC5931D15A Unit)))} (Right 3120123370638446806591421154959427514880865200209654970345);Pair {} (Left (Some Unit))}
# Operation (1): Transaction
# Fee: 0.65 XTZ
# Storage limit: 2
# Amount: 0.06 XTZ
# Destination: KT1CYT8oACUcCSNTu2qfgB4fj5bD7szYrpti
from utils.app import TezosAppScreen, DEFAULT_ACCOUNT
from utils.message import OperationGroup, Transaction

@requires_device("nanos")
def test_nanos_regression_batched_ops(app):
def test_nanos_regression_batched_ops(app: TezosAppScreen):
"""Check signing batch operation"""
test_name = Path(__file__).stem

app.setup_expert_mode()

message = Message.from_bytes("0300000000000000000000000000000000000000000000000000000000000000006c001597c45b11b421bb806a0c56c5da5638bf4b1adbf0e617090006a09c010000bac799dfc7f6af2ff0b95f83d023e68c895020baffff086a65616e5f626f620000009a020000009507070200000000050800c6bab5ccc8d891cd8de4b6f7070707020000004b0704030b070702000000040505030b070705050a0000001503f01167865dc63dfee0e31251329ceab660d9460607070a000000150107b21fca96c5763f67b286752c7aaefc5931d15a030b050800a9df9fc1e7eaa7a9c1f7bd87a9ba9cadf5b5b2cd829deea2b7fef9070707020000000005050509030b6c01ee572f02e5be5d097ba17369789582882e8abb8790d627063202e0d403012b704944f5b5fd30eed2ab4385478488e09fe04a0000")
message = OperationGroup([
Transaction(
source = 'tz1McCh72NRhYmJBcWr3zDrLJAxnfR9swcFh',
fee = 390000,
counter = 9,
gas_limit = 0,
storage_limit = 6,
destination = 'tz1cfdVKpBb9VRBdny8BQ5RSK82UudAp2miM',
amount = 20000,
entrypoint = 'jean_bob',
parameter = [{'prim':'Pair','args':[[],{'prim':'Right','args':[{'int':-76723569314251090535296646}]}]},{'prim':'Pair','args':[[{'prim':'Elt','args':[{'prim':'Unit','args':[]},{'prim':'Pair','args':[[{'prim':'Left','args':[{'prim':'Unit','args':[]}]}],{'prim':'Pair','args':[{'prim':'Left','args':[{'bytes':"03F01167865DC63DFEE0E31251329CEAB660D94606"}]},{'prim':'Pair','args':[{'bytes':"0107B21FCA96C5763F67B286752C7AAEFC5931D15A"},{'prim':'Unit','args':[]}]}]}]}]}],{'prim':'Right','args':[{'int':3120123370638446806591421154959427514880865200209654970345}]},]},{'prim':'Pair','args':[[],{'prim':'Left','args':[{'prim':'Some','args':[{'prim':'Unit','args':[]}]}]}]}]
),
Transaction(
source = 'tz2W3Tvcm64GjcV2bipUynnEsctLFz5Z6yRa',
fee = 650000,
counter = 6,
gas_limit = 50,
storage_limit = 2,
destination = 'KT1CYT8oACUcCSNTu2qfgB4fj5bD7szYrpti',
amount = 60000
)
])

data = app.sign(DEFAULT_ACCOUNT,
message,
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,35 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys

file_path=os.path.abspath(__file__)
dir_path=os.path.dirname(file_path)
root_path=os.path.dirname(dir_path)
sys.path.append(root_path)

from conftest import requires_device
"""Check signing operation that display potentially empty screens"""

from pathlib import Path

from utils.app import Screen, DEFAULT_ACCOUNT
from utils.message import Message
from conftest import requires_device

# Operation (0): Transfer ticket
# Fee: 0.01 XTZ
# Storage limit: 4
# Contents: UNPAIR
# Type: pair "1" 2
# Ticketer: tz1ixvCiPJYyMjsp2nKBVaq54f6AdbV8hCKa
# Amount: 1
# Destination: KT18amZmM5W7qDWVt2pH6uj7sCEd3kbzLrHT
# Entrypoint: S
#
# S
# S
# S
from utils.app import TezosAppScreen, DEFAULT_ACCOUNT
from utils.message import TransferTicket

@requires_device("nanosp")
def test_nanosp_regression_potential_empty_screen(app):
def test_nanosp_regression_potential_empty_screen(app: TezosAppScreen):
"""Check signing operation that display potentially empty screens"""
test_name = Path(__file__).stem

app.setup_expert_mode()

message = Message.from_bytes("0300000000000000000000000000000000000000000000000000000000000000009e00ffdd6102321bc251e4a5190ad5b12b251069d9b4904e02030400000002037a0000000a076501000000013100020000ffdd6102321bc251e4a5190ad5b12b251069d9b4010100000000000000000000000000000000000000000000000008530a0a530a530a53")
message = TransferTicket(
source = 'tz1ixvCiPJYyMjsp2nKBVaq54f6AdbV8hCKa',
fee = 10000,
counter = 2,
gas_limit = 3,
storage_limit = 4,
ticket_contents = {'prim': 'UNPAIR'},
ticket_ty = {'prim': 'pair', 'args': [{'string': '1'}, {'int': 2}]},
ticket_ticketer = 'tz1ixvCiPJYyMjsp2nKBVaq54f6AdbV8hCKa',
ticket_amount = 1,
destination = 'KT18amZmM5W7qDWVt2pH6uj7sCEd3kbzLrHT',
entrypoint = 'S\n\nS\nS\nS'
)

data = app.sign(DEFAULT_ACCOUNT,
message,
Expand Down
Loading

0 comments on commit ec5813a

Please sign in to comment.