Skip to content

Commit 41dfeeb

Browse files
authored
Merge pull request #280 from proto-kit/feature/event-hooks
Add Events to Protocol Hooks
2 parents b677d53 + 6bfbc51 commit 41dfeeb

File tree

4 files changed

+51
-27
lines changed

4 files changed

+51
-27
lines changed

packages/persistance/src/services/prisma/mappers/EventMapper.ts

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,53 @@ import { Field } from "o1js";
44

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

7+
type EventData = {
8+
eventName: string;
9+
data: Field[];
10+
source: "afterTxHook" | "beforeTxHook" | "runtime";
11+
};
12+
713
@singleton()
8-
export class EventMapper
9-
implements
10-
ObjectMapper<{ eventName: string; data: Field[] }, Prisma.JsonObject>
11-
{
12-
public mapIn(input: Prisma.JsonObject): { eventName: string; data: Field[] } {
13-
if (input === undefined) return { eventName: "", data: [] };
14+
export class EventMapper implements ObjectMapper<EventData, Prisma.JsonObject> {
15+
public mapIn(input: Prisma.JsonObject): EventData {
1416
return {
1517
eventName: input.eventName as string,
1618
data: (input.data as Prisma.JsonArray).map((field) =>
1719
Field.fromJSON(field as string)
1820
),
21+
source: this.sourceConvert(input.source as string),
1922
};
2023
}
2124

22-
public mapOut(input: {
23-
eventName: string;
24-
data: Field[];
25-
}): Prisma.JsonObject {
25+
public mapOut(input: EventData): Prisma.JsonObject {
2626
return {
2727
eventName: input.eventName,
2828
data: input.data.map((field) => field.toString()),
29+
source: input.source,
2930
} as Prisma.JsonObject;
3031
}
32+
33+
private sourceConvert(input: string) {
34+
if (
35+
input === "beforeTxHook" ||
36+
input === "afterTxHook" ||
37+
input === "runtime"
38+
) {
39+
return input;
40+
}
41+
throw new Error(
42+
"Event Source must be one of 'beforeTxHook', 'afterTxHook' or 'runtime'"
43+
);
44+
}
3145
}
3246

3347
@singleton()
3448
export class EventArrayMapper
35-
implements
36-
ObjectMapper<
37-
{ eventName: string; data: Field[] }[],
38-
Prisma.JsonValue | undefined
39-
>
49+
implements ObjectMapper<EventData[], Prisma.JsonValue | undefined>
4050
{
4151
public constructor(private readonly eventMapper: EventMapper) {}
4252

43-
public mapIn(
44-
input: Prisma.JsonValue | undefined
45-
): { eventName: string; data: Field[] }[] {
53+
public mapIn(input: Prisma.JsonValue | undefined): EventData[] {
4654
if (input === undefined) return [];
4755

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

56-
public mapOut(
57-
input: { eventName: string; data: Field[] }[]
58-
): Prisma.JsonValue {
64+
public mapOut(input: EventData[]): Prisma.JsonValue {
5965
return input.map((event) =>
6066
this.eventMapper.mapOut(event)
6167
) as Prisma.JsonArray;

packages/sequencer/src/protocol/production/sequencing/TransactionExecutionService.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,22 +111,32 @@ async function decodeTransaction(
111111
}
112112

113113
function extractEvents(
114-
runtimeResult: RuntimeContextReducedExecutionResult
115-
): { eventName: string; data: Field[] }[] {
114+
runtimeResult: RuntimeContextReducedExecutionResult,
115+
source: "afterTxHook" | "beforeTxHook" | "runtime"
116+
): {
117+
eventName: string;
118+
data: Field[];
119+
source: "afterTxHook" | "beforeTxHook" | "runtime";
120+
}[] {
116121
return runtimeResult.events.reduce(
117122
(acc, event) => {
118123
if (event.condition.toBoolean()) {
119124
const obj = {
120125
eventName: event.eventName,
121126
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
122127
data: event.eventType.toFields(event.event),
128+
source: source,
123129
};
124130
acc.push(obj);
125131
}
126132
return acc;
127133
},
128134
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
129-
[] as { eventName: string; data: Field[] }[]
135+
[] as {
136+
eventName: string;
137+
data: Field[];
138+
source: "afterTxHook" | "beforeTxHook" | "runtime";
139+
}[]
130140
);
131141
}
132142

@@ -314,6 +324,7 @@ export class TransactionExecutionService {
314324
async (hook, hookArgs) => await hook.beforeTransaction(hookArgs),
315325
"beforeTx"
316326
);
327+
const beforeHookEvents = extractEvents(beforeTxHookResult, "beforeTxHook");
317328

318329
await recordingStateService.applyStateTransitions(
319330
beforeTxHookResult.stateTransitions
@@ -363,6 +374,7 @@ export class TransactionExecutionService {
363374
async (hook, hookArgs) => await hook.afterTransaction(hookArgs),
364375
"afterTx"
365376
);
377+
const afterHookEvents = extractEvents(afterTxHookResult, "afterTxHook");
366378
await recordingStateService.applyStateTransitions(
367379
afterTxHookResult.stateTransitions
368380
);
@@ -376,7 +388,7 @@ export class TransactionExecutionService {
376388
appChain.setProofsEnabled(previousProofsEnabled);
377389

378390
// Extract sequencing results
379-
const events = extractEvents(runtimeResult);
391+
const runtimeResultEvents = extractEvents(runtimeResult, "runtime");
380392
const stateTransitions = this.buildSTBatches(
381393
[
382394
beforeTxHookResult.stateTransitions,
@@ -394,7 +406,7 @@ export class TransactionExecutionService {
394406
statusMessage: runtimeResult.statusMessage,
395407

396408
stateTransitions,
397-
events,
409+
events: beforeHookEvents.concat(runtimeResultEvents, afterHookEvents),
398410
},
399411
];
400412
}

packages/sequencer/src/storage/model/Block.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ export interface TransactionExecutionResult {
2020
stateTransitions: StateTransitionBatch[];
2121
status: Bool;
2222
statusMessage?: string;
23-
events: { eventName: string; data: Field[] }[];
23+
events: {
24+
eventName: string;
25+
data: Field[];
26+
source: "afterTxHook" | "beforeTxHook" | "runtime";
27+
}[];
2428
}
2529

2630
// TODO Why is Block using Fields, but BlockResult bigints? Align that towards the best option

packages/sequencer/test/integration/BlockProduction.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,11 +684,13 @@ describe("block production", () => {
684684
const firstEventReduced = {
685685
eventName: firstExpectedEvent.eventName,
686686
data: firstExpectedEvent.eventType.toFields(firstExpectedEvent.event),
687+
source: "runtime",
687688
};
688689

689690
const secondEventReduced = {
690691
eventName: secondExpectedEvent.eventName,
691692
data: secondExpectedEvent.eventType.toFields(secondExpectedEvent.event),
693+
source: "runtime",
692694
};
693695

694696
const block = await test.produceBlock();

0 commit comments

Comments
 (0)