1
1
#![ allow( clippy:: integer_arithmetic) ]
2
2
//! This account contains the serialized transaction instructions
3
3
4
- use crate :: { instruction:: Instruction , sanitize:: SanitizeError } ;
4
+ use crate :: {
5
+ account_info:: AccountInfo , instruction:: Instruction , program_error:: ProgramError ,
6
+ sanitize:: SanitizeError ,
7
+ } ;
5
8
6
9
// Instructions Sysvar, dummy type, use the associated helpers instead of the Sysvar trait
7
10
pub struct Instructions ( ) ;
@@ -23,13 +26,36 @@ pub fn store_current_index(data: &mut [u8], instruction_index: u16) {
23
26
}
24
27
25
28
/// Load an instruction at the specified index
29
+ #[ deprecated(
30
+ since = "1.8.0" ,
31
+ note = "Unsafe because the sysvar accounts address is not checked, please use `load_instruction_at_checked` instead"
32
+ ) ]
26
33
pub fn load_instruction_at ( index : usize , data : & [ u8 ] ) -> Result < Instruction , SanitizeError > {
27
34
crate :: message:: Message :: deserialize_instruction ( index, data)
28
35
}
29
36
37
+ /// Load an instruction at the specified index
38
+ pub fn load_instruction_at_checked (
39
+ index : usize ,
40
+ instruction_sysvar_account_info : & AccountInfo ,
41
+ ) -> Result < Instruction , ProgramError > {
42
+ if !check_id ( instruction_sysvar_account_info. key ) {
43
+ return Err ( ProgramError :: UnsupportedSysvar ) ;
44
+ }
45
+
46
+ let instruction_sysvar = instruction_sysvar_account_info. try_borrow_data ( ) ?;
47
+ crate :: message:: Message :: deserialize_instruction ( index, & instruction_sysvar) . map_err ( |err| {
48
+ match err {
49
+ SanitizeError :: IndexOutOfBounds => ProgramError :: InvalidArgument ,
50
+ _ => ProgramError :: InvalidInstructionData ,
51
+ }
52
+ } )
53
+ }
54
+
30
55
#[ cfg( test) ]
31
56
mod tests {
32
57
use super :: * ;
58
+ use crate :: { instruction:: AccountMeta , message:: Message , pubkey:: Pubkey } ;
33
59
34
60
#[ test]
35
61
fn test_load_store_instruction ( ) {
@@ -38,4 +64,51 @@ mod tests {
38
64
assert_eq ! ( load_current_index( & data) , 3 ) ;
39
65
assert_eq ! ( [ 4u8 ; 8 ] , data[ 0 ..8 ] ) ;
40
66
}
67
+
68
+ #[ test]
69
+ fn test_load_instruction_at_checked ( ) {
70
+ let instruction1 = Instruction :: new_with_bincode (
71
+ Pubkey :: new_unique ( ) ,
72
+ & 0 ,
73
+ vec ! [ AccountMeta :: new( Pubkey :: new_unique( ) , false ) ] ,
74
+ ) ;
75
+ let instruction2 = Instruction :: new_with_bincode (
76
+ Pubkey :: new_unique ( ) ,
77
+ & 0 ,
78
+ vec ! [ AccountMeta :: new( Pubkey :: new_unique( ) , false ) ] ,
79
+ ) ;
80
+ let message = Message :: new (
81
+ & [ instruction1. clone ( ) , instruction2. clone ( ) ] ,
82
+ Some ( & Pubkey :: new_unique ( ) ) ,
83
+ ) ;
84
+
85
+ let key = id ( ) ;
86
+ let mut lamports = 0 ;
87
+ let mut data = message. serialize_instructions ( true ) ;
88
+ data. resize ( data. len ( ) + 2 , 0 ) ;
89
+ let owner = crate :: sysvar:: id ( ) ;
90
+ let account_info = AccountInfo :: new (
91
+ & key,
92
+ false ,
93
+ false ,
94
+ & mut lamports,
95
+ & mut data,
96
+ & owner,
97
+ false ,
98
+ 0 ,
99
+ ) ;
100
+
101
+ assert_eq ! (
102
+ instruction1,
103
+ load_instruction_at_checked( 0 , & account_info) . unwrap( )
104
+ ) ;
105
+ assert_eq ! (
106
+ instruction2,
107
+ load_instruction_at_checked( 1 , & account_info) . unwrap( )
108
+ ) ;
109
+ assert_eq ! (
110
+ Err ( ProgramError :: InvalidArgument ) ,
111
+ load_instruction_at_checked( 2 , & account_info)
112
+ ) ;
113
+ }
41
114
}
0 commit comments