-
-
Notifications
You must be signed in to change notification settings - Fork 232
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
[Stellar] [WIP] Add protobuf messages to support Stellar #63
Conversation
protob/messages.proto
Outdated
////////////////////// | ||
|
||
/** | ||
* In: request for the public key at the specified index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use Request:
and @next
protob/messages.proto
Outdated
} | ||
|
||
/** | ||
* Out: public key for the given index |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use Response:
and @prev
protob/messages.proto
Outdated
* In: request for the public key at the specified index | ||
*/ | ||
message StellarGetPublicKey { | ||
required uint32 index = 1; // Account index (derived as m/44'/148'/index') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use optional
instead of required
https://developers.google.com/protocol-buffers/docs/proto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you clarify why this one should be optional? I'd like to ensure that an index is always passed with this message.
protob/messages.proto
Outdated
* In: request to sign the given transaction | ||
*/ | ||
message StellarSignTx { | ||
required uint32 index = 1; // Account index (derived as m/44'/148'/index') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any specific reason to not use repeated uint32 address_n
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I worked with the Stellar team and the developer working on Ledger support to standardize on a specific derivation path where the only thing the user can choose is an index. To keep things consistent, I'd prefer to prevent the user from overriding this.
More details here: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md
High-level remark: I don't like all the parsing that happens inside of the TREZOR. If you look at the implementation of other coins, what we do is that the client wallet does the parsing and passes already parsed structures to the device. The device can then build the binary stream (which is much safer than parsing), signs and (optionally returns) the constructed data together with the signature. I would be really happy if we changed the high-level logic in this fashion. |
@prusnak I see where you're coming from on this, and I was originally hoping to go that way, but I think you'd end up with a more complicated situation. Re-assembling the protobuf messages into XDR would require code with the same amount of complexity, but going the other direction. For example, I'd need In addition, I'd need to add XDR parsing to the client applications to build the protobuf messages. This wouldn't be too bad for javascript (since there's an official library) but I don't believe there's an official one for python so it would mean adding a third-party dependency or a lot of custom code to python-trezor. Is there some way I could add test cases to trezor-mcu or something else I could do to make you more comfortable with all the parsing? |
protob/messages.proto
Outdated
} | ||
|
||
/** | ||
* Request: Next operation in the transaction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be Response:
protob/messages.proto
Outdated
} | ||
|
||
/** | ||
* Response: next operation to sign |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be Request:
protob/messages.proto
Outdated
* @next StellarPublicKey | ||
*/ | ||
message StellarGetPublicKey { | ||
required uint32 index = 1; // Account index (derived as m/44'/148'/index') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use optional
instead of required
.
The rationale is explained in https://developers.google.com/protocol-buffers/docs/proto#specifying-field-rules under "Required Is Forever". Furthermore, Proto3 has removed required
.
protob/messages.proto
Outdated
* @next StellarSignedTx | ||
*/ | ||
message StellarTxOpAck { | ||
required bytes xdr = 1; // XDR-encoded bytes starting at the offset requested in StellarTxOpRequest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation
protob/messages.proto
Outdated
* @prev StellarTxOpAck | ||
*/ | ||
message StellarSignedTx { | ||
required bytes public_key = 1; // public key for the private key used to sign data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation
It will not be a more complicated situation for firmware, it will be much more simple in the firmware and this is more important as this is the critical code.
Agreed.
The logic is - if you have a wallet code that wants to interact with TREZOR, you already have all parsing primitives in the codebase. So you don't need to write it. Python-trezor is a specific example, because it is not a wallet, but I am still more OK with making python-trezor codebase more complex while making trezor-mcu codebase more simple.
It's not about making someone comfortable, it's about keeping the high-level idea of the device consistent. Imagine if every coin wanted to add their parsing routines in the mcu-code ... |
Also, it is far easier to understand the protocol if you look into the protobuf definition rather than looking into parsing code, which creates another added value. Would you be willing to rewrite the this PR and the other PR to use the parsing logic outside of the mcu-code? |
Definitely agreed there!
Yes, I'll rewrite the code that parses the transaction header to use protobuf messages and update python-trezor. Once I have that working (hopefully within a few days) I'll push it to this branch so you can verify it's going in the direction you expect. If that all looks good, I'll continue on and create messages for the rest of the operations. @saleemrashid - Thanks for your updated comments, I'll fix those problems as well! |
Love it! |
@zulucrypto No problem! Also your |
@prusnak - I've just pushed changes to all three PRs with the refactor to parse the XDR in python and send protobuf messages to the Trezor. I think it ended up being simpler overall, so thank you for sending me in this direction. I also discovered that there's a built-in XDR parsing library in Python, so that side was easier than I expected. Since it was easier, I was able to re-implement the transaction header parsing, the payment operation parsing, and also add the "create account" operation. Something I'd like your opinion on: right now, both the "payment" and "create account" operations share the However, from a design perspective it seems to make more sense to map each operation to its own protobuf message instead of taking the "union" approach. Any thoughts? |
Can you elaborate more on the overlap? I'd like to see which fields are shared and which not. |
Can you elaborate more on the overlap? I'd like to see which fields are shared and which not to make a decision. |
Current message:
Fields used for each operation: Common to all operations
Create Account
Payment
Path Payment (not implemented yet)
Manage Offer (not implemented yet)
Passive Offer (not implemented yet)
Set Options (not implemented yet)
Change Trust (not implemented yet)
Allow Trust (not implemented yet)
Account Merge (not implemented yet)
Manage Data (not implemented yet)
|
@zulucrypto You might want to take a look at how I implemented NEM support. If you look at |
@prusnak I decided to implement each Stellar operation as its own message. I've just pushed updates to this branch, the trezor-mcu repo, and the python-trezor repo. All operations are now implemented and I don't anticipate adding any more major functionality. I'll be doing some more testing here, but it should be ready for review again. |
Thank you! I have something to do this week, but hopefully I will have
time to review this the week after!
|
protob/messages.proto
Outdated
* @next StellarPublicKey | ||
*/ | ||
message StellarGetPublicKey { | ||
optional uint32 index = 1; // Account index (derived as m/44'/148'/index') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand why you want to enforce the BIP-32 path, but it should use address_n
to be consistent with all other supported coins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should use
address_n
...
Will do, are you OK with me using the address_n convention but only having one element in the array? Or would you still like it to be an n-element array and have the client be in charge of passing in the 44'/144'
parts as well as the index?
I'll work on the rest of the changes as well!
Edit: I was just talking with the developer who did the Ledger implementation and he supports paths like m/44'/144'/1'/2'/3'
so I'll take this route as well. The m/44'/144'
part is hardcoded by Ledger, so would you be OK with me hardcoding this part of the path on the Trezor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We never hardcode paths in the device as we try to avoid application specific code in the device codebase. We might revisit that in the future, but please always include full path.
protob/messages.proto
Outdated
* Request: ask device to sign the given string | ||
* @next StellarSignedData | ||
*/ | ||
message StellarSignString { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency, this should be StellarSignMessage
protob/messages.proto
Outdated
* Response: device has signed data | ||
* @prev StellarSignString | ||
*/ | ||
message StellarSignedData { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency, this should be StellarMessageSignature
protob/messages.proto
Outdated
* Response: device has checked signature and either verified or denied it | ||
* @prev StellarVerifyMessage | ||
*/ | ||
message StellarMessageVerification { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency, this should be removed and Success
or Failure
used instead.
I've refactored the code to use a BIP32 path array instead of the single index. @saleemrashid I've also addressed the protobuf message names in the trezor-common PR. As usual, thank you both for your quick comments! |
@prusnak I'm working on a web frontend and having trouble finding documentation on how to use Trezor Connect with a custom firmware. Is there anything you could point me at or is there a good time I could bug you on Gitter? :) |
|
||
optional bytes destination_account = 2; // 32-byte destination account | ||
optional StellarAssetType asset = 3; // asset involved in the operation | ||
optional int64 amount = 4; // amount of the given asset to pay |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be uint64 (also everywhere else)
@zulucrypto hey there, I should be the one looking more into this these days. So far I've noticed just one detail, some of the proto messages contain Also, in case you find the strength, do you think you could rebase all the PRs on top of current master? |
@tsusanka - Thanks for your review! Using I will work on rebasing the PRs on master and push them soon. |
@zulucrypto oh, I see. So amounts can be negative? |
That's really weird they use signed ints for amounts, unless they indeed need to use negative amounts. |
@tsusanka - Negative amounts are not allowed (this is enforced through logic in the servers that accept transactions from clients). The explanation I was given when I asked why the values were signed was that it makes detecting overflows easier. |
Hm, interesting. I think we could still use |
@tsusanka - I've got the branches rebased here, but haven't pushed them yet. Stellar is in the process of adding a new operation that I'd like to include support for, so I plan to add it and then submit this PR for review again. In the meantime, some questions:
Thanks again for looking this over! |
@zulucrypto awesome!
One extra point:
|
LGTM, Thanks! |
@zulucrypto re the signed ints again is it important that the value is signed, or that the value is "protobuf int64"? If the former, it will be better to use |
Hi @matejcik - I'm mostly concerned that the data structures that are being passed to the Trezor (and hashed) match what the Stellar protocol specifies. From what I can tell, using I'll update things here to use |
Adds protobuf messages used by related trezor-mcu and python-trezor PRs.
See the trezor-mcu PR for more details: trezor/trezor-mcu#259