You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -24,35 +28,36 @@ zkApp programmability is not yet available on the Mina Mainnet. You can get star
24
28
25
29
:::
26
30
27
-
:::note
28
31
29
-
This tutorial was last tested with [SnarkyJS](https://www.npmjs.com/package/snarkyjs) 0.8.0.
32
+
# Tutorial 5: Common Types and Functions
30
33
31
-
:::
34
+
In previous tutorials, you learned how to deploy smart contracts to the network interact with them from a React UI and NodeJS.
32
35
33
-
# Tutorial 5: Common Types and Functions
36
+
In this tutorial, you learn about types you can use when building with SnarkyJS. Earlier tutorials mostly use the `Field` type. SnarkyJS provides other higher-order types built from Fields that are useful for zkApp development and expand the possibilities for more applications.
34
37
35
-
In previous tutorials, we've seen how to deploy smart contracts to the network, and we've interacted with them from both a React UI and NodeJS.
38
+
All types are defined in the [SnarkyJS / Modules / Types](/zkapps/snarkyjs-reference/modules/Types) API reference documentation.
36
39
37
-
In this tutorial, we will talk about more typesthat are useful when building with SnarkyJS, so you can build more applications. So far, we've mostly been using the `Field` type. SnarkyJS provides other higher-order types built from Fields, that will be useful for your development.
40
+
The [example project](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src) includes a [main.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/main.ts) file that shows all of the concepts presented in this tutorial, along with smart contracts showing more advanced usage of some of the concepts, particularly Merkle Trees.
38
41
39
-
You can find all of these on the [SnarkyJS Reference page](../snarkyjs-reference), for their full API documentation.
42
+
## Prerequisites
40
43
41
-
There is also a project [here](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src), with a [main.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/main.ts) demoing the concepts presented in this tutorial, along with smart contracts showing more advanced usage of some of the concepts, particularly Merkle Trees.
44
+
This tutorial has been verified with [Mina zkApp CLI](https://github.com/o1-labs/zkapp-cli) version `0.11.0` and [SnarkyJS](https://www.npmjs.com/package/snarkyjs)`0.12.1`.
45
+
46
+
Ensure your environment meets the [Prerequisites](/zkapps/tutorials#prerequisites) for zkApp Developer Tutorials.
42
47
43
48
## Basic Types
44
49
45
-
To start, we'll discuss 5 basic types derived from the Fields:
All arguments passed into smart contracts need to be arguments SnarkyJS can understand. This means that we can't just pass normal strings - we need to pass in strings that have been wrapped to be compatible with circuits, which is what `Struct` accomplishes.
113
+
All arguments passed into smart contracts must be arguments SnarkyJS can consume. You cannot pass normal strings. Instead, you must pass in strings that are wrapped to be compatible with circuits. This is accomplished with `Struct`.
109
114
110
-
One special thing to note, is that the default `CircuitString` has a max length of 128 characters. This is because, under the hood, SnarkyJS types have to be fixed length. However, the `CircuitString` API abstracts this away and can be used like a dynamic length string, with the only caveat being the max length.
115
+
The default `CircuitString` has a maximum length of 128 charactersbecauseSnarkyJS types must be fixed length. However, the `CircuitString` API abstracts this restriction away and can be used like a dynamic length string with the maximum length caveat.
111
116
112
-
We'll see in the following section how to create custom types, where you could for example build your own strings, modified to whatever length you would like.
117
+
You can create custom types to build your own strings, modified to whatever length you want.
113
118
114
-
A brief example of using these:
119
+
A brief example of custom types:
115
120
116
121
```ts
117
122
const str1 =CircuitString.fromString('abc..xyz');
@@ -156,19 +161,21 @@ signature verified for data2: true
156
161
Fields in signature: 256
157
162
```
158
163
159
-
Small but important note: Make sure that you never use the private key above (or any private key that's publicly accessible) in a real application!
164
+
Observe and follow best practices for your key security. Make sure that you never use the private key in this example output, or any private key that's publicly accessible, in a real application.
160
165
161
-
If you're curious why there are 255 Fields in a private key and 256 in a signature - the reason for thisis cryptographic in nature: Elliptic curve scalars are most efficiently represented in a SNARK as an array of bits, and the bit length of these scalars happens to be 255.
166
+
There are 255 Fields in a private key and 256 Fields in a signature. If you are curious about the reason for this, the answer is cryptographic in nature: Elliptic curve scalars are most efficiently represented in a SNARK as an array of bits, and the bit length of these scalars is 255.
162
167
163
168
## Struct
164
169
165
-
A special type is [Struct](../snarkyjs-reference#struct), which lets you create your own compound data types.
170
+
You can create your own compound data types with the special [Struct](../snarkyjs-reference#struct) type.
171
+
172
+
Define a Struct as one or more data types that SnarkyJS understands. For example, Field, higher-order types built into SnarkyJS based on Field, or other Struct types defined by you. You can also define methods on your Struct to act upon this data type.
166
173
167
-
Your Struct can be defined as one or more data types that SnarkyJS understands, i.e. Field, higher-order types built into SnarkyJS based on Field, or other Struct types defined by you. You can also define methods on your Struct to act upon this data type, if desired, but doing so is optional.
174
+
The following example demonstrates how to use `Struct`to implement a `Point` structure and an array of points of length 8 structure.
168
175
169
-
See the following for an example of how to use `Struct`, implementing a `Point` structure, and an array of points of length 8 structure.
176
+
In SnarkyJS, programs are compiled into fixed-sized circuits. This means that data structures it consumes must also be a fixed size.
170
177
171
-
SnarkyJS compiles programs into fixed sized circuits. This means that data structures it consumes must also be a fixed size, and is why we declare the array in `Points8` structure to be a static size of 8 in the example below.
178
+
To meet the fixed-size requirement, this code declares the array in `Points8` structure to be a static size of 8.
With these, you can write conditionals inside SnarkyJS.
223
+
You can write conditionals inside SnarkyJS with these functions.
216
224
217
225
For example:
218
226
@@ -263,30 +271,30 @@ inputSumAbs: 5
263
271
largest: 22
264
272
```
265
273
266
-
Note that when using `Provable.if`, like in a JS ternary, both branches are executed. Unlike normal programming, because SnarkyJS under the hood is creating a zk circuit, there is no primitive for if statements where only one branch is executed.
274
+
Both branches are executed when using `Provable.if`, like in a JavaScript ternary. Because SnarkyJS is creating a zk circuit, there is no primitive for `if` statements where only one branch is executed.
267
275
268
276
## Assertions and Constraints
269
277
270
278
SnarkyJS functions are compiled to generate circuits.
271
279
272
-
When a transaction is proven in SnarkyJS, SnarkyJS is proving that the program logic is computed according to the written program, and all assertions are holding true.
280
+
When a transaction is proven in SnarkyJS, the proof is that the program logic is computed according to the written program, and all assertions are holding true.
273
281
274
-
We've seen assertions already, with `a.assertEquals(b)`, which we've often used. There is also `.assertTrue()` available on the Bool class.
282
+
In previous tutorials, you learned `a.assertEquals(b)`. The `.assertTrue()` is available on the Bool class.
275
283
276
-
Circuits in SnarkyJS currently have a fixed maximum size. Each operation performed in a function counts towards this maximum size. This maximum size is currently equivalent to the following:
284
+
Circuits in SnarkyJS have a fixed maximum size. Each operation performed in a function counts towards this maximum size. This maximum size is equivalent to:
277
285
278
286
- about 5,200 hashes on two fields
279
287
- about 2,600 hashes on four fields
280
288
- about `2^17` field multiplies
281
289
- about `2^17` field additions
282
290
283
-
If a program is too large to fit into these constraints, it can be broken up into multiple recursive proof verifications. See more on how to do this in the section [here](../snarkyjs/recursion).
291
+
If a program is too large to fit into these constraints, it can be broken up into multiple recursive proof verifications. See [Recursion](../snarkyjs/recursion).
284
292
285
293
## Merkle Trees
286
294
287
-
Lastly, let's go over an example using [merkle trees](../snarkyjs-reference/classes/MerkleTree). Merkle trees are very powerful, since they let us manage large amounts of data within a circuit. In the [project corresponding to this tutorial](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src), you can find a full reference for the example here. The contract can be found in [BasicMerkleTreeContract.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/BasicMerkleTreeContract.ts), and the example can be found in a section of [main.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/main.ts).
295
+
You can use [Merkle trees](../snarkyjs-reference/classes/MerkleTree) to manage large amounts of data within a circuit. The power of Merkle trees is demonstrated in the [05-common-types-and-functions/src](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src)reference project for this tutorial. See the [BasicMerkleTreeContract.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/BasicMerkleTreeContract.ts) contract and [main.ts](https://github.com/o1-labs/docs2/blob/main/examples/zkapps/05-common-types-and-functions/src/main.ts) that demonstrates how contracts interact with Merkle trees and how to construct them.
288
296
289
-
Start off by importing`MerkleTree`:
297
+
The first step is to import`MerkleTree`:
290
298
291
299
```ts
292
300
import {
@@ -296,18 +304,20 @@ import {
296
304
} from'snarkyjs'
297
305
```
298
306
299
-
Merkle Trees can be created in your application like so:
307
+
To create Merkle trees in your application:
300
308
301
309
```ts
302
310
const height =20;
303
311
const tree =newMerkleTree(height);
304
312
```
305
313
306
-
The height variable determines how many leaves are available to your application. A height of 20 for example will lead to a tree with `2^(20-1)`, or 524,288 leaves.
314
+
The height variable determines how many leaves are available to the application. For example, a height of 20 leads to a tree with `2^(20-1)`, or 524,288 leaves.
307
315
308
-
Merkle trees in smart contracts are stored as the hash of the merkle tree's root. Smart contract methods which update the merkle root can take a "witness" of the change as an argument, which represents the merkle path to the data for which inclusion is being proved.
316
+
Merkle trees in smart contracts are stored as the hash of the Merkle tree's root. Smart contract methods that update the Merkle root can take a _witness_ of the change as an argument. The [MerkleMapWitness](/zkapps/snarkyjs-reference/classes/MerkleMapWitness)represents the Merkle path to the data for which inclusion is being proved.
309
317
310
-
Here is a simple example of a contract that stores the root of a merkle tree, where each leaf stores a number, and the smart contract has an `update` function that adds a number to the leaf. As an example of putting a condition on a leaf update, the `update` function checks that the number added was less than 10.
318
+
A contract stores the root of a Merkle tree, where each leaf stores a number, and the smart contract has an `update` function that adds a number to the leaf.
319
+
320
+
For example, to put a condition on a leaf update, the `update` function checks that the number added was less than 10:
311
321
312
322
```ts
313
323
...
@@ -341,7 +351,7 @@ Here is a simple example of a contract that stores the root of a merkle tree, wh
341
351
}
342
352
```
343
353
344
-
And code to interact with it:
354
+
The code to interact with the smart contract:
345
355
346
356
```ts
347
357
// initialize the zkapp
@@ -401,13 +411,15 @@ console.log(
401
411
);
402
412
```
403
413
404
-
While in this example leaves are fields, you can put more variables in a leaf by instead hashing an array of fields, and setting a leaf to that.
414
+
In this example, leaves are fields. However, you can put more variables in a leaf by hashing an array of fields and setting a leaf to that hash.
415
+
416
+
This complete example is in the [project directory](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src).
405
417
406
-
You can find this complete example in the [project directory](https://github.com/o1-labs/docs2/tree/main/examples/zkapps/05-common-types-and-functions/src), as well as a more advanced example `LedgerContract`, which implements a basic ledger of tokens, including checks that the sender has signed their transaction and that the amount the sender has sent matches the amount the receiver receives.
418
+
A more advanced example `LedgerContract` implements a basic ledger of tokens, including checks that the sender has signed their transaction and that the amount the sender has sent matches the amount the receiver receives.
407
419
408
420
## Merkle Map
409
421
410
-
Lastly, let's go over an example using [merkle maps](../snarkyjs-reference/classes/MerkleMap). These allow us to implement keyvalue stores.
422
+
See the API reference documentation for the [MerkleMap](../snarkyjs-reference/classes/MerkleMap) class you can use to implement key-value stores.
411
423
412
424
The API for Merkle Maps is similar to Merkle Trees, just instead of using an index to set a leaf, one uses a key:
413
425
@@ -462,7 +474,7 @@ It can be used inside smart contracts with a witness, similar to merkle trees
462
474
}
463
475
```
464
476
465
-
With (abbreviated) code to interact with it, similar to the merkle tree example above:
477
+
With (abbreviated) code to interact with it, similar to the Merkle tree example above:
MerkleMaps can be used to implement many useful patterns. For example:
502
+
You use [MerkleMaps](/zkapps/snarkyjs-reference/classes/MerkleMap) to implement many useful patterns. For example:
491
503
492
504
- A key value store from public keys to booleans, of token accounts to whether they've participated in a voted yet.
493
505
- A nullifier that privately tracks if an input was used, without revealing it.
494
506
495
507
## Conclusion
496
508
497
-
Congrats! We have finished reviewing more common types and functions in SnarkyJS. With this, you should now be capable of writing many advanced smart contracts and zkApps.
509
+
Congratulations! You have finished reviewing more common types and functions in SnarkyJS. With this, you should now be capable of writing many advanced smart contracts and zkApps.
498
510
499
-
Checkout [Tutorial 6](offchain-storage) to learn how to use off-chain storage, to use more data from your zkApp.
511
+
To use more data from your zkApp, check out [Tutorial 6](offchain-storage) to learn how to use off-chain storage.
0 commit comments