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

Enabled proven settlement #224

Open
wants to merge 25 commits into
base: feature/contract-compiling
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d212dbf
fix: Missed hash function invocation
asimaranov May 1, 2024
8a039ab
Adding fix to avoid duplicate entries in fee analyzer service
ejMina226 Oct 29, 2024
f0d13e0
Add in test
ejMina226 Oct 29, 2024
3a5ba7e
Change comment
ejMina226 Oct 29, 2024
5ed58d5
Get tests working
ejMina226 Oct 30, 2024
96d460a
Merge pull request #216 from proto-kit/fix/fee-analyzer-service
ejMina226 Oct 30, 2024
b963a9a
Merge pull request #200 from proto-kit/refactor/smart-contract-modula…
maht0rz Oct 30, 2024
019136e
Add comment (WIP)
ejMina226 Nov 7, 2024
f125d7e
Add in details STProver
ejMina226 Nov 8, 2024
fd12704
Add in MerkleWitnesses to Batch
ejMina226 Nov 8, 2024
4716476
Change method to use witness
ejMina226 Nov 8, 2024
9d32968
Add in default for MerkleWitness
ejMina226 Nov 8, 2024
0d17c69
Add in default for MerkleWitness
ejMina226 Nov 8, 2024
ad77ece
Fix naming
ejMina226 Nov 8, 2024
9b173ff
Remove unneeded classes.
ejMina226 Nov 8, 2024
2cc6d37
Fix testing protocol.
ejMina226 Nov 8, 2024
8167e97
Merge pull request #222 from proto-kit/feature/refactor-stprover-merk…
ejMina226 Nov 8, 2024
684b621
Enabled proven settlement
rpanic Nov 9, 2024
c58ab4a
Enabled sourcemaps
rpanic Nov 9, 2024
4a3e15b
Added forceProverExists to protect against missing provers for non-si…
rpanic Nov 10, 2024
e9e6a97
Fix bug in protocol and flow for merging blocks
rpanic Nov 20, 2024
41afd2e
Merge pull request #229 from proto-kit/fix/block-merging
maht0rz Nov 21, 2024
ccf110a
Merge pull request #225 from proto-kit/feature/enable-sourcemaps
rpanic Nov 21, 2024
04124a9
Merge pull request #130 from asimaranov/develop
rpanic Nov 21, 2024
3ffc0c7
Merge branch 'develop' into feature/proven-settlemnet
rpanic Nov 26, 2024
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
25 changes: 21 additions & 4 deletions packages/common/src/compiling/CompileRegistry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { inject, injectable, singleton } from "tsyringe";

import { AreProofsEnabled } from "../zkProgrammable/ZkProgrammable";
import {
AreProofsEnabled,
CompileArtifact,
} from "../zkProgrammable/ZkProgrammable";

import {
ArtifactRecord,
Expand All @@ -27,18 +30,32 @@ export class CompileRegistry {

private artifacts: ArtifactRecord = {};

// TODO Add possibility to force recompilation for non-sideloaded dependencies
private inForceProverBlock = false;

/**
* This function forces compilation even if the artifact itself is in the registry.
* Basically the statement is: The artifact along is not enough, we need to
* actually have the prover compiled.
* This is true for non-sideloaded circuit dependencies.
*/
public async forceProverExists(
f: (registry: CompileRegistry) => Promise<void>
) {
this.inForceProverBlock = true;
await f(this);
this.inForceProverBlock = false;
}

public async compile(target: CompileTarget) {
if (this.artifacts[target.name] === undefined) {
if (this.artifacts[target.name] === undefined || this.inForceProverBlock) {
const artifact = await this.compiler.compileContract(target);
this.artifacts[target.name] = artifact;
return artifact;
}
return this.artifacts[target.name];
}

public getArtifact(name: string) {
public getArtifact(name: string): CompileArtifact | undefined {
if (this.artifacts[name] === undefined) {
throw new Error(
`Artifact for ${name} not available, did you compile it via the CompileRegistry?`
Expand Down
6 changes: 6 additions & 0 deletions packages/common/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ type NonMethodKeys<Type> = {
}[keyof Type];
export type NonMethods<Type> = Pick<Type, NonMethodKeys<Type>>;

export const MAX_FIELD = Field(Field.ORDER - 1n);

/**
* Returns a boolean indicating whether a given class is a subclass of another class,
* indicated by the name parameter.
Expand All @@ -176,6 +178,10 @@ export function isSubtypeOfName(
clas: TypedClass<unknown>,
name: string
): boolean {
if (clas === undefined || clas === null) {
return false;
}

if (clas.name === name) {
return true;
}
Expand Down
7 changes: 4 additions & 3 deletions packages/library/src/hooks/RuntimeFeeAnalyzerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export class RuntimeFeeAnalyzerService extends ConfigurableModule<RuntimeFeeAnal
});

container.resolve(RuntimeMethodExecutionContext).clear();

let methodCounter = 0;
const [values, indexes] =
await this.runtime.zkProgrammable.zkProgram.reduce<
Promise<[FeeTreeValues, FeeIndexes]>
Expand All @@ -93,7 +93,7 @@ export class RuntimeFeeAnalyzerService extends ConfigurableModule<RuntimeFeeAnal
[FeeTreeValues, FeeIndexes]
>(
// eslint-disable-next-line @typescript-eslint/no-shadow
([values, indexes], combinedMethodName, index) => {
([values, indexes], combinedMethodName) => {
const { rows } = analyzedMethods[combinedMethodName];
// const rows = 1000;
const [moduleName, methodName] = combinedMethodName.split(".");
Expand Down Expand Up @@ -128,7 +128,8 @@ export class RuntimeFeeAnalyzerService extends ConfigurableModule<RuntimeFeeAnal
},
{
...indexes,
[methodId.toString()]: BigInt(index),
// eslint-disable-next-line no-plusplus
[methodId.toString()]: BigInt(methodCounter++),
},
];
},
Expand Down
2 changes: 0 additions & 2 deletions packages/protocol/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ export * from "./prover/block/accummulators/BlockHashMerkleTree";
export * from "./prover/block/services/RuntimeVerificationKeyRootService";
export * from "./prover/statetransition/StateTransitionProver";
export * from "./prover/statetransition/StateTransitionProvable";
export * from "./prover/statetransition/StateTransitionWitnessProvider";
export * from "./prover/statetransition/StateTransitionWitnessProviderReference";
export * from "./protocol/Protocol";
export * from "./protocol/ProtocolModule";
export * from "./protocol/ProtocolEnvironment";
Expand Down
28 changes: 24 additions & 4 deletions packages/protocol/src/model/StateTransitionProvableBatch.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Bool, Provable, Struct } from "o1js";
import { range } from "@proto-kit/common";
import {
InMemoryMerkleTreeStorage,
range,
RollupMerkleTree,
RollupMerkleTreeWitness,
} from "@proto-kit/common";

import { constants } from "../Constants";

Expand Down Expand Up @@ -60,16 +65,22 @@ export class StateTransitionProvableBatch extends Struct({
ProvableStateTransitionType,
constants.stateTransitionProverBatchSize
),

merkleWitnesses: Provable.Array(
RollupMerkleTreeWitness,
constants.stateTransitionProverBatchSize
),
}) {
public static fromMappings(
transitions: {
transition: ProvableStateTransition;
type: ProvableStateTransitionType;
}[]
}[],
merkleWitnesses: RollupMerkleTreeWitness[]
): StateTransitionProvableBatch {
const batch = transitions.map((entry) => entry.transition);
const transitionTypes = transitions.map((entry) => entry.type);

const witnesses = merkleWitnesses.slice();
// Check that order is correct
let normalSTsStarted = false;
transitionTypes.forEach((x) => {
Expand All @@ -84,16 +95,23 @@ export class StateTransitionProvableBatch extends Struct({
while (batch.length < constants.stateTransitionProverBatchSize) {
batch.push(ProvableStateTransition.dummy());
transitionTypes.push(ProvableStateTransitionType.normal);
witnesses.push(
new RollupMerkleTree(new InMemoryMerkleTreeStorage()).getWitness(
BigInt(0)
)
);
}
return new StateTransitionProvableBatch({
batch,
transitionTypes,
merkleWitnesses: witnesses,
});
}

public static fromTransitions(
transitions: ProvableStateTransition[],
protocolTransitions: ProvableStateTransition[]
protocolTransitions: ProvableStateTransition[],
merkleWitnesses: RollupMerkleTreeWitness[]
): StateTransitionProvableBatch {
const array = transitions.slice().concat(protocolTransitions);

Expand All @@ -113,12 +131,14 @@ export class StateTransitionProvableBatch extends Struct({
return new StateTransitionProvableBatch({
batch: array,
transitionTypes,
merkleWitnesses,
});
}

private constructor(object: {
batch: ProvableStateTransition[];
transitionTypes: ProvableStateTransitionType[];
merkleWitnesses: RollupMerkleTreeWitness[];
}) {
super(object);
}
Expand Down
8 changes: 2 additions & 6 deletions packages/protocol/src/prover/block/BlockProvable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class BlockProverPublicInput extends Struct({
blockHashRoot: Field,
eternalTransactionsHash: Field,
incomingMessagesHash: Field,
blockNumber: Field,
}) {}

export class BlockProverPublicOutput extends Struct({
Expand All @@ -36,15 +37,10 @@ export class BlockProverPublicOutput extends Struct({
closed: Bool,
blockNumber: Field,
}) {
public equals(
input: BlockProverPublicInput,
closed: Bool,
blockNumber: Field
): Bool {
public equals(input: BlockProverPublicInput, closed: Bool): Bool {
const output2 = BlockProverPublicOutput.toFields({
...input,
closed,
blockNumber,
});
const output1 = BlockProverPublicOutput.toFields(this);
return output1
Expand Down
49 changes: 30 additions & 19 deletions packages/protocol/src/prover/block/BlockProver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
CompilableModule,
CompileArtifact,
CompileRegistry,
MAX_FIELD,
PlainZkProgram,
provableMethod,
WithZkProgrammable,
Expand Down Expand Up @@ -128,10 +129,6 @@ export interface BlockProverState {
incomingMessagesHash: Field;
}

function maxField() {
return Field(Field.ORDER - 1n);
}

export type BlockProof = Proof<BlockProverPublicInput, BlockProverPublicOutput>;
export type RuntimeProof = Proof<void, MethodPublicOutput>;

Expand Down Expand Up @@ -422,6 +419,11 @@ export class BlockProverProgrammable extends ZkProgrammable<
"ExecutionData Networkstate doesn't equal public input hash"
);

publicInput.blockNumber.assertEquals(
MAX_FIELD,
"blockNumber has to be MAX for transaction proofs"
);

// Verify the [methodId, vk] tuple against the baked-in vk tree root
const { verificationKey, witness: verificationKeyTreeWitness } =
verificationKeyWitness;
Expand Down Expand Up @@ -451,7 +453,7 @@ export class BlockProverProgrammable extends ZkProgrammable<

return new BlockProverPublicOutput({
...stateTo,
blockNumber: maxField(),
blockNumber: publicInput.blockNumber,
closed: Bool(false),
});
}
Expand Down Expand Up @@ -534,14 +536,14 @@ export class BlockProverProgrammable extends ZkProgrammable<
// stateTransitionProof.verifyIf(Bool(false));
// stateTransitionProof.verifyIf(stsEmitted);

// Verify Transaction proof if it has at least 1 tx
// Verify Transaction proof if it has at least 1 tx - i.e. the
// input and output doesn't match fully
// We have to compare the whole input and output because we can make no
// assumptions about the values, since it can be an arbitrary dummy-proof
const txProofOutput = transactionProof.publicOutput;
const isEmptyTransition = txProofOutput.equals(
transactionProof.publicInput,
txProofOutput.closed,
txProofOutput.blockNumber
txProofOutput.closed
);
Provable.log("VerifyIf 2", isEmptyTransition.not());
transactionProof.verifyIf(isEmptyTransition.not());
Expand Down Expand Up @@ -626,6 +628,8 @@ export class BlockProverProgrammable extends ZkProgrammable<
// Calculate the new block index
const blockIndex = blockWitness.calculateIndex();

blockIndex.assertEquals(publicInput.blockNumber);

blockWitness
.calculateRoot(Field(0))
.assertEquals(
Expand All @@ -643,7 +647,7 @@ export class BlockProverProgrammable extends ZkProgrammable<

return new BlockProverPublicOutput({
...state,
blockNumber: blockIndex,
blockNumber: blockIndex.add(1),
closed: Bool(true),
});
}
Expand Down Expand Up @@ -750,19 +754,25 @@ export class BlockProverProgrammable extends ZkProgrammable<
// assert proof1.height == proof2.height
// }

const proof1Height = proof1.publicOutput.blockNumber;
const proof1Closed = proof1.publicOutput.closed;
const proof2Height = proof2.publicOutput.blockNumber;
const proof2Closed = proof2.publicOutput.closed;

const isValidTransactionMerge = proof1Height
.equals(maxField())
.and(proof2Height.equals(proof1Height))
const blockNumberProgressionValid = publicInput.blockNumber
.equals(proof1.publicInput.blockNumber)
.and(
proof1.publicOutput.blockNumber.equals(proof2.publicInput.blockNumber)
);

// For tx proofs, we check that the progression starts and end with MAX
// in addition to that both proofs are non-closed
const isValidTransactionMerge = publicInput.blockNumber
.equals(MAX_FIELD)
.and(blockNumberProgressionValid)
.and(proof1Closed.or(proof2Closed).not());

const isValidClosedMerge = proof1Closed
.and(proof2Closed)
.and(proof1Height.add(1).equals(proof2Height));
.and(blockNumberProgressionValid);

isValidTransactionMerge
.or(isValidClosedMerge)
Expand All @@ -775,9 +785,8 @@ export class BlockProverProgrammable extends ZkProgrammable<
blockHashRoot: proof2.publicOutput.blockHashRoot,
eternalTransactionsHash: proof2.publicOutput.eternalTransactionsHash,
incomingMessagesHash: proof2.publicOutput.incomingMessagesHash,
// Provable.if(isValidClosedMerge, Bool(true), Bool(false));
closed: isValidClosedMerge,
blockNumber: proof2Height,
blockNumber: proof2.publicOutput.blockNumber,
});
}

Expand Down Expand Up @@ -931,8 +940,10 @@ export class BlockProver
public async compile(
registry: CompileRegistry
): Promise<Record<string, CompileArtifact> | undefined> {
await this.stateTransitionProver.compile(registry);
await this.runtime.compile(registry);
await registry.forceProverExists(async () => {
await this.stateTransitionProver.compile(registry);
await this.runtime.compile(registry);
});

return await this.zkProgrammable.compile(registry);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { WithZkProgrammable, CompilableModule } from "@proto-kit/common";

import { StateTransitionProvableBatch } from "../../model/StateTransitionProvableBatch";

import { StateTransitionWitnessProviderReference } from "./StateTransitionWitnessProviderReference";

export class StateTransitionProverPublicInput extends Struct({
stateTransitionsHash: Field,
protocolTransitionsHash: Field,
Expand All @@ -30,8 +28,6 @@ export interface StateTransitionProvable
StateTransitionProverPublicOutput
>,
CompilableModule {
witnessProviderReference: StateTransitionWitnessProviderReference;

runBatch: (
publicInput: StateTransitionProverPublicInput,
batch: StateTransitionProvableBatch
Expand Down
Loading