Page MenuHomePhabricator

[electrum] Sign stakes using Trezor devices
ClosedPublic

Authored by Fabien on Tue, Jan 21, 14:22.

Details

Reviewers
PiRK
Group Reviewers
Restricted Project
Commits
rABC7ca27c8ac51b: [electrum] Sign stakes using Trezor devices
Summary

This makes it possible to sign stakes with a Trezor device running a compatible firmware.
For now such a firmware doesn't exist unless it's built manually (so it's not official).

Test Plan

Sign a proof with a Trezor.
Run the tests.

Diff Detail

Repository
rABC Bitcoin ABC
Branch
electrum_sign_stake_trezor
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 32391
Build 64271: Build Diffelectrum-tests
Build 64270: arc lint + arc unit

Event Timeline

Tail of the build log:

======================================================================
FAIL: test_proof_data (electrumabc.tests.test_avalanche.TestAvalancheProofFromHex.test_proof_data)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/work/electrum/electrumabc/tests/test_avalanche.py", line 445, in test_proof_data
    proof = Proof.from_hex(expected_proof1)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 58, in from_hex
    return cls.deserialize(BytesIO(bytes.fromhex(hex_str)))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 221, in deserialize
    return Proof(
           ^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 188, in __init__
    self.limitedid = LimitedProofId.build(
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 136, in build
    ss += serialize_sequence(stakes)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 128, in serialize_sequence
    b += obj.serialize()
         ^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 96, in serialize
    assert self.pubkey
AssertionError

======================================================================
FAIL: test_proofid (electrumabc.tests.test_avalanche.TestAvalancheProofFromHex.test_proofid)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/work/electrum/electrumabc/tests/test_avalanche.py", line 388, in test_proofid
    proof = Proof.from_hex(
            ^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 58, in from_hex
    return cls.deserialize(BytesIO(bytes.fromhex(hex_str)))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 221, in deserialize
    return Proof(
           ^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 188, in __init__
    self.limitedid = LimitedProofId.build(
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 136, in build
    ss += serialize_sequence(stakes)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 128, in serialize_sequence
    b += obj.serialize()
         ^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 96, in serialize
    assert self.pubkey
AssertionError

----------------------------------------------------------------------
Ran 334 tests in 30.140s

FAILED (failures=4, errors=4, skipped=4)
Testing `setup.py --version`: OK

ninja: build stopped: cannot make progress due to previous errors.
Build electrum-tests failed with exit code 1

Back out unrelated changes

Tail of the build log:

======================================================================
FAIL: test_proof_data (electrumabc.tests.test_avalanche.TestAvalancheProofFromHex.test_proof_data)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/work/electrum/electrumabc/tests/test_avalanche.py", line 445, in test_proof_data
    proof = Proof.from_hex(expected_proof1)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 58, in from_hex
    return cls.deserialize(BytesIO(bytes.fromhex(hex_str)))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 221, in deserialize
    return Proof(
           ^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 188, in __init__
    self.limitedid = LimitedProofId.build(
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 136, in build
    ss += serialize_sequence(stakes)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 128, in serialize_sequence
    b += obj.serialize()
         ^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 96, in serialize
    assert self.pubkey
AssertionError

======================================================================
FAIL: test_proofid (electrumabc.tests.test_avalanche.TestAvalancheProofFromHex.test_proofid)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/work/electrum/electrumabc/tests/test_avalanche.py", line 388, in test_proofid
    proof = Proof.from_hex(
            ^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 58, in from_hex
    return cls.deserialize(BytesIO(bytes.fromhex(hex_str)))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 221, in deserialize
    return Proof(
           ^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 188, in __init__
    self.limitedid = LimitedProofId.build(
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 136, in build
    ss += serialize_sequence(stakes)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 128, in serialize_sequence
    b += obj.serialize()
         ^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 96, in serialize
    assert self.pubkey
AssertionError

----------------------------------------------------------------------
Ran 334 tests in 22.730s

FAILED (failures=4, errors=5, skipped=4)
Testing `setup.py --version`: OK

ninja: build stopped: cannot make progress due to previous errors.
Build electrum-tests failed with exit code 1

Tail of the build log:

======================================================================
FAIL: test_proof_data (electrumabc.tests.test_avalanche.TestAvalancheProofFromHex.test_proof_data)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/work/electrum/electrumabc/tests/test_avalanche.py", line 445, in test_proof_data
    proof = Proof.from_hex(expected_proof1)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 58, in from_hex
    return cls.deserialize(BytesIO(bytes.fromhex(hex_str)))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 221, in deserialize
    return Proof(
           ^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 188, in __init__
    self.limitedid = LimitedProofId.build(
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 136, in build
    ss += serialize_sequence(stakes)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 128, in serialize_sequence
    b += obj.serialize()
         ^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 96, in serialize
    assert self.pubkey
AssertionError

======================================================================
FAIL: test_proofid (electrumabc.tests.test_avalanche.TestAvalancheProofFromHex.test_proofid)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/work/electrum/electrumabc/tests/test_avalanche.py", line 388, in test_proofid
    proof = Proof.from_hex(
            ^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 58, in from_hex
    return cls.deserialize(BytesIO(bytes.fromhex(hex_str)))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 221, in deserialize
    return Proof(
           ^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 188, in __init__
    self.limitedid = LimitedProofId.build(
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 136, in build
    ss += serialize_sequence(stakes)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/serialize.py", line 128, in serialize_sequence
    b += obj.serialize()
         ^^^^^^^^^^^^^^^
  File "/work/electrum/electrumabc/avalanche/proof.py", line 96, in serialize
    assert self.pubkey
AssertionError

----------------------------------------------------------------------
Ran 334 tests in 42.445s

FAILED (failures=4, errors=5, skipped=4)
Testing `setup.py --version`: OK

ninja: build stopped: cannot make progress due to previous errors.
Build electrum-tests failed with exit code 1
PiRK added inline comments.
electrum/electrumabc/avalanche/proof.py
284 ↗(On Diff #52432)

Optional[AbstractWallet]?

electrum/electrumabc/tests/test_avalanche.py
227 ↗(On Diff #52432)

Wrong indentation? I think the test is doing nothing at the moment.

electrum/electrumabc_gui/qt/main_window.py
956–964 ↗(On Diff #52432)

Is this supposed to dynamically enable the menu action when the device is initialized and the firmware version is known? Or just delay the decision until the time the menu is shown the first time, in the hope that at this time the firmware version number is known?

At the moment it can just disable the tools, not enable it if necessary.

electrum/electrumabc_plugins/trezor/clientbase.py
283 ↗(On Diff #52432)

PublicKey.keydata is already used publicly in other places (e.g. DelegationEditor), so the round trip to/from hex is not necessary.

Fix the stake id not being computed upon import

Fabien edited the test plan for this revision. (Show Details)
Fabien marked 2 inline comments as done.Tue, Feb 11, 19:44
Fabien added inline comments.
electrum/electrumabc/avalanche/proof.py
284 ↗(On Diff #52432)

why? It's not optional

electrum/electrumabc_gui/qt/main_window.py
956–964 ↗(On Diff #52432)

This is a delay. When the menu is first built the support status is not known so it needs to be enabled or disabled later (when the user is able to click it).

Cleanup, use the hw features capabilities to determine is stake signing is supported. This will avoid conflicts with Trezor firmware updates

Fabien published this revision for review.Wed, Feb 12, 09:46
Fabien edited the summary of this revision. (Show Details)
electrum/electrumabc/avalanche/proof.py
284 ↗(On Diff #52432)

Ok. I think the issue is in init where it shouldn't be optional.

electrum/electrumabc/avalanche/proof.py
249 ↗(On Diff #52623)

not Optional?

electrum/electrumabc/avalanche/proof.py
249 ↗(On Diff #52623)

Good catch

Fix signing with a password protected wallet

This revision is now accepted and ready to land.Thu, Feb 13, 07:50
PiRK requested changes to this revision.Thu, Feb 13, 07:56
PiRK added inline comments.
electrum/electrumabc_plugins/trezor/clientbase.py
6 ↗(On Diff #52627)

This import is going to cause error with all previous versions of trezorlib

This revision now requires changes to proceed.Thu, Feb 13, 07:56
electrum/electrumabc_plugins/trezor/clientbase.py
6 ↗(On Diff #52627)
272 ↗(On Diff #52627)

Fix the import of trezorlib.ecash if not supported.
Fix the use of the non-existent capabability in trezorlib.

This revision is now accepted and ready to land.Thu, Feb 13, 09:59
This revision was automatically updated to reflect the committed changes.