Skip to content

Commit

Permalink
Merge pull request #786 from LuffySama-Dev/renameassertluffy
Browse files Browse the repository at this point in the history
#749  Rename deprecated assert* to require* in o1js precondition APIs
  • Loading branch information
ymekuria authored Jan 4, 2024
2 parents a46dbc8 + 86972da commit 823737b
Show file tree
Hide file tree
Showing 51 changed files with 368 additions and 225 deletions.
2 changes: 1 addition & 1 deletion docs/zkapps/faq.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ As represented in the tutorial example code:
```TypeScript
const currentState = this.num.get();

this.num.assertEquals(currentState);
this.num.requireEquals(currentState);
```

- The first line of code executes before the proof is generated.
Expand Down
2 changes: 1 addition & 1 deletion docs/zkapps/o1js/interact-with-mina.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ Other fields in this account update are:

- `publicKey` – the zkApp address (like other non-human-readable strings, this is truncated by `tx.toPretty()`)
- `update: { appState: [...] }` – shows how the method updates the on-chain state, using `this.<state>.set()`. The names and pretty types defined using `@state` are removed in this representation, showing a raw list of 8 field elements or `null` for state fields that aren't updated.
- `preconditions: { account: { state: [...] } }` – similar to the `update`, one entry per field of on-chain state for the preconditions created with `this.<state>.assertEquals()`. This example accepts transactions only if the first of the 8 state fields equals 0. The `null` values mean that no condition is set on the other 7 state fields.
- `preconditions: { account: { state: [...] } }` – similar to the `update`, one entry per field of on-chain state for the preconditions created with `this.<state>.requireEquals()`. This example accepts transactions only if the first of the 8 state fields equals 0. The `null` values mean that no condition is set on the other 7 state fields.
- `authorizationKind: 'Proof'` – indicates this account update must be authorized with a proof. Proof authorization is the default when calling a zkApp method, but not necessarily for other account updates.
- `authorization: undefined` – the proof needed on this update isn't there yet. You learn how to add it in a minute.

Expand Down
6 changes: 3 additions & 3 deletions docs/zkapps/o1js/merkle-tree.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,14 @@ class Leaderboard extends SmartContract {
@method guessPreimage(guess: Field, account: Account, path: MerkleWitness) {
// we fetch z from the chain
const z = this.z.get();
this.z.assertEquals(z);
this.z.requireEquals(z);

// if our guess preimage hashes to our target, we won a point!
Poseidon.hash([guess]).assertEquals(z);

// we fetch the on-chain commitment/root
const root = this.root.get();
this.root.assertEquals(root);
this.root.requireEquals(root);

// we check that the account is within the committed Merkle Tree
path.calculateRoot(account.hash()).assertEquals(root);
Expand All @@ -135,7 +135,7 @@ class Leaderboard extends SmartContract {
@method claimReward(account: Account, path: MerkleWitness) {
// we fetch the on-chain commitment
const root = this.root.get();
this.root.assertEquals(root);
this.root.requireEquals(root);

// we check that the account is within the committed Merkle Tree
path.calculateRoot(account.hash()).assertEquals(root);
Expand Down
26 changes: 13 additions & 13 deletions docs/zkapps/o1js/on-chain-values.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ For example, the timestamp on `this.network.timestamp` has four methods:

```ts
this.network.timestamp.get();
this.network.timestamp.assertEquals(timestamp);
this.network.timestamp.assertBetween(lower, upper);
this.network.timestamp.requireEquals(timestamp);
this.network.timestamp.requireBetween(lower, upper);
```

The familiar on-chain state has the same `get()` and `assertEquals()` methods. The `assertBetween()` method has even more power: it allows you to make assert that the timestamp is between `lower` and `upper` (inclusive).
The familiar on-chain state has the same `get()` and `requireEquals()` methods. The `requireBetween()` method has even more power: it allows you to make assert that the timestamp is between `lower` and `upper` (inclusive).

### Example: restricting timestamps

You can see how to use the `assertBetween()` method in the voting example that was mentioned earlier. Assume you want to allow voting throughout September 2022. Timestamps are represented as a `UInt64` in milliseconds since the [UNIX epoch](https://en.wikipedia.org/wiki/Unix_time). You can use the JS `Date` object to easily convert to this representation. In the simplest case, a zkApp could just hard-code the dates:
You can see how to use the `requireBetween()` method in the voting example that was mentioned earlier. Assume you want to allow voting throughout September 2022. Timestamps are represented as a `UInt64` in milliseconds since the [UNIX epoch](https://en.wikipedia.org/wiki/Unix_time). You can use the JS `Date` object to easily convert to this representation. In the simplest case, a zkApp could just hard-code the dates:

```ts
const startDate = UInt64.from(Date.UTC(2022, 9, 1));
Expand All @@ -56,7 +56,7 @@ class VotingApp extends SmartContract {
// ...

@method vote(...) {
this.network.timestamp.assertBetween(startDate, endDate);
this.network.timestamp.requireBetween(startDate, endDate);
// ...
}
}
Expand All @@ -68,15 +68,15 @@ In addition to using a predefined range, you can also construct a range that dep

```ts
const now = this.network.timestamp.get();
this.network.timestamp.assertBetween(now, now.add(60 * 60 * 1000));
this.network.timestamp.requireBetween(now, now.add(60 * 60 * 1000));
```

### Network reference

For completeness, here is the full list of network states you can use and make assertions about in your zkApp.

All of these fields have a `get()` and an `assertEquals()` method. The subset that represents
"ordered values" (those that are `UInt32` or `UInt64`) also have `assertBetween()`.
All of these fields have a `get()` and an `requireEquals()` method. The subset that represents
"ordered values" (those that are `UInt32` or `UInt64`) also have `requireBetween()`.

Of course, there's no need to remember this -- just type `this.network.` and let intelligent code complete guide you!

Expand Down Expand Up @@ -112,8 +112,8 @@ this.network.nextEpochData.startCheckpoint.get(): Field;

### Account reference

Here's the full list of values you can access on the zkApp account. Like the network states, these values have `get()` and `assertEquals()`.
Balance and nonce also have `assertBetween()`.
Here's the full list of values you can access on the zkApp account. Like the network states, these values have `get()` and `requireEquals()`.
Balance and nonce also have `requireBetween()`.

```ts
// the account balance; this might be nanoMINA or a custom token
Expand All @@ -134,13 +134,13 @@ this.account.receiptChainHash.get(): Field;
### Bailing out

In some rare cases, you might, for whatever reason, want to `get()` an on-chain value _without_ constraining it to any value.
If you try this, o1js throws a helpful error reminding you to use `assertEquals()` and `asserBetween()`.
If you try this, o1js throws a helpful error reminding you to use `requireEquals()` and `requireBetween()`.
As an escape hatch, if you want to `get()` a value and are really sure you want to not constrain the on-chain value in any way,
there's `assertNothing()` on all of these fields (including on-chain state). **Use at your own risk.**
there's `requireNothing()` on all of these fields (including on-chain state). **Use at your own risk.**

:::danger

`assertNothing()` should be rarely used and could cause security issues through unexpected behavior if used improperly. Be certain you know what you're doing before using this.
`requireNothing()` should be rarely used and could cause security issues through unexpected behavior if used improperly. Be certain you know what you're doing before using this.

:::

Expand Down
16 changes: 8 additions & 8 deletions docs/zkapps/o1js/smart-contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ class HelloWorld extends SmartContract {
@method increment() {
// read state
const x = this.x.get();
this.x.assertEquals(x);
this.x.requireEquals(x);

// write state
this.x.set(x.add(1));
Expand All @@ -189,20 +189,20 @@ Later, it sets the new state to `x + 1` using `this.x.set()`. Simple!
There's another line though, which looks weird at first:

```ts
this.x.assertEquals(x);
this.x.requireEquals(x);
```

To understand it, we have to take a step back, and understand what it means to "use an on-chain value" during off-chain execution.

For sure, when we use an on-chain value, we have to _prove_ that this is the on-chain value. Verification has to fail if it's a different value! Otherwise, a malicious user could modify o1js and make it just use any other value than the current on-chain state – breaking our zkApp.

To prevent that, we link "`x` at proving time" to be the same as "`x` at verification time". We call this a _precondition_ – a condition that is checked by the verifier (a Mina node) when it receives the proof in a transaction. This is what `this.x.assertEquals(x)` does: it adds the precondition that `this.x` – the on-chain state at verification time – has to equal `x` – the value we fetched from the chain on the client-side. In zkSNARK language, `x` becomes part of the public input.
To prevent that, we link "`x` at proving time" to be the same as "`x` at verification time". We call this a _precondition_ – a condition that is checked by the verifier (a Mina node) when it receives the proof in a transaction. This is what `this.x.requireEquals(x)` does: it adds the precondition that `this.x` – the on-chain state at verification time – has to equal `x` – the value we fetched from the chain on the client-side. In zkSNARK language, `x` becomes part of the public input.

Side note: `this.<state>.assertEquals` is more flexible than equating with the current value. For example, `this.x.assertEquals(10)` fixes the on-chain `x` to the number `10`.
Side note: `this.<state>.requireEquals` is more flexible than equating with the current value. For example, `this.x.requireEquals(10)` fixes the on-chain `x` to the number `10`.

:::note

Why didn't we just make `this.x.get()` add the precondition, automatically, so that you didn't have to write `this.x.assertEquals(x)`?
Why didn't we just make `this.x.get()` add the precondition, automatically, so that you didn't have to write `this.x.requireEquals(x)`?
Well, we like to keep things explicit. The assertion reminds us that we add logic which can make the proof fail: If `x` isn't the same at verification time, the transaction will be rejected. So, reading on-chain values has to be done with care if many users are supposed to read and update state concurrently. It is applicable in some situations, but might cause races, and call for workarounds, in other situations.
One such workaround is the use of actions – see [Actions and Reducer](./actions-and-reducer).

Expand All @@ -220,7 +220,7 @@ class HelloWorld extends SmartContract {

@method increment(xPlus1: Field) {
const x = this.x.get();
this.x.assertEquals(x);
this.x.requireEquals(x);

x.add(1).assertEquals(xPlus1);

Expand Down Expand Up @@ -283,7 +283,7 @@ class HelloWorld extends SmartContract {

@method incrementSecret(secret: Field) {
const x = this.x.get();
this.x.assertEquals(x);
this.x.requireEquals(x);

Poseidon.hash(secret).assertEquals(x);
this.x.set(Poseidon.hash(secret.add(1)));
Expand Down Expand Up @@ -392,7 +392,7 @@ export class Grid extends SmartContract {

@method move(newPoint: Point) {
const point = this.p.get();
this.p.assertEquals(point);
this.p.requireEquals(point);

const newX = point.x.add(newPoint.x);
const newY = point.y.add(newPoint.y);
Expand Down
2 changes: 1 addition & 1 deletion docs/zkapps/tutorials/01-hello-world.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ Finally, this code adds the `update()` function:
16
17 @method update(square: Field) {
18 const currentState = this.num.get();
19 this.num.assertEquals(currentState);
19 this.num.requireEquals(currentState);
20 square.assertEquals(currentState.mul(currentState));
21 this.num.set(square);
22 }
Expand Down
2 changes: 1 addition & 1 deletion docs/zkapps/tutorials/02-private-inputs-hash-functions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ This method updates the state:
9
10 @method incrementSecret(salt: Field, secret: Field) {
11 const x = this.x.get();
12 this.x.assertEquals(x);
12 this.x.requireEquals(x);
13
14 Poseidon.hash([ salt, secret ]).assertEquals(x);
15 this.x.set(Poseidon.hash([ salt, secret.add(1) ]));
Expand Down
4 changes: 2 additions & 2 deletions docs/zkapps/tutorials/05-common-types-and-functions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ For example, to put a condition on a leaf update, the `update` function checks t
incrementAmount: Field
) {
const initialRoot = this.treeRoot.get();
this.treeRoot.assertEquals(initialRoot);
this.treeRoot.requireEquals(initialRoot);

incrementAmount.assertLt(Field(10));

Expand Down Expand Up @@ -456,7 +456,7 @@ It can be used inside smart contracts with a witness, similar to merkle trees
incrementAmount: Field,
) {
const initialRoot = this.mapRoot.get();
this.mapRoot.assertEquals(initialRoot);
this.mapRoot.requireEquals(initialRoot);

incrementAmount.assertLt(Field(10));

Expand Down
4 changes: 2 additions & 2 deletions docs/zkapps/tutorials/07-oracle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,10 @@ To get the oracle's public key from the on-chain state, verify the signature of
```ts
// Get the oracle public key from the contract state
const oraclePublicKey = this.oraclePublicKey.get();
this.oraclePublicKey.assertEquals(oraclePublicKey);
this.oraclePublicKey.requireEquals(oraclePublicKey);
```
`assertEquals()` ensures that the public key that is retrieved at execution time is the same as the public key that exists within the zkApp account on the Mina network when the transaction is processed by the network.
`requireEquals()` ensures that the public key that is retrieved at execution time is the same as the public key that exists within the zkApp account on the Mina network when the transaction is processed by the network.
### Verify the signature
Expand Down
2 changes: 1 addition & 1 deletion docs/zkapps/tutorials/08-custom-tokens.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Next, add an init method and a method that mints tokens.
adminSignature: Signature
) {
let totalAmountInCirculation = this.totalAmountInCirculation.get();
this.totalAmountInCirculation.assertEquals(totalAmountInCirculation);
this.totalAmountInCirculation.requireEquals(totalAmountInCirculation);

let newTotalAmountInCirculation = totalAmountInCirculation.add(amount);

Expand Down
2 changes: 1 addition & 1 deletion docs/zkapps/tutorials/09-recursion.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ class RollupContract extends SmartContract {

@method update(rollupStateProof: RollupProof) {
const currentState = this.state.get();
this.state.assertEquals(currentState);
this.state.requireEquals(currentState);

rollupStateProof.publicInput.initialRoot.assertEquals(currentState);

Expand Down
32 changes: 16 additions & 16 deletions docs/zkapps/tutorials/10-account-updates.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ This zkApp has methods that call other methods to let you explore the impacts to
}

@method init() {
this.account.provedState.assertEquals(this.account.provedState.get());
this.account.provedState.requireEquals(this.account.provedState.get());
this.account.provedState.get().assertFalse();

super.init();
Expand All @@ -146,22 +146,22 @@ This zkApp has methods that call other methods to let you explore the impacts to
...
@method add(incrementBy: Field) {
this.account.provedState.assertEquals(this.account.provedState.get());
this.account.provedState.requireEquals(this.account.provedState.get());
this.account.provedState.get().assertTrue();
const num = this.num.get();
this.num.assertEquals(num);
this.num.requireEquals(num);
this.num.set(num.add(incrementBy));
this.incrementCalls();
}
@method incrementCalls() {
this.account.provedState.assertEquals(this.account.provedState.get());
this.account.provedState.requireEquals(this.account.provedState.get());
this.account.provedState.get().assertTrue();
const calls = this.calls.get();
this.calls.assertEquals(calls);
this.calls.requireEquals(calls);
this.calls.set(calls.add(Field(1)));
}
Expand All @@ -182,13 +182,13 @@ This zkApp has methods that call other methods to let you explore the impacts to
...
@method callSecondary(secondaryAddr: PublicKey) {
this.account.provedState.assertEquals(this.account.provedState.get());
this.account.provedState.requireEquals(this.account.provedState.get());
this.account.provedState.get().assertTrue();
const secondaryContract = new SecondaryZkApp(secondaryAddr);
const num = this.num.get();
this.num.assertEquals(num);
this.num.requireEquals(num);
secondaryContract.add(num);
Expand All @@ -212,18 +212,18 @@ export class SecondaryZkApp extends SmartContract {
@method init() {
super.init();
this.account.provedState.assertEquals(this.account.provedState.get());
this.account.provedState.requireEquals(this.account.provedState.get());
this.account.provedState.get().assertFalse();
this.num.set(Field(12));
}
@method add(incrementBy: Field) {
this.account.provedState.assertEquals(this.account.provedState.get());
this.account.provedState.requireEquals(this.account.provedState.get());
this.account.provedState.get().assertTrue();
const num = this.num.get();
this.num.assertEquals(num);
this.num.requireEquals(num);
this.num.set(num.add(incrementBy));
}
}
Expand Down Expand Up @@ -342,22 +342,22 @@ As a reminder, this update corresponds to code:
```typescript
...
@method add(incrementBy: Field) {
this.account.provedState.assertEquals(this.account.provedState.get());
this.account.provedState.requireEquals(this.account.provedState.get());
this.account.provedState.get().assertTrue();
const num = this.num.get();
this.num.assertEquals(num);
this.num.requireEquals(num);
this.num.set(num.add(incrementBy));
this.incrementCalls();
}
@method incrementCalls() {
this.account.provedState.assertEquals(this.account.provedState.get());
this.account.provedState.requireEquals(this.account.provedState.get());
this.account.provedState.get().assertTrue();
const calls = this.calls.get();
this.calls.assertEquals(calls);
this.calls.requireEquals(calls);
this.calls.set(calls.add(Field(1)));
}
...
Expand Down Expand Up @@ -393,13 +393,13 @@ And a quick reminder of the code for `callSecondary()`:

```typescript
@method callSecondary(secondaryAddr: PublicKey) {
this.account.provedState.assertEquals(this.account.provedState.get());
this.account.provedState.requireEquals(this.account.provedState.get());
this.account.provedState.get().assertTrue();
const secondaryContract = new SecondaryZkApp(secondaryAddr);
const num = this.num.get();
this.num.assertEquals(num);
this.num.requireEquals(num);
secondaryContract.add(num);
Expand Down
Loading

2 comments on commit 823737b

@vercel
Copy link

@vercel vercel bot commented on 823737b Jan 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs2 – ./

docs.minaprotocol.com
docs2-minadocs.vercel.app
docs2-git-main-minadocs.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 823737b Jan 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

07-oracles – ./examples/zkapps/07-oracles/oracle

07-oracles.vercel.app
07-oracles-minadocs.vercel.app
07-oracles-git-main-minadocs.vercel.app

Please sign in to comment.