solana_runtime/
verify_precompiles.rs1use {
2 solana_feature_set::FeatureSet,
3 solana_sdk::{
4 instruction::InstructionError,
5 precompiles::get_precompiles,
6 transaction::{Result, TransactionError},
7 },
8 solana_svm_transaction::svm_message::SVMMessage,
9};
10
11pub fn verify_precompiles(message: &impl SVMMessage, feature_set: &FeatureSet) -> Result<()> {
12 let mut all_instruction_data = None; let precompiles = get_precompiles();
15 for (index, (program_id, instruction)) in message.program_instructions_iter().enumerate() {
16 for precompile in precompiles {
17 if precompile.check_id(program_id, |id| feature_set.is_active(id)) {
18 let all_instruction_data: &Vec<&[u8]> = all_instruction_data
19 .get_or_insert_with(|| message.instructions_iter().map(|ix| ix.data).collect());
20 precompile
21 .verify(instruction.data, all_instruction_data, feature_set)
22 .map_err(|err| {
23 TransactionError::InstructionError(
24 index as u8,
25 InstructionError::Custom(err as u32),
26 )
27 })?;
28 break;
29 }
30 }
31 }
32
33 Ok(())
34}
35
36#[cfg(test)]
37mod tests {
38 use {
39 super::*,
40 rand0_7::{thread_rng, Rng},
41 solana_sdk::{
42 ed25519_instruction::new_ed25519_instruction,
43 hash::Hash,
44 pubkey::Pubkey,
45 secp256k1_instruction::new_secp256k1_instruction,
46 signature::Keypair,
47 signer::Signer,
48 system_instruction, system_transaction,
49 transaction::{SanitizedTransaction, Transaction},
50 },
51 };
52
53 #[test]
54 fn test_verify_precompiles_simple_transaction() {
55 let tx = SanitizedTransaction::from_transaction_for_tests(system_transaction::transfer(
56 &Keypair::new(),
57 &Pubkey::new_unique(),
58 1,
59 Hash::default(),
60 ));
61 assert!(verify_precompiles(&tx, &FeatureSet::all_enabled()).is_ok());
62 }
63
64 #[test]
65 fn test_verify_precompiles_secp256k1() {
66 let secp_privkey = libsecp256k1::SecretKey::random(&mut thread_rng());
67 let message_arr = b"hello";
68 let mut secp_instruction = new_secp256k1_instruction(&secp_privkey, message_arr);
69 let mint_keypair = Keypair::new();
70 let feature_set = FeatureSet::all_enabled();
71
72 let tx =
73 SanitizedTransaction::from_transaction_for_tests(Transaction::new_signed_with_payer(
74 &[secp_instruction.clone()],
75 Some(&mint_keypair.pubkey()),
76 &[&mint_keypair],
77 Hash::default(),
78 ));
79
80 assert!(verify_precompiles(&tx, &feature_set).is_ok());
81
82 let index = thread_rng().gen_range(0, secp_instruction.data.len());
83 secp_instruction.data[index] = secp_instruction.data[index].wrapping_add(12);
84 let tx =
85 SanitizedTransaction::from_transaction_for_tests(Transaction::new_signed_with_payer(
86 &[secp_instruction],
87 Some(&mint_keypair.pubkey()),
88 &[&mint_keypair],
89 Hash::default(),
90 ));
91
92 assert!(verify_precompiles(&tx, &feature_set).is_err());
93 }
94
95 #[test]
96 fn test_verify_precompiles_ed25519() {
97 let privkey = ed25519_dalek::Keypair::generate(&mut thread_rng());
98 let message_arr = b"hello";
99 let mut instruction = new_ed25519_instruction(&privkey, message_arr);
100 let mint_keypair = Keypair::new();
101 let feature_set = FeatureSet::all_enabled();
102
103 let tx =
104 SanitizedTransaction::from_transaction_for_tests(Transaction::new_signed_with_payer(
105 &[instruction.clone()],
106 Some(&mint_keypair.pubkey()),
107 &[&mint_keypair],
108 Hash::default(),
109 ));
110
111 assert!(verify_precompiles(&tx, &feature_set).is_ok());
112
113 let index = loop {
114 let index = thread_rng().gen_range(0, instruction.data.len());
115 if index != 1 {
117 break index;
118 }
119 };
120
121 instruction.data[index] = instruction.data[index].wrapping_add(12);
122 let tx =
123 SanitizedTransaction::from_transaction_for_tests(Transaction::new_signed_with_payer(
124 &[instruction],
125 Some(&mint_keypair.pubkey()),
126 &[&mint_keypair],
127 Hash::default(),
128 ));
129 assert!(verify_precompiles(&tx, &feature_set).is_err());
130 }
131
132 #[test]
133 fn test_verify_precompiles_mixed() {
134 let message_arr = b"hello";
135 let secp_privkey = libsecp256k1::SecretKey::random(&mut thread_rng());
136 let mut secp_instruction = new_secp256k1_instruction(&secp_privkey, message_arr);
137 let ed25519_privkey = ed25519_dalek::Keypair::generate(&mut thread_rng());
138 let ed25519_instruction = new_ed25519_instruction(&ed25519_privkey, message_arr);
139
140 let mint_keypair = Keypair::new();
141 let feature_set = FeatureSet::all_enabled();
142
143 let tx =
144 SanitizedTransaction::from_transaction_for_tests(Transaction::new_signed_with_payer(
145 &[
146 secp_instruction.clone(),
147 ed25519_instruction.clone(),
148 system_instruction::transfer(&mint_keypair.pubkey(), &Pubkey::new_unique(), 1),
149 ],
150 Some(&mint_keypair.pubkey()),
151 &[&mint_keypair],
152 Hash::default(),
153 ));
154 assert!(verify_precompiles(&tx, &feature_set).is_ok());
155
156 let index = thread_rng().gen_range(0, secp_instruction.data.len());
157 secp_instruction.data[index] = secp_instruction.data[index].wrapping_add(12);
158 let tx =
159 SanitizedTransaction::from_transaction_for_tests(Transaction::new_signed_with_payer(
160 &[
161 secp_instruction,
162 ed25519_instruction,
163 system_instruction::transfer(&mint_keypair.pubkey(), &Pubkey::new_unique(), 1),
164 ],
165 Some(&mint_keypair.pubkey()),
166 &[&mint_keypair],
167 Hash::default(),
168 ));
169 assert!(verify_precompiles(&tx, &feature_set).is_err());
170 }
171}