From f1c19c5891ca78cac2dda0e91cdab86640b60179 Mon Sep 17 00:00:00 2001 From: Matej Sima Date: Tue, 13 Feb 2024 12:42:09 +0100 Subject: [PATCH 1/3] fix: updated TestingAppChain & sdk tests to work with settlement changes --- package.json | 3 +-- .../src/blockmodules/NoopSettlementHook.ts | 10 ++++++++-- packages/sdk/src/appChain/AppChain.ts | 16 +++++++++++---- packages/sdk/src/appChain/TestingAppChain.ts | 6 ++++++ packages/sdk/test/TestingAppChain.test.ts | 4 ++-- packages/sdk/test/XYK/Balances.ts | 2 +- packages/sdk/test/XYK/XYK.ts | 10 +++++----- .../sdk/test/blockProof/blockProof.test.ts | 8 ++++++-- packages/sdk/test/graphql/Post.ts | 13 +++++++++--- packages/sdk/test/graphql/server.ts | 20 +++++++++++-------- packages/sdk/test/networkstate/Balance.ts | 9 ++++++--- packages/sdk/test/parameters.test.ts | 2 +- packages/sequencer/src/index.ts | 1 + 13 files changed, 71 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 70952c2b5..c39411e51 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,5 @@ "*.ts": [ "npm run lint:staged" ] - }, - "dependencies": {} + } } diff --git a/packages/protocol/src/blockmodules/NoopSettlementHook.ts b/packages/protocol/src/blockmodules/NoopSettlementHook.ts index 3aba58c73..0a1a68930 100644 --- a/packages/protocol/src/blockmodules/NoopSettlementHook.ts +++ b/packages/protocol/src/blockmodules/NoopSettlementHook.ts @@ -3,13 +3,19 @@ import { noop } from "@proto-kit/common"; import { SmartContract } from "o1js"; import { BlockProof } from "../prover/block/BlockProver"; -import { ProvableSettlementHook, SettlementHookInputs } from "../settlement/ProvableSettlementHook"; +import { + ProvableSettlementHook, + SettlementHookInputs, +} from "../settlement/ProvableSettlementHook"; @injectable() export class NoopSettlementHook extends ProvableSettlementHook< Record > { - public beforeSettlement(contract: SmartContract, state: SettlementHookInputs): void { + public beforeSettlement( + contract: SmartContract, + state: SettlementHookInputs + ): void { noop(); } } diff --git a/packages/sdk/src/appChain/AppChain.ts b/packages/sdk/src/appChain/AppChain.ts index 890c11c97..6b9fb3aec 100644 --- a/packages/sdk/src/appChain/AppChain.ts +++ b/packages/sdk/src/appChain/AppChain.ts @@ -34,8 +34,10 @@ import { AccountStateModule, StateServiceProvider, ProtocolCustomModulesRecord, + PublicKeyOption, + UInt64Option, } from "@proto-kit/protocol"; -import { Field, ProvableExtended, PublicKey, UInt64, Proof } from "o1js"; +import { Field, ProvableExtended, PublicKey, UInt64, Proof, Bool } from "o1js"; import { container, DependencyContainer } from "tsyringe"; import { AppChainTransaction } from "../transaction/AppChainTransaction"; @@ -246,8 +248,14 @@ export class AppChain< executionContext.setup({ transaction: { - sender, - nonce: UInt64.from(options?.nonce ?? 0), + sender: new PublicKeyOption({ + value: sender, + isSome: Bool(true), + }), + nonce: new UInt64Option({ + isSome: Bool(true), + value: UInt64.from(options?.nonce ?? 0), + }), argsHash: Field(0), } as unknown as RuntimeTransaction, @@ -314,7 +322,7 @@ export class AppChain< argsJSON, nonce, sender, - isMessage: false + isMessage: false, }); const signer = this.container.resolve("Signer"); diff --git a/packages/sdk/src/appChain/TestingAppChain.ts b/packages/sdk/src/appChain/TestingAppChain.ts index 420898c11..345b1c5d8 100644 --- a/packages/sdk/src/appChain/TestingAppChain.ts +++ b/packages/sdk/src/appChain/TestingAppChain.ts @@ -27,6 +27,7 @@ import { InMemoryTransactionSender } from "../transaction/InMemoryTransactionSen import { BlockStorageNetworkStateModule } from "../query/BlockStorageNetworkStateModule"; import { AppChain, AppChainModulesRecord } from "./AppChain"; +import { SettlementModule } from "@proto-kit/sequencer"; export class TestingAppChain< RuntimeModules extends RuntimeModulesRecord, @@ -54,6 +55,7 @@ export class TestingAppChain< UnprovenProducerModule, BlockTrigger: ManualBlockTrigger, TaskQueue: LocalTaskQueue, + SettlementModule: SettlementModule, }, }); @@ -83,6 +85,10 @@ export class TestingAppChain< TaskQueue: { simulatedDuration: 0, }, + SettlementModule: { + feepayer: PrivateKey.random(), + address: PrivateKey.random().toPublicKey(), + }, }, Protocol: { diff --git a/packages/sdk/test/TestingAppChain.test.ts b/packages/sdk/test/TestingAppChain.test.ts index d9411cd66..65a33fc22 100644 --- a/packages/sdk/test/TestingAppChain.test.ts +++ b/packages/sdk/test/TestingAppChain.test.ts @@ -23,7 +23,7 @@ export class Admin extends RuntimeModule { public isSenderAdmin() { assert( - this.transaction.sender.equals(this.config.admin), + this.transaction.sender.value.equals(this.config.admin), "Sender is not admin" ); } @@ -62,7 +62,7 @@ class Balances extends RuntimeModule { "Adding the balance would overflow the total supply" ); - const isSender = this.transaction.sender.equals(address); + const isSender = this.transaction.sender.value.equals(address); assert(isSender, "Address is not the sender"); const currentBalance = this.balances.get(address); diff --git a/packages/sdk/test/XYK/Balances.ts b/packages/sdk/test/XYK/Balances.ts index 925e0e228..a50f36571 100644 --- a/packages/sdk/test/XYK/Balances.ts +++ b/packages/sdk/test/XYK/Balances.ts @@ -92,7 +92,7 @@ export class Balances extends RuntimeModule { to: PublicKey, amount: Balance ) { - assert(this.transaction.sender.equals(from), errors.senderNotFrom()); + assert(this.transaction.sender.value.equals(from), errors.senderNotFrom()); this.transfer(tokenId, from, to, amount); } diff --git a/packages/sdk/test/XYK/XYK.ts b/packages/sdk/test/XYK/XYK.ts index d54ef0954..ea7dd8e37 100644 --- a/packages/sdk/test/XYK/XYK.ts +++ b/packages/sdk/test/XYK/XYK.ts @@ -94,7 +94,7 @@ export class XYK extends RuntimeModule { const key = PoolKey.fromTokenIdPair(tokenIdIn, tokenIdOut); this.pools.set(key, XYK.defaultPoolValue); - const creator = this.transaction.sender; + const creator = this.transaction.sender.value; const pool = PoolKey.fromTokenIdPair(tokenIdIn, tokenIdOut); this.balances.transfer(tokenIdIn, creator, pool, tokenInAmount); @@ -210,7 +210,7 @@ export class XYK extends RuntimeModule { this.balances.transfer( tokenIdIn, - this.transaction.sender, + this.transaction.sender.value, pool, tokenInAmountIn ); @@ -218,7 +218,7 @@ export class XYK extends RuntimeModule { this.balances.transfer( tokenIdOut, pool, - this.transaction.sender, + this.transaction.sender.value, tokenOutAmountOut ); } @@ -252,13 +252,13 @@ export class XYK extends RuntimeModule { this.balances.transfer( tokenIdOut, pool, - this.transaction.sender, + this.transaction.sender.value, tokenOutAmountOut ); this.balances.transfer( tokenIdIn, - this.transaction.sender, + this.transaction.sender.value, pool, tokenInAmountIn ); diff --git a/packages/sdk/test/blockProof/blockProof.test.ts b/packages/sdk/test/blockProof/blockProof.test.ts index 8ef30450d..6f5bfcc30 100644 --- a/packages/sdk/test/blockProof/blockProof.test.ts +++ b/packages/sdk/test/blockProof/blockProof.test.ts @@ -1,5 +1,6 @@ -import { PrivateKey, UInt64 } from "o1js"; +import { Bool, PrivateKey, UInt64 } from "o1js"; import { + PublicKeyOption, RuntimeMethodExecutionContext, StateServiceProvider, } from "@proto-kit/protocol"; @@ -68,7 +69,10 @@ describe("blockProof", () => { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/consistent-type-assertions appChain.protocol.resolve("AccountState").onTransaction({ transaction: { - sender: alice, + sender: new PublicKeyOption({ + isSome: Bool(true), + value: alice, + }), nonce: UInt64.from(0), }, // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/sdk/test/graphql/Post.ts b/packages/sdk/test/graphql/Post.ts index f7208dd49..cdad1a0f2 100644 --- a/packages/sdk/test/graphql/Post.ts +++ b/packages/sdk/test/graphql/Post.ts @@ -5,7 +5,14 @@ import { state, } from "@proto-kit/module"; import { StateMap } from "@proto-kit/protocol"; -import { CircuitString, Field, Poseidon, PublicKey, Struct, UInt64 } from "o1js"; +import { + CircuitString, + Field, + Poseidon, + PublicKey, + Struct, + UInt64, +} from "o1js"; export class Post extends Struct({ message: CircuitString, @@ -25,10 +32,10 @@ export class MessageBoard extends RuntimeModule> { public post(message: CircuitString) { const post = new Post({ message, - author: this.transaction.sender, + author: this.transaction.sender.value, createdAt: this.network.block.height, }); this.posts.set(post.id, post); } -} \ No newline at end of file +} diff --git a/packages/sdk/test/graphql/server.ts b/packages/sdk/test/graphql/server.ts index 4c7190e91..6551daac6 100644 --- a/packages/sdk/test/graphql/server.ts +++ b/packages/sdk/test/graphql/server.ts @@ -21,11 +21,13 @@ import { InMemoryDatabase, LocalTaskQueue, LocalTaskWorkerModule, + ManualBlockTrigger, NoopBaseLayer, PrivateMempool, Sequencer, + SettlementModule, TimedBlockTrigger, - UnprovenProducerModule + UnprovenProducerModule, } from "@proto-kit/sequencer"; import { BlockStorageResolver, @@ -92,7 +94,7 @@ export async function startServer() { }, }), - protocol: VanillaProtocol.from({ }), + protocol: VanillaProtocol.from({}), sequencer: Sequencer.from({ modules: { @@ -103,8 +105,9 @@ export async function startServer() { BaseLayer: NoopBaseLayer, BlockProducerModule, UnprovenProducerModule, - BlockTrigger: TimedBlockTrigger, + BlockTrigger: ManualBlockTrigger, TaskQueue: LocalTaskQueue, + SettlementModule: SettlementModule, Graphql: GraphqlSequencerModule.from({ modules: { @@ -147,7 +150,7 @@ export async function startServer() { StateTransitionProver: {}, AccountState: {}, BlockHeight: {}, - LastStateRoot: {} + LastStateRoot: {}, }, Sequencer: { @@ -156,6 +159,10 @@ export async function startServer() { host: "0.0.0.0", graphiql: true, }, + SettlementModule: { + address: PrivateKey.random().toPublicKey(), + feepayer: PrivateKey.random(), + }, Graphql: { QueryGraphqlModule: {}, @@ -177,10 +184,7 @@ export async function startServer() { allowEmptyBlock: true, }, - BlockTrigger: { - blockInterval: 15000, - settlementInterval: 30000, - }, + BlockTrigger: {}, }, TransactionSender: {}, diff --git a/packages/sdk/test/networkstate/Balance.ts b/packages/sdk/test/networkstate/Balance.ts index 56fee4f14..b9ab18bea 100644 --- a/packages/sdk/test/networkstate/Balance.ts +++ b/packages/sdk/test/networkstate/Balance.ts @@ -48,7 +48,7 @@ export class Balance extends RuntimeModule { public setTotalSupply() { // eslint-disable-next-line @typescript-eslint/no-magic-numbers this.totalSupply.set(UInt64.from(20)); - this.admin.isAdmin(this.transaction.sender); + this.admin.isAdmin(this.transaction.sender.value); } @runtimeMethod() @@ -73,7 +73,7 @@ export class Balance extends RuntimeModule { @runtimeMethod() public addBalanceToSelf(value: UInt64, blockHeight: UInt64) { - const address = this.transaction.sender; + const address = this.transaction.sender.value; const balance = this.balances.get(address); log.provable.debug("Sender:", address); @@ -101,6 +101,9 @@ export class Balance extends RuntimeModule { @runtimeMethod() public assertLastBlockHash(hash: Field) { const lastRootHash = this.network.previous.rootHash; - assert(hash.equals(lastRootHash), `Root hash not matching: ${lastRootHash.toString()}`); + assert( + hash.equals(lastRootHash), + `Root hash not matching: ${lastRootHash.toString()}` + ); } } diff --git a/packages/sdk/test/parameters.test.ts b/packages/sdk/test/parameters.test.ts index 843cda64b..73752f150 100644 --- a/packages/sdk/test/parameters.test.ts +++ b/packages/sdk/test/parameters.test.ts @@ -86,7 +86,7 @@ class TestRuntime extends RuntimeModule { proof: ProgramProof ) { const valid = signature.verify( - this.transaction.sender, + this.transaction.sender.value, TestStruct.toFields(struct) ); assert(valid, "Signature invalid"); diff --git a/packages/sequencer/src/index.ts b/packages/sequencer/src/index.ts index b56bd4306..5b9116e3b 100644 --- a/packages/sequencer/src/index.ts +++ b/packages/sequencer/src/index.ts @@ -58,3 +58,4 @@ export * from "./state/state/DummyStateService"; export * from "./state/state/SyncCachedStateService"; export * from "./state/state/CachedStateService"; export * from "./state/MerkleStoreWitnessProvider"; +export * from "./settlement/SettlementModule"; From eead72b264e15d5df1fc1dd70c87bbd4f64c6394 Mon Sep 17 00:00:00 2001 From: Matej Sima Date: Tue, 13 Feb 2024 20:38:43 +0100 Subject: [PATCH 2/3] testing proofs enabled --- .../src/zkProgrammable/ZkProgrammable.ts | 5 ++ .../src/zkProgrammable/provableMethod.ts | 16 +++- .../src/method/MethodParameterEncoder.ts | 25 ++++-- packages/module/src/method/runtimeMethod.ts | 27 ++++-- packages/module/src/runtime/Runtime.ts | 22 ++++- .../protocol/src/prover/block/BlockProver.ts | 36 +++++++- .../statetransition/StateTransitionProver.ts | 20 +++-- packages/protocol/src/state/assert/assert.ts | 14 ++-- .../context/RuntimeMethodExecutionContext.ts | 3 +- packages/sdk/package.json | 2 +- packages/sdk/src/appChain/AppChain.ts | 13 ++- packages/sdk/test/TestingAppChain.test.ts | 65 +++++++++----- .../production/BlockTaskFlowService.ts | 3 +- .../production/tasks/BlockProvingTask.ts | 6 ++ .../production/tasks/RuntimeProvingTask.ts | 16 +++- .../production/tasks/StateTransitionTask.ts | 11 ++- .../sequencer/src/worker/queue/BullQueue.ts | 4 +- .../src/worker/queue/LocalTaskQueue.ts | 84 ++++++++++++------- .../sequencer/src/worker/queue/TaskQueue.ts | 4 +- .../src/worker/worker/FlowTaskWorker.ts | 16 ++-- .../sequencer/src/worker/worker/TaskWorker.ts | 8 +- 21 files changed, 292 insertions(+), 108 deletions(-) diff --git a/packages/common/src/zkProgrammable/ZkProgrammable.ts b/packages/common/src/zkProgrammable/ZkProgrammable.ts index e859656c3..90d4fceb2 100644 --- a/packages/common/src/zkProgrammable/ZkProgrammable.ts +++ b/packages/common/src/zkProgrammable/ZkProgrammable.ts @@ -78,6 +78,7 @@ export function compileToMockable( { areProofsEnabled }: AreProofsEnabled ): () => Promise { return async () => { + console.log("mocked compile", { areProofsEnabled }); if (areProofsEnabled) { return await compile(); } @@ -104,6 +105,10 @@ export abstract class ZkProgrammable< throw errors.appChainNotSet(this.constructor.name); } + console.log("getting zkProgram()", { + areProofsEnabled: this.appChain.areProofsEnabled, + }); + return { ...zkProgram, verify: verifyToMockable(zkProgram.verify, this.appChain), diff --git a/packages/common/src/zkProgrammable/provableMethod.ts b/packages/common/src/zkProgrammable/provableMethod.ts index c685f569e..38d237c39 100644 --- a/packages/common/src/zkProgrammable/provableMethod.ts +++ b/packages/common/src/zkProgrammable/provableMethod.ts @@ -4,14 +4,21 @@ import { container } from "tsyringe"; import { ProvableMethodExecutionContext } from "./ProvableMethodExecutionContext"; import type { WithZkProgrammable, ZkProgrammable } from "./ZkProgrammable"; import { ToFieldable } from "../utils"; +import { Pickles } from "o1js/dist/node/snarky"; +import { dummyBase64Proof } from "o1js/dist/node/lib/proof_system"; -export type O1JSPrimitive = InferProvable> & ToFieldable; +export type O1JSPrimitive = InferProvable> & + ToFieldable; export type ArgumentTypes = (O1JSPrimitive | Proof)[]; // eslint-disable-next-line etc/prefer-interface export type DecoratedMethod = (...args: ArgumentTypes) => unknown; -export const MOCK_PROOF = "mock-proof"; +// export const MOCK_PROOF = "mock-proof"; +export const [, MOCK_PROOF] = Pickles.proofOfBase64( + await dummyBase64Proof(), + 2 +); export function toProver( methodName: string, @@ -24,6 +31,11 @@ export function toProver( const areProofsEnabled = this.appChain?.areProofsEnabled; if (areProofsEnabled ?? false) { const programProvableMethod = this.zkProgram.methods[methodName]; + console.log("proving provable method", { + methodName, + methods: this.zkProgram.methods, + args, + }); return await Reflect.apply(programProvableMethod, this, args); } diff --git a/packages/module/src/method/MethodParameterEncoder.ts b/packages/module/src/method/MethodParameterEncoder.ts index 8d65e5986..c0e1df8e5 100644 --- a/packages/module/src/method/MethodParameterEncoder.ts +++ b/packages/module/src/method/MethodParameterEncoder.ts @@ -1,5 +1,11 @@ /* eslint-disable no-underscore-dangle */ -import { Field, FlexibleProvable, Proof, ProvableExtended } from "o1js"; +import { + Field, + FlexibleProvable, + Proof, + Provable, + ProvableExtended, +} from "o1js"; import { ArgumentTypes, ProofTypes, @@ -118,17 +124,22 @@ export class MethodParameterEncoder { return argumentType.toFields(argument); }); - const argsJSON = args.map((argument, index) => { - if (argument instanceof Proof) { - return JSON.stringify(argument.toJSON()); - } + let argsJSON: string[]; + + Provable.asProver(() => { + argsJSON = args.map((argument, index) => { + if (argument instanceof Proof) { + return JSON.stringify(argument.toJSON()); + } - const argumentType = this.types[index] as ToJSONableStatic; - return JSON.stringify(argumentType.toJSON(argument)); + const argumentType = this.types[index] as ToJSONableStatic; + return JSON.stringify(argumentType.toJSON(argument)); + }); }); return { argsFields, + // @ts-expect-error argsJSON, }; } diff --git a/packages/module/src/method/runtimeMethod.ts b/packages/module/src/method/runtimeMethod.ts index 5815fc689..6b5f0a56f 100644 --- a/packages/module/src/method/runtimeMethod.ts +++ b/packages/module/src/method/runtimeMethod.ts @@ -5,6 +5,7 @@ import { FlexibleProvable, Poseidon, Proof, + Provable, ProvableExtended, } from "o1js"; import { container } from "tsyringe"; @@ -73,7 +74,6 @@ export function toWrappedMethod( this: RuntimeModule, methodName: string, moduleMethod: (...args: ArgumentTypes) => unknown, - methodArguments: ArgumentTypes, options: { invocationType: RuntimeMethodInvocationType; } @@ -122,14 +122,16 @@ export function toWrappedMethod( * Use the type info obtained previously to convert * the args passed to fields */ - const { argsFields } = MethodParameterEncoder.fromMethod(this, methodName).encode(args); + const { argsFields } = MethodParameterEncoder.fromMethod( + this, + methodName + ).encode(args); // Assert that the argsHash that has been signed matches the given arguments // We can use js-if here, because methodArguments is statically sizes // i.e. the result of the if-statement will be the same for all executions // of this method - const argsHash = - methodArguments.length > 0 ? Poseidon.hash(argsFields) : Field(0); + const argsHash = args.length > 0 ? Poseidon.hash(argsFields) : Field(0); transaction.argsHash.assertEquals( argsHash, @@ -142,13 +144,16 @@ export function toWrappedMethod( const transactionHash = transaction.hash(); const networkStateHash = networkState.hash(); - return new MethodPublicOutput({ + const output = new MethodPublicOutput({ stateTransitionsHash, status, transactionHash, networkStateHash, isMessage, }); + console.log("output", output); + + return output; }; Object.defineProperty(wrappedMethod, "name", { @@ -189,7 +194,9 @@ export function isRuntimeMethod( export type RuntimeMethodInvocationType = "SIGNATURE" | "INCOMING_MESSAGE"; -function runtimeMethodInternal(options: { invocationType: RuntimeMethodInvocationType }) { +function runtimeMethodInternal(options: { + invocationType: RuntimeMethodInvocationType; +}) { return ( target: RuntimeModule, methodName: string, @@ -239,10 +246,11 @@ function runtimeMethodInternal(options: { invocationType: RuntimeMethodInvocatio const simulatedWrappedMethod = Reflect.apply(toWrappedMethod, this, [ methodName, simulatedMethod, - args, options, ]); + Provable.log("simulatedWrappedMethod", args); + /** * Before the prover runs, make sure it is operating on the correct * RuntimeMethodExecutionContext state, meaning it enters and exits @@ -251,6 +259,11 @@ function runtimeMethodInternal(options: { invocationType: RuntimeMethodInvocatio // eslint-disable-next-line @typescript-eslint/no-explicit-any async function prover(this: ZkProgrammable) { executionContext.beforeMethod(constructorName, methodName, args); + console.log("proving method", { + runtimeModuleName: this.constructor.name, + methodName, + invocationType: options.invocationType, + }); const innerProver = toProver( combineMethodName(constructorName, methodName), simulatedWrappedMethod, diff --git a/packages/module/src/runtime/Runtime.ts b/packages/module/src/runtime/Runtime.ts index f533f5827..c1f6084c2 100644 --- a/packages/module/src/runtime/Runtime.ts +++ b/packages/module/src/runtime/Runtime.ts @@ -23,6 +23,7 @@ import { import { combineMethodName, isRuntimeMethod, + runtimeMethodTypeMetadataKey, toWrappedMethod, WrappedMethod, } from "../method/runtimeMethod"; @@ -115,10 +116,16 @@ export class RuntimeZkProgrammable< methodName ); const method = modulePrototype[methodName]; + const invocationType = Reflect.getMetadata( + runtimeMethodTypeMetadataKey, + runtimeModule, + methodName + ); + const wrappedMethod = Reflect.apply( toWrappedMethod, runtimeModule, - [methodName, method] + [methodName, method, { invocationType }] ); // eslint-disable-next-line no-warning-comments @@ -130,6 +137,12 @@ export class RuntimeZkProgrammable< methodName ); + console.log("runtime with method", { + runtimeModuleName, + methodName, + invocationType, + }); + return { ...allModuleMethods, @@ -163,6 +176,8 @@ export class RuntimeZkProgrammable< methods: sortedRuntimeMethods, }); + console.log("runtime methods", sortedRuntimeMethods); + const SelfProof = Experimental.ZkProgram.Proof(program); const methods = Object.keys(sortedRuntimeMethods).reduce< @@ -173,7 +188,10 @@ export class RuntimeZkProgrammable< }, {}); return { - compile: program.compile.bind(program), + compile: async () => { + console.log("compiling runtime"); + return await program.compile.bind(program)(); + }, verify: program.verify.bind(program), Proof: SelfProof, methods, diff --git a/packages/protocol/src/prover/block/BlockProver.ts b/packages/protocol/src/prover/block/BlockProver.ts index c97644e66..a57cd5827 100644 --- a/packages/protocol/src/prover/block/BlockProver.ts +++ b/packages/protocol/src/prover/block/BlockProver.ts @@ -35,7 +35,10 @@ import { RuntimeMethodExecutionContext } from "../../state/context/RuntimeMethod import { ProvableBlockHook } from "../../protocol/ProvableBlockHook"; import { NetworkState } from "../../model/network/NetworkState"; import { SignedTransaction } from "../../model/transaction/SignedTransaction"; -import { MinaActions, MinaActionsHashList } from "../../utils/MinaPrefixedProvableHashList"; +import { + MinaActions, + MinaActionsHashList, +} from "../../utils/MinaPrefixedProvableHashList"; import { BlockProvable, @@ -366,7 +369,9 @@ export class BlockProverProgrammable extends ZkProgrammable< // Append tx to incomingMessagesHash const actionHash = MinaActions.actionHash(transaction.hashData()); - const incomingMessagesList = new MinaActionsHashList(state.incomingMessagesHash); + const incomingMessagesList = new MinaActionsHashList( + state.incomingMessagesHash + ); incomingMessagesList.pushIf(actionHash, isMessage); stateTo.incomingMessagesHash = incomingMessagesList.commitment; @@ -736,6 +741,7 @@ export class BlockProverProgrammable extends ZkProgrammable< const proveTransaction = prover.proveTransaction.bind(prover); const merge = prover.merge.bind(prover); + const proveBlock = prover.proveBlock.bind(prover); const program = Experimental.ZkProgram({ publicInput: BlockProverPublicInput, @@ -764,6 +770,31 @@ export class BlockProverProgrammable extends ZkProgrammable< }, }, + proveBlock: { + privateInputs: [ + NetworkState, + BlockHashMerkleTreeWitness, + StateTransitionProofClass, + SelfProof, + ], + + method( + publicInput: BlockProverPublicInput, + networkState: NetworkState, + blockWitness: BlockHashMerkleTreeWitness, + stateTransitionProof: StateTransitionProof, + transactionProof: BlockProverProof + ) { + return proveBlock( + publicInput, + networkState, + blockWitness, + stateTransitionProof, + transactionProof + ); + }, + }, + merge: { privateInputs: [ SelfProof, @@ -783,6 +814,7 @@ export class BlockProverProgrammable extends ZkProgrammable< const methods = { proveTransaction: program.proveTransaction, + proveBlock: program.proveBlock, merge: program.merge, }; diff --git a/packages/protocol/src/prover/statetransition/StateTransitionProver.ts b/packages/protocol/src/prover/statetransition/StateTransitionProver.ts index e376924b4..0f8385d62 100644 --- a/packages/protocol/src/prover/statetransition/StateTransitionProver.ts +++ b/packages/protocol/src/prover/statetransition/StateTransitionProver.ts @@ -89,7 +89,7 @@ export class StateTransitionProverProgrammable extends ZkProgrammable< publicOutput: StateTransitionProverPublicOutput, methods: { - proveBatch: { + runBatch: { privateInputs: [StateTransitionProvableBatch], method( @@ -118,7 +118,7 @@ export class StateTransitionProverProgrammable extends ZkProgrammable< }); const methods = { - proveBatch: program.proveBatch.bind(program), + runBatch: program.runBatch.bind(program), merge: program.merge.bind(program), }; @@ -199,14 +199,18 @@ export class StateTransitionProverProgrammable extends ZkProgrammable< transition.from.value ); - membershipValid - .or(transition.from.isSome.not()) - .assertTrue( - errors.merkleWitnessNotCorrect( + const isTransitionValid = membershipValid.or(transition.from.isSome.not()); + + Provable.asProver(() => { + if (!isTransitionValid.toBoolean()) { + throw errors.merkleWitnessNotCorrect( index, type.isNormal().toBoolean() ? "normal" : "protocol" - ) - ); + ); + } + }); + + isTransitionValid.assertTrue(); const newRoot = witness.calculateRoot(transition.to.value); diff --git a/packages/protocol/src/state/assert/assert.ts b/packages/protocol/src/state/assert/assert.ts index 0009c250b..f2c2a33b5 100644 --- a/packages/protocol/src/state/assert/assert.ts +++ b/packages/protocol/src/state/assert/assert.ts @@ -1,4 +1,4 @@ -import { Bool } from "o1js"; +import { Bool, Provable } from "o1js"; import { container } from "tsyringe"; import { log } from "@proto-kit/common"; @@ -18,12 +18,14 @@ export function assert(condition: Bool, message?: string) { const previousStatus = executionContext.current().result.status; const status = condition.and(previousStatus); - if (!condition.toBoolean()) { - if (!executionContext.current().isSimulated) { - log.debug("Assertion failed: ", message); + Provable.asProver(() => { + if (!condition.toBoolean()) { + if (!executionContext.current().isSimulated) { + log.debug("Assertion failed: ", message); + } + executionContext.setStatusMessage(message); } - executionContext.setStatusMessage(message); - } + }); executionContext.setStatus(status); } diff --git a/packages/protocol/src/state/context/RuntimeMethodExecutionContext.ts b/packages/protocol/src/state/context/RuntimeMethodExecutionContext.ts index 45213125d..8d413e0ae 100644 --- a/packages/protocol/src/state/context/RuntimeMethodExecutionContext.ts +++ b/packages/protocol/src/state/context/RuntimeMethodExecutionContext.ts @@ -95,6 +95,7 @@ export class RuntimeMethodExecutionContext extends ProvableMethodExecutionContex * @param input Input witness data required for a runtime execution */ public setup(input: RuntimeMethodExecutionData) { + Provable.log("setting up with input", input); this.input = input; } @@ -125,7 +126,7 @@ export class RuntimeMethodExecutionContext extends ProvableMethodExecutionContex super.afterMethod(); if (this.isFinished) { this.lastInput = this.input; - this.input = undefined; + // this.input = undefined; this.isSimulated = false; } } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index dfa5855a5..467f84e19 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -8,7 +8,7 @@ "build": "tsc -p tsconfig.json", "dev": "tsc -p tsconfig.json --watch", "lint": "eslint ./src ./test", - "test:file": "node --experimental-vm-modules --experimental-wasm-modules --experimental-wasm-threads ../../node_modules/jest/bin/jest.js", + "test:file": "node --experimental-vm-modules --experimental-wasm-modules ../../node_modules/jest/bin/jest.js", "test": "npm run test:file -- ./src/** ./test/**", "test:watch": "npm run test:file -- ./src/** ./test/** --watch", "graphql": "cd ../api && npm run build && cd ../sdk && npm run test:file -- test/graphql/run-graphql.test.ts" diff --git a/packages/sdk/src/appChain/AppChain.ts b/packages/sdk/src/appChain/AppChain.ts index 6b9fb3aec..2a4340e04 100644 --- a/packages/sdk/src/appChain/AppChain.ts +++ b/packages/sdk/src/appChain/AppChain.ts @@ -45,7 +45,10 @@ import { Signer } from "../transaction/InMemorySigner"; import { TransactionSender } from "../transaction/InMemoryTransactionSender"; import { AppChainModule } from "./AppChainModule"; -import { AreProofsEnabledFactory } from "./AreProofsEnabledFactory"; +import { + AreProofsEnabledFactory, + InMemoryAreProofsEnabled, +} from "./AreProofsEnabledFactory"; import { SharedDependencyFactory } from "./SharedDependencyFactory"; export type AppChainModulesRecord = ModulesRecord< @@ -345,6 +348,14 @@ export class AppChain< this.useDependencyFactory(this.container.resolve(AreProofsEnabledFactory)); this.useDependencyFactory(this.container.resolve(SharedDependencyFactory)); + const areProofsEnabled = this.resolveOrFail( + "AreProofsEnabled", + InMemoryAreProofsEnabled + ); + areProofsEnabled.setProofsEnabled(true); + + console.log("areProofsEnabled", areProofsEnabled); + // These three statements are crucial for dependencies inside any of these // components to access their siblings inside their constructor. // This is because when it is the first time they are resolved, create() diff --git a/packages/sdk/test/TestingAppChain.test.ts b/packages/sdk/test/TestingAppChain.test.ts index 65a33fc22..bf0e78bcd 100644 --- a/packages/sdk/test/TestingAppChain.test.ts +++ b/packages/sdk/test/TestingAppChain.test.ts @@ -7,11 +7,14 @@ import { runtimeModule, state, } from "@proto-kit/module"; -import { TestingAppChain } from "../src/index"; +import { InMemoryAreProofsEnabled, TestingAppChain } from "../src/index"; import { container, inject } from "tsyringe"; -import { log } from "@proto-kit/common"; +import { AreProofsEnabled, log } from "@proto-kit/common"; import { randomUUID } from "crypto"; import { assert, State, StateMap } from "@proto-kit/protocol"; +import { ManualBlockTrigger } from "@proto-kit/sequencer"; + +log.setLevel("debug"); export interface AdminConfig { admin: PublicKey; @@ -42,34 +45,40 @@ class Balances extends RuntimeModule { UInt64 ); - public constructor(@inject("Admin") public admin: Admin) { - super(); - } + /** + * The constructor function takes an instance of the Admin class as a parameter and assigns it to the + * admin property. + * @param {Admin} admin - The "admin" parameter is of type "Admin" and is being injected using the + * "@inject" decorator. + */ + // public constructor(@inject("Admin") public admin: Admin) { + // super(); + // } @runtimeMethod() public addBalance(address: PublicKey, balance: UInt64) { - const totalSupply = this.totalSupply.get(); + // const totalSupply = this.totalSupply.get(); - const newTotalSupply = totalSupply.value.add(balance); - const isSupplyNotOverflown = newTotalSupply.lessThanOrEqual( - this.config.totalSupply - ); + // const newTotalSupply = totalSupply.value.add(balance); + // const isSupplyNotOverflown = newTotalSupply.lessThanOrEqual( + // this.config.totalSupply + // ); - this.totalSupply.set(newTotalSupply); + // this.totalSupply.set(newTotalSupply); - assert( - isSupplyNotOverflown, - "Adding the balance would overflow the total supply" - ); + // assert( + // isSupplyNotOverflown, + // "Adding the balance would overflow the total supply" + // ); - const isSender = this.transaction.sender.value.equals(address); - assert(isSender, "Address is not the sender"); + // const isSender = this.transaction.sender.value.equals(address); + // assert(isSender, "Address is not the sender"); - const currentBalance = this.balances.get(address); + // const currentBalance = this.balances.get(address); - const newBalance = currentBalance.value.add(balance); + // const newBalance = currentBalance.value.add(balance); - this.balances.set(address, newBalance); + this.balances.set(address, balance); } } @@ -103,6 +112,14 @@ describe("testing app chain", () => { // start the chain, sequencer is now accepting transactions await appChain.start(); + // const areProofsEnabled = appChain.resolveOrFail( + // "AreProofsEnabled", + // InMemoryAreProofsEnabled + // ); + // areProofsEnabled.setProofsEnabled(true); + + // console.log("areProofsEnabled", areProofsEnabled); + /** * Setup the transaction signer / sender */ @@ -128,11 +145,17 @@ describe("testing app chain", () => { expect(block?.transactions[0].status.toBoolean()).toBe(true); + console.log("proving"); + console.time("prove"); + const provenBlock = await appChain.sequencer + .resolveOrFail("BlockTrigger", ManualBlockTrigger) + .produceProven(); + console.timeEnd("prove"); /** * Observe new state after the block has been produced */ const balance = await appChain.query.runtime.Balances.balances.get(sender); expect(balance?.toBigInt()).toBe(1000n); - }, 60_000); + }, 6_000_000); }); diff --git a/packages/sequencer/src/protocol/production/BlockTaskFlowService.ts b/packages/sequencer/src/protocol/production/BlockTaskFlowService.ts index 381e63d87..c978ecdfe 100644 --- a/packages/sequencer/src/protocol/production/BlockTaskFlowService.ts +++ b/packages/sequencer/src/protocol/production/BlockTaskFlowService.ts @@ -288,7 +288,8 @@ export class BlockTaskFlowService { eternalTransactionsHash: blockTrace.block.publicInput.eternalTransactionsHash, - incomingMessagesHash: blockTrace.block.publicInput.incomingMessagesHash, + incomingMessagesHash: + blockTrace.block.publicInput.incomingMessagesHash, }; const publicInput = new BlockProverPublicInput(piObject); diff --git a/packages/sequencer/src/protocol/production/tasks/BlockProvingTask.ts b/packages/sequencer/src/protocol/production/tasks/BlockProvingTask.ts index 14a78391c..4303eaf38 100644 --- a/packages/sequencer/src/protocol/production/tasks/BlockProvingTask.ts +++ b/packages/sequencer/src/protocol/production/tasks/BlockProvingTask.ts @@ -100,10 +100,13 @@ export class BlockReductionTask } public async prepare(): Promise { + console.log("preparing block prover"); + console.time("prepare-block-prover-merge"); await this.compileRegistry.compile( "BlockProver", this.blockProver.zkProgrammable.zkProgram ); + console.timeEnd("prepare-block-prover-merge"); } } @@ -250,9 +253,12 @@ export class BlockProvingTask // eslint-disable-next-line sonarjs/no-identical-functions public async prepare(): Promise { // Compile + console.log("compiling blockprover"); + console.time("prepare-block-prover-tx"); await this.compileRegistry.compile( "BlockProver", this.blockProver.zkProgrammable.zkProgram ); + console.timeEnd("prepare-block-prover-tx"); } } diff --git a/packages/sequencer/src/protocol/production/tasks/RuntimeProvingTask.ts b/packages/sequencer/src/protocol/production/tasks/RuntimeProvingTask.ts index 21004dc7d..becf7cc43 100644 --- a/packages/sequencer/src/protocol/production/tasks/RuntimeProvingTask.ts +++ b/packages/sequencer/src/protocol/production/tasks/RuntimeProvingTask.ts @@ -1,4 +1,4 @@ -import { inject, injectable, Lifecycle, scoped } from "tsyringe"; +import { container, inject, injectable, Lifecycle, scoped } from "tsyringe"; import { MethodIdResolver, MethodParameterEncoder, @@ -8,8 +8,11 @@ import { MethodPublicOutput, RuntimeTransaction, RuntimeMethodExecutionContext, + PublicKeyOption, + UInt64Option, + NetworkState, } from "@proto-kit/protocol"; -import { Proof } from "o1js"; +import { Field, Proof, PublicKey, UInt64 } from "o1js"; import { Task } from "../../../worker/flow/Task"; import { TaskSerializer } from "../../../worker/manager/ReducableTask"; @@ -90,6 +93,15 @@ export class RuntimeProvingTask } public async prepare(): Promise { + const inputs = { + transaction: RuntimeTransaction.dummyTransaction(), + networkState: NetworkState.empty(), + }; + console.log("preparing runtime proving task", inputs); + const context = container.resolve(RuntimeMethodExecutionContext); + context.setup(inputs); + console.time("prepare-runtime"); await this.runtimeZkProgrammable.compile(); + console.timeEnd("prepare-runtime"); } } diff --git a/packages/sequencer/src/protocol/production/tasks/StateTransitionTask.ts b/packages/sequencer/src/protocol/production/tasks/StateTransitionTask.ts index 42ee610ae..3a7ea433b 100644 --- a/packages/sequencer/src/protocol/production/tasks/StateTransitionTask.ts +++ b/packages/sequencer/src/protocol/production/tasks/StateTransitionTask.ts @@ -78,10 +78,10 @@ export class StateTransitionTask input.publicInput, StateTransitionProvableBatch.fromMappings(stBatch) ); - log.debug("STTask public io:", { - input: StateTransitionProverPublicInput.toJSON(input.publicInput), - output: StateTransitionProverPublicOutput.toJSON(output), - }); + // log.debug("STTask public io:", { + // input: StateTransitionProverPublicInput.toJSON(input.publicInput), + // output: StateTransitionProverPublicOutput.toJSON(output), + // }); const proof = await this.executionContext .current() @@ -94,10 +94,13 @@ export class StateTransitionTask } public async prepare(): Promise { + console.log("compiling st prover"); + console.time("prepare-st-prover"); await this.compileRegistry.compile( "StateTransitionProver", this.stateTransitionProver.zkProgrammable.zkProgram ); + console.timeEnd("prepare-st-prover"); } } diff --git a/packages/sequencer/src/worker/queue/BullQueue.ts b/packages/sequencer/src/worker/queue/BullQueue.ts index e5049f782..9bf0d2e26 100644 --- a/packages/sequencer/src/worker/queue/BullQueue.ts +++ b/packages/sequencer/src/worker/queue/BullQueue.ts @@ -23,11 +23,11 @@ export class BullQueue implements TaskQueue { } = {} ) {} - public createWorker( + public async createWorker( name: string, executor: (data: TaskPayload) => Promise, options?: { concurrency: number } - ): Closeable { + ): Promise { const worker = new Worker( name, async (job) => JSON.stringify(await executor(job.data)), diff --git a/packages/sequencer/src/worker/queue/LocalTaskQueue.ts b/packages/sequencer/src/worker/queue/LocalTaskQueue.ts index bb637c9fb..aac78411d 100644 --- a/packages/sequencer/src/worker/queue/LocalTaskQueue.ts +++ b/packages/sequencer/src/worker/queue/LocalTaskQueue.ts @@ -19,14 +19,18 @@ export interface LocalTaskQueueConfig { simulatedDuration?: number; } -export class LocalTaskQueue extends SequencerModule implements TaskQueue { +export class LocalTaskQueue + extends SequencerModule + implements TaskQueue +{ private queues: { [key: string]: { payload: TaskPayload; taskId: string }[]; } = {}; + private busy = false; + private workers: { [key: string]: { - busy: boolean; handler: (data: TaskPayload) => Promise; }; } = {}; @@ -35,46 +39,66 @@ export class LocalTaskQueue extends SequencerModule implem [key: string]: QueueListener[]; } = {}; - private workNextTasks() { - Object.entries(this.queues).forEach((queue) => { - const [queueName, tasks] = queue; - - if (tasks.length > 0) { - tasks.forEach((task) => { - // Execute task in worker - // eslint-disable-next-line max-len - // eslint-disable-next-line promise/prefer-await-to-then,promise/always-return - void this.workers[queueName].handler(task.payload).then((payload) => { - log.debug("LocalTaskQueue got", JSON.stringify(payload)); - // Notify listeners about result - const listenerPromises = this.listeners[queueName].map( - async (listener) => { - await listener(payload); - } - ); - void Promise.all(listenerPromises); - }); - }); - } + private async workNextTasks() { + log.debug("workNextTasks busy", this.busy); + if (this.busy) return; + this.busy = true; + + try { + for (const queueName of Object.keys(this.queues)) { + if (!this.workers[queueName]) return; + + const tasks = this.queues[queueName]; + + for (const task of tasks) { + const worker = this.workers[queueName]; - this.queues[queue[0]] = []; - }); + // clear the currently processed task from the queue + this.queues[queueName] = this.queues[queueName].filter( + (pendingTask) => pendingTask.taskId !== task.taskId + ); + + log.debug("LocalTaskQueue processing", task.payload.name); + console.time("handling"); + const result = await worker.handler(task.payload); + console.timeEnd("handling"); + log.debug("LocalTaskQueue got", JSON.stringify(result)); + + for (const listener of this.listeners[queueName]) { + await listener(result); + } + } + } + } catch (error) { + log.error("LocalTaskQueue error:", error); + } finally { + this.busy = false; + } + + const outstandingTasks = Object.values(this.queues).reduce( + (taskCount, tasks) => taskCount.concat(tasks), + [] + ).length; + + log.debug("outstandingTasks", outstandingTasks); + + if (outstandingTasks > 0) { + this.workNextTasks(); + } } - public createWorker( + public async createWorker( queueName: string, executor: (data: TaskPayload) => Promise - ): Closeable { + ): Promise { this.workers[queueName] = { - busy: false, - handler: async (data: TaskPayload) => { await sleep(this.config.simulatedDuration ?? 0); return await executor(data); }, }; - this.workNextTasks(); + await this.workNextTasks(); return { // eslint-disable-next-line putout/putout close: async () => { diff --git a/packages/sequencer/src/worker/queue/TaskQueue.ts b/packages/sequencer/src/worker/queue/TaskQueue.ts index d48a0ebee..96db4af15 100644 --- a/packages/sequencer/src/worker/queue/TaskQueue.ts +++ b/packages/sequencer/src/worker/queue/TaskQueue.ts @@ -10,7 +10,7 @@ export interface TaskQueue { createWorker: ( name: string, executor: (data: TaskPayload) => Promise - ) => Closeable; + ) => Promise; } export interface Closeable { @@ -34,4 +34,4 @@ export interface InstantiatedQueue extends Closeable { onCompleted: ( listener: (payload: TaskPayload) => Promise ) => Promise; -} \ No newline at end of file +} diff --git a/packages/sequencer/src/worker/worker/FlowTaskWorker.ts b/packages/sequencer/src/worker/worker/FlowTaskWorker.ts index 37441106d..82643a6a3 100644 --- a/packages/sequencer/src/worker/worker/FlowTaskWorker.ts +++ b/packages/sequencer/src/worker/worker/FlowTaskWorker.ts @@ -39,6 +39,7 @@ export class FlowTaskWorker[]> // element type, and after that, we expect multiple elements of that -> [] private initHandler(task: Task) { const queueName = task.name; + console.log("initHandler", queueName); return this.queue.createWorker(queueName, async (data) => { log.debug(`Received task in queue ${queueName}`); @@ -64,7 +65,7 @@ export class FlowTaskWorker[]> } catch (error: unknown) { const payload = error instanceof Error ? error.message : JSON.stringify(error); - + console.trace("error", error); return { status: "error", taskId: data.taskId, @@ -85,11 +86,14 @@ export class FlowTaskWorker[]> await task.prepare(); } - this.workers = this.tasks.map((task: Task) => - this.initHandler< - InferTaskInput, - InferTaskOutput - >(task) + this.workers = await Promise.all( + this.tasks.map( + async (task: Task) => + await this.initHandler< + InferTaskInput, + InferTaskOutput + >(task) + ) ); } diff --git a/packages/sequencer/src/worker/worker/TaskWorker.ts b/packages/sequencer/src/worker/worker/TaskWorker.ts index e8a289494..dea122818 100644 --- a/packages/sequencer/src/worker/worker/TaskWorker.ts +++ b/packages/sequencer/src/worker/worker/TaskWorker.ts @@ -161,9 +161,11 @@ export class TaskWorker implements Closeable { await task.task.prepare(); } - this.workers = Object.entries( - groupBy(this.tasks, (task) => task.queue) - ).map((tasks) => this.initHandler(tasks[0], tasks[1])); + this.workers = await Promise.all( + Object.entries(groupBy(this.tasks, (task) => task.queue)).map( + async (tasks) => await this.initHandler(tasks[0], tasks[1]) + ) + ); } public async close() { From 0c6169fbc6fb9203706a9bf56db00265595d0a71 Mon Sep 17 00:00:00 2001 From: Matej Sima Date: Thu, 22 Feb 2024 10:21:16 +0100 Subject: [PATCH 3/3] updated zk programs to enable proving --- .../src/zkProgrammable/ZkProgrammable.ts | 13 +-- packages/module/src/runtime/Runtime.ts | 6 +- packages/module/src/runtime/RuntimeModule.ts | 4 +- .../protocol/src/prover/block/BlockProver.ts | 1 + .../statetransition/StateTransitionProver.ts | 1 + packages/sdk/src/appChain/AppChain.ts | 8 -- packages/sdk/test/TestingAppChain.test.ts | 80 ++++++++++++------- .../production/tasks/RuntimeProvingTask.ts | 6 ++ .../worker/worker/LocalTaskWorkerModule.ts | 25 +++--- 9 files changed, 87 insertions(+), 57 deletions(-) diff --git a/packages/common/src/zkProgrammable/ZkProgrammable.ts b/packages/common/src/zkProgrammable/ZkProgrammable.ts index 90d4fceb2..6296517df 100644 --- a/packages/common/src/zkProgrammable/ZkProgrammable.ts +++ b/packages/common/src/zkProgrammable/ZkProgrammable.ts @@ -34,6 +34,7 @@ export interface PlainZkProgram { FlexibleProvablePure > >; + analyzeMethods(): any; methods: Record< string, | (( @@ -50,10 +51,10 @@ export interface PlainZkProgram { export function verifyToMockable( verify: Verify, - { areProofsEnabled }: AreProofsEnabled + areProofsEnabled: AreProofsEnabled ) { return async (proof: Proof) => { - if (areProofsEnabled) { + if (areProofsEnabled.areProofsEnabled) { let verified = false; try { @@ -75,11 +76,13 @@ export const MOCK_VERIFICATION_KEY = "mock-verification-key"; export function compileToMockable( compile: Compile, - { areProofsEnabled }: AreProofsEnabled + areProofsEnabled: AreProofsEnabled ): () => Promise { return async () => { - console.log("mocked compile", { areProofsEnabled }); - if (areProofsEnabled) { + console.log("mocked compile", { + areProofsEnabled: areProofsEnabled.areProofsEnabled, + }); + if (areProofsEnabled.areProofsEnabled) { return await compile(); } diff --git a/packages/module/src/runtime/Runtime.ts b/packages/module/src/runtime/Runtime.ts index c1f6084c2..eb9fec451 100644 --- a/packages/module/src/runtime/Runtime.ts +++ b/packages/module/src/runtime/Runtime.ts @@ -188,10 +188,8 @@ export class RuntimeZkProgrammable< }, {}); return { - compile: async () => { - console.log("compiling runtime"); - return await program.compile.bind(program)(); - }, + ...program, + compile: program.compile.bind(program), verify: program.verify.bind(program), Proof: SelfProof, methods, diff --git a/packages/module/src/runtime/RuntimeModule.ts b/packages/module/src/runtime/RuntimeModule.ts index b8a744817..032971f49 100644 --- a/packages/module/src/runtime/RuntimeModule.ts +++ b/packages/module/src/runtime/RuntimeModule.ts @@ -57,10 +57,12 @@ export class RuntimeModule< } private getInputs(): RuntimeMethodExecutionData { - const { input } = container.resolve( + const context = container.resolve( RuntimeMethodExecutionContext ); + const input = context.witnessInput(); + if (input === undefined) { throw errors.inputDataNotSet(); } diff --git a/packages/protocol/src/prover/block/BlockProver.ts b/packages/protocol/src/prover/block/BlockProver.ts index a57cd5827..61865d775 100644 --- a/packages/protocol/src/prover/block/BlockProver.ts +++ b/packages/protocol/src/prover/block/BlockProver.ts @@ -821,6 +821,7 @@ export class BlockProverProgrammable extends ZkProgrammable< const SelfProofClass = Experimental.ZkProgram.Proof(program); return { + ...program, compile: program.compile.bind(program), verify: program.verify.bind(program), Proof: SelfProofClass, diff --git a/packages/protocol/src/prover/statetransition/StateTransitionProver.ts b/packages/protocol/src/prover/statetransition/StateTransitionProver.ts index 0f8385d62..49d675a66 100644 --- a/packages/protocol/src/prover/statetransition/StateTransitionProver.ts +++ b/packages/protocol/src/prover/statetransition/StateTransitionProver.ts @@ -125,6 +125,7 @@ export class StateTransitionProverProgrammable extends ZkProgrammable< const SelfProofClass = Experimental.ZkProgram.Proof(program); return { + ...program, compile: program.compile.bind(program), verify: program.verify.bind(program), Proof: SelfProofClass, diff --git a/packages/sdk/src/appChain/AppChain.ts b/packages/sdk/src/appChain/AppChain.ts index 2a4340e04..479b18b08 100644 --- a/packages/sdk/src/appChain/AppChain.ts +++ b/packages/sdk/src/appChain/AppChain.ts @@ -348,14 +348,6 @@ export class AppChain< this.useDependencyFactory(this.container.resolve(AreProofsEnabledFactory)); this.useDependencyFactory(this.container.resolve(SharedDependencyFactory)); - const areProofsEnabled = this.resolveOrFail( - "AreProofsEnabled", - InMemoryAreProofsEnabled - ); - areProofsEnabled.setProofsEnabled(true); - - console.log("areProofsEnabled", areProofsEnabled); - // These three statements are crucial for dependencies inside any of these // components to access their siblings inside their constructor. // This is because when it is the first time they are resolved, create() diff --git a/packages/sdk/test/TestingAppChain.test.ts b/packages/sdk/test/TestingAppChain.test.ts index bf0e78bcd..30ff3c99d 100644 --- a/packages/sdk/test/TestingAppChain.test.ts +++ b/packages/sdk/test/TestingAppChain.test.ts @@ -11,8 +11,16 @@ import { InMemoryAreProofsEnabled, TestingAppChain } from "../src/index"; import { container, inject } from "tsyringe"; import { AreProofsEnabled, log } from "@proto-kit/common"; import { randomUUID } from "crypto"; -import { assert, State, StateMap } from "@proto-kit/protocol"; -import { ManualBlockTrigger } from "@proto-kit/sequencer"; +import { + assert, + RuntimeMethodExecutionContext, + State, + StateMap, +} from "@proto-kit/protocol"; +import { + LocalTaskWorkerModule, + ManualBlockTrigger, +} from "@proto-kit/sequencer"; log.setLevel("debug"); @@ -22,8 +30,6 @@ export interface AdminConfig { @runtimeModule() export class Admin extends RuntimeModule { - public id = randomUUID(); - public isSenderAdmin() { assert( this.transaction.sender.value.equals(this.config.admin), @@ -51,34 +57,39 @@ class Balances extends RuntimeModule { * @param {Admin} admin - The "admin" parameter is of type "Admin" and is being injected using the * "@inject" decorator. */ - // public constructor(@inject("Admin") public admin: Admin) { - // super(); - // } + public constructor(@inject("Admin") public admin: Admin) { + super(); + } @runtimeMethod() public addBalance(address: PublicKey, balance: UInt64) { - // const totalSupply = this.totalSupply.get(); + this.admin.isSenderAdmin(); + const totalSupply = this.totalSupply.get(); - // const newTotalSupply = totalSupply.value.add(balance); - // const isSupplyNotOverflown = newTotalSupply.lessThanOrEqual( - // this.config.totalSupply - // ); + const newTotalSupply = totalSupply.value.add(balance); + const isSupplyNotOverflown = newTotalSupply.lessThanOrEqual( + this.config.totalSupply + ); + + this.totalSupply.set(newTotalSupply); - // this.totalSupply.set(newTotalSupply); + assert( + isSupplyNotOverflown, + "Adding the balance would overflow the total supply" + ); - // assert( - // isSupplyNotOverflown, - // "Adding the balance would overflow the total supply" - // ); + const isSender = this.transaction.sender.value.equals(address); + assert(isSender, "Address is not the sender"); - // const isSender = this.transaction.sender.value.equals(address); - // assert(isSender, "Address is not the sender"); + const currentBalance = this.balances.get(address); - // const currentBalance = this.balances.get(address); + const newBalance = currentBalance.value.add(balance); - // const newBalance = currentBalance.value.add(balance); + this.balances.set(address, newBalance); - this.balances.set(address, balance); + const context = container.resolve(RuntimeMethodExecutionContext); + Provable.log("ST length", context.current().result.stateTransitions.length); + Provable.log("RUNTIME HEIGHT", this.network.block.height); } } @@ -112,13 +123,19 @@ describe("testing app chain", () => { // start the chain, sequencer is now accepting transactions await appChain.start(); - // const areProofsEnabled = appChain.resolveOrFail( - // "AreProofsEnabled", - // InMemoryAreProofsEnabled - // ); - // areProofsEnabled.setProofsEnabled(true); + const areProofsEnabled = appChain.resolveOrFail( + "AreProofsEnabled", + InMemoryAreProofsEnabled + ); + areProofsEnabled.setProofsEnabled(true); + + console.log("areProofsEnabled", areProofsEnabled); - // console.log("areProofsEnabled", areProofsEnabled); + const taskWorkerModule = appChain.sequencer.resolveOrFail( + "LocalTaskWorkerModule", + LocalTaskWorkerModule + ); + await taskWorkerModule.prepare(); /** * Setup the transaction signer / sender @@ -157,5 +174,12 @@ describe("testing app chain", () => { const balance = await appChain.query.runtime.Balances.balances.get(sender); expect(balance?.toBigInt()).toBe(1000n); + + Provable.log("unproven", block); + + Provable.log("proof", { + input: provenBlock?.proof.publicInput, + output: provenBlock?.proof.publicOutput, + }); }, 6_000_000); }); diff --git a/packages/sequencer/src/protocol/production/tasks/RuntimeProvingTask.ts b/packages/sequencer/src/protocol/production/tasks/RuntimeProvingTask.ts index becf7cc43..576ceadb7 100644 --- a/packages/sequencer/src/protocol/production/tasks/RuntimeProvingTask.ts +++ b/packages/sequencer/src/protocol/production/tasks/RuntimeProvingTask.ts @@ -100,6 +100,12 @@ export class RuntimeProvingTask console.log("preparing runtime proving task", inputs); const context = container.resolve(RuntimeMethodExecutionContext); context.setup(inputs); + + console.log( + "runtime analyze methods", + this.runtimeZkProgrammable.analyzeMethods() + ); + console.time("prepare-runtime"); await this.runtimeZkProgrammable.compile(); console.timeEnd("prepare-runtime"); diff --git a/packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts b/packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts index 5ee68d3e9..3fcee708e 100644 --- a/packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts +++ b/packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts @@ -28,6 +28,16 @@ import { FlowTaskWorker } from "./FlowTaskWorker"; */ @sequencerModule() export class LocalTaskWorkerModule extends SequencerModule { + private readonly worker = new FlowTaskWorker(this.taskQueue, [ + this.stateTransitionTask, + this.stateTransitionReductionTask, + this.runtimeProvingTask, + this.blockProvingTask, + this.blockReductionTask, + this.blockBuildingTask, + // this.contractDeployTask, + ]); + // eslint-disable-next-line max-params public constructor( @inject("TaskQueue") private readonly taskQueue: TaskQueue, @@ -44,17 +54,10 @@ export class LocalTaskWorkerModule extends SequencerModule { super(); } - public async start(): Promise { - const worker = new FlowTaskWorker(this.taskQueue, [ - this.stateTransitionTask, - this.stateTransitionReductionTask, - this.runtimeProvingTask, - this.blockProvingTask, - this.blockReductionTask, - this.blockBuildingTask, - // this.contractDeployTask, - ]); - worker + public async start() {} + + public async prepare() { + this.worker .start() // eslint-disable-next-line max-len // eslint-disable-next-line promise/prefer-await-to-then,promise/always-return