From 0ab1a551adb0440acedf94763446cd9a47b713eb Mon Sep 17 00:00:00 2001 From: Aleksandr Ivlev Date: Tue, 16 Jul 2024 15:22:29 +0300 Subject: [PATCH] Fixed issue with ticket round and ticketId in reduceProof --- src/PLottery.test.ts | 29 +++++++++++++++++++++++++++-- src/PLottery.ts | 19 +++++++++++++++---- src/StateManager/PStateManager.ts | 26 +++++++++++++++++++++----- src/TicketReduceProof.ts | 27 +++++++++++++++++++++------ 4 files changed, 84 insertions(+), 17 deletions(-) diff --git a/src/PLottery.test.ts b/src/PLottery.test.ts index 0fa7658..395c94e 100644 --- a/src/PLottery.test.ts +++ b/src/PLottery.test.ts @@ -170,11 +170,23 @@ describe('Add', () => { await tx2.sign([senderKey]).send(); checkConsistancy(); + // Buy dummy ticket in next round, so reudcer works as expected + state.syncWithCurBlock( + +Mina.activeInstance.getNetworkState().globalSlotSinceGenesis + ); + let dummy_ticket = Ticket.random(senderAccount); + dummy_ticket.amount = UInt64.zero; + let tx_1 = await Mina.transaction(senderAccount, async () => { + await lottery.buyTicket(dummy_ticket, Field.from(curRound + 1)); + }); + await tx_1.prove(); + await tx_1.sign([senderKey]).send(); + // Reduce tickets let reduceProof = await state.reduceTickets(); let tx2_1 = await Mina.transaction(senderAccount, async () => { - await lottery.reduceTickets(reduceProof, Field(1)); + await lottery.reduceTickets(reduceProof); }); await tx2_1.prove(); @@ -257,10 +269,23 @@ describe('Add', () => { checkConsistancy(); // Reduce tickets + + // Buy dummy ticket in next round, so reudcer works as expected + state.syncWithCurBlock( + +Mina.activeInstance.getNetworkState().globalSlotSinceGenesis + ); + let dummy_ticket = Ticket.random(senderAccount); + dummy_ticket.amount = UInt64.zero; + let tx_1 = await Mina.transaction(senderAccount, async () => { + await lottery.buyTicket(dummy_ticket, Field.from(round + 1)); + }); + await tx_1.prove(); + await tx_1.sign([senderKey]).send(); + let reduceProof = await state.reduceTickets(); let tx2_1 = await Mina.transaction(senderAccount, async () => { - await lottery.reduceTickets(reduceProof, Field(round + 1)); + await lottery.reduceTickets(reduceProof); }); await tx2_1.prove(); diff --git a/src/PLottery.ts b/src/PLottery.ts index 99c692a..ab7bf6f 100644 --- a/src/PLottery.ts +++ b/src/PLottery.ts @@ -137,6 +137,8 @@ export class PLottery extends SmartContract { @state(Field) lastReduceInRound = State(); + @state(Field) lastProcessedTicketId = State(); + init() { super.init(); @@ -183,12 +185,12 @@ export class PLottery extends SmartContract { ); } - @method async reduceTickets(reduceProof: TicketReduceProof, round: Field) { + @method async reduceTickets(reduceProof: TicketReduceProof) { reduceProof.verify(); - this.checkCurrentRound(UInt32.fromFields([round])); - let lastProcessedState = this.lastProcessedState.getAndRequireEquals(); + let lastProcessedTicketId = + this.lastProcessedTicketId.getAndRequireEquals(); let actionState = this.account.actionState.getAndRequireEquals(); reduceProof.publicOutput.processedActionList.assertEquals( @@ -208,10 +210,19 @@ export class PLottery extends SmartContract { 'Final state is not match contract actionState' ); + // Check inital ticket id + lastProcessedTicketId.assertEquals( + reduceProof.publicOutput.initialTicketId, + 'Initial ticket id don not match contract last processed ticket id' + ); + this.lastProcessedState.set(reduceProof.publicOutput.finalState); this.ticketRoot.set(reduceProof.publicOutput.newTicketRoot); this.bankRoot.set(reduceProof.publicOutput.newBankRoot); - this.lastReduceInRound.set(round); + this.lastReduceInRound.set(reduceProof.publicOutput.lastProcessedRound); + this.lastProcessedTicketId.set( + reduceProof.publicOutput.lastProcessedTicketId + ); this.emitEvent( 'reduce', diff --git a/src/StateManager/PStateManager.ts b/src/StateManager/PStateManager.ts index 73c36fe..212c71a 100644 --- a/src/StateManager/PStateManager.ts +++ b/src/StateManager/PStateManager.ts @@ -55,7 +55,7 @@ export class PStateManager extends BaseStateManager { this.contract = plottery; this.processedTicketData = { - ticketId: 1, + ticketId: 0, round: 0, }; } @@ -114,7 +114,14 @@ export class PStateManager extends BaseStateManager { let curProof = this.isMock ? await mockProof( - await TRinit(input, initialState, initialTicketRoot, initialBankRoot), + await TRinit( + input, + initialState, + initialTicketRoot, + initialBankRoot, + Field.from(this.processedTicketData.round), + Field.from(this.processedTicketData.ticketId) + ), TicketReduceProof, input ) @@ -122,7 +129,9 @@ export class PStateManager extends BaseStateManager { input, initialState, initialTicketRoot, - initialBankRoot + initialBankRoot, + Field.from(this.processedTicketData.round), + Field.from(this.processedTicketData.ticketId) ); for (let actionList of actionLists) { @@ -130,7 +139,16 @@ export class PStateManager extends BaseStateManager { if (+action.round != this.processedTicketData.round) { this.processedTicketData.round = +action.round; this.processedTicketData.ticketId = 1; + } else { + this.processedTicketData.ticketId++; } + + console.log( + `Process ticket: <${+action.round}> <${ + this.processedTicketData.ticketId + }>` + ); + input = new TicketReduceProofPublicInput({ action: action, roundWitness: this.ticketMap.getWitness(action.round), @@ -141,8 +159,6 @@ export class PStateManager extends BaseStateManager { bankValue: this.bankMap.get(action.round), }); - this.processedTicketData.ticketId++; - curProof = this.isMock ? await mockProof( await TRaddTicket(input, curProof), diff --git a/src/TicketReduceProof.ts b/src/TicketReduceProof.ts index 3c6e5a9..a109e70 100644 --- a/src/TicketReduceProof.ts +++ b/src/TicketReduceProof.ts @@ -86,6 +86,7 @@ export class TicketReduceProofPublicOutput extends Struct({ finalState: Field, initialTicketRoot: Field, initialBankRoot: Field, + initialTicketId: Field, newTicketRoot: Field, newBankRoot: Field, processedActionList: Field, @@ -97,18 +98,21 @@ export const init = async ( input: TicketReduceProofPublicInput, initialState: Field, initialTicketRoot: Field, - initialBankRoot: Field + initialBankRoot: Field, + initialRound: Field, + initialTicketId: Field ): Promise => { return new TicketReduceProofPublicOutput({ initialState, finalState: initialState, initialTicketRoot, initialBankRoot, + initialTicketId, newTicketRoot: initialTicketRoot, newBankRoot: initialBankRoot, processedActionList: ActionList.emptyHash, - lastProcessedRound: Field(0), - lastProcessedTicketId: Field(0), + lastProcessedRound: initialRound, + lastProcessedTicketId: initialTicketId, }); }; @@ -174,6 +178,7 @@ export const addTicket = async ( finalState: prevProof.publicOutput.finalState, initialTicketRoot: prevProof.publicOutput.initialTicketRoot, initialBankRoot: prevProof.publicOutput.initialBankRoot, + initialTicketId: prevProof.publicOutput.initialTicketId, newTicketRoot, newBankRoot, processedActionList, @@ -202,6 +207,7 @@ export const cutActions = async ( finalState, initialTicketRoot: prevProof.publicOutput.initialTicketRoot, initialBankRoot: prevProof.publicOutput.initialBankRoot, + initialTicketId: prevProof.publicOutput.initialTicketId, newTicketRoot: prevProof.publicOutput.newTicketRoot, newBankRoot: prevProof.publicOutput.newBankRoot, processedActionList, @@ -221,14 +227,23 @@ export const TicketReduceProgram = ZkProgram({ publicOutput: TicketReduceProofPublicOutput, methods: { init: { - privateInputs: [Field, Field, Field], + privateInputs: [Field, Field, Field, Field, Field], async method( input: TicketReduceProofPublicInput, initialState: Field, initialTicketRoot: Field, - initialBankRoot: Field + initialBankRoot: Field, + initialRound: Field, + initialTicketId: Field ): Promise { - return init(input, initialState, initialTicketRoot, initialBankRoot); + return init( + input, + initialState, + initialTicketRoot, + initialBankRoot, + initialRound, + initialTicketId + ); }, }, addTicket: {