|
| 1 | +--- |
| 2 | +title: Get Notes |
| 3 | +sidebar_position: 4 |
| 4 | +tags: [private-state, smart-contracts, notes] |
| 5 | +description: Learn how to get notes from a data oracle in Aztec.nr. |
| 6 | +--- |
| 7 | + |
| 8 | +## Overview |
| 9 | + |
| 10 | +## `NoteGetterOptions` |
| 11 | + |
| 12 | +`NoteGetterOptions` encapsulates a set of configurable options for filtering and retrieving a selection of notes from a data oracle. Developers can design instances of `NoteGetterOptions`, to determine how notes should be filtered and returned to the functions of their smart contracts. |
| 13 | + |
| 14 | +You can view the implementation [here (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr). |
| 15 | + |
| 16 | +### `selects: BoundedVec<Option<Select>, N>` |
| 17 | + |
| 18 | +`selects` is a collection of filtering criteria, specified by `Select { property_selector: PropertySelector, comparator: u8, value: Field }` structs. It instructs the data oracle to find notes whose serialized field (as specified by the `PropertySelector`) matches the provided `value`, according to the `comparator`. The PropertySelector is in turn specified as having an `index` (nth position of the selected field in the serialized note), an `offset` (byte offset inside the selected serialized field) and `length` (bytes to read of the field from the offset). These values are not expected to be manually computed, but instead specified by passing functions autogenerated from the note definition. |
| 19 | + |
| 20 | +### `sorts: BoundedVec<Option<Sort>, N>` |
| 21 | + |
| 22 | +`sorts` is a set of sorting instructions defined by `Sort { property_selector: PropertySelector, order: u2 }` structs. This directs the data oracle to sort the matching notes based on the value of the specified PropertySelector and in the indicated order. The value of order is **1** for _DESCENDING_ and **2** for _ASCENDING_. |
| 23 | + |
| 24 | +### `limit: u32` |
| 25 | + |
| 26 | +When the `limit` is set to a non-zero value, the data oracle will return a maximum of `limit` notes. |
| 27 | + |
| 28 | +### `offset: u32` |
| 29 | + |
| 30 | +This setting enables us to skip the first `offset` notes. It's particularly useful for pagination. |
| 31 | + |
| 32 | +### `preprocessor: fn ([Option<Note>; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], PREPROCESSOR_ARGS) -> [Option<Note>; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]` |
| 33 | + |
| 34 | +Developers have the option to provide a custom preprocessor. |
| 35 | +This allows specific logic to be applied to notes that meet the criteria outlined above. |
| 36 | +The preprocessor takes the notes returned from the oracle and `preprocessor_args` as its parameters. |
| 37 | + |
| 38 | +An important distinction from the filter function described below is that preprocessor is applied first and unlike filter it is applied in an unconstrained context. |
| 39 | + |
| 40 | +### `preprocessor_args: PREPROCESSOR_ARGS` |
| 41 | + |
| 42 | +`preprocessor_args` provides a means to furnish additional data or context to the custom preprocessor. |
| 43 | + |
| 44 | +### `filter: fn ([Option<Note>; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option<Note>; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]` |
| 45 | + |
| 46 | +Just like preprocessor just applied in a constrained context (correct execution is proven) and applied after the preprocessor. |
| 47 | + |
| 48 | +### `filter_args: FILTER_ARGS` |
| 49 | + |
| 50 | +`filter_args` provides a means to furnish additional data or context to the custom filter. |
| 51 | + |
| 52 | +### `status: u2` |
| 53 | + |
| 54 | +`status` allows the caller to retrieve notes that have been nullified, which can be useful to prove historical data. Note that when querying for both active and nullified notes the caller cannot know if each note retrieved has or has not been nullified. |
| 55 | + |
| 56 | +### Methods |
| 57 | + |
| 58 | +Several methods are available on `NoteGetterOptions` to construct the options in a more readable manner: |
| 59 | + |
| 60 | +### `fn new() -> NoteGetterOptions<Note, N, Field>` |
| 61 | + |
| 62 | +This function initializes a `NoteGetterOptions` that simply returns the maximum number of notes allowed in a call. |
| 63 | + |
| 64 | +### `fn with_filter(filter, filter_args) -> NoteGetterOptions<Note, N, FILTER_ARGS>` |
| 65 | + |
| 66 | +This function initializes a `NoteGetterOptions` with a [`filter`](#filter-fn-optionnote-max_note_hash_read_requests_per_call-filter_args---optionnote-max_note_hash_read_requests_per_call) and [`filter_args`](#filter_args-filter_args). |
| 67 | + |
| 68 | +### `.select` |
| 69 | + |
| 70 | +This method adds a [`Select`](#selects-boundedvecoptionselect-n) criterion to the options. |
| 71 | + |
| 72 | +### `.sort` |
| 73 | + |
| 74 | +This method adds a [`Sort`](#sorts-boundedvecoptionsort-n) criterion to the options. |
| 75 | + |
| 76 | +### `.set_limit` |
| 77 | + |
| 78 | +This method lets you set a limit for the maximum number of notes to be retrieved. |
| 79 | + |
| 80 | +### `.set_offset` |
| 81 | + |
| 82 | +This method sets the offset value, which determines where to start retrieving notes. |
| 83 | + |
| 84 | +### `.set_status` |
| 85 | + |
| 86 | +This method sets the status of notes to retrieve (active or nullified). |
| 87 | + |
| 88 | +### Examples |
| 89 | + |
| 90 | +#### Example 1 |
| 91 | + |
| 92 | +The following code snippet creates an instance of `NoteGetterOptions`, which has been configured to find the cards that belong to an account with nullifying key hash equal to `account_npk_m_hash`. The returned cards are sorted by their points in descending order, and the first `offset` cards with the highest points are skipped. |
| 93 | + |
| 94 | +#include_code state_vars-NoteGetterOptionsSelectSortOffset /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/options.nr rust |
| 95 | + |
| 96 | +The first value of `.select` and `.sort` indicates the property of the note we're looking for. For this we use helper functions that are autogenerated from the note definition. `CardNote` that has the following fields: |
| 97 | + |
| 98 | +#include_code state_vars-CardNote /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/types/card_note.nr rust |
| 99 | + |
| 100 | +`CardNote::properties()` will return a struct with the values to pass for each field, which are related to their indices inside the `CardNote` struct, internal offset and length. |
| 101 | + |
| 102 | +In the example, `.select(CardNote::properties().npk_m_hash, Comparator.EQ, account_npk_m_hash)` matches notes which have the `npk_m_hash` field set to `account_npk_m_hash`. In this case we're using the equality comparator, but other operations exist in the `Comparator` utility struct. |
| 103 | + |
| 104 | +`.sort(0, SortOrder.DESC)` sorts the 0th field of `CardNote`, which is `points`, in descending order. |
| 105 | + |
| 106 | +There can be as many conditions as the number of fields a note type has. The following example finds cards whose fields match the three given values: |
| 107 | + |
| 108 | +#include_code state_vars-NoteGetterOptionsMultiSelects /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/options.nr rust |
| 109 | + |
| 110 | +While `selects` lets us find notes with specific values, `filter` lets us find notes in a more dynamic way. The function below picks the cards whose points are at least `min_points`, although this now can be done by using the select function with a GTE comparator: |
| 111 | + |
| 112 | +#include_code state_vars-OptionFilter /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/options.nr rust |
| 113 | + |
| 114 | +We can use it as a filter to further reduce the number of the final notes: |
| 115 | + |
| 116 | +#include_code state_vars-NoteGetterOptionsFilter /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/options.nr rust |
| 117 | + |
| 118 | +One thing to remember is, `filter` will be applied on the notes after they are picked from the database, so it is more efficient to use select with comparators where possible. Another side effect of this is that it's possible that the actual notes we end up getting are fewer than the limit. |
| 119 | + |
| 120 | +The limit is `MAX_NOTE_HASH_READ_REQUESTS_PER_CALL` by default. But we can set it to any value **smaller** than that: |
| 121 | + |
| 122 | +#include_code state_vars-NoteGetterOptionsPickOne /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/options.nr rust |
| 123 | + |
| 124 | +#### Example 2 |
| 125 | + |
| 126 | +An example of how we can use a Comparator to select notes when calling a Noir contract from aztec.js is below. |
| 127 | + |
| 128 | +#include_code state_vars-NoteGetterOptionsComparatorExampleTs /yarn-project/end-to-end/src/e2e_note_getter.test.ts typescript |
| 129 | + |
| 130 | +In this example, we use the above typescript code to invoke a call to our Noir contract below. This Noir contract function takes an input to match with, and a comparator to use when fetching and selecting notes from storage. |
| 131 | + |
| 132 | +#include_code state_vars-NoteGetterOptionsComparatorExampleNoir /noir-projects/noir-contracts/contracts/docs/docs_example_contract/src/main.nr rust |
0 commit comments