CLI: Add multi-session signing support (#8927)
* SDK: Add `NullSigner` implementation * SDK: Split `Transaction::verify()` to gain access to results * CLI: Minor refactor of --sign_only result parsing * CLI: Enable paritial signing Signers specified by pubkey, but without a matching --signer arg supplied fall back to a `NullSigner` when --sign-only is in effect. This allows their pubkey to be used for TX construction as usual, but leaves their `sign_message()` a NOP. As such, with --sign-only in effect, signing and verification must be done separately, with the latter's per-signature results considered * CLI: Surface/report missing/bad signers to user * CLI: Suppress --sign-only JSON output * nits * Docs for multi-session offline signing
This commit is contained in:
@ -269,6 +269,39 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// NullSigner - A `Signer` implementation that always produces `Signature::default()`.
|
||||
/// Used as a placeholder for absentee signers whose 'Pubkey` is required to construct
|
||||
/// the transaction
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct NullSigner {
|
||||
pubkey: Pubkey,
|
||||
}
|
||||
|
||||
impl NullSigner {
|
||||
pub fn new(pubkey: &Pubkey) -> Self {
|
||||
Self { pubkey: *pubkey }
|
||||
}
|
||||
}
|
||||
|
||||
impl Signer for NullSigner {
|
||||
fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
|
||||
Ok(self.pubkey)
|
||||
}
|
||||
|
||||
fn try_sign_message(&self, _message: &[u8]) -> Result<Signature, SignerError> {
|
||||
Ok(Signature::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialEq<T> for NullSigner
|
||||
where
|
||||
T: Signer,
|
||||
{
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
self.pubkey == other.pubkey()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_keypair<R: Read>(reader: &mut R) -> Result<Keypair, Box<dyn error::Error>> {
|
||||
let bytes: Vec<u8> = serde_json::from_reader(reader)?;
|
||||
let dalek_keypair = ed25519_dalek::Keypair::from_bytes(&bytes)
|
||||
|
@ -300,14 +300,20 @@ impl Transaction {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify the transaction
|
||||
pub fn verify(&self) -> Result<()> {
|
||||
if !self
|
||||
.signatures
|
||||
pub fn verify_with_results(&self) -> Vec<bool> {
|
||||
self.signatures
|
||||
.iter()
|
||||
.zip(&self.message.account_keys)
|
||||
.map(|(signature, pubkey)| signature.verify(pubkey.as_ref(), &self.message_data()))
|
||||
.all(|verify_result| verify_result)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Verify the transaction
|
||||
pub fn verify(&self) -> Result<()> {
|
||||
if !self
|
||||
.verify_with_results()
|
||||
.iter()
|
||||
.all(|verify_result| *verify_result)
|
||||
{
|
||||
Err(TransactionError::SignatureFailure)
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user