diff --git a/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/errorHandler.ts b/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/errorHandler.ts index 4ddc21b6053..d8f08b80fa6 100644 --- a/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/errorHandler.ts +++ b/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/errorHandler.ts @@ -10,9 +10,17 @@ export const errorHandlerMiddleware = ( _next: NextFunction ) => { const error = - err instanceof ResponseError ? err : new InternalServerError(String(err)) + err instanceof ResponseError + ? err + : new InternalServerError( + err instanceof Error ? err.message : String(err) + ) if (!res.headersSent) { - res.status(error.status).send({ error: error.name }) + res + .status(error.status) + .set('X-Request-ID', res.locals.requestId) + .set('Access-Control-Expose-Headers', 'X-Request-ID') + .send({ error: error.message }) } // in milliseconds const responseTime = new Date().getTime() - res.locals.requestStartTime diff --git a/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/locals.ts b/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/locals.ts index ca955d27f1f..1b68f1bbdd6 100644 --- a/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/locals.ts +++ b/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/locals.ts @@ -5,6 +5,7 @@ import { Logger } from 'pino' declare global { namespace Express { interface Locals { + requestId: string signerUser?: Users isSignedByDiscovery?: boolean logger: Logger diff --git a/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/logging.ts b/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/logging.ts index 6452b5c56c6..036239c2e7b 100644 --- a/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/logging.ts +++ b/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/middleware/logging.ts @@ -12,6 +12,7 @@ export const incomingRequestLogger = ( response.locals.requestStartTime = startTime const requestId = uuidv4() const { path, method } = request + response.locals.requestId = requestId response.locals.logger = logger.child({ requestId, path, diff --git a/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/routes/relay/relay.ts b/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/routes/relay/relay.ts index 678198f9b5b..5b6e669be4a 100644 --- a/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/routes/relay/relay.ts +++ b/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/routes/relay/relay.ts @@ -15,6 +15,7 @@ import { sendTransactionWithRetries } from '../../utils/transaction' +import { InvalidRelayInstructionError } from './InvalidRelayInstructionError' import { assertRelayAllowedInstructions } from './assertRelayAllowedInstructions' /** @@ -103,10 +104,20 @@ export const relay = async ( const feePayerKey = decompiled.payerKey const feePayerKeyPair = getFeePayerKeyPair(feePayerKey) - await assertRelayAllowedInstructions(decompiled.instructions, { - user: res.locals.signerUser, - feePayer: feePayerKey.toBase58() - }) + + try { + await assertRelayAllowedInstructions(decompiled.instructions, { + user: res.locals.signerUser, + feePayer: feePayerKey.toBase58() + }) + } catch (e) { + if (e instanceof InvalidRelayInstructionError) { + res.locals.logger.error(e.toString()) + throw new BadRequestError('Invalid relay instructions') + } else { + throw e + } + } if (feePayerKeyPair) { res.locals.logger.info( diff --git a/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/utils/transaction.ts b/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/utils/transaction.ts index 03b1a9ab4cd..abd65f46e1d 100644 --- a/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/utils/transaction.ts +++ b/packages/discovery-provider/plugins/pedalboard/apps/solana-relay/src/utils/transaction.ts @@ -17,7 +17,6 @@ import { connections, getConnection } from './connections' import { delay } from './delay' const RETRY_DELAY_MS = 2 * 1000 -const RETRY_TIMEOUT_MS = 60 * 1000 /** * Forwards the transaction response to other Solana Relays on other discovery @@ -66,8 +65,7 @@ const forwardTransaction = async (logger: Logger, transaction: string) => { /** * Sends the transaction repeatedly to all configured RPCs until - * it's been confirmed with the given commitment level, expires, - * or times out. + * it's been confirmed with the given commitment level or the blockhash expires. */ export const sendTransactionWithRetries = async ({ transaction, @@ -103,13 +101,6 @@ export const sendTransactionWithRetries = async ({ } } - const createTimeoutPromise = async (signal: AbortSignal) => { - await delay(RETRY_TIMEOUT_MS) - if (!signal.aborted) { - logger.error('Timed out sending transaction') - } - } - const start = Date.now() const connection = connections[0] const abortController = new AbortController() @@ -130,12 +121,14 @@ export const sendTransactionWithRetries = async ({ connection.confirmTransaction( { ...confirmationStrategy, abortSignal: abortController.signal }, commitment - ), - createTimeoutPromise(abortController.signal) + ) ]) - if (!res || res.value.err) { - throw res?.value.err ?? 'Transaction polling timed out.' + if (!res) { + throw new Error('Failed to get transaction confirmation result') + } + if (res.value.err) { + throw new Error(JSON.stringify(res.value.err)) } logger.info({ commitment }, 'Transaction sent successfully') return confirmationStrategy.signature diff --git a/packages/web/src/store/errors/reportToSentry.ts b/packages/web/src/store/errors/reportToSentry.ts index 34adc531871..9620889103f 100644 --- a/packages/web/src/store/errors/reportToSentry.ts +++ b/packages/web/src/store/errors/reportToSentry.ts @@ -54,6 +54,7 @@ export const reportToSentry = async ({ additionalInfo = { ...additionalInfo, response: error.response, + requestId: error.response.headers.get('X-Request-ID'), responseBody } }