@ibgib/core-gib 0.1.44 → 0.1.47
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/dist/keystone/keystone-constants.d.mts +9 -0
- package/dist/keystone/keystone-constants.d.mts.map +1 -1
- package/dist/keystone/keystone-constants.mjs +9 -0
- package/dist/keystone/keystone-constants.mjs.map +1 -1
- package/dist/keystone/keystone-helpers.d.mts +19 -0
- package/dist/keystone/keystone-helpers.d.mts.map +1 -1
- package/dist/keystone/keystone-helpers.mjs +292 -4
- package/dist/keystone/keystone-helpers.mjs.map +1 -1
- package/dist/keystone/keystone-types.d.mts +2 -0
- package/dist/keystone/keystone-types.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.mjs +12 -3
- package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +0 -38
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +1 -83
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
- package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +24 -4
- package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.d.mts +14 -2
- package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +128 -11
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/package.json +1 -1
- package/src/keystone/keystone-constants.mts +9 -0
- package/src/keystone/keystone-helpers.mts +320 -5
- package/src/keystone/keystone-types.mts +4 -1
- package/src/sync/sync-peer/sync-peer-v1.mts +13 -3
- package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +3 -107
- package/src/sync/sync-saga-context/sync-saga-context-types.mts +25 -4
- package/src/sync/sync-saga-coordinator.mts +159 -9
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { extractErrorMsg, hash, pretty } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
1
|
+
import { extractErrorMsg, hash, HashAlgorithm, pretty } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
2
|
+
import { GIB } from "@ibgib/ts-gib/dist/V1/constants.mjs";
|
|
2
3
|
import { Ib, TransformResult } from "@ibgib/ts-gib/dist/types.mjs";
|
|
3
4
|
import { getIbAndGib, getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
|
|
4
5
|
import { validateIbGibIntrinsically } from "@ibgib/ts-gib/dist/V1/validate-helper.mjs";
|
|
@@ -7,12 +8,23 @@ import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
|
|
|
7
8
|
import { getGib } from "@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs";
|
|
8
9
|
|
|
9
10
|
import { GLOBAL_LOG_A_LOT } from "../core-constants.mjs";
|
|
10
|
-
import { KEYSTONE_ATOM } from "./keystone-constants.mjs";
|
|
11
|
-
import {
|
|
11
|
+
import { KEYSTONE_ATOM, KEYSTONE_HASH_MAX_ROUNDS, KEYSTONE_POOL_ID_REGEXP, KEYSTONE_SALT_REGEXP } from "./keystone-constants.mjs";
|
|
12
|
+
import {
|
|
13
|
+
KeystoneData_V1, KeystoneIbGib_V1, KeystoneIb_V1, KeystoneChallengePool,
|
|
14
|
+
DeterministicResult, KeystoneProof, KeystonePoolConfig,
|
|
15
|
+
KeystoneReplenishStrategy, KEYSTONE_REPLENISH_STRATEGY_VALID_VALUES,
|
|
16
|
+
KeystoneClaim, KeystoneSolution,
|
|
17
|
+
KeystoneChallengeType,
|
|
18
|
+
KEYSTONE_CHALLENGE_TYPE_VALID_VALUES,
|
|
19
|
+
KeystonePoolConfig_HashV1,
|
|
20
|
+
} from "./keystone-types.mjs";
|
|
12
21
|
import { MetaspaceService } from "../witness/space/metaspace/metaspace-types.mjs";
|
|
13
22
|
import { IbGibSpaceAny } from "../witness/space/space-base-v1.mjs";
|
|
14
23
|
import { KeystoneStrategyFactory } from "./strategy/keystone-strategy-factory.mjs";
|
|
15
|
-
import {
|
|
24
|
+
import { getDependencyGraph } from "../common/other/graph-helper.mjs";
|
|
25
|
+
import { getIbGibsFromCache_fallbackToSpaces, getTimelinesGroupedByTjp, splitPerTjpAndOrDna } from "../common/other/ibgib-helper.mjs";
|
|
26
|
+
import { IbGib_V1, IbGibData_V1, IbGibRel8ns_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
|
|
27
|
+
import { getLatestAddrs } from "../witness/space/space-helper.mjs";
|
|
16
28
|
|
|
17
29
|
const logalot = GLOBAL_LOG_A_LOT;
|
|
18
30
|
|
|
@@ -512,6 +524,156 @@ export async function solveAndReplenish({
|
|
|
512
524
|
}
|
|
513
525
|
}
|
|
514
526
|
|
|
527
|
+
export async function validateChallengePool_typeHashRevealV1({ pool }: {
|
|
528
|
+
pool: KeystoneChallengePool;
|
|
529
|
+
}): Promise<string[]> {
|
|
530
|
+
const lc = `[${validateChallengePool_typeHashRevealV1.name}]`;
|
|
531
|
+
try {
|
|
532
|
+
if (logalot) { console.log(`${lc} starting... (I: e2ffd568b698cc12d8c5e838d73ae726)`); }
|
|
533
|
+
|
|
534
|
+
if (!pool.config) { throw new Error(`(UNEXPECTED) pool.configy falsy? (E: fcde88fe20e8004a58d7e445436bf526)`); }
|
|
535
|
+
if (pool.config.type !== KeystoneChallengeType.hash_reveal_v1) {
|
|
536
|
+
throw new Error(`(UNEXPECTED) pool.config.type !== KeystoneChallengeType.hash_reveal_v1? (E: e205f8872909c37168a624a9df778c26)`);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const errors: string[] = [];
|
|
540
|
+
|
|
541
|
+
const { algo, rounds, salt, } = pool.config as KeystonePoolConfig_HashV1;
|
|
542
|
+
|
|
543
|
+
const validAlgos: HashAlgorithm[] = [HashAlgorithm.sha_256];
|
|
544
|
+
if (algo) {
|
|
545
|
+
if (!validAlgos.includes(algo)) {
|
|
546
|
+
errors.push(`${lc} invalid hash algorithm (${algo}). Must be one of ${validAlgos}. (E: a22399ca3a68e63ffcc7507699be5826)`);
|
|
547
|
+
}
|
|
548
|
+
} else {
|
|
549
|
+
errors.push(`${lc} algorithm required. (E: 8cd6bfb0590862b9bae24d98d2cf3826)`)
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (rounds && typeof rounds === 'number' && Number.isInteger(rounds)) {
|
|
553
|
+
if (rounds > KEYSTONE_HASH_MAX_ROUNDS) {
|
|
554
|
+
errors.push(`${lc} rounds too high. max rounds: ${KEYSTONE_HASH_MAX_ROUNDS} (E: 31ce082f7fd88d6b58ef08a816458826)`);
|
|
555
|
+
}
|
|
556
|
+
} else {
|
|
557
|
+
errors.push(`${lc} invalid rounds (${rounds}). must be positive integer. (E: 73c643ccda78afaf28d52a6871a9e826)`);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (salt && typeof salt === 'string') {
|
|
561
|
+
// no limits on this? sanity check?
|
|
562
|
+
if (!KEYSTONE_SALT_REGEXP.test(salt)) {
|
|
563
|
+
errors.push(`${lc} invalid salt (${salt.substring(0, 99)}). Must match regexp ${KEYSTONE_SALT_REGEXP}`);
|
|
564
|
+
}
|
|
565
|
+
} else {
|
|
566
|
+
errors.push(`${lc} invalid salt (${salt}). must be truthy string value. (E: 564a4844ec88fc1988197ce89c381426)`);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return errors;
|
|
570
|
+
|
|
571
|
+
} catch (error) {
|
|
572
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
573
|
+
throw error;
|
|
574
|
+
} finally {
|
|
575
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
export async function validateChallengePool({ pool }: {
|
|
580
|
+
pool: KeystoneChallengePool;
|
|
581
|
+
}): Promise<string[]> {
|
|
582
|
+
const lc = `[${validateChallengePool.name}]`;
|
|
583
|
+
try {
|
|
584
|
+
if (logalot) { console.log(`${lc} starting... (I: 1a0eafc158a83d1ba8fc019d5c979a26)`); }
|
|
585
|
+
const errors: string[] = [];
|
|
586
|
+
|
|
587
|
+
if (pool.config) {
|
|
588
|
+
// first validate common to all pools, regardless of type...
|
|
589
|
+
if (pool.config.id) {
|
|
590
|
+
if (!KEYSTONE_POOL_ID_REGEXP.test(pool.config.id)) {
|
|
591
|
+
// not 100% that this is needed but hey
|
|
592
|
+
errors.push(`${lc} pool.config.id is not formatted correctly. must pass regexp: ${KEYSTONE_POOL_ID_REGEXP.source}`);
|
|
593
|
+
}
|
|
594
|
+
} else {
|
|
595
|
+
errors.push(`${lc} pool.config.id falsy (E: 31d7943d95f877326d5f4ea14463d626)`);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (pool.config.behavior) {
|
|
599
|
+
const { size } = pool.config.behavior;
|
|
600
|
+
if (!size || size === 0) {
|
|
601
|
+
errors.push(`${lc} invalid pool.config.behavior.size (${size}). Must be positive integer. (E: b221e36ec102bdc944552248ce8fe626)`)
|
|
602
|
+
}
|
|
603
|
+
// todo: more behavior checks
|
|
604
|
+
} else {
|
|
605
|
+
errors.push(`${lc} pool.config.behavior falsy (E: bede081c066c39732eefe2f92e296326)`)
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// ...then do type-specific validation
|
|
609
|
+
const poolType = pool.config.type;
|
|
610
|
+
switch (poolType) {
|
|
611
|
+
case KeystoneChallengeType.hash_reveal_v1:
|
|
612
|
+
const errorsHashRevealV1 = await validateChallengePool_typeHashRevealV1({ pool });
|
|
613
|
+
errorsHashRevealV1.forEach(x => errors.push(x));
|
|
614
|
+
break;
|
|
615
|
+
default:
|
|
616
|
+
throw new Error(`(UNEXPECTED) unknown pool.config.type (${poolType})? We only implement the following at this time: ${KEYSTONE_CHALLENGE_TYPE_VALID_VALUES} (E: cce5285cf7580b8bc82172488eba2826)`);
|
|
617
|
+
}
|
|
618
|
+
} else {
|
|
619
|
+
errors.push(`${lc} pool.config falsy. (E: 8d05c875a1d2c58018a5eaf803977d26)`);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
return errors;
|
|
623
|
+
} catch (error) {
|
|
624
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
625
|
+
throw error;
|
|
626
|
+
} finally {
|
|
627
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
export async function validateGenesisKeystone({
|
|
633
|
+
keystoneIbGib
|
|
634
|
+
}: {
|
|
635
|
+
keystoneIbGib: KeystoneIbGib_V1;
|
|
636
|
+
}): Promise<string[]> {
|
|
637
|
+
const lc = `[${validateGenesisKeystone.name}]`;
|
|
638
|
+
try {
|
|
639
|
+
if (logalot) { console.log(`${lc} starting... (I: ec6ba82ec848b5ac3d8953e89d8d9826)`); }
|
|
640
|
+
|
|
641
|
+
const errors: string[] = [];
|
|
642
|
+
|
|
643
|
+
const { data, rel8ns } = keystoneIbGib;
|
|
644
|
+
|
|
645
|
+
// no proofs/solutions yet
|
|
646
|
+
if (data.proofs && data.proofs.length > 0) {
|
|
647
|
+
errors.push(`${lc} proofs already exist on genesis keystone. (E: 7a5e15f20918f1bbd8ffb62857dcd526)`);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
for (const pool of data.challengePools) {
|
|
651
|
+
// validate each pool intrinsically (config, sanity)
|
|
652
|
+
const poolErrors = await validateChallengePool({ pool });
|
|
653
|
+
poolErrors.forEach(x => errors.push(x));
|
|
654
|
+
|
|
655
|
+
// additionally ensure each pool has challenges. This is only on
|
|
656
|
+
// this genesis keystone, as it is valid to have pool without
|
|
657
|
+
// challenges after revocation
|
|
658
|
+
if (!pool.challenges || Object.keys(pool.challenges).length === 0) {
|
|
659
|
+
errors.push(`${lc} invalid pool (${pool.id}). pool.challenges is falsy/empty. (E: 8cd16a5416ae62a058342828be465b26)`);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// not stated as revoked already
|
|
664
|
+
if (!!data.revocationInfo) {
|
|
665
|
+
errors.push(`${lc} genesis keystone already has revocationInfo. (E: e11408d0c558d0fa948efbce611ec826)`);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return errors;
|
|
669
|
+
} catch (error) {
|
|
670
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
671
|
+
throw error;
|
|
672
|
+
} finally {
|
|
673
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
515
677
|
/**
|
|
516
678
|
* Validates the transition from Prev -> Curr.
|
|
517
679
|
* Enforces Cryptography AND Behavioral Policy.
|
|
@@ -782,4 +944,157 @@ export async function createKeystoneIbGibImpl({
|
|
|
782
944
|
} finally {
|
|
783
945
|
if (logalot) { console.log(`${lc} complete.`); }
|
|
784
946
|
}
|
|
785
|
-
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
export async function validateKeystoneGraph({
|
|
950
|
+
keystoneIbGib,
|
|
951
|
+
getLatest,
|
|
952
|
+
invalidIfMoreRecentKeystoneFoundInSpace,
|
|
953
|
+
space,
|
|
954
|
+
}: {
|
|
955
|
+
keystoneIbGib: KeystoneIbGib_V1,
|
|
956
|
+
/**
|
|
957
|
+
* if true, then this will get the latest keystone known in the incoming
|
|
958
|
+
* {@link keystoneIbGib} timeline, as found in {@link space}.
|
|
959
|
+
*/
|
|
960
|
+
getLatest: boolean,
|
|
961
|
+
invalidIfMoreRecentKeystoneFoundInSpace: boolean,
|
|
962
|
+
space: IbGibSpaceAny,
|
|
963
|
+
}): Promise<string[]> {
|
|
964
|
+
const lc = `[${validateKeystoneGraph.name}]`;
|
|
965
|
+
try {
|
|
966
|
+
if (logalot) { console.log(`${lc} starting... (I: 22e1ca1d5a08a3f90b7fe9da95df7b26)`); }
|
|
967
|
+
|
|
968
|
+
// maybe too defensive but...
|
|
969
|
+
if (!keystoneIbGib) { throw new Error(`(UNEXPECTED) keystoneIbGib falsy? (E: 26482871d529fff6e8899c5d8a6c3826)`); }
|
|
970
|
+
|
|
971
|
+
// #region leaving off here
|
|
972
|
+
// asdf
|
|
973
|
+
// just implemented validate keystone graph. incorporate this into the
|
|
974
|
+
// context ibgib, which now has the session ibgib as part of it. each
|
|
975
|
+
// step in ping pong should validate the entire keystone graph
|
|
976
|
+
|
|
977
|
+
// #endregion leaving off here
|
|
978
|
+
const errors: string[] = [];
|
|
979
|
+
|
|
980
|
+
// first, get the latest if that is the case...
|
|
981
|
+
if (getLatest) {
|
|
982
|
+
const keystoneAddr = getIbGibAddr({ ibGib: keystoneIbGib });
|
|
983
|
+
const resGetLatestAddrs = await getLatestAddrs({
|
|
984
|
+
ibGibs: [keystoneIbGib],
|
|
985
|
+
space,
|
|
986
|
+
});
|
|
987
|
+
if (!resGetLatestAddrs.data) { throw new Error(`(UNEXPECTED) resGetLatestAddrs.data falsy? (E: 3a23b3b420a8da1928219ca8d47b2126)`); }
|
|
988
|
+
if (!resGetLatestAddrs.data.latestAddrsMap) { throw new Error(`(UNEXPECTED) resGetLatestAddrs.data.latestAddrsMap falsy? (E: 93f1180598fb65a4b8d36e08d6c50426)`); }
|
|
989
|
+
|
|
990
|
+
const { latestAddrsMap } = resGetLatestAddrs.data;
|
|
991
|
+
if (Object.keys(latestAddrsMap).length === 0) {
|
|
992
|
+
throw new Error(`(UNEXPECTED) latestAddrsMap truthy but empty? (E: 7142f8f7625b9186281d08251e407826)`);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
const latestAddr = latestAddrsMap[keystoneAddr];
|
|
996
|
+
if (latestAddr) {
|
|
997
|
+
if (latestAddr !== keystoneAddr) {
|
|
998
|
+
if (invalidIfMoreRecentKeystoneFoundInSpace) {
|
|
999
|
+
errors.push(`${lc} more recent keystone (${latestAddr}) found than the one passed in (${keystoneAddr}) in space (${space.ib}). (E: 64bf48de9448ee5c7528bf03bed2a826)`);
|
|
1000
|
+
} else {
|
|
1001
|
+
// get the latest ibgib and point the incoming ref to that
|
|
1002
|
+
const [latestKeystoneIbGib] = await getIbGibsFromCache_fallbackToSpaces({
|
|
1003
|
+
addrs: [latestAddr],
|
|
1004
|
+
space,
|
|
1005
|
+
});
|
|
1006
|
+
keystoneIbGib = latestKeystoneIbGib as KeystoneIbGib_V1;
|
|
1007
|
+
}
|
|
1008
|
+
} else {
|
|
1009
|
+
// the incoming ibgib **is** the latest keystone, so nothing more to be done.
|
|
1010
|
+
if (logalot) { console.log(`${lc} incoming keystone (${keystoneAddr}) is the latest in the space (${space.ib}) (I: 8ffbd8d6cbc8a461e5e7f1084bd22a26)`); }
|
|
1011
|
+
}
|
|
1012
|
+
} else {
|
|
1013
|
+
// keystone not found in space?
|
|
1014
|
+
console.warn(`${lc} keystoneIbGib (${keystoneAddr}) not found in space (${space.ib}). I don't know what the implications of this are. (W: 258c88742448db34a585669484771826)`)
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
const dependencyGraph = await getDependencyGraph({
|
|
1019
|
+
ibGib: keystoneIbGib,
|
|
1020
|
+
space,
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
const depIbGibs = Object.values(dependencyGraph);
|
|
1024
|
+
const { mapWithTjp_NoDna, mapWithTjp_YesDna, mapWithoutTjps, } =
|
|
1025
|
+
splitPerTjpAndOrDna({ ibGibs: depIbGibs });
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
// there should be no DNA
|
|
1029
|
+
if (Object.keys(mapWithTjp_YesDna).length > 0) {
|
|
1030
|
+
errors.push(`${lc} DNA found. Keystones should NOT have DNA. (E: a3ec7827c4284cdea61c2372c0615826)`);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// is there a tjp? I think there is, so mapWithoutTjps should also be
|
|
1034
|
+
// empty
|
|
1035
|
+
if (Object.keys(mapWithoutTjps).length > 0) {
|
|
1036
|
+
errors.push(`${lc} Non-tjp ibgibs found? Keystones are expected to have tjps. (E: a3ec7827c4284cdea61c2372c0615826)`);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
if (Object.keys(mapWithTjp_NoDna).length > 0) {
|
|
1040
|
+
// happy path here. These should be the keystone ibgibs. we will put
|
|
1041
|
+
// them in order, then do validation on the transitions. We will
|
|
1042
|
+
// also check other graph-scoped integrity of keystones (like do
|
|
1043
|
+
// certain properties match among ALL keystones, etc.)
|
|
1044
|
+
|
|
1045
|
+
const keystoneIbGibs_unordered = Object.values(mapWithTjp_NoDna);
|
|
1046
|
+
|
|
1047
|
+
const orderedKeystonesMap = getTimelinesGroupedByTjp({ ibGibs: keystoneIbGibs_unordered });
|
|
1048
|
+
const keys = Object.keys(orderedKeystonesMap);
|
|
1049
|
+
if (keys.length === 0) {
|
|
1050
|
+
throw new Error(`(UNEXPECTED) orderedKeystonesMap empty? (E: d437b80bef58e83a034b28af46278726)`);
|
|
1051
|
+
} else if (keys.length > 0) {
|
|
1052
|
+
// keys.length > 0
|
|
1053
|
+
throw new Error(`(UNEXPECTED) more than one timeline in keystone graph? ATOW (02/19/2026) we are expecting only a single timeline. (E: 66085b14e3887a59c872afd240511f26)`);
|
|
1054
|
+
}
|
|
1055
|
+
// happy path: exactly one timeline
|
|
1056
|
+
const keystoneTjpAddr = keys[0];
|
|
1057
|
+
const keystoneIbGibs_ordered = orderedKeystonesMap[keystoneTjpAddr] as KeystoneIbGib_V1[];
|
|
1058
|
+
|
|
1059
|
+
if (keystoneIbGibs_ordered.length === 0) { throw new Error(`(UNEXPECTED) empty keystoneIbGibs_ordered? (E: 4a6b085aa8a76828a8d65367e7e56526)`); }
|
|
1060
|
+
|
|
1061
|
+
const genesisErrors = await validateGenesisKeystone({
|
|
1062
|
+
keystoneIbGib: keystoneIbGibs_ordered[0]
|
|
1063
|
+
});
|
|
1064
|
+
genesisErrors.forEach(x => errors.push(x));
|
|
1065
|
+
|
|
1066
|
+
if (keystoneIbGibs_ordered.length === 1) {
|
|
1067
|
+
// only the genesis keystone, which has already been done.
|
|
1068
|
+
} else {
|
|
1069
|
+
// more than 1 keystone, so validate the transitions
|
|
1070
|
+
for (let i = 0; i < keystoneIbGibs_ordered.length - 1; i++) {
|
|
1071
|
+
const prevIbGib = keystoneIbGibs_ordered[i];
|
|
1072
|
+
const currentIbGib = keystoneIbGibs_ordered[i + 1];
|
|
1073
|
+
const transitionErrors = await validateKeystoneTransition({
|
|
1074
|
+
prevIbGib, currentIbGib
|
|
1075
|
+
});
|
|
1076
|
+
if (transitionErrors.length > 0) {
|
|
1077
|
+
errors.push(`${lc} keystone has ${transitionErrors.length} transition errors. i: ${i}. prevIbGib addr: ${getIbGibAddr({ ibGib: prevIbGib })}. currentIbGib addr: ${getIbGibAddr({ ibGib: currentIbGib })}. (E: 3ac17be916141d0c286ca5a87bb1b426)`);
|
|
1078
|
+
transitionErrors.forEach(x => errors.push(x));
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
break; // stop after the first found transition error
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
} else {
|
|
1085
|
+
// one of the other errors regarding mapWithTjp_YesDna or
|
|
1086
|
+
// mapWithoutTjps will exist at this point, so we don't need to add
|
|
1087
|
+
// any more errors.
|
|
1088
|
+
if (errors.length === 0) { throw new Error(`(UNEXPECTED) mapWithTjp_NoDna empty (which is an error) but errors.length === 0? If we get here, we expect one of the other errors to have been populated. (E: 7bca2866b6f8fca318923de8c88e8826)`); }
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
return errors;
|
|
1092
|
+
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
1095
|
+
throw error;
|
|
1096
|
+
} finally {
|
|
1097
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
@@ -336,7 +336,10 @@ export interface KeystoneRel8ns_V1 extends IbGibRel8ns_V1 {
|
|
|
336
336
|
// Specific hard-links for composite keystones go here later.
|
|
337
337
|
}
|
|
338
338
|
|
|
339
|
-
export interface KeystoneIbGib_V1 extends IbGib_V1<KeystoneData_V1, KeystoneRel8ns_V1> {
|
|
339
|
+
export interface KeystoneIbGib_V1 extends IbGib_V1<KeystoneData_V1, KeystoneRel8ns_V1> {
|
|
340
|
+
data: KeystoneData_V1;
|
|
341
|
+
rel8ns: KeystoneRel8ns_V1;
|
|
342
|
+
}
|
|
340
343
|
|
|
341
344
|
export interface DeterministicResult {
|
|
342
345
|
/**
|
|
@@ -133,13 +133,23 @@ export abstract class SyncPeer_V1<TInitializeOpts extends InitializeSyncPeerOpts
|
|
|
133
133
|
|
|
134
134
|
if (!this.opts) { throw new Error(`(UNEXPECTED) this.opts falsy? Concrete class should have initialized sender opts by now. (E: 0b9e28287318fdf8bf9f5a6886a24826)`); }
|
|
135
135
|
|
|
136
|
-
//
|
|
137
|
-
//
|
|
136
|
+
// #region leaving off here
|
|
137
|
+
// NOTES: the context ibgib now has a reference to the signed
|
|
138
|
+
// keystone. the signed keystone targets the context ibgib, and the
|
|
139
|
+
// context ibgib itself points to the previous frame of the
|
|
140
|
+
// keystone. I've started on creating a validateKeystone function,
|
|
141
|
+
// whcih I need to at least add the validate transitions to. I
|
|
142
|
+
// _think_ I need to also fill in some authentication here in this
|
|
143
|
+
// peer at the very least, then I can move on to other layers.
|
|
144
|
+
// #endregion leaving off here
|
|
145
|
+
|
|
146
|
+
// NOTE: There are three basic types of peers:
|
|
147
|
+
// * local-only
|
|
138
148
|
// * this peer is both sender/receiver peer
|
|
139
149
|
// * for local merges and relatively fast spaces
|
|
140
150
|
// * proxy to remote space
|
|
141
151
|
// * this peer is both sender/receiver peer
|
|
142
|
-
// * works directly with remote/outerspaces
|
|
152
|
+
// * works directly with remote/outerspaces via API calls
|
|
143
153
|
// * Less efficient over-the-wire xfer due to chatiness
|
|
144
154
|
// * symmetric node sender/receiver peers
|
|
145
155
|
// * separate sender/receiver classes
|
|
@@ -20,33 +20,12 @@ import { IbGibSpaceAny } from '../../witness/space/space-base-v1.mjs';
|
|
|
20
20
|
import { putInSpace, registerNewIbGib } from '../../witness/space/space-helper.mjs';
|
|
21
21
|
import { SyncIbGib_V1 } from '../sync-types.mjs';
|
|
22
22
|
import { validateSyncSagaFrame } from '../sync-helpers.mjs';
|
|
23
|
+
import { validateKeystoneGraph, validateKeystoneTransition } from '../../keystone/keystone-helpers.mjs';
|
|
24
|
+
import { KeystoneService_V1 } from '../../keystone/keystone-service-v1.mjs';
|
|
25
|
+
import { KeystoneIbGib_V1 } from '../../keystone/keystone-types.mjs';
|
|
23
26
|
|
|
24
27
|
const logalot = GLOBAL_LOG_A_LOT;
|
|
25
28
|
|
|
26
|
-
/**
|
|
27
|
-
* Options for creating a SyncSagaContext ibgib.
|
|
28
|
-
*/
|
|
29
|
-
export interface CreateSyncSagaContextOptions {
|
|
30
|
-
/**
|
|
31
|
-
* The main saga frame (Init, Ack, etc.).
|
|
32
|
-
*/
|
|
33
|
-
sagaFrame: SyncIbGib_V1;
|
|
34
|
-
/**
|
|
35
|
-
* Session identity keystones.
|
|
36
|
-
*/
|
|
37
|
-
sessionKeystones?: IbGib_V1[];
|
|
38
|
-
/**
|
|
39
|
-
* Domain payload ibgibs when the sync saga frame includes actual domain
|
|
40
|
-
* payloads to send, e.g., in a Delta frame.
|
|
41
|
-
*/
|
|
42
|
-
payloadIbGibsDomain?: IbGib_V1[];
|
|
43
|
-
/**
|
|
44
|
-
* we persist the context in the local/sender space (relative to our
|
|
45
|
-
* execution POV) right when we create it.
|
|
46
|
-
*/
|
|
47
|
-
localSpace: IbGibSpaceAny;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
29
|
/**
|
|
51
30
|
* Constructs the standard 'ib' string for a Sync Saga Context stone.
|
|
52
31
|
*/
|
|
@@ -117,89 +96,6 @@ export async function parseSyncSagaContextIb({
|
|
|
117
96
|
}
|
|
118
97
|
}
|
|
119
98
|
|
|
120
|
-
/**
|
|
121
|
-
* Creates new SyncSagaContext stone. Puts/registers in {@link localSpace}
|
|
122
|
-
* immediately after creation.
|
|
123
|
-
*
|
|
124
|
-
* @returns The context ibGib.
|
|
125
|
-
*
|
|
126
|
-
* ## notes
|
|
127
|
-
*
|
|
128
|
-
* the other ibgibs that are related to this context stone should already be
|
|
129
|
-
* put/registered in {@link localSpace}.
|
|
130
|
-
*/
|
|
131
|
-
export async function createSyncSagaContext({
|
|
132
|
-
sagaFrame,
|
|
133
|
-
sessionKeystones,
|
|
134
|
-
payloadIbGibsDomain,
|
|
135
|
-
localSpace,
|
|
136
|
-
}: CreateSyncSagaContextOptions): Promise<SyncSagaContextIbGib_V1> {
|
|
137
|
-
const lc = `[${createSyncSagaContext.name}]`;
|
|
138
|
-
try {
|
|
139
|
-
if (logalot) { console.log(`${lc} starting... (I: 6b87bee313e811d1d2fc90e87fbec826)`); }
|
|
140
|
-
|
|
141
|
-
if (!sagaFrame.data) { throw new Error(`(UNEXPECTED) sagaFrame.data falsy? (E: 04c49b4cccba6842a8b52e4c6f570726)`); }
|
|
142
|
-
if (!sagaFrame.data.n && sagaFrame.data.n !== 0) { throw new Error(`(UNEXPECTED) sagaFrame.data.n falsy and not 0? (E: 45b508da64a8b28428b11765d684b826)`); }
|
|
143
|
-
|
|
144
|
-
const date = new Date();
|
|
145
|
-
const timestamp = getTimestamp(date);
|
|
146
|
-
const timestampMs = date.getMilliseconds();
|
|
147
|
-
|
|
148
|
-
const data: SyncSagaContextData_V1 = {
|
|
149
|
-
timestamp,
|
|
150
|
-
timestampMs,
|
|
151
|
-
sagaN: sagaFrame.data.n,
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
// Domain Payloads
|
|
155
|
-
const payloadAddrsDomain = payloadIbGibsDomain ?
|
|
156
|
-
payloadIbGibsDomain?.map(x => getIbGibAddr({ ibGib: x })) :
|
|
157
|
-
undefined;
|
|
158
|
-
if (payloadAddrsDomain && payloadAddrsDomain.length > 0) {
|
|
159
|
-
data[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN] = payloadAddrsDomain;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// rel8ns should always have saga frame, sometimes have keystone
|
|
163
|
-
const rel8ns: SyncSagaContextRel8ns_V1 = {
|
|
164
|
-
sagaFrame: [getIbGibAddr({ ibGib: sagaFrame })],
|
|
165
|
-
};
|
|
166
|
-
if (sessionKeystones && sessionKeystones.length > 0) {
|
|
167
|
-
rel8ns.sessionKeystone = sessionKeystones.map(x => getIbGibAddr({ ibGib: x }));
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Generate standard ib
|
|
171
|
-
const ib = await getSyncSagaContextIb({ data });
|
|
172
|
-
|
|
173
|
-
const contextIbGib = await Factory_V1.stone<SyncSagaContextData_V1, SyncSagaContextRel8ns_V1>({
|
|
174
|
-
parentPrimitiveIb: SYNC_SAGA_CONTEXT_ATOM,
|
|
175
|
-
ib,
|
|
176
|
-
data,
|
|
177
|
-
rel8ns,
|
|
178
|
-
}) as SyncSagaContextIbGib_V1;
|
|
179
|
-
|
|
180
|
-
// put/register immediately. Note that contextIbGib at this point is
|
|
181
|
-
// pure DTO, i.e., only ib, gib, data, rel8ns props.
|
|
182
|
-
await putInSpace({ ibGib: contextIbGib, space: localSpace, });
|
|
183
|
-
await registerNewIbGib({
|
|
184
|
-
ibGib: contextIbGib,
|
|
185
|
-
space: localSpace,
|
|
186
|
-
fnBroadcast: undefined,
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// Attach actual ibgibs for transport (not pure DTO now)
|
|
190
|
-
contextIbGib.sagaFrame = sagaFrame;
|
|
191
|
-
if (payloadIbGibsDomain && payloadIbGibsDomain.length > 0) {
|
|
192
|
-
contextIbGib.payloadIbGibsDomain = payloadIbGibsDomain;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return contextIbGib;
|
|
196
|
-
} catch (error) {
|
|
197
|
-
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
198
|
-
throw error;
|
|
199
|
-
} finally {
|
|
200
|
-
if (logalot) { console.log(`${lc} complete.`); }
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
99
|
|
|
204
100
|
/**
|
|
205
101
|
* Validates ONLY the {@link context} ibgib itself and saga frame/msg stone(s)
|
|
@@ -8,6 +8,7 @@ import { IbGibData_V1, IbGibRel8ns_V1, IbGib_V1 } from '@ibgib/ts-gib/dist/V1/ty
|
|
|
8
8
|
import { SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN } from '../sync-constants.mjs';
|
|
9
9
|
import { SyncIbGib_V1 } from '../sync-types.mjs';
|
|
10
10
|
import { SYNC_SAGA_CONTEXT_ATOM } from './sync-saga-context-constants.mjs';
|
|
11
|
+
import { KeystoneIbGib_V1 } from '../../keystone/keystone-types.mjs';
|
|
11
12
|
|
|
12
13
|
export interface SyncSagaContextIb_V1 {
|
|
13
14
|
atom: typeof SYNC_SAGA_CONTEXT_ATOM;
|
|
@@ -49,13 +50,21 @@ export interface SyncSagaContextRel8ns_V1 extends IbGibRel8ns_V1 {
|
|
|
49
50
|
sagaFrame: IbGibAddr[];
|
|
50
51
|
|
|
51
52
|
/**
|
|
52
|
-
* The Ephemeral Session Keystone Identity used for this saga.
|
|
53
|
-
*
|
|
53
|
+
* The Ephemeral Session Keystone Identity used for this saga. Required for
|
|
54
|
+
* validating the saga frame and this context.
|
|
55
|
+
*
|
|
56
|
+
* WARNING!!!: THIS DOES NOT POINT TO THE CURRENT SESSION KEYSTONE IN
|
|
57
|
+
* {@link SyncSagaContextIbGib_V1.signedSessionKeystone}. This points to the
|
|
58
|
+
* PREVIOUS FRAME (immediate past) of that frame. That session keystone
|
|
59
|
+
* signs with THIS context's frame as its target, so it is logically
|
|
60
|
+
* impossible because the hash would be different.
|
|
54
61
|
*
|
|
55
62
|
* ## notes
|
|
56
63
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
64
|
+
* ATOW (02/18/2026), this is a single address that will have a primary pool
|
|
65
|
+
* for the sender and a delegated pool for the receiver.
|
|
66
|
+
*
|
|
67
|
+
* @see {@link SyncSagaContextIbGib_V1.signedSessionKeystone}
|
|
59
68
|
*/
|
|
60
69
|
sessionKeystone?: IbGibAddr[];
|
|
61
70
|
}
|
|
@@ -79,4 +88,16 @@ export interface SyncSagaContextIbGib_V1 extends IbGib_V1<SyncSagaContextData_V1
|
|
|
79
88
|
* This frame's addr should be {@link SyncSagaContextRel8ns_V1.sagaFrame}.
|
|
80
89
|
*/
|
|
81
90
|
sagaFrame: SyncIbGib_V1;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* If session keystone is in play, then this will be populated with that
|
|
94
|
+
* keystone. This session keystone will point to the this context ibgib,
|
|
95
|
+
* BUT, this context ibgib will point to the **PREVIOUS** frame of the
|
|
96
|
+
* keystone.
|
|
97
|
+
*
|
|
98
|
+
* So in order to verify this context ibgib, we must verify the keystone
|
|
99
|
+
* points to this context ibgib AND that this context ibgib points to the
|
|
100
|
+
* previous frame of the keystone.
|
|
101
|
+
*/
|
|
102
|
+
signedSessionKeystone?: KeystoneIbGib_V1;
|
|
82
103
|
}
|