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

fix: hard-coded CLA byte #138

Merged
merged 2 commits into from
Jul 27, 2024
Merged

Conversation

xJonathanLEI
Copy link
Contributor

Fixes #137.

Submitting this patch optimistically. This contains a breaking change as a new field cla has been added.

Existing downstream applications would need to set cla to 0xe0 to continue to use app-ethereum.

@xJonathanLEI
Copy link
Contributor Author

CI failing but looks like it's due to a newer Rust version instead of my diffs.

@prestwich
Copy link
Member

CI failing but looks like it's due to a newer Rust version instead of my diffs.

you do need to update the APDU construction in wasm.rs

That said, in what cases would we NOT know the CLA at compile-time?

@xJonathanLEI
Copy link
Contributor Author

I guess you'd always know it compile time.

Am I understanding correctly that you're suggesting const generic?

@prestwich
Copy link
Member

yes, if we did a const generic with default 0xE0 this would not be a breaking API change

@xJonathanLEI
Copy link
Contributor Author

Weird. I changed the struct definition to:

pub struct APDUCommand<const CLA: u8 = 0xE0> {
  ...
}

but it still gives me an compilation error when I omit the generic param:

error[E0282]: type annotations needed for `common::APDUCommand<_>`
   --> crates/ledger/src/common.rs:314:13
    |
314 |         let command = APDUCommand {
    |             ^^^^^^^
    |
help: consider giving `command` an explicit type, where the value of const parameter `CLA` is specified
    |
314 |         let command: common::APDUCommand<CLA> = APDUCommand {
    |                    ++++++++++++++++++++++++++

I've never worked with default const generic values before. It looks like the compiler accepts the syntax but somehow wouldn't allow omitting it when instantiating? Am I missing anything here? Sorry if this is obvious.

@xJonathanLEI
Copy link
Contributor Author

xJonathanLEI commented Jun 18, 2024

Oh I figured out. Don't know how I missed this Stack Overflow answer in the first attempt.

So the solution is to change

        let command = APDUCommand {

into

        let command: APDUCommand = APDUCommand {

and then it magically works. It looks like the default only applies when you name the type, not when you construct it.

But apparently this would mean that using const generic with a default value would still be a breaking change, as downstream code that rely on type inference would no longer compile.

@prestwich
Copy link
Member

Would it be worthwhile to add a few type aliases ?

type BitcoinAPDUCommand = APDUCommand<0xE1>;
type StarknetAPDUCommand = APDUCommand<0x5A>;

@xJonathanLEI
Copy link
Contributor Author

Yeah that would probably be ideal. Posting the above just to say we'll end up breaking users whether we do it field-based or const-generic-based.

I'm making the change towards const generics and fixing the CI now.

@xJonathanLEI
Copy link
Contributor Author

xJonathanLEI commented Jun 18, 2024

Hmmm I just realized an issue. Since APDUCommand is used as a field in APDUExchange, which is in turn used in LedgerTask and LedgerHandle, making APDUCommand generic would mean that both APDUExchange, LedgerTask, and LedgerHandle become generic too. Ledger will also become generic since it wraps LedgerHandle.

For APDUExchange and LedgerTask it's probably fine as they can only be instantiated from within the library.

But for LedgerHandle... not so much. When you call ::init() the compiler cannot infer the const generic value. Even if we use a default value, as shown above, it only works when the type is explicitly specified on the left hand side. We could add aliases for it too like BitcoinLedgerHandle and StarknetLedgerHandle but I kinda feel like overengineering.

It's not just structs. The LedgerAsync trait will also need to be updated to make exchange() generic, along with all the implementations. This would mean if any downstream app/lib implements LedgerAsync they're further broken too... for pretty much no good reason.

What do you think? Should we pollute all these types with generics or go back to adding a new cla field? Adding const generic also has the downside of making a LedgerHandle instance only capable of sending a fixed CLA prefix. Not that I can think of use cases when you'd want to change CLA on the fly though..

Overall I just feel like the added complexity isn't worth it when we can just add a field. The breakage from adding a field is actually smaller by comparison.

Just my 2 cents though. Apparently if you still prefer the const generic way I will proceed. Thanks!

@prestwich
Copy link
Member

mmm fair point. let's keep it as a prop and publish a breaking change

@xJonathanLEI
Copy link
Contributor Author

Updated with the clippy and wasm fix.

@xJonathanLEI
Copy link
Contributor Author

@prestwich Yo mind taking a look? Using this in a downstream crate but cannot publish to crates.io until this is released. Thanks for your time!

@prestwich
Copy link
Member

oh sorry i was sure I had merged this. I'll run a release this morning. This is a breaking change so we're going to 0.12.0

@prestwich prestwich merged commit cbfdece into summa-tx:main Jul 27, 2024
6 checks passed
@xJonathanLEI xJonathanLEI deleted the fix/hard_coded_cla branch July 27, 2024 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Hard-coded CLA for app-ethereum (0xE0)
2 participants