Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

CLI: dynamic signing#8336

Closed
CriesofCarrots wants to merge 25 commits into
solana-labs:masterfrom
CriesofCarrots:cli-remote-signing-less-general
Closed

CLI: dynamic signing#8336
CriesofCarrots wants to merge 25 commits into
solana-labs:masterfrom
CriesofCarrots:cli-remote-signing-less-general

Conversation

@CriesofCarrots
Copy link
Copy Markdown
Contributor

@CriesofCarrots CriesofCarrots commented Feb 19, 2020

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: @t-nelson

  • Consolidate signer CLI argument specification and support HW wallet paths
  • In contrast to CLI: Remote wallet signing #8318 , which attempted a general solution, this PR adds a select set of new Transaction and RpcClient apis that utilize KeypairUtil trait-object signer types to allow for dynamic signing. Since some signers implementing KeypairUtil may fail in signing, these new methods are also fallible, bubbling up signing errors before a Transaction is submitted.
  • Plumb the new methods into CLI, and replace Keypair data structure fields with Box
  • Doc updates

Closes #8318

@CriesofCarrots
Copy link
Copy Markdown
Contributor Author

@jstarry , this rework should address most of your comments on #8318 . The one exception is part of @t-nelson 's proposal here: #8318 (comment)
Fallible signing is handled in this pr, and most pubkey() methods are already infallible. But RemoteKepair requires a little bit of work under the hood, which I would prefer to handle in a separate PR.

@garious
Copy link
Copy Markdown
Contributor

garious commented Feb 20, 2020

You shouldn't need to pass a trait object in as an input parameter anywhere. Consider f<T: KeypairUtil, U: KeypairUtil>(k1: T, k2: U) instead.

@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 20, 2020

Codecov Report

❗ No coverage uploaded for pull request base (master@d0bcde0). Click here to learn what that means.
The diff coverage is 58.9%.

@@           Coverage Diff            @@
##             master   #8336   +/-   ##
========================================
  Coverage          ?   80.5%           
========================================
  Files             ?     254           
  Lines             ?   55392           
  Branches          ?       0           
========================================
  Hits              ?   44600           
  Misses            ?   10792           
  Partials          ?       0

@garious
Copy link
Copy Markdown
Contributor

garious commented Feb 20, 2020

Thinking more on this, I think we can implement this without any trait objects or new methods. I'm AFK but will post something soon.

@garious
Copy link
Copy Markdown
Contributor

garious commented Feb 20, 2020

No dyn, no new methods (because no negative perf consequences), and fewer code changes: #8342

Only major drawback is there's some copypasta, but we could remove most of that with a macro or two.

@garious
Copy link
Copy Markdown
Contributor

garious commented Feb 20, 2020

Looks like this PR is trying to solve multiple issues all at once. Are you able to split out and land anything on its own? For example, the --keypair ASK feature?

@garious
Copy link
Copy Markdown
Contributor

garious commented Feb 20, 2020

It's also not obvious to me if the fallible methods need to be on the same trait.

Comment thread sdk/src/signature.rs
#[derive(Debug, Default)]
impl<T> From<T> for Box<dyn KeypairUtil>
where
T: KeypairUtil + 'static,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why 'static?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh! + 'static isn't necessary here. I was following the compiler at one point and later figured out it was being overly specific. I must've missed removing this one

Comment thread sdk/src/transaction.rs
&mut self,
keypairs: &[&dyn KeypairUtil],
recent_blockhash: Hash,
) -> result::Result<(), Box<dyn error::Error>> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why Box<dyn error::Error> and not something specific to the actual errors that are possible?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Are you envisioning something like:

enum SigningError {
  PresignerError,
  RemoteWalletError,
  ..
}

Short and sweet for now, but forces any new signers that impl KeypairUtil to add a variation to the enum.
I suppose we could have a single SigningError(String) that wraps any signer error it receives, but is that any better than the Box?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

SigningError(String) would definitely be worse. I think you should create that enum but I don't think it'll need many escape hatches. Mayyyybe a CustomError, like we have in InstructionError.

Copy link
Copy Markdown
Contributor Author

@CriesofCarrots CriesofCarrots Feb 20, 2020

Choose a reason for hiding this comment

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

Just realized a problem with that enum. It would be best to bubble up the actual errors from signers (particularly RemoteKeypair which can throw a variety of different kinds of errors). Something like this would be nice with thiserror:

#[derive(Error, Debug)]
pub enum SigningError {
    #[error("remote wallet error")]
    RemoteWallet(#[from] remote_wallet::RemoteWalletError),
}

But there is no way to do that due to resulting circular dependency between remote-wallet and sdk.
An alternative is a generic SigningError::RemoteWallet, but losing that error data is worse than Box, imho

Comment thread sdk/src/transaction.rs
/// KeypairUtil trait objects
pub fn sign_dynamic_signers(
&mut self,
keypairs: &[&dyn KeypairUtil],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This method looks to mix two independents concepts, fallible implementations, and heterogeneous lists. But it's not clear to me how this implements heterogeneous lists with a Box.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't understand your comment here.

Just realizing that if we are able to make #8342 work, we will still need these fallible implementations.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I mistyped. Should be "without a Box"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm still confused. &dyn Trait is still a trait object, just the reference type.

Comment thread sdk/src/transaction.rs
/// Check keys and keypair lengths, then sign this transaction, using an assortment of
/// KeypairUtil trait objects
pub fn sign_dynamic_signers(
&mut self,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why mut?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This emulates the original Transaction::sign method to place the signature in the Transaction struct itself, hence self needs to be mut.
https://github.com/solana-labs/solana/pull/8336/files#diff-b8441031257e554aba72a1fd238539bcR308

@CriesofCarrots
Copy link
Copy Markdown
Contributor Author

Looks like this PR is trying to solve multiple issues all at once. Are you able to split out and land anything on its own? For example, the --keypair ASK feature?

I'll see what I can pull out.

@CriesofCarrots
Copy link
Copy Markdown
Contributor Author

It's also not obvious to me if the fallible methods need to be on the same trait.

I don't think they have to be, but since we're wanting to handle all KeypairUtils the same, it sure makes things easier.

@garious
Copy link
Copy Markdown
Contributor

garious commented Feb 21, 2020

@CriesofCarrots, are you planning to rebase this one? Or can you close it and come back with whatever wasn't in your earlier PRs?

@CriesofCarrots
Copy link
Copy Markdown
Contributor Author

@CriesofCarrots, are you planning to rebase this one? Or can you close it and come back with whatever wasn't in your earlier PRs?

I'll close and open a fresh PR

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants