Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ledger support #26

Closed
wants to merge 11 commits into from
Closed

Ledger support #26

wants to merge 11 commits into from

Conversation

bargst
Copy link

@bargst bargst commented Jun 5, 2018

What was wrong?

Issue #25

How was it fixed?

Create a class LedgerAccount

Cute Animal Picture

put a cute animal picture link inside the parentheses

Copy link
Member

@pipermerriam pipermerriam left a comment

Choose a reason for hiding this comment

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

Some preliminary feedback.

if len(element) == 1:
result = result + struct.pack(">I", int(element[0]))
else:
result = result + struct.pack(">I", 0x80000000 | int(element[0]))
Copy link
Member

Choose a reason for hiding this comment

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

Any chance we can get an explanation of what this code is doing and why with some inline comments?

offset = 1 + result[0]
address = result[offset + 1 : offset + 1 + result[offset]]

return f'0x{address.decode()}'
Copy link
Member

Choose a reason for hiding this comment

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

This should use eth_utils.to_normalized_address (assuming address is a bytes value.

result = result + struct.pack(">I", 0x80000000 | int(element[0]))
return result

def get_addresses(self, offset):
Copy link
Member

Choose a reason for hiding this comment

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

The name of this function suggests that it will return multiple addresses, but it seems to only return a single one.

"""
offset = 0
while address != self.get_addresses(offset):
offset += 1
Copy link
Member

Choose a reason for hiding this comment

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

Instead of this mutation pattern, how about:

import itertools

for offset in itertools.count():
    ...

Also, lets set an upper bound on this to some reasonable value (like 20?).

Copy link
Contributor

@carver carver Jun 5, 2018

Choose a reason for hiding this comment

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

Also, lets set an upper bound on this to some reasonable value (like 20?).

I'm not sure we can define what maximum number of addresses should be allowed against a wallet. I guess we can start with something like: how many addresses can we check in one second? At the least, we would need an escape hatch for people who might have tons of addresses, like:

    def get_offset(self, address, maximum_search_length=100):

(but with a better name)

Copy link
Member

Choose a reason for hiding this comment

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

Good plan, like the kwarg. how about search_limit? We should probably also allow for specifying the starting offset value.

@bargst
Copy link
Author

bargst commented Jun 6, 2018

Thanks for the feedback, I updated accordingly !

I will probably change the offset name to something more explicit like account_id.

Next is signTransaction() then encrypt() and signHash()

@pipermerriam
Copy link
Member

@carver probably something for us to do separately, but this feels like the time to create an abstract base class for accounts so the public required API is explicitly defined.

@carver
Copy link
Contributor

carver commented Jun 7, 2018

Note that encrypt() is probably not possible to implement (I hope!), so just the other two are sufficient. A draft of the spec is in #28.

Edit: see #29 for a preview of BaseAccount, which defines the appropriate interface

@bargst bargst changed the title initial Ledger support (WIP) [WIP] Ledger support Jun 7, 2018
class LedgerAccount:
"""
'''
Copy link

@dylanjw dylanjw Jun 7, 2018

Choose a reason for hiding this comment

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

Have a look at the PEP docstring format https://www.python.org/dev/peps/pep-0257/, I think it allows the docstring to get parsed correctly.

Copy link

Choose a reason for hiding this comment

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

Nevermind, I just noticed all the docstrings in the project use triple single quotes.


reply = self.device.exchange(apdu, timeout=60)
except:
raise Exception('Something went wrong when communicating with device')
Copy link

@dylanjw dylanjw Jun 7, 2018

Choose a reason for hiding this comment

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

Im not too keen on masking the underlying exception in all cases. Are there specific exceptions raised by the exchange method that could be made more friendly?

Copy link
Author

Choose a reason for hiding this comment

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

Ok, I will remove the try catch

@carver
Copy link
Contributor

carver commented Jun 7, 2018

After a rebase on master, you can subclass BaseAccount.

@bargst
Copy link
Author

bargst commented Jun 8, 2018

@carver signHash(), as currently defined, is not doable with the ledger: what is sent to the device is not the hash of the message, it is the whole message. The message is then hashed directly in the ledger and vrs signature are then returned.

Is it possible to have the message passed to signHash() in BaseAccount ?

@bargst
Copy link
Author

bargst commented Jun 12, 2018

@pipermerriam @carver I consider dev done, could you review ?
What's missing is commit history clean-up and a decision about signHash() issue.

@carver
Copy link
Contributor

carver commented Jun 12, 2018

decision about signHash() issue.

Yeah, signing is ugly right now. The process for hashing messages is not well standardized. It's baked into the hardware keys, so we can't have a single signMessage implemented by all the different signers as a drop-in replacement. They all do it a little differently.

So to support ledger signing, it should probably just be a custom method. ledgerSignMessage() is an option for the name. Alternatively, you could name it defunctSignMessage() (if it's the exact same hashing process as geth). It's called the defunct style elsewhere in eth-account.

You can raise a NotImplementedError from signHash saying that the Ledger doesn't support signing opaque hashes.

What's missing is commit history clean-up and a decision about signHash() issue.

Also, passing CI tests :)

@dylanjw
Copy link

dylanjw commented Jun 12, 2018

Because ledgerblue depends on pycrypto, and some of the other dependencies (eth-keyfile) have replaced it with pycryptodome, we are getting errors on this branch, like the following:

ImportError while importing test module '/home/dwilson/Develop/Projects/ethereum/eth-account/tests/core/test_ledger.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/core/test_ledger.py:5: in <module>
    from eth_account import (
eth_account/__init__.py:1: in <module>
    from eth_account.account import Account  # noqa: F401
eth_account/account.py:10: in <module>
    from eth_keyfile import (
venv/lib/python3.6/site-packages/eth_keyfile/__init__.py:7: in <module>
    from eth_keyfile.keyfile import (  # noqa: F401
venv/lib/python3.6/site-packages/eth_keyfile/keyfile.py:6: in <module>
    from Crypto.Cipher import AES
venv/lib/python3.6/site-packages/Crypto/Cipher/__init__.py:3: in <module>
    from Crypto.Cipher._mode_ecb import _create_ecb_cipher
venv/lib/python3.6/site-packages/Crypto/Cipher/_mode_ecb.py:29: in <module>
    from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
venv/lib/python3.6/site-packages/Crypto/Util/_raw_api.py:32: in <module>
    from Crypto.Util.py3compat import byte_string
E   ImportError: cannot import name 'byte_string'

There is an open issue on ledgerblue: LedgerHQ/blue-loader-python#44

@carver
Copy link
Contributor

carver commented Jun 12, 2018

Hm, maybe we should use pycryptodomex in eth-hash, eth-keys, eth-keyfile, etc, as recommended here: http://pycryptodome.readthedocs.io/en/latest/src/introduction.html

Or maybe just upgrade ledger software to use pycryptodome :)

Copy link
Member

@pipermerriam pipermerriam left a comment

Choose a reason for hiding this comment

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

If I understand correctly, test_ledger.py won't be runnable in CI. If so, can you move it to a new tests/integration/ledger/... directory. In addition, will you add a README to that directory which explains how to run the tests and what the per-requisits are.

@carver
Copy link
Contributor

carver commented Jun 12, 2018

Right now the tests are failing for fixable reasons, so I want to see those get resolved before we hide them in a test that's skipped by CI.


'''

def __init__(self, account_id=0, address='', path_prefix=ETH_DERIVATION_PATH_PREFIX):
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer None as the default value for address here.


for account_id in itertools.count(start=search_account_id):
if account_id > search_limit:
raise Exception(f'Address {address} not found' +
Copy link
Member

Choose a reason for hiding this comment

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

Prefer use of ValueError or even a custom exception type here rather than a bare Exception

raise Exception(f'Address {address} not found' +
f'(search_limit={search_limit}, ' +
f'search_account_id={search_account_id})')
if address == self.get_address(account_id):
Copy link
Member

Choose a reason for hiding this comment

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

This should probably use eth_utils.is_same_address

'''
List Ethereum HD wallet adrress of the ledger device
'''
return list(map(lambda account_id: self.get_address(account_id),
Copy link
Member

Choose a reason for hiding this comment

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

I think the lambda isn't needed here, you should be able to just pass in self.get_address.

Alternate way to do this which I think is more readable

return [self.get_address(account_id) for account_id in range(...)]

if address == self.get_address(account_id):
return account_id

def list(self, limit=5, page=0):
Copy link
Member

Choose a reason for hiding this comment

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

Alternate name suggestion get_addresses

'''
Not available with a Ledger
'''
raise Exception('signHash() is not available within ledger devices')
Copy link
Member

Choose a reason for hiding this comment

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

Can you use NotImplementedError here.

r = int.from_bytes(result[1:1 + 32], 'big')
s = int.from_bytes(result[1 + 32: 1 + 32 + 32], 'big')

rlp_encoded = encode_transaction(unsigned_transaction, vrs=(v, r, s))
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious if we should have a bit of validation here to sanity check that the returned signature does indeed belong to the expected signing address?

Copy link
Author

Choose a reason for hiding this comment

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

The sanity test has been added

setup.py Outdated
@@ -6,6 +6,9 @@
)

extras_require={
'ledger': [
"ledgerblue==0.1.17",
Copy link
Member

Choose a reason for hiding this comment

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

Should we change this to be a version range, maybe just pinned within the minor version? ledgerblue>=0.1.17,<0.2.0

@bargst
Copy link
Author

bargst commented Jun 13, 2018

I will now try to:

What's your thought on the third point ?

@carver
Copy link
Contributor

carver commented Jun 13, 2018

look at the complexity to just extract the dongle interface to the device from ledgerblue to import it in eth-account directly

Sorry, I don't know much about the internals here of the dongle interface. Can you show how this proposal would change the eth-account API?

@bargst
Copy link
Author

bargst commented Jun 14, 2018

@carver I see it as copying and adapting HIDDongleHIDAPI class from https://github.com/LedgerHQ/blue-loader-python/blob/master/ledgerblue/comm.py#L56 and inserting it in ledger.py directly.
Then in LedgerAccount._send_to_device() use this new class instead of ledgerblue.comm.getDongle()

This HIDDongleHIDAPI class only has a dependency on 'hidapi>=0.7.99' and so we can get rid of ledgerbue requirement, but off course I need to make a small POC ...

@pipermerriam
Copy link
Member

so we can get rid of ledgerbue requirement

This would be great in theory. Will have to see how it looks in practice.

@bargst
Copy link
Author

bargst commented Jun 16, 2018

I don't know why but I can't find a way to make the defunctSignMessage() work with my ledger and I don't think it is a requirement for supporting ledger in eth-account so I won't dig deeper and instead focus on ledegerblue dependency.

@bargst
Copy link
Author

bargst commented Jun 20, 2018

I will try to simplify USBDevice class to be cleaner. Maybe we can do like geth where they have implemented a usbwallet.driver so it can be used by other hardware device: https://github.com/ethereum/go-ethereum/blob/master/accounts/usbwallet/ledger.go

Copy link
Member

@pipermerriam pipermerriam left a comment

Choose a reason for hiding this comment

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

  • The two wrap and unwrap APDU methods are quite long and don't read well. Do you think you could add some comments to explain what exactly is happening in them?
  • All of the method and variable names should be updated to use snake_casing instead of camelCasing
  • All Exception and BaseException usage should be updated to use either an appropriate standard library exception or a custom exception class.

time.sleep(0.0001)
return bytearray(data)

def wrapCommandAPDU(self, channel, command, packetSize):
Copy link
Member

Choose a reason for hiding this comment

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

This method doesn't appear to use self. What do you think about extracting it to a utility function so that it can have some basic tests written for it (which will also allow it to be easily tested in isolation)

def waitFirstResponse(self, timeout):
start = time.time()
data = ""
while len(data) == 0:
Copy link
Member

Choose a reason for hiding this comment

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

Maybe a cleaner way to do this

start_at = time.time()
while True:
    data = self.device.read(65)
    if data:
        break
    else:
        # check timeout, sleep, etc

result += b"\x00"
return bytearray(result)

def unwrapResponseAPDU(self, channel, data, packetSize):
Copy link
Member

Choose a reason for hiding this comment

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

Same with this method. No self usage so it should be able to be extracted into a utility method and tested in isolation.

possibleCause = "Condition of use not satisfied (denied by the user?)"
if sw == 0x6a84 or sw == 0x6a85:
possibleCause = "Not enough space?"
if sw == 0x6484:
Copy link
Member

Choose a reason for hiding this comment

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

These should probably all be elif clauses.

if self.debug:
print("HID <= %s %.2x" % (to_hex(response), sw))
if sw != 0x9000:
possibleCause = "Unknown reason"
Copy link
Member

Choose a reason for hiding this comment

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

Can you move this to a final else clause.

result.extend(bytearray(self.device.read(65)))
sw = (result[swOffset] << 8) + result[swOffset + 1]
response = result[dataStart : dataLength + dataStart]
if self.debug:
Copy link
Member

Choose a reason for hiding this comment

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

Can you drop the debug flag and instead use the standard python logging facilities. We don't ship with print statements.

class LedgerUsbDevice:
    logger = logging.getLogger('eth_account.signers.ledger.LedgerUsbDevices')

    def some_method(self):
        self.logging.debug('the message')

@bargst
Copy link
Author

bargst commented Jun 24, 2018

I think the use of the hidapi is the way to go, so I spent some time cleanly implementing it with comments. Hope it looks like it could be possibly merged this way ? :)

I still have to move test_ledger.py to tests/integration/ledger/... directory and make a README for tests usage.

Copy link

@dylanjw dylanjw left a comment

Choose a reason for hiding this comment

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

Mostly optional nitpicky stuff. The only big question is it doesnt look like there is handling for transactions larger than 255 bytes.

packet = header + commands[packet_id]

# Add padding to the packet to make it exactly PACKET_SIZE long
packet += bytes([0x0] * (PACKET_SIZE - len(packet)))
Copy link

Choose a reason for hiding this comment

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

could this be simplified with ljust?

packet.ljust(PACKET_SIZE, bytes([0x0]))

command = struct.pack('>H', len(command)) + command

# Split command into at max PACKET_FREE sized chunks
commands = [command[i:i + PACKET_FREE] for i in range(0, len(command), PACKET_FREE)]
Copy link

Choose a reason for hiding this comment

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

The var name commands was confusing the first couple times reading through. Could it be something like command_chunks, command_packets, or simply chunks?

class LedgerUsbDevice:
'''
References:
- https://github.com/LedgerHQ/blue-loader-python/blob/master/ledgerblue/comm.py#L56
Copy link

Choose a reason for hiding this comment

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

Should the comm reference be taken out now that it is no longer used, or is it an important example for how the ledger works?

Copy link
Author

Choose a reason for hiding this comment

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

I would rather let it as is because part of the comm module are still present (device detection for ex.)

for hidDevice in hid.enumerate(0, 0):
if hidDevice['vendor_id'] == 0x2c97:
if ('interface_number' in hidDevice and hidDevice['interface_number'] == 0) \
or ('usage_page' in hidDevice and hidDevice['usage_page'] == 0xffa0):
Copy link

Choose a reason for hiding this comment

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

Could these hex values be put in global constants? LEDGER_VENDOR_ID and LEDGER_USAGE_PAGE_ID?

if not channel:
if reply_start + timeout < time.time():
raise LedgerUsbException(f'Timeout waiting for a device' +
f'response (timeout={timeout}s)')
Copy link

Choose a reason for hiding this comment

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

TIL about f-strings!

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, they're pretty cool. I can't wait to use them more broadly! Unfortunately f-strings weren't added until 3.6, but Web3.py (and therefore eth-account) has to support py3.5. So this will have to be switched out for % or .format style instead. :(

Copy link
Author

Choose a reason for hiding this comment

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

That explain why circleCI lint was failing ! Too bad we are not on 3.6 :)
I will update to remove all f-strings.

# Status is stored at then end of the reply
(status,) = struct.unpack('>H', reply[-2:])

if status == 0x9000:
Copy link

Choose a reason for hiding this comment

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

What does 0x9000 mean? A constant var could explain this.

rlp_encoded_tx = rlp.encode(unsigned_transaction)

# https://github.com/LedgerHQ/blue-app-eth/blob/master/doc/ethapp.asc#sign-eth-transaction
apdu = bytes.fromhex('e0040000')
Copy link

Choose a reason for hiding this comment

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

'e0040000' could be saved to a constant, with a descriptive name like: ADPU_SIGN_TX_FIRST_DATA_BLOCK

apdu = bytes.fromhex('e0040000')
apdu += bytes([len(bip32_path) + len(rlp_encoded_tx)])
apdu += bip32_path
apdu += rlp_encoded_tx
Copy link

Choose a reason for hiding this comment

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

What happens if the rlp_encoded_tx is greater than the 255 byte limit? Should this be getting chunked and sent with the next data block adpu ('e0048000')?

Copy link
Author

Choose a reason for hiding this comment

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

The chunk is done by the exchange() function, but I will add a test to see if it is working as expected.

@bargst
Copy link
Author

bargst commented Jun 30, 2018

@dylanjw you were right ! Transaction larger than 255 would not be signed. Now fixed !

@bargst bargst force-pushed the ledger branch 2 times, most recently from c81fcec to 457dd86 Compare June 30, 2018 17:18
@bargst
Copy link
Author

bargst commented Jul 2, 2018

I finally found a way to make defunctSignMessage() work and sign message on the ledger !

I think the PR is now worth reviewing @pipermerriam @carver @dylanjw but do you want me to squash history before or after review ?

This PR now use hidapi python module and do not rely anymore on ledgerblue.

@carver
Copy link
Contributor

carver commented Jul 10, 2018

Squashing can happen after. I should be able to do another review tomorrow.

@carver
Copy link
Contributor

carver commented Jul 13, 2018

... and by tomorrow I mean next week. Sorry for the delay. I've been pretty heads-down on getting the next trinity release out the door.

Copy link
Contributor

@carver carver left a comment

Choose a reason for hiding this comment

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

Not a full review, but at least something to get started on.

)

# Not a fixture because it does not support multiple LedgerAccount
ledger = LedgerAccount()
Copy link
Contributor

Choose a reason for hiding this comment

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

What does it mean that "it does not support multiple LedgerAccount"? Maybe it should be a session fixture, like:

@pytest.fixture(scope="session")
def ledger:
  return LedgerAccount()


@pytest.fixture
def acct(request):
return Account
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like this could just be Account down below, and drop the acct fixture altogether.

assert type(signed.r) is str
assert type(signed.s) is str

assert signed.hash == tx_hash
Copy link
Contributor

Choose a reason for hiding this comment

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

This approach looks problematic. The tx_hash will be different for every ledger, because it will be a different account signing it. So if I ran it on my own ledger, the test would fail. Am I missing something?

I guess one way to make it work would be to include a test setup with a (burned) mnemonic that everyone can use to initialize their ledger to the same account before the test.

assert len(accounts_4p1) == 4
assert accounts_4p0 == accounts_10[:4]
assert accounts_4p1 == accounts_10[4:8]
assert accounts_10 == (accounts_4p0 + accounts_4p1 + accounts_4p2[:2])
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe just do accounts_12 instead of accounts_10 above, then all three of these assertions can be dropped for: assert accounts_12 == accounts_4p0 + accounts_4p1 + accounts_4p2.

accounts_4p0 = ledger.get_addresses(limit=4, page=0)
accounts_4p1 = ledger.get_addresses(limit=4, page=1)
accounts_4p2 = ledger.get_addresses(limit=4, page=2)
assert len(accounts_4p1) == 4
Copy link
Contributor

Choose a reason for hiding this comment

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

Might as well check the length of all three


assert signed.hash == tx_hash

assert acct.recoverTransaction(signed.rawTransaction).lower() == expected_sender
Copy link
Contributor

Choose a reason for hiding this comment

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

ledger.address should return the address in checksum format. Then this doesn't need to be lower()d in the assertion.


assert type(signed.v) is int
assert type(signed.r) is str
assert type(signed.s) is str
Copy link
Contributor

Choose a reason for hiding this comment

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

r and s should also be returned from signTransaciton() as int, like http://eth-account.readthedocs.io/en/latest/eth_account.html#eth_account.account.Account.signTransaction

Assuming r and s are hex strings, you can convert with eth_utils.to_int(hexstr=r)

assert signed.messageHash == msghash
assert type(signed.v) is int
assert type(signed.r) is str
assert type(signed.s) is str
Copy link
Contributor

Choose a reason for hiding this comment

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

@@ -0,0 +1,116 @@
# Require a connected Ledger ...
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe even better to point to the readme, like:

# This test requires a connected Ledger
# For setup instructions see tests/integration/ledger/README.md

pip install -e .[ledger]
```

Run the tests with:
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably need to set up the ledger somehow first right? From the other comments, maybe we need a shared seed for testing.

Copy link
Author

@bargst bargst Jul 25, 2018

Choose a reason for hiding this comment

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

You were right, I added a seed in the README and used it in the tests.

@bargst
Copy link
Author

bargst commented Jul 25, 2018

@carver I updated following your review. I tested using the seed and it worked on both a nanos and a ledger blue using he hidapi approach !

@bargst bargst changed the title [WIP] Ledger support Ledger support Aug 7, 2018
@bargst
Copy link
Author

bargst commented Aug 7, 2018

@carver seems my PR missed the 0.3.0 release :)

@bargst
Copy link
Author

bargst commented Sep 3, 2018

@carver @pipermerriam do you think this PR still needs some work ?

The function defunctSignMessage() is not working but is added for
documentation purpose.
- remove ledgerblue dependency
- pack all device comm in LedgerUsbDevice class
- small fixes
- make transaction larger than 255 bytes be able to be signed !
- use checksumed address
- return r and s as int
- Add instruction for ledger init using a well defined seed
- add ledger as a sessions fixture
- add tx_signed and addresses values related to the new seed
- update tests to use new defined seed
@pipermerriam
Copy link
Member

@bargst sorry for our silence, 👀

@pipermerriam
Copy link
Member

@bargst thanks so much for this. Merged in #34

This pr, and the new HDAccount one both fall into a category where we'll need to do an in-depth review and security audit before we can include in master and release for public use. Our current workload suggests it'll be later this year after Devcon before we can do that so we've merged into a local feature branch until that time.

Thank you for your contribution. It's going to be a big improvement.

@bargst
Copy link
Author

bargst commented Sep 27, 2018

Thanks @pipermerriam for merging ! I will close this PR, feel free to ping me during review/audit :)

@bargst bargst closed this Sep 27, 2018
carver added a commit to carver/eth-account that referenced this pull request May 3, 2019
…ve-pypy-markdown-support

switch to native pypy markdown support
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants