11use {
22 anchor_lang:: { prelude:: AccountMeta , InstructionData } ,
33 pyth_lazer_solana_contract:: { ed25519_program_args, ANCHOR_DISCRIMINATOR_BYTES } ,
4- solana_program_test:: { BanksClient , ProgramTest } ,
4+ solana_program_test:: { BanksClient , BanksClientError , ProgramTest } ,
55 solana_sdk:: {
66 account:: Account ,
77 ed25519_program,
88 hash:: Hash ,
9- instruction:: Instruction ,
9+ instruction:: { Instruction , InstructionError } ,
1010 pubkey:: { Pubkey , PUBKEY_BYTES } ,
1111 signature:: Keypair ,
1212 signer:: Signer ,
1313 system_instruction, system_program, system_transaction, sysvar,
14- transaction:: Transaction ,
14+ transaction:: { Transaction , TransactionError } ,
1515 } ,
1616 std:: env,
1717} ;
@@ -103,24 +103,45 @@ impl Setup {
103103 }
104104
105105 async fn verify_message ( & mut self , message : & [ u8 ] , treasury : Pubkey ) {
106+ let treasury_starting_lamports = self
107+ . banks_client
108+ . get_account ( treasury)
109+ . await
110+ . unwrap ( )
111+ . unwrap ( )
112+ . lamports ;
113+
114+ // 8 bytes for Anchor header, 4 bytes for Vec length.
115+ self . verify_message_with_offset ( message, treasury, 12 )
116+ . await
117+ . unwrap ( ) ;
118+
119+ assert_eq ! (
120+ self . banks_client
121+ . get_account( treasury)
122+ . await
123+ . unwrap( )
124+ . unwrap( )
125+ . lamports,
126+ treasury_starting_lamports + 1 ,
127+ ) ;
128+ }
129+
130+ async fn verify_message_with_offset (
131+ & mut self ,
132+ message : & [ u8 ] ,
133+ treasury : Pubkey ,
134+ message_offset : u16 ,
135+ ) -> Result < ( ) , BanksClientError > {
106136 // Instruction #0 will be ed25519 instruction;
107137 // Instruction #1 will be our contract instruction.
108138 let instruction_index = 1 ;
109- // 8 bytes for Anchor header, 4 bytes for Vec length.
110- let message_offset = 12 ;
111139 let ed25519_args = dbg ! ( pyth_lazer_solana_contract:: Ed25519SignatureOffsets :: new(
112140 message,
113141 instruction_index,
114142 message_offset,
115143 ) ) ;
116144
117- let treasury_starting_lamports = self
118- . banks_client
119- . get_account ( treasury)
120- . await
121- . unwrap ( )
122- . unwrap ( )
123- . lamports ;
124145 let mut transaction_verify = Transaction :: new_with_payer (
125146 & [
126147 Instruction :: new_with_bytes (
@@ -134,7 +155,6 @@ impl Setup {
134155 message_data : message. to_vec ( ) ,
135156 ed25519_instruction_index : 0 ,
136157 signature_index : 0 ,
137- message_offset,
138158 }
139159 . data ( ) ,
140160 vec ! [
@@ -152,17 +172,6 @@ impl Setup {
152172 self . banks_client
153173 . process_transaction ( transaction_verify)
154174 . await
155- . unwrap ( ) ;
156-
157- assert_eq ! (
158- self . banks_client
159- . get_account( treasury)
160- . await
161- . unwrap( )
162- . unwrap( )
163- . lamports,
164- treasury_starting_lamports + 1 ,
165- ) ;
166175 }
167176}
168177
@@ -207,6 +216,84 @@ async fn test_basic() {
207216 setup. verify_message ( & message, treasury) . await ;
208217}
209218
219+ #[ tokio:: test]
220+ async fn test_rejects_wrong_offset ( ) {
221+ let mut setup = Setup :: new ( ) . await ;
222+ let treasury = setup. create_treasury ( ) . await ;
223+
224+ let mut transaction_init_contract = Transaction :: new_with_payer (
225+ & [ Instruction :: new_with_bytes (
226+ pyth_lazer_solana_contract:: ID ,
227+ & pyth_lazer_solana_contract:: instruction:: Initialize {
228+ top_authority : setup. payer . pubkey ( ) ,
229+ treasury,
230+ }
231+ . data ( ) ,
232+ vec ! [
233+ AccountMeta :: new( setup. payer. pubkey( ) , true ) ,
234+ AccountMeta :: new( pyth_lazer_solana_contract:: STORAGE_ID , false ) ,
235+ AccountMeta :: new_readonly( system_program:: ID , false ) ,
236+ ] ,
237+ ) ] ,
238+ Some ( & setup. payer . pubkey ( ) ) ,
239+ ) ;
240+ transaction_init_contract. sign ( & [ & setup. payer ] , setup. recent_blockhash ) ;
241+ setup
242+ . banks_client
243+ . process_transaction ( transaction_init_contract)
244+ . await
245+ . unwrap ( ) ;
246+
247+ let verifying_key =
248+ hex:: decode ( "74313a6525edf99936aa1477e94c72bc5cc617b21745f5f03296f3154461f214" ) . unwrap ( ) ;
249+ let verifying_key_2 =
250+ hex:: decode ( "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ) . unwrap ( ) ;
251+ let message = hex:: decode (
252+ [
253+ // --- First copy of the message (this data is returned by the Lazer contract)
254+
255+ // SOLANA_FORMAT_MAGIC_LE
256+ "b9011a82" ,
257+ // Signature
258+ "e5cddee2c1bd364c8c57e1c98a6a28d194afcad410ff412226c8b2ae931ff59a57147cb47c7307afc2a0a1abec4dd7e835a5b7113cf5aeac13a745c6bed6c600" ,
259+ // Pubkey
260+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ,
261+ // Payload length (could be adjusted)
262+ "1c00" ,
263+ // Payload
264+ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ,
265+
266+ // --- Second copy of the message (this data is used by the ed25519 program)
267+
268+ // Unused, was SOLANA_FORMAT_MAGIC_LE, could be removed, left it for slightly easier offset adjustments
269+ "AABBCCDD" ,
270+ // Signature
271+ "e5cddee2c1bd364c8c57e1c98a6a28d194afcad410ff412226c8b2ae931ff59a57147cb47c7307afc2a0a1abec4dd7e835a5b7113cf5aeac13a745c6bed6c600" ,
272+ // Pubkey
273+ "74313a6525edf99936aa1477e94c72bc5cc617b21745f5f03296f3154461f214" ,
274+ // Payload length
275+ "1c00" ,
276+ // Payload
277+ "75d3c7931c9773f30a240600010102000000010000e1f50500000000"
278+ ] . concat ( )
279+ )
280+ . unwrap ( ) ;
281+
282+ setup. set_trusted ( verifying_key. try_into ( ) . unwrap ( ) ) . await ;
283+ setup. set_trusted ( verifying_key_2. try_into ( ) . unwrap ( ) ) . await ;
284+ let err = setup
285+ . verify_message_with_offset ( & message, treasury, 12 + 130 )
286+ . await
287+ . unwrap_err ( ) ;
288+ assert ! ( matches!(
289+ err,
290+ BanksClientError :: TransactionError ( TransactionError :: InstructionError (
291+ 1 ,
292+ InstructionError :: InvalidInstructionData
293+ ) )
294+ ) ) ;
295+ }
296+
210297#[ tokio:: test]
211298async fn test_migrate_from_0_1_0 ( ) {
212299 let mut program_test = program_test ( ) ;
@@ -277,3 +364,58 @@ async fn test_migrate_from_0_1_0() {
277364 // because it was present in the original storage PDA data.
278365 setup. verify_message ( & message, treasury) . await ;
279366}
367+
368+ #[ tokio:: test]
369+ async fn test_disallows_extra_migrate ( ) {
370+ let mut setup = Setup :: new ( ) . await ;
371+ let treasury = setup. create_treasury ( ) . await ;
372+
373+ let mut transaction_init_contract = Transaction :: new_with_payer (
374+ & [ Instruction :: new_with_bytes (
375+ pyth_lazer_solana_contract:: ID ,
376+ & pyth_lazer_solana_contract:: instruction:: Initialize {
377+ top_authority : setup. payer . pubkey ( ) ,
378+ treasury,
379+ }
380+ . data ( ) ,
381+ vec ! [
382+ AccountMeta :: new( setup. payer. pubkey( ) , true ) ,
383+ AccountMeta :: new( pyth_lazer_solana_contract:: STORAGE_ID , false ) ,
384+ AccountMeta :: new_readonly( system_program:: ID , false ) ,
385+ ] ,
386+ ) ] ,
387+ Some ( & setup. payer . pubkey ( ) ) ,
388+ ) ;
389+ transaction_init_contract. sign ( & [ & setup. payer ] , setup. recent_blockhash ) ;
390+ setup
391+ . banks_client
392+ . process_transaction ( transaction_init_contract)
393+ . await
394+ . unwrap ( ) ;
395+
396+ let mut transaction_migrate_contract = Transaction :: new_with_payer (
397+ & [ Instruction :: new_with_bytes (
398+ pyth_lazer_solana_contract:: ID ,
399+ & pyth_lazer_solana_contract:: instruction:: MigrateFrom010 { treasury } . data ( ) ,
400+ vec ! [
401+ AccountMeta :: new( setup. payer. pubkey( ) , true ) ,
402+ AccountMeta :: new( pyth_lazer_solana_contract:: STORAGE_ID , false ) ,
403+ AccountMeta :: new_readonly( system_program:: ID , false ) ,
404+ ] ,
405+ ) ] ,
406+ Some ( & setup. payer . pubkey ( ) ) ,
407+ ) ;
408+ transaction_migrate_contract. sign ( & [ & setup. payer ] , setup. recent_blockhash ) ;
409+ let err = setup
410+ . banks_client
411+ . process_transaction ( transaction_migrate_contract)
412+ . await
413+ . unwrap_err ( ) ;
414+ assert ! ( matches!(
415+ err,
416+ BanksClientError :: TransactionError ( TransactionError :: InstructionError (
417+ 0 ,
418+ InstructionError :: InvalidAccountData
419+ ) )
420+ ) ) ;
421+ }
0 commit comments