-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #43 from orochi-network/feature/accumulation
Accumulation. Initial Commit
- Loading branch information
Showing
16 changed files
with
529 additions
and
12 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import { | ||
Field, | ||
SmartContract, | ||
State, | ||
state, | ||
Reducer, | ||
method, | ||
UInt64, | ||
AccountUpdate, | ||
Provable, | ||
Mina | ||
} from 'o1js'; | ||
import { Action } from '../rollup/action.js'; | ||
import { RollUpProof } from '../rollup/offchain-rollup.js'; | ||
import { RollupService } from '../rollup/rollup-service.js'; | ||
|
||
export class DatabaseContract extends SmartContract { | ||
@state(Field) rootCommitment = State<Field>(); | ||
@state(Field) currentActionState = State<Field>(); | ||
|
||
reducer = Reducer({ actionType: Action }); | ||
|
||
events = { | ||
INSERT: Field, | ||
REMOVE: Field, | ||
}; | ||
|
||
@method init() { | ||
this.account.provedState.assertEquals(this.account.provedState.get()); | ||
this.account.provedState.get().assertFalse(); | ||
|
||
super.init(); | ||
|
||
this.currentActionState.set(Reducer.initialActionState); | ||
const merkleTreeRoot = Provable.witness(Field, () => RollupService.get().getMerkleTree().getRoot()) | ||
this.rootCommitment.set(merkleTreeRoot); | ||
} | ||
|
||
// TODO: Figured out how to replace the Field with IDocument / ISchema, which must be provable | ||
@method insert(index: UInt64, hash: Field) { | ||
this.reducer.dispatch( | ||
new Action({ | ||
type: Field(0), | ||
index: index, | ||
hash: hash, | ||
}) | ||
); | ||
this.emitEvent('INSERT', hash); | ||
} | ||
|
||
@method remove(index: UInt64) { | ||
this.reducer.dispatch( | ||
new Action({ | ||
type: Field(1), | ||
index: index, | ||
hash: Field(0), | ||
}) | ||
); | ||
this.emitEvent('REMOVE', index.toFields()[0]); | ||
} | ||
|
||
@method rollup(proof: RollUpProof) { | ||
this.rootCommitment.getAndAssertEquals(); | ||
this.currentActionState.getAndAssertEquals(); | ||
|
||
proof.verify(); | ||
|
||
this.rootCommitment.assertEquals(proof.publicInput.onChainRoot); | ||
this.currentActionState.assertEquals(proof.publicInput.onChainActionState); | ||
|
||
// If we have no error we can garantee that action state is truthworthy | ||
this.reducer.getActions({ | ||
fromActionState: this.currentActionState.get(), | ||
endActionState: proof.publicOutput.newActionState, | ||
}); | ||
|
||
// const newActionState = Provable.witness(Field, () => pendingActions.reduce((oldActionState, actions) => { | ||
// const action = actions[0]; | ||
// const actionsHash = AccountUpdate.Actions.hash([Action.toFields(action)]); | ||
// return AccountUpdate.Actions.updateSequenceState(oldActionState, actionsHash) | ||
// }, this.currentActionState.get())); | ||
|
||
// proof.publicOutput.newActionState.assertEquals(proof.publicOutput.newActionState); | ||
|
||
this.rootCommitment.set(proof.publicOutput.newRoot); | ||
this.currentActionState.set(proof.publicOutput.newActionState); | ||
} | ||
|
||
getState(): Field { | ||
return this.rootCommitment.get(); | ||
} | ||
|
||
getActionState(): Field { | ||
return this.currentActionState.get(); | ||
} | ||
|
||
async getUnprocessedActions(size: number): Promise<Action[]> { | ||
const fromActionState = this.getActionState(); | ||
|
||
return (await this.reducer.fetchActions({ fromActionState })) | ||
.slice(0, size) | ||
.map((action) => action[0]); | ||
} | ||
|
||
getEndActionState(actions: Action[]): Field { | ||
let fromActionState = this.getActionState(); | ||
|
||
for (const action of actions) { | ||
const actionHashs = AccountUpdate.Actions.hash([Action.toFields(action)]); | ||
fromActionState = AccountUpdate.Actions.updateSequenceState( | ||
fromActionState, | ||
actionHashs | ||
); | ||
} | ||
|
||
return fromActionState; | ||
} | ||
|
||
async rollUp(proof: RollUpProof): Promise<void> { | ||
const creds = RollupService.get().getCredentials(); | ||
|
||
const tx = await Mina.transaction(creds.getFeePayer(), () => { | ||
this.rollup(proof); | ||
}); | ||
|
||
await tx.prove(); | ||
await tx.sign([creds.getFeePayerKey(), creds.getZkAppKey()]).send(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { MerkleWitness } from "o1js"; | ||
|
||
export class DatabaseMerkleWitness extends MerkleWitness(8) {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
export * from './common.js'; | ||
export * from './schema.js'; | ||
export * from './loader.js'; | ||
export * from './zkdb-storage.js'; | ||
export * from './zkdb-storage.js' | ||
export * from './database-witness.js' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { | ||
Mina, | ||
PrivateKey, | ||
AccountUpdate, | ||
UInt32, | ||
CircuitString, | ||
UInt64, | ||
Provable | ||
} from 'o1js'; | ||
import { User } from './user.js'; | ||
import { ZKDatabaseStorage } from '../../core/zkdb-storage.js'; | ||
import { DatabaseContract } from '../../core/database-contract.js'; | ||
import { RollupService } from '../../rollup/rollup-service.js'; | ||
import { Credentials } from '../../models/credentials.js'; | ||
|
||
let doProofs = false; | ||
|
||
const merkleHeight = 8; | ||
|
||
(async () => { | ||
let Local = Mina.LocalBlockchain({ proofsEnabled: doProofs }); | ||
Mina.setActiveInstance(Local); | ||
let initialBalance = 10_000_000_000; | ||
|
||
let feePayerKey = Local.testAccounts[0].privateKey; | ||
let feePayer = Local.testAccounts[0].publicKey; | ||
|
||
// the zkapp account | ||
let zkappKey = PrivateKey.random(); | ||
let zkappAddress = zkappKey.toPublicKey(); | ||
|
||
// Initialize offchain service | ||
|
||
const zkdb = await ZKDatabaseStorage.getInstance('zkdb-test', { | ||
storageEngine: 'local', | ||
merkleHeight, | ||
storageEngineCfg: { | ||
location: './data', | ||
}, | ||
}); | ||
|
||
const offchainContract = new DatabaseContract(zkappAddress); | ||
const rollUpService = await RollupService.activate(offchainContract, zkdb, new Credentials(feePayerKey, zkappKey)); | ||
|
||
if (doProofs) { | ||
await DatabaseContract.compile(); | ||
} | ||
|
||
console.log('Deploying Database Smart Contract...'); | ||
let tx = await Mina.transaction(feePayer, () => { | ||
AccountUpdate.fundNewAccount(feePayer).send({ | ||
to: zkappAddress, | ||
amount: initialBalance, | ||
}); | ||
offchainContract.deploy(); | ||
}); | ||
await tx.prove(); | ||
await tx.sign([feePayerKey, zkappKey]).send(); | ||
|
||
Provable.log('on chain commitment', offchainContract.getState()); | ||
Provable.log('off chain commitment', await zkdb.getMerkleRoot()); | ||
|
||
// Feed | ||
console.log('Update Database Smart Contract...'); | ||
for (let i = 0; i < 2; i++) { | ||
const newUser = new User({ | ||
accountName: CircuitString.fromString(`user ${i}`), | ||
ticketAmount: UInt32.from(i), | ||
}); | ||
|
||
|
||
console.log(`Saving user ${i}`); | ||
const index = await zkdb.add(newUser); | ||
|
||
const tx = await Mina.transaction(feePayer, () => { | ||
offchainContract.insert(UInt64.from(index), newUser.hash()); | ||
}); | ||
|
||
await tx.prove(); | ||
await tx.sign([feePayerKey, zkappKey,]).send(); | ||
} | ||
|
||
const batchSize = 5; | ||
await rollUpService.rollUp(batchSize); | ||
|
||
Provable.log('on chain commitment', offchainContract.getState()); | ||
Provable.log('off chain commitment', await zkdb.getMerkleRoot()); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Schema } from "../../core/schema.js"; | ||
import { CircuitString, UInt32 } from "o1js"; | ||
|
||
export class User extends Schema({ | ||
accountName: CircuitString, | ||
ticketAmount: UInt32, | ||
}) { | ||
static deserialize(data: Uint8Array): User { | ||
return new User(User.decode(data)); | ||
} | ||
|
||
index(): { accountName: string } { | ||
return { | ||
accountName: this.accountName.toString(), | ||
}; | ||
} | ||
|
||
json(): { accountName: string; ticketAmount: string } { | ||
return { | ||
accountName: this.accountName.toString(), | ||
ticketAmount: this.ticketAmount.toString(), | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { PrivateKey, PublicKey } from "o1js"; | ||
|
||
export class Credentials { | ||
private feePayerKey: PrivateKey; | ||
private zkAppKey: PrivateKey; | ||
|
||
constructor(feePayerKey: PrivateKey, zkAppKey: PrivateKey) { | ||
this.feePayerKey = feePayerKey; | ||
this.zkAppKey = zkAppKey; | ||
} | ||
|
||
public getZkAppKey(): PrivateKey { | ||
return this.zkAppKey; | ||
} | ||
|
||
public getFeePayerKey(): PrivateKey { | ||
return this.feePayerKey; | ||
} | ||
|
||
public getZkApp(): PublicKey { | ||
return this.zkAppKey.toPublicKey(); | ||
} | ||
|
||
public getFeePayer(): PublicKey { | ||
return this.feePayerKey.toPublicKey(); | ||
} | ||
} |
Oops, something went wrong.