/// import type { ContextTimed } from '@matrixai/contexts'; import type { DBTransaction, KeyPath, LevelPath } from '@matrixai/db'; import type { QUICClientCrypto, QUICServerCrypto } from '@matrixai/quic'; import type { X509Certificate } from '@peculiar/x509'; import type { Hostname } from '../network/types.js'; import type { NodeAddress, NodeContact, NodeContactAddress, NodeBucket, NodeBucketIndex, NodeId, SeedNodes, AuthenticateNetworkForwardCallback, AuthenticateNetworkReverseCallback } from './types.js'; import type { NodesAuthenticateConnectionMessageNone } from './agent/types.js'; import type { ClaimNetworkAccess } from '../claims/payloads/index.js'; import { native } from '@matrixai/quic'; import Token from '../tokens/Token.js'; declare const sepBuffer: Buffer; /** * Calculate the bucket index that the target node should be located in * A node's k-buckets are organised such that for the ith k-bucket where * 0 <= i < nodeIdBits, the contacts in this ith bucket are known to adhere to * the following inequality: * 2^i <= distance (from current node) < 2^(i+1) * This means lower buckets will have less nodes then the upper buckets. * The highest bucket will contain half of all possible nodes. * The lowest bucket will only contain 1 node. * * NOTE: because XOR is a commutative operation (i.e. a XOR b = b XOR a), the * order of the passed parameters is actually irrelevant. These variables are * purely named for communicating function purpose. * * NOTE: Kademlia literature generally talks about buckets with 1-based indexing * and that the buckets are ordered from largest to smallest. This means the first * 1th-bucket is far & large bucket, and the last 255th-bucket is the close bucket. * This is reversed in our `NodeBucketIndex` encoding. This is so that lexicographic * sort orders our buckets from closest bucket to farthest bucket. * * To convert from `NodeBucketIndex` to nth-bucket in Kademlia literature: * * | NodeBucketIndex | Nth-Bucket | * | --------------- | ---------- | * | 255 | 1 | farthest & largest * | 254 | 2 | * | ... | ... | * | 1 | 254 | * | 0 | 256 | closest & smallest */ declare function bucketIndex(sourceNode: NodeId, targetNode: NodeId): NodeBucketIndex; /** * Encodes NodeAddress to NodeAddressKey */ declare function nodeContactAddress([host, port]: NodeAddress): NodeContactAddress; /** * Encodes bucket index to bucket sublevel key */ declare function bucketKey(bucketIndex: NodeBucketIndex): string; /** * Creates key for buckets sublevel */ declare function bucketsDbKey(bucketIndex: NodeBucketIndex, nodeId: NodeId): Buffer; /** * Creates key for single bucket sublevel */ declare function bucketDbKey(nodeId: NodeId): Buffer; declare function connectedKey(lastUpdated: number): Buffer; declare function parseConnectedKey(buffer: Buffer): number; declare function parseNodeContactAddress(nodeContactAddress: string): NodeAddress; declare function parseNodeAddressKey(keyBuffer: Buffer): NodeAddress; /** * Parse the NodeGraph buckets sublevel key * The keys look like `!!` * It is assumed that the `!` is the sublevel prefix. */ declare function parseBucketsDbKey(keyPath: KeyPath): { bucketIndex: NodeBucketIndex; bucketKey: string; nodeId: NodeId; nodeContactAddress: NodeContactAddress; }; /** * Parse the NodeGraph bucket key * The keys look like `` */ declare function parseBucketDbKey(keyBuffer: Buffer): NodeId; /** * Parse the NodeGraph index sublevel key * The keys look like `!!-` * It is assumed that the `!` is the sublevel prefix. */ declare function parseLastUpdatedBucketsDbKey(keyPath: KeyPath): { bucketIndex: NodeBucketIndex; bucketKey: string; lastUpdated: number; nodeId: NodeId; }; /** * Parse the NodeGraph index bucket sublevel key * The keys look like `-` * It is assumed that the `!` is the sublevel prefix. */ declare function parseLastUpdatedBucketDbKey(keyPath: KeyPath): { lastUpdated: number; nodeId: NodeId; }; /** * Compute the distance between two nodes. * distance = nodeId1 ^ nodeId2 * where ^ = bitwise XOR operator */ declare function nodeDistance(nodeId1: NodeId, nodeId2: NodeId): bigint; declare function nodeDistanceCmpFactory(targetNodeId: NodeId): (nodeId1: NodeId, nodeId2: NodeId) => -1 | 0 | 1; declare function bucketSortByDistance(bucket: NodeBucket, nodeId: NodeId, order?: 'asc' | 'desc'): void; declare function generateRandomDistanceForBucket(bucketIndex: NodeBucketIndex): NodeId; declare function xOrNodeId(node1: NodeId, node2: NodeId): NodeId; declare function generateRandomNodeIdForBucket(nodeId: NodeId, bucket: NodeBucketIndex): NodeId; /** * This is used to check if the given error is the result of a connection failure. * Connection failures can happen due to the following. * Failure to establish a connection, * an existing connection fails, * the RPC client has been destroyed, * or the NodeConnection has been destroyed. * This is generally used to check the connection has failed * before cleaning it up. */ declare function isConnectionError(e: unknown): boolean; /** * This generates a random delay based on the given delay and jitter multiplier. * For example, a delay of 100 and multiplier of 0.5 would result in a delay * randomly between 50 and 150. * @param delay - base delay to 'jitter' around * @param jitterMultiplier - jitter amount as a multiple of the delay */ declare function refreshBucketsDelayJitter(delay: number, jitterMultiplier: number): number; /** * Converts transport level error reasons to codes for the quic system. * * Any unknown reasons default to code 0. * */ declare const reasonToCode: (_type: 'read' | 'write', reason?: any) => number; /** * Converts any codes from the quic system back to reasons * @param _type * @param code */ declare const codeToReason: (_type: 'read' | 'write', code: number) => any; declare function parseRemoteCertsChain(remoteCertChain: Array): { nodeId: NodeId; certChain: Readonly[]; }; /** * Returns the associated hostname for a network. (`testnet.polykey.com`, etc.) */ declare function parseNetwork(data: any): Hostname; /** * Takes in a hostname/domain and performs a DNS resolution for related seednode services. */ declare function resolveSeednodes(hostname: Hostname, resolveSrv?: (hostname: string) => Promise>): Promise; /** * Seed nodes expected to be of form 'nodeId1@host:port;nodeId2@host:port;...' * By default, any specified seed nodes (in CLI option, or environment variable) * will overwrite the default nodes in src/config.ts. * Special flag `` indicates that the default seed * nodes should be added to the starting seed nodes instead of being overwritten */ declare function parseSeedNodes(data: any): [SeedNodes, boolean]; /** * Verify the server certificate chain when connecting to it from a client * This is a custom verification intended to verify that the server owned * the relevant NodeId. * It is possible that the server has a new NodeId. In that case we will * verify that the new NodeId is the true descendant of the target NodeId. */ declare function verifyServerCertificateChain(nodeIds: Array, certs: Array): Promise<{ result: 'success'; nodeId: NodeId; } | { result: 'fail'; value: native.CryptoError; }>; /** * Verify the client certificate chain when it connects to the server. * The server does have a target NodeId. This means we verify the entire chain. */ declare function verifyClientCertificateChain(certs: Array): Promise; /** * QUIC Client Crypto * This uses the keys utilities which uses `allocUnsafeSlow`. * This ensures that the underlying buffer is not shared. * Also all node buffers satisfy the `ArrayBuffer` interface. */ declare const quicClientCrypto: QUICClientCrypto; /** * QUIC Server Crypto * This uses the keys utilities which uses `allocUnsafeSlow`. * This ensures that the underlying buffer is not shared. * Also all node buffers satisfy the `ArrayBuffer` interface. */ declare const quicServerCrypto: QUICServerCrypto; declare function collectNodeContacts(levelPath: LevelPath, tran: DBTransaction, ctx: ContextTimed, options?: { reverse?: boolean; lt?: LevelPath; gt?: LevelPath; limit?: number; pathAdjust?: KeyPath; }): AsyncGenerator<[NodeId, NodeContact], void>; declare function nodesAuthenticateConnectionForwardDefault(): Promise; declare function nodesAuthenticateConnectionReverseDefault(): Promise; declare function nodesAuthenticateConnectionForwardBasicPublicFactory(networkId: string): AuthenticateNetworkForwardCallback; declare function nodesAuthenticateConnectionReverseBasicPublicFactory(networkId: string): AuthenticateNetworkReverseCallback; declare function nodesAuthenticateConnectionReverseDeny(): Promise; declare function nodesAuthenticationConnectionForwardPrivateFactory(networkAccessClaim: Token): AuthenticateNetworkForwardCallback; declare function nodesAuthenticationConnectionReversePrivateFactory(networkAccessClaim: Token): AuthenticateNetworkReverseCallback; export { sepBuffer, nodeContactAddress, bucketIndex, bucketKey, bucketsDbKey, bucketDbKey, connectedKey, parseConnectedKey, parseNodeContactAddress, parseNodeAddressKey, parseBucketsDbKey, parseBucketDbKey, parseLastUpdatedBucketsDbKey, parseLastUpdatedBucketDbKey, nodeDistance, nodeDistanceCmpFactory, bucketSortByDistance, generateRandomDistanceForBucket, xOrNodeId, generateRandomNodeIdForBucket, isConnectionError, refreshBucketsDelayJitter, reasonToCode, codeToReason, parseRemoteCertsChain, parseNetwork, resolveSeednodes, parseSeedNodes, verifyServerCertificateChain, verifyClientCertificateChain, quicClientCrypto, quicServerCrypto, collectNodeContacts, nodesAuthenticateConnectionForwardDefault, nodesAuthenticateConnectionReverseDefault, nodesAuthenticateConnectionForwardBasicPublicFactory, nodesAuthenticateConnectionReverseBasicPublicFactory, nodesAuthenticateConnectionReverseDeny, nodesAuthenticationConnectionForwardPrivateFactory, nodesAuthenticationConnectionReversePrivateFactory, }; export { encodeNodeId, decodeNodeId } from '../ids/index.js';