CLI: Support dumping the TX message in sign-only mode (#15932)

(cherry picked from commit 672e9c640f)

Co-authored-by: Trent Nelson <trent@solana.com>
This commit is contained in:
mergify[bot]
2021-03-17 04:41:08 +00:00
committed by GitHub
parent be05c8b121
commit 6a334a8bef
12 changed files with 305 additions and 13 deletions

View File

@@ -10,6 +10,7 @@ homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-cli-output"
[dependencies]
base64 = "0.13.0"
chrono = { version = "0.4.11", features = ["serde"] }
console = "0.11.3"
humantime = "2.0.1"

View File

@@ -1265,6 +1265,8 @@ impl fmt::Display for CliInflation {
#[serde(rename_all = "camelCase")]
pub struct CliSignOnlyData {
pub blockhash: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub signers: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
@@ -1280,6 +1282,9 @@ impl fmt::Display for CliSignOnlyData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln_name_value(f, "Blockhash:", &self.blockhash)?;
if let Some(message) = self.message.as_ref() {
writeln_name_value(f, "Transaction Message:", message)?;
}
if !self.signers.is_empty() {
writeln!(f, "{}", style("Signers (Pubkey=Signature):").bold())?;
for signer in self.signers.iter() {
@@ -1642,9 +1647,22 @@ impl fmt::Display for CliUpgradeableBuffer {
}
}
#[derive(Debug, Default)]
pub struct ReturnSignersConfig {
pub dump_transaction_message: bool,
}
pub fn return_signers(
tx: &Transaction,
output_format: &OutputFormat,
) -> Result<String, Box<dyn std::error::Error>> {
return_signers_with_config(tx, output_format, &ReturnSignersConfig::default())
}
pub fn return_signers_with_config(
tx: &Transaction,
output_format: &OutputFormat,
config: &ReturnSignersConfig,
) -> Result<String, Box<dyn std::error::Error>> {
let verify_results = tx.verify_with_results();
let mut signers = Vec::new();
@@ -1663,9 +1681,16 @@ pub fn return_signers(
bad_sig.push(key.to_string());
}
});
let message = if config.dump_transaction_message {
let message_data = tx.message_data();
Some(base64::encode(&message_data))
} else {
None
};
let cli_command = CliSignOnlyData {
blockhash: tx.message.recent_blockhash.to_string(),
message,
signers,
absent,
bad_sig,
@@ -1720,8 +1745,14 @@ pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
.collect();
}
let message = object
.get("message")
.and_then(|o| o.as_str())
.map(|m| m.to_string());
SignOnly {
blockhash,
message,
present_signers,
absent_signers,
bad_signers,
@@ -2000,6 +2031,25 @@ mod tests {
let res = return_signers(&tx, &OutputFormat::JsonCompact).unwrap();
let sign_only = parse_sign_only_reply_string(&res);
assert_eq!(sign_only.blockhash, blockhash);
assert_eq!(sign_only.message, None);
assert_eq!(sign_only.present_signers[0].0, present.pubkey());
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
let expected_msg = "AwECBwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDgTl3Dqh9\
F19Wo1Rmw0x+zMuNipG07jeiXfYPW4/Js5QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE\
BAQEBAYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBQUFBQUFBQUFBQUFBQUFBQUF\
BQUFBQUFBQUFBQUFBQUGp9UXGSxWjuCKhF9z0peIzwNcMUWyGrNE2AYuqUAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcH\
BwcCBgMDBQIEBAAAAAYCAQQMAgAAACoAAAAAAAAA"
.to_string();
let config = ReturnSignersConfig {
dump_transaction_message: true,
};
let res = return_signers_with_config(&tx, &OutputFormat::JsonCompact, &config).unwrap();
let sign_only = parse_sign_only_reply_string(&res);
assert_eq!(sign_only.blockhash, blockhash);
assert_eq!(sign_only.message, Some(expected_msg));
assert_eq!(sign_only.present_signers[0].0, present.pubkey());
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
assert_eq!(sign_only.bad_signers[0], bad.pubkey());