Skip to content

Commit

Permalink
re-introduce requestHash
Browse files Browse the repository at this point in the history
  • Loading branch information
dohaki committed Dec 24, 2024
1 parent 91f4cc2 commit 703ef6e
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 38 deletions.
6 changes: 3 additions & 3 deletions api/relay/_queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ const client = new Client({
export async function pushRelayRequestToQueue({
request,
strategy,
requestId,
}: {
request: RelayRequest;
strategy: RelayStrategy;
requestId: string;
}) {
const strategyName = strategy.strategyName;
const queue = getRelayRequestQueue(strategyName, request.chainId);
Expand All @@ -24,11 +22,13 @@ export async function pushRelayRequestToQueue({

const baseUrl = resolveVercelEndpoint(true);
const response = await queue.enqueueJSON({
headers: new Headers({
"Upstash-Content-Based-Deduplication": "true",
}),
url: `${baseUrl}/api/relay/jobs/process`,
// callbackUrl: `${baseUrl}/api/relay/jobs/success`,
// failureCallbackUrl: `${baseUrl}/api/relay/jobs/failure`,
body: {
requestId,
request,
strategyName,
},
Expand Down
73 changes: 53 additions & 20 deletions api/relay/_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,39 +197,46 @@ export function encodeCalldataForRelayRequest(request: RelayRequest) {
return encodedCalldata;
}

export function getRelayRequestHash(request: RelayRequest) {
return utils.keccak256(
utils.defaultAbiCoder.encode(
["bytes", "bytes"],
[request.signatures.permit, request.signatures.deposit]
)
);
}

type CachedRelayRequest =
| {
status: "pending";
request: RelayRequest;
requestId: string;
messageId: string;
}
| {
status: "success";
request: RelayRequest;
txHash: string;
requestId: string;
messageId: string;
}
| {
status: "failure";
request: RelayRequest;
error: Error;
requestId: string;
messageId: string;
}
| {
status: "unknown";
requestId: string;
};

export async function getCachedRelayRequest(
requestId: string
requestOrHash: RelayRequest | string
): Promise<CachedRelayRequest> {
const cachedRelayRequest = await redisCache.get<CachedRelayRequest>(
getRelayRequestCacheKey(requestId)
getRelayRequestCacheKey(requestOrHash)
);

if (!cachedRelayRequest) {
return {
requestId,
status: "unknown",
};
}
Expand All @@ -238,54 +245,80 @@ export async function getCachedRelayRequest(
}

export async function setCachedRelayRequestPending(params: {
requestId: string;
messageId: string;
request: RelayRequest;
}) {
await redisCache.set(
getRelayRequestCacheKey(params.requestId),
getRelayRequestCacheKey(params.request),
{
status: "pending",
requestId: params.requestId,
messageId: params.messageId,
request: params.request,
},
60 * 60 * 24 // 1 day
);
}

export async function setCachedRelayRequestFailure(params: {
requestId: string;
request: RelayRequest;
error: Error;
}) {
const cachedRelayRequest = await getCachedRelayRequest(params.request);

if (!cachedRelayRequest || cachedRelayRequest.status === "unknown") {
throw new Error("Request not found in cache");
}

if (cachedRelayRequest.status !== "pending") {
throw new Error(
"Can not set 'failure' status for request that is not pending"
);
}

await redisCache.set(
getRelayRequestCacheKey(params.requestId),
getRelayRequestCacheKey(params.request),
{
status: "failure",
requestId: params.requestId,
request: params.request,
messageId: cachedRelayRequest.messageId,
request: cachedRelayRequest.request,
error: params.error,
},
60 * 60 * 24 // 1 day
);
}

export async function setCachedRelayRequestSuccess(params: {
requestId: string;
request: RelayRequest;
txHash: string;
}) {
const cachedRelayRequest = await getCachedRelayRequest(params.request);

if (!cachedRelayRequest || cachedRelayRequest.status === "unknown") {
throw new Error("Request not found in cache");
}

if (cachedRelayRequest.status !== "pending") {
throw new Error(
"Can not set 'success' status for request that is not pending"
);
}

await redisCache.set(
getRelayRequestCacheKey(params.requestId),
getRelayRequestCacheKey(params.request),
{
status: "success",
requestId: params.requestId,
request: params.request,
messageId: cachedRelayRequest.messageId,
request: cachedRelayRequest.request,
txHash: params.txHash,
},
60 * 60 * 24 // 1 day
);
}

function getRelayRequestCacheKey(requestId: string) {
return `relay-request:${requestId}`;
function getRelayRequestCacheKey(requestOrHash: RelayRequest | string) {
const requestHash =
typeof requestOrHash === "string"
? requestOrHash
: getRelayRequestHash(requestOrHash);
return `relay-request:${requestHash}`;
}
9 changes: 6 additions & 3 deletions api/relay/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,19 @@ export default async function handler(
methodNameAndArgs,
signatures,
};
const queueResponse = await pushRelayRequestToQueue(relayRequest, strategy);
const queueResponse = await pushRelayRequestToQueue({
request: relayRequest,
strategy,
});

// Store requestId in database
await setCachedRelayRequestPending({
requestId: queueResponse.messageId,
messageId: queueResponse.messageId,
request: relayRequest,
});

response.status(200).json({
requestId: queueResponse.messageId,
messageId: queueResponse.messageId,
});
} catch (error) {
return handleErrorCondition("api/relay", response, logger, error);
Expand Down
26 changes: 18 additions & 8 deletions api/relay/jobs/process.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { VercelRequest, VercelResponse } from "@vercel/node";
import { assert, enums, type, string } from "superstruct";
import { assert, enums, type } from "superstruct";
import { Receiver } from "@upstash/qstash";

import { handleErrorCondition } from "../../_errors";
import { handleErrorCondition, InvalidParamError } from "../../_errors";
import { getLogger } from "../../_utils";
import {
validateMethodArgs,
verifySignatures,
setCachedRelayRequestSuccess,
setCachedRelayRequestFailure,
getCachedRelayRequest,
} from "../_utils";
import { RelayRequest } from "../_types";
import { strategiesByName } from "../_strategies";
Expand All @@ -21,7 +22,6 @@ const messageReceiver = new Receiver({

const RelayProcessJobBodySchema = type({
strategyName: enums(Object.keys(strategiesByName)),
requestId: string(),
request: BaseRelayRequestBodySchema,
});

Expand Down Expand Up @@ -50,7 +50,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) {
}

assert(req.body, RelayProcessJobBodySchema);
const { request, strategyName, requestId } = req.body;
const { request, strategyName } = req.body;

// Validate method-specific request body
const methodNameAndArgs = validateMethodArgs(
Expand All @@ -75,27 +75,37 @@ export default async function handler(req: VercelRequest, res: VercelResponse) {
signatures,
};

// Get cached request
const cachedRequest = await getCachedRelayRequest(relayRequest);

if (!cachedRequest || cachedRequest.status !== "pending") {
throw new InvalidParamError({
param: "request",
message: "Request not found in cache or is not pending",
});
}

const { messageId } = cachedRequest;

// Handle request via strategy
try {
const txHash = await strategy.relay(relayRequest);
// Store requestId in database
await setCachedRelayRequestSuccess({
requestId,
request: relayRequest,
txHash,
});
res.status(200).json({
requestId,
messageId,
txHash,
});
} catch (error) {
await setCachedRelayRequestFailure({
requestId,
request: relayRequest,
error: error as Error,
});
res.status(500).json({
requestId,
messageId,
error: error as Error,
});
}
Expand Down
8 changes: 4 additions & 4 deletions api/relay/status.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { VercelResponse } from "@vercel/node";
import { assert, type, string, Infer } from "superstruct";
import { assert, type, Infer } from "superstruct";

import { handleErrorCondition } from "../_errors";
import { getLogger } from "../_utils";
import { getLogger, hexString } from "../_utils";
import { getCachedRelayRequest } from "./_utils";
import { TypedVercelRequest } from "../_types";

const RelayRequestStatusSchema = type({
requestId: string(),
requestHash: hexString(),
});

type RelayRequestStatusType = Infer<typeof RelayRequestStatusSchema>;
Expand All @@ -27,7 +27,7 @@ export default async function handler(
assert(request.query, RelayRequestStatusSchema);

const cachedRelayRequest = await getCachedRelayRequest(
request.query.requestId
request.query.requestHash
);

response.status(200).json(cachedRelayRequest);
Expand Down

0 comments on commit 703ef6e

Please sign in to comment.