Skip to content

Commit c0b98ce

Browse files
authored
Merge pull request #224 from proto-kit/feature/proven-settlemnet
Enabled proven settlement
2 parents d9cc60a + c157add commit c0b98ce

File tree

16 files changed

+294
-95
lines changed

16 files changed

+294
-95
lines changed

packages/common/src/compiling/CompileRegistry.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { inject, injectable, singleton } from "tsyringe";
22

3-
import { AreProofsEnabled } from "../zkProgrammable/ZkProgrammable";
3+
import {
4+
AreProofsEnabled,
5+
CompileArtifact,
6+
} from "../zkProgrammable/ZkProgrammable";
47

58
import {
69
ArtifactRecord,
@@ -27,18 +30,32 @@ export class CompileRegistry {
2730

2831
private artifacts: ArtifactRecord = {};
2932

30-
// TODO Add possibility to force recompilation for non-sideloaded dependencies
33+
private inForceProverBlock = false;
34+
35+
/**
36+
* This function forces compilation even if the artifact itself is in the registry.
37+
* Basically the statement is: The artifact along is not enough, we need to
38+
* actually have the prover compiled.
39+
* This is true for non-sideloaded circuit dependencies.
40+
*/
41+
public async forceProverExists(
42+
f: (registry: CompileRegistry) => Promise<void>
43+
) {
44+
this.inForceProverBlock = true;
45+
await f(this);
46+
this.inForceProverBlock = false;
47+
}
3148

3249
public async compile(target: CompileTarget) {
33-
if (this.artifacts[target.name] === undefined) {
50+
if (this.artifacts[target.name] === undefined || this.inForceProverBlock) {
3451
const artifact = await this.compiler.compileContract(target);
3552
this.artifacts[target.name] = artifact;
3653
return artifact;
3754
}
3855
return this.artifacts[target.name];
3956
}
4057

41-
public getArtifact(name: string) {
58+
public getArtifact(name: string): CompileArtifact | undefined {
4259
if (this.artifacts[name] === undefined) {
4360
throw new Error(
4461
`Artifact for ${name} not available, did you compile it via the CompileRegistry?`

packages/common/src/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ export function isSubtypeOfName(
182182
clas: TypedClass<unknown>,
183183
name: string
184184
): boolean {
185+
if (clas === undefined || clas === null) {
186+
return false;
187+
}
188+
185189
if (clas.name === name) {
186190
return true;
187191
}

packages/protocol/src/prover/block/BlockProver.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -940,8 +940,10 @@ export class BlockProver
940940
public async compile(
941941
registry: CompileRegistry
942942
): Promise<Record<string, CompileArtifact> | undefined> {
943-
await this.stateTransitionProver.compile(registry);
944-
await this.runtime.compile(registry);
943+
await registry.forceProverExists(async () => {
944+
await this.stateTransitionProver.compile(registry);
945+
await this.runtime.compile(registry);
946+
});
945947

946948
return await this.zkProgrammable.compile(registry);
947949
}

packages/sequencer/src/protocol/baselayer/MinaBaseLayer.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import { DependencyFactory } from "@proto-kit/common";
1+
import { AreProofsEnabled, DependencyFactory } from "@proto-kit/common";
22
import { Mina } from "o1js";
33
import { match } from "ts-pattern";
4+
import { inject } from "tsyringe";
45

56
import { MinaIncomingMessageAdapter } from "../../settlement/messages/MinaIncomingMessageAdapter";
6-
import { SequencerModule } from "../../sequencer/builder/SequencerModule";
7+
import {
8+
sequencerModule,
9+
SequencerModule,
10+
} from "../../sequencer/builder/SequencerModule";
711
import { MinaTransactionSender } from "../../settlement/transactions/MinaTransactionSender";
812
import { WithdrawalQueue } from "../../settlement/messages/WithdrawalQueue";
913

@@ -27,6 +31,7 @@ export interface MinaBaseLayerConfig {
2731
};
2832
}
2933

34+
@sequencerModule()
3035
export class MinaBaseLayer
3136
extends SequencerModule<MinaBaseLayerConfig>
3237
implements BaseLayer, DependencyFactory
@@ -35,6 +40,13 @@ export class MinaBaseLayer
3540

3641
public originalNetwork?: Parameters<typeof Mina.setActiveInstance>[0];
3742

43+
public constructor(
44+
@inject("AreProofsEnabled")
45+
private readonly areProofsEnabled: AreProofsEnabled
46+
) {
47+
super();
48+
}
49+
3850
public dependencies() {
3951
return {
4052
IncomingMessageAdapter: {
@@ -63,15 +75,18 @@ export class MinaBaseLayer
6375
const Network = await match(network)
6476
.with(
6577
{ type: "local" },
66-
async () => await Mina.LocalBlockchain({ proofsEnabled: false })
78+
async () =>
79+
await Mina.LocalBlockchain({
80+
proofsEnabled: this.areProofsEnabled.areProofsEnabled,
81+
})
6782
)
6883
.with({ type: "lightnet" }, async (lightnet) => {
6984
const net = Mina.Network({
7085
mina: lightnet.graphql,
7186
archive: lightnet.archive,
7287
lightnetAccountManager: lightnet.accountManager,
7388
});
74-
net.proofsEnabled = false;
89+
net.proofsEnabled = this.areProofsEnabled.areProofsEnabled;
7590
return net;
7691
})
7792
.with({ type: "remote" }, async (remote) =>

packages/sequencer/src/protocol/production/tasks/CircuitCompilerTask.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
CompileRegistry,
99
CompilableModule,
1010
safeParseJson,
11+
reduceSequential,
1112
} from "@proto-kit/common";
1213
import {
1314
MandatorySettlementModulesRecord,
@@ -132,11 +133,29 @@ export class CircuitCompilerTask extends UnpreparingTask<
132133
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
133134
settlementModule.moduleNames as StringKeyOf<MandatorySettlementModulesRecord>[];
134135

135-
const modules = moduleNames.map((name) => [
136+
const modules = moduleNames.map<[string, CompilableModule]>((name) => [
136137
`Settlement.${name}`,
137138
settlementModule.resolve(name),
138139
]);
139140

141+
const sumModule = {
142+
compile: async (registry: CompileRegistry) => {
143+
await reduceSequential<CompilableModule, ArtifactRecord>(
144+
modules.map(([, module]) => module),
145+
async (record, module) => {
146+
const artifacts = await module.compile(registry);
147+
return {
148+
...record,
149+
...artifacts,
150+
};
151+
},
152+
{}
153+
);
154+
},
155+
};
156+
157+
modules.push(["Settlement", sumModule]);
158+
140159
return Object.fromEntries(modules);
141160
}
142161
return {};

packages/sequencer/src/protocol/production/tasks/StateTransitionTask.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,6 @@ export class StateTransitionTask
6565
): Promise<StateTransitionProof> {
6666
const stBatch = input.stateTransitions.slice();
6767
const merkleWitnesses = input.merkleWitnesses.slice();
68-
// Array.from({
69-
// length: ProtocolConstants.stateTransitionProverBatchSize - stBatch.length,
70-
// }).forEach(() => {
71-
// stBatch.push({
72-
// ProvableStateTransition.dummy()
73-
// });
74-
// });
7568

7669
const output = await this.stateTransitionProver.runBatch(
7770
input.publicInput,

packages/sequencer/src/sequencer/SequencerStartupModule.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,6 @@ export class SequencerStartupModule extends SequencerModule {
136136
bridgeVk.verificationKey;
137137
}
138138

139-
const record = await this.pushCompileTask(flow, {
140-
existingArtifacts: this.compileRegistry.getAllArtifacts(),
141-
targets: ["Settlement.SettlementContract"],
142-
});
143-
144-
this.compileRegistry.addArtifactsRaw(record);
145-
146-
// TODO Compile all contracts and retrieve artifacts to enable crafting of
147-
// the deployments - edit: can also be done on-demand with the CompileTask
148-
149139
await this.registrationFlow.start({
150140
runtimeVerificationKeyRoot: root,
151141
bridgeContractVerificationKey: bridgeVk?.verificationKey,
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { injectable } from "tsyringe";
2+
import {
3+
ArtifactRecord,
4+
CompileArtifact,
5+
CompileRegistry,
6+
log,
7+
} from "@proto-kit/common";
8+
9+
import { FlowCreator } from "../worker/flow/Flow";
10+
import { CircuitCompilerTask } from "../protocol/production/tasks/CircuitCompilerTask";
11+
12+
@injectable()
13+
export class SettlementStartupModule {
14+
public constructor(
15+
private readonly compileRegistry: CompileRegistry,
16+
private readonly flowCreator: FlowCreator,
17+
private readonly compileTask: CircuitCompilerTask
18+
) {}
19+
20+
// TODO Compile only individual contracts - this however runs into the
21+
// unlinkability issue from module name to artifact name
22+
// although - the settlement proving task currently also only works if
23+
// all contracts that a tx touches are compiled on that worker instance
24+
private async compile() {
25+
const flow = this.flowCreator.createFlow("compile-deploy", {});
26+
const artifacts = await flow.withFlow<ArtifactRecord>(async (res) => {
27+
await flow.pushTask(
28+
this.compileTask,
29+
{
30+
existingArtifacts: this.compileRegistry.getAllArtifacts(),
31+
targets: ["Settlement"],
32+
runtimeVKRoot: undefined,
33+
},
34+
async (result) => res(result)
35+
);
36+
});
37+
this.compileRegistry.addArtifactsRaw(artifacts);
38+
return artifacts;
39+
}
40+
41+
private async getArtifacts(retry: boolean): Promise<{
42+
SettlementSmartContract: CompileArtifact;
43+
DispatchSmartContract: CompileArtifact;
44+
}> {
45+
const settlementVerificationKey = this.compileRegistry.getArtifact(
46+
"SettlementSmartContract"
47+
);
48+
const dispatchVerificationKey = this.compileRegistry.getArtifact(
49+
"DispatchSmartContract"
50+
);
51+
52+
if (
53+
settlementVerificationKey === undefined ||
54+
dispatchVerificationKey === undefined
55+
) {
56+
if (!retry) {
57+
log.info(
58+
"Settlement Contracts not yet compiled, initializing compilation"
59+
);
60+
await this.compile();
61+
return await this.getArtifacts(true);
62+
}
63+
throw new Error(
64+
"Settlement contract verification keys not available for deployment"
65+
);
66+
}
67+
68+
return {
69+
SettlementSmartContract: settlementVerificationKey,
70+
DispatchSmartContract: dispatchVerificationKey,
71+
};
72+
}
73+
74+
public async retrieveVerificationKeys() {
75+
return await this.getArtifacts(false);
76+
}
77+
}

packages/sequencer/src/settlement/SettlementModule.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
log,
2828
AreProofsEnabled,
2929
DependencyFactory,
30-
CompileRegistry,
3130
} from "@proto-kit/common";
3231
import truncate from "lodash/truncate";
3332

@@ -41,6 +40,7 @@ import { Batch, SettleableBatch } from "../storage/model/Batch";
4140
import { BlockProofSerializer } from "../protocol/production/helpers/BlockProofSerializer";
4241
import { Settlement } from "../storage/model/Settlement";
4342
import { FeeStrategy } from "../protocol/baselayer/fees/FeeStrategy";
43+
import { SettlementStartupModule } from "../sequencer/SettlementStartupModule";
4444

4545
import { IncomingMessageAdapter } from "./messages/IncomingMessageAdapter";
4646
import { MinaTransactionSender } from "./transactions/MinaTransactionSender";
@@ -97,7 +97,7 @@ export class SettlementModule
9797
@inject("AreProofsEnabled") areProofsEnabled: AreProofsEnabled,
9898
@inject("FeeStrategy")
9999
private readonly feeStrategy: FeeStrategy,
100-
private readonly compileRegistry: CompileRegistry
100+
private readonly settlementStartupModule: SettlementStartupModule
101101
) {
102102
super();
103103
this.utils = new SettlementUtils(areProofsEnabled, baseLayer);
@@ -253,8 +253,6 @@ export class SettlementModule
253253

254254
const nonce = options?.nonce ?? 0;
255255

256-
// const verificationKey:
257-
258256
const sm = this.protocol.dependencyContainer.resolve<
259257
SettlementContractModule<MandatorySettlementModulesRecord>
260258
>("SettlementContractModule");
@@ -263,6 +261,9 @@ export class SettlementModule
263261
dispatch: dispatchKey.toPublicKey(),
264262
});
265263

264+
const verificationsKeys =
265+
await this.settlementStartupModule.retrieveVerificationKeys();
266+
266267
const permissions = this.utils.isSignedSettlement()
267268
? new SignedSettlementPermissions()
268269
: new ProvenSettlementPermissions();
@@ -277,13 +278,14 @@ export class SettlementModule
277278
async () => {
278279
AccountUpdate.fundNewAccount(feepayer, 2);
279280
await settlement.deploy({
280-
// TODO Create compilation task that generates those artifacts if proofs enabled
281-
verificationKey: undefined,
281+
verificationKey:
282+
verificationsKeys.SettlementSmartContract.verificationKey,
282283
});
283284
settlement.account.permissions.set(permissions.settlementContract());
284285

285286
await dispatch.deploy({
286-
verificationKey: undefined,
287+
verificationKey:
288+
verificationsKeys.DispatchSmartContract.verificationKey,
287289
});
288290
dispatch.account.permissions.set(permissions.dispatchContract());
289291
}

0 commit comments

Comments
 (0)