Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STProver v3 #260

Merged
merged 26 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
90e64b8
Added unconstrained values to hashlist
rpanic Mar 15, 2024
9dd8c82
Changed STProver to work on appliedbatches
rpanic Mar 15, 2024
8256e68
Merge branch 'refactor/sequencing' into feature/st-prover-v3
rpanic Jan 8, 2025
21f2f34
Merge branch 'refactor/tasks' into feature/st-prover-v3
rpanic Jan 9, 2025
7fd6fb3
New STProver: Protocol side
rpanic Jan 20, 2025
12aefff
First working e2e, fixed dummies in STProver, code cleanup
rpanic Jan 23, 2025
4b44136
Renamed transaction hooks
rpanic Jan 23, 2025
7d6145b
Adapted persistence schema
rpanic Jan 24, 2025
46c50de
Removed previous results from new blocks query
rpanic Jan 24, 2025
46d8ea4
Removed state service from tracing
rpanic Jan 27, 2025
cf6e49c
Refactorings
rpanic Jan 27, 2025
d44805e
Made ST and batch tracing parallel
rpanic Jan 27, 2025
42f5f71
Renamed rootAccumulator to witnessedRootsHash
rpanic Jan 27, 2025
9b941f6
Fixed compile error
rpanic Jan 27, 2025
bb3409b
Added migration
rpanic Jan 29, 2025
1a421e7
Merge branch 'develop' into feature/st-prover-3
rpanic Jan 29, 2025
b52ebea
Merged new ST Prover with atomic transactions arch
rpanic Jan 29, 2025
d8b69b5
Merge branch 'develop' into feature/st-prover-3
rpanic Feb 4, 2025
aefb9b9
Added missing check in SettlementSmartContract
rpanic Feb 6, 2025
6726a6f
Merge branch 'develop' into feature/st-prover-3
rpanic Feb 6, 2025
ab51068
Fixed merge errors
rpanic Feb 6, 2025
30fadea
Removed verbose in-circuit logs
rpanic Feb 6, 2025
e091cfb
Fixed remaining test compile error
rpanic Feb 7, 2025
2c065f4
Test: dump nodejs version for ci
rpanic Feb 10, 2025
cad11cc
Added logs
rpanic Feb 10, 2025
885679c
Try 2
rpanic Feb 10, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/pull-request-develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 22.9.0
node-version: 18
cache: npm

- name: "Install dependencies"
Expand Down
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from "./config/ModuleContainer";
export * from "./config/ConfigurableModule";
export * from "./config/ChildContainerProvider";
export * from "./config/ChildContainerCreatable";
export * from "./config/injectAlias";
export * from "./types";
export * from "./zkProgrammable/ZkProgrammable";
export * from "./zkProgrammable/ProvableMethodExecutionContext";
Expand All @@ -22,4 +23,3 @@ export * from "./compiling/AtomicCompileHelper";
export * from "./compiling/CompileRegistry";
export * from "./compiling/CompilableModule";
export * from "./compiling/services/ChildVerificationKeyService";
export * from "./config/injectAlias";
3 changes: 2 additions & 1 deletion packages/common/src/trees/RollupMerkleTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export function createMerkleTree(height: number): AbstractMerkleTreeClass {

public static dummy() {
return new RollupMerkleWitness({
isLeft: Array<Bool>(height - 1).fill(Bool(false)),
isLeft: Array<Bool>(height - 1).fill(Bool(true)),
path: Array<Field>(height - 1).fill(Field(0)),
});
}
Expand All @@ -222,6 +222,7 @@ export function createMerkleTree(height: number): AbstractMerkleTreeClass {
public static WITNESS = RollupMerkleWitness;

// private in interface
// TODO Cache this in some static variable so that we don't recompute it every time
readonly zeroes: bigint[];

readonly store: MerkleTreeStore;
Expand Down
61 changes: 61 additions & 0 deletions packages/common/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
DynamicProof,
Proof,
} from "o1js";
import _ from "lodash";

import { TypedClass } from "./types";

Expand Down Expand Up @@ -72,6 +73,26 @@ export function reduceSequential<T, U>(
);
}

export function yieldSequential<Source, State, Target>(
array: Source[],
callbackfn: (
previousValue: State,
currentValue: Source,
currentIndex: number,
array: Source[]
) => Promise<[State, Target]>,
initialValue: State
): Promise<[State, Target[]]> {
return reduceSequential<Source, [State, Target[]]>(
array,
async ([state, collectedTargets], curr, index, arr) => {
const [newState, addition] = await callbackfn(state, curr, index, arr);
return [newState, collectedTargets.concat(addition)];
},
[initialValue, []]
);
}

export function mapSequential<T, R>(
array: T[],
f: (element: T, index: number, array: T[]) => Promise<R>
Expand Down Expand Up @@ -198,3 +219,43 @@ export function safeParseJson<T>(json: string) {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return JSON.parse(json) as T;
}

export type Nullable<T> = {
[Key in keyof T]: T[Key] | undefined;
};

export function isFull<T>(t: Nullable<T>): t is T {
return Object.values(t).findIndex((v) => v === undefined) === -1;
}

// TODO Restructure utils into separate package and multiple files

export function padArray<T>(
array: T[],
batchSize: number,
generator: (index: number) => T
): T[] {
const slice = array.slice();
const dummies = range(0, batchSize - (array.length % batchSize)).map((i) =>
generator(i + array.length)
);
slice.push(...dummies);
return slice;
}

export function batch<T>(
arr: T[],
batchSize: number,
dummy: (index: number) => T
): T[][] {
const padded = padArray(arr, batchSize, dummy);

const partitioned = _.groupBy(
padded.map((v, i) => [v, i] as const),
([v, i]) => Math.floor(i / batchSize)
);

const numBatches = Math.ceil(arr.length / batchSize);

return range(0, numBatches).map((i) => partitioned[i].map((x) => x[0]));
}
4 changes: 3 additions & 1 deletion packages/common/src/zkProgrammable/provableMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export function toProver(
);

if (zkProgram === undefined) {
throw new Error("Correct ZkProgram not found");
throw new Error(
`Correct ZkProgram not found (searching for method ${methodName})`
);
}

if (areProofsEnabled) {
Expand Down
1 change: 1 addition & 0 deletions packages/deployment/src/queue/BullQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class BullQueue
await this.activePromise;
}
let resOutside: () => void = () => {};
// TODO Use Promise.withResolvers() for that
const promise = new Promise<void>((res) => {
resOutside = res;
});
Expand Down
11 changes: 8 additions & 3 deletions packages/library/src/hooks/TransactionFeeHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {
} from "@proto-kit/module";
import { inject, injectable } from "tsyringe";
import {
BeforeTransactionHookArguments,
ProvableTransactionHook,
BlockProverExecutionData,
PublicKeyOption,
} from "@proto-kit/protocol";
import { Field, Provable, PublicKey } from "o1js";
import { noop } from "@proto-kit/common";

import { UInt64 } from "../math/UInt64";
import { Balance, TokenId } from "../runtime/Balances";
Expand Down Expand Up @@ -122,8 +123,8 @@ export class TransactionFeeHook extends ProvableTransactionHook<TransactionFeeHo
*
* @param executionData
*/
public async onTransaction(
executionData: BlockProverExecutionData
public async beforeTransaction(
executionData: BeforeTransactionHookArguments
): Promise<void> {
const feeConfig = Provable.witness(MethodFeeConfigData, () =>
this.feeAnalyzer.getFeeConfig(
Expand Down Expand Up @@ -154,4 +155,8 @@ export class TransactionFeeHook extends ProvableTransactionHook<TransactionFeeHo
UInt64.Unsafe.fromField(fee.value)
);
}

public async afterTransaction(): Promise<void> {
noop();
}
}
3 changes: 1 addition & 2 deletions packages/module/src/method/runtimeMethod.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Bool, Field, FlexibleProvablePure, Poseidon } from "o1js";
import { container } from "tsyringe";
import {
StateTransition,
ProvableStateTransition,
MethodPublicOutput,
RuntimeMethodExecutionContext,
Expand Down Expand Up @@ -40,7 +39,7 @@ const errors = {
};

export function toStateTransitionsHash(
stateTransitions: StateTransition<any>[]
stateTransitions: { toProvable: () => ProvableStateTransition }[]
) {
const stateTransitionsHashList = new StateTransitionReductionList(
ProvableStateTransition
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Warnings:
- You are about to drop the column `blockStateTransitions` on the `BlockResult` table. All the data in the column will be lost.
- You are about to drop the column `protocolTransitions` on the `TransactionExecutionResult` table. All the data in the column will be lost.
- Added the required column `beforeBlockStateTransitions` to the `Block` table without a default value. This is not possible if the table is not empty.
- Added the required column `fromStateRoot` to the `Block` table without a default value. This is not possible if the table is not empty.
- Added the required column `afterBlockStateTransitions` to the `BlockResult` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "Block" ADD COLUMN "beforeBlockStateTransitions" JSON NOT NULL,
ADD COLUMN "fromStateRoot" TEXT NOT NULL;

-- AlterTable
ALTER TABLE "BlockResult" DROP COLUMN "blockStateTransitions",
ADD COLUMN "afterBlockStateTransitions" JSON NOT NULL,
ADD COLUMN "witnessedRoots" TEXT[];

-- AlterTable
ALTER TABLE "TransactionExecutionResult" DROP COLUMN "protocolTransitions";
24 changes: 14 additions & 10 deletions packages/persistance/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ model Transaction {
}

model TransactionExecutionResult {
stateTransitions Json @db.Json
protocolTransitions Json @db.Json
status Boolean
statusMessage String?
events Json @db.Json
// TODO Make StateTransitionBatch and StateTransition Table
stateTransitions Json @db.Json
status Boolean
statusMessage String?
events Json @db.Json

tx Transaction @relation(fields: [txHash], references: [hash])
txHash String @id
Expand All @@ -65,6 +65,9 @@ model Block {
fromBlockHashRoot String
fromMessagesHash String
toMessagesHash String
fromStateRoot String

beforeBlockStateTransitions Json @db.Json

parentHash String? @unique
parent Block? @relation("Parent", fields: [parentHash], references: [hash])
Expand All @@ -91,11 +94,12 @@ model Batch {
model BlockResult {
blockHash String @id @unique

stateRoot String
blockHashRoot String
afterNetworkState Json @db.Json
blockStateTransitions Json @db.Json
blockHashWitness Json @db.Json
stateRoot String
blockHashRoot String
witnessedRoots String[]
afterNetworkState Json @db.Json
afterBlockStateTransitions Json @db.Json
blockHashWitness Json @db.Json

block Block? @relation(fields: [blockHash], references: [hash])
}
Expand Down
46 changes: 11 additions & 35 deletions packages/persistance/src/services/prisma/PrismaBlockStorage.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import {
distinctByString,
HistoricalBlockStorage,
TransactionExecutionResult,
Block,
BlockResult,
BlockQueue,
BlockStorage,
BlockWithResult,
BlockWithPreviousResult,
BlockWithMaybeResult,
} from "@proto-kit/sequencer";
import { filterNonNull, log } from "@proto-kit/common";
import { log } from "@proto-kit/common";
import {
Prisma,
TransactionExecutionResult as DBTransactionExecutionResult,
Expand Down Expand Up @@ -108,6 +106,8 @@ export class PrismaBlockStorage
await prismaClient.block.create({
data: {
...encodedBlock,
beforeBlockStateTransitions:
encodedBlock.beforeBlockStateTransitions as Prisma.InputJsonArray,
beforeNetworkState:
encodedBlock.beforeNetworkState as Prisma.InputJsonObject,
duringNetworkState:
Expand All @@ -122,8 +122,6 @@ export class PrismaBlockStorage
txHash: tx.txHash,

stateTransitions: tx.stateTransitions as Prisma.InputJsonArray,
protocolTransitions:
tx.protocolTransitions as Prisma.InputJsonArray,
events: tx.events as Prisma.InputJsonArray,
};
}),
Expand All @@ -143,8 +141,8 @@ export class PrismaBlockStorage
data: {
afterNetworkState: encoded.afterNetworkState as Prisma.InputJsonValue,
blockHashWitness: encoded.blockHashWitness as Prisma.InputJsonValue,
blockStateTransitions:
encoded.blockStateTransitions as Prisma.InputJsonValue,
afterBlockStateTransitions:
encoded.afterBlockStateTransitions as Prisma.InputJsonValue,

stateRoot: encoded.stateRoot,
blockHash: encoded.blockHash,
Expand Down Expand Up @@ -198,7 +196,7 @@ export class PrismaBlockStorage
return result;
}

public async getNewBlocks(): Promise<BlockWithPreviousResult[]> {
public async getNewBlocks(): Promise<BlockWithResult[]> {
const blocks = await this.connection.prismaClient.block.findMany({
where: {
batch: null,
Expand All @@ -209,24 +207,13 @@ export class PrismaBlockStorage
tx: true,
},
},
result: true,
},
orderBy: {
height: Prisma.SortOrder.asc,
},
});

const blockHashes = blocks
.flatMap((block) => [block.parentHash, block.hash])
.filter(filterNonNull)
.filter(distinctByString);
const result = await this.connection.prismaClient.blockResult.findMany({
where: {
blockHash: {
in: blockHashes,
},
},
});

return blocks.map((block, index) => {
const transactions = block.transactions.map<TransactionExecutionResult>(
(txresult) => {
Expand All @@ -236,28 +223,17 @@ export class PrismaBlockStorage
const decodedBlock = this.blockMapper.mapIn(block);
decodedBlock.transactions = transactions;

const correspondingResult = result.find(
(candidate) => candidate.blockHash === block.hash
);
const { result } = block;

if (correspondingResult === undefined) {
if (result === null) {
throw new Error(
`No BlockResult has been set for block ${block.hash} yet`
);
}

const parentResult = result.find(
(candidate) => candidate.blockHash === block.parentHash
);
return {
block: {
block: decodedBlock,
result: this.blockResultMapper.mapIn(correspondingResult),
},
lastBlockResult:
parentResult !== undefined
? this.blockResultMapper.mapIn(parentResult)
: undefined,
block: decodedBlock,
result: this.blockResultMapper.mapIn(result),
};
});
}
Expand Down
Loading
Loading