Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 17 additions & 23 deletions contrib/deterministic-build/find_restricted_dependencies.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
#!/usr/bin/env python3
import sys

try:
import requests
except ImportError as e:
sys.exit(f"Error: {str(e)}. Try 'python3 -m pip install <module-name>'")
from importlib.metadata import requires, PackageNotFoundError

def is_dependency_edge_blacklisted(*, parent_pkg: str, dep: str) -> bool:
"""Sometimes a package declares a hard dependency
Expand Down Expand Up @@ -38,26 +34,24 @@ def main():
if not p:
continue
assert "==" in p, "This script expects a list of packages with pinned version, e.g. package==1.2.3, not {}".format(p)
p, v = p.rsplit("==", 1)
try:
data = requests.get("https://pypi.org/pypi/{}/{}/json".format(p, v)).json()["info"]
except ValueError:
raise Exception("Package could not be found: {}=={}".format(p, v))
pkg_name, _ = p.rsplit("==", 1)
try:
for r in data["requires_dist"]: # type: str
if ";" not in r:
continue
# example value for "r" at this point: "pefile (>=2017.8.1) ; sys_platform == \"win32\""
dep, restricted = r.split(";", 1)
dep = dep.strip()
restricted = restricted.strip()
dep_basename = dep.split(" ")[0]
if check_restriction(dep=dep, restricted=restricted, parent_pkg=p):
print(dep_basename, sep=" ")
print("Installing {} from {} although it is only needed for {}".format(dep, p, restricted), file=sys.stderr)
except TypeError:
# Has no dependencies at all
reqs = requires(pkg_name)
except PackageNotFoundError:
raise Exception("Package not found in this environment: {}. Install it first.".format(p))
if reqs is None:
continue
for r in reqs:
if ";" not in r:
continue
# example value for "r": "pefile (>=2017.8.1) ; sys_platform == \"win32\""
dep, restricted = r.split(";", 1)
dep = dep.strip()
restricted = restricted.strip()
dep_basename = dep.split(" ")[0]
if check_restriction(dep=dep, restricted=restricted, parent_pkg=pkg_name):
print(dep_basename, sep=" ")
print("Installing {} from {} although it is only needed for {}".format(dep, pkg_name, restricted), file=sys.stderr)

if __name__ == "__main__":
main()
16 changes: 13 additions & 3 deletions contrib/freeze_packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ for suffix in '' '-hw' '-binaries' '-binaries-mac' '-build-wine' '-build-mac' '-
reqfile="requirements${suffix}.txt"

rm -rf "$venv_dir"
virtualenv -p "${SYSTEM_PYTHON}" "$venv_dir"
"${SYSTEM_PYTHON}" -m venv "$venv_dir"

source "$venv_dir/bin/activate"

Expand All @@ -36,16 +36,20 @@ for suffix in '' '-hw' '-binaries' '-binaries-mac' '-build-wine' '-build-mac' '-
# that we should explicitly install them now, so that we pin latest versions if possible.
python -m pip install --upgrade pip setuptools wheel

# install ghost packages to satisfy dependency resolvers
for package in $(cat "$contrib/requirements/ghost.txt"); do
python $contrib/install_ghost.py "$package"
done

python -m pip install -r "$contrib/requirements/${reqfile}" --upgrade

echo "OK."

requirements=$(pip freeze --all)

restricted=$(echo $requirements | ${SYSTEM_PYTHON} "$contrib/deterministic-build/find_restricted_dependencies.py")
restricted=$(echo $requirements | python "$contrib/deterministic-build/find_restricted_dependencies.py")
if [ ! -z "$restricted" ]; then
python -m pip install $restricted
requirements=$(pip freeze --all)
fi

echo "Generating package hashes... (${reqfile})"
Expand All @@ -67,6 +71,12 @@ for suffix in '' '-hw' '-binaries' '-binaries-mac' '-build-wine' '-build-mac' '-
HASHIN_FLAGS="--python-version source"
fi

# remove ghost packages before hashin step, so that they aren't hashed
for package in $(cat "$contrib/requirements/ghost.txt"); do
python -m pip uninstall -y $package
done
requirements=$(pip freeze --all)

echo -e "\r Hashing requirements for $reqfile..."
${SYSTEM_PYTHON} -m hashin $HASHIN_FLAGS -r "$contrib/deterministic-build/${reqfile}" $requirements

Expand Down
32 changes: 32 additions & 0 deletions contrib/install_ghost.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import sys, tempfile, subprocess
from pathlib import Path
from importlib.metadata import distribution


PYPROJECT_TOML = """
[project]
name = "{name}"
version = "{version}"
description = "Ghost package to satisfy dependencies"
"""


def install_ghost(name: str, version: str) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
pyproject_toml = PYPROJECT_TOML.format(name=name, version=version)
(Path(tmpdir) / "pyproject.toml").write_text(pyproject_toml)
subprocess.check_call([sys.executable, "-m", "pip", "install", tmpdir])

dist = distribution(name)
for file in dist.files:
path = file.locate()
if path.name == "direct_url.json":
path.unlink()


if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python install_ghost.py <package name>==<package version>")
sys.exit(1)
name, version = sys.argv[1].split("==")
install_ghost(name, version)
5 changes: 5 additions & 0 deletions contrib/requirements/ghost.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
click==8.3.1
construct==2.10.70
construct-classes==0.2.2
platformdirs==4.9.4
keyring==25.7.0
2 changes: 1 addition & 1 deletion contrib/requirements/requirements-hw.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
hidapi

# device plugin: trezor
trezor[hidapi]>=0.13.0,<0.14
trezor[hidapi]>=0.20.0,<0.21

# device plugin: safe_t
safet>=0.1.5
Expand Down
83 changes: 59 additions & 24 deletions electrum/plugins/trezor/clientbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
from electrum.plugin import runs_in_hwd_thread
from electrum.hw_wallet.plugin import OutdatedHwFirmwareException, HardwareClientBase

from trezorlib.client import TrezorClient, PASSPHRASE_ON_DEVICE
from trezorlib.client import TrezorClient, PassphraseSetting, get_default_client
from trezorlib.exceptions import TrezorFailure, Cancelled, OutdatedFirmwareError
from trezorlib.messages import WordRequestType, FailureType, ButtonRequestType
from trezorlib.messages import WordRequestType, FailureType, ButtonRequestType, Capability
import trezorlib.btc
import trezorlib.device

Expand Down Expand Up @@ -53,7 +53,14 @@ def __init__(self, transport, handler, plugin):
HardwareClientBase.__init__(self, plugin=plugin)
if plugin.is_outdated_fw_ignored():
TrezorClient.is_outdated = lambda *args, **kwargs: False
self.client = TrezorClient(transport, ui=self)

self.client = get_default_client(
app_name="Electrum",
path_or_transport=transport,
button_callback=self.button_request,
pin_callback=self.get_pin,
)
self._session = None
self.device = plugin.device
self.handler = handler
Logger.__init__(self)
Expand All @@ -65,6 +72,30 @@ def __init__(self, transport, handler, plugin):

self.used()

@property
def session(self):
if self._session is None:
assert self.handler is not None

# If needed, unlock the device (triggering PIN entry dialog for legacy model).
with self.client.get_session(passphrase=PassphraseSetting.STANDARD_WALLET) as session:
session.ensure_unlocked()

passphrase = PassphraseSetting.STANDARD_WALLET # (empty passphrase)
if self.client.features.passphrase_protection:
passphrase = self.get_passphrase(Capability.PassphraseEntry in self.client.features.capabilities)

# Then, derive a session for this wallet (possibly with a passphrase)
if passphrase == PassphraseSetting.STANDARD_WALLET:
self._session = session # reuse the session above to avoid re-derivation
self.logger.info("Opened standard %s", self._session)
else:
self._session = self.client.get_session(passphrase)
self.logger.info("Re-opened passphrase %s", self._session)

return self._session


def run_flow(self, message=None, creating_wallet=False):
if self.in_flow:
raise RuntimeError("Overlapping call to run_flow")
Expand Down Expand Up @@ -123,8 +154,9 @@ def has_usable_connection_with_device(self):
return True

try:
self.client.init_device()
self.client.ping(message="")
except BaseException:
self.logger.exception("Ping failed")
return False
return True

Expand All @@ -148,7 +180,7 @@ def i4b(self, x):
def get_xpub(self, bip32_path, xtype, creating=False):
address_n = parse_path(bip32_path)
with self.run_flow(creating_wallet=creating):
node = trezorlib.btc.get_public_node(self.client, address_n).node
node = trezorlib.btc.get_public_node(self.session, address_n).node
return BIP32Node(xtype=xtype,
eckey=ecc.ECPubkey(node.public_key),
chaincode=node.chain_code,
Expand All @@ -164,17 +196,17 @@ def toggle_passphrase(self):
msg = _("Confirm on your {} device to enable passphrases")
enabled = not self.features.passphrase_protection
with self.run_flow(msg):
trezorlib.device.apply_settings(self.client, use_passphrase=enabled)
trezorlib.device.apply_settings(self.session, use_passphrase=enabled)

@runs_in_hwd_thread
def change_label(self, label):
with self.run_flow(_("Confirm the new label on your {} device")):
trezorlib.device.apply_settings(self.client, label=label)
trezorlib.device.apply_settings(self.session, label=label)

@runs_in_hwd_thread
def change_homescreen(self, homescreen):
with self.run_flow(_("Confirm on your {} device to change your home screen")):
trezorlib.device.apply_settings(self.client, homescreen=homescreen)
trezorlib.device.apply_settings(self.session, homescreen=homescreen)

@runs_in_hwd_thread
def set_pin(self, remove):
Expand All @@ -185,7 +217,7 @@ def set_pin(self, remove):
else:
msg = _("Confirm on your {} device to set a PIN")
with self.run_flow(msg):
trezorlib.device.change_pin(self.client, remove)
trezorlib.device.change_pin(self.session, remove)

@runs_in_hwd_thread
def clear_session(self):
Expand All @@ -194,16 +226,19 @@ def clear_session(self):
self.logger.info(f"clear session: {self}")
self.prevent_timeouts()
try:
self.client.clear_session()
self.close()
except BaseException as e:
# If the device was removed it has the same effect...
self.logger.info(f"clear_session: ignoring error {e}")

@runs_in_hwd_thread
def close(self):
'''Called when Our wallet was closed or the device removed.'''
self.logger.info("closing client")
self.clear_session()
self.logger.info("locking: %s", self.client)
self.client.lock()
self.logger.info("closing: %s", self._session)
if self._session is not None:
self._session.close()

@runs_in_hwd_thread
def is_uptodate(self):
Expand Down Expand Up @@ -233,7 +268,7 @@ def show_address(self, address_str, script_type, multisig=None):
address_n = parse_path(address_str)
with self.run_flow():
return trezorlib.btc.get_address(
self.client,
self.session,
coin_name,
address_n,
show_display=True,
Expand All @@ -246,7 +281,7 @@ def sign_message(self, address_str, message, *, script_type):
address_n = parse_path(address_str)
with self.run_flow():
return trezorlib.btc.sign_message(
self.client,
self.session,
coin_name,
address_n,
message,
Expand All @@ -256,9 +291,9 @@ def sign_message(self, address_str, message, *, script_type):
@runs_in_hwd_thread
def recover_device(self, recovery_type, *args, **kwargs):
input_callback = self.mnemonic_callback(recovery_type)
with self.run_flow():
with self.run_flow(), self.client.get_session(None) as seedless_session:
return trezorlib.device.recover(
self.client,
seedless_session,
*args,
input_callback=input_callback,
type=recovery_type,
Expand All @@ -269,27 +304,27 @@ def recover_device(self, recovery_type, *args, **kwargs):
@runs_in_hwd_thread
def sign_tx(self, *args, **kwargs):
with self.run_flow():
return trezorlib.btc.sign_tx(self.client, *args, **kwargs)
return trezorlib.btc.sign_tx(self.session, *args, **kwargs)

@runs_in_hwd_thread
def get_ownership_id(self, *args, **kwargs):
with self.run_flow():
return trezorlib.btc.get_ownership_id(self.client, *args, **kwargs)
return trezorlib.btc.get_ownership_id(self.session, *args, **kwargs)

@runs_in_hwd_thread
def get_ownership_proof(self, *args, **kwargs):
with self.run_flow():
return trezorlib.btc.get_ownership_proof(self.client, *args, **kwargs)
return trezorlib.btc.get_ownership_proof(self.session, *args, **kwargs)

@runs_in_hwd_thread
def reset_device(self, *args, **kwargs):
with self.run_flow():
return trezorlib.device.reset(self.client, *args, **kwargs)
with self.run_flow(), self.client.get_session(None) as seedless_session:
return trezorlib.device.reset(seedless_session, *args, **kwargs)

@runs_in_hwd_thread
def wipe_device(self, *args, **kwargs):
with self.run_flow():
return trezorlib.device.wipe(self.client, *args, **kwargs)
with self.run_flow(), self.client.get_session(None) as seedless_session:
return trezorlib.device.wipe(seedless_session, *args, **kwargs)

# ========= UI methods ==========

Expand Down Expand Up @@ -335,7 +370,7 @@ def get_passphrase(self, available_on_device):

self.handler.passphrase_on_device = available_on_device
passphrase = self.handler.get_passphrase(msg, self.creating_wallet)
if passphrase is PASSPHRASE_ON_DEVICE:
if passphrase is PassphraseSetting.ON_DEVICE:
return passphrase
if passphrase is None:
raise Cancelled
Expand Down
8 changes: 5 additions & 3 deletions electrum/plugins/trezor/trezor.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
InputScriptType, OutputScriptType, MultisigRedeemScriptType,
TxInputType, TxOutputType, TxOutputBinType, TransactionType, AmountUnit)

from trezorlib.client import PASSPHRASE_ON_DEVICE
from trezorlib.client import PassphraseSetting
import trezorlib.log
#trezorlib.log.enable_debug_output()

PASSPHRASE_ON_DEVICE = PassphraseSetting.ON_DEVICE

TREZORLIB = True
except Exception as e:
if not (isinstance(e, ModuleNotFoundError) and e.name == 'trezorlib'):
Expand Down Expand Up @@ -153,8 +155,8 @@ class TrezorPlugin(HW_PluginBase):
libraries_URL = 'https://pypi.org/project/trezor/'
minimum_firmware = (1, 5, 2)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tested this on a T1 with fw 1.12.1 and with a model T with fw 2.6.4. Worked ok.
I expect you tested cutting edge fw, so no point for me to repeat that.

I also have another T1 with fw 1.8.3. That device works with electrum master and trezorlib 0.13.x, but not with this branch and new trezorlib.

This is what I get in the Electrum Wizard when trying to create a wallet with that trezor model one:

 10.69 | D | gui.qt.wizard.wallet | resolve_next view is trezor_xpub
 10.69 | D | gui.qt.wizard.wallet | wizard stack:
0: 0x7f3e8cd72d00 - {}
1: 0x7f3e8cd88200 - {'wallet_name': 'wallet_88', 'wallet_exists': False, 'wallet_is_open': False, 'password': '<redacted>', 'wallet_needs_hw_unlock': False}
2: 0x7f3e8cd81d00 - {'wallet_name': 'wallet_88', 'wallet_exists': False, 'wallet_is_open': False, 'password': '<redacted>', 'wallet_needs_hw_unlock': False, 'wallet_type': 'standard'}
3: 0x7f3e771a9880 - {'wallet_name': 'wallet_88', 'wallet_exists': False, 'wallet_is_open': False, 'password': '<redacted>', 'wallet_needs_hw_unlock': False, 'wallet_type': 'standard', 'keystore_type': 'hardware'}
4: 0x7f3e77360a00 - {'wallet_name': 'wallet_88', 'wallet_exists': False, 'wallet_is_open': False, 'password': '<redacted>', 'wallet_needs_hw_unlock': False, 'wallet_type': 'standard', 'keystore_type': 'hardware', 'hardware_device': ('trezor', DeviceInfo(device=Device(path='webusb:001:4', interface_number=-1, id_='webusb:001:4', product_key='Trezor', usage_page=0, transport_ui_string='webusb:001:4'), label='white', initialized=True, exception=None, plugin_name='trezor', soft_device_id='466354651092540CD6071750', model_name='Trezor One'))}
c: 0x7f3e77360f80 - {'wallet_name': 'wallet_88', 'wallet_exists': False, 'wallet_is_open': False, 'password': '<redacted>', 'wallet_needs_hw_unlock': False, 'wallet_type': 'standard', 'keystore_type': 'hardware', 'hardware_device': ('trezor', DeviceInfo(device=Device(path='webusb:001:4', interface_number=-1, id_='webusb:001:4', product_key='Trezor', usage_page=0, transport_ui_string='webusb:001:4'), label='white', initialized=True, exception=None, plugin_name='trezor', soft_device_id='466354651092540CD6071750', model_name='Trezor One')), 'script_type': 'p2wpkh', 'derivation_path': 'm/84h/1h/0h'}
 10.70 | D | gui.qt.wizard.wallet | load_next_component: <class 'electrum.plugins.trezor.qt.WCTrezorXPub'>
 10.70 | D | gui.qt.wizard.wallet | view "trezor_xpub" last: False
 10.74 | E | trezorlib.protocol_v1 | Trezor did not return a session ID. Session management is now broken.
/tmp/.mount_electrdPnlnC/usr/lib/python3.12/site-packages/trezorlib/protocol_v1.py:210: UserWarning: Your Trezor firmware does not support root fingerprint.
  warnings.warn("Your Trezor firmware does not support root fingerprint.")
 11.25 | E | plugins.trezor.qt.WCTrezorXPub | AssertionError()
Traceback (most recent call last):
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/site-packages/electrum/gui/qt/wizard/wallet.py", line 1438, in get_xpub_task
    self.xpub = self.get_xpub_from_client(_client, _derivation, _xtype)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/site-packages/electrum/plugins/trezor/qt.py", line 815, in get_xpub_from_client
    return client.get_xpub(derivation, xtype, True)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/site-packages/electrum/plugin.py", line 993, in wrapper
    return run_in_hwd_thread(partial(func, *args, **kwargs))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/site-packages/electrum/plugin.py", line 986, in run_in_hwd_thread
    return fut.result()
           ^^^^^^^^^^^^
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/concurrent/futures/_base.py", line 456, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/concurrent/futures/thread.py", line 59, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/site-packages/electrum/plugins/trezor/clientbase.py", line 183, in get_xpub
    node = trezorlib.btc.get_public_node(self.session, address_n).node
                                         ^^^^^^^^^^^^
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/site-packages/electrum/plugins/trezor/clientbase.py", line 82, in session
    session.ensure_unlocked()
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/site-packages/trezorlib/tools.py", line 336, in wrapper
    return context_func(context, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/.mount_electrdPnlnC/usr/lib/python3.12/site-packages/trezorlib/client.py", line 184, in ensure_unlocked
    assert resp.root_fingerprint is not None
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

I did not investigate the root cause. I guess if you think that's the best way to handle, we could just bump minimum_firmware. but you need to investigate at least to the degree that you know which version to bump to. :)

OTOH note that some people with geo-distributed cold multisigs likely won't be happy if we bump the minimum. Up to you.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Will take a look tomorrow.

Copy link
Copy Markdown
Contributor Author

@romanz romanz Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trezor/trezor-firmware#6580 should support old FWs.

keystore_class = TrezorKeyStore
minimum_library = (0, 13, 0)
maximum_library = (0, 14)
minimum_library = (0, 20, 0)
Copy link
Copy Markdown
Member

@SomberNight SomberNight Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please see SomberNight@f8226f9 and cherry-pick that or add something similar manually

I built an appimage and found that the plugin is broken at runtime due to the change to trezorlib.__version__.
ref https://github.com/trezor/trezor-firmware/blame/e754ba60a15c770de4667f072ae4e1f09c58e731/python/src/trezorlib/__init__.py#L21-L28
(btw note how the code says removal in 0.15 -- and you jumped from 0.14 to 0.20, guess that needs updating)

  8.16 | W | gui.qt.wizard.wallet.WCChooseHWDevice | error getting device infos for trezor: Library version for 'trezor' is incompatible. // Installed: unknown, Needed: 0.20.0 <= x < 0.21 // Make sure you install it with python3
>>> trezorlib.__version__
Traceback (most recent call last):
  File "<string>", line 1, in <module>
NameError: name 'trezorlib' is not defined
>>> import trezorlib
>>> trezorlib.__version__
Traceback (most recent call last):
  File "/tmp/.mount_electrcmMljC/usr/lib/python3.12/importlib/metadata/__init__.py", line 397, in from_name
    return next(cls.discover(name=name))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
StopIteration

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/tmp/.mount_electrcmMljC/usr/lib/python3.12/site-packages/trezorlib/__init__.py", line 27, in __getattr__
    return importlib.metadata.version("trezor")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/.mount_electrcmMljC/usr/lib/python3.12/importlib/metadata/__init__.py", line 889, in version
    return distribution(distribution_name).version
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/.mount_electrcmMljC/usr/lib/python3.12/importlib/metadata/__init__.py", line 862, in distribution
    return Distribution.from_name(distribution_name)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/.mount_electrcmMljC/usr/lib/python3.12/importlib/metadata/__init__.py", line 399, in from_name
    raise PackageNotFoundError(name)
importlib.metadata.PackageNotFoundError: No package metadata was found for trezor

We atm have a whitelist for which packages get .dist-info/ included and trezor needs to be put on that list now.
That's fine, it just needs to be added.

The issue in general with the .dist-info metadata stuff is that the RECORD file is often not reproducible, making the whole build not deterministic (see c52a29f). Usually it is due to packages building .so files with debug symbols, pip-random-generated-filesystem-paths, etc included. All that non-determinism in actual .so files we strip after-the-fact, see

info "stripping binaries from debug symbols."
# "-R .note.gnu.build-id" also strips the build id
# "-R .comment" also strips the GCC version information
strip_binaries()
{
chmod u+w -R "$APPDIR"
{
printf '%s\0' "$APPDIR/usr/bin/python${PY_VER_MAJOR}"
find "$APPDIR" -type f -regex '.*\.so\(\.[0-9.]+\)?$' -print0
} | xargs -0 --no-run-if-empty --verbose strip -R .note.gnu.build-id -R .comment
}
strip_binaries
, so the .so files we bundle are reproducible but the .dist-info/RECORD files are not. Further note that this stripping we do obviously changes the hashes of the .so files, making the RECORD files not consistent with the actual state. Hence it is best not to include the RECORD files (and we just rm the whole .dist-info/ dir).

but I just built two appimages and trezorlib's RECORD file is reproducible, so it can get whitelisted.

maximum_library = (0, 21)
SUPPORTED_XTYPES = ('standard', 'p2wpkh-p2sh', 'p2wpkh', 'p2wsh-p2sh', 'p2wsh')
DEVICE_IDS = (TREZOR_PRODUCT_KEY,)

Expand Down