diff --git a/src/config/server.ts b/src/config/server.ts index 32834ba73..4fd5d0b11 100644 --- a/src/config/server.ts +++ b/src/config/server.ts @@ -175,7 +175,8 @@ const SERVER_CONFIG: StrictServerConfiguration = { networkTransactionsToProcessPerCycle: 20, getTxTimestampTimeoutOffset: 0, dropNGTByGossipEnabled: false, - timestampCacheFixSize: 10000 + timestampCacheFixSize: 10000, + removedNodeIDCacheSize: 1000 }, ip: { externalIp: '0.0.0.0', diff --git a/src/p2p/NodeList.ts b/src/p2p/NodeList.ts index ce2ba2876..c25071d4f 100644 --- a/src/p2p/NodeList.ts +++ b/src/p2p/NodeList.ts @@ -3,7 +3,14 @@ import { P2P } from '@shardeum-foundation/lib-types' import { Logger } from 'log4js' import { isDebugModeMiddleware, isDebugModeMiddlewareLow } from '../network/debugMiddleware' import { ShardusEvent } from '../shardus/shardus-types' -import { binarySearch, getTime, insertSorted, linearInsertSorted, propComparator, propComparator2 } from '../utils' +import { + binarySearch, + FIFOCache, + insertSorted, + linearInsertSorted, + propComparator, + propComparator2 +} from '../utils' import * as Comms from './Comms' import { config, crypto, logger, network } from './Context' import * as CycleChain from './CycleChain' @@ -41,6 +48,10 @@ export let readyByTimeAndIdOrder: P2P.NodeListTypes.Node[] export let activeOthersByIdOrder: P2P.NodeListTypes.Node[] export let potentiallyRemoved: Set export let selectedById: Map +export let removedNodeIDCache: FIFOCache< + P2P.NodeListTypes.Node['id'], + P2P.NodeListTypes.Node['publicKey'] +> const VERBOSE = false // Use to dump complete NodeList and CycleChain data @@ -179,6 +190,10 @@ export function addNodes(newNodes: P2P.NodeListTypes.Node[], caller: string) { } } +export function getRemovedNodePubKeyFromCache(nodeId: P2P.NodeListTypes.Node['id']) { + return removedNodeIDCache.get(nodeId); +} + export function removeSelectedNode(id: string) { selectedById.delete(id) const idx = binarySearch(selectedByIdOrder, { id }, propComparator('id')) @@ -264,6 +279,14 @@ export function removeNode( selectedById.delete(id) //readyByTimeAndIdOrder = readyByTimeAndIdOrder.filter((node) => node.id !== id) + // add to removed node cache + if (!removedNodeIDCache) { + removedNodeIDCache = new FIFOCache( + config.p2p.removedNodeIDCacheSize + ) + } + removedNodeIDCache.set(id, node.publicKey) + Comms.evictCachedSockets([node]) if (raiseEvents) { diff --git a/src/p2p/ServiceQueue.ts b/src/p2p/ServiceQueue.ts index 6a88cc716..03d1af923 100644 --- a/src/p2p/ServiceQueue.ts +++ b/src/p2p/ServiceQueue.ts @@ -533,6 +533,15 @@ export function sendRequests(): void { /** Module Functions */ +export function containsTx(txHash: string): boolean { + return txList.some((entry) => entry.hash === txHash) +} + +export function containsTxData(txData: OpaqueTransaction): boolean { + const hash = crypto.hash(txData) + return containsTx(hash) +} + export function registerShutdownHandler( type: string, handler: ( diff --git a/src/p2p/Wrapper.ts b/src/p2p/Wrapper.ts index 4395ed66c..613507e89 100644 --- a/src/p2p/Wrapper.ts +++ b/src/p2p/Wrapper.ts @@ -175,6 +175,10 @@ class State extends EventEmitter { return NodeList.nodes.get(id) } + getRemovedNodePubKeyFromCache(id: string): P2PTypings.NodeListTypes.Node['publicKey'] | undefined { + return NodeList.getRemovedNodePubKeyFromCache(id) + } + getNodes() { return NodeList.nodes } diff --git a/src/shardus/index.ts b/src/shardus/index.ts index 0e1bf7e10..80d68a1ed 100644 --- a/src/shardus/index.ts +++ b/src/shardus/index.ts @@ -139,15 +139,15 @@ interface Shardus { registerExternalPut: RouteHandlerRegister registerExternalDelete: RouteHandlerRegister registerExternalPatch: RouteHandlerRegister - registerBeforeAddVerifier: (type: string, verifier: (tx: OpaqueTransaction) => Promise) => void - registerApplyVerifier: (type: string, verifier: (tx: OpaqueTransaction) => Promise) => void - registerShutdownHandler: ( - type: string, - handler: ( - activeNode: P2P.NodeListTypes.Node, - record: P2P.CycleCreatorTypes.CycleRecord - ) => Omit | null | undefined - ) => void + serviceQueue: { + registerBeforeAddVerifier: typeof ServiceQueue.registerBeforeAddVerifier + registerApplyVerifier: typeof ServiceQueue.registerApplyVerifier + registerShutdownHandler: typeof ServiceQueue.registerShutdownHandler + containsTxData: typeof ServiceQueue.containsTxData + containsTx: typeof ServiceQueue.containsTx + addNetworkTx: typeof ServiceQueue.addNetworkTx + getLatestNetworkTxEntryForSubqueueKey: typeof ServiceQueue.getLatestNetworkTxEntryForSubqueueKey + } _listeners: any appliedConfigChanges: Set @@ -265,10 +265,16 @@ class Shardus extends EventEmitter { this.registerExternalPatch = (route, authHandler, handler) => this.network.registerExternalPatch(route, authHandler, handler) - this.registerBeforeAddVerifier = ServiceQueue.registerBeforeAddVerifier - this.registerApplyVerifier = ServiceQueue.registerApplyVerifier - this.registerApplyVerifier = ServiceQueue.registerApplyVerifier - this.registerShutdownHandler = ServiceQueue.registerShutdownHandler + // serviceQueue module + this.serviceQueue = { + registerBeforeAddVerifier: ServiceQueue.registerBeforeAddVerifier, + registerApplyVerifier: ServiceQueue.registerApplyVerifier, + registerShutdownHandler: ServiceQueue.registerShutdownHandler, + containsTxData: ServiceQueue.containsTxData, + containsTx: ServiceQueue.containsTx, + addNetworkTx: ServiceQueue.addNetworkTx, + getLatestNetworkTxEntryForSubqueueKey: ServiceQueue.getLatestNetworkTxEntryForSubqueueKey + } this.exitHandler.addSigListeners() this.exitHandler.registerSync('reporter', () => { @@ -1808,6 +1814,10 @@ class Shardus extends EventEmitter { return this.p2p.state.getNode(id) } + getRemovedNodePubKeyFromCache(id: string): ShardusTypes.Node['publicKey'] | undefined { + return this.p2p.state.getRemovedNodePubKeyFromCache(id) + } + getNodeByPubKey(id: string): ShardusTypes.Node { return this.p2p.state.getNodeByPubKey(id) } diff --git a/src/shardus/shardus-types.ts b/src/shardus/shardus-types.ts index c773ad3c6..98cf8c1e4 100644 --- a/src/shardus/shardus-types.ts +++ b/src/shardus/shardus-types.ts @@ -761,7 +761,7 @@ export interface ServerConfiguration { enableProblematicNodeRemoval?: boolean /** when true, we will remove problematic nodes even when calculateToAcceptV2 says we should not remove any nodes. This is useful in development when testing this feature. */ enableDangerousProblematicNodeRemoval?: boolean - /** enable problematic node removal on a specific cycle. This is to allow the network to stabilize before removing problematic nodes. + /** enable problematic node removal on a specific cycle. This is to allow the network to stabilize before removing problematic nodes. * enableProblematicNodeRemoval must be true for this to take effect*/ enableProblematicNodeRemovalOnCycle?: number /** The problematicNodeRemovalCycleFrequency parameter is an Integer specifying the number of cycles between problematic node removals. */ @@ -986,6 +986,8 @@ export interface ServerConfiguration { getTxTimestampTimeoutOffset?: number // default timeout is 5 seconds so this can be used to add or subtract time from that /** allow dropping NGTs by hitting a single node's endpoint and the drop mesage being sent to other nodes by gossip */ dropNGTByGossipEnabled: boolean + // cache size for mapping of nodeId to pubKey for the `n` last removed nodes + removedNodeIDCacheSize: number timestampCacheFixSize: number } /** Server IP configuration */