@@ -314,6 +314,22 @@ fn test_config_updates() {
314314 let updated_config_account = result. get_account ( & config) . unwrap ( ) ;
315315
316316 // Attempt update with incomplete signatures.
317+ let keys = vec ! [
318+ ( pubkey, false ) ,
319+ ( signer1, true ) , // Missing signer0.
320+ ] ;
321+ let instruction = config_instruction:: store ( & config, false , keys, & my_config) ;
322+ mollusk. process_and_validate_instruction (
323+ & instruction,
324+ & [
325+ ( config, updated_config_account. clone ( ) ) ,
326+ // Missing signer0.
327+ ( signer1, AccountSharedData :: default ( ) ) ,
328+ ] ,
329+ & [ Check :: err ( ProgramError :: MissingRequiredSignature ) ] ,
330+ ) ;
331+
332+ // Do it again, this time missing signer1.
317333 let keys = vec ! [
318334 ( pubkey, false ) ,
319335 ( signer0, true ) , // Missing signer1.
@@ -323,7 +339,8 @@ fn test_config_updates() {
323339 & instruction,
324340 & [
325341 ( config, updated_config_account. clone ( ) ) ,
326- ( signer0, AccountSharedData :: default ( ) ) , // Missing signer1.
342+ ( signer0, AccountSharedData :: default ( ) ) ,
343+ // Missing signer1.
327344 ] ,
328345 & [ Check :: err ( ProgramError :: MissingRequiredSignature ) ] ,
329346 ) ;
@@ -346,6 +363,55 @@ fn test_config_updates() {
346363 ) ;
347364}
348365
366+ #[ test]
367+ fn test_config_updates_empty_current_keys ( ) {
368+ let mollusk = setup ( ) ;
369+
370+ let config = Pubkey :: new_unique ( ) ;
371+
372+ // New keys contains the config account, as well as another signer.
373+ let signer = Pubkey :: new_unique ( ) ;
374+ let new_keys = vec ! [ ( config, true ) , ( signer, true ) ] ;
375+ let my_config = MyConfig :: new ( 42 ) ;
376+
377+ let config_account = {
378+ // Allocate enough space for they `new_keys`, but leave the account
379+ // uninitalized.
380+ let space = get_config_space ( new_keys. len ( ) ) ;
381+ let lamports = mollusk. sysvars . rent . minimum_balance ( space) ;
382+ AccountSharedData :: new ( lamports, space, & solana_config_program:: id ( ) )
383+ } ;
384+
385+ let mut instruction = config_instruction:: store ( & config, true , new_keys, & my_config) ;
386+ mollusk. process_and_validate_instruction (
387+ & instruction,
388+ & [
389+ ( config, config_account. clone ( ) ) ,
390+ ( signer, AccountSharedData :: default ( ) ) ,
391+ ] ,
392+ & [ Check :: err ( ProgramError :: MissingRequiredSignature ) ] ,
393+ ) ;
394+
395+ // This is kind of strange, since the `store` helper was taken directly
396+ // from the builtin crate, and it's designed to only add the config account
397+ // once, even if it's a signer.
398+ // However, if you include it in the instruction twice, the loop-counter
399+ // mechanism of the processor actually works...
400+ instruction. accounts = vec ! [
401+ AccountMeta :: new( config, true ) ,
402+ AccountMeta :: new( config, true ) ,
403+ AccountMeta :: new( signer, true ) ,
404+ ] ;
405+ mollusk. process_and_validate_instruction (
406+ & instruction,
407+ & [
408+ ( config, config_account) ,
409+ ( signer, AccountSharedData :: default ( ) ) ,
410+ ] ,
411+ & [ Check :: success ( ) ] ,
412+ ) ;
413+ }
414+
349415#[ test]
350416fn test_config_initialize_contains_duplicates_fails ( ) {
351417 let mollusk = setup ( ) ;
0 commit comments