From a8a32ab7b5592d082d4a24c30d0836f8b8e1ff33 Mon Sep 17 00:00:00 2001 From: Aleksandr Ivlev Date: Fri, 12 Jul 2024 16:34:29 +0300 Subject: [PATCH] Preparations for random done --- src/Lottery.ts | 2 +- src/PLottery.ts | 2 +- src/Random/RandomManager.ts | 142 ++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 src/Random/RandomManager.ts diff --git a/src/Lottery.ts b/src/Lottery.ts index 2b4718b..a8a1a8a 100644 --- a/src/Lottery.ts +++ b/src/Lottery.ts @@ -396,7 +396,7 @@ export class Lottery extends SmartContract { public checkRoundPass(round: UInt32) { const startBlock = this.startBlock.getAndRequireEquals(); this.network.globalSlotSinceGenesis.requireBetween( - startBlock.add(round.mul(BLOCK_PER_ROUND)), + startBlock.add(round.add(1).mul(BLOCK_PER_ROUND)), UInt32.MAXINT() ); } diff --git a/src/PLottery.ts b/src/PLottery.ts index fa1c213..99c692a 100644 --- a/src/PLottery.ts +++ b/src/PLottery.ts @@ -451,7 +451,7 @@ export class PLottery extends SmartContract { public checkRoundPass(round: UInt32) { const startBlock = this.startBlock.getAndRequireEquals(); this.network.globalSlotSinceGenesis.requireBetween( - startBlock.add(round.mul(BLOCK_PER_ROUND)), + startBlock.add(round.add(1).mul(BLOCK_PER_ROUND)), UInt32.MAXINT() ); } diff --git a/src/Random/RandomManager.ts b/src/Random/RandomManager.ts new file mode 100644 index 0000000..2e6655d --- /dev/null +++ b/src/Random/RandomManager.ts @@ -0,0 +1,142 @@ +import { + Field, + MerkleMap, + MerkleMapWitness, + Poseidon, + PublicKey, + SmartContract, + State, + UInt32, + method, + state, +} from 'o1js'; +import { treasury } from '../private_constants'; +import { BLOCK_PER_ROUND } from '../constants'; + +const emptyMapRoot = new MerkleMap().getRoot(); + +export class RandomManager extends SmartContract { + @state(Field) commitRoot = State(); + + @state(Field) hashCommitRoot = State(); + + @state(Field) resultRoot = State(); + + @state(UInt32) startSlot = State(); + + init() { + super.init(); + + this.commitRoot.set(emptyMapRoot); + this.hashCommitRoot.set(emptyMapRoot); + this.resultRoot.set(emptyMapRoot); + + this.startSlot.set( + this.network.globalSlotSinceGenesis.getAndRequireEquals() + ); + } + + /* + * Can we update value + * What we will do if value is wrong? + */ + @method async commitValue(witness: MerkleMapWitness, value: Field) { + this.permissionCheck(); + + const [prevCommitRoot, round] = witness.computeRootAndKey(Field(0)); + + prevCommitRoot.assertEquals( + this.commitRoot.getAndRequireEquals(), + 'Wrong commit witness' + ); + + this.checkRoundDoNotEnd(UInt32.fromFields([round])); + + const [newCommitRoot] = witness.computeRootAndKey(value); + + this.commitRoot.set(newCommitRoot); + } + + @method async commitBlockHash(witness: MerkleMapWitness) { + const [prevBlockCommitRoot, key] = witness.computeRootAndKey(Field(0)); + + prevBlockCommitRoot.assertEquals( + this.hashCommitRoot.getAndRequireEquals(), + 'Wrong witness for hashCommits' + ); + + this.checkRoundPass(UInt32.fromFields([key])); + + const newValue = Poseidon.hash([ + this.network.snarkedLedgerHash.get(), + this.network.globalSlotSinceGenesis.getAndRequireEquals().value, + ]); + const [newBlockCommitRoot] = witness.computeRootAndKey(newValue); + + this.hashCommitRoot.set(newBlockCommitRoot); + } + + @method async produceValue( + commitWitness: MerkleMapWitness, + commitValue: Field, + revealValue: Field, + salt: Field, + blockHashCommitWitness: MerkleMapWitness, + blockHashValue: Field, + blockHashProof: BlockHashProof + ) { + const [commitRoot, commitKey] = + commitWitness.computeRootAndKey(commitValue); + + commitRoot.assertEquals( + this.commitRoot.getAndRequireEquals(), + 'Wrong commit witness' + ); + + Poseidon.hash([revealValue, salt]).assertEquals( + commitValue, + 'Wrong reveal' + ); + + const [blockHashCommitRoot, blockHashCommitKey] = + blockHashCommitWitness.computeRootAndKey(blockHashValue); + + blockHashCommitRoot.assertEquals( + this.hashCommitRoot.getAndRequireEquals(), + 'Wrong hash commit witness' + ); + + commitKey.assertEquals( + blockHashCommitKey, + 'Different rounds for commit and hash commit' + ); + + blockHashProof.verify(); + + // Check blockHashProof initialHash to equal blockHashValue + + // Check that blockHashProof final block is right slot + + // Call lottery contract + } + + private permissionCheck() { + this.sender.getAndRequireSignature().assertEquals(treasury); + } + + public checkRoundPass(round: UInt32) { + const startBlock = this.startSlot.getAndRequireEquals(); + this.network.globalSlotSinceGenesis.requireBetween( + startBlock.add(round.add(1).mul(BLOCK_PER_ROUND)), + UInt32.MAXINT() + ); + } + + public checkRoundDoNotEnd(round: UInt32) { + const startBlock = this.startSlot.getAndRequireEquals(); + this.network.globalSlotSinceGenesis.requireBetween( + UInt32.from(0), + startBlock.add(round.add(1).mul(BLOCK_PER_ROUND)) + ); + } +}