stellar_baselib/
signer_key.rs1use core::panic;
2use std::{collections::HashMap, str::FromStr};
3
4use crate::xdr;
5use crate::xdr::{SignerKey as XDRSignerKey, SignerKeyEd25519SignedPayload};
6use stellar_strkey::{
7 ed25519::{PublicKey, SignedPayload},
8 HashX, PreAuthTx,
9};
10
11pub struct SignerKey;
12
13pub trait SignerKeyBehavior {
15 fn decode_address(address: &str) -> XDRSignerKey;
16 fn encode_signer_key(signer_key: &XDRSignerKey) -> String;
17}
18
19impl SignerKeyBehavior for SignerKey {
20 fn decode_address(address: &str) -> XDRSignerKey {
21 let val = stellar_strkey::Strkey::from_string(address);
22 if val.is_err() {
23 panic!("Invalid Type")
24 }
25
26 match val.unwrap() {
27 stellar_strkey::Strkey::SignedPayloadEd25519(x) => {
28 XDRSignerKey::Ed25519SignedPayload(SignerKeyEd25519SignedPayload {
29 ed25519: xdr::Uint256(x.ed25519),
30 payload: x.payload.try_into().unwrap(),
31 })
32 }
33 stellar_strkey::Strkey::PublicKeyEd25519(x) => XDRSignerKey::Ed25519(xdr::Uint256(x.0)),
34 stellar_strkey::Strkey::PreAuthTx(x) => XDRSignerKey::PreAuthTx(xdr::Uint256(x.0)),
35 stellar_strkey::Strkey::HashX(x) => XDRSignerKey::HashX(xdr::Uint256(x.0)),
36 _ => panic!("Invalid Type"),
37 }
38 }
39
40 fn encode_signer_key(signer_key: &XDRSignerKey) -> String {
41 match signer_key {
42 XDRSignerKey::Ed25519(x) => {
43 stellar_strkey::Strkey::PublicKeyEd25519(PublicKey::from_payload(&x.0).unwrap())
44 .to_string()
45 }
46 XDRSignerKey::PreAuthTx(x) => {
47 stellar_strkey::Strkey::PreAuthTx(PreAuthTx(x.0)).to_string()
48 }
49 XDRSignerKey::HashX(x) => stellar_strkey::Strkey::HashX(HashX(x.0)).to_string(),
50 XDRSignerKey::Ed25519SignedPayload(x) => {
51 stellar_strkey::Strkey::SignedPayloadEd25519(SignedPayload {
52 ed25519: x.ed25519.0,
53 payload: x.payload.clone().into_vec(),
54 })
55 .to_string()
56 }
57 }
58 }
59}
60
61fn assert_panic<F: FnOnce(), S: AsRef<str>>(f: F, expected_msg: S) {
62 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
63 match result {
64 Ok(_) => panic!("Function did not panic as expected"),
65 Err(err) => {
66 if let Some(s) = err.downcast_ref::<&str>() {
67 assert!(
68 s.contains(expected_msg.as_ref()),
69 "Unexpected panic message. Got: {}",
70 s
71 );
72 } else {
73 panic!("Unexpected panic type");
74 }
75 }
76 }
77}
78
79mod tests {
80 use xdr::{ReadXdr, WriteXdr};
81
82 use super::*;
83 #[derive(Debug)]
84 struct TestCase {
85 strkey: &'static str,
86 r#type: xdr::SignerKeyType,
87 }
88
89 static TEST_CASES: [TestCase; 4] = [
90 TestCase {
91 strkey: "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
92 r#type: xdr::SignerKeyType::Ed25519,
93 },
94 TestCase {
95 strkey: "TBU2RRGLXH3E5CQHTD3ODLDF2BWDCYUSSBLLZ5GNW7JXHDIYKXZWHXL7",
96 r#type: xdr::SignerKeyType::PreAuthTx,
97 },
98 TestCase {
99 strkey: "XBU2RRGLXH3E5CQHTD3ODLDF2BWDCYUSSBLLZ5GNW7JXHDIYKXZWGTOG",
100 r#type: xdr::SignerKeyType::HashX,
101 },
102 TestCase {
103 strkey: "PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAQACAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4DUPB6IBZGM",
104 r#type: xdr::SignerKeyType::Ed25519SignedPayload,
105 },
106 ];
107
108 #[test]
109 fn test_encode_decode_roundtrip() {
110 for test_case in &TEST_CASES {
111 let skey = SignerKey::decode_address(test_case.strkey);
112
113 assert_eq!(skey.discriminant(), test_case.r#type);
114
115 let raw_xdr = skey.to_xdr(xdr::Limits::none()).unwrap();
116 let raw_sk = xdr::SignerKey::from_xdr(raw_xdr, xdr::Limits::none()).unwrap();
117 assert_eq!(raw_sk, skey);
118
119 let address = SignerKey::encode_signer_key(&skey);
120 assert_eq!(address, test_case.strkey);
121 }
122 }
123
124 #[test]
125 fn error_cases_for_invalid_signers() {
126 let invalid_signers = &[
127 "SAB5556L5AN5KSR5WF7UOEFDCIODEWEO7H2UR4S5R62DFTQOGLKOVZDY",
128 "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVAAAAAAAAAAAAAJLK",
129 "NONSENSE",
130 ];
131
132 for strkey in invalid_signers.iter() {
133 let scenario_1 = || {
134 SignerKey::decode_address(strkey);
135 };
136 assert_panic(scenario_1, "Invalid Type")
137 }
138 }
139
140 #[test]
141 fn error_cases_for_invalid_strkey() {
142 let strkey = "G47QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVP2I";
143 let scenario_1 = || {
144 SignerKey::decode_address(strkey);
145 };
146 assert_panic(scenario_1, "Invalid Type")
147 }
148}