-
Notifications
You must be signed in to change notification settings - Fork 95
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
cardano: Allow vote delegation #1299
cardano: Allow vote delegation #1299
Conversation
Tried testing it through devdevice, but even in docker environment when running
looking into the error logs this error was reported
which seems like the cmake have and the gcc specifically have some sort of internal error. |
9581584
to
85113f5
Compare
Did you run this command? |
Not initially, but it was needed to build the simulator so eventually yes. The command |
Interesting, I guess I am not running into this as I use We apply this fix here btw: bitbox02-firmware/releases/build.sh Line 51 in b399d44
Maybe it could be added in dockerenv.sh too so it automatically runs there too. |
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.
Thanks!
I left some early comments, but the direction seems good!
messages/cardano.proto
Outdated
KeyHash = 0; | ||
ScriptHash = 1; | ||
AlwaysAbstain = 2; | ||
AlwaysNoConfidence = 3; |
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.
Unfortunately protobuf enum fields live in the global namespace, so all fields need a namespace prefix :( Please add CARDANO_DREP_TYPE_
. In Rust, the protobuf generator will strip the prefix again I think, so it's not too bad.
If this message will never be used outside of the VoteDelegation message, you can also define it within VoteDelegation. In that case, you don't need the prefix, as the enum will be scoped.
Afaik the naming convention for enum fields is all uppercase too, so KEY_HASH
, etc.
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 do not think that in forseeable future with the current business case I was told of this will be used elsewhere, so I moved it into VoteDelegation
. I put it on top with the casing based on other protobuf files and the naming in CardanoNetwork
to keep consistency, but this should be nicer.
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.
Thanks. Indeed, CardanoNetwork uses a different style unfortunately. I checked, most other enums in the project are uppercase.
messages/cardano.proto
Outdated
message Certificate { | ||
message StakeDelegation { | ||
repeated uint32 keypath = 1; | ||
repeated uint32 stake_keypath = 1; |
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.
Seems like an unrelated change that breaks downstream libraries. Is this necessary?
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 was suggested during internal review to make naming consistent and in vote delegation it makes sense. I am not completely partial to it so I fine with keeping the naming keypath
in StakeDelegation
certificate
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 is also what seemed to break CI:
--> bitbox02-rust/src/hww/api/cardano/sign_transaction.rs:526:29
|
526 | ... keypath: vec![1852 + HARDENED, 1815 + HARDENED, HARDENED, 2, 0],
| ^^^^^^^ `StakeDelegation` does not have this field
|
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'd leave it as it was, as otherwise:
- renaming it here means that downstream libraries need to change and get a major version bump, and the Adalite integration with the bitbox-api NPM package then also needs to update the name.
- this update would seem to be inconsistent with the
stake_registration
andstake_deregistration
fields, where the name is also stillkeypath
.
Could it make sense to simply name the VoteDelegation keypath field keypath
instead for consistency?
The TypeScript types right now are derived from the .proto field names like this:
type CardanoCertificate =
| {
stakeRegistration: {
keypath: Keypath
}
}
| {
stakeDeregistration: {
keypath: Keypath
}
}
| {
stakeDelegation: {
keypath: Keypath
poolKeyhash: Uint8Array
}
};
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 think it can make sense, but I will add a comment above it so at least in code there is a comment that it is supposed to be stake_keypath
else if matches!(r#type,2){ | ||
encoder.array(1)?.u8(2)?; | ||
} | ||
else if matches!(r#type,3){ |
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.
please apply rustfmt on save to format the Rust code.
}) => { | ||
encoder.array(3)?.u8(9)?; | ||
encode_stake_credential(&mut encoder, stake_keypath)?; | ||
if matches!(r#type,0){ |
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.
you can decode this to have a nicer pattern matching:
let drep_type = CardanoDRepType::try_from(r#type)?;
match drep_type {
CardanoDRepType::KeyHash => { ... }
// etc
}
encoder.array(2)?.u8(0)?; | ||
match drep_credhash { | ||
Some(hash) => { | ||
encoder.bytes(hash)?; |
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 also check the expected length of the hash.
instead of making it optional ...
, you could remove that keyword and check the length only. clients that omit it default to the empty bytestring.
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.
Added checking of length and I think using optional
makes more sense here and makes it a bit more readable, maybe just because I dont like to rely on defaults from languages/libraries.
I'm thinking of adding a check in the cases where there should not be a drep_credhash
sent to check it is none or throw an error. Functionality wise it does not change anything(even if it was sent it will not be encoded), but it might be nice to keep the requests clean. What do you think?
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.
Sounds good to me 👍
d9627ba
to
249bfaa
Compare
Some(hash) => { | ||
if hash.len() != 28 { | ||
return Err(Error::InvalidInput); | ||
} |
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 also shorten this as Some(hash) if hash.len() == 28 => { ... }
Also just to let it be known here this PR adds support for the whole certificate, Ada lite currently supports only |
}) => { | ||
validate_address_shelley_stake(keypath, Some(bip44_account))?; | ||
signing_keypaths.push(keypath); | ||
confirm::confirm(&confirm::Params { |
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.
Don't we also have to confirm the drep type and drep credhash?
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.
Added a second confirm screen to do this, I didn't want to merge into one because it made it a bit unreadable in my opinion.
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.
Please rebase, squash the commits and also add a line to CHANGELOG.md. Thanks!
9ca59e2
to
47fc205
Compare
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.
Please also rebase again, a change was merged that modifies some protobuf files too, it will make it easire to copy them to bitbox-api-rs.
Some(hash) => { confirm::confirm(&confirm::Params { | ||
title: params.name, | ||
body: &format!( | ||
"to type #{} and drep #{}?", |
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.
why the hashtag #
?
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 just now realized it was there to signify number in the message so I removed them.
confirm::confirm(&confirm::Params { | ||
title: params.name, | ||
body: &format!( | ||
"Delegate voting for account #{}?", |
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 think UX would be a bit better if it was just a single line - it is already scrollable. Then the user does not have to worry about which type/drep it is, they can't see ahead.
If you think two screens are better anyway, it's better to not start it with "to ...", but maybe simply "Type: .... DRep: ...".
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 am split as I think 2 screens are a little bit more readable, but also a bit more confusing as I am not sure how many users will actually know what which type of delegation means so it might just unnecessarily confuse them. I made it 1 screen in the end.
727722f
to
1456c75
Compare
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.
final nit before merge 😇
Some(hash) => { confirm::confirm(&confirm::Params { | ||
title: params.name, | ||
body: &format!( | ||
"Delegate voting for account #{} to type {} and drep {}??", |
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.
typo: double ??
😄
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.
Yes sorry, fix pushed
Allow cardano based on conway.cddl to sign messages containing Vote Delegation certificate. This is needed for withdrawing rewards. Signed-off-by: RostarMarek <rostarmarek@gmail.com> cardano: Add Test and minor improvements Adds unit test for vote delegation and adresses minor issues mentioned in PR. Signed-off-by: RostarMarek <rostarmarek@gmail.com> cardano: Adress review issues Addresses review issues found during the review process Signed-off-by: RostarMarek <rostarmarek@gmail.com> cardano: Add confirmation screen Adds confirmation screen for drep vote delegation dislpaying type and if present drep credential hash. Signed-off-by: RostarMarek <rostarmarek@gmail.com>
1456c75
to
d0e3716
Compare
Some(_hash) => return Err(Error::InvalidInput), | ||
None => return Err(Error::InvalidInput), |
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.
could collapse these into one _ => return Err ...
arm. Same above
let drep_type = certificate::vote_delegation::CardanoDRepType::try_from(*r#type)?; | ||
match drep_type { | ||
certificate::vote_delegation::CardanoDRepType::KeyHash => { | ||
encoder.array(2)?.u8(0)?; |
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 have no good of way of verifying this is correct, so we'll see in an end-to-end test, but
vote_deleg_cert = (9, stake_credential, drep)
I guess the encoder.array(3?).u8(9)?
above starts the array and adds the first element. Shouldn't the stake_credential
and drep
now be added directly as two elements? Here it seems like you are adding them as an array of 2 elements.
Have you verified somehow that the cbor output here is correct? Could very well be that I am just mis-reading this, it's a bit hairy 😅
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.
Nevermind, I just realized the stake_credential part is itself an array of 2!
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.
LGTM, thanks! Nice job!
Allow cardano based on conway.cddl to sign messages containing Vote Delegation certificate. This is needed for withdrawing rewards.
I will add tests for firmware soon, just wanted to begin the review process as soon as possible. It has been tested through simulator and works as expected.