Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,13 +269,12 @@ async function digestArguments() {
async function isPortAvailable(port: number): Promise<boolean> {
return new Promise((resolve, reject) => {
const server = net.createServer()
server.once("error", err => {
server.once("error", (err: NodeJS.ErrnoException) => {
server.close()
if (err["code"] == "EADDRINUSE") {
if (err.code === "EADDRINUSE") {
resolve(false)
} else {
resolve(false) // or throw error!!
// reject(err);
reject(err)
}
})

Expand Down
16 changes: 0 additions & 16 deletions src/libs/blockchain/chainBlocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import log from "src/utilities/logger"
import Block from "./block"
import Mempool from "./mempool"
import Transaction, { toTransactionsEntity } from "./transaction"
import Transaction, { toTransactionsEntity } from "./transaction"
import Datasource from "src/model/datasource"
import { Blocks } from "src/model/entities/Blocks"
import { Transactions } from "src/model/entities/Transactions"
Expand All @@ -27,21 +26,6 @@ import {
} from "@/forks/migrations/gasFeeSeparation"
import { isForkActive } from "@/forks/forkGates"
import { isForkMachineryDisabled } from "@/forks/loadForkConfig"
import tallyUpgradeVotes from "./routines/tallyUpgradeVotes"
import applyNetworkUpgrade from "./routines/applyNetworkUpgrade"
import { loadNetworkParameters } from "./routines/loadNetworkParameters"
import { NetworkUpgrade } from "@/model/entities/NetworkUpgrade"
import { NetworkUpgradeVote } from "@/model/entities/NetworkUpgradeVote"
import {
isOsDenominationMigrationApplied,
runOsDenominationMigration,
} from "@/forks/migrations/osDenomination"
import {
isGasFeeSeparationMigrationApplied,
runGasFeeSeparationMigration,
} from "@/forks/migrations/gasFeeSeparation"
import { isForkActive } from "@/forks/forkGates"
import { isForkMachineryDisabled } from "@/forks/loadForkConfig"
import type { FindManyOptions } from "typeorm"

export function isGenesis(block: Block): boolean {
Expand Down
3 changes: 1 addition & 2 deletions src/libs/blockchain/mempool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ export default class Mempool {
hashes: string[],
transactionalEntityManager?: EntityManager,
) {
// REVIEW: CRITICAL FIX - Support transactional entity manager for atomic operations
// When called within a transaction, use the transactional manager to ensure atomicity
// Use transactional EM for atomicity if provided by caller
const repo = transactionalEntityManager
? transactionalEntityManager.getRepository(this.repo.target)
: this.repo
Expand Down
15 changes: 12 additions & 3 deletions src/libs/communications/broadcastManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Block from "../blockchain/block"
import Chain from "../blockchain/chain"
import { Peer, PeerManager } from "../peer"
import { syncBlock } from "../blockchain/routines/Sync"
import { RPCRequest } from "@kynesyslabs/demosdk/types"
import { RPCRequest, RPCResponse } from "@kynesyslabs/demosdk/types"
import { Waiter } from "@/utilities/waiter"
import { getSharedState } from "@/utilities/sharedState"
import SecretaryManager from "../consensus/v2/types/secretaryManager"
Expand Down Expand Up @@ -47,10 +47,15 @@ export class BroadcastManager {
}
})

const responses = await Promise.all(promises)
type BroadcastResult = { pubkey: string; result: RPCResponse }
const settled = await Promise.allSettled(promises)
const responses = settled
.filter((r): r is PromiseFulfilledResult<BroadcastResult> => r.status === "fulfilled")
.map(r => r.value)
const successful = responses.filter(res => res.result.result === 200)

for (const res of responses) {
if (res.result.result !== 200) continue
await this.handleUpdatePeerSyncData(
res.pubkey,
res.result.response.syncData,
Expand Down Expand Up @@ -194,7 +199,11 @@ export class BroadcastManager {
}
})

const responses = await Promise.all(promises)
type SyncResult = { pubkey: string; result: RPCResponse }
const settled = await Promise.allSettled(promises)
const responses = settled
.filter((r): r is PromiseFulfilledResult<SyncResult> => r.status === "fulfilled")
.map(r => r.value)
const successful = responses.filter(res => res.result.result === 200)

for (const res of responses) {
Expand Down
4 changes: 1 addition & 3 deletions src/libs/consensus/v2/PoRBFT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,7 @@ export async function consensusRoutine(): Promise<void> {
// Prune the mempool of the failed txs
// NOTE The mempool should now be updated with only the successful txs
const pruneStart = Date.now()
for (const tx of failedTxs) {
await Mempool.removeTransactionsByHashes([tx])
}
await Mempool.removeTransactionsByHashes(failedTxs)
const pruneEnd = Date.now()
log.only(
`[consensusRoutine] Prune took ${pruneEnd - pruneStart}ms with ${failedTxs.length} failed txs`,
Expand Down
12 changes: 11 additions & 1 deletion src/libs/network/bunServer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Server } from "bun"
import { Headers } from "node-fetch"
import log from "@/utilities/logger"
import { handleError } from "src/errors"

export type BunRequest = Request & { params: Record<string, string> }
export type Handler = (req: BunRequest) => Promise<Response> | Response
Expand Down Expand Up @@ -126,7 +127,12 @@
}

// Execute the complete chain
return await handler()
try {
return await handler()
} catch (err) {
handleError(err, "NETWORK", { source: "bunServer.handleRequest", path: (req as Request).url })

Check warning on line 133 in src/libs/network/bunServer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This assertion is unnecessary since it does not change the type of the expression.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo5ewC04PLFhxj3H&open=AZ5zzo5ewC04PLFhxj3H&pullRequest=882
return jsonResponse({ error: "Internal error" }, 500)
}
}

start(): Server {
Expand All @@ -136,6 +142,10 @@
fetch: async (req, server) => {
return await this.handleRequest(req, server)
},
error(err) {
handleError(err, "NETWORK", { source: "bun_serve" })
return new Response(JSON.stringify({ error: "Internal error" }), { status: 500, headers: { "content-type": "application/json" } })
},
})
return this.server
}
Expand Down
36 changes: 30 additions & 6 deletions src/libs/network/handlers/blockHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,36 @@

getLastBlockNumber: async (_data, response) => {
log.debug("[SERVER] Received getLastBlockNumber")
response.response = await Chain.getLastBlockNumber()
log.debug("[CHAIN] Received reply from the database")
try {
response.response = await Chain.getLastBlockNumber()
log.debug("[CHAIN] Received reply from the database")
} catch (e) {
response.result = 503
response.response = "STATE_NOT_READY"
response.extra = { message: e instanceof Error ? e.message : String(e) }

Check warning on line 83 in src/libs/network/handlers/blockHandlers.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'e' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo3_wC04PLFhxj27&open=AZ5zzo3_wC04PLFhxj27&pullRequest=882
}
return response
},

getLastBlock: async (_data, response) => {
response.response = await Chain.getLastBlock()
try {
response.response = await Chain.getLastBlock()
} catch (e) {
response.result = 503
response.response = "STATE_NOT_READY"
response.extra = { message: e instanceof Error ? e.message : String(e) }

Check warning on line 94 in src/libs/network/handlers/blockHandlers.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'e' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo3_wC04PLFhxj28&open=AZ5zzo3_wC04PLFhxj28&pullRequest=882
}
return response
},

getLastBlockHash: async (_data, response) => {
response.response = await Chain.getLastBlockHash()
try {
response.response = await Chain.getLastBlockHash()
} catch (e) {
response.result = 503
response.response = "STATE_NOT_READY"
response.extra = { message: e instanceof Error ? e.message : String(e) }

Check warning on line 105 in src/libs/network/handlers/blockHandlers.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'e' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo3_wC04PLFhxj29&open=AZ5zzo3_wC04PLFhxj29&pullRequest=882
}
return response
},

Expand Down Expand Up @@ -115,7 +133,7 @@
} catch (e) {
response.response = null
response.result = 400
response.extra = e
response.extra = { message: e instanceof Error ? e.message : String(e) }

Check warning on line 136 in src/libs/network/handlers/blockHandlers.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'e' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo3_wC04PLFhxj2-&open=AZ5zzo3_wC04PLFhxj2-&pullRequest=882
}
return response
},
Expand All @@ -126,7 +144,13 @@
response.response = "No block hash specified"
return response
}
response.response = await Chain.getBlockTransactions(data.blockHash)
try {
response.response = await Chain.getBlockTransactions(data.blockHash)
} catch (e) {
response.result = 503
response.response = "STATE_NOT_READY"
response.extra = { message: e instanceof Error ? e.message : String(e) }

Check warning on line 152 in src/libs/network/handlers/blockHandlers.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'e' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo3_wC04PLFhxj2_&open=AZ5zzo3_wC04PLFhxj2_&pullRequest=882
}
return response
},
}
2 changes: 1 addition & 1 deletion src/libs/network/handlers/identityHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
} catch (error) {
response.result = 400
response.response = "error"
response.extra = error
response.extra = { message: error instanceof Error ? error.message : String(error) }

Check warning on line 24 in src/libs/network/handlers/identityHandlers.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'error' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo34wC04PLFhxj26&open=AZ5zzo34wC04PLFhxj26&pullRequest=882
}
return response
},
Expand Down
8 changes: 5 additions & 3 deletions src/libs/network/manageP2P.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
// Multiton class to manage P2P connections and sessions
export default class DemosP2P {

private static instances: Map<string, DemosP2P>
private static instances: Map<string, DemosP2P> = new Map()

// SECTION Properties and constructor

Expand All @@ -33,6 +33,7 @@
constructor(partecipants: [string, string]) {
this.partecipants = partecipants
this.sessionId = DemosP2P.getSessionId(partecipants[0], partecipants[1])
this.messages = new Map()
}

// SECTION Static methods
Expand Down Expand Up @@ -65,12 +66,13 @@
// Relay a message to the other partecipant
public relayMessage(message: Message): void {
// ! TODO Signature verification
this.messages.get(message.publicKey).push(message)
if (!this.messages.has(message.publicKey)) this.messages.set(message.publicKey, [])
this.messages.get(message.publicKey)!.push(message)

Check warning on line 70 in src/libs/network/manageP2P.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This assertion is unnecessary since it does not change the type of the expression.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo5swC04PLFhxj3I&open=AZ5zzo5swC04PLFhxj3I&pullRequest=882
}

// Get the messages for the partecipant and mark them as read
public getMessagesForPartecipant(publicKey: string): Message[] {
const messages = this.messages.get(publicKey)
const messages = this.messages.get(publicKey) ?? []
for (const message of messages) {
message.read = true
}
Expand Down
6 changes: 3 additions & 3 deletions src/libs/network/middleware/rateLimiter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@
15 * 60 * 1000,
)

this.loadIPs()
void this.loadIPs()

Check failure on line 277 in src/libs/network/middleware/rateLimiter.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this asynchronous operation outside of the constructor.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo4kwC04PLFhxj3C&open=AZ5zzo4kwC04PLFhxj3C&pullRequest=882
}

/**
Expand Down Expand Up @@ -375,12 +375,12 @@
}
}

private loadIPs(): void {
private async loadIPs(): Promise<void> {
const filePath = "blocked_ips.json"

try {
const data: Record<string, RateLimitData> = JSON.parse(
fs.readFileSync(filePath, "utf8"),
await fs.promises.readFile(filePath, "utf8"),
)

// load each IP and its RateLimitData to this.ipRequests
Expand Down
2 changes: 1 addition & 1 deletion src/libs/network/routines/normalizeWebBuffers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
return [Buffer.from(bufferized.data), null]
}
} catch (e) {
return [null, e["message"]]
return [null, e instanceof Error ? e.message : String(e)]

Check warning on line 28 in src/libs/network/routines/normalizeWebBuffers.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'e' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzoyvwC04PLFhxj25&open=AZ5zzoyvwC04PLFhxj25&pullRequest=882
}
}
2 changes: 1 addition & 1 deletion src/libs/network/rpcDispatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
)
}

export async function processPayload(

Check failure on line 65 in src/libs/network/rpcDispatch.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 24 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo4IwC04PLFhxj3A&open=AZ5zzo4IwC04PLFhxj3A&pullRequest=882
payload: RPCRequest,
sender: string,
): Promise<RPCResponse> {
Expand Down Expand Up @@ -131,7 +131,7 @@
response: "Error in nodeCall: ",
require_reply: false,
extra: {
error: error.toString(),
error: error instanceof Error ? error.message : String(error),

Check warning on line 134 in src/libs/network/rpcDispatch.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'error' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo4IwC04PLFhxj3B&open=AZ5zzo4IwC04PLFhxj3B&pullRequest=882
},
}
}
Expand Down
22 changes: 15 additions & 7 deletions src/libs/network/server_rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
})
})

server.get("/health", async () => {

Check failure on line 78 in src/libs/network/server_rpc.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 24 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo5KwC04PLFhxj3D&open=AZ5zzo5KwC04PLFhxj3D&pullRequest=882
// PR #797 contract — preserve every field so SDK probes do not
// break. New blocks are additive (Epic 13 T7):
// - `status`: ok | degraded | dormant | failing
Expand All @@ -96,7 +96,7 @@
try {
mempoolSize = await Mempool.count()
} catch (err) {
log.error("[/health] Mempool.count() failed:", err)
log.error("[/health] Mempool.count() failed: " + (err instanceof Error ? err.message : String(err)))

Check warning on line 99 in src/libs/network/server_rpc.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'err' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo5KwC04PLFhxj3E&open=AZ5zzo5KwC04PLFhxj3E&pullRequest=882
}

const subsystems = snapshotSubsystems(getSharedState.subsystems)
Expand Down Expand Up @@ -237,14 +237,22 @@
})

server.get("/genesis", async () => {
const genesisBlock = await Chain.getGenesisBlock()
let genesisData = genesisBlock.content.extra?.genesisData || null
try {
const genesisBlock = await Chain.getGenesisBlock()
let genesisData = genesisBlock.content.extra?.genesisData || null

if (typeof genesisData === "string") {
try {
genesisData = JSON.parse(genesisData)
} catch (_e) {
return jsonResponse({ result: 503, response: "STATE_NOT_READY", extra: { message: "Corrupt genesis data" } }, 503)
}

Check warning on line 249 in src/libs/network/server_rpc.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Handle this exception or don't catch it at all.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo5KwC04PLFhxj3F&open=AZ5zzo5KwC04PLFhxj3F&pullRequest=882
}

if (typeof genesisData === "string") {
genesisData = JSON.parse(genesisData)
return jsonResponse(genesisData)
} catch (e) {
return jsonResponse({ result: 503, response: "STATE_NOT_READY", extra: { message: e instanceof Error ? e.message : String(e) } }, 503)

Check warning on line 254 in src/libs/network/server_rpc.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'e' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo5KwC04PLFhxj3G&open=AZ5zzo5KwC04PLFhxj3G&pullRequest=882
}

return jsonResponse(genesisData)
})

server.get("/rate-limit/stats", () => {
Expand Down
3 changes: 1 addition & 2 deletions src/libs/omniprotocol/transport/ConnectionPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -758,8 +758,7 @@ export class ConnectionPool extends EventEmitter {
}

if (!this.instance && !rateLimiter) {
log.error("Connection Pool not initialized")
process.exit(1)
throw new Error("ConnectionPool not initialised: must call getInstance(rateLimiter) before getInstance()")
}

return this.instance
Expand Down
3 changes: 2 additions & 1 deletion src/libs/omniprotocol/transport/PeerConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,7 @@
* Handle an incoming request from peer
* Performs authentication, rate limiting, and dispatches to appropriate handler
*/
private async handleIncomingRequest(

Check failure on line 787 in src/libs/omniprotocol/transport/PeerConnection.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 17 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo71wC04PLFhxj3Q&open=AZ5zzo71wC04PLFhxj3Q&pullRequest=882
header: OmniMessageHeader,
payload: Buffer,
auth: AuthBlock | null,
Expand Down Expand Up @@ -885,9 +885,10 @@
`[PeerConnection] ${this._peerIdentity} handler error: ${error}`,
)

handleError(error, "NETWORK", { source: "PeerConnection.handler" })
// Send error response
const errorPayload = Buffer.from(
JSON.stringify({ error: String(error) }),
JSON.stringify({ error: error instanceof Error ? error.message : String(error) }),

Check warning on line 891 in src/libs/omniprotocol/transport/PeerConnection.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'error' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo71wC04PLFhxj3R&open=AZ5zzo71wC04PLFhxj3R&pullRequest=882
)
await this.sendResponse(header.sequence, errorPayload)
}
Expand Down
10 changes: 7 additions & 3 deletions src/libs/peer/Peer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@
}

// Single HTTP call (no retry logic - use longCall for retries)
async httpCall(

Check failure on line 271 in src/libs/peer/Peer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 16 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo7awC04PLFhxj3N&open=AZ5zzo7awC04PLFhxj3N&pullRequest=882
request: RPCRequest,
isAuthenticated = true,
): Promise<RPCResponse> {
Expand Down Expand Up @@ -382,7 +382,7 @@

return {
result: 500,
response: error,
response: error instanceof Error ? error.message : String(error),

Check warning on line 385 in src/libs/peer/Peer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'error' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo7awC04PLFhxj3O&open=AZ5zzo7awC04PLFhxj3O&pullRequest=882
require_reply: false,
extra: null,
}
Expand All @@ -400,8 +400,12 @@
}
const url = this.connection.string + "/" + endpoint
log.info("[Fetch] Making fetch call to: " + url)
const response = await axios.get(url)
return response.data
try {
const response = await axios.get(url)
return response.data
} catch (e) {
return { status: 0, error: e instanceof Error ? e.message : String(e) }

Check warning on line 407 in src/libs/peer/Peer.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'e' will use Object's default stringification format ('[object Object]') when stringified.

See more on https://sonarcloud.io/project/issues?id=kynesyslabs_node&issues=AZ5zzo7awC04PLFhxj3P&open=AZ5zzo7awC04PLFhxj3P&pullRequest=882
}
}

async getInfo(): Promise<any> {
Expand Down
Loading
Loading