22
33import json
44import logging
5- from typing import Mapping , Optional , Sequence , Text , Tuple
5+ from typing import Mapping , NamedTuple , Optional , Sequence , Text , Tuple
66
77from ..connections .models .conn_record import ConnRecord
88from ..core .error import BaseError
@@ -26,6 +26,17 @@ class RevocationManagerError(BaseError):
2626 """Revocation manager error."""
2727
2828
29+ class RevocationNotificationInfo (NamedTuple ):
30+ """Revocation notification information."""
31+
32+ rev_reg_id : str
33+ cred_rev_id : str
34+ thread_id : Optional [str ]
35+ connection_id : Optional [str ]
36+ comment : Optional [str ]
37+ notify_version : Optional [str ]
38+
39+
2940class RevocationManager :
3041 """Class for managing revocation operations."""
3142
@@ -107,6 +118,46 @@ async def revoke_credential_by_cred_ex_id(
107118 write_ledger = write_ledger ,
108119 )
109120
121+ async def _prepare_revocation_notification (
122+ self ,
123+ revoc_notif_info : RevocationNotificationInfo ,
124+ ):
125+ """Saves the revocation notification record, and thread_id if not provided."""
126+ thread_id = (
127+ revoc_notif_info .thread_id
128+ or f"indy::{ revoc_notif_info .rev_reg_id } ::{ revoc_notif_info .cred_rev_id } "
129+ )
130+ rev_notify_rec = RevNotificationRecord (
131+ rev_reg_id = revoc_notif_info .rev_reg_id ,
132+ cred_rev_id = revoc_notif_info .cred_rev_id ,
133+ thread_id = thread_id ,
134+ connection_id = revoc_notif_info .connection_id ,
135+ comment = revoc_notif_info .comment ,
136+ version = revoc_notif_info .notify_version ,
137+ )
138+ async with self ._profile .session () as session :
139+ await rev_notify_rec .save (session , reason = "New revocation notification" )
140+
141+ async def _get_endorsement_txn_for_revocation (
142+ self , endorser_conn_id : str , issuer_rr_upd : IssuerRevRegRecord
143+ ):
144+ async with self ._profile .session () as session :
145+ try :
146+ connection_record = await ConnRecord .retrieve_by_id (
147+ session , endorser_conn_id
148+ )
149+ except StorageNotFoundError :
150+ raise RevocationManagerError (
151+ "No endorser connection record found " f"for id: { endorser_conn_id } "
152+ )
153+ endorser_info = await connection_record .metadata_get (session , "endorser_info" )
154+ endorser_did = endorser_info ["endorser_did" ]
155+ return await issuer_rr_upd .send_entry (
156+ self ._profile ,
157+ write_ledger = False ,
158+ endorser_did = endorser_did ,
159+ )
160+
110161 async def revoke_credential (
111162 self ,
112163 rev_reg_id : str ,
@@ -150,81 +201,72 @@ async def revoke_credential(
150201 write_ledger is True, otherwise None.
151202 """
152203 issuer = self ._profile .inject (IndyIssuer )
153-
154204 revoc = IndyRevocation (self ._profile )
205+
155206 issuer_rr_rec = await revoc .get_issuer_rev_reg_record (rev_reg_id )
156207 if not issuer_rr_rec :
157208 raise RevocationManagerError (
158209 f"No revocation registry record found for id: { rev_reg_id } "
159210 )
160211
161212 if notify :
162- thread_id = thread_id or f"indy::{ rev_reg_id } ::{ cred_rev_id } "
163- rev_notify_rec = RevNotificationRecord (
164- rev_reg_id = rev_reg_id ,
165- cred_rev_id = cred_rev_id ,
166- thread_id = thread_id ,
167- connection_id = connection_id ,
168- comment = comment ,
169- version = notify_version ,
170- )
171- async with self ._profile .session () as session :
172- await rev_notify_rec .save (session , reason = "New revocation notification" )
173-
174- if publish :
175- rev_reg = await revoc .get_ledger_registry (rev_reg_id )
176- await rev_reg .get_or_fetch_local_tails_path ()
177- # pick up pending revocations on input revocation registry
178- crids = (issuer_rr_rec .pending_pub or []) + [cred_rev_id ]
179- (delta_json , _ ) = await issuer .revoke_credentials (
180- issuer_rr_rec .cred_def_id ,
181- issuer_rr_rec .revoc_reg_id ,
182- issuer_rr_rec .tails_local_path ,
183- crids ,
213+ await self ._prepare_revocation_notification (
214+ RevocationNotificationInfo (
215+ rev_reg_id = rev_reg_id ,
216+ cred_rev_id = cred_rev_id ,
217+ thread_id = thread_id ,
218+ connection_id = connection_id ,
219+ comment = comment ,
220+ notify_version = notify_version ,
221+ ),
184222 )
185- async with self ._profile .transaction () as txn :
186- issuer_rr_upd = await IssuerRevRegRecord .retrieve_by_id (
187- txn , issuer_rr_rec .record_id , for_update = True
188- )
189- if delta_json :
190- issuer_rr_upd .revoc_reg_entry = json .loads (delta_json )
191- await issuer_rr_upd .clear_pending (txn , crids )
192- await txn .commit ()
193- await self .set_cred_revoked_state (rev_reg_id , crids )
194- if delta_json :
195- if write_ledger :
196- rev_entry_resp = await issuer_rr_upd .send_entry (self ._profile )
197- await notify_revocation_published_event (
198- self ._profile , rev_reg_id , [cred_rev_id ]
199- )
200- return rev_entry_resp
201- else :
202- async with self ._profile .session () as session :
203- try :
204- connection_record = await ConnRecord .retrieve_by_id (
205- session , endorser_conn_id
206- )
207- except StorageNotFoundError :
208- raise RevocationManagerError (
209- "No endorser connection record found "
210- f"for id: { endorser_conn_id } "
211- )
212- endorser_info = await connection_record .metadata_get (
213- session , "endorser_info"
214- )
215- endorser_did = endorser_info ["endorser_did" ]
216- rev_entry_resp = await issuer_rr_upd .send_entry (
217- self ._profile ,
218- write_ledger = write_ledger ,
219- endorser_did = endorser_did ,
220- )
221- return rev_entry_resp
222- else :
223+
224+ if not publish :
225+ # If not publishing, just mark the revocation as pending.
223226 async with self ._profile .transaction () as txn :
224227 await issuer_rr_rec .mark_pending (txn , cred_rev_id )
225228 await txn .commit ()
226229 return None
227230
231+ rev_reg = await revoc .get_ledger_registry (rev_reg_id )
232+ await rev_reg .get_or_fetch_local_tails_path ()
233+ # pick up pending revocations on input revocation registry
234+ crids = (issuer_rr_rec .pending_pub or []) + [cred_rev_id ]
235+ (delta_json , _ ) = await issuer .revoke_credentials (
236+ issuer_rr_rec .cred_def_id ,
237+ issuer_rr_rec .revoc_reg_id ,
238+ issuer_rr_rec .tails_local_path ,
239+ crids ,
240+ )
241+
242+ # Update the revocation registry record with the new delta
243+ # and clear pending revocations
244+ async with self ._profile .transaction () as txn :
245+ issuer_rr_upd = await IssuerRevRegRecord .retrieve_by_id (
246+ txn , issuer_rr_rec .record_id , for_update = True
247+ )
248+ if delta_json :
249+ issuer_rr_upd .revoc_reg_entry = json .loads (delta_json )
250+ await issuer_rr_upd .clear_pending (txn , crids )
251+ await txn .commit ()
252+
253+ await self .set_cred_revoked_state (rev_reg_id , crids )
254+
255+ # Revocation list needs to be updated on ledger
256+ if delta_json :
257+ # Can write to ledger directly
258+ if write_ledger :
259+ rev_entry_resp = await issuer_rr_upd .send_entry (self ._profile )
260+ await notify_revocation_published_event (
261+ self ._profile , rev_reg_id , [cred_rev_id ]
262+ )
263+ return rev_entry_resp
264+ # Author --> Need endorsed transaction for revocation
265+ else :
266+ return await self ._get_endorsement_txn_for_revocation (
267+ endorser_conn_id , issuer_rr_upd
268+ )
269+
228270 async def update_rev_reg_revoked_state (
229271 self ,
230272 apply_ledger_update : bool ,
0 commit comments