@@ -14,7 +14,7 @@ use doublezero_serviceability::{
1414 pda:: {
1515 get_accesspass_pda, get_contributor_pda, get_device_pda, get_exchange_pda,
1616 get_globalconfig_pda, get_globalstate_pda, get_location_pda, get_multicastgroup_pda,
17- get_program_config_pda, get_resource_extension_pda, get_user_pda,
17+ get_program_config_pda, get_resource_extension_pda, get_tenant_pda , get_user_pda,
1818 } ,
1919 processors:: {
2020 accesspass:: set:: SetAccessPassArgs ,
@@ -34,6 +34,7 @@ use doublezero_serviceability::{
3434 } ,
3535 create:: MulticastGroupCreateArgs ,
3636 } ,
37+ tenant:: create:: TenantCreateArgs ,
3738 user:: create_subscribe:: UserCreateSubscribeArgs ,
3839 } ,
3940 resource:: ResourceType ,
@@ -932,3 +933,142 @@ async fn test_create_subscribe_user_inactive_mgroup_fails() {
932933 "Should fail with graceful error when mgroup is not activated"
933934 ) ;
934935}
936+
937+ /// Multicast user creation succeeds when the access-pass has a tenant_allowlist.
938+ ///
939+ /// Regression test: multicast connections are not tenant-scoped. A user with an access-pass
940+ /// restricted to a specific tenant should still be able to create a multicast connection,
941+ /// because CreateSubscribeUser never passes a tenant account.
942+ #[ tokio:: test]
943+ async fn test_create_subscribe_user_ignores_tenant_allowlist ( ) {
944+ let client_ip = [ 100 , 0 , 0 , 8 ] ;
945+ let f = setup_create_subscribe_fixture ( client_ip) . await ;
946+ let CreateSubscribeFixture {
947+ mut banks_client,
948+ payer,
949+ program_id,
950+ globalstate_pubkey,
951+ device_pubkey,
952+ mgroup_pubkey,
953+ user_ip,
954+ ..
955+ } = f;
956+
957+ let recent_blockhash = banks_client. get_latest_blockhash ( ) . await . unwrap ( ) ;
958+
959+ // Create a tenant
960+ let ( vrf_ids_pda, _, _) = get_resource_extension_pda ( & program_id, ResourceType :: VrfIds ) ;
961+ let ( tenant_pubkey, _) = get_tenant_pda ( & program_id, "solana" ) ;
962+ execute_transaction (
963+ & mut banks_client,
964+ recent_blockhash,
965+ program_id,
966+ DoubleZeroInstruction :: CreateTenant ( TenantCreateArgs {
967+ code : "solana" . to_string ( ) ,
968+ administrator : payer. pubkey ( ) ,
969+ token_account : None ,
970+ metro_routing : true ,
971+ route_liveness : false ,
972+ } ) ,
973+ vec ! [
974+ AccountMeta :: new( tenant_pubkey, false ) ,
975+ AccountMeta :: new( globalstate_pubkey, false ) ,
976+ AccountMeta :: new( vrf_ids_pda, false ) ,
977+ ] ,
978+ & payer,
979+ )
980+ . await ;
981+
982+ // Create access pass with the tenant in its allowlist
983+ let ( accesspass_pubkey, _) = get_accesspass_pda ( & program_id, & user_ip, & payer. pubkey ( ) ) ;
984+ execute_transaction (
985+ & mut banks_client,
986+ recent_blockhash,
987+ program_id,
988+ DoubleZeroInstruction :: SetAccessPass ( SetAccessPassArgs {
989+ accesspass_type : AccessPassType :: Prepaid ,
990+ client_ip : user_ip,
991+ last_access_epoch : 9999 ,
992+ allow_multiple_ip : false ,
993+ } ) ,
994+ vec ! [
995+ AccountMeta :: new( accesspass_pubkey, false ) ,
996+ AccountMeta :: new( globalstate_pubkey, false ) ,
997+ AccountMeta :: new( payer. pubkey( ) , false ) ,
998+ AccountMeta :: new( Pubkey :: default ( ) , false ) , // no tenant to remove
999+ AccountMeta :: new( tenant_pubkey, false ) , // add tenant to allowlist
1000+ ] ,
1001+ & payer,
1002+ )
1003+ . await ;
1004+
1005+ // Add mgroup to allowlists
1006+ execute_transaction (
1007+ & mut banks_client,
1008+ recent_blockhash,
1009+ program_id,
1010+ DoubleZeroInstruction :: AddMulticastGroupPubAllowlist ( AddMulticastGroupPubAllowlistArgs {
1011+ client_ip : user_ip,
1012+ user_payer : payer. pubkey ( ) ,
1013+ } ) ,
1014+ vec ! [
1015+ AccountMeta :: new( mgroup_pubkey, false ) ,
1016+ AccountMeta :: new( accesspass_pubkey, false ) ,
1017+ AccountMeta :: new( globalstate_pubkey, false ) ,
1018+ ] ,
1019+ & payer,
1020+ )
1021+ . await ;
1022+
1023+ execute_transaction (
1024+ & mut banks_client,
1025+ recent_blockhash,
1026+ program_id,
1027+ DoubleZeroInstruction :: AddMulticastGroupSubAllowlist ( AddMulticastGroupSubAllowlistArgs {
1028+ client_ip : user_ip,
1029+ user_payer : payer. pubkey ( ) ,
1030+ } ) ,
1031+ vec ! [
1032+ AccountMeta :: new( mgroup_pubkey, false ) ,
1033+ AccountMeta :: new( accesspass_pubkey, false ) ,
1034+ AccountMeta :: new( globalstate_pubkey, false ) ,
1035+ ] ,
1036+ & payer,
1037+ )
1038+ . await ;
1039+
1040+ // Multicast user creation should succeed even though access-pass has a tenant_allowlist
1041+ let ( user_pubkey, _) = get_user_pda ( & program_id, & user_ip, UserType :: Multicast ) ;
1042+ let recent_blockhash = banks_client. get_latest_blockhash ( ) . await . unwrap ( ) ;
1043+ execute_transaction (
1044+ & mut banks_client,
1045+ recent_blockhash,
1046+ program_id,
1047+ DoubleZeroInstruction :: CreateSubscribeUser ( UserCreateSubscribeArgs {
1048+ user_type : UserType :: Multicast ,
1049+ cyoa_type : UserCYOA :: GREOverDIA ,
1050+ client_ip : user_ip,
1051+ publisher : false ,
1052+ subscriber : true ,
1053+ tunnel_endpoint : Ipv4Addr :: UNSPECIFIED ,
1054+ dz_prefix_count : 0 ,
1055+ } ) ,
1056+ vec ! [
1057+ AccountMeta :: new( user_pubkey, false ) ,
1058+ AccountMeta :: new( device_pubkey, false ) ,
1059+ AccountMeta :: new( mgroup_pubkey, false ) ,
1060+ AccountMeta :: new( accesspass_pubkey, false ) ,
1061+ AccountMeta :: new( globalstate_pubkey, false ) ,
1062+ ] ,
1063+ & payer,
1064+ )
1065+ . await ;
1066+
1067+ let user = get_account_data ( & mut banks_client, user_pubkey)
1068+ . await
1069+ . expect ( "User should exist" )
1070+ . get_user ( )
1071+ . unwrap ( ) ;
1072+ assert_eq ! ( user. status, UserStatus :: Pending ) ;
1073+ assert_eq ! ( user. subscribers, vec![ mgroup_pubkey] ) ;
1074+ }
0 commit comments