Skip to content

Commit

Permalink
Merge pull request #652 from o1-labs/feature/fee-payer-public
Browse files Browse the repository at this point in the history
Pass in fee payer as public key
  • Loading branch information
mitschabaude authored Dec 16, 2022
2 parents 1f33ead + b350bf4 commit 98685b1
Show file tree
Hide file tree
Showing 33 changed files with 999 additions and 1,297 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `this.account.<field>.set()` as a unified API to update fields on the account https://github.com/o1-labs/snarkyjs/pull/643
- covers `permissions`, `verificationKey`, `zkappUri`, `tokenSymbol`, `delegate`, `votingFor`
- exists on `SmartContract.account` and `AccountUpdate.account`
- `Circuit.constraintSystemFromKeypair(keypair)` to inspect the circuit at a low level https://github.com/o1-labs/snarkyjs/pull/529
- Works with a `keypair` (prover + verifier key) generated with the `Circuit` API
- `this.sender` to get the public key of the transaction's sender https://github.com/o1-labs/snarkyjs/pull/652
- To get the sender outside a smart contract, there's now `Mina.sender()`
- `tx.wait()` is now implemented. It waits for the transactions inclusion in a block https://github.com/o1-labs/snarkyjs/pull/645
- `wait()` also now takes an optional `options` parameter to specify the polling interval or maximum attempts. `wait(options?: { maxAttempts?: number; interval?: number }): Promise<void>;`
- `Circuit.constraintSystemFromKeypair(keypair)` to inspect the circuit at a low level https://github.com/o1-labs/snarkyjs/pull/529
- Works with a `keypair` (prover + verifier key) generated with the `Circuit` API

### Changed

- BREAKING CHANGE: Constraint changes in `sign()`, `requireSignature()` and `createSigned()` on `AccountUpdate` / `SmartContract`. _This means that smart contracts using these methods in their proofs won't be able to create valid proofs against old deployed verification keys._ https://github.com/o1-labs/snarkyjs/pull/637
- `Mina.transaction` now takes a _public key_ as the fee payer argument (passing in a private key is deprecated) https://github.com/o1-labs/snarkyjs/pull/652
- Before: `Mina.transaction(privateKey, ...)`. Now: `Mina.transaction(publicKey, ...)`
- `AccountUpdate.fundNewAccount()` now enables funding multiple accounts at once, and deprecates the `initialBalance` argument
- New option `enforceTransactionLimits` for `LocalBlockchain` (default value: `true`), to disable the enforcement of protocol transaction limits (maximum events, maximum sequence events and enforcing certain layout of `AccountUpdate`s depending on their authorization) https://github.com/o1-labs/snarkyjs/pull/620
- Change the default `send` permissions (for sending MINA or tokens) that get set when deploying a zkApp, from `signature()` to `proof()` https://github.com/o1-labs/snarkyjs/pull/648

Expand All @@ -38,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `this.setPermissions()` in favor of `this.account.permissions.set()` https://github.com/o1-labs/snarkyjs/pull/643
- `this.tokenSymbol.set()` in favor of `this.account.tokenSymbol.set()`
- `this.setValue()` in favor of `this.account.<field>.set()`
- `Mina.transaction(privateKey: PrivateKey, ...)` in favor of new signature `Mina.transaction(publicKey: PublicKey, ...)`
- `AccountUpdate.createSigned(privateKey: PrivateKey)` in favor of new signature `AccountUpdate.createSigned(publicKey: PublicKey)` https://github.com/o1-labs/snarkyjs/pull/637

### Fixed
Expand Down
22 changes: 11 additions & 11 deletions src/examples/simple_zkapp.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@ class SimpleZkapp extends SmartContract {
this.x = State();
}

events = {
update: Field,
};
events = { update: Field };

deploy(args) {
super.deploy(args);
init() {
super.init();
this.x.set(initialState);
}

update(y) {
this.emitEvent('update', y);
this.emitEvent('update', y);
Expand All @@ -48,6 +47,7 @@ let Local = Mina.LocalBlockchain();
Mina.setActiveInstance(Local);

let feePayerKey = Local.testAccounts[0].privateKey;
let feePayer = Local.testAccounts[0].publicKey;

let zkappKey = PrivateKey.random();
let zkappAddress = zkappKey.toPublicKey();
Expand All @@ -59,18 +59,18 @@ console.log('compile');
await SimpleZkapp.compile();

console.log('deploy');
let tx = await Mina.transaction(feePayerKey, () => {
AccountUpdate.fundNewAccount(feePayerKey);
zkapp.deploy({ zkappKey });
let tx = await Mina.transaction(feePayer, () => {
AccountUpdate.fundNewAccount(feePayer);
zkapp.deploy();
});
await tx.send();
await tx.sign([feePayerKey, zkappKey]).send();

console.log('initial state: ' + zkapp.x.get());

console.log('update');
tx = await Mina.transaction(feePayerKey, () => zkapp.update(Field(3)));
tx = await Mina.transaction(feePayer, () => zkapp.update(Field(3)));
await tx.prove();
await tx.send();
await tx.sign([feePayerKey]).send();
console.log('final state: ' + zkapp.x.get());

shutdown();
43 changes: 19 additions & 24 deletions src/examples/simple_zkapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import {
Mina,
AccountUpdate,
isReady,
Permissions,
DeployArgs,
Bool,
PublicKey,
} from 'snarkyjs';
Expand All @@ -23,15 +21,10 @@ await isReady;
class SimpleZkapp extends SmartContract {
@state(Field) x = State<Field>();

events = {
update: Field,
payout: UInt64,
payoutReceiver: PublicKey,
};
events = { update: Field, payout: UInt64, payoutReceiver: PublicKey };

@method init(zkappKey: PrivateKey) {
super.init(zkappKey);
this.balance.addInPlace(UInt64.from(initialBalance));
this.x.set(initialState);
}

Expand Down Expand Up @@ -74,7 +67,7 @@ let Local = Mina.LocalBlockchain({ proofsEnabled: doProofs });
Mina.setActiveInstance(Local);

// a test account that pays all the fees, and puts additional funds into the zkapp
let feePayer = Local.testAccounts[0].privateKey;
let { privateKey: senderKey, publicKey: sender } = Local.testAccounts[0];

// the zkapp account
let zkappKey = PrivateKey.random();
Expand All @@ -94,12 +87,13 @@ if (doProofs) {
}

console.log('deploy');
let tx = await Mina.transaction(feePayer, () => {
AccountUpdate.fundNewAccount(feePayer, { initialBalance });
let tx = await Mina.transaction(sender, () => {
let senderUpdate = AccountUpdate.fundNewAccount(sender);
senderUpdate.send({ to: zkappAddress, amount: initialBalance });
zkapp.deploy({ zkappKey });
});
await tx.prove();
await tx.send();
await tx.sign([senderKey]).send();

console.log('initial state: ' + zkapp.x.get());
console.log(`initial balance: ${zkapp.account.balance.get().div(1e9)} MINA`);
Expand All @@ -108,49 +102,50 @@ let account = Mina.getAccount(zkappAddress);
console.log('account is proved:', account.provedState.toBoolean());

console.log('update');
tx = await Mina.transaction(feePayer, () => {
tx = await Mina.transaction(sender, () => {
zkapp.update(Field(3));
});
await tx.prove();
await tx.send();
await tx.sign([senderKey]).send();

// pay more into the zkapp -- this doesn't need a proof
console.log('receive');
tx = await Mina.transaction(feePayer, () => {
let payerAccountUpdate = AccountUpdate.createSigned(feePayer);
tx = await Mina.transaction(sender, () => {
let payerAccountUpdate = AccountUpdate.createSigned(sender);
payerAccountUpdate.send({ to: zkappAddress, amount: UInt64.from(8e9) });
});
await tx.send();
await tx.sign([senderKey]).send();

console.log('payout');
tx = await Mina.transaction(feePayer, () => {
AccountUpdate.fundNewAccount(feePayer);
tx = await Mina.transaction(sender, () => {
AccountUpdate.fundNewAccount(sender);
zkapp.payout(privilegedKey);
});
await tx.prove();
await tx.send();
await tx.sign([senderKey]).send();
sender;

console.log('final state: ' + zkapp.x.get());
console.log(`final balance: ${zkapp.account.balance.get().div(1e9)} MINA`);

console.log('try to payout a second time..');
tx = await Mina.transaction(feePayer, () => {
tx = await Mina.transaction(sender, () => {
zkapp.payout(privilegedKey);
});
try {
await tx.prove();
await tx.send();
await tx.sign([senderKey]).send();
} catch (err: any) {
console.log('Transaction failed with error', err.message);
}

console.log('try to payout to a different account..');
try {
tx = await Mina.transaction(feePayer, () => {
tx = await Mina.transaction(sender, () => {
zkapp.payout(Local.testAccounts[2].privateKey);
});
await tx.prove();
await tx.send();
await tx.sign([senderKey]).send();
} catch (err: any) {
console.log('Transaction failed with error', err.message);
}
Expand Down
21 changes: 11 additions & 10 deletions src/examples/simple_zkapp_berkeley.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ await isReady;
class SimpleZkapp extends SmartContract {
@state(Field) x = State<Field>();

deploy(args: DeployArgs) {
super.deploy(args);
init() {
super.init();
this.x.set(initialState);
}

Expand All @@ -49,12 +49,13 @@ Mina.setActiveInstance(Berkeley);
let feePayerKey = PrivateKey.fromBase58(
'EKEQc95PPQZnMY9d9p1vq1MWLeDJKtvKj4V75UDG3rjnf32BerWD'
);
let response = await fetchAccount({ publicKey: feePayerKey.toPublicKey() });
let feePayerAddress = feePayerKey.toPublicKey();
let response = await fetchAccount({ publicKey: feePayerAddress });
if (response.error) throw Error(response.error.statusText);
let { nonce, balance } = response.account;
console.log(`Using fee payer account with nonce ${nonce}, balance ${balance}`);

// this is an actual zkapp that was deployed and updated with this script:
// this used to be an actual zkapp that was deployed and updated with this script:
// https://berkeley.minaexplorer.com/wallet/B62qpRzFVjd56FiHnNfxokVbcHMQLT119My1FEdSq8ss7KomLiSZcan
// replace this with a new zkapp key if you want to deploy another zkapp
// and please never expose actual private keys in public code repositories like this!
Expand All @@ -81,26 +82,26 @@ if (!isDeployed) {
console.log(`Deploying zkapp for public key ${zkappAddress.toBase58()}.`);
// the `transaction()` interface is the same as when testing with a local blockchain
let transaction = await Mina.transaction(
{ feePayerKey, fee: transactionFee },
{ sender: feePayerAddress, fee: transactionFee },
() => {
AccountUpdate.fundNewAccount(feePayerKey);
zkapp.deploy({ zkappKey, verificationKey });
AccountUpdate.fundNewAccount(feePayerAddress);
zkapp.deploy({ verificationKey });
}
);
// if you want to inspect the transaction, you can print it out:
// console.log(transaction.toGraphqlQuery());

// send the transaction to the graphql endpoint
console.log('Sending the transaction...');
await transaction.send();
await transaction.sign([feePayerKey, zkappKey]).send();
}

// if the zkapp is not deployed yet, create an update transaction
if (isDeployed) {
let x = zkapp.x.get();
console.log(`Found deployed zkapp, updating state ${x} -> ${x.add(10)}.`);
let transaction = await Mina.transaction(
{ feePayerKey, fee: transactionFee },
{ sender: feePayerAddress, fee: transactionFee },
() => {
zkapp.update(Field(10));
}
Expand All @@ -114,7 +115,7 @@ if (isDeployed) {

// send the transaction to the graphql endpoint
console.log('Sending the transaction...');
await transaction.send();
await transaction.sign([feePayerKey]).send();
}

shutdown();
10 changes: 5 additions & 5 deletions src/examples/sudoku/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { AccountUpdate, Mina, PrivateKey, shutdown } from 'snarkyjs';
const Local = Mina.LocalBlockchain();
Mina.setActiveInstance(Local);

const account = Local.testAccounts[0].privateKey;
const { publicKey: account, privateKey: accountKey } = Local.testAccounts[0];
const sudoku = generateSudoku(0.5);
const zkAppPrivateKey = PrivateKey.random();
const zkAppAddress = zkAppPrivateKey.toPublicKey();
Expand All @@ -22,13 +22,13 @@ let tx = await Mina.transaction(account, () => {
});
await tx.prove();
/**
* note: this tx needs to be signed with `tx.sign()`, because `deploy` uses `requireSignature()` under the hood,
* note: this tx needs to be signed with the `zkAppPrivateKey`, because `deploy` uses `requireSignature()` under the hood,
* so one of the account updates in this tx has to be authorized with a signature (vs proof).
* this is necessary for the deploy tx because the initial permissions for all account fields are "signature".
* (but `deploy()` changes some of those permissions to "proof" and adds the verification key that enables proofs.
* that's why we don't need `tx.sign()` for the later transactions.)
*/
await tx.sign([zkAppPrivateKey]).send();
await tx.sign([zkAppPrivateKey, accountKey]).send();

console.log('Is the sudoku solved?', zkApp.isSolved.get().toBoolean());

Expand All @@ -45,7 +45,7 @@ try {
zkApp.submitSolution(Sudoku.from(sudoku), Sudoku.from(noSolution));
});
await tx.prove();
await tx.send();
await tx.sign([accountKey]).send();
} catch {
console.log('There was an error submitting the solution, as expected');
}
Expand All @@ -57,7 +57,7 @@ tx = await Mina.transaction(account, () => {
zkApp.submitSolution(Sudoku.from(sudoku), Sudoku.from(solution!));
});
await tx.prove();
await tx.send();
await tx.sign([accountKey]).send();
console.log('Is the sudoku solved?', zkApp.isSolved.get().toBoolean());

// cleanup
Expand Down
19 changes: 8 additions & 11 deletions src/examples/zkapps/composability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ let Local = Mina.LocalBlockchain({ proofsEnabled: doProofs });
Mina.setActiveInstance(Local);

// a test account that pays all the fees, and puts additional funds into the zkapp
let feePayer = Local.testAccounts[0].privateKey;
let feePayerKey = Local.testAccounts[0].privateKey;
let feePayer = Local.testAccounts[0].publicKey;

// the first contract's address
let incrementerKey = PrivateKey.random();
Expand Down Expand Up @@ -86,14 +87,12 @@ if (doProofs) {
console.log('deploy');
let tx = await Mina.transaction(feePayer, () => {
// TODO: enable funding multiple accounts properly
AccountUpdate.fundNewAccount(feePayer, {
initialBalance: Mina.accountCreationFee().add(Mina.accountCreationFee()),
});
zkapp.deploy({ zkappKey });
adderZkapp.deploy({ zkappKey: adderKey });
incrementerZkapp.deploy({ zkappKey: incrementerKey });
AccountUpdate.fundNewAccount(feePayer, 3);
zkapp.deploy();
adderZkapp.deploy();
incrementerZkapp.deploy();
});
await tx.send();
await tx.sign([feePayerKey, zkappKey, adderKey, incrementerKey]).send();

console.log('call interaction');
tx = await Mina.transaction(feePayer, () => {
Expand All @@ -102,10 +101,8 @@ tx = await Mina.transaction(feePayer, () => {
});
console.log('proving (3 proofs.. can take a bit!)');
await tx.prove();
tx.sign();
console.log(tx.toPretty());

await tx.send();
await tx.sign([feePayerKey]).send();

// should hopefully be 12 since we added 5 + 6 + 1
console.log('state: ' + zkapp.sum.get());
Expand Down
Loading

0 comments on commit 98685b1

Please sign in to comment.