Skip to content

Commit

Permalink
feat: add latest synced block data (#721)
Browse files Browse the repository at this point in the history
* feat(db): add last synced block slot and root fields

* feat(api): expose last upper synced block root and slot fields

* chore: add changeset

* test: uncomment env var

* test(api): add tests

* fix(api): validate slot, block number, and block root when updating or fetching blockchain sync state
  • Loading branch information
PJColombo authored Feb 14, 2025
1 parent 22ae59a commit 242af90
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 86 deletions.
6 changes: 6 additions & 0 deletions .changeset/dull-apricots-wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@blobscan/api": minor
"@blobscan/db": minor
---

Added last upper synced block root and block slot fields
2 changes: 1 addition & 1 deletion .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ GOOGLE_STORAGE_BUCKET_NAME=blobscan-test-bucket
GOOGLE_STORAGE_PROJECT_ID=blobscan-test-project
GOOGLE_STORAGE_API_ENDPOINT=http://localhost:4443
GOOGLE_STORAGE_ENABLED=true
# GOOGLE_SERVICE_KEY=
GOOGLE_SERVICE_KEY=

BEE_ENDPOINT=http://localhost:1633
SWARM_BATCH_ID=f89e63edf757f06e89933761d6d46592d03026efb9871f9d244f34da86b6c242
Expand Down
11 changes: 9 additions & 2 deletions packages/api/src/routers/blockchain-sync-state/getState.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { z } from "@blobscan/zod";

import { publicProcedure } from "../../procedures";
import { blockHashSchema, slotSchema } from "../../utils";
import { BASE_PATH } from "./common";

export const inputSchema = z.void();

export const outputSchema = z.object({
lastAggregatedBlock: z.number().nullable(),
lastFinalizedBlock: z.number().nullable(),
lastLowerSyncedSlot: z.number().nullable(),
lastUpperSyncedSlot: z.number().nullable(),
lastLowerSyncedSlot: slotSchema.nullable(),
lastUpperSyncedSlot: slotSchema.nullable(),
lastUpperSyncedBlockRoot: blockHashSchema.nullable(),
lastUpperSyncedBlockSlot: slotSchema.nullable(),
});

export const getState = publicProcedure
Expand All @@ -30,6 +33,8 @@ export const getState = publicProcedure
lastFinalizedBlock: true,
lastLowerSyncedSlot: true,
lastUpperSyncedSlot: true,
lastUpperSyncedBlockRoot: true,
lastUpperSyncedBlockSlot: true,
},
where: { id: 1 },
});
Expand All @@ -40,6 +45,8 @@ export const getState = publicProcedure
lastFinalizedBlock: null,
lastLowerSyncedSlot: null,
lastUpperSyncedSlot: null,
lastUpperSyncedBlockRoot: null,
lastUpperSyncedBlockSlot: null,
}
);
});
76 changes: 45 additions & 31 deletions packages/api/src/routers/blockchain-sync-state/updateState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import { TRPCError } from "@trpc/server";
import { z } from "@blobscan/zod";

import { createAuthedProcedure } from "../../procedures";
import { blockHashSchema, blockNumberSchema, slotSchema } from "../../utils";
import { BASE_PATH } from "./common";

export const inputSchema = z.object({
lastLowerSyncedSlot: z.number().optional(),
lastUpperSyncedSlot: z.number().optional(),
lastFinalizedBlock: z.number().optional(),
lastLowerSyncedSlot: slotSchema.optional(),
lastUpperSyncedSlot: slotSchema.optional(),
lastFinalizedBlock: blockNumberSchema.optional(),
lastUpperSyncedBlockRoot: blockHashSchema.optional(),
lastUpperSyncedBlockSlot: slotSchema.optional(),
});

export const outputSchema = z.void();
Expand All @@ -25,35 +28,46 @@ export const updateState = createAuthedProcedure("indexer")
})
.input(inputSchema)
.output(outputSchema)
.mutation(async ({ ctx, input }) => {
const lastLowerSyncedSlot = input.lastLowerSyncedSlot;
const lastUpperSyncedSlot = input.lastUpperSyncedSlot;
const lastFinalizedBlock = input.lastFinalizedBlock;

if (
lastLowerSyncedSlot !== undefined &&
lastUpperSyncedSlot !== undefined &&
lastLowerSyncedSlot > lastUpperSyncedSlot
) {
throw new TRPCError({
code: "BAD_REQUEST",
message:
"Last lower synced slot must be less than or equal to last upper synced slot",
});
}

await ctx.prisma.blockchainSyncState.upsert({
where: { id: 1 },
update: {
.mutation(
async ({
ctx,
input: {
lastLowerSyncedSlot,
lastUpperSyncedSlot,
lastFinalizedBlock,
lastUpperSyncedBlockRoot,
lastUpperSyncedBlockSlot,
},
create: {
id: 1,
lastLowerSyncedSlot,
lastUpperSyncedSlot,
lastFinalizedBlock,
},
});
});
}) => {
if (
lastLowerSyncedSlot !== undefined &&
lastUpperSyncedSlot !== undefined &&
lastLowerSyncedSlot > lastUpperSyncedSlot
) {
throw new TRPCError({
code: "BAD_REQUEST",
message:
"Last lower synced slot must be less than or equal to last upper synced slot",
});
}

await ctx.prisma.blockchainSyncState.upsert({
where: { id: 1 },
update: {
lastLowerSyncedSlot,
lastUpperSyncedSlot,
lastFinalizedBlock,
lastUpperSyncedBlockRoot,
lastUpperSyncedBlockSlot,
},
create: {
id: 1,
lastLowerSyncedSlot,
lastUpperSyncedSlot,
lastFinalizedBlock,
lastUpperSyncedBlockRoot,
lastUpperSyncedBlockSlot,
},
});
}
);
169 changes: 169 additions & 0 deletions packages/api/test/__snapshots__/blockchain-sync-state.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Blockchain sync state route > updateState > when authorized > should fail when trying to update last finalized slot to an invalid slot 1`] = `
"[
{
\\"code\\": \\"too_small\\",
\\"minimum\\": 0,
\\"type\\": \\"number\\",
\\"inclusive\\": true,
\\"exact\\": false,
\\"message\\": \\"Number must be greater than or equal to 0\\",
\\"path\\": [
\\"lastFinalizedBlock\\"
]
}
]"
`;

exports[`Blockchain sync state route > updateState > when authorized > should fail when trying to update last finalized slot to an invalid slot 2`] = `
[ZodError: [
{
"code": "too_small",
"minimum": 0,
"type": "number",
"inclusive": true,
"exact": false,
"message": "Number must be greater than or equal to 0",
"path": [
"lastFinalizedBlock"
]
}
]]
`;

exports[`Blockchain sync state route > updateState > when authorized > should fail when trying to update last lower synced slot to an invalid slot 1`] = `
"[
{
\\"code\\": \\"too_small\\",
\\"minimum\\": 0,
\\"type\\": \\"number\\",
\\"inclusive\\": true,
\\"exact\\": false,
\\"message\\": \\"Number must be greater than or equal to 0\\",
\\"path\\": [
\\"lastLowerSyncedSlot\\"
]
}
]"
`;

exports[`Blockchain sync state route > updateState > when authorized > should fail when trying to update last lower synced slot to an invalid slot 2`] = `
[ZodError: [
{
"code": "too_small",
"minimum": 0,
"type": "number",
"inclusive": true,
"exact": false,
"message": "Number must be greater than or equal to 0",
"path": [
"lastLowerSyncedSlot"
]
}
]]
`;

exports[`Blockchain sync state route > updateState > when authorized > should fail when trying to update last upper synced block root to an invalid hash 1`] = `
"[
{
\\"validation\\": \\"regex\\",
\\"code\\": \\"invalid_string\\",
\\"message\\": \\"Invalid hexadecimal string\\",
\\"path\\": [
\\"lastUpperSyncedBlockRoot\\"
]
},
{
\\"code\\": \\"custom\\",
\\"message\\": \\"Block hashes must be 66 characters long\\",
\\"path\\": [
\\"lastUpperSyncedBlockRoot\\"
]
}
]"
`;

exports[`Blockchain sync state route > updateState > when authorized > should fail when trying to update last upper synced block root to an invalid hash 2`] = `
[ZodError: [
{
"validation": "regex",
"code": "invalid_string",
"message": "Invalid hexadecimal string",
"path": [
"lastUpperSyncedBlockRoot"
]
},
{
"code": "custom",
"message": "Block hashes must be 66 characters long",
"path": [
"lastUpperSyncedBlockRoot"
]
}
]]
`;

exports[`Blockchain sync state route > updateState > when authorized > should fail when trying to update last upper synced block slot to an invalid slot 1`] = `
"[
{
\\"code\\": \\"too_small\\",
\\"minimum\\": 0,
\\"type\\": \\"number\\",
\\"inclusive\\": true,
\\"exact\\": false,
\\"message\\": \\"Number must be greater than or equal to 0\\",
\\"path\\": [
\\"lastUpperSyncedBlockSlot\\"
]
}
]"
`;

exports[`Blockchain sync state route > updateState > when authorized > should fail when trying to update last upper synced block slot to an invalid slot 2`] = `
[ZodError: [
{
"code": "too_small",
"minimum": 0,
"type": "number",
"inclusive": true,
"exact": false,
"message": "Number must be greater than or equal to 0",
"path": [
"lastUpperSyncedBlockSlot"
]
}
]]
`;

exports[`Blockchain sync state route > updateState > when authorized > should fail when trying to update last upper synced slot to an invalid slot 1`] = `
"[
{
\\"code\\": \\"too_small\\",
\\"minimum\\": 0,
\\"type\\": \\"number\\",
\\"inclusive\\": true,
\\"exact\\": false,
\\"message\\": \\"Number must be greater than or equal to 0\\",
\\"path\\": [
\\"lastUpperSyncedSlot\\"
]
}
]"
`;

exports[`Blockchain sync state route > updateState > when authorized > should fail when trying to update last upper synced slot to an invalid slot 2`] = `
[ZodError: [
{
"code": "too_small",
"minimum": 0,
"type": "number",
"inclusive": true,
"exact": false,
"message": "Number must be greater than or equal to 0",
"path": [
"lastUpperSyncedSlot"
]
}
]]
`;
Loading

0 comments on commit 242af90

Please sign in to comment.