1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
pub mod blockhash_query; use crate::nonce; use clap::{App, Arg, ArgMatches}; use serde_json::Value; use solana_clap_utils::{ input_parsers::{pubkey_of, value_of}, input_validators::{is_hash, is_pubkey_sig}, keypair::presigner_from_pubkey_sigs, offline::{BLOCKHASH_ARG, SIGNER_ARG, SIGN_ONLY_ARG}, }; use solana_client::rpc_client::RpcClient; use solana_sdk::{ fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey, signature::{Presigner, Signature}, }; use std::str::FromStr; fn blockhash_arg<'a, 'b>() -> Arg<'a, 'b> { Arg::with_name(BLOCKHASH_ARG.name) .long(BLOCKHASH_ARG.long) .takes_value(true) .value_name("BLOCKHASH") .validator(is_hash) .help(BLOCKHASH_ARG.help) } fn sign_only_arg<'a, 'b>() -> Arg<'a, 'b> { Arg::with_name(SIGN_ONLY_ARG.name) .long(SIGN_ONLY_ARG.long) .takes_value(false) .requires(BLOCKHASH_ARG.name) .help(SIGN_ONLY_ARG.help) } fn signer_arg<'a, 'b>() -> Arg<'a, 'b> { Arg::with_name(SIGNER_ARG.name) .long(SIGNER_ARG.long) .takes_value(true) .value_name("PUBKEY=SIGNATURE") .validator(is_pubkey_sig) .requires(BLOCKHASH_ARG.name) .multiple(true) .help(SIGNER_ARG.help) } pub trait OfflineArgs { fn offline_args(self) -> Self; } impl OfflineArgs for App<'_, '_> { fn offline_args(self) -> Self { self.arg(blockhash_arg()) .arg(sign_only_arg()) .arg(signer_arg()) } } pub struct SignOnly { pub blockhash: Hash, pub present_signers: Vec<(Pubkey, Signature)>, pub absent_signers: Vec<Pubkey>, pub bad_signers: Vec<Pubkey>, } impl SignOnly { pub fn has_all_signers(&self) -> bool { self.absent_signers.is_empty() && self.bad_signers.is_empty() } pub fn presigner_of(&self, pubkey: &Pubkey) -> Option<Presigner> { presigner_from_pubkey_sigs(pubkey, &self.present_signers) } } pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly { let object: Value = serde_json::from_str(&reply).unwrap(); let blockhash_str = object.get("blockhash").unwrap().as_str().unwrap(); let blockhash = blockhash_str.parse::<Hash>().unwrap(); let mut present_signers: Vec<(Pubkey, Signature)> = Vec::new(); let signer_strings = object.get("signers"); if let Some(sig_strings) = signer_strings { present_signers = sig_strings .as_array() .unwrap() .iter() .map(|signer_string| { let mut signer = signer_string.as_str().unwrap().split('='); let key = Pubkey::from_str(signer.next().unwrap()).unwrap(); let sig = Signature::from_str(signer.next().unwrap()).unwrap(); (key, sig) }) .collect(); } let mut absent_signers: Vec<Pubkey> = Vec::new(); let signer_strings = object.get("absent"); if let Some(sig_strings) = signer_strings { absent_signers = sig_strings .as_array() .unwrap() .iter() .map(|val| { let s = val.as_str().unwrap(); Pubkey::from_str(s).unwrap() }) .collect(); } let mut bad_signers: Vec<Pubkey> = Vec::new(); let signer_strings = object.get("badSig"); if let Some(sig_strings) = signer_strings { bad_signers = sig_strings .as_array() .unwrap() .iter() .map(|val| { let s = val.as_str().unwrap(); Pubkey::from_str(s).unwrap() }) .collect(); } SignOnly { blockhash, present_signers, absent_signers, bad_signers, } }