keri-ts 2.2.4 → 2.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/keri/npm/src/_dnt.polyfills.js +14 -14
- package/esm/keri/npm/src/acdc/dhking.js +29 -2
- package/esm/keri/npm/src/acdc/observing.js +10 -3
- package/esm/keri/npm/src/acdc/query-resend.js +74 -0
- package/esm/keri/npm/src/acdc/regengine.js +39 -9
- package/esm/keri/npm/src/acdc/regeventing.js +5 -3
- package/esm/keri/npm/src/acdc/registering.js +19 -0
- package/esm/keri/npm/src/acdc/salting.js +4 -0
- package/esm/keri/npm/src/acdc/unblinding.js +38 -3
- package/esm/keri/npm/src/app/bootstrap/authenticating.js +32 -10
- package/esm/keri/npm/src/app/bootstrap/oobiery.js +363 -30
- package/esm/keri/npm/src/app/credentials/credential-importing.js +33 -4
- package/esm/keri/npm/src/app/credentials/root-replicator.js +27 -15
- package/esm/keri/npm/src/app/credentials/schema-resolving.js +5 -1
- package/esm/keri/npm/src/app/credentials/tel-publishing.js +16 -7
- package/esm/keri/npm/src/app/delivery/forwarding.js +205 -44
- package/esm/keri/npm/src/app/delivery/relaying.js +232 -0
- package/esm/keri/npm/src/app/delivery/respondant.js +8 -5
- package/esm/keri/npm/src/app/exchanges/exchange-messaging.js +1 -1
- package/esm/keri/npm/src/app/exchanges/exchanging.js +65 -9
- package/esm/keri/npm/src/app/identity/delegating.js +66 -9
- package/esm/keri/npm/src/app/identity/habbing.js +190 -71
- package/esm/keri/npm/src/app/identity/keeping.js +111 -39
- package/esm/keri/npm/src/app/identity/retire-identifier.js +98 -0
- package/esm/keri/npm/src/app/ipex/disclosure-replaying.js +116 -0
- package/esm/keri/npm/src/app/ipex/group-ipex.js +122 -25
- package/esm/keri/npm/src/app/ipex/group-issuance.js +137 -37
- package/esm/keri/npm/src/app/ipex/ipex-discloser.js +94 -31
- package/esm/keri/npm/src/app/ipex/ipex-grouping.js +53 -3
- package/esm/keri/npm/src/app/ipex/ipex-v2.js +7 -2
- package/esm/keri/npm/src/app/ipex/issuance.js +147 -44
- package/esm/keri/npm/src/app/ipex/pending-presentations.js +4 -2
- package/esm/keri/npm/src/app/ipex/presenting.js +3 -18
- package/esm/keri/npm/src/app/ipex/receive-issuance.js +2 -1
- package/esm/keri/npm/src/app/ipex/unblinding-workflow.js +39 -11
- package/esm/keri/npm/src/app/mailbox/agent-inbox.js +292 -0
- package/esm/keri/npm/src/app/mailbox/forward-handler.js +298 -52
- package/esm/keri/npm/src/app/mailbox/kel-publisher.js +26 -31
- package/esm/keri/npm/src/app/mailbox/mailbox-poller.js +70 -62
- package/esm/keri/npm/src/app/mailbox/mailboxing.js +20 -4
- package/esm/keri/npm/src/app/multisig/counseling.js +71 -27
- package/esm/keri/npm/src/app/multisig/group-members.js +41 -5
- package/esm/keri/npm/src/app/multisig/grouping.js +50 -2
- package/esm/keri/npm/src/app/multisig/multisig-workflows.js +3 -18
- package/esm/keri/npm/src/app/multisig/proposing.js +1 -16
- package/esm/keri/npm/src/app/multisig/rejoin-group.js +99 -0
- package/esm/keri/npm/src/app/multisig/replace-member.js +29 -8
- package/esm/keri/npm/src/app/protocol/parsering.js +45 -17
- package/esm/keri/npm/src/app/protocol/protocol-processing.js +47 -21
- package/esm/keri/npm/src/app/queries/query-replies.js +0 -22
- package/esm/keri/npm/src/app/queries/relay-refresh.js +81 -0
- package/esm/keri/npm/src/app/queries/witness-inquisitor.js +180 -34
- package/esm/keri/npm/src/app/runtime/agent-runtime.js +42 -73
- package/esm/keri/npm/src/app/runtime/cue-runtime.js +45 -5
- package/esm/keri/npm/src/app/runtime/ipex-auxiliaries.js +8 -1
- package/esm/keri/npm/src/app/runtime/operation-owners.js +26 -56
- package/esm/keri/npm/src/app/runtime/workflow-contract.js +7 -4
- package/esm/keri/npm/src/app/transport/http-client.js +20 -2
- package/esm/keri/npm/src/app/transport/message-source.js +2 -1
- package/esm/keri/npm/src/app/transport/messengering.js +39 -8
- package/esm/keri/npm/src/app/witness/ingress.js +7 -0
- package/esm/keri/npm/src/app/witness/receipt-client.js +43 -16
- package/esm/keri/npm/src/app/witness/receipting.js +62 -20
- package/esm/keri/npm/src/cli/messaging/multisig.js +4 -3
- package/esm/keri/npm/src/core/errors.js +73 -0
- package/esm/keri/npm/src/core/kel/delegation-ancestry.js +11 -2
- package/esm/keri/npm/src/core/kel/eventing.js +25 -28
- package/esm/keri/npm/src/core/kel/kever.js +15 -9
- package/esm/keri/npm/src/core/mailbox/kram-policy.js +16 -0
- package/esm/keri/npm/src/core/mailbox/kram-pruning.js +25 -6
- package/esm/keri/npm/src/core/mailbox/kram-time.js +34 -6
- package/esm/keri/npm/src/core/mailbox/kraming.js +58 -2
- package/esm/keri/npm/src/core/missing-anchor-query.js +20 -0
- package/esm/keri/npm/src/core/routing.js +18 -25
- package/esm/keri/npm/src/core/scheming.js +12 -5
- package/esm/keri/npm/src/core/wire-fields.js +126 -0
- package/esm/keri/npm/src/db/basing.js +4 -13
- package/esm/keri/npm/src/db/core/indexeddb-persistence.js +3 -2
- package/esm/keri/npm/src/db/core/webdber.js +85 -27
- package/esm/keri/npm/src/db/mailbox/mailboxing.js +13 -0
- package/esm/keri/npm/src/db/subing.js +4 -0
- package/esm/keri/npm/src/runtime/index.js +11 -5
- package/esm/keri/npm/src/time/mod.js +5 -0
- package/esm/keri/npm/src/vdr/credential-tsn-record.js +2 -7
- package/esm/keri/npm/src/vdr/eventing.js +71 -28
- package/esm/keri/npm/src/vdr/registry-tsn-record.js +3 -13
- package/esm/keri/npm/src/version.js +2 -2
- package/package.json +1 -1
- package/types/_dnt.polyfills.d.ts +9 -9
- package/types/_dnt.polyfills.d.ts.map +1 -1
- package/types/acdc/dhking.d.ts +8 -0
- package/types/acdc/dhking.d.ts.map +1 -1
- package/types/acdc/observing.d.ts +5 -1
- package/types/acdc/observing.d.ts.map +1 -1
- package/types/acdc/query-resend.d.ts +24 -0
- package/types/acdc/query-resend.d.ts.map +1 -0
- package/types/acdc/regengine.d.ts +19 -1
- package/types/acdc/regengine.d.ts.map +1 -1
- package/types/acdc/regeventing.d.ts.map +1 -1
- package/types/acdc/registering.d.ts +6 -0
- package/types/acdc/registering.d.ts.map +1 -1
- package/types/acdc/salting.d.ts.map +1 -1
- package/types/acdc/unblinding.d.ts +13 -1
- package/types/acdc/unblinding.d.ts.map +1 -1
- package/types/app/bootstrap/authenticating.d.ts +12 -2
- package/types/app/bootstrap/authenticating.d.ts.map +1 -1
- package/types/app/bootstrap/oobiery.d.ts +144 -7
- package/types/app/bootstrap/oobiery.d.ts.map +1 -1
- package/types/app/credentials/credential-importing.d.ts +8 -0
- package/types/app/credentials/credential-importing.d.ts.map +1 -1
- package/types/app/credentials/root-replicator.d.ts +19 -8
- package/types/app/credentials/root-replicator.d.ts.map +1 -1
- package/types/app/credentials/schema-resolving.d.ts.map +1 -1
- package/types/app/credentials/tel-publishing.d.ts +4 -2
- package/types/app/credentials/tel-publishing.d.ts.map +1 -1
- package/types/app/delivery/forwarding.d.ts +90 -5
- package/types/app/delivery/forwarding.d.ts.map +1 -1
- package/types/app/delivery/relaying.d.ts +144 -0
- package/types/app/delivery/relaying.d.ts.map +1 -0
- package/types/app/delivery/respondant.d.ts +9 -2
- package/types/app/delivery/respondant.d.ts.map +1 -1
- package/types/app/exchanges/exchanging.d.ts +36 -0
- package/types/app/exchanges/exchanging.d.ts.map +1 -1
- package/types/app/identity/delegating.d.ts +6 -0
- package/types/app/identity/delegating.d.ts.map +1 -1
- package/types/app/identity/habbing.d.ts +106 -19
- package/types/app/identity/habbing.d.ts.map +1 -1
- package/types/app/identity/keeping.d.ts +54 -19
- package/types/app/identity/keeping.d.ts.map +1 -1
- package/types/app/identity/retire-identifier.d.ts +24 -0
- package/types/app/identity/retire-identifier.d.ts.map +1 -0
- package/types/app/ipex/disclosure-replaying.d.ts +61 -0
- package/types/app/ipex/disclosure-replaying.d.ts.map +1 -0
- package/types/app/ipex/group-ipex.d.ts +60 -14
- package/types/app/ipex/group-ipex.d.ts.map +1 -1
- package/types/app/ipex/group-issuance.d.ts +54 -8
- package/types/app/ipex/group-issuance.d.ts.map +1 -1
- package/types/app/ipex/ipex-discloser.d.ts +39 -2
- package/types/app/ipex/ipex-discloser.d.ts.map +1 -1
- package/types/app/ipex/ipex-grouping.d.ts +23 -2
- package/types/app/ipex/ipex-grouping.d.ts.map +1 -1
- package/types/app/ipex/ipex-v2.d.ts +5 -2
- package/types/app/ipex/ipex-v2.d.ts.map +1 -1
- package/types/app/ipex/issuance.d.ts +46 -16
- package/types/app/ipex/issuance.d.ts.map +1 -1
- package/types/app/ipex/pending-presentations.d.ts +4 -2
- package/types/app/ipex/pending-presentations.d.ts.map +1 -1
- package/types/app/ipex/presenting.d.ts.map +1 -1
- package/types/app/ipex/receive-issuance.d.ts +2 -1
- package/types/app/ipex/receive-issuance.d.ts.map +1 -1
- package/types/app/ipex/unblinding-workflow.d.ts +13 -2
- package/types/app/ipex/unblinding-workflow.d.ts.map +1 -1
- package/types/app/mailbox/agent-inbox.d.ts +126 -0
- package/types/app/mailbox/agent-inbox.d.ts.map +1 -0
- package/types/app/mailbox/forward-handler.d.ts +114 -14
- package/types/app/mailbox/forward-handler.d.ts.map +1 -1
- package/types/app/mailbox/kel-publisher.d.ts +12 -22
- package/types/app/mailbox/kel-publisher.d.ts.map +1 -1
- package/types/app/mailbox/mailbox-poller.d.ts +40 -24
- package/types/app/mailbox/mailbox-poller.d.ts.map +1 -1
- package/types/app/mailbox/mailboxing.d.ts +19 -5
- package/types/app/mailbox/mailboxing.d.ts.map +1 -1
- package/types/app/multisig/counseling.d.ts +32 -11
- package/types/app/multisig/counseling.d.ts.map +1 -1
- package/types/app/multisig/group-members.d.ts +17 -1
- package/types/app/multisig/group-members.d.ts.map +1 -1
- package/types/app/multisig/grouping.d.ts +17 -1
- package/types/app/multisig/grouping.d.ts.map +1 -1
- package/types/app/multisig/multisig-workflows.d.ts +0 -8
- package/types/app/multisig/multisig-workflows.d.ts.map +1 -1
- package/types/app/multisig/proposing.d.ts +4 -19
- package/types/app/multisig/proposing.d.ts.map +1 -1
- package/types/app/multisig/rejoin-group.d.ts +119 -0
- package/types/app/multisig/rejoin-group.d.ts.map +1 -0
- package/types/app/multisig/replace-member.d.ts +15 -1
- package/types/app/multisig/replace-member.d.ts.map +1 -1
- package/types/app/protocol/parsering.d.ts +21 -2
- package/types/app/protocol/parsering.d.ts.map +1 -1
- package/types/app/protocol/protocol-processing.d.ts +25 -5
- package/types/app/protocol/protocol-processing.d.ts.map +1 -1
- package/types/app/queries/query-replies.d.ts +4 -8
- package/types/app/queries/query-replies.d.ts.map +1 -1
- package/types/app/queries/relay-refresh.d.ts +26 -0
- package/types/app/queries/relay-refresh.d.ts.map +1 -0
- package/types/app/queries/witness-inquisitor.d.ts +56 -5
- package/types/app/queries/witness-inquisitor.d.ts.map +1 -1
- package/types/app/runtime/agent-runtime.d.ts +34 -3
- package/types/app/runtime/agent-runtime.d.ts.map +1 -1
- package/types/app/runtime/cue-runtime.d.ts +15 -3
- package/types/app/runtime/cue-runtime.d.ts.map +1 -1
- package/types/app/runtime/ipex-auxiliaries.d.ts.map +1 -1
- package/types/app/runtime/operation-owners.d.ts +16 -26
- package/types/app/runtime/operation-owners.d.ts.map +1 -1
- package/types/app/runtime/workflow-contract.d.ts +21 -6
- package/types/app/runtime/workflow-contract.d.ts.map +1 -1
- package/types/app/transport/http-client.d.ts +9 -0
- package/types/app/transport/http-client.d.ts.map +1 -1
- package/types/app/transport/message-source.d.ts +6 -3
- package/types/app/transport/message-source.d.ts.map +1 -1
- package/types/app/transport/messengering.d.ts +10 -1
- package/types/app/transport/messengering.d.ts.map +1 -1
- package/types/app/witness/ingress.d.ts +1 -0
- package/types/app/witness/ingress.d.ts.map +1 -1
- package/types/app/witness/receipt-client.d.ts +19 -1
- package/types/app/witness/receipt-client.d.ts.map +1 -1
- package/types/app/witness/receipting.d.ts +24 -1
- package/types/app/witness/receipting.d.ts.map +1 -1
- package/types/cli/messaging/multisig.d.ts.map +1 -1
- package/types/core/cues.d.ts +53 -1
- package/types/core/cues.d.ts.map +1 -1
- package/types/core/errors.d.ts +32 -0
- package/types/core/errors.d.ts.map +1 -1
- package/types/core/kel/delegation-ancestry.d.ts.map +1 -1
- package/types/core/kel/eventing.d.ts.map +1 -1
- package/types/core/kel/kever-decisions.d.ts +3 -1
- package/types/core/kel/kever-decisions.d.ts.map +1 -1
- package/types/core/kel/kever.d.ts +7 -1
- package/types/core/kel/kever.d.ts.map +1 -1
- package/types/core/mailbox/kram-policy.d.ts +12 -0
- package/types/core/mailbox/kram-policy.d.ts.map +1 -1
- package/types/core/mailbox/kram-pruning.d.ts +5 -1
- package/types/core/mailbox/kram-pruning.d.ts.map +1 -1
- package/types/core/mailbox/kram-time.d.ts +26 -2
- package/types/core/mailbox/kram-time.d.ts.map +1 -1
- package/types/core/mailbox/kraming.d.ts +14 -1
- package/types/core/mailbox/kraming.d.ts.map +1 -1
- package/types/core/missing-anchor-query.d.ts +34 -0
- package/types/core/missing-anchor-query.d.ts.map +1 -0
- package/types/core/routing.d.ts +3 -7
- package/types/core/routing.d.ts.map +1 -1
- package/types/core/scheming.d.ts.map +1 -1
- package/types/core/wire-fields.d.ts +56 -0
- package/types/core/wire-fields.d.ts.map +1 -0
- package/types/db/basing.d.ts.map +1 -1
- package/types/db/core/indexeddb-persistence.d.ts +3 -2
- package/types/db/core/indexeddb-persistence.d.ts.map +1 -1
- package/types/db/core/webdber.d.ts +32 -6
- package/types/db/core/webdber.d.ts.map +1 -1
- package/types/db/exchange/exchange-records.d.ts +4 -0
- package/types/db/exchange/exchange-records.d.ts.map +1 -1
- package/types/db/mailbox/mailboxing.d.ts +10 -1
- package/types/db/mailbox/mailboxing.d.ts.map +1 -1
- package/types/db/subing.d.ts +2 -0
- package/types/db/subing.d.ts.map +1 -1
- package/types/runtime/index.d.ts +20 -14
- package/types/runtime/index.d.ts.map +1 -1
- package/types/time/mod.d.ts +2 -0
- package/types/time/mod.d.ts.map +1 -1
- package/types/vdr/credential-tsn-record.d.ts.map +1 -1
- package/types/vdr/eventing.d.ts +32 -1
- package/types/vdr/eventing.d.ts.map +1 -1
- package/types/vdr/registry-tsn-record.d.ts.map +1 -1
- package/types/version.d.ts +2 -2
- package/esm/keri/npm/src/app/runtime/signer-conditions.js +0 -51
- package/types/app/runtime/signer-conditions.d.ts +0 -32
- package/types/app/runtime/signer-conditions.d.ts.map +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Roles } from "../../core/roles.js";
|
|
1
2
|
import { doEvery, PROTOCOL_PACING } from "./doing.js";
|
|
2
3
|
/**
|
|
3
4
|
* Use an explicitly selected or sole local habitat; never guess among hosted identities.
|
|
@@ -13,11 +14,28 @@ function resolveCueHab(runtime, hab) {
|
|
|
13
14
|
const first = habitats.next();
|
|
14
15
|
return first.done || !habitats.next().done ? null : first.value;
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Hand an accepted mailbox end role to the KEL publisher and the mailbox poller, so both look at its controller on
|
|
19
|
+
* their next tock rather than at their next sweep. Other roles concern neither.
|
|
20
|
+
*
|
|
21
|
+
* @param runtime Borrowed composed runtime containing the publisher and poller.
|
|
22
|
+
* @param cue The committed end-role fact from `Revery`.
|
|
23
|
+
*/
|
|
24
|
+
export function promptForEndRole(runtime, cue) {
|
|
25
|
+
if (cue.role !== Roles.mailbox)
|
|
26
|
+
return;
|
|
27
|
+
runtime.kelPublisher.prompt(cue.cid);
|
|
28
|
+
runtime.mailboxPoller.prompt(cue.cid);
|
|
29
|
+
}
|
|
16
30
|
/**
|
|
17
31
|
* Route one initial cue batch to its concrete owners before removing source records.
|
|
18
32
|
*
|
|
19
|
-
* Transfer query instructions to the sender
|
|
20
|
-
*
|
|
33
|
+
* Transfer query instructions to the sender (a relaying runtime skips one identical to a request already queued),
|
|
34
|
+
* stream cues to mailbox correlation,
|
|
35
|
+
* accepted mailbox end roles to the KEL publisher and poller, and produced responder
|
|
36
|
+
* messages to Poster. No network delivery runs inline.
|
|
37
|
+
* A responder cue whose signing habitat cannot sign yet moves to the tail and is
|
|
38
|
+
* tried again on a later pass; the cues behind it still go now.
|
|
21
39
|
* Saved key-state facts transfer once to the command's optional query Deck;
|
|
22
40
|
* its noticer never competes with this worker over the runtime source Deck.
|
|
23
41
|
* Admission and source removal run synchronously within this finite batch.
|
|
@@ -33,14 +51,36 @@ export function* processCuesOnce(runtime, { hab, queryCues } = {}) {
|
|
|
33
51
|
const cue = runtime.cues.peekHead();
|
|
34
52
|
if (!cue)
|
|
35
53
|
break;
|
|
54
|
+
if (cue.kin === "kramRefused") {
|
|
55
|
+
// Pulled first: a faulty sink must not wedge the head of the Deck.
|
|
56
|
+
runtime.cues.pull();
|
|
57
|
+
runtime.changes?.push({ kind: "kramRefused", id: cue.said, refusal: cue });
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (cue.kin === "endRoleSaved") {
|
|
61
|
+
runtime.cues.pull();
|
|
62
|
+
promptForEndRole(runtime, cue);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
36
65
|
if (cue.kin === "query") {
|
|
37
|
-
|
|
66
|
+
// A relaying host serves many edges asking about the same subjects; one queued request per query suffices.
|
|
67
|
+
if (runtime.relaying)
|
|
68
|
+
runtime.querying.enqueueCueOnce(cue, interpreter);
|
|
69
|
+
else
|
|
70
|
+
runtime.querying.enqueueCue(cue, interpreter);
|
|
38
71
|
}
|
|
39
72
|
else if (cue.kin === "stream") {
|
|
40
73
|
runtime.mailboxDirector.retainQueryCue(cue);
|
|
41
74
|
}
|
|
42
|
-
else if (interpreter
|
|
43
|
-
|
|
75
|
+
else if (interpreter) {
|
|
76
|
+
const outcome = runtime.respondant.enqueueCue(interpreter, runtime.cues, hab);
|
|
77
|
+
if (outcome === "taken")
|
|
78
|
+
continue;
|
|
79
|
+
if (outcome === "unsignable") {
|
|
80
|
+
// Kept for a later pass, behind the cues that can go now; `count` bounds this pass.
|
|
81
|
+
runtime.cues.append(runtime.cues.pull());
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
44
84
|
}
|
|
45
85
|
runtime.cues.pull();
|
|
46
86
|
if (cue.kin === "keyStateSaved")
|
|
@@ -122,7 +122,14 @@ export class IpexAuxiliaries {
|
|
|
122
122
|
const current = this.unblinds.get(hab.pre);
|
|
123
123
|
if (current?.hab === hab)
|
|
124
124
|
return current;
|
|
125
|
-
const owner = new Unblind({
|
|
125
|
+
const owner = new Unblind({
|
|
126
|
+
hab,
|
|
127
|
+
exc: this.exc,
|
|
128
|
+
registry: this.registry,
|
|
129
|
+
rvy: this.rvy,
|
|
130
|
+
now: this.now,
|
|
131
|
+
kram: this.kram,
|
|
132
|
+
});
|
|
126
133
|
current?.close();
|
|
127
134
|
this.unblinds.set(hab.pre, owner);
|
|
128
135
|
return owner;
|
|
@@ -14,28 +14,6 @@ export const OWNER_PACING = Object.freeze({
|
|
|
14
14
|
tockMs: OWNER_TOCK_MS,
|
|
15
15
|
sweepTocks: OWNER_SWEEP_TOCKS,
|
|
16
16
|
});
|
|
17
|
-
/**
|
|
18
|
-
* Failures of the owner loop itself. A failure of one operation (a delivery that throws, an unreadable stored
|
|
19
|
-
* Grant) ends that operation as `failed` and is never recorded here; this records only what escaped an owner
|
|
20
|
-
* pass, which the loop survives so that the other owners keep running. `faults` counts them and `last` keeps
|
|
21
|
-
* the latest. Nothing clears it: a host reads it and decides.
|
|
22
|
-
*/
|
|
23
|
-
export class OwnerHealth {
|
|
24
|
-
constructor() {
|
|
25
|
-
Object.defineProperty(this, "faults", {
|
|
26
|
-
enumerable: true,
|
|
27
|
-
configurable: true,
|
|
28
|
-
writable: true,
|
|
29
|
-
value: 0
|
|
30
|
-
});
|
|
31
|
-
Object.defineProperty(this, "last", {
|
|
32
|
-
enumerable: true,
|
|
33
|
-
configurable: true,
|
|
34
|
-
writable: true,
|
|
35
|
-
value: null
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
17
|
/** Construct the owners over their in-memory tables; the derivation store defaults to the registry database. */
|
|
40
18
|
export function composeOwners(parts, stores = {}) {
|
|
41
19
|
const { hby, acdc, exc, protocol, reactor, postman, receiptor, ipex, clock, registryRoot, mux, counselor } = parts;
|
|
@@ -82,7 +60,6 @@ export function composeOwners(parts, stores = {}) {
|
|
|
82
60
|
retry: parts.retry,
|
|
83
61
|
changes,
|
|
84
62
|
}),
|
|
85
|
-
health: new OwnerHealth(),
|
|
86
63
|
unblinding: new UnblindingOperations({
|
|
87
64
|
hby,
|
|
88
65
|
exc,
|
|
@@ -95,7 +72,9 @@ export function composeOwners(parts, stores = {}) {
|
|
|
95
72
|
changes,
|
|
96
73
|
}),
|
|
97
74
|
};
|
|
98
|
-
const rootReplicator = registryRoot
|
|
75
|
+
const rootReplicator = registryRoot
|
|
76
|
+
? new RootReplicator({ root: registryRoot, postman, clock, changes, changed: parts.groupChanges })
|
|
77
|
+
: null;
|
|
99
78
|
return { operations, rootReplicator };
|
|
100
79
|
}
|
|
101
80
|
/**
|
|
@@ -106,47 +85,38 @@ export function composeOwners(parts, stores = {}) {
|
|
|
106
85
|
* Idle cost, per tock: four constant-time table checks, one in-memory walk of the Unblind owners for an owed
|
|
107
86
|
* reply, one drain of each DH owner's cue deck, and the replicator's emptiness checks. The replicator's
|
|
108
87
|
* rotation check (the establishment SAID of each local group, one keyed read per local identifier) runs on
|
|
109
|
-
* tock 0 and every `pacing.sweepTocks`. No owner reads a protocol store
|
|
110
|
-
* pending exchange escrow for resumable Grants
|
|
88
|
+
* tock 0 and every `pacing.sweepTocks`. No owner reads a protocol store on an ordinary tock. The issuance owner
|
|
89
|
+
* scans the pending exchange escrow on its first pass and then every `ISSUANCE_SWEEP_MS`, for resumable Grants and
|
|
90
|
+
* for group Grants whose custodian's final proof a member follows without signing; nothing else walks it per tock.
|
|
111
91
|
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
92
|
+
* Nothing is caught here. Every remote, network or validation outcome an owner meets is already a typed result
|
|
93
|
+
* below this loop: a failed delivery is retried by its operation, and an operation that cannot go on ends `failed`
|
|
94
|
+
* or `expired` alone. What escapes a pass is a real fault (a store that cannot be read or written, corrupt or
|
|
95
|
+
* missing durable state such as a `MissingDurableStateError`, a `SignerNotHeldError` past a `canSign`
|
|
96
|
+
* gate), and it ends the loop and with it `runAgentRuntime`. Halting the loop is not a fault: Effection halts a
|
|
97
|
+
* pass by returning from it, so no error is thrown. The owners run one after another, so a delivery that does not
|
|
98
|
+
* return holds the others up until it fails or its Grant deadline passes; operations already bound each delivery by
|
|
99
|
+
* that deadline.
|
|
115
100
|
*/
|
|
116
101
|
export function* operationOwnersDo(owners, pacing = OWNER_PACING) {
|
|
117
|
-
const { operations, rootReplicator, ipex, clock } = owners
|
|
118
|
-
const guarded = function* (owner, pass) {
|
|
119
|
-
try {
|
|
120
|
-
yield* pass();
|
|
121
|
-
}
|
|
122
|
-
catch (error) {
|
|
123
|
-
health.faults++;
|
|
124
|
-
health.last = {
|
|
125
|
-
owner,
|
|
126
|
-
error: error instanceof Error ? error.message : String(error),
|
|
127
|
-
at: new Date(clock.now()).toISOString(),
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
};
|
|
102
|
+
const { operations, rootReplicator, ipex, clock } = owners;
|
|
131
103
|
return yield* doEvery(clock, pacing.tockMs, function* (tock) {
|
|
132
104
|
if (operations.issuance.active())
|
|
133
|
-
yield*
|
|
105
|
+
yield* operations.issuance.processOnce();
|
|
134
106
|
if (operations.groupIpex.active())
|
|
135
|
-
yield*
|
|
107
|
+
yield* operations.groupIpex.processOnce();
|
|
136
108
|
if (operations.presentation.active())
|
|
137
|
-
yield*
|
|
109
|
+
yield* operations.presentation.processOnce();
|
|
138
110
|
if (operations.unblinding.active())
|
|
139
|
-
yield*
|
|
111
|
+
yield* operations.unblinding.processOnce();
|
|
140
112
|
if (rootReplicator) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
yield* rootReplicator.processDue();
|
|
149
|
-
});
|
|
113
|
+
for (const dh of ipex.dhkeOwners()) {
|
|
114
|
+
while (dh.replicated.length)
|
|
115
|
+
rootReplicator.replicate(dh.replicated.pull());
|
|
116
|
+
}
|
|
117
|
+
if (tock % pacing.sweepTocks === 0)
|
|
118
|
+
rootReplicator.sweep();
|
|
119
|
+
yield* rootReplicator.processDue();
|
|
150
120
|
}
|
|
151
121
|
});
|
|
152
122
|
}
|
|
@@ -24,22 +24,25 @@ export class MemoryChangeSink {
|
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
26
|
push(change) {
|
|
27
|
-
this.changes.push({ kind: change.kind, id: change.id });
|
|
27
|
+
this.changes.push(change.kind === "kramRefused" ? change : { kind: change.kind, id: change.id });
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* Back a sink with the host's transient `Signaler`. Publishing needs no polling:
|
|
32
32
|
* `push` is a synchronous append that collapses repeats of one workflow into a
|
|
33
|
-
* single signal (collapse key `kind:id`).
|
|
33
|
+
* single signal (collapse key `kind:id`). A {@link KramRefusedChange} adds its refusal fields to the signal
|
|
34
|
+
* attributes, so a resent message collapses by SAID. Delivery is pull-based, though: the
|
|
34
35
|
* Signaler has no subscriber hook, so the consumer must read `signaler.list()`.
|
|
35
36
|
* A closed or failing Signaler drops the change instead of throwing: a hint must
|
|
36
37
|
* never break the workflow that published it.
|
|
37
38
|
*/
|
|
38
39
|
export function signalerChangeSink(signaler) {
|
|
39
40
|
return {
|
|
40
|
-
push: (
|
|
41
|
+
push: (change) => {
|
|
42
|
+
const { kind, id } = change;
|
|
41
43
|
try {
|
|
42
|
-
|
|
44
|
+
const attrs = change.kind === "kramRefused" ? { id, ...change.refusal } : { id };
|
|
45
|
+
signaler.push(attrs, `/workflow/${kind}`, { ckey: `${kind}:${id}` });
|
|
43
46
|
}
|
|
44
47
|
catch {
|
|
45
48
|
// Dropped on purpose; consumers re-read status and tolerate a missed hint.
|
|
@@ -4,6 +4,25 @@ import { ValidationError } from "../../core/errors.js";
|
|
|
4
4
|
import { abortable } from "../runtime/abortable.js";
|
|
5
5
|
import { collectBytes } from "./byte-source.js";
|
|
6
6
|
import { TransportError } from "./transport-error.js";
|
|
7
|
+
/**
|
|
8
|
+
* Whether {@link FetchHttpClient.open} can request `url` at all: an absolute HTTP(S) URL without embedded
|
|
9
|
+
* credentials. Anything else is refused by construction, before any I/O, so a caller holding a URL from a remote
|
|
10
|
+
* party can refuse it at intake instead of queuing work that can never succeed.
|
|
11
|
+
*
|
|
12
|
+
* @param url Candidate request URL.
|
|
13
|
+
* @returns False for an unparseable URL, a non-HTTP(S) scheme, or a URL carrying a user name or password.
|
|
14
|
+
*/
|
|
15
|
+
export function isRequestableHttpUrl(url) {
|
|
16
|
+
let endpoint;
|
|
17
|
+
try {
|
|
18
|
+
endpoint = new URL(url);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return (endpoint.protocol === "http:" || endpoint.protocol === "https:") && !endpoint.username
|
|
24
|
+
&& !endpoint.password;
|
|
25
|
+
}
|
|
7
26
|
/**
|
|
8
27
|
* Native requests and signals that a pending `fetch` still needs. WebKit links an in-flight fetch to
|
|
9
28
|
* its abort signal only weakly: once the `Request`, or an `AbortSignal.any` composite, is garbage
|
|
@@ -78,8 +97,7 @@ export class FetchHttpClient {
|
|
|
78
97
|
: new TransportError(`${message} for ${url}`, { cause });
|
|
79
98
|
try {
|
|
80
99
|
signal.throwIfAborted();
|
|
81
|
-
|
|
82
|
-
if (!["http:", "https:"].includes(endpoint.protocol) || endpoint.username || endpoint.password) {
|
|
100
|
+
if (!isRequestableHttpUrl(url)) {
|
|
83
101
|
throw new ValidationError("HTTP output requires an HTTP(S) URL without credentials");
|
|
84
102
|
}
|
|
85
103
|
// Construction errors are caller errors, before native network classification.
|
|
@@ -53,7 +53,8 @@ export function* processMessages(source, protocol, kvy, options = {}) {
|
|
|
53
53
|
signal.throwIfAborted();
|
|
54
54
|
if (result.done)
|
|
55
55
|
return;
|
|
56
|
-
|
|
56
|
+
// Only the intake choices: nothing a caller adds to its options can mark live input as retained history.
|
|
57
|
+
yield* protocol.dispatch(result.value, { local: options.local, mailboxAid: options.mailboxAid, escrows: options.escrows }, kvy);
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
finally {
|
|
@@ -7,25 +7,56 @@
|
|
|
7
7
|
* do not select a stored framing preference or acquire workers, stores or queues.
|
|
8
8
|
*/
|
|
9
9
|
import { ValidationError } from "../../core/errors.js";
|
|
10
|
+
import { readUrl } from "../../core/wire-fields.js";
|
|
11
|
+
import { isRequestableHttpUrl } from "./http-client.js";
|
|
10
12
|
import { HTTPMessenger } from "./http-messenger.js";
|
|
11
13
|
import { HTTPStreamMessenger } from "./http-stream-messenger.js";
|
|
12
14
|
import { requireTcpDialer } from "./tcp-dialer.js";
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Choose HTTPS, HTTP, then TCP, refusing before I/O what no messenger can use: an unparseable URL, a scheme other than
|
|
17
|
+
* the advertised one, an HTTP(S) URL the HTTP client refuses ({@link isRequestableHttpUrl}: embedded credentials), or
|
|
18
|
+
* a TCP URL without a valid port. A refused higher-priority URL does not fall through to another transport.
|
|
19
|
+
*
|
|
20
|
+
* @param urls Resolved endpoints, keyed by their advertised scheme.
|
|
21
|
+
* @returns The selection, never a throw.
|
|
22
|
+
*/
|
|
23
|
+
function selectEndpoint(urls) {
|
|
15
24
|
for (const scheme of ["https", "http", "tcp"]) {
|
|
16
25
|
const value = urls[scheme];
|
|
17
26
|
if (value === undefined)
|
|
18
27
|
continue;
|
|
19
|
-
const endpoint =
|
|
20
|
-
if (endpoint
|
|
21
|
-
|
|
28
|
+
const endpoint = readUrl(value);
|
|
29
|
+
if (!endpoint)
|
|
30
|
+
return { kind: "refused", reason: `Invalid ${scheme} messenger endpoint: ${value}` };
|
|
31
|
+
const usable = scheme === "tcp" ? !endpoint.username && !endpoint.password : isRequestableHttpUrl(value);
|
|
32
|
+
if (endpoint.protocol !== `${scheme}:` || !usable) {
|
|
33
|
+
return { kind: "refused", reason: `Invalid ${scheme} messenger endpoint: ${value}` };
|
|
22
34
|
}
|
|
23
35
|
if (scheme === "tcp" && (!endpoint.port || Number(endpoint.port) < 1 || Number(endpoint.port) > 65535)) {
|
|
24
|
-
|
|
36
|
+
return { kind: "refused", reason: `TCP messenger endpoint requires a valid port: ${value}` };
|
|
25
37
|
}
|
|
26
|
-
return endpoint;
|
|
38
|
+
return { kind: "usable", value, endpoint };
|
|
27
39
|
}
|
|
28
|
-
|
|
40
|
+
return { kind: "refused", reason: "No supported messenger endpoint is available." };
|
|
41
|
+
}
|
|
42
|
+
/** Select the factories' endpoint, refusing an unusable one as a caller error. */
|
|
43
|
+
function endpointFrom(urls) {
|
|
44
|
+
const selection = selectEndpoint(urls);
|
|
45
|
+
if (selection.kind === "refused")
|
|
46
|
+
throw new ValidationError(selection.reason);
|
|
47
|
+
return selection.endpoint;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The URL the messenger factories would use for these endpoints, or null when they would refuse it. A caller holding
|
|
51
|
+
* a location another party advertised reads a refused one as no location, so it fails one delivery as unroutable
|
|
52
|
+
* instead of throwing out of the factory.
|
|
53
|
+
*
|
|
54
|
+
* @param urls Resolved endpoints, keyed by their advertised scheme.
|
|
55
|
+
* @returns The selected URL exactly as advertised, or null.
|
|
56
|
+
*/
|
|
57
|
+
export function messengerUrl(urls) {
|
|
58
|
+
const selection = selectEndpoint(urls);
|
|
59
|
+
return selection.kind === "usable" ? selection.value : null;
|
|
29
60
|
}
|
|
30
61
|
/**
|
|
31
62
|
* Bind ordinary signed-message delivery to the first present HTTPS/HTTP/TCP URL.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { parse } from "cesr-ts";
|
|
3
3
|
import { call, ensure } from "effection";
|
|
4
4
|
import { rethrowCleanupFailure } from "../runtime/abortable.js";
|
|
5
|
+
import { promptForEndRole } from "../runtime/cue-runtime.js";
|
|
5
6
|
import { chunkBytes } from "../transport/byte-source.js";
|
|
6
7
|
/** Return the active wire-message habitat or `null` when selection is ambiguous. */
|
|
7
8
|
function cueHab(runtime, serviceHab) {
|
|
@@ -15,6 +16,7 @@ function cueHab(runtime, serviceHab) {
|
|
|
15
16
|
/**
|
|
16
17
|
* Route one initial witness cue batch, leaving saved key-state facts for the
|
|
17
18
|
* application cue worker and its optional command-owned noticer destination.
|
|
19
|
+
* An accepted mailbox end role prompts the KEL publisher and poller as the cue worker does.
|
|
18
20
|
* Respondant publishes Poster work; this ingress helper never drains Poster
|
|
19
21
|
* network delivery. Query network I/O stays with the independent sender.
|
|
20
22
|
*
|
|
@@ -39,6 +41,11 @@ export function* drainWitnessCues(runtime, serviceHab, cues, { deliver = true }
|
|
|
39
41
|
cues.append(cue);
|
|
40
42
|
continue;
|
|
41
43
|
}
|
|
44
|
+
if (cue.kin === "endRoleSaved") {
|
|
45
|
+
cues.pull();
|
|
46
|
+
promptForEndRole(runtime, cue);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
42
49
|
if (deliver) {
|
|
43
50
|
if (cue.kin === "query") {
|
|
44
51
|
runtime.querying.enqueueCue(cue, hab);
|
|
@@ -8,6 +8,7 @@ import { collectBytes } from "../transport/byte-source.js";
|
|
|
8
8
|
import { buildCesrRequest, CESR_CONTENT_TYPE, KERIPY_CESR_JSON_CONTENT_TYPE } from "../transport/cesr-http.js";
|
|
9
9
|
import { HTTPMessenger } from "../transport/http-messenger.js";
|
|
10
10
|
import { requireTcpDialer } from "../transport/tcp-dialer.js";
|
|
11
|
+
import { TransportError } from "../transport/transport-error.js";
|
|
11
12
|
import { inspectReceiptMessage } from "./receipt-messages.js";
|
|
12
13
|
const WitnessReceiptPollAttempts = 20;
|
|
13
14
|
const WitnessReceiptPollDelayMs = 100;
|
|
@@ -51,6 +52,8 @@ function preferredWitnessTransportUrl(hab, witness) {
|
|
|
51
52
|
return witnessHttpUrl(hab, witness) ?? witnessTcpUrl(hab, witness);
|
|
52
53
|
}
|
|
53
54
|
/**
|
|
55
|
+
* Deliver one message to a witness, reporting remote failure as data.
|
|
56
|
+
*
|
|
54
57
|
* Send via HTTP first; an explicit protocol processor processes same-socket TCP replies.
|
|
55
58
|
* Without a protocol processor TCP reports local transmission only. Actual socket/parser
|
|
56
59
|
* cleanup finishes before this borrowed protocol processor can be released.
|
|
@@ -62,27 +65,51 @@ function preferredWitnessTransportUrl(hab, witness) {
|
|
|
62
65
|
* @param clock Borrowed clock with epoch-millisecond now and millisecond timer delays.
|
|
63
66
|
* @param protocol Optional same-socket reply processor; null selects transmit-only TCP.
|
|
64
67
|
* @param auth Optional HTTP Authorization header value.
|
|
65
|
-
* @
|
|
68
|
+
* @returns `unreachable` when the witness advertises no endpoint, refuses over HTTP, or the connection fails
|
|
69
|
+
* (`TransportError`); the caller decides whether to retry later. Parser, storage, programmer and cleanup
|
|
70
|
+
* failures still throw.
|
|
66
71
|
*/
|
|
67
|
-
export function*
|
|
72
|
+
export function* deliverWitnessMessage(hab, witness, bytes, http, clock, protocol, auth) {
|
|
68
73
|
const url = preferredWitnessTransportUrl(hab, witness);
|
|
69
74
|
if (!url) {
|
|
70
|
-
|
|
75
|
+
return {
|
|
76
|
+
kind: "unreachable",
|
|
77
|
+
witness,
|
|
78
|
+
error: new ValidationError(`Unable to find a valid endpoint for witness ${witness}.`),
|
|
79
|
+
};
|
|
71
80
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
try {
|
|
82
|
+
const parsed = new URL(url);
|
|
83
|
+
if (parsed.protocol === "tcp:") {
|
|
84
|
+
yield* requireTcpDialer(http).messenger(url, clock, protocol).send(bytes, {
|
|
85
|
+
replies: Boolean(protocol),
|
|
86
|
+
local: true,
|
|
87
|
+
});
|
|
88
|
+
return { kind: "delivered" };
|
|
89
|
+
}
|
|
90
|
+
const outcome = yield* new HTTPMessenger(url, http, {
|
|
91
|
+
destination: witness,
|
|
92
|
+
headers: auth ? { Authorization: auth } : undefined,
|
|
93
|
+
}).send(bytes);
|
|
94
|
+
if (outcome.kind === "refuse")
|
|
95
|
+
return { kind: "unreachable", witness, error: outcome.error };
|
|
96
|
+
return { kind: "delivered" };
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (!(error instanceof TransportError))
|
|
100
|
+
throw error;
|
|
101
|
+
return { kind: "unreachable", witness, error };
|
|
79
102
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Send one message to a witness for callers that require delivery.
|
|
106
|
+
*
|
|
107
|
+
* @throws The delivery's remote failure (missing endpoint, peer refusal, transport) and any local failure.
|
|
108
|
+
*/
|
|
109
|
+
export function* sendWitnessMessage(hab, witness, bytes, http, clock, protocol, auth) {
|
|
110
|
+
const delivery = yield* deliverWitnessMessage(hab, witness, bytes, http, clock, protocol, auth);
|
|
111
|
+
if (delivery.kind === "unreachable")
|
|
112
|
+
throw delivery.error;
|
|
86
113
|
}
|
|
87
114
|
function isKeripyContentTypeRejection(status, contentType, responseText) {
|
|
88
115
|
return status === 406
|
|
@@ -8,8 +8,12 @@ import { dgKey } from "../../db/core/keys.js";
|
|
|
8
8
|
import { acceptedEventReplayMessage } from "../identity/habbing.js";
|
|
9
9
|
import { chunkBytes } from "../transport/byte-source.js";
|
|
10
10
|
import { processMessages } from "../transport/message-source.js";
|
|
11
|
-
import {
|
|
11
|
+
import { TransportError } from "../transport/transport-error.js";
|
|
12
|
+
import { deliverWitnessMessage, getWitnessReceiptEndpoint, pollWitnessReceipt, postWitnessReceiptEndpoint, witnessHttpUrl, witnessTcpUrl, } from "./receipt-client.js";
|
|
12
13
|
import { buildDetachedReceiptMessage } from "./receipt-messages.js";
|
|
14
|
+
function incomplete(witness, error) {
|
|
15
|
+
return { kind: "incomplete", witness, error };
|
|
16
|
+
}
|
|
13
17
|
/** Build one `loc/scheme` replay bundle for witness introductions. */
|
|
14
18
|
function* witnessSchemeReplies(hab, eids, gvrsn) {
|
|
15
19
|
const replies = eids
|
|
@@ -94,7 +98,17 @@ export class Receiptor {
|
|
|
94
98
|
this.gvrsn = gvrsn;
|
|
95
99
|
}
|
|
96
100
|
/** Submit the latest or specified event to all witnesses and gather receipts. */
|
|
97
|
-
*receipt(pre,
|
|
101
|
+
*receipt(pre, options = {}) {
|
|
102
|
+
const outcome = yield* this.attempt(pre, options);
|
|
103
|
+
if (outcome.kind === "incomplete")
|
|
104
|
+
throw outcome.error;
|
|
105
|
+
return outcome.result;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Submit like `receipt`, but report a witness that is unreachable, refuses, or does not receipt as
|
|
109
|
+
* `incomplete` data. Local faults (unknown local AID, missing key state, storage) still throw.
|
|
110
|
+
*/
|
|
111
|
+
*attempt(pre, { sn, auths = {}, allowTcp = false } = {}) {
|
|
98
112
|
return yield* call(() => this.receiptOnce(pre, { sn, auths }, allowTcp));
|
|
99
113
|
}
|
|
100
114
|
/**
|
|
@@ -118,11 +132,13 @@ export class Receiptor {
|
|
|
118
132
|
const { serder, message } = acceptedEventReplayMessage(this.hby, pre, eventSn, this.gvrsn);
|
|
119
133
|
const witnesses = this.hby.db.acceptedEventWitnesses(serder);
|
|
120
134
|
if (witnesses.length === 0) {
|
|
121
|
-
return { witnesses: [], statuses: {} };
|
|
135
|
+
return { kind: "receipted", result: { witnesses: [], statuses: {} } };
|
|
122
136
|
}
|
|
123
137
|
if (serder.ilk === Ilks.rot || serder.ilk === Ilks.drt) {
|
|
124
138
|
for (const witness of serder.adds) {
|
|
125
|
-
yield* this.
|
|
139
|
+
const caughtUp = yield* this.replayHistory(hab, witness);
|
|
140
|
+
if (caughtUp.kind === "unreachable")
|
|
141
|
+
return incomplete(witness, caughtUp.error);
|
|
126
142
|
}
|
|
127
143
|
}
|
|
128
144
|
const receiptGroups = new Map();
|
|
@@ -134,23 +150,35 @@ export class Receiptor {
|
|
|
134
150
|
for (const witness of witnesses) {
|
|
135
151
|
if (kever.delegated) {
|
|
136
152
|
for (const dmsg of this.hby.db.cloneDelegation(kever, this.gvrsn)) {
|
|
137
|
-
yield*
|
|
153
|
+
const delivery = yield* deliverWitnessMessage(hab, witness, this.selected(dmsg), this.http, this.clock, this.protocol);
|
|
154
|
+
if (delivery.kind === "unreachable")
|
|
155
|
+
return incomplete(witness, delivery.error);
|
|
138
156
|
}
|
|
139
157
|
}
|
|
140
158
|
if (allowTcp && !witnessHttpUrl(hab, witness) && witnessTcpUrl(hab, witness)) {
|
|
141
|
-
yield*
|
|
159
|
+
const delivery = yield* deliverWitnessMessage(hab, witness, this.selected(message), this.http, this.clock, this.protocol);
|
|
160
|
+
if (delivery.kind === "unreachable")
|
|
161
|
+
return incomplete(witness, delivery.error);
|
|
142
162
|
statuses[witness] = 200;
|
|
143
163
|
}
|
|
144
164
|
else {
|
|
145
165
|
// A single receipt attempt owns its response until parsing and collection finish.
|
|
146
|
-
let response
|
|
147
|
-
|
|
148
|
-
response = yield*
|
|
166
|
+
let response;
|
|
167
|
+
try {
|
|
168
|
+
response = yield* call(() => postWitnessReceiptEndpoint(hab, witness, message, this.http, auths[witness], this.gvrsn));
|
|
169
|
+
if (response.kind === "escrow") {
|
|
170
|
+
response = yield* pollWitnessReceipt(hab, witness, pre, eventSn, said, this.http, this.gvrsn);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
if (!(error instanceof TransportError))
|
|
175
|
+
throw error;
|
|
176
|
+
return incomplete(witness, error);
|
|
149
177
|
}
|
|
150
178
|
statuses[witness] = response.status;
|
|
151
179
|
if (response.kind !== "accepted") {
|
|
152
180
|
const detail = response.kind === "reject" ? response.message : "receipt remained escrowed";
|
|
153
|
-
|
|
181
|
+
return incomplete(witness, new ValidationError(`Witness ${witness} failed to receipt ${pre}:${eventSn.toString(16)}: ${detail}`));
|
|
154
182
|
}
|
|
155
183
|
yield* processMessages((signal) => chunkBytes(response.body, { signal }), this.protocol, this.kvy, {
|
|
156
184
|
local: false,
|
|
@@ -161,7 +189,7 @@ export class Receiptor {
|
|
|
161
189
|
const index = witnesses.indexOf(witness);
|
|
162
190
|
const wigers = this.hby.db.wigs.get(dgKey(pre, said)).filter((siger) => siger.index === index);
|
|
163
191
|
if (wigers.length === 0) {
|
|
164
|
-
|
|
192
|
+
return incomplete(witness, new ValidationError(`Witness ${witness} did not receipt ${pre}:${eventSn.toString(16)}.`));
|
|
165
193
|
}
|
|
166
194
|
receiptGroups.set(witness, wigers);
|
|
167
195
|
}
|
|
@@ -190,9 +218,11 @@ export class Receiptor {
|
|
|
190
218
|
pipelined: true,
|
|
191
219
|
genusify: true,
|
|
192
220
|
}));
|
|
193
|
-
yield*
|
|
221
|
+
const delivery = yield* deliverWitnessMessage(hab, witness, concatBytes(...parts), this.http, this.clock, this.protocol);
|
|
222
|
+
if (delivery.kind === "unreachable")
|
|
223
|
+
return incomplete(witness, delivery.error);
|
|
194
224
|
}
|
|
195
|
-
return { witnesses, statuses };
|
|
225
|
+
return { kind: "receipted", result: { witnesses, statuses } };
|
|
196
226
|
}
|
|
197
227
|
/**
|
|
198
228
|
* Query a stored witness receipt and apply it to local state when found.
|
|
@@ -243,15 +273,27 @@ export class Receiptor {
|
|
|
243
273
|
if (!hab) {
|
|
244
274
|
throw new ValidationError(`${pre} not a valid local AID.`);
|
|
245
275
|
}
|
|
276
|
+
const delivery = yield* this.replayHistory(hab, witness);
|
|
277
|
+
if (delivery.kind === "unreachable")
|
|
278
|
+
throw delivery.error;
|
|
279
|
+
}
|
|
280
|
+
/** Replay a delegated inception's delegation chain and the KEL to one witness, stopping at the first failure. */
|
|
281
|
+
*replayHistory(hab, witness) {
|
|
246
282
|
const kever = hab.kever;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
yield*
|
|
283
|
+
const db = this.hby.db;
|
|
284
|
+
const gvrsn = this.gvrsn;
|
|
285
|
+
const pre = hab.pre;
|
|
286
|
+
const messages = (function* () {
|
|
287
|
+
if (kever?.delegated)
|
|
288
|
+
yield* db.cloneDelegation(kever, gvrsn);
|
|
289
|
+
yield* db.clonePreIter(pre, 0, gvrsn);
|
|
290
|
+
})();
|
|
291
|
+
for (const msg of messages) {
|
|
292
|
+
const delivery = yield* deliverWitnessMessage(hab, witness, this.selected(msg), this.http, this.clock, this.protocol);
|
|
293
|
+
if (delivery.kind === "unreachable")
|
|
294
|
+
return delivery;
|
|
254
295
|
}
|
|
296
|
+
return { kind: "delivered" };
|
|
255
297
|
}
|
|
256
298
|
/** Complete streams select their framing before the body; detached receipt headers retain their existing enclosure. */
|
|
257
299
|
selected(message) {
|
|
@@ -16,7 +16,7 @@ import { telEventStatus, waitForIssuedCredential, waitForTelEvent, } from "../..
|
|
|
16
16
|
import { endpointRoleAccepted, isLocalGroupHab, localGroupMember, proposeGroupEndpointRole, } from "../../app/identity/endpoint-roleing.js";
|
|
17
17
|
import { MULTISIG_REV_ROUTE, MULTISIG_ROT_ROUTE, MULTISIG_VCP_ROUTE } from "../../app/multisig/grouping.js";
|
|
18
18
|
import { routeForKelEvent } from "../../app/multisig/multisig-workflows.js";
|
|
19
|
-
import { proposeGroupInception, proposeGroupInteraction, proposeGroupRotation,
|
|
19
|
+
import { proposeGroupInception, proposeGroupInteraction, proposeGroupRotation, } from "../../app/multisig/proposing.js";
|
|
20
20
|
import { observeUntil } from "../../app/runtime/workflow-contract.js";
|
|
21
21
|
import { ValidationError } from "../../core/errors.js";
|
|
22
22
|
import { isV2RegistryRoute } from "../../core/exchange/protocol-exchanging.js";
|
|
@@ -272,8 +272,9 @@ export function* multisigRotateCommand(args) {
|
|
|
272
272
|
let delegationPhase = null;
|
|
273
273
|
let rootCopies = [];
|
|
274
274
|
if (accepted) {
|
|
275
|
-
//
|
|
276
|
-
|
|
275
|
+
// Acceptance was read straight from the KEL, possibly before the Counselor's pass: follow it now, since the
|
|
276
|
+
// root copies below go to the rotated members.
|
|
277
|
+
hby.alignGroupMembers(sent.group);
|
|
277
278
|
delegationPhase = yield* finishAcceptedEvent(hby, runtime, sent.event, commandArgs);
|
|
278
279
|
rootCopies = yield* resealAfterRotation(hby, runtime, sent.group, sent.event.said, since);
|
|
279
280
|
}
|