CLI: Remote wallet signing#8318
Conversation
what to do about write_keypair outstanding
This reverts commit 88fe185. Create-from-seed should be re-enabled in another changeset
|
Supersedes #8252 |
Codecov Report
@@ Coverage Diff @@
## master #8318 +/- ##
========================================
+ Coverage 80.5% 80.5% +<.1%
========================================
Files 254 254
Lines 55477 55386 -91
========================================
- Hits 44700 44641 -59
+ Misses 10777 10745 -32 |
|
|
||
| impl PartialEq for dyn KeypairUtil { | ||
| fn eq(&self, other: &dyn KeypairUtil) -> bool { | ||
| self.pubkey() == other.pubkey() |
There was a problem hiding this comment.
This looks a bit dangerous since it would return true if both keypairs return an error for pubkey. How about slapping a #[cfg(test)] on here along with a warning comment?
There was a problem hiding this comment.
Unfortunately, PartialEq is a requirement on the CliCommand enum, so gating to cfg(test) won't quite work. @CriesofCarrots is also working on some KeypairUtil filtering that will require it.
I think we can eliminate the default behavior. I'll address it in a reply to one of your later comments where more appropriate
| derivation_of(matches, "derivation_path"), | ||
| )?)), | ||
| } | ||
| generate_keypair_util(matches, path, "pubkey recovery") |
There was a problem hiding this comment.
This name is pretty confusing to me. Maybe keypair_util_from_path?
There was a problem hiding this comment.
May I also suggest that we rename KeypairUtil to Signer?
There was a problem hiding this comment.
I think we can work something out here 😉
There was a problem hiding this comment.
I think we can work something out here 😉
There was a problem hiding this comment.
+1 for Signer and ergo signer_from_path()(?)
There was a problem hiding this comment.
That said, the Signer rename is going to cause a ton of churn. Separate pr, perhaps?
| fn tx_uses_nonce_empty_ix_fail() { | ||
| let tx = | ||
| Transaction::new_signed_instructions(&[&Keypair::new(); 0], vec![], Hash::default()); | ||
| let tx = Transaction::new_signed_instructions( |
There was a problem hiding this comment.
nit: &vec![] is more succint
| return 1; | ||
| }; | ||
| let keypairs_ref: Vec<&KeypairNative> = keypairs.iter().collect(); | ||
| let mut keypairs_ref: Vec<&dyn KeypairUtil> = Vec::new(); |
There was a problem hiding this comment.
nit: you could coerce like this as well. Not much cleaner though 🤷♂
let keypairs_ref = keypairs
.iter()
.map(|k| -> &dyn KeypairUtil { k })
.collect::<Vec<_>>();There was a problem hiding this comment.
Yeah, we couldn't come up with anything very aesthetically pleasing either 😕
| }; | ||
|
|
||
| if let Some(signers) = signers { | ||
| replace_signatures(&mut tx, &signers)?; |
There was a problem hiding this comment.
Looks like fn replace_signatures is dead code now. I'm confused why we don't need this anymore, could you please explain?
There was a problem hiding this comment.
Hmm, yeah I was expecting clippy to nag about this one.
replace_signatures() is unnecessary as of Presigner
Lines 170 to 175 in d0bcde0
We can now emit the correct signature in sign_message(), so no post-processing is required. This is a step toward supporting TX construction over multiple signing sessions
| } = parse_command(&matches)?; | ||
|
|
||
| let (keypair, keypair_path) = if require_keypair { | ||
| let KeypairWithSource { keypair, source } = keypair_input(&matches, "keypair")?; |
There was a problem hiding this comment.
Looks like you can remove the global ASK_SEED_PHRASE_ARG arg now
There was a problem hiding this comment.
Ugh... Github, what are you doing?
| derivation_of(matches, "derivation_path"), | ||
| )?)), | ||
| KeypairUrl::Pubkey(pubkey) => { | ||
| let presigner = pubkeys_sigs_of(matches, "signer") |
There was a problem hiding this comment.
"signer" > SIGNER_ARG.name?
There was a problem hiding this comment.
Ah! I meant to come back to this one. I'm pretty sure that would create a cli <-> clap_utils circular dependency. Probably need to move the constant into the latter
| /// Create and sign new system_instruction::Assign transaction | ||
| pub fn assign(from_keypair: &Keypair, recent_blockhash: Hash, program_id: &Pubkey) -> Transaction { | ||
| pub fn assign( | ||
| from_keypair: &dyn KeypairUtil, |
There was a problem hiding this comment.
This makes it easier to create bad transactions. Anything which takes a KeypairUtil could create bad pubkeys or bad signatures because of the fallback behavior in KeypairUtil::pubkey() and KeypairUtil::sign_message. I'm not sure it's a good idea to make this easier. Anyone who creates a system transaction with a remote keypair or presigner keypair will have to be aware that the transaction they create, might fail due to an error that isn't bubbled up.
There was a problem hiding this comment.
I think we can eliminate the default fallbacks. sign_message() has a manageable number of callers, many just setting up tests, so probably not too bad to make fallible throughout. pubkey() however, is called all over the place. I believe it can be made infallible, though. Any implementers that might fail, can query and cache the pubkey at construction and fail there instead. @CriesofCarrots wdyt?
@jstarry would that alleviate your concerns RE default fallbacks?
|
I'm surprised to see existing methods generalized here, which results in changing lots and lots of code. What about the approach of adding new methods to KeypairUtil and Client and only using them in the cases where multi-sig was needed from the CLI? |
|
@t-nelson, does this PR still have a future? Or is it an earlier version of what @CriesofCarrots is working on? |
Problem
Our signer interfaces are too restrictive to accommodate a rich signing experience. This makes things like hardware wallets, offline signing and certain instruction constructions difficult to implement and mixed signer types impossible.
Summary of Changes
Co-conspirator: @CriesofCarrots
KeypairUtilgenerics-based interfaces withKeypairUtiltrait-objects-based onesKeypairdata structure fields withBox<dyn KeypairUtil>where appropriateFor review purposes:
The most essential changes in this PR can be seen in sdk/src/transaction.rs (use of
KeypairUtiltrait objects), and thegenerate_keypair_util()method in clap-utils/src/keypair.rs demonstrates how keypair inputs are parsed into differentKeypairUtilobjects.