Oracle Program#
The Aleo Oracle program is designed to store information provided by the Attestation Reports generated in TEEs by the Oracle Notarization backend. The program can verify that the report is valid, and it was signed by an allowed key, and it was generated by a backend running a certain version of the software.
This page explains in detail the source code of the Aleo Oracle and how to use it.
Setting up local oracle for testing#
If you want to test your integration locally without interacting with a live network you can use your locally set up network and deploy your own oracle using source code below.
Requirements:
Steps to run local network:
- Start 4 instances of validator nodes to start mining blocks locally. Open 4 terminals and run this command:
For every validator increase --dev
by 1
- Change the
owner
address in oracle source code to the address provided by the 1st instance of the validator node when you started it. -
Deploy oracle contract to the local network:
snarkos developer deploy official_oracle.aleo --private-key <privateKey> --query "http://0.0.0.0:3030" --path "./" --broadcast "http://0.0.0.0:3030/mainnet/transaction/broadcast" --priority-fee 0
Where
privateKey
is the key provided when you started the 1st instance of validator node -
Update oracle with
unique_id
andpublic_key
. You can getunique_id
andpublic_key
by requesting/info
endpoint of the Oracle Notarization backendsnarkos developer execute official_oracle.aleo set_key <signerPubKey> --private-key <privateKey> --query "http://0.0.0.0:3030" --broadcast "http://0.0.0.0:3030/mainnet/transaction/broadcast" snarkos developer execute official_oracle.aleo set_unique_id <unique_id_1> <unique_id_2> --private-key <privateKey> --query "http://0.0.0.0:3030" --broadcast "http://0.0.0.0:3030/mainnet/transaction/broadcast"
-
Oracle is set and ready to be used.
Aleo Oracle source code#
You can find this program deployed in the Aleo Explorer or Aleo Info.
Here is the source code of the Aleo Oracle in both Leo and compiled to Aleo versions:
Aleo Oracle program
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
|
Mappings#
unique_id#
unique_id
unique_id
mapping stores 32 bytes of SGX enclave's unique ID split in 2 16-byte u128
formatted chunks with keys 1u8
and 2u8
. The program will allow reports only from the backends with this unique ID to make sure that report was produced by a backend running this specific version of source code. You can check which unique_id
Oracle Notarization backend is running by requesting the /info
endpoint.
You can also run the Oracle Notarization backend yourself using reproducible builds and see the generated unique ID. It should match the unique_id
provided by other Oracle Notarization backends if they run the same code.
allowed_keys#
allowed_keys
allowed_keys
contains public keys generated by the Oracle Notarization backends which are used to verify the Schnorr signature of a report. Each time the Oracle Notarization backend starts it generates a key, which is used to create a signature. We store a list of keys from the backends that are verified and trusted, and reject all reports with untrusted keys.
attested_data#
attested_data
attested_data
stores the latest acquired data from a specific request. When new data is being pushed to the program it replaces the old value. You can always access the stored data using your Request Hash as a key.
last_update_timestamp#
last_update_timestamp
last_update_timestamp
contains a timestamp of the attestation of the data that is stored in attested_data
mapping was attested. This timestamp is used to make sure that the current report was created after the last verified report.
Functions#
set_key#
set_key
This function is used by the owner of the program to add or remove allowed public keys that are used to verify Schnorr signature. The function flips the value of the key:
- If key was not present or not allowed then it becomes allowed
- If key was already allowed then it becomes not allowed
set_unique_id#
set_unique_id
This function is used by the owner of the program to replace the old SGX enclave unique_id
with a new one. unique_id
is used to verify that a report was produced using a specific version of the source code. This function is used when the source code of Oracle Notarization backend is updated to make sure that the oracle program can be updated without re-deploying.
verify_report#
verify_report
This function is used to verify that the provided report
is valid. As a first step, it takes Poseidon8 hash of data
, which is the report data that was included into the report. Then it checks that certain enclave flags are set correctly, for example that the SGX enclave is not in a debug mode (see here for more about SGX flags). Then it checks that the Poseidon8 data_hash
that we created is matching the one included in the report. For verification that the report is valid it takes the Poseidon8 hash of the report itself and checks the provided signature on top of the report hash against the provided public_key
generated by the enclave (we are going to check that this public key is allowed later in the finalize
step of set_data
).
Here is a detailed explanation of report
fields that are being verified.
set_data#
set_data
This function is used to update the Oracle program with the new data. It takes the report_data
that was included in the report, the report
itself, the Schnorr signature
of the provided report and the public_key
to verify this signature.
As a first step oracle verifies the report (see verify_report) and its signature, then it creates the request_hash
by creating a new structure with the attestation data and timestamp zeroed out. This hash is going to be used as a key to store the provided attestation_data
. You can read more about how the Request Hash
works here.
In the finalize step the Oracle verifies that the uniquie_id
of the report is correct and the public_key
provided for signature verification is allowed. Then it checks that the timestamp of the report creation is newer than the time of the last provided report to make sure the data is not outdated. And then it saves data into the attested_data
mapping and updates last_update_timestamp
with the timestamp of the provided report.
How to use the Oracle#
Here is an example on how to use values stored in the Aleo Oracle.
If you want to use the values outside of the Aleo blockchain then you can simply query the mapping value from the blockchain using the Request Hash as a key:
Querying the Aleo Oracle
curl https://api.explorer.aleo.org/v1/testnet/program/official_oracle.aleo/mapping/attested_data/{request_hash}
Where request_hash
is a Hash of the Request that was used to get data (with zeroed Data and Timestamp to make it static).
To use Aleo Oracle in your Aleo program you need to import the Oracle program first and then get a value from the attested_data
mapping. Keep in mind that in Aleo you can only read mappings during the Finalize function.
Querying the Aleo Oracle from Aleo program
Example of a simple program that will transfer an attested amount of some token.
Since you can read mappings only during the Finalize
stage, in this example we provide the amount as a function parameter to a Transition
function to use and then verify that the provided value is correct during the Finalize
step.
Where request_hash
is the Hash of the Request that was used during the Notarization process (with Data and Timestamp zeroed out to make it static).
Data timestamp#
In case you only want to use data that is not older than a certain timestamp you can use the last_update_timestamp
mapping from the Oracle. It contains the timestamp of the last report that was used to set data.
Using last_update_timestamp
Value type#
Aleo Oracle stores all the values as u128
numbers. In case you require smaller numbers, e.g. u64
, you can cast u128
to the desired size.
(!) Keep in mind that a u128
number should be small enough to fit into the desired type (for example u64
). A u64
number represents 8 bytes of information while u128
is 16 bytes. So if you want to cast u128
to u64
then the u128
value should only contain not more than 8 bytes of information, not more than 4 bytes for u32
, etc. Use this trick only if you know that your data provider gives smaller than u128
responses.
Casting a u128
to a smaller number