Skip to content

fix: resolve missing AES on delegate's witness after delegation - #1498

Open
lenkan wants to merge 1 commit into
WebOfTrust:v1.2.14from
global-vlei:fix-delegator-seal-v1.2.14
Open

fix: resolve missing AES on delegate's witness after delegation#1498
lenkan wants to merge 1 commit into
WebOfTrust:v1.2.14from
global-vlei:fix-delegator-seal-v1.2.14

Conversation

@lenkan

@lenkan lenkan commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Supersedes #1402, its original target branch (v1.2.13) was deleted. Please refer to #1402 for prior review discussion.

Witnesses accept delegated events (dip/drt) before the delegator has anchored them, to avoid a deadlock in the delegation flow. However, the authorizer event seal (AES) was never back-filled once the delegator's anchoring event arrived, leaving the witness permanently showing "Not anchored" for the delegated identifier.

Introduce a pending witness delegation escrow (pwde) that tracks delegated events accepted by a witness without an AES. A new processEscrowWitnessAnchors method, called from processEscrows, periodically checks whether the delegator's KEL now contains the anchoring seal and stores the AES when it does.

Fixes #1317

Witnesses accept delegated events (dip/drt) before the delegator has
anchored them, to avoid a deadlock in the delegation flow. However,
the authorizer event seal (AES) was never back-filled once the
delegator's anchoring event arrived, leaving the witness permanently
showing "Not anchored" for the delegated identifier.

Introduce a pending witness delegation escrow (pwde) that tracks
delegated events accepted by a witness without an AES. A new
processEscrowWitnessAnchors method, called from processEscrows,
periodically checks whether the delegator's KEL now contains the
anchoring seal and stores the AES when it does.

Fixes WebOfTrust#1317

@dhh1128 dhh1128 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The escrow approach here is the right one — parking a witness-accepted delegated event in pwde and only setting the AES after confirming the delegator's KEL actually anchors it is how this should work, and it goes straight at #1317.

The blocker is that it fixes dip but not drt. The enrollment condition in Kever.logEvent (src/keri/core/eventing.py ~3150-3156, self.delpre and ilk != ixn and locallyWitnessed) fires for delegated rotations as well as inceptions, but processEscrowWitnessAnchors reads the delegator as delpre = eserder.ked.get('di') (~5393-5439), and a drt carries no di — the Kever derives a rotation's delegator from prior state (eventing.py ~2297-2298). So a drt hits if not delpre: continue, the AES is never filled, the witness stays on "Not anchored" (the #1317 symptom again), and the pwde entry never clears. The new test (tests/core/test_escrow.py:752) covers only dip. The disabled reference at eventing.py ~5697/~6038 already reads self.kevers[eserder.pre].delpre, which works for both; deriving the delegator that way, and falling back to ked['di'] only for dip, plus a drt case in the test, would cover it.

Next, processEscrowWitnessAnchors (eventing.py:5407-5439) has no timeout. Every other Kevery escrow prunes against a Timeout* constant — TimeoutPWE (eventing.py:3648) drives the eviction at 5975-5990 — but this one writes no datetime and exits only on success, an exception, or an indefinite continue, while fetchLastSealingEventByEventSeal (basing.py:1778) rescans the delegator KEL from sn 0 on every processEscrows pass. A delegate that names this witness and incepts or rotates many delegated AIDs without getting the delegator to anchor leaves a permanent entry each time, each one an O(KEL) rescan per cycle, and a witness isn't a watcher, so it won't fetch the delegator's KEL on its own to clear them. A dts stamp and a Timeout* prune would bound it; a fetch cue for the delegator KEL would help more.

Smaller: validateDelegation's eager branch (eventing.py ~3060-3090) already does the same fetchLastSealingEventByEventSeal + setAes, guarded by a fons acceptance check; it just skips the witness because it short-circuits on locallyWitnessed. This adds a second path that omits the fons guard, so a later change to the AES couple format or the acceptance rule could land on one and miss the other. Routing the witness case through the eager path, or mirroring its fons guard, would keep them from drifting — though a dedicated escrow may read more clearly, so your call.

I'm guessing at intent in a couple of spots, the drt derivation especially, so correct me where I've misread the flow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants