11use solana_program:: {
2- account_info:: AccountInfo , entrypoint, entrypoint:: ProgramResult , msg, pubkey:: Pubkey ,
2+ account_info:: { next_account_info, AccountInfo } ,
3+ entrypoint,
4+ entrypoint:: ProgramResult ,
5+ hash:: Hash ,
6+ msg,
7+ program_error:: ProgramError ,
8+ pubkey:: Pubkey ,
9+ sysvar,
310} ;
11+ use std:: convert:: TryInto ;
412
513entrypoint ! ( process_instruction) ;
614fn process_instruction (
7- program_id : & Pubkey ,
15+ _program_id : & Pubkey ,
816 accounts : & [ AccountInfo ] ,
9- instruction_data : & [ u8 ] ,
17+ _instruction_data : & [ u8 ] ,
1018) -> ProgramResult {
11- msg ! (
12- "process_instruction: {}: {} accounts, data={:?}" ,
13- program_id,
14- accounts. len( ) ,
15- instruction_data
16- ) ;
19+ let accounts_iter = & mut accounts. iter ( ) ;
20+ let sysvar_slot_history = next_account_info ( accounts_iter) ?;
21+
22+ /*
23+ Decoding the SlotHashes sysvar using `from_account_info` is too expensive.
24+ For example this statement will exceed the current BPF compute unit budget:
25+
26+ let slot_hashes = SlotHashes::from_account_info(&sysvar_slot_history).unwrap();
27+
28+ Instead manually decode the sysvar.
29+ */
30+
31+ if * sysvar_slot_history. key != sysvar:: slot_hashes:: id ( ) {
32+ msg ! ( "Invalid SlotHashes sysvar" ) ;
33+ return Err ( ProgramError :: InvalidArgument ) ;
34+ }
35+
36+ let data = sysvar_slot_history. try_borrow_data ( ) ?;
37+
38+ let num_slot_hashes = u64:: from_le_bytes ( data[ 0 ..8 ] . try_into ( ) . unwrap ( ) ) ;
39+ let mut pos = 8 ;
40+
41+ for _i in 0 ..num_slot_hashes {
42+ let slot = u64:: from_le_bytes ( data[ pos..pos + 8 ] . try_into ( ) . unwrap ( ) ) ;
43+ pos += 8 ;
44+ let hash = & data[ pos..pos + 32 ] ;
45+ pos += 32 ;
46+
47+ if slot == 54943128 {
48+ msg ! ( "Found slot {}, hash {}" , slot, Hash :: new( hash) ) ;
49+ }
50+ }
51+
1752 Ok ( ( ) )
1853}
1954
@@ -22,7 +57,11 @@ mod test {
2257 use {
2358 super :: * ,
2459 assert_matches:: * ,
25- solana_program:: instruction:: { AccountMeta , Instruction } ,
60+ solana_program:: {
61+ instruction:: { AccountMeta , Instruction } ,
62+ native_token:: sol_to_lamports,
63+ sysvar,
64+ } ,
2665 solana_program_test:: * ,
2766 solana_sdk:: { signature:: Signer , transaction:: Transaction } ,
2867 } ;
@@ -31,19 +70,30 @@ mod test {
3170 async fn test_transaction ( ) {
3271 let program_id = Pubkey :: new_unique ( ) ;
3372
34- let ( mut banks_client , payer , recent_blockhash ) = ProgramTest :: new (
73+ let mut program_test = ProgramTest :: new (
3574 "bpf_program_template" ,
3675 program_id,
3776 processor ! ( process_instruction) ,
38- )
39- . start ( )
40- . await ;
77+ ) ;
78+
79+ // Replace the SlotHashes sysvar will a full populated version that was grabbed off Mainnet
80+ // Beta by running:
81+ // solana account SysvarS1otHashes111111111111111111111111111 -o slot_hashes.bin
82+ program_test. add_account_with_file_data (
83+ sysvar:: slot_hashes:: id ( ) ,
84+ sol_to_lamports ( 1. ) ,
85+ Pubkey :: default ( ) ,
86+ "slot_hashes.bin" ,
87+ ) ;
88+
89+ let ( mut banks_client, payer, recent_blockhash) = program_test. start ( ) . await ;
4190
4291 let mut transaction = Transaction :: new_with_payer (
4392 & [ Instruction {
4493 program_id,
45- accounts : vec ! [ AccountMeta :: new( payer. pubkey( ) , false ) ] ,
46- data : vec ! [ 1 , 2 , 3 ] ,
94+ accounts : vec ! [ AccountMeta :: new( sysvar:: slot_hashes:: id( ) , false ) ] ,
95+ //accounts: vec![AccountMeta::new(fake_slot_hashes, false)],
96+ data : vec ! [ ] ,
4797 } ] ,
4898 Some ( & payer. pubkey ( ) ) ,
4999 ) ;
0 commit comments