@@ -362,7 +362,6 @@ fn create_summary_payload_helper(
362362 . ongoing_xnet_reshares
363363 . retain ( |request, _| !new_key_transcripts. contains ( & request. master_key_id ) ) ;
364364
365- idkg_summary. uid_generator . update_height ( height) ?;
366365 update_summary_refs ( height, & mut idkg_summary, block_reader) ?;
367366
368367 Ok ( Some ( idkg_summary) )
@@ -376,7 +375,7 @@ fn update_summary_refs(
376375 // Gather the refs and update them to point to the new
377376 // summary block height.
378377 let prev_refs = summary. active_transcripts ( ) ;
379- summary. update_refs ( height) ;
378+ summary. update_refs ( height) ? ;
380379
381380 // Resolve the transcript refs pointing into the parent chain,
382381 // copy the resolved transcripts into the summary block.
@@ -1152,6 +1151,120 @@ mod tests {
11521151 } )
11531152 }
11541153
1154+ #[ test]
1155+ fn test_create_summary_payload_updates_refs_all_algorithms ( ) {
1156+ for key_id in fake_master_public_key_ids_for_all_idkg_algorithms ( ) {
1157+ println ! ( "Running test for key ID {key_id}" ) ;
1158+ test_create_summary_payload_updates_refs ( & key_id) ;
1159+ }
1160+ }
1161+
1162+ /// The summary payload is the new anchor of the chain: the blocks of the previous
1163+ /// DKG interval are purged, so a summary that still points into them dangles.
1164+ /// Therefore `create_summary_payload_helper` must re-point every transcript ref of
1165+ /// the parent payload to the height of the new summary block, copy the resolved
1166+ /// transcripts into `idkg_transcripts`, and advance the UID generator's height.
1167+ fn test_create_summary_payload_updates_refs ( key_id : & IDkgMasterPublicKeyId ) {
1168+ ic_test_utilities:: artifact_pool_config:: with_test_pool_config ( |pool_config| {
1169+ let mut rng = reproducible_rng ( ) ;
1170+ let Dependencies { registry, .. } = DependenciesBuilder :: new ( pool_config, 1 ) . build ( ) ;
1171+ let subnet_id = subnet_test_id ( 1 ) ;
1172+ let parent_height = Height :: from ( 10 ) ;
1173+ let summary_height = Height :: from ( 11 ) ;
1174+
1175+ let env = CanisterThresholdSigTestEnvironment :: new ( 4 , & mut rng) ;
1176+ let mut block_reader = TestIDkgBlockReader :: new ( ) ;
1177+
1178+ // Both the current key transcript and the transcript being reshared to another
1179+ // subnet live in the parent chain, i.e. their refs point to `parent_height`.
1180+ let ( key_transcript, key_transcript_ref, current_key_transcript) =
1181+ generate_key_transcript ( key_id, & env, & mut rng, parent_height) ;
1182+ block_reader. add_transcript ( * key_transcript_ref. as_ref ( ) , key_transcript) ;
1183+
1184+ let ( reshare_key_transcript, reshare_key_transcript_ref, _) =
1185+ generate_key_transcript ( key_id, & env, & mut rng, parent_height) ;
1186+ let reshare_params = idkg:: ReshareOfUnmaskedParams :: new (
1187+ create_transcript_id ( 1001 ) ,
1188+ BTreeSet :: new ( ) ,
1189+ RegistryVersion :: from ( 1001 ) ,
1190+ & reshare_key_transcript,
1191+ reshare_key_transcript_ref,
1192+ ) ;
1193+ block_reader
1194+ . add_transcript ( * reshare_key_transcript_ref. as_ref ( ) , reshare_key_transcript) ;
1195+
1196+ let mut parent_payload =
1197+ empty_idkg_payload_with_key_ids ( subnet_id, vec ! [ key_id. clone( ) ] ) ;
1198+ * parent_payload. single_key_transcript_mut ( ) = idkg:: MasterKeyTranscript {
1199+ current : Some ( current_key_transcript. clone ( ) ) ,
1200+ next_in_creation : idkg:: KeyTranscriptCreation :: Created ( key_transcript_ref) ,
1201+ master_key_id : key_id. clone ( ) ,
1202+ } ;
1203+ parent_payload
1204+ . ongoing_xnet_reshares
1205+ . insert ( create_reshare_request ( key_id. clone ( ) , 1 , 1 ) , reshare_params) ;
1206+
1207+ // Sanity check: nothing points at the new summary height yet.
1208+ for transcript_ref in parent_payload. active_transcripts ( ) {
1209+ assert_eq ! ( transcript_ref. height, parent_height) ;
1210+ }
1211+
1212+ // Keep the registry version unchanged, so that no new key transcript is
1213+ // created and the ongoing xnet reshares aren't purged from the summary.
1214+ let registry_version = current_key_transcript. registry_version ( ) ;
1215+ let summary = create_summary_payload_helper (
1216+ subnet_id,
1217+ std:: slice:: from_ref ( key_id) ,
1218+ registry. as_ref ( ) ,
1219+ & block_reader,
1220+ summary_height,
1221+ registry_version,
1222+ registry_version,
1223+ & parent_payload,
1224+ None ,
1225+ & no_op_logger ( ) ,
1226+ )
1227+ . unwrap ( )
1228+ . unwrap ( ) ;
1229+
1230+ // All the refs of the parent payload were carried over, and re-pointed to the
1231+ // height of the new summary block.
1232+ let active_transcripts = summary. active_transcripts ( ) ;
1233+ assert_eq ! (
1234+ active_transcripts
1235+ . iter( )
1236+ . map( |transcript_ref| transcript_ref. transcript_id)
1237+ . collect:: <BTreeSet <_>>( ) ,
1238+ parent_payload
1239+ . active_transcripts( )
1240+ . iter( )
1241+ . map( |transcript_ref| transcript_ref. transcript_id)
1242+ . collect:: <BTreeSet <_>>( )
1243+ ) ;
1244+ for transcript_ref in & active_transcripts {
1245+ assert_eq ! ( transcript_ref. height, summary_height) ;
1246+ }
1247+
1248+ // The referenced transcripts were resolved against the parent chain and copied
1249+ // into the summary block, such that they survive the purging of that chain.
1250+ assert_eq ! ( summary. idkg_transcripts. len( ) , active_transcripts. len( ) ) ;
1251+ for transcript_ref in & active_transcripts {
1252+ let transcript = summary
1253+ . idkg_transcripts
1254+ . get ( & transcript_ref. transcript_id )
1255+ . expect ( "transcript should have been copied into the summary block" ) ;
1256+ assert_eq ! ( transcript. algorithm_id, AlgorithmId :: from( key_id. inner( ) ) ) ;
1257+ }
1258+
1259+ // The UID generator hands out transcript IDs anchored at the new summary height.
1260+ let mut uid_generator = summary. uid_generator . clone ( ) ;
1261+ assert_eq ! (
1262+ uid_generator. next_transcript_id( ) . source_height( ) ,
1263+ summary_height
1264+ ) ;
1265+ } )
1266+ }
1267+
11551268 #[ test]
11561269 fn test_summary_proto_conversion_all_algorithms ( ) {
11571270 for key_id in fake_master_public_key_ids_for_all_idkg_algorithms ( ) {
0 commit comments