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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 27 additions & 21 deletions packages/persistance/src/services/prisma/mappers/EventMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,53 @@ import { Field } from "o1js";

import { ObjectMapper } from "../../../ObjectMapper";

type EventData = {
eventName: string;
data: Field[];
source: "afterTxHook" | "beforeTxHook" | "runtime";
};

@singleton()
export class EventMapper
implements
ObjectMapper<{ eventName: string; data: Field[] }, Prisma.JsonObject>
{
public mapIn(input: Prisma.JsonObject): { eventName: string; data: Field[] } {
if (input === undefined) return { eventName: "", data: [] };
export class EventMapper implements ObjectMapper<EventData, Prisma.JsonObject> {
public mapIn(input: Prisma.JsonObject): EventData {
return {
eventName: input.eventName as string,
data: (input.data as Prisma.JsonArray).map((field) =>
Field.fromJSON(field as string)
),
source: this.sourceConvert(input.source as string),
};
}

public mapOut(input: {
eventName: string;
data: Field[];
}): Prisma.JsonObject {
public mapOut(input: EventData): Prisma.JsonObject {
return {
eventName: input.eventName,
data: input.data.map((field) => field.toString()),
source: input.source,
} as Prisma.JsonObject;
}

private sourceConvert(input: string) {
if (
input === "beforeTxHook" ||
input === "afterTxHook" ||
input === "runtime"
) {
return input;
}
throw new Error(
"Event Source must be one of 'beforeTxHook', 'afterTxHook' or 'runtime'"
);
}
}

@singleton()
export class EventArrayMapper
implements
ObjectMapper<
{ eventName: string; data: Field[] }[],
Prisma.JsonValue | undefined
>
implements ObjectMapper<EventData[], Prisma.JsonValue | undefined>
{
public constructor(private readonly eventMapper: EventMapper) {}

public mapIn(
input: Prisma.JsonValue | undefined
): { eventName: string; data: Field[] }[] {
public mapIn(input: Prisma.JsonValue | undefined): EventData[] {
if (input === undefined) return [];

if (Array.isArray(input)) {
Expand All @@ -53,9 +61,7 @@ export class EventArrayMapper
return [];
}

public mapOut(
input: { eventName: string; data: Field[] }[]
): Prisma.JsonValue {
public mapOut(input: EventData[]): Prisma.JsonValue {
return input.map((event) =>
this.eventMapper.mapOut(event)
) as Prisma.JsonArray;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,32 @@ async function decodeTransaction(
}

function extractEvents(
runtimeResult: RuntimeContextReducedExecutionResult
): { eventName: string; data: Field[] }[] {
runtimeResult: RuntimeContextReducedExecutionResult,
source: "afterTxHook" | "beforeTxHook" | "runtime"
): {
eventName: string;
data: Field[];
source: "afterTxHook" | "beforeTxHook" | "runtime";
}[] {
return runtimeResult.events.reduce(
(acc, event) => {
if (event.condition.toBoolean()) {
const obj = {
eventName: event.eventName,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
data: event.eventType.toFields(event.event),
source: source,
};
acc.push(obj);
}
return acc;
},
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
[] as { eventName: string; data: Field[] }[]
[] as {
eventName: string;
data: Field[];
source: "afterTxHook" | "beforeTxHook" | "runtime";
}[]
);
}

Expand Down Expand Up @@ -314,6 +324,7 @@ export class TransactionExecutionService {
async (hook, hookArgs) => await hook.beforeTransaction(hookArgs),
"beforeTx"
);
const beforeHookEvents = extractEvents(beforeTxHookResult, "beforeTxHook");

await recordingStateService.applyStateTransitions(
beforeTxHookResult.stateTransitions
Expand Down Expand Up @@ -363,6 +374,7 @@ export class TransactionExecutionService {
async (hook, hookArgs) => await hook.afterTransaction(hookArgs),
"afterTx"
);
const afterHookEvents = extractEvents(afterTxHookResult, "afterTxHook");
await recordingStateService.applyStateTransitions(
afterTxHookResult.stateTransitions
);
Expand All @@ -376,7 +388,7 @@ export class TransactionExecutionService {
appChain.setProofsEnabled(previousProofsEnabled);

// Extract sequencing results
const events = extractEvents(runtimeResult);
const runtimeResultEvents = extractEvents(runtimeResult, "runtime");
const stateTransitions = this.buildSTBatches(
[
beforeTxHookResult.stateTransitions,
Expand All @@ -394,7 +406,7 @@ export class TransactionExecutionService {
statusMessage: runtimeResult.statusMessage,

stateTransitions,
events,
events: beforeHookEvents.concat(runtimeResultEvents, afterHookEvents),
},
];
}
Expand Down
6 changes: 5 additions & 1 deletion packages/sequencer/src/storage/model/Block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ export interface TransactionExecutionResult {
stateTransitions: StateTransitionBatch[];
status: Bool;
statusMessage?: string;
events: { eventName: string; data: Field[] }[];
events: {
eventName: string;
data: Field[];
source: "afterTxHook" | "beforeTxHook" | "runtime";
}[];
}

// TODO Why is Block using Fields, but BlockResult bigints? Align that towards the best option
Expand Down
2 changes: 2 additions & 0 deletions packages/sequencer/test/integration/BlockProduction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -684,11 +684,13 @@ describe("block production", () => {
const firstEventReduced = {
eventName: firstExpectedEvent.eventName,
data: firstExpectedEvent.eventType.toFields(firstExpectedEvent.event),
source: "runtime",
};

const secondEventReduced = {
eventName: secondExpectedEvent.eventName,
data: secondExpectedEvent.eventType.toFields(secondExpectedEvent.event),
source: "runtime",
};

const block = await test.produceBlock();
Expand Down