mirror of
https://github.com/lux-tel/websites.git
synced 2026-10-30 20:31:36 +00:00
107 lines
3.7 KiB
TypeScript
107 lines
3.7 KiB
TypeScript
import { VOLATILE_STORAGE } from '@/lib/constants';
|
|
import logger from '@/lib/logger';
|
|
import { useVolatileStorage } from '@/providers/volatile-storage-provider';
|
|
import { ed25519PublicKeySchema, ethereumAddressSchema } from '@session/staking-api-js/schema';
|
|
import { safeTrySyncWithFallback } from '@session/util-js/try';
|
|
import { useCallback, useMemo } from 'react';
|
|
import { z } from 'zod';
|
|
|
|
export enum CONFIRMATION_TYPE {
|
|
REGISTRATION = 'registration',
|
|
EXIT_REQUEST = 'exitRequest',
|
|
EXIT = 'exit',
|
|
}
|
|
|
|
const volatileStorageNodeConfirmingSchema = z.object({
|
|
pubkeyEd25519: ed25519PublicKeySchema,
|
|
pubkeyBls: z.string(),
|
|
operatorAddress: ethereumAddressSchema,
|
|
rewardsAddress: ethereumAddressSchema.nullable(),
|
|
estimatedConfirmationTimestampMs: z.coerce.number(),
|
|
confirmationType: z.nativeEnum(CONFIRMATION_TYPE),
|
|
confirmationOwner: ethereumAddressSchema,
|
|
});
|
|
|
|
export type VolatileStorageNodeConfirming = z.infer<typeof volatileStorageNodeConfirmingSchema>;
|
|
|
|
export const useNodesWithConfirmations = () => {
|
|
const { getItem, setItem } = useVolatileStorage();
|
|
const nodesConfirming = getItem<string>(VOLATILE_STORAGE.NODES_CONFIRMING);
|
|
|
|
const nodes = useMemo(() => {
|
|
const nodeMap = {
|
|
nodesConfirmingRegistration: [] as Array<VolatileStorageNodeConfirming>,
|
|
nodesConfirmingExitRequest: [] as Array<VolatileStorageNodeConfirming>,
|
|
nodesConfirmingExit: [] as Array<VolatileStorageNodeConfirming>,
|
|
};
|
|
|
|
const [err, unvalidatedNodes] = safeTrySyncWithFallback(
|
|
() => JSON.parse(nodesConfirming ?? '[]') as Array<unknown>,
|
|
[]
|
|
);
|
|
if (err) logger.error(err);
|
|
|
|
if (!Array.isArray(unvalidatedNodes)) return nodeMap;
|
|
|
|
const nodes = unvalidatedNodes.filter(
|
|
(m) => volatileStorageNodeConfirmingSchema.safeParse(m).success
|
|
) as Array<VolatileStorageNodeConfirming>;
|
|
|
|
const now = Date.now();
|
|
const nodesCurrentlyConfirming = nodes.filter((m) => m.estimatedConfirmationTimestampMs > now);
|
|
|
|
if (nodesCurrentlyConfirming.length < unvalidatedNodes.length) {
|
|
logger.debug('Volatile storage contains expired or invalid confirmations, removing them');
|
|
setItem(VOLATILE_STORAGE.NODES_CONFIRMING, JSON.stringify(nodesCurrentlyConfirming));
|
|
} else {
|
|
for (const node of nodesCurrentlyConfirming) {
|
|
switch (node.confirmationType) {
|
|
case CONFIRMATION_TYPE.REGISTRATION:
|
|
nodeMap.nodesConfirmingRegistration.push(node);
|
|
break;
|
|
case CONFIRMATION_TYPE.EXIT_REQUEST:
|
|
nodeMap.nodesConfirmingExitRequest.push(node);
|
|
break;
|
|
case CONFIRMATION_TYPE.EXIT:
|
|
nodeMap.nodesConfirmingExit.push(node);
|
|
break;
|
|
default:
|
|
logger.error('Unknown confirmation type:', node.confirmationType);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nodeMap;
|
|
}, [nodesConfirming, setItem]);
|
|
|
|
const addConfirmingNode = useCallback(
|
|
(node: VolatileStorageNodeConfirming) => {
|
|
const currentlyConfirming = nodes.nodesConfirmingRegistration
|
|
.concat(nodes.nodesConfirmingExitRequest)
|
|
.concat(nodes.nodesConfirmingExit);
|
|
const parsedNode = volatileStorageNodeConfirmingSchema.parse(node);
|
|
if (
|
|
currentlyConfirming.some(
|
|
(m) =>
|
|
m.pubkeyEd25519 === parsedNode.pubkeyEd25519 &&
|
|
m.confirmationType === parsedNode.confirmationType
|
|
)
|
|
) {
|
|
logger.debug('Node already confirming, ignoring');
|
|
return;
|
|
}
|
|
currentlyConfirming.push(parsedNode);
|
|
setItem(VOLATILE_STORAGE.NODES_CONFIRMING, JSON.stringify(currentlyConfirming));
|
|
},
|
|
[nodes, setItem]
|
|
);
|
|
|
|
return {
|
|
nodes,
|
|
addConfirmingNode,
|
|
};
|
|
};
|
|
|
|
export type NodesWithConfirmations = ReturnType<typeof useNodesWithConfirmations>['nodes'];
|