1
1
use {
2
2
anchor_lang:: { prelude:: AccountMeta , InstructionData } ,
3
3
pyth_lazer_solana_contract:: { ed25519_program_args, ANCHOR_DISCRIMINATOR_BYTES } ,
4
- solana_program_test:: { BanksClient , ProgramTest } ,
4
+ solana_program_test:: { BanksClient , BanksClientError , ProgramTest } ,
5
5
solana_sdk:: {
6
6
account:: Account ,
7
7
ed25519_program,
8
8
hash:: Hash ,
9
- instruction:: Instruction ,
9
+ instruction:: { Instruction , InstructionError } ,
10
10
pubkey:: { Pubkey , PUBKEY_BYTES } ,
11
11
signature:: Keypair ,
12
12
signer:: Signer ,
13
13
system_instruction, system_program, system_transaction, sysvar,
14
- transaction:: Transaction ,
14
+ transaction:: { Transaction , TransactionError } ,
15
15
} ,
16
16
std:: env,
17
17
} ;
@@ -103,24 +103,45 @@ impl Setup {
103
103
}
104
104
105
105
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 > {
106
136
// Instruction #0 will be ed25519 instruction;
107
137
// Instruction #1 will be our contract instruction.
108
138
let instruction_index = 1 ;
109
- // 8 bytes for Anchor header, 4 bytes for Vec length.
110
- let message_offset = 12 ;
111
139
let ed25519_args = dbg ! ( pyth_lazer_solana_contract:: Ed25519SignatureOffsets :: new(
112
140
message,
113
141
instruction_index,
114
142
message_offset,
115
143
) ) ;
116
144
117
- let treasury_starting_lamports = self
118
- . banks_client
119
- . get_account ( treasury)
120
- . await
121
- . unwrap ( )
122
- . unwrap ( )
123
- . lamports ;
124
145
let mut transaction_verify = Transaction :: new_with_payer (
125
146
& [
126
147
Instruction :: new_with_bytes (
@@ -134,7 +155,6 @@ impl Setup {
134
155
message_data : message. to_vec ( ) ,
135
156
ed25519_instruction_index : 0 ,
136
157
signature_index : 0 ,
137
- message_offset,
138
158
}
139
159
. data ( ) ,
140
160
vec ! [
@@ -152,17 +172,6 @@ impl Setup {
152
172
self . banks_client
153
173
. process_transaction ( transaction_verify)
154
174
. 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
- ) ;
166
175
}
167
176
}
168
177
@@ -207,6 +216,84 @@ async fn test_basic() {
207
216
setup. verify_message ( & message, treasury) . await ;
208
217
}
209
218
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
+
210
297
#[ tokio:: test]
211
298
async fn test_migrate_from_0_1_0 ( ) {
212
299
let mut program_test = program_test ( ) ;
@@ -277,3 +364,58 @@ async fn test_migrate_from_0_1_0() {
277
364
// because it was present in the original storage PDA data.
278
365
setup. verify_message ( & message, treasury) . await ;
279
366
}
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