diff --git a/packages/cactus-plugin-satp-hermes/package.json b/packages/cactus-plugin-satp-hermes/package.json index fe12890e3f..244474a1ed 100644 --- a/packages/cactus-plugin-satp-hermes/package.json +++ b/packages/cactus-plugin-satp-hermes/package.json @@ -89,7 +89,7 @@ "db:migrate": "knex migrate:latest --knexfile src/knex/knexfile.js", "db:migrate:production": "knex migrate:latest --env production --knexfile src/knex/knexfile.ts", "db:seed": "knex seed:run --knexfile src/knex/knexfile.ts", - "db:cleanup": "find src/knex/data -name '.dev-*.sqlite3' -delete" + "db:cleanup": "find src/knex/ -name '.dev.local-*.sqlite3' -delete" }, "jest": { "moduleNameMapper": { @@ -137,6 +137,7 @@ "kubo-rpc-client": "3.0.1", "npm-run-all": "4.1.5", "openzeppelin-solidity": "3.4.2", + "pg": "8.13.1", "safe-stable-stringify": "2.5.0", "secp256k1": "4.0.3", "socket.io": "4.6.2", @@ -160,6 +161,7 @@ "@types/fs-extra": "11.0.4", "@types/google-protobuf": "3.15.12", "@types/node": "18.18.2", + "@types/pg": "8.11.10", "@types/swagger-ui-express": "4.1.6", "@types/tape": "4.13.4", "@types/uuid": "10.0.0", diff --git a/packages/cactus-plugin-satp-hermes/src/knex/knexfile-remote.ts b/packages/cactus-plugin-satp-hermes/src/knex/knexfile-remote.ts index 98a8c4332c..1a0bd3709a 100644 --- a/packages/cactus-plugin-satp-hermes/src/knex/knexfile-remote.ts +++ b/packages/cactus-plugin-satp-hermes/src/knex/knexfile-remote.ts @@ -1,11 +1,12 @@ import path from "path"; import { v4 as uuidv4 } from "uuid"; import dotenv from "dotenv"; +import { Knex } from "knex"; const envPath = process.env.ENV_PATH; dotenv.config({ path: envPath }); -module.exports = { +const config: { [key: string]: Knex.Config } = { development: { client: "sqlite3", connection: { @@ -20,7 +21,7 @@ module.exports = { client: "pg", connection: { host: process.env.DB_HOST, - port: process.env.DB_PORT, + port: Number(process.env.DB_PORT), user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, @@ -30,3 +31,5 @@ module.exports = { }, }, }; + +export default config; diff --git a/packages/cactus-plugin-satp-hermes/src/knex/knexfile.ts b/packages/cactus-plugin-satp-hermes/src/knex/knexfile.ts index 9bf0da1e63..9c7535ea11 100644 --- a/packages/cactus-plugin-satp-hermes/src/knex/knexfile.ts +++ b/packages/cactus-plugin-satp-hermes/src/knex/knexfile.ts @@ -1,15 +1,16 @@ import path from "path"; import { v4 as uuidv4 } from "uuid"; import dotenv from "dotenv"; +import { Knex } from "knex"; const envPath = process.env.ENV_PATH; dotenv.config({ path: envPath }); -module.exports = { +const config: { [key: string]: Knex.Config } = { development: { client: "sqlite3", connection: { - filename: path.join(__dirname, "data", "/.dev-" + uuidv4() + ".sqlite3"), + filename: path.resolve(__dirname, `.dev.local-${uuidv4()}.sqlite3`), }, migrations: { directory: path.resolve(__dirname, "migrations"), @@ -23,7 +24,7 @@ module.exports = { client: "pg", connection: { host: process.env.DB_HOST, - port: process.env.DB_PORT, + port: Number(process.env.DB_PORT), user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, @@ -33,3 +34,5 @@ module.exports = { }, }, }; + +export default config; diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/blo/dispatcher.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/blo/dispatcher.ts index 17399ca618..9526c0408e 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/blo/dispatcher.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/blo/dispatcher.ts @@ -32,6 +32,10 @@ import { IntegrationsEndpointV1 } from "../web-services/integrations-endpoint"; import { executeGetHealthCheck } from "./admin/get-healthcheck-handler-service"; import { executeGetStatus } from "./admin/get-status-handler-service"; import { executeTransact } from "./transaction/transact-handler-service"; +import { + ILocalLogRepository, + IRemoteLogRepository, +} from "../repository/interfaces/repository"; export interface BLODispatcherOptions { logger: Logger; @@ -41,6 +45,8 @@ export interface BLODispatcherOptions { signer: JsObjectSigner; bridgesManager: SATPBridgesManager; pubKey: string; + localRepository: ILocalLogRepository; + remoteRepository: IRemoteLogRepository; } export class BLODispatcher { @@ -54,6 +60,8 @@ export class BLODispatcher { private manager: SATPManager; private orchestrator: GatewayOrchestrator; private bridgeManager: SATPBridgesManager; + private localRepository: ILocalLogRepository; + private remoteRepository: IRemoteLogRepository; constructor(public readonly options: BLODispatcherOptions) { const fnTag = `${BLODispatcher.CLASS_NAME}#constructor()`; @@ -61,12 +69,17 @@ export class BLODispatcher { this.level = this.options.logLevel || "INFO"; this.label = this.className; - this.logger = LoggerProvider.getOrCreate({ level: this.level, label: this.label }); + this.logger = LoggerProvider.getOrCreate({ + level: this.level, + label: this.label, + }); this.instanceId = options.instanceId; this.logger.info(`Instantiated ${this.className} OK`); this.orchestrator = options.orchestrator; const signer = options.signer; const ourGateway = this.orchestrator.ourGateway; + this.localRepository = options.localRepository; + this.remoteRepository = options.remoteRepository; this.bridgeManager = options.bridgesManager; @@ -78,6 +91,8 @@ export class BLODispatcher { bridgeManager: this.bridgeManager, orchestrator: this.orchestrator, pubKey: options.pubKey, + localRepository: this.localRepository, + remoteRepository: this.remoteRepository, }; this.manager = new SATPManager(SATPManagerOpts); diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage0-client-service.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage0-client-service.ts index df63ac5081..6081646c5c 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage0-client-service.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage0-client-service.ts @@ -63,6 +63,7 @@ export class Stage0ClientService extends SATPService { serviceName: ops.serviceName, signer: ops.signer, serviceType: Stage0ClientService.SERVICE_TYPE, + dbLogger: ops.dbLogger, }; super(commonOptions); if (ops.bridgeManager == undefined) { @@ -79,45 +80,83 @@ export class Stage0ClientService extends SATPService { ): Promise { const stepTag = `newSessionRequest()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.NEW_SESSION_REQUEST]; if (session == undefined) { throw new SessionError(fnTag); } session.verify(fnTag, SessionType.CLIENT); - const sessionData = session.getClientSessionData(); - const newSessionRequestMessage = create(NewSessionRequestMessageSchema, { - sessionId: sessionData.id, - contextId: sessionData.transferContextId, - recipientGatewayNetworkId: sessionData.recipientGatewayNetworkId, - senderGatewayNetworkId: sessionData.senderGatewayNetworkId, - gatewayId: thisGatewayId, - messageType: MessageType.NEW_SESSION_REQUEST, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(newSessionRequestMessage)), - ); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); - newSessionRequestMessage.clientSignature = messageSignature; + const newSessionRequestMessage = create(NewSessionRequestMessageSchema, { + sessionId: sessionData.id, + contextId: sessionData.transferContextId, + recipientGatewayNetworkId: sessionData.recipientGatewayNetworkId, + senderGatewayNetworkId: sessionData.senderGatewayNetworkId, + gatewayId: thisGatewayId, + messageType: MessageType.NEW_SESSION_REQUEST, + }); - saveSignature( - sessionData, - MessageType.NEW_SESSION_REQUEST, - messageSignature, - ); + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(newSessionRequestMessage)), + ); - saveHash( - sessionData, - MessageType.NEW_SESSION_REQUEST, - getHash(newSessionRequestMessage), - ); + newSessionRequestMessage.clientSignature = messageSignature; - this.Log.info(`${fnTag}, sending NewSessionRequest...`); + saveSignature( + sessionData, + MessageType.NEW_SESSION_REQUEST, + messageSignature, + ); - return newSessionRequestMessage; + saveHash( + sessionData, + MessageType.NEW_SESSION_REQUEST, + getHash(newSessionRequestMessage), + ); + + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + + this.Log.info(`${fnTag}, sending NewSessionRequest...`); + + return newSessionRequestMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } public async checkNewSessionResponse( @@ -218,6 +257,7 @@ export class Stage0ClientService extends SATPService { ): Promise { const stepTag = `preSATPTransferRequest()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.PRE_SATP_TRANSFER_REQUEST]; if (session == undefined) { throw new SessionError(fnTag); @@ -226,81 +266,136 @@ export class Stage0ClientService extends SATPService { session.verify(fnTag, SessionType.CLIENT); const sessionData = session.getClientSessionData(); + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); - if (sessionData.receiverContractOntology == "") { - //TODO check ontology - throw new OntologyContractError(fnTag); - } + if (sessionData.receiverContractOntology == "") { + //TODO check ontology + throw new OntologyContractError(fnTag); + } - if (sessionData.senderAsset?.tokenId == "") { - throw new LedgerAssetIdError(fnTag); - } + if (sessionData.senderAsset?.tokenId == "") { + throw new LedgerAssetIdError(fnTag); + } - if (sessionData.senderGatewayNetworkId == "") { - throw new GatewayNetworkIdError(fnTag); - } + if (sessionData.senderGatewayNetworkId == "") { + throw new GatewayNetworkIdError(fnTag); + } - if (sessionData.senderAsset == undefined) { - throw new LedgerAssetError(fnTag); - } + if (sessionData.senderAsset == undefined) { + throw new LedgerAssetError(fnTag); + } - if (sessionData.receiverAsset == undefined) { - throw new LedgerAssetError(fnTag); - } + if (sessionData.receiverAsset == undefined) { + throw new LedgerAssetError(fnTag); + } - const preSATPTransferRequest = create(PreSATPTransferRequestMessageSchema, { - sessionId: sessionData.id, - contextId: sessionData.transferContextId, - clientTransferNumber: sessionData.clientTransferNumber, - senderGatewayNetworkId: sessionData.senderGatewayNetworkId, - recipientGatewayNetworkId: sessionData.recipientGatewayNetworkId, - senderAsset: sessionData.senderAsset, - receiverAsset: sessionData.receiverAsset, - wrapAssertionClaim: sessionData.senderWrapAssertionClaim, - messageType: MessageType.PRE_SATP_TRANSFER_REQUEST, - }); + const preSATPTransferRequest = create( + PreSATPTransferRequestMessageSchema, + { + sessionId: sessionData.id, + contextId: sessionData.transferContextId, + clientTransferNumber: sessionData.clientTransferNumber, + senderGatewayNetworkId: sessionData.senderGatewayNetworkId, + recipientGatewayNetworkId: sessionData.recipientGatewayNetworkId, + senderAsset: sessionData.senderAsset, + receiverAsset: sessionData.receiverAsset, + wrapAssertionClaim: sessionData.senderWrapAssertionClaim, + messageType: MessageType.PRE_SATP_TRANSFER_REQUEST, + }, + ); - preSATPTransferRequest.hashPreviousMessage = getMessageHash( - sessionData, - MessageType.NEW_SESSION_RESPONSE, - ); + preSATPTransferRequest.hashPreviousMessage = getMessageHash( + sessionData, + MessageType.NEW_SESSION_RESPONSE, + ); - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(preSATPTransferRequest)), - ); + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(preSATPTransferRequest)), + ); - preSATPTransferRequest.clientSignature = messageSignature; + preSATPTransferRequest.clientSignature = messageSignature; - saveSignature( - sessionData, - MessageType.PRE_SATP_TRANSFER_REQUEST, - messageSignature, - ); + saveSignature( + sessionData, + MessageType.PRE_SATP_TRANSFER_REQUEST, + messageSignature, + ); - saveHash( - sessionData, - MessageType.PRE_SATP_TRANSFER_REQUEST, - getHash(preSATPTransferRequest), - ); + saveHash( + sessionData, + MessageType.PRE_SATP_TRANSFER_REQUEST, + getHash(preSATPTransferRequest), + ); + + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: String(MessageType.PRE_SATP_TRANSFER_REQUEST), + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); - this.Log.info(`${fnTag}, sending PreSATPTransferRequest...`); + this.Log.info(`${fnTag}, sending PreSATPTransferRequest...`); - return preSATPTransferRequest; + return preSATPTransferRequest; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } public async wrapToken(session: SATPSession): Promise { const stepTag = `wrapToken()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; - try { - this.Log.info(`${fnTag}, Wrapping Asset...`); - - if (session == undefined) { - throw new SessionError(fnTag); - } + this.Log.info(`${fnTag}, Wrapping Asset...`); + if (session == undefined) { + throw new SessionError(fnTag); + } - session.verify(fnTag, SessionType.CLIENT); + session.verify(fnTag, SessionType.CLIENT); - const sessionData = session.getClientSessionData(); + const sessionData = session.getClientSessionData(); + this.Log.info(`init-${stepTag}`); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "wrap-token", + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + try { + this.Log.info(`exec-${stepTag}`); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "wrap-token", + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, Wrapping Asset...`); if (sessionData.senderGatewayNetworkId == "") { throw new GatewayNetworkIdError(fnTag); @@ -337,11 +432,30 @@ export class Stage0ClientService extends SATPService { sessionData.senderWrapAssertionClaim.receipt = await bridge.wrapAsset(token); + sessionData.senderWrapAssertionClaim.proof = + await bridge.getProof(assetId); + sessionData.senderWrapAssertionClaim.signature = bufArray2HexStr( sign(this.Signer, sessionData.senderWrapAssertionClaim.receipt), ); + + this.dbLogger.storeProof({ + sessionID: sessionData.id, + type: "wrap-token", + operation: "done", + data: safeStableStringify(sessionData.senderWrapAssertionClaim.proof), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, done-${fnTag}`); } catch (error) { this.logger.debug(`Crash in ${fnTag}`, error); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "wrap-token", + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); throw new FailedToProcessError(fnTag, "WrapToken"); } } diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage1-client-service.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage1-client-service.ts index 481121a8c4..68a34a7d88 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage1-client-service.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage1-client-service.ts @@ -56,6 +56,7 @@ export class Stage1ClientService extends SATPService { serviceName: ops.serviceName, signer: ops.signer, serviceType: Stage1ClientService.SERVICE_TYPE, + dbLogger: ops.dbLogger, }; super(commonOptions); } @@ -67,7 +68,7 @@ export class Stage1ClientService extends SATPService { const stepTag = `transferProposalRequest()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; this.Log.debug(`${fnTag}, transferProposalRequest...`); - + const messageType = MessageType[MessageType.INIT_PROPOSAL]; if (session == undefined) { throw new SessionError(fnTag); } @@ -76,143 +77,172 @@ export class Stage1ClientService extends SATPService { const sessionData = session.getClientSessionData(); - if ( - !supportedDLTs.includes( - sessionData.senderGatewayNetworkId as SupportedChain, - ) - ) { - throw new Error( //todo change this to the transferClaims check - `${fnTag}, recipient gateway dlt system is not supported by this gateway`, - ); - } - - sessionData.lastSequenceNumber = sessionData.lastSequenceNumber + BigInt(1); - - const commonBody = create(CommonSatpSchema, { - version: sessionData.version, - messageType: MessageType.INIT_PROPOSAL, - sessionId: sessionData.id, - sequenceNumber: sessionData.lastSequenceNumber, - resourceUrl: sessionData.resourceUrl, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - hashPreviousMessage: "", - }); - - if (sessionData.transferContextId != undefined) { - commonBody.transferContextId = sessionData.transferContextId; - } - - const transferInitClaims = create(TransferClaimsSchema, { - digitalAssetId: sessionData.digitalAssetId, - assetProfileId: sessionData.assetProfileId, - verifiedOriginatorEntityId: sessionData.verifiedOriginatorEntityId, - verifiedBeneficiaryEntityId: sessionData.verifiedBeneficiaryEntityId, - originatorPubkey: sessionData.originatorPubkey, - beneficiaryPubkey: sessionData.beneficiaryPubkey, - senderGatewayNetworkId: sessionData.senderGatewayNetworkId, - recipientGatewayNetworkId: sessionData.recipientGatewayNetworkId, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - senderGatewayOwnerId: sessionData.senderGatewayOwnerId, - receiverGatewayOwnerId: sessionData.receiverGatewayOwnerId, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); - sessionData.hashTransferInitClaims = getHash(transferInitClaims); - - const networkCapabilities = create(NetworkCapabilitiesSchema, { - senderGatewayNetworkId: sessionData.senderGatewayNetworkId, - signatureAlgorithm: sessionData.signatureAlgorithm, - lockType: sessionData.lockType, - lockExpirationTime: sessionData.lockExpirationTime, - credentialProfile: sessionData.credentialProfile, - loggingProfile: sessionData.loggingProfile, - accessControlProfile: sessionData.accessControlProfile, - }); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + if ( + !supportedDLTs.includes( + sessionData.senderGatewayNetworkId as SupportedChain, + ) + ) { + throw new Error( //todo change this to the transferClaims check + `${fnTag}, recipient gateway dlt system is not supported by this gateway`, + ); + } - if (sessionData.permissions != undefined) { - this.Log.info(`${fnTag}, Optional variable loaded: permissions...`); - networkCapabilities.permissions = sessionData.permissions; - } + sessionData.lastSequenceNumber = + sessionData.lastSequenceNumber + BigInt(1); + + const commonBody = create(CommonSatpSchema, { + version: sessionData.version, + messageType: MessageType.INIT_PROPOSAL, + sessionId: sessionData.id, + sequenceNumber: sessionData.lastSequenceNumber, + resourceUrl: sessionData.resourceUrl, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + hashPreviousMessage: "", + }); + + if (sessionData.transferContextId != undefined) { + commonBody.transferContextId = sessionData.transferContextId; + } - if (sessionData.developerUrn != "") { - this.Log.info(`${fnTag}, Optional variable loaded: developerUrn...`); - networkCapabilities.developerUrn = sessionData.developerUrn; - } + const transferInitClaims = create(TransferClaimsSchema, { + digitalAssetId: sessionData.digitalAssetId, + assetProfileId: sessionData.assetProfileId, + verifiedOriginatorEntityId: sessionData.verifiedOriginatorEntityId, + verifiedBeneficiaryEntityId: sessionData.verifiedBeneficiaryEntityId, + originatorPubkey: sessionData.originatorPubkey, + beneficiaryPubkey: sessionData.beneficiaryPubkey, + senderGatewayNetworkId: sessionData.senderGatewayNetworkId, + recipientGatewayNetworkId: sessionData.recipientGatewayNetworkId, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + senderGatewayOwnerId: sessionData.senderGatewayOwnerId, + receiverGatewayOwnerId: sessionData.receiverGatewayOwnerId, + }); + + sessionData.hashTransferInitClaims = getHash(transferInitClaims); + + const networkCapabilities = create(NetworkCapabilitiesSchema, { + senderGatewayNetworkId: sessionData.senderGatewayNetworkId, + signatureAlgorithm: sessionData.signatureAlgorithm, + lockType: sessionData.lockType, + lockExpirationTime: sessionData.lockExpirationTime, + credentialProfile: sessionData.credentialProfile, + loggingProfile: sessionData.loggingProfile, + accessControlProfile: sessionData.accessControlProfile, + }); + + if (sessionData.permissions != undefined) { + this.Log.info(`${fnTag}, Optional variable loaded: permissions...`); + networkCapabilities.permissions = sessionData.permissions; + } - if (sessionData.applicationProfile != "") { - this.Log.info( - `${fnTag}, Optional variable loaded: applicationProfile...`, - ); - networkCapabilities.applicationProfile = sessionData.applicationProfile; - } + if (sessionData.developerUrn != "") { + this.Log.info(`${fnTag}, Optional variable loaded: developerUrn...`); + networkCapabilities.developerUrn = sessionData.developerUrn; + } - if (sessionData.subsequentCalls != undefined) { - this.Log.info(`${fnTag}, Optional variable loaded: subsequentCalls...`); - networkCapabilities.subsequentCalls = sessionData.subsequentCalls; - } + if (sessionData.applicationProfile != "") { + this.Log.info( + `${fnTag}, Optional variable loaded: applicationProfile...`, + ); + networkCapabilities.applicationProfile = sessionData.applicationProfile; + } - if (sessionData.history.length > 0) { - this.Log.info(`${fnTag}, Optional variable loaded: history...`); - networkCapabilities.history = sessionData.history; - } + if (sessionData.subsequentCalls != undefined) { + this.Log.info(`${fnTag}, Optional variable loaded: subsequentCalls...`); + networkCapabilities.subsequentCalls = sessionData.subsequentCalls; + } - const transferProposalRequestMessage = create( - TransferProposalRequestMessageSchema, - { - common: commonBody, - transferInitClaims: transferInitClaims, - networkCapabilities: networkCapabilities, - }, - ); + if (sessionData.history.length > 0) { + this.Log.info(`${fnTag}, Optional variable loaded: history...`); + networkCapabilities.history = sessionData.history; + } - if (sessionData.transferClaimsFormat != undefined) { - this.Log.info( - `${fnTag}, Optional variable loaded: transferInitClaimsFormat...`, - ); - transferProposalRequestMessage.transferInitClaimsFormat = - sessionData.transferClaimsFormat; - } - if (sessionData.multipleCancelsAllowed) { - this.Log.info( - `${fnTag}, Optional variable loaded: multipleCancelsAllowed...`, - ); - transferProposalRequestMessage.multipleCancelsAllowed = - sessionData.multipleCancelsAllowed; - } - if (sessionData.multipleClaimsAllowed) { - this.Log.info( - `${fnTag}, Optional variable loaded: multipleClaimsAllowed...`, + const transferProposalRequestMessage = create( + TransferProposalRequestMessageSchema, + { + common: commonBody, + transferInitClaims: transferInitClaims, + networkCapabilities: networkCapabilities, + }, ); - transferProposalRequestMessage.multipleClaimsAllowed = - sessionData.multipleClaimsAllowed; - } - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(transferProposalRequestMessage)), - ); + if (sessionData.transferClaimsFormat != undefined) { + this.Log.info( + `${fnTag}, Optional variable loaded: transferInitClaimsFormat...`, + ); + transferProposalRequestMessage.transferInitClaimsFormat = + sessionData.transferClaimsFormat; + } + if (sessionData.multipleCancelsAllowed) { + this.Log.info( + `${fnTag}, Optional variable loaded: multipleCancelsAllowed...`, + ); + transferProposalRequestMessage.multipleCancelsAllowed = + sessionData.multipleCancelsAllowed; + } + if (sessionData.multipleClaimsAllowed) { + this.Log.info( + `${fnTag}, Optional variable loaded: multipleClaimsAllowed...`, + ); + transferProposalRequestMessage.multipleClaimsAllowed = + sessionData.multipleClaimsAllowed; + } - transferProposalRequestMessage.clientSignature = messageSignature; + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(transferProposalRequestMessage)), + ); - saveSignature(sessionData, MessageType.INIT_PROPOSAL, messageSignature); + transferProposalRequestMessage.clientSignature = messageSignature; - saveHash( - sessionData, - MessageType.INIT_PROPOSAL, - getHash(transferProposalRequestMessage), - ); + saveSignature(sessionData, MessageType.INIT_PROPOSAL, messageSignature); - /* - await storeLog(gateway, { - sessionID: sessionID, - type: "transferProposalRequest", - operation: "validate", - data: safeStableStringify(sessionData), - }); - */ - this.Log.info(`${fnTag}, sending TransferProposalRequest...`); + saveHash( + sessionData, + MessageType.INIT_PROPOSAL, + getHash(transferProposalRequestMessage), + ); - return transferProposalRequestMessage; + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, sending TransferProposalRequest...`); + + return transferProposalRequestMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async transferCommenceRequest( @@ -221,6 +251,7 @@ export class Stage1ClientService extends SATPService { ): Promise { const stepTag = `transferCommenceRequest()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.TRANSFER_COMMENCE_REQUEST]; this.Log.debug(`${fnTag}, transferCommenceRequest...`); if (session == undefined) { @@ -231,60 +262,90 @@ export class Stage1ClientService extends SATPService { const sessionData = session.getClientSessionData(); - const commonBody = create(CommonSatpSchema, { - version: sessionData.version, - messageType: MessageType.TRANSFER_COMMENCE_REQUEST, - sessionId: sessionData.id, - sequenceNumber: response.common!.sequenceNumber + BigInt(1), - resourceUrl: sessionData.resourceUrl, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.INIT_RECEIPT, - ), - transferContextId: sessionData.transferContextId, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); - sessionData.lastSequenceNumber = commonBody.sequenceNumber; - - const transferCommenceRequestMessage = create( - TransferCommenceRequestMessageSchema, - { - common: commonBody, - hashTransferInitClaims: sessionData.hashTransferInitClaims, - }, - ); - - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(transferCommenceRequestMessage)), - ); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + + const commonBody = create(CommonSatpSchema, { + version: sessionData.version, + messageType: MessageType.TRANSFER_COMMENCE_REQUEST, + sessionId: sessionData.id, + sequenceNumber: response.common!.sequenceNumber + BigInt(1), + resourceUrl: sessionData.resourceUrl, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.INIT_RECEIPT, + ), + transferContextId: sessionData.transferContextId, + }); + + sessionData.lastSequenceNumber = commonBody.sequenceNumber; + + const transferCommenceRequestMessage = create( + TransferCommenceRequestMessageSchema, + { + common: commonBody, + hashTransferInitClaims: sessionData.hashTransferInitClaims, + }, + ); - transferCommenceRequestMessage.clientSignature = messageSignature; + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(transferCommenceRequestMessage)), + ); - saveSignature( - sessionData, - MessageType.TRANSFER_COMMENCE_REQUEST, - messageSignature, - ); + transferCommenceRequestMessage.clientSignature = messageSignature; - saveHash( - sessionData, - MessageType.TRANSFER_COMMENCE_REQUEST, - getHash(transferCommenceRequestMessage), - ); + saveSignature( + sessionData, + MessageType.TRANSFER_COMMENCE_REQUEST, + messageSignature, + ); - /* - await storeLog(gateway, { - sessionID: sessionData.id, - type: "transferCommenceRequest", - operation: "validate", - data: safeStableStringify(sessionData), - }); - */ - this.Log.info(`${fnTag}, sending TransferCommenceRequest...`); + saveHash( + sessionData, + MessageType.TRANSFER_COMMENCE_REQUEST, + getHash(transferCommenceRequestMessage), + ); - return transferCommenceRequestMessage; + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + + this.Log.info(`${fnTag}, sending TransferCommenceRequest...`); + + return transferCommenceRequestMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async checkPreSATPTransferResponse( diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage2-client-service.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage2-client-service.ts index 825f1f9d15..10784597e4 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage2-client-service.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage2-client-service.ts @@ -53,6 +53,7 @@ export class Stage2ClientService extends SATPService { signer: ops.signer, serviceType: Stage2ClientService.SERVICE_TYPE, bridgeManager: ops.bridgeManager, + dbLogger: ops.dbLogger, }; super(commonOptions); @@ -70,6 +71,7 @@ export class Stage2ClientService extends SATPService { ): Promise { const stepTag = `lockAssertionRequest()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.LOCK_ASSERT]; this.Log.debug(`${fnTag}, lockAssertionRequest...`); if (session == undefined) { @@ -79,85 +81,112 @@ export class Stage2ClientService extends SATPService { session.verify(fnTag, SessionType.CLIENT); const sessionData = session.getClientSessionData(); - - const commonBody = create(CommonSatpSchema, { - version: sessionData.version, - messageType: MessageType.LOCK_ASSERT, - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.TRANSFER_COMMENCE_RESPONSE, - ), - sessionId: response.common!.sessionId, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - resourceUrl: sessionData.resourceUrl, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + const commonBody = create(CommonSatpSchema, { + version: sessionData.version, + messageType: MessageType.LOCK_ASSERT, + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.TRANSFER_COMMENCE_RESPONSE, + ), + sessionId: response.common!.sessionId, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + resourceUrl: sessionData.resourceUrl, + }); + + sessionData.lastSequenceNumber = commonBody.sequenceNumber = + response.common!.sequenceNumber + BigInt(1); + + const lockAssertionRequestMessage = create( + LockAssertionRequestMessageSchema, + { + common: commonBody, + }, + ); - sessionData.lastSequenceNumber = commonBody.sequenceNumber = - response.common!.sequenceNumber + BigInt(1); - - const lockAssertionRequestMessage = create( - LockAssertionRequestMessageSchema, - { - common: commonBody, - }, - ); + if (sessionData.lockAssertionClaim == undefined) { + throw new LockAssertionClaimError(fnTag); + } + lockAssertionRequestMessage.lockAssertionClaim = + sessionData.lockAssertionClaim; - if (sessionData.lockAssertionClaim == undefined) { - throw new LockAssertionClaimError(fnTag); - } - lockAssertionRequestMessage.lockAssertionClaim = - sessionData.lockAssertionClaim; + if (sessionData.lockAssertionClaimFormat == undefined) { + throw new LockAssertionClaimFormatError(fnTag); + } + lockAssertionRequestMessage.lockAssertionClaimFormat = + sessionData.lockAssertionClaimFormat; + if ( + sessionData.lockAssertionExpiration == undefined || + sessionData.lockAssertionExpiration == BigInt(0) + ) { + throw new LockAssertionExpirationError(fnTag); + } - if (sessionData.lockAssertionClaimFormat == undefined) { - throw new LockAssertionClaimFormatError(fnTag); - } - lockAssertionRequestMessage.lockAssertionClaimFormat = - sessionData.lockAssertionClaimFormat; - if ( - sessionData.lockAssertionExpiration == undefined || - sessionData.lockAssertionExpiration == BigInt(0) - ) { - throw new LockAssertionExpirationError(fnTag); - } + lockAssertionRequestMessage.lockAssertionExpiration = + sessionData.lockAssertionExpiration; - lockAssertionRequestMessage.lockAssertionExpiration = - sessionData.lockAssertionExpiration; + if (sessionData.transferContextId != undefined) { + lockAssertionRequestMessage.common!.transferContextId = + sessionData.transferContextId; + } + if (sessionData.clientTransferNumber != undefined) { + lockAssertionRequestMessage.clientTransferNumber = + sessionData.clientTransferNumber; + } - if (sessionData.transferContextId != undefined) { - lockAssertionRequestMessage.common!.transferContextId = - sessionData.transferContextId; - } - if (sessionData.clientTransferNumber != undefined) { - lockAssertionRequestMessage.clientTransferNumber = - sessionData.clientTransferNumber; - } + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(lockAssertionRequestMessage)), + ); - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(lockAssertionRequestMessage)), - ); + lockAssertionRequestMessage.clientSignature = messageSignature; - lockAssertionRequestMessage.clientSignature = messageSignature; + saveSignature(sessionData, MessageType.LOCK_ASSERT, messageSignature); - saveSignature(sessionData, MessageType.LOCK_ASSERT, messageSignature); + saveHash( + sessionData, + MessageType.LOCK_ASSERT, + getHash(lockAssertionRequestMessage), + ); - saveHash( - sessionData, - MessageType.LOCK_ASSERT, - getHash(lockAssertionRequestMessage), - ); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); - /* - await storeLog(gateway, { - sessionID: sessionData.id, - type: "lockAssertionRequest", - operation: "lock", - data: safeStableStringify(sessionData), - }); - */ - this.Log.info(`${fnTag}, sending LockAssertionMessage...`); + this.Log.info(`${fnTag}, sending LockAssertionMessage...`); - return lockAssertionRequestMessage; + return lockAssertionRequestMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async checkTransferCommenceResponseMessage( @@ -204,17 +233,32 @@ export class Stage2ClientService extends SATPService { async lockAsset(session: SATPSession): Promise { const stepTag = `lockAsset()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; - try { - this.Log.info(`${fnTag}, Locking Asset...`); - - if (session == undefined) { - throw new SessionError(fnTag); - } - - session.verify(fnTag, SessionType.CLIENT); + this.Log.info(`${fnTag}, Locking Asset...`); + if (session == undefined) { + throw new SessionError(fnTag); + } - const sessionData = session.getClientSessionData(); + session.verify(fnTag, SessionType.CLIENT); + const sessionData = session.getClientSessionData(); + this.Log.info(`init-${stepTag}`); + this.dbLogger.storeProof({ + sessionID: sessionData.id, + type: "lock-asset", + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + try { + this.Log.info(`exec-${stepTag}`); + this.dbLogger.storeProof({ + sessionID: sessionData.id, + type: "lock-asset", + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, Locking Asset...`); const assetId = sessionData.senderAsset?.tokenId; const amount = sessionData.senderAsset?.amount; @@ -251,7 +295,23 @@ export class Stage2ClientService extends SATPService { sessionData.lockAssertionClaim.signature = bufArray2HexStr( sign(this.Signer, sessionData.lockAssertionClaim.receipt), ); + + this.dbLogger.storeProof({ + sessionID: sessionData.id, + type: "lock-asset", + operation: "done", + data: safeStableStringify(sessionData.lockAssertionClaim.proof), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, done-${fnTag}`); } catch (error) { + this.dbLogger.storeProof({ + sessionID: sessionData.id, + type: "lock-asset", + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); throw new FailedToProcessError(fnTag, "LockAsset", error); } } diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage3-client-service.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage3-client-service.ts index 3e4c084da8..351bfe0b9b 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage3-client-service.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/client/stage3-client-service.ts @@ -62,6 +62,7 @@ export class Stage3ClientService extends SATPService { signer: ops.signer, serviceType: Stage3ClientService.SERVICE_TYPE, bridgeManager: ops.bridgeManager, + dbLogger: ops.dbLogger, }; super(commonOptions); @@ -79,6 +80,7 @@ export class Stage3ClientService extends SATPService { ): Promise { const stepTag = `commitPreparation()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.COMMIT_PREPARE]; this.Log.debug(`${fnTag}, CommitPreparation...`); if (session == undefined) { @@ -88,67 +90,94 @@ export class Stage3ClientService extends SATPService { session.verify(fnTag, SessionType.CLIENT); const sessionData = session.getClientSessionData(); - - const commonBody = create(CommonSatpSchema, { - version: SATP_VERSION, - messageType: MessageType.COMMIT_PREPARE, - sequenceNumber: response.common!.sequenceNumber + BigInt(1), - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.ASSERTION_RECEIPT, - ), - sessionId: response.common!.sessionId, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - resourceUrl: sessionData.resourceUrl, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + + const commonBody = create(CommonSatpSchema, { + version: SATP_VERSION, + messageType: MessageType.COMMIT_PREPARE, + sequenceNumber: response.common!.sequenceNumber + BigInt(1), + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.ASSERTION_RECEIPT, + ), + sessionId: response.common!.sessionId, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + resourceUrl: sessionData.resourceUrl, + }); + + sessionData.lastSequenceNumber = commonBody.sequenceNumber = + response.common!.sequenceNumber + BigInt(1); + + const commitPreparationRequestMessage = create( + CommitPreparationRequestMessageSchema, + { + common: commonBody, + }, + ); - sessionData.lastSequenceNumber = commonBody.sequenceNumber = - response.common!.sequenceNumber + BigInt(1); - - const commitPreparationRequestMessage = create( - CommitPreparationRequestMessageSchema, - { - common: commonBody, - }, - ); - - if (sessionData.transferContextId != undefined) { - commitPreparationRequestMessage.common!.transferContextId = - sessionData.transferContextId; - } + if (sessionData.transferContextId != undefined) { + commitPreparationRequestMessage.common!.transferContextId = + sessionData.transferContextId; + } - if (sessionData.clientTransferNumber != undefined) { - commitPreparationRequestMessage.clientTransferNumber = - sessionData.clientTransferNumber; - } + if (sessionData.clientTransferNumber != undefined) { + commitPreparationRequestMessage.clientTransferNumber = + sessionData.clientTransferNumber; + } - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(commitPreparationRequestMessage)), - ); + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(commitPreparationRequestMessage)), + ); - commitPreparationRequestMessage.clientSignature = messageSignature; + commitPreparationRequestMessage.clientSignature = messageSignature; - saveSignature(sessionData, MessageType.COMMIT_PREPARE, messageSignature); + saveSignature(sessionData, MessageType.COMMIT_PREPARE, messageSignature); - saveHash( - sessionData, - MessageType.COMMIT_PREPARE, - getHash(commitPreparationRequestMessage), - ); + saveHash( + sessionData, + MessageType.COMMIT_PREPARE, + getHash(commitPreparationRequestMessage), + ); - /* - await storeLog(gateway, { - sessionID: sessionData.id, - type: "commitPreparation", - operation: "lock", - data: safeStableStringify(sessionData), - }); - */ + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); - this.Log.info(`${fnTag}, sending CommitPreparationMessage...`); + this.Log.info(`${fnTag}, sending CommitPreparationMessage...`); - return commitPreparationRequestMessage; + return commitPreparationRequestMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async commitFinalAssertion( @@ -157,6 +186,7 @@ export class Stage3ClientService extends SATPService { ): Promise { const stepTag = `commitFinalAssertion()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.COMMIT_FINAL]; this.Log.debug(`${fnTag}, CommitFinalAssertion...`); if (session == undefined) { @@ -166,85 +196,113 @@ export class Stage3ClientService extends SATPService { session.verify(fnTag, SessionType.CLIENT); const sessionData = session.getClientSessionData(); - - const commonBody = create(CommonSatpSchema, { - version: SATP_VERSION, - messageType: MessageType.COMMIT_FINAL, - sequenceNumber: response.common!.sequenceNumber + BigInt(1), - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.COMMIT_READY, - ), - sessionId: response.common!.sessionId, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - resourceUrl: sessionData.resourceUrl, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); - sessionData.lastSequenceNumber = commonBody.sequenceNumber = - response.common!.sequenceNumber + BigInt(1); - - commonBody.sessionId = response.common!.sessionId; - commonBody.clientGatewayPubkey = sessionData.clientGatewayPubkey; - commonBody.serverGatewayPubkey = sessionData.serverGatewayPubkey; - commonBody.resourceUrl = sessionData.resourceUrl; - - const commitFinalAssertionRequestMessage = create( - CommitFinalAssertionRequestMessageSchema, - { - common: commonBody, - }, - ); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + + const commonBody = create(CommonSatpSchema, { + version: SATP_VERSION, + messageType: MessageType.COMMIT_FINAL, + sequenceNumber: response.common!.sequenceNumber + BigInt(1), + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.COMMIT_READY, + ), + sessionId: response.common!.sessionId, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + resourceUrl: sessionData.resourceUrl, + }); + sessionData.lastSequenceNumber = commonBody.sequenceNumber = + response.common!.sequenceNumber + BigInt(1); + + commonBody.sessionId = response.common!.sessionId; + commonBody.clientGatewayPubkey = sessionData.clientGatewayPubkey; + commonBody.serverGatewayPubkey = sessionData.serverGatewayPubkey; + commonBody.resourceUrl = sessionData.resourceUrl; + + const commitFinalAssertionRequestMessage = create( + CommitFinalAssertionRequestMessageSchema, + { + common: commonBody, + }, + ); - if (sessionData.burnAssertionClaim == undefined) { - throw new BurnAssertionClaimError(fnTag); - } + if (sessionData.burnAssertionClaim == undefined) { + throw new BurnAssertionClaimError(fnTag); + } - commitFinalAssertionRequestMessage.burnAssertionClaim = - sessionData.burnAssertionClaim; + commitFinalAssertionRequestMessage.burnAssertionClaim = + sessionData.burnAssertionClaim; - if (sessionData.burnAssertionClaimFormat != undefined) { - commitFinalAssertionRequestMessage.burnAssertionClaimFormat = - sessionData.burnAssertionClaimFormat; - } + if (sessionData.burnAssertionClaimFormat != undefined) { + commitFinalAssertionRequestMessage.burnAssertionClaimFormat = + sessionData.burnAssertionClaimFormat; + } - if (sessionData.transferContextId != undefined) { - commitFinalAssertionRequestMessage.common!.transferContextId = - sessionData.transferContextId; - } + if (sessionData.transferContextId != undefined) { + commitFinalAssertionRequestMessage.common!.transferContextId = + sessionData.transferContextId; + } - if (sessionData.clientTransferNumber != undefined) { - commitFinalAssertionRequestMessage.clientTransferNumber = - sessionData.clientTransferNumber; - } + if (sessionData.clientTransferNumber != undefined) { + commitFinalAssertionRequestMessage.clientTransferNumber = + sessionData.clientTransferNumber; + } - const messageSignature = bufArray2HexStr( - sign( - this.Signer, - safeStableStringify(commitFinalAssertionRequestMessage), - ), - ); + const messageSignature = bufArray2HexStr( + sign( + this.Signer, + safeStableStringify(commitFinalAssertionRequestMessage), + ), + ); - commitFinalAssertionRequestMessage.clientSignature = messageSignature; + commitFinalAssertionRequestMessage.clientSignature = messageSignature; - saveSignature(sessionData, MessageType.COMMIT_FINAL, messageSignature); + saveSignature(sessionData, MessageType.COMMIT_FINAL, messageSignature); - saveHash( - sessionData, - MessageType.COMMIT_FINAL, - getHash(commitFinalAssertionRequestMessage), - ); + saveHash( + sessionData, + MessageType.COMMIT_FINAL, + getHash(commitFinalAssertionRequestMessage), + ); - /* - await storeLog(gateway, { - sessionID: sessionData.id, - type: "commitFinalAssertion", - operation: "lock", - data: safeStableStringify(sessionData), - }); - */ - this.Log.info(`${fnTag}, sending CommitFinalAssertionMessage...`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); - return commitFinalAssertionRequestMessage; + this.Log.info(`${fnTag}, sending CommitFinalAssertionMessage...`); + + return commitFinalAssertionRequestMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async transferComplete( @@ -253,6 +311,7 @@ export class Stage3ClientService extends SATPService { ): Promise { const stepTag = `transferComplete()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.COMMIT_TRANSFER_COMPLETE]; this.Log.debug(`${fnTag}, TransferComplete...`); if (session == undefined) { @@ -262,76 +321,102 @@ export class Stage3ClientService extends SATPService { session.verify(fnTag, SessionType.CLIENT); const sessionData = session.getClientSessionData(); - - const commonBody = create(CommonSatpSchema, { - version: SATP_VERSION, - messageType: MessageType.COMMIT_TRANSFER_COMPLETE, - sequenceNumber: response.common!.sequenceNumber + BigInt(1), - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.ACK_COMMIT_FINAL, - ), - sessionId: response.common!.sessionId, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - resourceUrl: sessionData.resourceUrl, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + const commonBody = create(CommonSatpSchema, { + version: SATP_VERSION, + messageType: MessageType.COMMIT_TRANSFER_COMPLETE, + sequenceNumber: response.common!.sequenceNumber + BigInt(1), + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.ACK_COMMIT_FINAL, + ), + sessionId: response.common!.sessionId, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + resourceUrl: sessionData.resourceUrl, + }); + + sessionData.lastSequenceNumber = commonBody.sequenceNumber = + response.common!.sequenceNumber + BigInt(1); + + const transferCompleteRequestMessage = create( + TransferCompleteRequestMessageSchema, + { + common: commonBody, + }, + ); - sessionData.lastSequenceNumber = commonBody.sequenceNumber = - response.common!.sequenceNumber + BigInt(1); - - const transferCompleteRequestMessage = create( - TransferCompleteRequestMessageSchema, - { - common: commonBody, - }, - ); - - if (sessionData.transferContextId != undefined) { - transferCompleteRequestMessage.common!.transferContextId = - sessionData.transferContextId; - } + if (sessionData.transferContextId != undefined) { + transferCompleteRequestMessage.common!.transferContextId = + sessionData.transferContextId; + } - if (sessionData.clientTransferNumber != undefined) { - transferCompleteRequestMessage.clientTransferNumber = - sessionData.clientTransferNumber; - } + if (sessionData.clientTransferNumber != undefined) { + transferCompleteRequestMessage.clientTransferNumber = + sessionData.clientTransferNumber; + } - transferCompleteRequestMessage.hashTransferCommence = getMessageHash( - sessionData, - MessageType.TRANSFER_COMMENCE_REQUEST, - ); + transferCompleteRequestMessage.hashTransferCommence = getMessageHash( + sessionData, + MessageType.TRANSFER_COMMENCE_REQUEST, + ); - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(transferCompleteRequestMessage)), - ); + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(transferCompleteRequestMessage)), + ); - transferCompleteRequestMessage.clientSignature = messageSignature; + transferCompleteRequestMessage.clientSignature = messageSignature; - saveSignature( - sessionData, - MessageType.COMMIT_TRANSFER_COMPLETE, - messageSignature, - ); + saveSignature( + sessionData, + MessageType.COMMIT_TRANSFER_COMPLETE, + messageSignature, + ); - saveHash( - sessionData, - MessageType.COMMIT_TRANSFER_COMPLETE, - getHash(transferCompleteRequestMessage), - ); + saveHash( + sessionData, + MessageType.COMMIT_TRANSFER_COMPLETE, + getHash(transferCompleteRequestMessage), + ); - /* - await storeLog(gateway, { - sessionID: sessionData.id, - type: "transferComplete", - operation: "lock", - data: safeStableStringify(sessionData), - }); - */ + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); - this.Log.info(`${fnTag}, sending TransferCompleteMessage...`); + this.Log.info(`${fnTag}, sending TransferCompleteMessage...`); - return transferCompleteRequestMessage; + return transferCompleteRequestMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async checkLockAssertionReceiptMessage( @@ -536,16 +621,32 @@ export class Stage3ClientService extends SATPService { async burnAsset(session: SATPSession): Promise { const stepTag = `lockAsset()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; - try { - this.Log.debug(`${fnTag}, Burning Asset...`); - if (session == undefined) { - throw new SessionError(fnTag); - } + if (session == undefined) { + throw new SessionError(fnTag); + } - session.verify(fnTag, SessionType.CLIENT); + session.verify(fnTag, SessionType.CLIENT); - const sessionData = session.getClientSessionData(); + const sessionData = session.getClientSessionData(); + this.Log.info(`init-${stepTag}`); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "burn-asset", + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.debug(`${fnTag}, Burning Asset...`); + try { + this.Log.info(`exec-${stepTag}`); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "burn-asset", + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); const assetId = sessionData.senderAsset?.tokenId; const amount = sessionData.senderAsset?.amount; @@ -579,7 +680,22 @@ export class Stage3ClientService extends SATPService { sessionData.burnAssertionClaim.signature = bufArray2HexStr( sign(this.Signer, sessionData.burnAssertionClaim.receipt), ); + this.dbLogger.storeProof({ + sessionID: sessionData.id, + type: "burn-asset", + operation: "done", + data: safeStableStringify(sessionData.burnAssertionClaim.proof), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, done-${fnTag}`); } catch (error) { + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "burn-asset", + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); throw new FailedToProcessError(fnTag, "BurnAsset", error); } } diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/satp-service.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/satp-service.ts index 556ffac253..59b4c0c88b 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/satp-service.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/satp-service.ts @@ -9,6 +9,7 @@ import { SatpStage0Service } from "../../generated/proto/cacti/satp/v02/stage_0_ import { SatpStage1Service } from "../../generated/proto/cacti/satp/v02/stage_1_pb"; import { SatpStage2Service } from "../../generated/proto/cacti/satp/v02/stage_2_pb"; import { SatpStage3Service } from "../../generated/proto/cacti/satp/v02/stage_3_pb"; +import { SATPLogger } from "../../logging"; export enum SATPServiceType { Server = "Server", @@ -24,6 +25,7 @@ export type ISATPServiceOptions = { signer: JsObjectSigner; serviceType: SATPServiceType; bridgeManager?: SATPBridgesManager; + dbLogger: SATPLogger; }; export interface SATPServiceStatic { @@ -56,6 +58,7 @@ export abstract class SATPService { readonly serviceType: SATPServiceType; private readonly signer: JsObjectSigner; readonly serviceName: string; + public dbLogger: SATPLogger; constructor(ops: ISATPServiceOptions) { this.logger = LoggerProvider.getOrCreate(ops.loggerOptions); @@ -63,6 +66,10 @@ export abstract class SATPService { this.serviceType = ops.serviceType; this.stage = ops.stage; this.signer = ops.signer; + if (!ops.dbLogger) { + throw new Error("dbLogger is required for SATPService"); + } + this.dbLogger = ops.dbLogger; this.logger.trace(`Signer logger level: ${this.signer.options.logLevel}`); } diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage0-server-service.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage0-server-service.ts index 370dc91fa0..0015248db3 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage0-server-service.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage0-server-service.ts @@ -70,6 +70,7 @@ export class Stage0ServerService extends SATPService { serviceName: ops.serviceName, signer: ops.signer, serviceType: Stage0ServerService.SERVICE_TYPE, + dbLogger: ops.dbLogger, }; super(commonOptions); if (ops.bridgeManager == undefined) { @@ -281,7 +282,7 @@ export class Stage0ServerService extends SATPService { ): Promise { const stepTag = `newSessionResponse()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; - + const messageType = MessageType[MessageType.NEW_SESSION_RESPONSE]; if (session == undefined) { throw new SessionError(fnTag); } @@ -291,41 +292,77 @@ export class Stage0ServerService extends SATPService { } const sessionData = session.getServerSessionData(); - const newSessionResponse = create(NewSessionResponseMessageSchema, { - sessionId: sessionData.id, - contextId: sessionData.transferContextId, - recipientGatewayNetworkId: sessionData.recipientGatewayNetworkId, - senderGatewayNetworkId: sessionData.senderGatewayNetworkId, - messageType: MessageType.NEW_SESSION_RESPONSE, - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.NEW_SESSION_REQUEST, - ), + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + const newSessionResponse = create(NewSessionResponseMessageSchema, { + sessionId: sessionData.id, + contextId: sessionData.transferContextId, + recipientGatewayNetworkId: sessionData.recipientGatewayNetworkId, + senderGatewayNetworkId: sessionData.senderGatewayNetworkId, + messageType: MessageType.NEW_SESSION_RESPONSE, + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.NEW_SESSION_REQUEST, + ), + }); - if (sessionData.id != request.sessionId) { - newSessionResponse.status = STATUS.STATUS_REJECTED; - } else { - newSessionResponse.status = STATUS.STATUS_ACCEPTED; - } + if (sessionData.id != request.sessionId) { + newSessionResponse.status = STATUS.STATUS_REJECTED; + } else { + newSessionResponse.status = STATUS.STATUS_ACCEPTED; + } - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(newSessionResponse)), - ); + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(newSessionResponse)), + ); - newSessionResponse.serverSignature = messageSignature; + newSessionResponse.serverSignature = messageSignature; - saveSignature( - sessionData, - MessageType.NEW_SESSION_REQUEST, - messageSignature, - ); + saveSignature( + sessionData, + MessageType.NEW_SESSION_REQUEST, + messageSignature, + ); - saveHash(sessionData, MessageType.NEW_SESSION_REQUEST, fnTag); + saveHash(sessionData, MessageType.NEW_SESSION_REQUEST, fnTag); - this.Log.info(`${fnTag}, sending NewSessionRequest...`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); - return newSessionResponse; + this.Log.info(`${fnTag}, sending NewSessionRequest...`); + + return newSessionResponse; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } public async newSessionErrorResponse( @@ -381,7 +418,7 @@ export class Stage0ServerService extends SATPService { ): Promise { const stepTag = `preSATPTransferResponse()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; - + const messageType = MessageType[MessageType.PRE_TRANSFER_COMMENCE_RESPONSE]; if (session == undefined) { throw new SessionError(fnTag); } @@ -392,58 +429,112 @@ export class Stage0ServerService extends SATPService { const sessionData = session.getServerSessionData(); - if (request.receiverAsset == undefined) { - throw new AssetMissing(fnTag); - } + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); - const preSATPTransferResponse = create( - PreSATPTransferResponseMessageSchema, - { - sessionId: sessionData.id, - contextId: sessionData.transferContextId, - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.PRE_SATP_TRANSFER_REQUEST, - ), - wrapAssertionClaim: sessionData.receiverWrapAssertionClaim, - recipientTokenId: sessionData.receiverAsset!.tokenId, - messageType: MessageType.PRE_SATP_TRANSFER_RESPONSE, - }, - ); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(preSATPTransferResponse)), - ); + if (request.receiverAsset == undefined) { + throw new AssetMissing(fnTag); + } - preSATPTransferResponse.serverSignature = messageSignature; + const preSATPTransferResponse = create( + PreSATPTransferResponseMessageSchema, + { + sessionId: sessionData.id, + contextId: sessionData.transferContextId, + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.PRE_SATP_TRANSFER_REQUEST, + ), + wrapAssertionClaim: sessionData.receiverWrapAssertionClaim, + recipientTokenId: sessionData.receiverAsset!.tokenId, + messageType: MessageType.PRE_SATP_TRANSFER_RESPONSE, + }, + ); - saveSignature( - sessionData, - MessageType.PRE_SATP_TRANSFER_REQUEST, - messageSignature, - ); + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(preSATPTransferResponse)), + ); - saveHash(sessionData, MessageType.PRE_SATP_TRANSFER_REQUEST, fnTag); + preSATPTransferResponse.serverSignature = messageSignature; - this.Log.info(`${fnTag}, sending PreSATPTransferResponse...`); + saveSignature( + sessionData, + MessageType.PRE_SATP_TRANSFER_REQUEST, + messageSignature, + ); - return preSATPTransferResponse; + saveHash(sessionData, MessageType.PRE_SATP_TRANSFER_REQUEST, fnTag); + + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + + this.Log.info(`${fnTag}, sending PreSATPTransferResponse...`); + + return preSATPTransferResponse; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } public async wrapToken(session: SATPSession): Promise { const stepTag = `wrapToken()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + + if (session == undefined) { + throw new SessionError(fnTag); + } + + const sessionData = session.getServerSessionData(); + this.Log.info(`init-${stepTag}`); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "wrap-token", + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); try { + this.Log.info(`exec-${stepTag}`); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "wrap-token", + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); this.Log.info(`${fnTag}, Wrapping Asset...`); - if (session == undefined) { - throw new SessionError(fnTag); - } - //TODO: check if is necessary to verify more things - const sessionData = session.getServerSessionData(); - if (sessionData.recipientGatewayNetworkId == "") { throw new GatewayNetworkIdError(fnTag); } @@ -475,14 +566,33 @@ export class Stage0ServerService extends SATPService { ); sessionData.receiverWrapAssertionClaim.receipt = await bridge.wrapAsset(token); + sessionData.receiverWrapAssertionClaim.proof = + await bridge.getProof(assetId); sessionData.receiverWrapAssertionClaim.signature = bufArray2HexStr( sign(this.Signer, sessionData.receiverWrapAssertionClaim.receipt), ); + + this.dbLogger.storeProof({ + sessionID: sessionData.id, + type: "wrap-token", + operation: "done", + data: safeStableStringify(sessionData.receiverWrapAssertionClaim.proof), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, done-${fnTag}`); } catch (error) { + this.Log.debug(`Crash in ${fnTag}`, error); + + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "wrap-token", + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); throw new FailedToProcessError(fnTag, "WrapAsset", error); } } - private setError( message: NewSessionResponseMessage | PreSATPTransferResponseMessage, error: SATPInternalError, diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage1-server-service.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage1-server-service.ts index d0f9664997..51f0a557a3 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage1-server-service.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage1-server-service.ts @@ -60,6 +60,7 @@ export class Stage1ServerService extends SATPService { serviceName: ops.serviceName, signer: ops.signer, serviceType: Stage1ServerService.SERVICE_TYPE, + dbLogger: ops.dbLogger, }; super(commonOptions); } @@ -70,6 +71,7 @@ export class Stage1ServerService extends SATPService { ): Promise { const stepTag = `transferProposalResponse()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.INIT_RECEIPT]; this.Log.debug(`${fnTag}, transferProposalResponse...`); if (session == undefined) { @@ -84,84 +86,111 @@ export class Stage1ServerService extends SATPService { const sessionData = session.getServerSessionData(); - sessionData.sourceLedgerAssetId = - request.transferInitClaims!.verifiedOriginatorEntityId; - sessionData.recipientLedgerAssetId = - request.transferInitClaims!.verifiedBeneficiaryEntityId; // todo shouldn't be the server to create this id? - - sessionData.hashTransferInitClaims = getHash(request.transferInitClaims); - - const commonBody = create(CommonSatpSchema, { - version: sessionData.version, - sessionId: sessionData.id, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - transferContextId: sessionData.transferContextId, - resourceUrl: sessionData.resourceUrl, - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.INIT_PROPOSAL, - ), - sequenceNumber: request.common!.sequenceNumber + BigInt(1), + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); - - sessionData.lastSequenceNumber = request.common!.sequenceNumber + BigInt(1); - - const transferProposalReceiptMessage = create( - TransferProposalReceiptMessageSchema, - {}, - ); - if (sessionData.state == State.REJECTED) { - transferProposalReceiptMessage.common = commonBody; - commonBody.messageType = MessageType.INIT_REJECT; - transferProposalReceiptMessage.timestamp = getMessageTimestamp( - sessionData, - MessageType.INIT_REJECT, - TimestampType.RECEIVED, + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + sessionData.sourceLedgerAssetId = + request.transferInitClaims!.verifiedOriginatorEntityId; + sessionData.recipientLedgerAssetId = + request.transferInitClaims!.verifiedBeneficiaryEntityId; // todo shouldn't be the server to create this id? + + sessionData.hashTransferInitClaims = getHash(request.transferInitClaims); + + const commonBody = create(CommonSatpSchema, { + version: sessionData.version, + sessionId: sessionData.id, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + transferContextId: sessionData.transferContextId, + resourceUrl: sessionData.resourceUrl, + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.INIT_PROPOSAL, + ), + sequenceNumber: request.common!.sequenceNumber + BigInt(1), + }); + + sessionData.lastSequenceNumber = + request.common!.sequenceNumber + BigInt(1); + + const transferProposalReceiptMessage = create( + TransferProposalReceiptMessageSchema, + {}, ); - } else if (sessionData.state == State.CONDITIONAL_REJECTED) { - throw new Error("Not Implemented"); - } else { - sessionData.state = State.ONGOING; - transferProposalReceiptMessage.common = commonBody; - transferProposalReceiptMessage.hashTransferInitClaims = - sessionData.hashTransferInitClaims; - commonBody.messageType = MessageType.INIT_RECEIPT; - transferProposalReceiptMessage.timestamp = getMessageTimestamp( - sessionData, - MessageType.INIT_PROPOSAL, - TimestampType.RECEIVED, + if (sessionData.state == State.REJECTED) { + transferProposalReceiptMessage.common = commonBody; + commonBody.messageType = MessageType.INIT_REJECT; + transferProposalReceiptMessage.timestamp = getMessageTimestamp( + sessionData, + MessageType.INIT_REJECT, + TimestampType.RECEIVED, + ); + } else if (sessionData.state == State.CONDITIONAL_REJECTED) { + throw new Error("Not Implemented"); + } else { + sessionData.state = State.ONGOING; + transferProposalReceiptMessage.common = commonBody; + transferProposalReceiptMessage.hashTransferInitClaims = + sessionData.hashTransferInitClaims; + commonBody.messageType = MessageType.INIT_RECEIPT; + transferProposalReceiptMessage.timestamp = getMessageTimestamp( + sessionData, + MessageType.INIT_PROPOSAL, + TimestampType.RECEIVED, + ); + } + + //TODO implement conditional reject + + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(transferProposalReceiptMessage)), ); - } - //TODO implement conditional reject + transferProposalReceiptMessage.serverSignature = messageSignature; - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(transferProposalReceiptMessage)), - ); - - transferProposalReceiptMessage.serverSignature = messageSignature; - - saveSignature(sessionData, commonBody.messageType, messageSignature); - - saveHash( - sessionData, - commonBody.messageType, - getHash(transferProposalReceiptMessage), - ); + saveSignature(sessionData, commonBody.messageType, messageSignature); - // TODO: store logs in the database using session ID; refactor storelog not to need gateway as input - /* - await storeLog(gateway, { - sessionID: sessionData.id, - type: "transferProposalResponse", - operation: "lock", - data: safeStableStringify(sessionData), - }); - */ - this.Log.info(`${fnTag}, sending TransferProposalResponseMessage...`); + saveHash( + sessionData, + commonBody.messageType, + getHash(transferProposalReceiptMessage), + ); - return transferProposalReceiptMessage; + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, sending TransferProposalResponseMessage...`); + + return transferProposalReceiptMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async transferProposalErrorResponse( @@ -220,6 +249,7 @@ export class Stage1ServerService extends SATPService { ): Promise { const stepTag = `transferCommenceResponse()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.TRANSFER_COMMENCE_RESPONSE]; this.Log.debug(`${fnTag}, transferCommenceResponse...`); if (session == undefined) { @@ -229,61 +259,88 @@ export class Stage1ServerService extends SATPService { session.verify(fnTag, SessionType.SERVER); const sessionData = session.getServerSessionData(); - - const commonBody = create(CommonSatpSchema, { - version: sessionData.version, - sessionId: sessionData.id, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - transferContextId: sessionData.transferContextId, - resourceUrl: sessionData.resourceUrl, - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.TRANSFER_COMMENCE_REQUEST, - ), - sequenceNumber: request.common!.sequenceNumber + BigInt(1), - messageType: MessageType.TRANSFER_COMMENCE_RESPONSE, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); - sessionData.lastSequenceNumber = commonBody.sequenceNumber = - request.common!.sequenceNumber + BigInt(1); - - const transferCommenceResponseMessage = create( - TransferCommenceResponseMessageSchema, - { - common: commonBody, - }, - ); - - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(transferCommenceResponseMessage)), - ); - - transferCommenceResponseMessage.serverSignature = messageSignature; + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + + const commonBody = create(CommonSatpSchema, { + version: sessionData.version, + sessionId: sessionData.id, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + transferContextId: sessionData.transferContextId, + resourceUrl: sessionData.resourceUrl, + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.TRANSFER_COMMENCE_REQUEST, + ), + sequenceNumber: request.common!.sequenceNumber + BigInt(1), + messageType: MessageType.TRANSFER_COMMENCE_RESPONSE, + }); + sessionData.lastSequenceNumber = commonBody.sequenceNumber = + request.common!.sequenceNumber + BigInt(1); + + const transferCommenceResponseMessage = create( + TransferCommenceResponseMessageSchema, + { + common: commonBody, + }, + ); - saveSignature( - sessionData, - MessageType.TRANSFER_COMMENCE_RESPONSE, - messageSignature, - ); + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(transferCommenceResponseMessage)), + ); - saveHash( - sessionData, - MessageType.TRANSFER_COMMENCE_RESPONSE, - getHash(transferCommenceResponseMessage), - ); + transferCommenceResponseMessage.serverSignature = messageSignature; - /* - await storeLog(gateway, { - sessionID: sessionData.id, - type: "transferCommenceResponse", - operation: "lock", - data: safeStableStringify(sessionData), - }); - */ + saveSignature( + sessionData, + MessageType.TRANSFER_COMMENCE_RESPONSE, + messageSignature, + ); - this.Log.info(`${fnTag}, sending TransferCommenceResponseMessage...`); + saveHash( + sessionData, + MessageType.TRANSFER_COMMENCE_RESPONSE, + getHash(transferCommenceResponseMessage), + ); - return transferCommenceResponseMessage; + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + + this.Log.info(`${fnTag}, sending TransferCommenceResponseMessage...`); + + return transferCommenceResponseMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async checkTransferProposalRequestMessage( diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage2-server-service.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage2-server-service.ts index 6e27be04d4..f0ca1f8785 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage2-server-service.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage2-server-service.ts @@ -45,6 +45,7 @@ export class Stage2ServerService extends SATPService { serviceName: ops.serviceName, signer: ops.signer, serviceType: Stage2ServerService.SERVICE_TYPE, + dbLogger: ops.dbLogger, }; super(commonOptions); } @@ -55,6 +56,7 @@ export class Stage2ServerService extends SATPService { ): Promise { const stepTag = `lockAssertionResponse()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.ASSERTION_RECEIPT]; this.Log.debug(`${fnTag}, lockAssertionResponse...`); if (session == undefined) { @@ -64,63 +66,96 @@ export class Stage2ServerService extends SATPService { session.verify(fnTag, SessionType.SERVER); const sessionData = session.getServerSessionData(); - - const commonBody = create(CommonSatpSchema, { - version: sessionData.version, - messageType: MessageType.ASSERTION_RECEIPT, - sequenceNumber: request.common!.sequenceNumber + BigInt(1), - hashPreviousMessage: getMessageHash(sessionData, MessageType.LOCK_ASSERT), - sessionId: request.common!.sessionId, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - resourceUrl: sessionData.resourceUrl, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + + const commonBody = create(CommonSatpSchema, { + version: sessionData.version, + messageType: MessageType.ASSERTION_RECEIPT, + sequenceNumber: request.common!.sequenceNumber + BigInt(1), + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.LOCK_ASSERT, + ), + sessionId: request.common!.sessionId, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + resourceUrl: sessionData.resourceUrl, + }); + + sessionData.lastSequenceNumber = commonBody.sequenceNumber; + + const lockAssertionReceiptMessage = create( + LockAssertionReceiptMessageSchema, + { + common: commonBody, + }, + ); - sessionData.lastSequenceNumber = commonBody.sequenceNumber; - - const lockAssertionReceiptMessage = create( - LockAssertionReceiptMessageSchema, - { - common: commonBody, - }, - ); - - if (sessionData.transferContextId != undefined) { - lockAssertionReceiptMessage.common!.transferContextId = - sessionData.transferContextId; - } - - if (sessionData.serverTransferNumber != undefined) { - lockAssertionReceiptMessage.serverTransferNumber = - sessionData.serverTransferNumber; - } - - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(lockAssertionReceiptMessage)), - ); + if (sessionData.transferContextId != undefined) { + lockAssertionReceiptMessage.common!.transferContextId = + sessionData.transferContextId; + } - lockAssertionReceiptMessage.serverSignature = messageSignature; + if (sessionData.serverTransferNumber != undefined) { + lockAssertionReceiptMessage.serverTransferNumber = + sessionData.serverTransferNumber; + } - saveSignature(sessionData, MessageType.ASSERTION_RECEIPT, messageSignature); + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(lockAssertionReceiptMessage)), + ); - saveHash( - sessionData, - MessageType.ASSERTION_RECEIPT, - getHash(lockAssertionReceiptMessage), - ); + lockAssertionReceiptMessage.serverSignature = messageSignature; - /* - await storeLog(gateway, { - sessionID: sessionData.id, - type: "lockAssertionResponse", - operation: "lock", - data: safeStableStringify(sessionData), - }); - */ + saveSignature( + sessionData, + MessageType.ASSERTION_RECEIPT, + messageSignature, + ); - this.Log.info(`${fnTag}, sending LockAssertionResponseMessage...`); + saveHash( + sessionData, + MessageType.ASSERTION_RECEIPT, + getHash(lockAssertionReceiptMessage), + ); - return lockAssertionReceiptMessage; + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, sending LockAssertionResponseMessage...`); + + return lockAssertionReceiptMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async lockAssertionErrorResponse( diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage3-server-service.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage3-server-service.ts index 31a9033e61..b9ad9a2b7c 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage3-server-service.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/stage-services/server/stage3-server-service.ts @@ -67,6 +67,7 @@ export class Stage3ServerService extends SATPService { signer: ops.signer, serviceType: Stage3ServerService.SERVICE_TYPE, bridgeManager: ops.bridgeManager, + dbLogger: ops.dbLogger, }; super(commonOptions); if (ops.bridgeManager == undefined) { @@ -83,6 +84,7 @@ export class Stage3ServerService extends SATPService { ): Promise { const stepTag = `commitReady()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.COMMIT_READY]; this.Log.debug(`${fnTag}, commitReady...`); if (session == undefined) { @@ -92,70 +94,96 @@ export class Stage3ServerService extends SATPService { session.verify(fnTag, SessionType.SERVER); const sessionData = session.getServerSessionData(); - - const commonBody = create(CommonSatpSchema, { - version: sessionData.version, - messageType: MessageType.COMMIT_READY, - sequenceNumber: request.common!.sequenceNumber + BigInt(1), - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.COMMIT_PREPARE, - ), - sessionId: request.common!.sessionId, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - resourceUrl: sessionData.resourceUrl, - }); - - sessionData.lastSequenceNumber = commonBody.sequenceNumber; - - const commitReadyMessage = create(CommitReadyResponseMessageSchema, { - common: commonBody, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + const commonBody = create(CommonSatpSchema, { + version: sessionData.version, + messageType: MessageType.COMMIT_READY, + sequenceNumber: request.common!.sequenceNumber + BigInt(1), + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.COMMIT_PREPARE, + ), + sessionId: request.common!.sessionId, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + resourceUrl: sessionData.resourceUrl, + }); + + sessionData.lastSequenceNumber = commonBody.sequenceNumber; + + const commitReadyMessage = create(CommitReadyResponseMessageSchema, { + common: commonBody, + }); - if (sessionData.mintAssertionClaim == undefined) { - throw new MintAssertionClaimError(fnTag); - } + if (sessionData.mintAssertionClaim == undefined) { + throw new MintAssertionClaimError(fnTag); + } - commitReadyMessage.mintAssertionClaim = sessionData.mintAssertionClaim; - commitReadyMessage.mintAssertionClaimFormat = - sessionData.mintAssertionClaimFormat; + commitReadyMessage.mintAssertionClaim = sessionData.mintAssertionClaim; + commitReadyMessage.mintAssertionClaimFormat = + sessionData.mintAssertionClaimFormat; - if (sessionData.transferContextId != undefined) { - commitReadyMessage.common!.transferContextId = - sessionData.transferContextId; - } + if (sessionData.transferContextId != undefined) { + commitReadyMessage.common!.transferContextId = + sessionData.transferContextId; + } - if (sessionData.serverTransferNumber != undefined) { - commitReadyMessage.serverTransferNumber = - sessionData.serverTransferNumber; - } + if (sessionData.serverTransferNumber != undefined) { + commitReadyMessage.serverTransferNumber = + sessionData.serverTransferNumber; + } - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(commitReadyMessage)), - ); + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(commitReadyMessage)), + ); - commitReadyMessage.serverSignature = messageSignature; + commitReadyMessage.serverSignature = messageSignature; - saveSignature(sessionData, MessageType.COMMIT_READY, messageSignature); + saveSignature(sessionData, MessageType.COMMIT_READY, messageSignature); - saveHash( - sessionData, - MessageType.COMMIT_READY, - getHash(commitReadyMessage), - ); + saveHash( + sessionData, + MessageType.COMMIT_READY, + getHash(commitReadyMessage), + ); - /* - await storeLog(gateway, { - sessionID: sessionData.id, - type: "commitReady", - operation: "lock", - data: safeStableStringify(sessionData), - }); - */ - this.Log.info(`${fnTag}, sending commitReadyMessage...`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, sending commitReadyMessage...`); - return commitReadyMessage; + return commitReadyMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async commitReadyErrorResponse( @@ -189,6 +217,7 @@ export class Stage3ServerService extends SATPService { ): Promise { const stepTag = `commitFinalAcknowledgementReceiptResponse()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = MessageType[MessageType.ACK_COMMIT_FINAL]; this.Log.debug(`${fnTag}, commitFinalAcknowledgementReceiptResponse...`); if (session == undefined) { @@ -199,82 +228,114 @@ export class Stage3ServerService extends SATPService { const sessionData = session.getServerSessionData(); - const commonBody = create(CommonSatpSchema, { - version: sessionData.version, - messageType: MessageType.ACK_COMMIT_FINAL, - sequenceNumber: request.common!.sequenceNumber + BigInt(1), - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.COMMIT_FINAL, - ), - sessionId: request.common!.sessionId, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - resourceUrl: sessionData.resourceUrl, + this.Log.info(`init-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + const commonBody = create(CommonSatpSchema, { + version: sessionData.version, + messageType: MessageType.ACK_COMMIT_FINAL, + sequenceNumber: request.common!.sequenceNumber + BigInt(1), + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.COMMIT_FINAL, + ), + sessionId: request.common!.sessionId, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + resourceUrl: sessionData.resourceUrl, + }); + + sessionData.lastSequenceNumber = + request.common!.sequenceNumber + BigInt(1); + + const commitFinalAcknowledgementReceiptResponseMessage = create( + CommitFinalAcknowledgementReceiptResponseMessageSchema, + { + common: commonBody, + }, + ); - sessionData.lastSequenceNumber = request.common!.sequenceNumber + BigInt(1); - - const commitFinalAcknowledgementReceiptResponseMessage = create( - CommitFinalAcknowledgementReceiptResponseMessageSchema, - { - common: commonBody, - }, - ); - - if (sessionData.assignmentAssertionClaim == undefined) { - throw new AssignmentAssertionClaimError(fnTag); - } + if (sessionData.assignmentAssertionClaim == undefined) { + throw new AssignmentAssertionClaimError(fnTag); + } - commitFinalAcknowledgementReceiptResponseMessage.assignmentAssertionClaim = - sessionData.assignmentAssertionClaim; + commitFinalAcknowledgementReceiptResponseMessage.assignmentAssertionClaim = + sessionData.assignmentAssertionClaim; - if (sessionData.assignmentAssertionClaimFormat != undefined) { - commitFinalAcknowledgementReceiptResponseMessage.assignmentAssertionClaimFormat = - sessionData.assignmentAssertionClaimFormat; - } + if (sessionData.assignmentAssertionClaimFormat != undefined) { + commitFinalAcknowledgementReceiptResponseMessage.assignmentAssertionClaimFormat = + sessionData.assignmentAssertionClaimFormat; + } - if (sessionData.transferContextId != undefined) { - commitFinalAcknowledgementReceiptResponseMessage.common!.transferContextId = - sessionData.transferContextId; - } + if (sessionData.transferContextId != undefined) { + commitFinalAcknowledgementReceiptResponseMessage.common!.transferContextId = + sessionData.transferContextId; + } - if (sessionData.serverTransferNumber != undefined) { - commitFinalAcknowledgementReceiptResponseMessage.serverTransferNumber = - sessionData.serverTransferNumber; - } + if (sessionData.serverTransferNumber != undefined) { + commitFinalAcknowledgementReceiptResponseMessage.serverTransferNumber = + sessionData.serverTransferNumber; + } - const messageSignature = bufArray2HexStr( - sign( - this.Signer, - safeStableStringify(commitFinalAcknowledgementReceiptResponseMessage), - ), - ); + const messageSignature = bufArray2HexStr( + sign( + this.Signer, + safeStableStringify(commitFinalAcknowledgementReceiptResponseMessage), + ), + ); - commitFinalAcknowledgementReceiptResponseMessage.serverSignature = - messageSignature; + commitFinalAcknowledgementReceiptResponseMessage.serverSignature = + messageSignature; - saveSignature(sessionData, MessageType.ACK_COMMIT_FINAL, messageSignature); + saveSignature( + sessionData, + MessageType.ACK_COMMIT_FINAL, + messageSignature, + ); - saveHash( - sessionData, - MessageType.ACK_COMMIT_FINAL, - getHash(commitFinalAcknowledgementReceiptResponseMessage), - ); + saveHash( + sessionData, + MessageType.ACK_COMMIT_FINAL, + getHash(commitFinalAcknowledgementReceiptResponseMessage), + ); - /* - await storeLog(gateway, { - sessionID: sessionData.id, - type: "commitFinalAcknowledgementReceiptResponse", - operation: "lock", - data: safeStableStringify(sessionData), - }); - */ - this.Log.info( - `${fnTag}, sending commitFinalAcknowledgementReceiptResponseMessage...`, - ); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info( + `${fnTag}, sending commitFinalAcknowledgementReceiptResponseMessage...`, + ); - return commitFinalAcknowledgementReceiptResponseMessage; + return commitFinalAcknowledgementReceiptResponseMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async commitFinalAcknowledgementReceiptErrorResponse( @@ -466,6 +527,8 @@ export class Stage3ServerService extends SATPService { ): Promise { const stepTag = `createTransferCompleteResponseMessage()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + const messageType = + MessageType[MessageType.COMMIT_TRANSFER_COMPLETE_RESPONSE]; this.Log.debug(`${fnTag}, createTransferCompleteResponseMessage...`); if (session == undefined) { @@ -476,60 +539,94 @@ export class Stage3ServerService extends SATPService { const sessionData = session.getServerSessionData(); - const commonBody = create(CommonSatpSchema, { - version: sessionData.version, - messageType: MessageType.COMMIT_TRANSFER_COMPLETE_RESPONSE, - sequenceNumber: request.common!.sequenceNumber + BigInt(1), - hashPreviousMessage: getMessageHash( - sessionData, - MessageType.COMMIT_TRANSFER_COMPLETE, - ), - sessionId: request.common!.sessionId, - clientGatewayPubkey: sessionData.clientGatewayPubkey, - serverGatewayPubkey: sessionData.serverGatewayPubkey, - resourceUrl: sessionData.resourceUrl, + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), }); + try { + this.Log.info(`exec-${messageType}`); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + const commonBody = create(CommonSatpSchema, { + version: sessionData.version, + messageType: MessageType.COMMIT_TRANSFER_COMPLETE_RESPONSE, + sequenceNumber: request.common!.sequenceNumber + BigInt(1), + hashPreviousMessage: getMessageHash( + sessionData, + MessageType.COMMIT_TRANSFER_COMPLETE, + ), + sessionId: request.common!.sessionId, + clientGatewayPubkey: sessionData.clientGatewayPubkey, + serverGatewayPubkey: sessionData.serverGatewayPubkey, + resourceUrl: sessionData.resourceUrl, + }); + + sessionData.lastSequenceNumber = + request.common!.sequenceNumber + BigInt(1); + + const transferCompleteResponseMessage = create( + TransferCompleteResponseMessageSchema, + { + common: commonBody, + }, + ); - sessionData.lastSequenceNumber = request.common!.sequenceNumber + BigInt(1); - - const transferCompleteResponseMessage = create( - TransferCompleteResponseMessageSchema, - { - common: commonBody, - }, - ); - - if (sessionData.transferContextId != undefined) { - transferCompleteResponseMessage.common!.transferContextId = - sessionData.transferContextId; - } - - if (sessionData.serverTransferNumber != undefined) { - transferCompleteResponseMessage.serverTransferNumber = - sessionData.serverTransferNumber; - } - - const messageSignature = bufArray2HexStr( - sign(this.Signer, safeStableStringify(transferCompleteResponseMessage)), - ); + if (sessionData.transferContextId != undefined) { + transferCompleteResponseMessage.common!.transferContextId = + sessionData.transferContextId; + } - transferCompleteResponseMessage.serverSignature = messageSignature; + if (sessionData.serverTransferNumber != undefined) { + transferCompleteResponseMessage.serverTransferNumber = + sessionData.serverTransferNumber; + } - saveSignature( - sessionData, - MessageType.COMMIT_TRANSFER_COMPLETE_RESPONSE, - messageSignature, - ); + const messageSignature = bufArray2HexStr( + sign(this.Signer, safeStableStringify(transferCompleteResponseMessage)), + ); - saveHash( - sessionData, - MessageType.COMMIT_TRANSFER_COMPLETE_RESPONSE, - getHash(transferCompleteResponseMessage), - ); + transferCompleteResponseMessage.serverSignature = messageSignature; - this.Log.info(`${fnTag}, sending transferCompleteResponseMessage...`); + saveSignature( + sessionData, + MessageType.COMMIT_TRANSFER_COMPLETE_RESPONSE, + messageSignature, + ); - return transferCompleteResponseMessage; + saveHash( + sessionData, + MessageType.COMMIT_TRANSFER_COMPLETE_RESPONSE, + getHash(transferCompleteResponseMessage), + ); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "done", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, sending transferCompleteResponseMessage...`); + + return transferCompleteResponseMessage; + } catch (error) { + this.Log.error(`fail-${messageType}`, error); + await this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: messageType, + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + throw error; + } } async transferCompleteErrorResponse( @@ -560,16 +657,30 @@ export class Stage3ServerService extends SATPService { async mintAsset(session: SATPSession): Promise { const stepTag = `mintAsset()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; - try { - this.Log.info(`${fnTag}, Minting Asset...`); - - if (session == undefined) { - throw new SessionError(fnTag); - } + if (session == undefined) { + throw new SessionError(fnTag); + } - session.verify(fnTag, SessionType.SERVER); + session.verify(fnTag, SessionType.SERVER); - const sessionData = session.getServerSessionData(); + const sessionData = session.getServerSessionData(); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "mint-asset", + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + try { + this.Log.info(`exec-${stepTag}`); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "mint-asset", + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, Minting Asset...`); const assetId = sessionData.receiverAsset?.tokenId; const amount = sessionData.receiverAsset?.amount; @@ -604,7 +715,23 @@ export class Stage3ServerService extends SATPService { sessionData.mintAssertionClaim.signature = bufArray2HexStr( sign(this.Signer, sessionData.mintAssertionClaim.receipt), ); + this.dbLogger.storeProof({ + sessionID: sessionData.id, + type: "mint-asset", + operation: "done", + data: safeStableStringify(sessionData.mintAssertionClaim.proof), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, done-${fnTag}`); } catch (error) { + this.logger.debug(`Crash in ${fnTag}`, error); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "mint-asset", + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); throw new FailedToProcessError(fnTag, "MintAsset", error); } } @@ -612,16 +739,30 @@ export class Stage3ServerService extends SATPService { async assignAsset(session: SATPSession): Promise { const stepTag = `assignAsset()`; const fnTag = `${this.getServiceIdentifier()}#${stepTag}`; + if (session == undefined) { + throw new SessionError(fnTag); + } + + session.verify(fnTag, SessionType.SERVER); + const sessionData = session.getServerSessionData(); + this.Log.info(`init-${stepTag}`); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "assign-asset", + operation: "init", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); try { this.Log.info(`${fnTag}, Assigning Asset...`); - - if (session == undefined) { - throw new SessionError(fnTag); - } - - session.verify(fnTag, SessionType.SERVER); - - const sessionData = session.getServerSessionData(); + this.Log.info(`exec-${stepTag}`); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "assign-asset", + operation: "exec", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); const assetId = sessionData.receiverAsset?.tokenId; const amount = sessionData.receiverAsset?.amount; @@ -665,7 +806,23 @@ export class Stage3ServerService extends SATPService { sessionData.assignmentAssertionClaim.signature = bufArray2HexStr( sign(this.Signer, sessionData.assignmentAssertionClaim.receipt), ); + this.dbLogger.storeProof({ + sessionID: sessionData.id, + type: "assign-asset", + operation: "done", + data: safeStableStringify(sessionData.assignmentAssertionClaim.proof), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); + this.Log.info(`${fnTag}, done-${fnTag}`); } catch (error) { + this.logger.debug(`Crash in ${fnTag}`, error); + this.dbLogger.persistLogEntry({ + sessionID: sessionData.id, + type: "assign-asset", + operation: "fail", + data: safeStableStringify(sessionData), + sequenceNumber: Number(sessionData.lastSequenceNumber), + }); throw new FailedToProcessError(fnTag, "AssignAsset", error); } } diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/types.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/types.ts index 2c5215441b..b7613010c8 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/core/types.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/core/types.ts @@ -12,6 +12,7 @@ import { IMergePolicyValue } from "@hyperledger/cactus-plugin-bungee-hermes/dist import { NetworkBridge } from "./stage-services/satp-bridge/network-bridge"; import { SATPServiceInstance } from "./stage-services/satp-service"; import { NetworkConfig } from "../types/blockchain-interaction"; +import { Knex } from "knex"; export type SATPConnectHandler = ( gateway: SATPGateway, @@ -81,6 +82,8 @@ export interface SATPGatewayConfig { privacyPolicies?: IPrivacyPolicyValue[]; mergePolicies?: IMergePolicyValue[]; bridgesConfig?: NetworkConfig[]; + knexLocalConfig?: Knex.Config; + knexRemoteConfig?: Knex.Config; } // export interface SATPBridgeConfig { @@ -106,10 +109,11 @@ export function isOfType( export interface LocalLog { sessionID: string; type: string; - key?: string; + key: string; operation: string; timestamp?: string; data: string; + sequenceNumber: number; } export interface RemoteLog { key: string; diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/gateway-utils.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/gateway-utils.ts index ec964ebea4..ce61708740 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/gateway-utils.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/gateway-utils.ts @@ -1,6 +1,4 @@ import { JsObjectSigner } from "@hyperledger/cactus-common"; -import { LocalLog, RemoteLog } from "./core/types"; -import { SATPGateway } from "./plugin-satp-hermes-gateway"; import { SHA256 } from "crypto-js"; import { stringify as safeStableStringify } from "safe-stable-stringify"; @@ -61,89 +59,6 @@ export function verifySignature( } } -export async function storeProof( - gateway: SATPGateway, - localLog: LocalLog, -): Promise { - if (localLog.data == undefined) return; - - localLog.key = getSatpLogKey( - localLog.sessionID, - localLog.type, - localLog.operation, - ); - localLog.timestamp = Date.now().toString(); - - await storeInDatabase(gateway, localLog); - - const hash = SHA256(localLog.data).toString(); - - await storeRemoteLog(gateway, localLog.key, hash); -} - -export async function storeLog( - gateway: SATPGateway, - localLog: LocalLog, -): Promise { - localLog.key = getSatpLogKey( - localLog.sessionID, - localLog.type, - localLog.operation, - ); - localLog.timestamp = Date.now().toString(); - - await storeInDatabase(gateway, localLog); - - // Keep the order consistent with the order of the fields in the table - // so that the hash matches when retrieving from the database - const hash = SHA256( - safeStableStringify(localLog, [ - "sessionID", - "type", - "key", - "operation", - "timestamp", - "data", - ]), - ).toString(); - - await storeRemoteLog(gateway, localLog.key, hash); -} - -export async function storeInDatabase( - gateway: SATPGateway, - LocalLog: LocalLog, -) { - await gateway.localRepository?.create(LocalLog); -} - -export async function storeRemoteLog( - gateway: SATPGateway, - key: string, - hash: string, -) { - const fnTag = `${gateway.className}#storeInDatabase()`; - - const remoteLog: RemoteLog = { - key: key, - hash: hash, - signature: "", - signerPubKey: gateway.pubKey, - }; - - remoteLog.signature = bufArray2HexStr( - sign(gateway.Signer, safeStableStringify(remoteLog)), - ); - - const response = await gateway.remoteRepository?.create(remoteLog); - - if (response.status < 200 && response.status > 299) { - throw new Error( - `${fnTag}, got response ${response.status} when logging to remote`, - ); - } -} - export function getSatpLogKey( sessionID: string, type: string, diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/gol/satp-manager.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/gol/satp-manager.ts index 398defdfb0..4595c63172 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/gol/satp-manager.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/gol/satp-manager.ts @@ -77,6 +77,11 @@ import { } from "../core/errors/satp-errors"; import { getMessageTypeName } from "../core/satp-utils"; import { HealthCheckResponseStatusEnum } from "../generated/gateway-client/typescript-axios"; +import { + ILocalLogRepository, + IRemoteLogRepository, +} from "../repository/interfaces/repository"; +import { ISATPLoggerConfig, SATPLogger } from "../logging"; export interface ISATPManagerOptions { logLevel?: LogLevelDesc; @@ -87,6 +92,8 @@ export interface ISATPManagerOptions { supportedDLTs: SupportedChain[]; bridgeManager: SATPBridgesManager; orchestrator: GatewayOrchestrator; + localRepository: ILocalLogRepository; + remoteRepository: IRemoteLogRepository; } export class SATPManager { @@ -111,6 +118,9 @@ export class SATPManager { private readonly orchestrator: GatewayOrchestrator; private gatewaysPubKeys: Map = new Map(); + private localRepository: ILocalLogRepository; + private remoteRepository: IRemoteLogRepository; + private readonly dbLogger: SATPLogger; constructor(public readonly options: ISATPManagerOptions) { const fnTag = `${SATPManager.CLASS_NAME}#constructor()`; @@ -128,6 +138,8 @@ export class SATPManager { this.orchestrator = options.orchestrator; this._pubKey = options.pubKey; this.loadPubKeys(this.orchestrator.getCounterPartyGateways()); + this.localRepository = options.localRepository; + this.remoteRepository = options.remoteRepository; this.sessions = options.sessions || new Map(); const handlersClasses = [ @@ -137,6 +149,16 @@ export class SATPManager { Stage3SATPHandler as unknown as SATPHandlerInstance, ]; + const satpLoggerConfig: ISATPLoggerConfig = { + localRepository: this.localRepository, + remoteRepository: this.remoteRepository, + signer: this.signer, + pubKey: this.pubKey, + }; + + this.dbLogger = new SATPLogger(satpLoggerConfig); + this.logger.debug(`SATPManager dbLogger initialized: ${!!this.dbLogger}`); + const serviceClasses = [ Stage0ServerService as unknown as SATPServiceInstance, Stage0ClientService as unknown as SATPServiceInstance, @@ -272,6 +294,7 @@ export class SATPManager { serviceType: serviceClass.SERVICE_TYPE, serviceName: serviceClass.SATP_SERVICE_INTERNAL_NAME, bridgeManager: this.bridgesManager, + dbLogger: this.dbLogger, })); } diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/logging.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/logging.ts new file mode 100644 index 0000000000..9f024f015c --- /dev/null +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/logging.ts @@ -0,0 +1,173 @@ +import { LocalLog, RemoteLog } from "./core/types"; +import { + ILocalLogRepository, + IRemoteLogRepository, +} from "./repository/interfaces/repository"; +import { + JsObjectSigner, + Logger, + LoggerProvider, + LogLevelDesc, +} from "@hyperledger/cactus-common"; +import { SHA256 } from "crypto-js"; +import { stringify as safeStableStringify } from "safe-stable-stringify"; +import { bufArray2HexStr, getSatpLogKey, sign } from "./gateway-utils"; + +interface SATPLogEntry { + sessionID: string; + type: string; + operation: string; + data: string; + sequenceNumber: number; +} + +export interface ISATPLoggerConfig { + localRepository: ILocalLogRepository; + remoteRepository: IRemoteLogRepository; + signer: JsObjectSigner; + pubKey: string; +} + +export class SATPLogger { + public localRepository: ILocalLogRepository; + public remoteRepository: IRemoteLogRepository; + private signer: JsObjectSigner; + private pubKey: string; + private readonly log: Logger; + + constructor(config: ISATPLoggerConfig) { + this.localRepository = config.localRepository; + this.remoteRepository = config.remoteRepository; + this.signer = config.signer; + this.pubKey = config.pubKey; + + const logLevel: LogLevelDesc = "INFO"; + this.log = LoggerProvider.getOrCreate({ + label: "SATPLogger", + level: logLevel, + }); + + this.log.info("SATPLogger initialized."); + } + + public async storeProof(logEntry: SATPLogEntry): Promise { + const fnTag = `SATPLogger#storeProof()`; + this.log.info( + `${fnTag} - Storing proof log entry for sessionID: ${logEntry.sessionID}`, + ); + + if (logEntry.data == undefined) { + this.log.warn(`${fnTag} - No data provided in log entry.`); + return; + } + + const key = getSatpLogKey( + logEntry.sessionID, + logEntry.type, + logEntry.operation, + ); + const localLog: LocalLog = { + sessionID: logEntry.sessionID, + type: logEntry.type, + key: key, + timestamp: Date.now().toString(), + operation: logEntry.operation, + data: logEntry.data, + sequenceNumber: logEntry.sequenceNumber, + }; + + await this.storeInDatabase(localLog); + + const hash = SHA256(localLog.data).toString(); + + this.log.debug(`${fnTag} - generated hash: ${hash}`); + await this.storeRemoteLog(localLog.key, hash); + } + + public async persistLogEntry(logEntry: SATPLogEntry): Promise { + const fnTag = `SATPLogger#persistLogEntry()`; + this.log.info( + `${fnTag} - Persisting log entry for sessionID: ${logEntry.sessionID}`, + ); + + const key = getSatpLogKey( + logEntry.sessionID, + logEntry.type, + logEntry.operation, + ); + const localLog: LocalLog = { + sessionID: logEntry.sessionID, + type: logEntry.type, + key: key, + timestamp: Date.now().toString(), + operation: logEntry.operation, + data: logEntry.data, + sequenceNumber: logEntry.sequenceNumber, + }; + + await this.storeInDatabase(localLog); + + const hash = this.getHash(localLog); + + this.log.debug(`${fnTag} - generated hash: ${hash}`); + await this.storeRemoteLog(localLog.key, hash); + } + + private getHash(logEntry: LocalLog): string { + const fnTag = `SATPLogger#getHash()`; + this.log.debug( + `${fnTag} - generating hash for log entry with sessionID: ${logEntry.sessionID}`, + ); + + return SHA256( + safeStableStringify(logEntry, [ + "sessionID", + "type", + "key", + "operation", + "timestamp", + "data", + "sequenceNumber", + ]), + ).toString(); + } + + private async storeInDatabase(localLog: LocalLog): Promise { + const fnTag = `SATPLogger#storeInDatabase()`; + this.log.info(`${fnTag} - Storing log entry with key: ${localLog.key}`); + + await this.localRepository.create(localLog); + } + + private async storeRemoteLog(key: string, hash: string): Promise { + const fnTag = `SATPLogger#storeRemoteLog()`; + this.log.info( + `${fnTag} - Storing remote log with key: ${key} and hash: ${hash}`, + ); + + const remoteLog: RemoteLog = { + key: key, + hash: hash, + signature: "", + signerPubKey: this.pubKey, + }; + + remoteLog.signature = bufArray2HexStr( + sign(this.signer, safeStableStringify(remoteLog)), + ); + + this.log.debug(`${fnTag} - Generated signature: ${remoteLog.signature}`); + const response = await this.remoteRepository.create(remoteLog); + + if (response.status < 200 || response.status > 299) { + this.log.error( + `${fnTag} - Failed to store remote log. Response status: ${response.status}`, + ); + throw new Error( + `${fnTag} - Got response ${response.status} when logging to remote`, + ); + } + + this.log.info(`${fnTag} - Successfully stored remote log.`); + } +} diff --git a/packages/cactus-plugin-satp-hermes/src/main/typescript/plugin-satp-hermes-gateway.ts b/packages/cactus-plugin-satp-hermes/src/main/typescript/plugin-satp-hermes-gateway.ts index 48e54902e7..520311b98c 100644 --- a/packages/cactus-plugin-satp-hermes/src/main/typescript/plugin-satp-hermes-gateway.ts +++ b/packages/cactus-plugin-satp-hermes/src/main/typescript/plugin-satp-hermes-gateway.ts @@ -43,6 +43,8 @@ import { ILocalLogRepository, IRemoteLogRepository, } from "./repository/interfaces/repository"; +import { KnexRemoteLogRepository as RemoteLogRepository } from "./repository/knex-remote-log-repository"; +import { KnexLocalLogRepository as LocalLogRepository } from "./repository/knex-local-log-repository"; import { BLODispatcher, BLODispatcherOptions } from "./blo/dispatcher"; import swaggerUi, { JsonObject } from "swagger-ui-express"; import { @@ -109,6 +111,9 @@ export class SATPGateway implements IPluginWebService, ICactusPlugin { this.logger = LoggerProvider.getOrCreate(logOptions); this.logger.info("Initializing Gateway Coordinator"); + this.localRepository = new LocalLogRepository(options.knexLocalConfig); + this.remoteRepository = new RemoteLogRepository(options.knexRemoteConfig); + if (this.config.keyPair == undefined) { throw new Error("Key pair is undefined"); } @@ -162,6 +167,8 @@ export class SATPGateway implements IPluginWebService, ICactusPlugin { signer: this.signer, bridgesManager: this.bridgesManager, pubKey: this.pubKey, + localRepository: this.localRepository, + remoteRepository: this.remoteRepository, }; this.supportedDltIDs = this.config.gid!.supportedDLTs; diff --git a/packages/cactus-plugin-satp-hermes/src/test/typescript/unit/services.test.ts b/packages/cactus-plugin-satp-hermes/src/test/typescript/unit/services.test.ts index 96ef118a26..a81a66110c 100644 --- a/packages/cactus-plugin-satp-hermes/src/test/typescript/unit/services.test.ts +++ b/packages/cactus-plugin-satp-hermes/src/test/typescript/unit/services.test.ts @@ -67,6 +67,18 @@ import { STATUS, } from "../../../main/typescript/generated/proto/cacti/satp/v02/stage_0_pb"; import { TokenType } from "../../../main/typescript/core/stage-services/satp-bridge/types/asset"; +import { + ILocalLogRepository, + IRemoteLogRepository, +} from "../../../main/typescript/repository/interfaces/repository"; +import { knexClientConnection, knexRemoteConnection } from "../knex.config"; +import { Knex, knex } from "knex"; +import { KnexLocalLogRepository as LocalLogRepository } from "../../../main/typescript/repository/knex-local-log-repository"; +import { KnexRemoteLogRepository as RemoteLogRepository } from "../../../main/typescript/repository/knex-remote-log-repository"; +import { SATPLogger } from "../../../main/typescript/logging"; + +let knexInstanceClient: Knex; // test as a client +let knexInstanceRemote: Knex; import { create, isMessage } from "@bufbuild/protobuf"; const logLevel: LogLevelDesc = "DEBUG"; @@ -89,11 +101,13 @@ const signer = new JsObjectSigner({ }); const supportedDLTs = [SupportedChain.FABRIC, SupportedChain.BESU]; - +let localRepository: ILocalLogRepository; +let remoteRepository: IRemoteLogRepository; +let dbLogger: SATPLogger; +let persistLogEntrySpy: jest.SpyInstance; let bridgeManager: SATPBridgesManager; let mockSession: SATPSession; - let satpClientService0: Stage0ClientService; let satpServerService0: Stage0ServerService; let satpClientService1: Stage1ClientService; @@ -129,6 +143,23 @@ beforeAll(async () => { logLevel: logLevel, }); + knexInstanceClient = knex(knexClientConnection); + await knexInstanceClient.migrate.latest(); + + knexInstanceRemote = knex(knexRemoteConnection); + await knexInstanceRemote.migrate.latest(); + + localRepository = new LocalLogRepository(knexClientConnection); + remoteRepository = new RemoteLogRepository(knexRemoteConnection); + dbLogger = new SATPLogger({ + localRepository, + remoteRepository, + signer, + pubKey: Buffer.from(keyPairs.publicKey).toString("hex"), + }); + + persistLogEntrySpy = jest.spyOn(dbLogger, "persistLogEntry"); + mockSession = new SATPSession({ contextID: "MOCK_CONTEXT_ID", server: false, @@ -174,6 +205,36 @@ beforeAll(async () => { } } }); + +afterEach(() => { + persistLogEntrySpy.mockClear(); +}); + +afterAll(async () => { + const services = [ + satpClientService0, + satpServerService0, + satpClientService1, + satpServerService1, + satpClientService2, + satpServerService2, + satpClientService3, + satpServerService3, + ]; + + for (const service of services) { + await service.dbLogger.localRepository.destroy(); + await service.dbLogger.remoteRepository.destroy(); + } + + if (knexInstanceClient) { + await knexInstanceClient.destroy(); + } + if (knexInstanceRemote) { + await knexInstanceRemote.destroy(); + } +}); + describe("SATP Services Testing", () => { it("Service0Client newSessionRequest", async () => { const sessionData = mockSession.getClientSessionData(); @@ -238,6 +299,7 @@ describe("SATP Services Testing", () => { mockSession, SupportedChain.BESU, ); + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(newSessionRequestMessage).toBeDefined(); expect(newSessionRequestMessage.contextId).toBe( @@ -280,6 +342,8 @@ describe("SATP Services Testing", () => { mockSession, ); + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); + expect(newSessionResponseMessage).toBeDefined(); expect(newSessionResponseMessage.contextId).toBe( mockSession.getClientSessionData()?.transferContextId, @@ -321,6 +385,7 @@ describe("SATP Services Testing", () => { preSATPTransferRequestMessage = await satpClientService0.preSATPTransferRequest(mockSession); + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(preSATPTransferRequestMessage).toBeDefined(); expect(preSATPTransferRequestMessage.sessionId).toBe(sessionData.id); @@ -374,7 +439,7 @@ describe("SATP Services Testing", () => { preSATPTransferRequestMessage, mockSession, ); - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(preSATPTransferResponseMessage).toBeDefined(); expect(preSATPTransferResponseMessage.sessionId).toBe( preSATPTransferRequestMessage.sessionId, @@ -419,7 +484,7 @@ describe("SATP Services Testing", () => { mockSession, supportedDLTs, )) as TransferProposalRequestMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect( isMessage( transferProposalRequestMessage, @@ -507,7 +572,7 @@ describe("SATP Services Testing", () => { transferProposalRequestMessage, mockSession, )) as TransferProposalReceiptMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect( isMessage( transferProposalResponseMessage, @@ -541,7 +606,7 @@ describe("SATP Services Testing", () => { transferProposalResponseMessage, mockSession, )) as TransferCommenceRequestMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect( isMessage( transferCommenceRequestMessage, @@ -585,7 +650,7 @@ describe("SATP Services Testing", () => { transferCommenceRequestMessage, mockSession, )) as TransferCommenceResponseMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(transferCommenceResponseMessage).toBeDefined(); expect(transferCommenceResponseMessage.common?.transferContextId).toBe( transferCommenceRequestMessage.common?.transferContextId, @@ -636,7 +701,7 @@ describe("SATP Services Testing", () => { transferCommenceResponseMessage, mockSession, )) as LockAssertionRequestMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(lockAssertionRequestMessage).toBeDefined(); expect(lockAssertionRequestMessage.common?.messageType).toBe( MessageType.LOCK_ASSERT, @@ -681,7 +746,7 @@ describe("SATP Services Testing", () => { lockAssertionRequestMessage, mockSession, )) as LockAssertionReceiptMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(lockAssertionReceiptMessage).toBeDefined(); expect(lockAssertionReceiptMessage.common?.transferContextId).toBe( lockAssertionRequestMessage.common?.transferContextId, @@ -722,7 +787,7 @@ describe("SATP Services Testing", () => { lockAssertionReceiptMessage, mockSession, )) as CommitPreparationRequestMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(commitPreparationRequestMessage).toBeDefined(); expect(commitPreparationRequestMessage.common?.sessionId).toBe( mockSession.getSessionId(), @@ -769,7 +834,7 @@ describe("SATP Services Testing", () => { commitPreparationRequestMessage, mockSession, )) as CommitReadyResponseMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(commitReadyResponseMessage).toBeDefined(); expect(commitReadyResponseMessage.common?.sessionId).toBe( commitPreparationRequestMessage.common?.sessionId, @@ -817,7 +882,7 @@ describe("SATP Services Testing", () => { commitReadyResponseMessage, mockSession, )) as CommitFinalAssertionRequestMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(commitFinalAssertionRequestMessage).toBeDefined(); expect(commitFinalAssertionRequestMessage.common?.sessionId).toBe( commitReadyResponseMessage.common?.sessionId, @@ -870,7 +935,7 @@ describe("SATP Services Testing", () => { commitFinalAssertionRequestMessage, mockSession, )) as CommitFinalAcknowledgementReceiptResponseMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(commitFinalAcknowledgementReceiptResponseMessage).toBeDefined(); expect( commitFinalAcknowledgementReceiptResponseMessage.common?.sessionId, @@ -925,6 +990,7 @@ describe("SATP Services Testing", () => { commitFinalAcknowledgementReceiptResponseMessage, mockSession, )) as TransferCompleteRequestMessage; + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(transferCompleteRequestMessage).toBeDefined(); expect(transferCompleteRequestMessage.common?.sessionId).toBe( @@ -979,7 +1045,7 @@ describe("SATP Services Testing", () => { transferCompleteRequestMessage, mockSession, )) as TransferCompleteResponseMessage; - + expect(persistLogEntrySpy).toHaveBeenCalledTimes(3); expect(transferCompleteResponseMessage).toBeDefined(); expect(transferCompleteResponseMessage.common?.sessionId).toBe( transferCompleteRequestMessage.common?.sessionId, @@ -1017,6 +1083,7 @@ function initializeServiceOptions( serviceType: index % 2 === 0 ? SATPServiceType.Server : SATPServiceType.Client, bridgeManager: bridgeManager, + dbLogger: dbLogger, })); } diff --git a/yarn.lock b/yarn.lock index 092ff8d376..2402ef4c55 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9279,6 +9279,7 @@ __metadata: "@types/fs-extra": "npm:11.0.4" "@types/google-protobuf": "npm:3.15.12" "@types/node": "npm:18.18.2" + "@types/pg": "npm:8.11.10" "@types/swagger-ui-express": "npm:4.1.6" "@types/tape": "npm:4.13.4" "@types/uuid": "npm:10.0.0" @@ -9308,6 +9309,7 @@ __metadata: make-dir-cli: "npm:3.1.0" npm-run-all: "npm:4.1.5" openzeppelin-solidity: "npm:3.4.2" + pg: "npm:8.13.1" protobufjs: "npm:7.2.5" safe-stable-stringify: "npm:2.5.0" secp256k1: "npm:4.0.3" @@ -16282,6 +16284,17 @@ __metadata: languageName: node linkType: hard +"@types/pg@npm:8.11.10": + version: 8.11.10 + resolution: "@types/pg@npm:8.11.10" + dependencies: + "@types/node": "npm:*" + pg-protocol: "npm:*" + pg-types: "npm:^4.0.1" + checksum: 10/65b7d7ca9c90b7cb94aa94ad94bb1883356845e1f64688bc824ecd499da25f63a2400f0a58500554637048a7cc8b91055bbfe14301c082ce9669afd0c18e414c + languageName: node + linkType: hard + "@types/pg@npm:8.6.5": version: 8.6.5 resolution: "@types/pg@npm:8.6.5" @@ -39546,7 +39559,7 @@ __metadata: languageName: node linkType: hard -"obuf@npm:^1.0.0, obuf@npm:^1.1.2": +"obuf@npm:^1.0.0, obuf@npm:^1.1.2, obuf@npm:~1.1.2": version: 1.1.2 resolution: "obuf@npm:1.1.2" checksum: 10/53ff4ab3a13cc33ba6c856cf281f2965c0aec9720967af450e8fd06cfd50aceeefc791986a16bcefa14e7898b3ca9acdfcf15b9d9a1b9c7e1366581a8ad6e65e @@ -40809,6 +40822,13 @@ __metadata: languageName: node linkType: hard +"pg-cloudflare@npm:^1.1.1": + version: 1.1.1 + resolution: "pg-cloudflare@npm:1.1.1" + checksum: 10/45ca0c7926967ec9e66a9efc73ca57e3e933671b541bc774631a02ce683e7f658d0a4e881119b3f61486f38e344ae1b008d3a20eb5e21701c5fa8ff8382c5538 + languageName: node + linkType: hard + "pg-connection-string@npm:2.5.0": version: 2.5.0 resolution: "pg-connection-string@npm:2.5.0" @@ -40823,7 +40843,7 @@ __metadata: languageName: node linkType: hard -"pg-connection-string@npm:^2.5.0": +"pg-connection-string@npm:^2.5.0, pg-connection-string@npm:^2.7.0": version: 2.7.0 resolution: "pg-connection-string@npm:2.7.0" checksum: 10/68015a8874b7ca5dad456445e4114af3d2602bac2fdb8069315ecad0ff9660ec93259b9af7186606529ac4f6f72a06831e6f20897a689b16cc7fda7ca0e247fd @@ -40837,7 +40857,14 @@ __metadata: languageName: node linkType: hard -"pg-pool@npm:^3.5.2": +"pg-numeric@npm:1.0.2": + version: 1.0.2 + resolution: "pg-numeric@npm:1.0.2" + checksum: 10/8899f8200caa1744439a8778a9eb3ceefb599d893e40a09eef84ee0d4c151319fd416634a6c0fc7b7db4ac268710042da5be700b80ef0de716fe089b8652c84f + languageName: node + linkType: hard + +"pg-pool@npm:^3.5.2, pg-pool@npm:^3.7.0": version: 3.7.0 resolution: "pg-pool@npm:3.7.0" peerDependencies: @@ -40846,7 +40873,7 @@ __metadata: languageName: node linkType: hard -"pg-protocol@npm:*, pg-protocol@npm:^1.5.0": +"pg-protocol@npm:*, pg-protocol@npm:^1.5.0, pg-protocol@npm:^1.7.0": version: 1.7.0 resolution: "pg-protocol@npm:1.7.0" checksum: 10/ffffdf74426c9357b57050f1c191e84447c0e8b2a701b3ab302ac7dd0eb27b862d92e5e3b2d38876a1051de83547eb9165d6a58b3a8e90bb050dae97f9993d54 @@ -40866,6 +40893,43 @@ __metadata: languageName: node linkType: hard +"pg-types@npm:^4.0.1": + version: 4.0.2 + resolution: "pg-types@npm:4.0.2" + dependencies: + pg-int8: "npm:1.0.1" + pg-numeric: "npm:1.0.2" + postgres-array: "npm:~3.0.1" + postgres-bytea: "npm:~3.0.0" + postgres-date: "npm:~2.1.0" + postgres-interval: "npm:^3.0.0" + postgres-range: "npm:^1.1.1" + checksum: 10/f4d529da864d4169afab300eb8629a84a6a06aa70c471160a7e46c34b6d4dd0e61cbd57d10d98c3a36e98f474e2ff85d41e4b1c953a321146b4bae09372c58d3 + languageName: node + linkType: hard + +"pg@npm:8.13.1": + version: 8.13.1 + resolution: "pg@npm:8.13.1" + dependencies: + pg-cloudflare: "npm:^1.1.1" + pg-connection-string: "npm:^2.7.0" + pg-pool: "npm:^3.7.0" + pg-protocol: "npm:^1.7.0" + pg-types: "npm:^2.1.0" + pgpass: "npm:1.x" + peerDependencies: + pg-native: ">=3.0.1" + dependenciesMeta: + pg-cloudflare: + optional: true + peerDependenciesMeta: + pg-native: + optional: true + checksum: 10/542aa49fcb37657cf5f779b4a31fe6eb336e683445ecca38e267eeb0ca85d873ffe51f04794f9f9e184187e9f74bf7895e932a0fa9507132ac0dfc76c7c73451 + languageName: node + linkType: hard + "pg@npm:8.8.0": version: 8.8.0 resolution: "pg@npm:8.8.0" @@ -42162,6 +42226,13 @@ __metadata: languageName: node linkType: hard +"postgres-array@npm:~3.0.1": + version: 3.0.2 + resolution: "postgres-array@npm:3.0.2" + checksum: 10/0159517e4e5f263bf9e324f0c4d3c10244a294021f2b5980abc8c23afdb965370a7fc0c82012fce4d28e83186ad089b6476b05fcef6c88f8e43e37a3a2fa0ad5 + languageName: node + linkType: hard + "postgres-bytea@npm:~1.0.0": version: 1.0.0 resolution: "postgres-bytea@npm:1.0.0" @@ -42169,6 +42240,15 @@ __metadata: languageName: node linkType: hard +"postgres-bytea@npm:~3.0.0": + version: 3.0.0 + resolution: "postgres-bytea@npm:3.0.0" + dependencies: + obuf: "npm:~1.1.2" + checksum: 10/f5c01758fd2fa807afbd34e1ba2146f683818ebc2d23f4a62f0fd627c0b1126fc543cab1b63925f97ce6c7d8f5f316043218619c447445210ea82f10411efb1b + languageName: node + linkType: hard + "postgres-date@npm:~1.0.4": version: 1.0.7 resolution: "postgres-date@npm:1.0.7" @@ -42176,6 +42256,13 @@ __metadata: languageName: node linkType: hard +"postgres-date@npm:~2.1.0": + version: 2.1.0 + resolution: "postgres-date@npm:2.1.0" + checksum: 10/faa1c70dfad0e35bd4aa7cb6088fcd4e4f039aa25dc42150129178fc2a0baa7e37eca0bf18e4142a40dea18d1955459b08783f78ec487ef27b4b93ab5e854597 + languageName: node + linkType: hard + "postgres-interval@npm:^1.1.0": version: 1.2.0 resolution: "postgres-interval@npm:1.2.0" @@ -42185,6 +42272,20 @@ __metadata: languageName: node linkType: hard +"postgres-interval@npm:^3.0.0": + version: 3.0.0 + resolution: "postgres-interval@npm:3.0.0" + checksum: 10/c7a1cf006de97de663b6b8c4d2b167aa9909a238c4866a94b15d303762f5ac884ff4796cd6e2111b7f0a91302b83c570453aa8506fd005b5a5d5dfa87441bebc + languageName: node + linkType: hard + +"postgres-range@npm:^1.1.1": + version: 1.1.4 + resolution: "postgres-range@npm:1.1.4" + checksum: 10/035759f17b44bf9ba7e71a30402ed2ca1e2b7fabb3ad794b08169a5b453d38d06905a6dfb51fe41a3f6d9fac4e183dac9e769b95053053db933be16785edce1f + languageName: node + linkType: hard + "postman-request@npm:^2.88.1-postman.33": version: 2.88.1-postman.8-beta.1 resolution: "postman-request@npm:2.88.1-postman.8-beta.1"