@@ -782,9 +782,9 @@ mod tests {
782782 /// duplicated accounts, and instruction data.
783783 ///
784784 /// This function differs from `create_input` in that it creates accounts
785- /// with a marker indicating that they are duplicated. There is only a single
786- /// unique account - the first one - and all subsequent accounts
787- /// are marked as duplicated .
785+ /// with a marker indicating that they are duplicated. There will be
786+ /// `accounts - duplicated` unique accounts, and the remaining `duplicated`
787+ /// accounts will be duplicates of the last unique account .
788788 ///
789789 /// This function mimics the input buffer created by the SVM loader.
790790 /// Each account created has zeroed data, apart from the `data_len`
@@ -797,30 +797,37 @@ mod tests {
797797 unsafe fn create_input_with_duplicates (
798798 accounts : usize ,
799799 instruction_data : & [ u8 ] ,
800- account_len : usize ,
800+ duplicated : usize ,
801801 ) -> AlignedMemory {
802802 let mut input = AlignedMemory :: new ( 1_000_000_000 ) ;
803803 // Number of accounts.
804804 input. write ( & ( accounts as u64 ) . to_le_bytes ( ) , 0 ) ;
805805 let mut offset = size_of :: < u64 > ( ) ;
806806
807807 if accounts > 0 {
808- // Account data.
809- let mut account = [ 0u8 ; STATIC_ACCOUNT_DATA + size_of :: < u64 > ( ) ] ;
810- account[ 0 ] = NON_DUP_MARKER ;
811- // Set the accounts data length. The actual account data is zeroed.
812- account[ 80 ..88 ] . copy_from_slice ( & account_len. to_le_bytes ( ) ) ;
813- input. write ( & account, offset) ;
814- offset += account. len ( ) ;
815- // Padding for the account data to align to `BPF_ALIGN_OF_U128`.
816- let padding_for_data =
817- ( account_len + ( BPF_ALIGN_OF_U128 - 1 ) ) & !( BPF_ALIGN_OF_U128 - 1 ) ;
818- input. write ( & vec ! [ 0u8 ; padding_for_data] , offset) ;
819- offset += padding_for_data;
808+ assert ! (
809+ duplicated < accounts,
810+ "Duplicated accounts must be less than total accounts"
811+ ) ;
812+ let unique = accounts - duplicated;
813+
814+ for i in 0 ..unique {
815+ // Account data.
816+ let mut account = [ 0u8 ; STATIC_ACCOUNT_DATA + size_of :: < u64 > ( ) ] ;
817+ account[ 0 ] = NON_DUP_MARKER ;
818+ // Set the accounts data length. The actual account data is zeroed.
819+ account[ 80 ..88 ] . copy_from_slice ( & i. to_le_bytes ( ) ) ;
820+ input. write ( & account, offset) ;
821+ offset += account. len ( ) ;
822+ // Padding for the account data to align to `BPF_ALIGN_OF_U128`.
823+ let padding_for_data = ( i + ( BPF_ALIGN_OF_U128 - 1 ) ) & !( BPF_ALIGN_OF_U128 - 1 ) ;
824+ input. write ( & vec ! [ 0u8 ; padding_for_data] , offset) ;
825+ offset += padding_for_data;
826+ }
820827
821- // Remaining accounts are duplicated of the first one (index 0)
822- for _ in 1 ..accounts {
823- input. write ( & [ 0u8 ; 8 ] , offset) ;
828+ // Remaining accounts are duplicated of the last unique account.
829+ for _ in unique ..accounts {
830+ input. write ( & [ ( unique - 1 ) as u8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] , offset) ;
824831 offset += size_of :: < u64 > ( ) ;
825832 }
826833 }
@@ -848,14 +855,25 @@ mod tests {
848855
849856 /// Asserts that the accounts slice contains the expected number of accounts
850857 /// and all accounts are duplicated, apart from the first one.
851- fn assert_duplicated_accounts ( accounts : & [ MaybeUninit < AccountInfo > ] ) {
852- assert ! ( !accounts. is_empty( ) ) ;
853- let first_account = unsafe { accounts[ 0 ] . assume_init_ref ( ) } ;
858+ fn assert_duplicated_accounts ( accounts : & [ MaybeUninit < AccountInfo > ] , duplicated : usize ) {
859+ assert ! ( accounts. len( ) > duplicated) ;
860+
861+ let unique = accounts. len ( ) - duplicated;
862+
863+ // Unique accounts should have `data_len` equal to their index.
864+ for ( i, account) in accounts[ ..unique] . iter ( ) . enumerate ( ) {
865+ let account_info = unsafe { account. assume_init_ref ( ) } ;
866+ assert_eq ! ( account_info. data_len( ) , i) ;
867+ }
854868
855- for account in accounts[ 1 ..] . iter ( ) {
869+ // Duplicated accounts should have the same `data_len` as the
870+ // last unique account.
871+ for account in accounts[ unique..] . iter ( ) {
856872 let account_info = unsafe { account. assume_init_ref ( ) } ;
857- assert_eq ! ( account_info. raw, first_account. raw) ;
858- assert_eq ! ( account_info. data_len( ) , first_account. data_len( ) ) ;
873+ let duplicated = unsafe { accounts[ unique - 1 ] . assume_init_ref ( ) } ;
874+
875+ assert_eq ! ( account_info. raw, duplicated. raw) ;
876+ assert_eq ! ( account_info. data_len( ) , duplicated. data_len( ) ) ;
859877 }
860878 }
861879
@@ -910,7 +928,7 @@ mod tests {
910928
911929 // Input with 0 accounts.
912930
913- let mut input = unsafe { create_input_with_duplicates ( 0 , & ix_data, 50 ) } ;
931+ let mut input = unsafe { create_input_with_duplicates ( 0 , & ix_data, 0 ) } ;
914932 let mut accounts = [ UNINIT ; 1 ] ;
915933
916934 let ( program_id, count, parsed_ix_data) =
@@ -921,23 +939,27 @@ mod tests {
921939 assert_eq ! ( & ix_data, parsed_ix_data) ;
922940
923941 // Input with 3 (1 + 2 duplicated) accounts but the accounts array has only
924- // space for 1.
942+ // space for 2. The assert checks that the second account is a duplicate of
943+ // the first one and the first one is unique.
925944
926- let mut input = unsafe { create_input_with_duplicates ( 3 , & ix_data, 50 ) } ;
927- let mut accounts = [ UNINIT ; 1 ] ;
945+ let mut input = unsafe { create_input_with_duplicates ( 3 , & ix_data, 2 ) } ;
946+ let mut accounts = [ UNINIT ; 2 ] ;
928947
929948 let ( program_id, count, parsed_ix_data) =
930949 unsafe { deserialize ( input. as_mut_ptr ( ) , & mut accounts) } ;
931950
932- assert_eq ! ( count, 1 ) ;
951+ assert_eq ! ( count, 2 ) ;
933952 assert_eq ! ( program_id, & MOCK_PROGRAM_ID ) ;
934953 assert_eq ! ( & ix_data, parsed_ix_data) ;
935- assert_duplicated_accounts ( & accounts[ ..count] ) ;
954+ assert_duplicated_accounts ( & accounts[ ..count] , 1 ) ;
936955
937- // Input with `MAX_TX_ACCOUNTS` (1 + remaining duplicated) accounts but accounts
938- // array has only space for 64.
956+ // Input with `MAX_TX_ACCOUNTS` accounts (only 32 unique ones) but accounts
957+ // array has only space for 64. The assert checks that the first 32 accounts
958+ // are unique and the rest are duplicates of the account at index 31.
939959
940- let mut input = unsafe { create_input_with_duplicates ( MAX_TX_ACCOUNTS , & ix_data, 50 ) } ;
960+ let mut input = unsafe {
961+ create_input_with_duplicates ( MAX_TX_ACCOUNTS , & ix_data, MAX_TX_ACCOUNTS - 32 )
962+ } ;
941963 let mut accounts = [ UNINIT ; 64 ] ;
942964
943965 let ( program_id, count, parsed_ix_data) =
@@ -946,6 +968,6 @@ mod tests {
946968 assert_eq ! ( count, 64 ) ;
947969 assert_eq ! ( program_id, & MOCK_PROGRAM_ID ) ;
948970 assert_eq ! ( & ix_data, parsed_ix_data) ;
949- assert_duplicated_accounts ( & accounts) ;
971+ assert_duplicated_accounts ( & accounts, 32 ) ;
950972 }
951973}
0 commit comments