CLI: dynamic signing reboot (#8384)
* Add keypair_util_from_path helper * Cli: impl config.keypair as a trait object * SDK: Add Debug and PartialEq for dyn Signer * ClapUtils: Arg parsing from pubkey+signers to Presigner * Impl Signers for &dyn Signer collections * CLI: Add helper for getting signers from args * CLI: Replace SigningAuthority with Signer trait-objs * CLI: Drop disused signers command field * CLI: Drop redundant tests * Add clap validator that handles all current signer types * clap_utils: Factor Presigner resolution to helper * SDK: `From` for boxing Signer implementors to trait objects * SDK: Derive `Clone` for `Presigner` * Remove panic * Cli: dedup signers in transfer for remote-wallet ergonomics * Update docs vis-a-vis ASK changes * Cli: update transaction types to use new dynamic-signer methods * CLI: Fix tests No. 1 what to do about write_keypair outstanding * Work around `CliConfig`'s signer not necessarily being a `Keypair` * CLI: Fix tests No. 2 * Remove unused arg * Remove unused methods * Move offline arg constants upstream * Make cli signing fallible Co-authored-by: Trent Nelson <trent.a.b.nelson@gmail.com>
This commit is contained in:
@ -139,6 +139,18 @@ pub trait Signer {
|
||||
fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError>;
|
||||
}
|
||||
|
||||
impl PartialEq for dyn Signer {
|
||||
fn eq(&self, other: &dyn Signer) -> bool {
|
||||
self.pubkey() == other.pubkey()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for dyn Signer {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(fmt, "Signer: {:?}", self.pubkey())
|
||||
}
|
||||
}
|
||||
|
||||
impl Signer for Keypair {
|
||||
/// Return the public key for the given keypair
|
||||
fn pubkey(&self) -> Pubkey {
|
||||
@ -167,6 +179,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Box<dyn Signer>
|
||||
where
|
||||
T: Signer + 'static,
|
||||
{
|
||||
fn from(keypair_util: T) -> Self {
|
||||
Box::new(keypair_util)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, PartialEq)]
|
||||
pub enum SignerError {
|
||||
#[error("keypair-pubkey mismatch")]
|
||||
@ -202,15 +223,14 @@ pub enum SignerError {
|
||||
UserCancel,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Presigner {
|
||||
pubkey: Pubkey,
|
||||
signature: Signature,
|
||||
}
|
||||
|
||||
impl Presigner {
|
||||
#[allow(dead_code)]
|
||||
fn new(pubkey: &Pubkey, signature: &Signature) -> Self {
|
||||
pub fn new(pubkey: &Pubkey, signature: &Signature) -> Self {
|
||||
Self {
|
||||
pubkey: *pubkey,
|
||||
signature: *signature,
|
||||
|
@ -48,6 +48,34 @@ impl Signers for [Box<dyn Signer>] {
|
||||
default_keypairs_impl!();
|
||||
}
|
||||
|
||||
impl Signers for Vec<&dyn Signer> {
|
||||
default_keypairs_impl!();
|
||||
}
|
||||
|
||||
impl Signers for [&dyn Signer] {
|
||||
default_keypairs_impl!();
|
||||
}
|
||||
|
||||
impl Signers for [&dyn Signer; 0] {
|
||||
default_keypairs_impl!();
|
||||
}
|
||||
|
||||
impl Signers for [&dyn Signer; 1] {
|
||||
default_keypairs_impl!();
|
||||
}
|
||||
|
||||
impl Signers for [&dyn Signer; 2] {
|
||||
default_keypairs_impl!();
|
||||
}
|
||||
|
||||
impl Signers for [&dyn Signer; 3] {
|
||||
default_keypairs_impl!();
|
||||
}
|
||||
|
||||
impl Signers for [&dyn Signer; 4] {
|
||||
default_keypairs_impl!();
|
||||
}
|
||||
|
||||
impl<T: Signer> Signers for [&T; 0] {
|
||||
default_keypairs_impl!();
|
||||
}
|
||||
@ -111,4 +139,22 @@ mod tests {
|
||||
vec![Signature::default(), Signature::default()],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dyn_keypairs_by_ref_compile() {
|
||||
let foo = Foo {};
|
||||
let bar = Bar {};
|
||||
let xs: Vec<&dyn Signer> = vec![&foo, &bar];
|
||||
assert_eq!(
|
||||
xs.sign_message(b""),
|
||||
vec![Signature::default(), Signature::default()],
|
||||
);
|
||||
|
||||
// Same as above, but less compiler magic.
|
||||
let xs_ref: &[&dyn Signer] = &xs;
|
||||
assert_eq!(
|
||||
Signers::sign_message(xs_ref, b""),
|
||||
vec![Signature::default(), Signature::default()],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ mod tests {
|
||||
use crate::{
|
||||
hash::hash,
|
||||
instruction::AccountMeta,
|
||||
signature::{Keypair, Signer},
|
||||
signature::{Keypair, Presigner, Signer},
|
||||
system_instruction,
|
||||
};
|
||||
use bincode::{deserialize, serialize, serialized_size};
|
||||
@ -671,4 +671,52 @@ mod tests {
|
||||
);
|
||||
assert!(tx.is_signed());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_sign_dyn_keypairs() {
|
||||
let program_id = Pubkey::default();
|
||||
let keypair = Keypair::new();
|
||||
let pubkey = keypair.pubkey();
|
||||
let presigner_keypair = Keypair::new();
|
||||
let presigner_pubkey = presigner_keypair.pubkey();
|
||||
|
||||
let ix = Instruction::new(
|
||||
program_id,
|
||||
&0,
|
||||
vec![
|
||||
AccountMeta::new(pubkey, true),
|
||||
AccountMeta::new(presigner_pubkey, true),
|
||||
],
|
||||
);
|
||||
let mut tx = Transaction::new_unsigned_instructions(vec![ix]);
|
||||
|
||||
let presigner_sig = presigner_keypair.sign_message(&tx.message_data());
|
||||
let presigner = Presigner::new(&presigner_pubkey, &presigner_sig);
|
||||
|
||||
let signers: Vec<&dyn Signer> = vec![&keypair, &presigner];
|
||||
|
||||
let res = tx.try_sign(&signers, Hash::default());
|
||||
assert_eq!(res, Ok(()));
|
||||
assert_eq!(tx.signatures[0], keypair.sign_message(&tx.message_data()));
|
||||
assert_eq!(tx.signatures[1], presigner_sig);
|
||||
|
||||
// Wrong key should error, not panic
|
||||
let another_pubkey = Pubkey::new_rand();
|
||||
let ix = Instruction::new(
|
||||
program_id,
|
||||
&0,
|
||||
vec![
|
||||
AccountMeta::new(another_pubkey, true),
|
||||
AccountMeta::new(presigner_pubkey, true),
|
||||
],
|
||||
);
|
||||
let mut tx = Transaction::new_unsigned_instructions(vec![ix]);
|
||||
|
||||
let res = tx.try_sign(&signers, Hash::default());
|
||||
assert!(res.is_err());
|
||||
assert_eq!(
|
||||
tx.signatures,
|
||||
vec![Signature::default(), Signature::default()]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user