From 0d6c439cb945f20fbe8020bb92b3462e2d3de098 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Fri, 29 Sep 2023 11:17:28 -0400 Subject: [PATCH 01/33] update defi to DeFi, fmt --- docs/docs/about_aztec/history/history.mdx | 53 ++++++++++++++--------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/docs/docs/about_aztec/history/history.mdx b/docs/docs/about_aztec/history/history.mdx index 4a037c9cf8b..cda6774186e 100644 --- a/docs/docs/about_aztec/history/history.mdx +++ b/docs/docs/about_aztec/history/history.mdx @@ -9,27 +9,32 @@ import Image from "@theme/IdealImage"; --- + ## Bitcoin The original blockchain. -**Programmability**: -- None. +**Programmability**: + +- None. - Transfer bitcoin only. -**Privacy**: +**Privacy**: + - None. --- ## Ethereum -**Programmability**: +**Programmability**: + - Turing complete smart contracts. -**Privacy**: -- Originally: None. -- Now: +**Privacy**: + +- Originally: None. +- Now: - some specific apps on L1 - some specific apps, deployed via L2, like zk.money and Aztec Connect. @@ -37,46 +42,54 @@ The original blockchain. ## ZCash -**Programmability**: -- None. +**Programmability**: + +- None. - Transfer ZCash only. -**Privacy**: +**Privacy**: + - Transfers of shielded zcash are private. --- ## zk.money -**Programmability**: +**Programmability**: + - Any custom ERC20 token (on Ethereum L1) can be deposited to L2, transferred within L2, and withdrawn from L2. -**Privacy**: +**Privacy**: + - Transfers of the ERC20 tokens within the L2 are private. --- ## Aztec Connect -**Programmability**: -- The functionality of zk.money, plus: -- Tokens can be sent from the L2 shielded pool to many L1 defi contracts, and the resulting tokens can be re-shielded. This gives anonymity to L1 defi users. +**Programmability**: + +- The functionality of zk.money, plus: +- Tokens can be sent from the L2 shielded pool to many L1 DeFi contracts, and the resulting tokens can be re-shielded. This gives anonymity to L1 DeFi users. -**Privacy**: -- Transfers of the ERC20 tokens within the L2 are private. -- User defi interactions are anonymous. +**Privacy**: + +- Transfers of the ERC20 tokens within the L2 are private. +- User DeFi interactions are anonymous. --- ## Aztec -**Programmability**: +**Programmability**: + - Fully programmable private smart contracts: - private functions which can edit general private state - cheap L2 public functions - L1 (public) functions. -**Privacy**: +**Privacy**: + - Executing private functions grants: - Function privacy - Input privacy From c1a3a87a2c36ae57d20978c342739639f20493d3 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Fri, 29 Sep 2023 11:34:45 -0400 Subject: [PATCH 02/33] copy edits --- docs/docs/about_aztec/history/history.mdx | 4 ++-- docs/docs/about_aztec/overview.mdx | 12 ++++++------ .../advanced/circuits/kernels/private_kernel.md | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/docs/about_aztec/history/history.mdx b/docs/docs/about_aztec/history/history.mdx index cda6774186e..ad82aafd73d 100644 --- a/docs/docs/about_aztec/history/history.mdx +++ b/docs/docs/about_aztec/history/history.mdx @@ -84,8 +84,8 @@ The original blockchain. **Programmability**: - Fully programmable private smart contracts: - - private functions which can edit general private state - - cheap L2 public functions + - Private functions which can edit general private state + - Cheap L2 public functions - L1 (public) functions. **Privacy**: diff --git a/docs/docs/about_aztec/overview.mdx b/docs/docs/about_aztec/overview.mdx index 0e38c8a1dbd..7180fcb402b 100644 --- a/docs/docs/about_aztec/overview.mdx +++ b/docs/docs/about_aztec/overview.mdx @@ -4,21 +4,21 @@ title: Overview import ReactPlayer from "react-player/youtube"; -The next version of our rollup, Aztec, is a privacy-preserving, programmable extension to Ethereum. It is a layer 2 zk-rollup on Ethereum that enables programable privacy via composable smart contracts. +Aztec is a layer 2 zk-rollup on Ethereum that enables programmable privacy via composable smart contracts. ## Private Smart Contracts on Aztec A smart contract on Aztec is a collection of functions, written as ZK-SNARK circuits. These circuits can have different modes of execution: -1. Secret Functions -- can read and write private state, read historic public state, consume or send messages to / from L1, and read Ethereum state. Can call other secret functions in the same contract, or other contracts. They can call public functions. -2. Public Functions -- can read and write public state, write private state, consume or send messages to / from L1 and read Ethereum state. Can call other public functions on the same or other contracts. -3. Portal Contracts -- these are contracts on L1 that can receive messages from L2 or send allow messages to be sent to L2 from L1 contracts. +1. Secret Functions -- can read and write private state, read historic public state, consume or send messages to / from Ethereum, and read Ethereum state. They can call other secret functions in the same contract, or other contracts, and can call public functions. +2. Public Functions -- can read and write public state, write private state, consume or send messages to / from Ethereum and read Ethereum state. They can call other public functions on the same or other contracts. +3. Portal Contracts -- these are contracts on Ethereum that can receive messages from Aztec or send messages to Aztec from Ethereum contracts. Using these different modes of execution, developers can build applications with user privacy, data privacy and code privacy. User privacy -- transactions may not reveal information about the sender or the recipient. -Data privacy -- transactions may not reveal information about the payload of the transaction, e.g the asset or value being transacted. +Data privacy -- transactions may not reveal information about the payload of the transaction, e.g., the asset or value being transacted. Code privacy -- transactions may not reveal the program logic. @@ -50,7 +50,7 @@ Contributors to Aztec uphold many of the values of the Ethereum community -- bui ## Noir -Noir is a domain specific programming language for writing zero knowledge circuits. On Aztec a smart contract is a collection of circuits that developers write using Noir. +Noir is a domain specific programming language for writing zero-knowledge circuits. On Aztec a smart contract is a collection of circuits that developers write using Noir. You can find more information and resources for learning about Noir smart contracts on [this page](../dev_docs/contracts/main.md). diff --git a/docs/docs/concepts/advanced/circuits/kernels/private_kernel.md b/docs/docs/concepts/advanced/circuits/kernels/private_kernel.md index 405a6163061..cc0632c986f 100644 --- a/docs/docs/concepts/advanced/circuits/kernels/private_kernel.md +++ b/docs/docs/concepts/advanced/circuits/kernels/private_kernel.md @@ -21,5 +21,5 @@ This circuit is executed by the user, on their own device. This is to ensure pri - Verifies a previous 'Private Kernel Proof', recursively, when verifying transactions which are composed of many private function calls. - Optionally can [deploy](../../contract_creation) a new private contract. -> Note: **This is the only core protocol circuit which actually needs to be "zk" (zero knowledge)!!!** That's because this is the only core protocol circuit which handles private data, and hence the only circuit for which proofs must not leak any information about witnesses! (The private data being handled includes: details of the Aztec.nr Contract function which has been executed; the address of the user who executed the function; the intelligible inputs and outputs of that function). -> This is a really interesting point. Most so-called "zk-Rollups" do not make use of this "zero knowledge" property. Their snarks are "snarks"; with no need for zero-knowledge, because they don't seek privacy; they only seek the 'succinct' computation-compression properties of snarks. Aztec's "zk-Rollup" actually makes use of "zero knowledge" snarks. That's why we sometimes call it a "zk-zk-Rollup", or "_actual_ zk-Rollup". +> Note: **This is the only core protocol circuit which actually needs to be "zk" (zero-knowledge)!!!** That's because this is the only core protocol circuit which handles private data, and hence the only circuit for which proofs must not leak any information about witnesses! (The private data being handled includes: details of the Aztec.nr Contract function which has been executed; the address of the user who executed the function; the intelligible inputs and outputs of that function). +> This is a really interesting point. Most so-called "zk-Rollups" do not make use of this "zero-knowledge" property. Their snarks are "snarks"; with no need for zero-knowledge, because they don't seek privacy; they only seek the 'succinct' computation-compression properties of snarks. Aztec's "zk-Rollup" actually makes use of "zero-knowledge" snarks. That's why we sometimes call it a "zk-zk-Rollup", or "_actual_ zk-Rollup". From 9cf72d751481b3b515d803b014adf15fa22973b2 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Fri, 29 Sep 2023 12:45:27 -0400 Subject: [PATCH 03/33] edits --- docs/docs/about_aztec/overview.mdx | 2 +- docs/docs/dev_docs/getting_started/quickstart.md | 5 ++--- docs/docs/dev_docs/getting_started/sandbox.md | 4 +++- docs/docs/dev_docs/tutorials/main.md | 4 ++++ 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/docs/about_aztec/overview.mdx b/docs/docs/about_aztec/overview.mdx index 7180fcb402b..dde9f2c1192 100644 --- a/docs/docs/about_aztec/overview.mdx +++ b/docs/docs/about_aztec/overview.mdx @@ -4,7 +4,7 @@ title: Overview import ReactPlayer from "react-player/youtube"; -Aztec is a layer 2 zk-rollup on Ethereum that enables programmable privacy via composable smart contracts. +Aztec is an L2 that brings programmable privacy to Ethereum. ## Private Smart Contracts on Aztec diff --git a/docs/docs/dev_docs/getting_started/quickstart.md b/docs/docs/dev_docs/getting_started/quickstart.md index 48735d70aa0..999a8ccb206 100644 --- a/docs/docs/dev_docs/getting_started/quickstart.md +++ b/docs/docs/dev_docs/getting_started/quickstart.md @@ -37,7 +37,7 @@ This quickstart walks you through installing the Sandbox, deploying your first N - Node.js >= v18 (recommend installing with [nvm](https://github.com/nvm-sh/nvm)) - Docker and Docker Compose (Docker Desktop under WSL2 on windows) -## Installation +## Sandbox Installation You can run the Sandbox using either Docker or npm. @@ -69,7 +69,7 @@ You will also need an Ethereum node like Anvil or Hardhat running locally on por npx @aztec/aztec-sandbox ``` -### CLI +## CLI Installation To interact with the sandbox now that it's running locally, install the [Aztec CLI](https://www.npmjs.com/package/@aztec/cli): @@ -117,4 +117,3 @@ Aztec's Layer 2 network is a fully programmable combined private/public ZK rollu - Private Execution Environment (PXE) - Normally residing with the end client, this decrypts and stores a client's private state, executes simulations and submits transactions to the Aztec Node. - [Aztec.js](./sandbox) - Aztec's client library for interacting with the PXE (think Ethers.js). - [Aztec.nr](../contracts/main.md) - Aztec's smart contract framework - diff --git a/docs/docs/dev_docs/getting_started/sandbox.md b/docs/docs/dev_docs/getting_started/sandbox.md index 7c15428d9c0..799249bcc2c 100644 --- a/docs/docs/dev_docs/getting_started/sandbox.md +++ b/docs/docs/dev_docs/getting_started/sandbox.md @@ -260,6 +260,7 @@ In this section, we created 2 instances of the `TokenContract` contract abstract We can see that each account has the expected balance of tokens. ### Diagram of calling an unconstrained (view) function + Unconstrained function call ## Creating and submitting transactions @@ -312,7 +313,7 @@ Finally, the contract has a `mint` function that can be used to generate new tok Here is the Noir code: -#include_code mint /yarn-project/noir-contracts/src/contracts/private_token_contract/src/main.nr rust +#include_code mint_private /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust Let's mint some tokens to Bob's account using Typescript, add this to `index.ts`: @@ -350,6 +351,7 @@ That's it! We have successfully deployed a private token contract to an instance You can find the [complete tutorial code here](https://github.com/AztecProtocol/dev-rel/tree/main/tutorials/sandbox-tutorial/token). ### Diagram of sending a transaction + Sending a transaction ## Next Steps diff --git a/docs/docs/dev_docs/tutorials/main.md b/docs/docs/dev_docs/tutorials/main.md index da6889b6fc8..c294167c9d2 100644 --- a/docs/docs/dev_docs/tutorials/main.md +++ b/docs/docs/dev_docs/tutorials/main.md @@ -1,3 +1,7 @@ +--- +title: Tutorials +--- + import DocCardList from '@theme/DocCardList'; From d853c288dd35054a72129ebb7677134a6e777552 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Fri, 29 Sep 2023 16:25:05 -0400 Subject: [PATCH 04/33] update roadmap section --- .../roadmap/cryptography_roadmap.md | 23 +- .../roadmap/engineering_roadmap.md | 265 ------------------ .../roadmap/features_initial_ldt.md | 89 +----- docs/docs/about_aztec/roadmap/main.md | 11 +- docs/sidebars.js | 1 - docs/static/img/road_to_testnet.png | Bin 0 -> 260035 bytes 6 files changed, 29 insertions(+), 360 deletions(-) delete mode 100644 docs/docs/about_aztec/roadmap/engineering_roadmap.md create mode 100644 docs/static/img/road_to_testnet.png diff --git a/docs/docs/about_aztec/roadmap/cryptography_roadmap.md b/docs/docs/about_aztec/roadmap/cryptography_roadmap.md index 0cef1ff7e37..f24537c1a0b 100644 --- a/docs/docs/about_aztec/roadmap/cryptography_roadmap.md +++ b/docs/docs/about_aztec/roadmap/cryptography_roadmap.md @@ -2,26 +2,23 @@ title: Cryptography Roadmap --- -The cryptography team is currently working on [Barretenberg here](https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg) +The cryptography team is currently working on [Barretenberg here.](https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg) ## R&D projects -- Publish the Honk paper, describing practical considerations for constructing our cutting-edge proving system Honk along with formal proofs of its security properties. +Publish the Honk paper, describing practical considerations for constructing our cutting-edge proving system Honk along with formal proofs of its security properties. ## Honk -- Honk is a sumcheck-based zk-SNARK protocol with blazing-fast zk proof construction. We need Honk to allow users to prove correct execution of complicated, multi-step computations using recursion in a resource constraint environment like a cell phone. This is necessary for our mission, because we need to make sure our users' sensitive information never leaves their devices! -- List of Honk projects - - Completed: basic Honk prover and verifier with respectable construction and verification speeds, but no optimization. - - Upcoming: - - Bringing "Ultra" functionality to Honk: lookup tables, efficient range constraints, RAM, ROM, and more will result in orders-of-magnitude improvements to Honk's prover times. - - Recursion using cycles of curves will allow for efficient recursive verification of Honk proofs. Using this technique will lower the barrier to entry of our rollup providers, resulting in a more robust set of providers and greater security for the Aztec network. +Honk is a sumcheck-based zk-SNARK protocol with blazing-fast zk proof construction. We need Honk to allow users to prove correct execution of complicated, multi-step computations using recursion in a resource constraint environment like a cell phone. This is necessary for our mission, because we need to make sure our users' sensitive information never leaves their devices! -## Goblin projects +List of Honk projects: -- Goblin is a deferred verification framework thats allow for an order-of-magnitude increase in the complexity of computations that Aztec users can execute with full privacy. This corresponds to a 10x increase in the expressivity of Noir programs that can be run in practice without melting anybody's favorite phone or laptop. +- Completed: basic Honk prover and verifier with respectable construction and verification speeds, but no optimization. +- Upcoming: + - Bringing "Ultra" functionality to Honk: lookup tables, efficient range constraints, RAM, ROM, and more will result in orders-of-magnitude improvements to Honk's prover times. + - Recursion using cycles of curves will allow for efficient recursive verification of Honk proofs. Using this technique will lower the barrier to entry of our rollup providers, resulting in a more robust set of providers and greater security for the Aztec network. -Read more here. https://hackmd.io/@aztec-network/B19AA8812 +## Goblin projects -- List of Goblin projects - - Aside from some prototype code by Zac, we have not begun working on this yet. +Goblin is a deferred verification framework thats allow for an order-of-magnitude increase in the complexity of computations that Aztec users can execute with full privacy. This corresponds to a 10x increase in the expressivity of Noir programs that can be run in practice without melting anybody's favorite phone or laptop. Read more [here](https://hackmd.io/@aztec-network/B19AA8812). diff --git a/docs/docs/about_aztec/roadmap/engineering_roadmap.md b/docs/docs/about_aztec/roadmap/engineering_roadmap.md deleted file mode 100644 index 55756a69fd6..00000000000 --- a/docs/docs/about_aztec/roadmap/engineering_roadmap.md +++ /dev/null @@ -1,265 +0,0 @@ -# Engineering Wishlist - -The engineering roadmap is long. There are no timings assigned here. In a loose priority order: - -## Sandbox Community Support - -- Triage on discord / discourse / github. -- Iterating on the docs and code, given people's issues. -- Encouraging contributions to 'good first issue' issues. -- Release notes. -- Versioning. -- Aztec Improvement Proposals (AZIPs) -- Aztec Requests for Comment (AZRCs) - -## Benchmarking - -- Gather metrics about everything, to guide future decisions. - -## Standardisation efforts - -- Recommended Aztec smart contract coding patterns -- Access Control (whitelists/blacklists) - probably needs the Slow Updates tree (or something similar). -- Basic _example_ private tokens - - Including recursive calls to 'get_notes'. -- Compliant private tokens -- Private NFTs -- Public tokens -- Depositing and withdrawing tokens - - L1<\>L2 - - public<\>private -- The Aztec Connect bridging pattern -- Using Keys (the fully-featured version of keys that we want to build) -- Plume nullifiers -- Negative reputation example -- Anti-denial-of-service -- Combining Aztec with MPC - -## Polishing what we have - -- Refactoring sprints. - - Reduce tech debt. - - More tests. - -## Enforcing correct ordering Public & Private State Transitions - -## Enforcing correct ordering of other 'side effects' -- Log ordering -- Enqueued public function calls - -## What data actually needs to be submitted on-chain? -- For Public Functions: - - Just emit the initially-enqueued public function request data? (The 'inputs' of the tx); - - I.e. contract address, function selector, args, call_context. - - OR, Just emit the final state transitions? (The 'outputs' of the tx) - - I.e. the leaf indices and new values of the public data tree; and the new commitments/nullifiers of the private data tree; and logs; and l2->L1 messages. - -## Proper specs - -- Write detailed specs, given recent protocol changes. -- Review the code to ensure it matches what we _think_ the protocol is. -- Open issues to ensure the code matches the spec. -- (Note: bringing cryptographers into the fold (to review specs) is a separate section, later in this doc). - -## Iterate on the Sandbox - -Based on community feedback, we'll need some teams to iterate on Sandbox features and fix bugs. - -## Iterate on the Aztec Smart Contract Library - -## Iterating on CI - -CI takes up a significant amount of time. It gets its own section here, so we remember it exists. - -## Sequencer & Prover Selection protocols - -- Decide on protocol -- Spec -- Build. - -## Upgradeability - -- Decide on protocol -- Spec -- Build. - -## Fees - -- Design the Protocol - - Interdependence on the Sequencer & Upgradeability protocols. - - Pay fees in 1 currency, or fee abstraction? - - Escrowing fees - - Rebates - - L1->L2 message fees. - - L2->L1 fees - - Etc. -- Build it. - - Gas metering - - Etc. - -## Note Discovery - -- Note Discovery RFP -- Decide on the protocol -- Spec -- Build it. - -## Privacy-preserving queries to public nodes - -- Explore PIR -- Explore alternatives -- Implement - -## Keys - -- Write up keys spec -- Get internal comments -- Do a RFC from the external community -- Implement - -## Slow Updates tree? - -We _need_ a way to read mutable public data from a private function. - -## Contract classes and instances? - -- There's a suggestion to introduce contract classes. - -## Delegatecalls vs SetCode -- Which? (if at all) - -## Remove the contracts tree? 🤯 - -- There's a suggestion to remove the notion of a contracts tree. What do we actually need the tree for? To check that a vk hash exists for a particular contract address? -- If the contract address contains the function tree, and it also contains data about the constructor args to that contract, then perhaps we don't need the contract tree to exist. -- We might still need the notion of a 'deployment': - - to broadcast a contract's bytecode; - - to 'reserve' a contract address; - - and possibly to prevent a constructor from being executed twice (although an app could do this ("constructor abstraction")). - -## Cryptography review checkpoint - -- Once we have specs (see above), we should review the rigour and secureness to our protocol. - - Choice of hashes - - Domain separation - - Choice of encryption scheme - - Keys - - A security review of the protocol as a whole - -## Testing UX team - -A team focussed on testing and debugging UX. -This team should have free rein to design and add any features they see fit. - -Some example features: -- Writing contract tests in Noir. - - Mocking oracles. -- Taking inspiration from other testing frameworks. -- Much more detailed logging if things go wrong. -- Errors which only spit out opaque 254-bit hex numbers are bad. - - Ensure all circuits are fed the human-readable information underlying all of these hex numbers. - - If tree root comparisons (expected vs actual) fail, human-readable details about the leaves in trees should be provided. - -## Tooling - -## Proper Circuits - -### Redesign -- The Bus - - The bus will have an impact on the way we design the circuit logic. - - We can hopefully avoid hashing in circuit 1 and unpacking that hash in circuit 2. - - Understand the 'bus' and how we can use it to pass variable amounts of data between recursive circuit iterations. - - Redesign all circuit logic to allow for the variable-sized arrays that the 'bus' enables. -- Enable 'dynamic/variable-sized **loops**' - - allow each `for` loop (eg read requests, insertions, commitment squashing, call stack processing, bip32 key derivation, etc.) to vary in size, by deferring each loop to its own final circuit. This would require complex folding stuff. - - This would give much more flexibility over the sizes of various arrays that a circuit can output. Without it, if one array of an app circuit needs to be size 2000, but other arrays aren't used, we'd use a kernel where every array is size 2048, meaning a huge amount of unnecessary loops of computation for those empty arrays. -- Improvements - - We can definitely change how call stacks are processed within a kernel, to reduce hashing. - - Squash pending commitments/nullifiers in every kernel iteration, to enable a deeper nested call depth. -- Topology of a rollup - - Revisit the current topology: - - We can make the rollup trees 'wonky' (rather than balanced), meaning a sequencer doesn't need to prove a load of pointless 'padding' proofs? - - This would also enable new txs (entering the tx pool) to be added to a rollup block 'on-the-fly' (mid way through a rollup being proven) - but of course, the sequencer selection protocol might require an up-front commitment, so this might not be possible for that reason (sad face). - - We can definitely redesign the public kernel circuit to be a '2x2' topology (i.e. a tree of public kernel proofs), to get a logarithmic speed-up (parallelism). The question is, with folding schemes, do we need that optimisation? - -#### Refactor of packing & unpacking data in circuits - -We often pack data in circuit A, and then unpack it again in circuit B. -- args_hash -- return_values_hash -- call stacks -- read requests -- etc. - -Also, for logs in particular, we allow arbitrary-sized logs. But this requires sha256 packing inside an app circuit (which is slow) (and sha256 unpacking in Solidity (which is relatively cheap)). Perhaps we also use the bus ideas for logs, to give _some_ variability in log length, but up to an upper bound. - -Also, we do a lot of sha256-compressing in our kernel and rollup circuits for data which must be checked on-chain, but grows exponentially with every round of iteration. E.g.: new contract deployment data, new nullifiers, new commitments, public state transition data, etc. This might be unavoidable. Maybe all we can do is use polynomial commitments when the EIP-4844 work is done. But maybe we can use the bus for this stuff too. - -### Write proper circuits - -### The Public VM Circuit - -- Design it -- Build it - -### The Brillig Bytecode Commitment Circuit - -- A circuit which proves the brillig bytecode being emitted matches the polynomial commitment to that bytecode. - -### Decide on constants! - -### Honk -> Ultra Squisher Circuit - -### Ultra -> Standard Squisher Circuit - -## Authentication: access to private data -- Private data must not be returned to an app, unless the user authorizes it. - -## Validation: preventing execution of malicious bytecode -- A node should check that the bytecode provided by an application for a given app matches the leaf in the contract tree to ensure that user doesn't execute unplanned code which might access their notes. - -## Fuzz Testing - -## Formal Verification - -An investigation into how formal verification techniques might improve the security of Aztec software. - -## P2P network - -- A robust p2p network for the tx pool and the proof pool. - -## Hashes - -- An improved, standardised Pedersen hash in barretenberg. -- Poseidon hashing in barretenberg. - -## Tree epochs -- Nullifier tree epochs -- Maybe other tree epochs. - -## Chaining txs -- We have the ability to spend pending notes (which haven't-yet been added to the tree) _within the context of a single tx_. -- We need the ability to spend pending notes (which haven't yet been added to the tree) across different txs, within the context of a single rollup. - - This happens if Alice generates two txs X & Y, where tx Y spends notes from tx X. If we want Alice to be able to generate these txs in parallel (without interacting with the network at all), we need a way for tx Y to spend notes before they've been added to the tree. The 'chaining tx' concepts from Aztec Connect can enable this. -- This added _a lot_ of complexity to Aztec Connect. Especially around fees, iirc. Caution needed. - -## EIP-4844 - -- Understand it. Spec it. Build it. -- Includes: - - Smart Contract changes - - Circuit changes - - A circuit to prove equivalence vs a BLS12-381 polynomial commitment. - -## Make it all work in a browser - -## Code Freeze - -## Internal Audit - -## External Audits - - - - - diff --git a/docs/docs/about_aztec/roadmap/features_initial_ldt.md b/docs/docs/about_aztec/roadmap/features_initial_ldt.md index 34b86912cba..228cb2ee72a 100644 --- a/docs/docs/about_aztec/roadmap/features_initial_ldt.md +++ b/docs/docs/about_aztec/roadmap/features_initial_ldt.md @@ -1,87 +1,16 @@ --- -title: Initial Sandbox Features +title: Sandbox Features --- -import Disclaimer from "../../misc/common/\_disclaimer.mdx"; - - - -The Aztec Sandbox is intended to provide developers with a lightweight & fast node, with features similar to Ethereum's Ganache or Anvil 'local node' packages. +The Aztec Sandbox is intended to provide developers with a lightweight and fast local node. Developers should be able to quickly spin up local, emulated instances of an Ethereum blockchain and an Aztec encrypted rollup, and start deploying private contracts and submitting private txs. -Here's a summary of the features we intend to support with the first release of the Aztec Sandbox. - -## Aztec.nr Contracts - -See the source on Github [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec-nr). - -- Noir `contract` scopes. - - Declare a `contract`, containing a collection of state variables and functions. -- private state variables: - - `read`, `write`, and `delete` private state variables within private functions. -- public (non-private) state variables: - - Manipulate 'public' state in a familiar way to Ethereum state. -- private functions - - May read and modify private state. -- public functions - - May read and modify public state. -- `constructor` functions, for initialising contract state. -- `import` other Aztec.nr contracts, so their functions may be called. -- Nested function calls, for contract composability - - private functions can call private functions of other contracts, and receive return values. - - private functions can call public functions any contract. - - public functions can call private functions of any contract. - - public functions can call public functions of other contracts, and receive return values. - - private functions can be called recursively. - - public functions can be called recursively. -- Send messages from Aztec.nr contracts to Ethereum L1, for consumption by L1 smart contracts. - - Useful, for example, if writing an app to withdraw funds from L2 to L1. -- Consume messages which have been sent by: - - L1 functions. - - Useful, for example, if writing an app to deposit funds from L1 to L2. - - public L2 functions. -- Emit `event` data from a Aztec.nr Contract. - - Allows applications to subscribe to events which have been emitted by a Aztec.nr contract's functions, for example. -- Write `unconstrained` functions. - - These allow developers to write `pure` and `view` functions, which can perform calculations and retrieve state. E.g. for fetching contract-specific information, which may then be consumed by a dapp, without having to generate a zero-knowledge proof or interact with the 'network'. - -## `aztec.js` - -A typescript wrapper for making RPC calls to an Aztec Sandbox node. See the source on Github [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec.js). - -- Similar in purpose to `web3.js`/`ethers.js`/`viem`, but for interacting with Aztec Network nodes. The RPC interface for an Aztec node is necessarily different from that of an Ethereum node, because it deals with encrypted transactions and state variables. -- A library for public/private key management. -- Construct `Contract` instances from a Aztec.nr contract's JSON ABI. -- Deploy new contracts to the Aztec Sandbox. -- Construct tx requests, passing arguments to a function of a contract. -- Sign tx requests. -- Send txs to the Sandbox node, for simulating. -- Send txs to the Sandbox node, to be sent to the Sandbox network. -- Call `unconstrained` functions of a Aztec.nr contract, to perform `pure` calculations or retrieve state. - -## Aztec Sandbox Node - -A bundle of packages which emulate the actions of all eventual Aztec network participants. The goal is for developer experience to be akin to Ganache / Anvil. +The sandbox allows developers to: -- PXE client - - Simulate and/or execute private functions locally. -- Aztec Public Node - - Broadcasts a user's txs to the tx pool. - - Simulate public functions locally. -- Tx Pool - - An in-memory emulation of a tx pool. By default, a user's txs will be rolled-up into an L2 block immediately. -- Sequencer Node - - Reads the tx pool and bundles pending txs into a rollup block immediately. - - Orders txs. - - Executes public functions. - - Passes messages between L1 and L2. -- L1 Rollup smart contract - - Verifies the rollup's snark. - - Reconciles calldata with snark public inputs. - - Updates the rollup's state hash. -- L1 data archiver - - Gobbles up and stores all calldata, events, and state changes from L1 -- World state DB - - Reconstructs the Aztec Network's various trees. - - Allows tree state to be queried. +- Write and deploy Aztec contracts +- Leverage private and public state variables in contracts +- Write private and public functions in contracts +- Call private and public functions on other Aztec contracts (contract composability) +- Send messages between Aztec and Ethereum contracts +- Interact with the Aztec network using a familiar Typescript SDK ([aztec.js](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec.js)) diff --git a/docs/docs/about_aztec/roadmap/main.md b/docs/docs/about_aztec/roadmap/main.md index 5e8f320137b..587f8751d6e 100644 --- a/docs/docs/about_aztec/roadmap/main.md +++ b/docs/docs/about_aztec/roadmap/main.md @@ -1,5 +1,14 @@ +--- +title: Roadmap +--- + import DocCardList from '@theme/DocCardList'; +import Image from '@theme/IdealImage'; + +The next major milestone on the journey to mainnet is launching our testnet. + + -# Roadmap +## Read more diff --git a/docs/sidebars.js b/docs/sidebars.js index ab75b2abe2a..275dce7c0fc 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -46,7 +46,6 @@ const sidebars = { }, items: [ "about_aztec/roadmap/features_initial_ldt", - "about_aztec/roadmap/engineering_roadmap", "about_aztec/roadmap/cryptography_roadmap", ], }, diff --git a/docs/static/img/road_to_testnet.png b/docs/static/img/road_to_testnet.png new file mode 100644 index 0000000000000000000000000000000000000000..6753422ca837199fd6325fa76f29d3df0ed3206c GIT binary patch literal 260035 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'uQ5KUn5MFGu4d3OsOo9N`f_Yes*>{ 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

70s;2geK(Fc-c;=yg`+w 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�FLy{OA=6!(P%t11Q>;JF-=4);4q5XxK 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 gR2}0Se;;>uGd>Uh2Tjm3ivR!s literal 0 HcmV?d00001 From acb4c010ebb98d033f5b4fa36ff1dcffd905fdf8 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Fri, 29 Sep 2023 20:00:45 -0400 Subject: [PATCH 05/33] remove engineering roadmap links --- docs/docs/dev_docs/limitations/main.md | 20 ++++++++++---------- docs/docs/dev_docs/privacy/main.md | 25 ++++++------------------- docs/netlify.toml | 4 ---- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/docs/docs/dev_docs/limitations/main.md b/docs/docs/dev_docs/limitations/main.md index d55bb375404..44a8e565989 100644 --- a/docs/docs/dev_docs/limitations/main.md +++ b/docs/docs/dev_docs/limitations/main.md @@ -12,7 +12,6 @@ The Aztec Sandbox and the Aztec Smart Contract Library are **prototypes**, and s - An 'unpolished' UX; - Missing information. - ## Why participate? Front-run the future! @@ -27,22 +26,23 @@ Help shape and define: - Core protocol improvements; ## Limitations developers need to know about + - It is a testing environment, it is insecure, unaudited and does not generate any proofs, its only for testing purposes; - Constructors can not call nor alter public state - - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [constructor](../contracts/syntax/functions.md#constructor). + - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [constructor](../contracts/syntax/functions.md#constructor). - No static nor delegate calls (see [mutability](../contracts/syntax/functions.md#mutability)). - - These values are unused in the call-context. + - These values are unused in the call-context. - Beware that what you think of as a `view` could alter state ATM! Notably the account could alter state or re-enter whenever the account contract's `is_valid` function is called. - `msg_sender` is currently leaking when doing private -> public calls - The `msg_sender` will always be set, if you call a public function from the private world, the `msg_sender` will be set to the private caller's address. See [function context](../contracts/syntax/context.mdx). - The initial `msg_sender` is 0, which can be problematic for some contracts, see [function visibility](../contracts/syntax/functions.md#function-visibility). -- Unencrypted logs don't link to the contract that emitted it, so essentially just a `debug_log`` that you can match values against. +- Unencrypted logs don't link to the contract that emitted it, so essentially just a `debug_log`` that you can match values against. - A note that is created and nullified in the same transaction will still emit an encrypted log. -- A limited amount of new commitments, nullifiers and calls that are supported by a transaction, see [circuit limitations](#circuit-limitations). +- A limited amount of new commitments, nullifiers and calls that are supported by a transaction, see [circuit limitations](#circuit-limitations). ## Limitations -There are plans to resolve all of the below. See also the [engineering roadmap](../../about_aztec/roadmap/engineering_roadmap.md). +There are plans to resolve all of the below. ### It is not audited @@ -72,7 +72,7 @@ Obviously, as development continues, the so-called 'circuits' will actually beco The Sandbox will execute more quickly. The logic of all 'circuits' is still in place*. Smart contract logic will be executed, and core protocol logic will be executed*. So invalid transactions will be caught\* and rejected. -\*Note: some core protocol circuit assertions and constraints still need to be written (see [GitHub](https://github.com/AztecProtocol/aztec-packages/issues)). This would be bad in an adversarial environment, but the Sandbox is not that. Naturally, proper circuits will need to be written - see the [engineering roadmap](../../about_aztec/roadmap/engineering_roadmap.md). +\*Note: some core protocol circuit assertions and constraints still need to be written (see [GitHub](https://github.com/AztecProtocol/aztec-packages/issues)). This would be bad in an adversarial environment, but the Sandbox is not that. Naturally, proper circuits will need to be written. ### No Fees! @@ -90,7 +90,7 @@ Apps won't yet be able to allow for any L2 fee logic. Once fees are introduced, The way in which keypairs and addresses are currently derived and implemented (inside the Sandbox) is greatly over-simplified, relative to future plans. -They're so over-simplified that they're known to be insecure. Other features have been prioritised so-far in Sandbox development. Please refer to the [future roadmap](../../about_aztec/roadmap/engineering_roadmap.md) +They're so over-simplified that they're known to be insecure. Other features have been prioritised so-far in Sandbox development. #### What are the consequences? @@ -130,7 +130,7 @@ A contract can't perform a delegatecall yet (if ever). Delegatecalls are quite a Ethereum has a notion of a 'full node' which keeps-up with the blockchain and stores the full chain state. Many users don't wish to run full nodes, so rely on 3rd-party 'full-node-as-a-service' infrastructure providers, who service blockchain queries from their users. -This pattern is likely to develop in Aztec as well, except there's a problem: privacy. If a privacy-seeking user makes a query to a 3rd-party 'full node', that user might leak data about who they are, or about their historic network activity, or about their future intentions. One solution to this problem is "always run a full node", but pragmatically, not everyone will. To protect less-advanced users' privacy, [research is underway](../../about_aztec/roadmap/engineering_roadmap.md) to explore how a privacy-seeking user may request and receive data from a 3rd-party node without revealing what that data is, nor who is making the request. +This pattern is likely to develop in Aztec as well, except there's a problem: privacy. If a privacy-seeking user makes a query to a 3rd-party 'full node', that user might leak data about who they are, or about their historic network activity, or about their future intentions. One solution to this problem is "always run a full node", but pragmatically, not everyone will. To protect less-advanced users' privacy, research is underway to explore how a privacy-seeking user may request and receive data from a 3rd-party node without revealing what that data is, nor who is making the request. ### No private data authentication @@ -209,7 +209,7 @@ Not only are there limits on a _per function_ basis, there are also limits on a **In particular, these _per-transaction_ limits will limit transaction call stack depths** in the Sandbox. That means if a function call results in a cascade of nested function calls, and each of those function calls outputs lots of state reads and writes, or logs (etc.), then all of that accumulated output data might exceed the per-transaction limits that we currently have. This would cause such transactions to fail. -There are [plans](../../about_aztec/roadmap/engineering_roadmap.md#proper-circuits) to relax all of this rigidity, by providing many 'sizes' of [kernel circuit](../../concepts/advanced/circuits/kernels/main.md), and introducing a 'bus' to ferry varying lengths of data between kernel iterations. But that'll all take some time. +There are plans to relax all of this rigidity, by providing many 'sizes' of [kernel circuit](../../concepts/advanced/circuits/kernels/main.md), and introducing a 'bus' to ferry varying lengths of data between kernel iterations. But that'll all take some time. > **In the mean time**, if you encounter a per-transaction limit when testing, and you're feeling adventurous, you could 'hack' the Sandbox to increase the limits. See here (TODO: link) for a guide. **However**, the limits cannot be increased indefinitely. So although we do anticipate that we'll be able to increase them a little bit, don't go mad and provide yourself with 1 million state transitions per transaction. That would be as unrealistic as artificially increasing Ethereum gas limits to 1 trillion. diff --git a/docs/docs/dev_docs/privacy/main.md b/docs/docs/dev_docs/privacy/main.md index 38debb833e8..1b79fe82d83 100644 --- a/docs/docs/dev_docs/privacy/main.md +++ b/docs/docs/dev_docs/privacy/main.md @@ -24,22 +24,18 @@ Emit encrypted events, or encrypted messages from a private smart contract funct Execute a private function without the world knowing which function you've executed. - - :::danger Privacy is not guaranteed without care. Although Aztec provides the tools for private smart contracts, information can still be leaked unless the dapp developer is careful. This page outlines some best practices to aid dapp developers. ::: - --- ## Leaky practices There are many caveats to the above. Since Aztec also enables interaction with the _public_ world (public L2 functions and L1 functions), private information can be accidentally leaked if developers aren't careful. - ### Crossing the private -> public boundary Any time a private function makes a call to a public function, information is leaked. Now, that might be perfectly fine in some use cases (it's up to the smart contract developer). Indeed, most interesting apps will require some public state. But let's have a look at some leaky patterns: @@ -51,12 +47,10 @@ Any time a private function makes a call to a public function, information is le - Emitting unencrypted events from a private function. The unencrypted event name and arguments will be publicly visible. - Sending L2->L1 messages from a private function. The entire message, and the resulting L1 function execution will all be publicly visible. - ### Crossing the public -> private boundary If a public function sends a message to be consumed by a private function, the act of consuming that message might be leaked if not following recommended patterns. See [here](../contracts/portals/inbox.md) for more details. - ### Timing of transactions Information about the nature of a transaction can be leaked based on the timing of that transaction. @@ -69,7 +63,6 @@ Suppose that every time Alice sends Bob a private token, 1 minute later a transa Tl;dr: app developers should think about the _timing_ of user transactions, and how this might leak information. - ### Function Fingerprints and Tx Fingerprints A 'Function Fingerprint' is any data which is exposed by a function to the outside world. A 'Tx Fingerprint' is any data which is exposed by a tx to the outside world. We're interested in minimising leakages of information from private txs. The leakiness of a Tx Fingerprint depends on the leakiness of its consituent functions' Function Fingerprints _and_ on the appearance of the tx's Tx Fingerprint as a whole. For a private function (and by extension, for a private tx), the following information _could_ be leaked (depending on the function, of course): @@ -82,7 +75,7 @@ A 'Function Fingerprint' is any data which is exposed by a function to the outsi - The contents of L2 -> L1 messages. - All unencrypted logs (topics and arguments). - The roots of all trees which have been read from. -- The _number_ of ['side effects'](https://en.wikipedia.org/wiki/Side_effect_(computer_science)): +- The _number_ of ['side effects'](): - \# new commitments - \# new nullifiers - \# bytes of encrypted logs @@ -90,18 +83,14 @@ A 'Function Fingerprint' is any data which is exposed by a function to the outsi - \# L2->L1 messages - \# nonzero roots[^1] - - > Note: many of these were mentioned in the ["Crossing the private -> public boundary"](#crossing-the-private---public-boundary) section. > Note: the calldata submitted to L1 is [encoded](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Decoder.sol) in such a way that all categories of data are packed together, when submitted. E.g. all commitments from all txs in a block are arranged as contiguous bytes of calldata. But that _doesn't_ mean the data from a particular tx is garbled in with all other txs' calldata: the distinct Tx Fingerprint of each tx can is publicly visible when a tx is submitted to the L2 tx pool. - #### Standardising Fingerprints If each private function were to have a unique Fingerprint, then all private functions would be distinguishable from each-other, and all of the efforts of the Aztec protocol to enable 'private function execution' would have been pointless. Standards need to be developed, to encourage smart contract developers to adhere to a restricted set of Tx Fingerprints. For example, a standard might propose that the number of new commitments, nullifiers, logs, etc. must always be equal, and must always equal a power of two. Such a standard would effectively group private functions/txs into 'privacy sets', where all functions/txs in a particular 'privacy set' would look indistinguishable from each-other, when executed. - ### Data queries It's not just the broadcasting of transactions to the network that can leak data. @@ -128,20 +117,18 @@ If a user runs their own node, there's no problem: they can query the latest sib But if a user is not running their own node, they would need to query the very-latest sibling path of their note(s) from some 3rd-party node. In order to query the sibling path of a leaf, the leaf's index needs to be provided as an argument. Revealing the leaf's index to a 3rd-party trivially reveals exactly the note(s) you're about to read. And since those notes were created in some prior transaction, the 3rd-party will be able to link you with that prior transaction. Suppose then that the 3rd-party also serviced the creator of said prior transaction: the 3rd-party will slowly be able to link more and more transactions, and gain more and more insight into a network which is meant to be private! -We're [researching](../../about_aztec/roadmap/engineering_roadmap.md) cryptographic ways to enable users to retrieve sibling paths from 3rd-parties without revealing leaf indices. +We're researching cryptographic ways to enable users to retrieve sibling paths from 3rd-parties without revealing leaf indices. > \* Note: due to the non-uniformity of Aztec transactions, the 'anonymity set' of a transaction might not be the entire set of transactions that came before. See here (LINK). ##### Any query -Any query to a node leaks information to that node. - -We're [researching](../../about_aztec/roadmap/engineering_roadmap.md) cryptographic ways to enable users to query any data privately. - - +Any query to a node leaks information to that node. +We're researching cryptographic ways to enable users to query any data privately. --- + Footnotes -[^1]: All txs should set the kernel circuit public inputs for all roots to _valid_, _up-to-date_ nonzero values, so as to mask which trees have _actually_ been read from. The Sandbox will eventually automate this (see this [issue](https://github.com/AztecProtocol/aztec-packages/issues/1676)). \ No newline at end of file +[^1]: All txs should set the kernel circuit public inputs for all roots to _valid_, _up-to-date_ nonzero values, so as to mask which trees have _actually_ been read from. The Sandbox will eventually automate this (see this [issue](https://github.com/AztecProtocol/aztec-packages/issues/1676)). diff --git a/docs/netlify.toml b/docs/netlify.toml index f0647be3c7a..fa128d2d14f 100644 --- a/docs/netlify.toml +++ b/docs/netlify.toml @@ -98,10 +98,6 @@ from = "/aztec/cryptography/cryptography-roadmap" to = "/about_aztec/roadmap/cryptography_roadmap" -[[redirects]] - from = "/aztec/milestones" - to = "/about_aztec/roadmap/engineering_roadmap" - [[redirects]] from = "/aztec/milestones/features-initial-ldt" to = "/about_aztec/roadmap/features_initial_ldt" From b6041c858c12e4bea3e4bec22c925be4a8796c83 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Fri, 29 Sep 2023 20:03:36 -0400 Subject: [PATCH 06/33] add intro section --- .../data_structures/indexed_merkle_tree.md | 17 ++++++++++++----- .../concepts/advanced/data_structures/trees.md | 18 +++++++++++++----- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/docs/docs/concepts/advanced/data_structures/indexed_merkle_tree.md b/docs/docs/concepts/advanced/data_structures/indexed_merkle_tree.md index 927a4e6a387..751b209dc9b 100644 --- a/docs/docs/concepts/advanced/data_structures/indexed_merkle_tree.md +++ b/docs/docs/concepts/advanced/data_structures/indexed_merkle_tree.md @@ -3,17 +3,24 @@ title: Indexed Merkle Tree --- import Image from "@theme/IdealImage"; -import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; - +## Overview -## Indexed Merkle Trees +This article will introduce the concept of an indexed merkle tree, and how it can be used to improve the performance of nullifier trees in circuits. -This article will introduce the concept of an indexed merkle tree, and how it can be used to improve the performance of nullifier trees in circuits. The content was also covered in a presentation for the [Privacy + Scaling Explorations team at the Ethereum Foundation](https://pse.dev/). +This page will answer: + +- Why we need nullifier trees at all +- How indexed merkle trees work +- How they can be used for membership exclusion proofs +- How they can leverage batch insertions +- Tradoffs of using indexed merkle trees + +The content was also covered in a presentation for the [Privacy + Scaling Explorations team at the Ethereum Foundation](https://pse.dev/). -#### Primer on Nullifier Trees +## Primer on Nullifier Trees Currently the only feasible way to get privacy in public blockchains is via a UTXO model. In this model, state is stored in encrypted UTXO's in merkle trees. However, to maintain privacy, state can not be updated. The very act of performing an update leaks information. In order to simulate "updating" the state, we "destroy" old UTXO's and create new ones for each state update. Resulting in a merkle tree that is append-only. diff --git a/docs/docs/concepts/advanced/data_structures/trees.md b/docs/docs/concepts/advanced/data_structures/trees.md index d2d4034b477..b4db42c0c28 100644 --- a/docs/docs/concepts/advanced/data_structures/trees.md +++ b/docs/docs/concepts/advanced/data_structures/trees.md @@ -2,10 +2,18 @@ title: Trees --- -import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; import Image from "@theme/IdealImage"; - +## Overview + +Data trees are how we keep track of all the data in the network. Each type of data is stored in it's own data tree. Different tree structures are used for different kinds of data, as the requirements for each are different. + +Data includes: + +- Private state +- Nullifiers to invalidate old private state +- Public state +- Contracts ## Private State Tree @@ -17,7 +25,7 @@ Any function of any Aztec contract may insert new leaves into the this tree. Once inserted into this tree, a leaf's value can never be modified. We enforce this, to prevent linkability of transactions. If an observer sees that 'tx A' inserted a leaf and 'tx B' modified that leaf, then the observer knows these two transactions are related in some way. This is a big 'no no' if we want to ensure privacy. -So, if an app needs to edit a private state variable (which will be represented by one or more leaves in the tree), it may do so in a manner inspired by [zerocash](http://zerocash-project.org/media/pdf/zerocash-extended-20140518.pdf). (See Nullifier Tree, further down this page). This allows the leaf to be 'nullified' and a new leaf value inserted into the next empty position in the tree, in a way which prevents observers from linking the old and new leaves. +So, if an app needs to edit a private state variable (which will be represented by one or more leaves in the tree), it may do so in a manner inspired by [zerocash](http://zerocash-project.org/media/pdf/zerocash-extended-20140518.pdf). (See [Nullifier Tree](#nullifier-tree)). This allows the leaf to be 'nullified' and a new leaf value inserted into the next empty position in the tree, in a way which prevents observers from linking the old and new leaves. @@ -136,6 +144,6 @@ The contract tree contains information about every function of every contract de - `treeOfHistoricPrivateDataTreeRoots`: for membership checks against historic roots of the `privateDataTree` - `treeOfHistoricContractTreeRoots`: for membership checks against historic roots of the `contractTree` -## Trees of valid Kernel/Rollup circuit VKs +## Trees of valid Kernel/Rollup circuit Verification Keys -Eventually, we'll have trees of VKs for various permutations of kernel/rollup circuits. Such permutations might be the number of public inputs, or the logic contained within the circuits. +Eventually, we'll have trees of verification keys for various permutations of kernel/rollup circuits. Such permutations might be the number of public inputs, or the logic contained within the circuits. From 3a0f6c69cc23004a033e40f6d1849c637604b2db Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Wed, 4 Oct 2023 18:08:34 +0100 Subject: [PATCH 07/33] intermediate intro to contracts, state model, acconts, cross chain calls, public private calls, portals, functions, storage, writing account contract --- .../docs/concepts/foundation/accounts/main.md | 24 ++++-- .../communication/cross_chain_calls.md | 13 ++- .../communication/public_private_calls.md | 9 +- docs/docs/concepts/foundation/contracts.md | 11 +++ docs/docs/concepts/foundation/state_model.md | 12 +++ docs/docs/dev_docs/contracts/portals/main.md | 85 +++++++++++-------- .../dev_docs/contracts/syntax/functions.md | 12 ++- .../docs/dev_docs/contracts/syntax/storage.md | 66 +++++++++----- .../wallets/writing_an_account_contract.md | 13 ++- 9 files changed, 175 insertions(+), 70 deletions(-) diff --git a/docs/docs/concepts/foundation/accounts/main.md b/docs/docs/concepts/foundation/accounts/main.md index 26f9c234a27..5f6b1cf8595 100644 --- a/docs/docs/concepts/foundation/accounts/main.md +++ b/docs/docs/concepts/foundation/accounts/main.md @@ -2,13 +2,21 @@ **Every account in Aztec is a smart contract** which defines the rules for whether a transaction is or is not valid. This allows implementing different schemes for transaction signing, nonce management, and fee payments. However, encryption and nullifying keys, which are specific to private blockchains, are still enshrined at the protocol level. +In this section, you’ll learn about how Aztec defines AA (account abstraction) and its correlation with encryption keys and nullifying keys. We’ll go through: + +- The importance and implications of AA +- Understanding account contracts and wallets in relation to Aztec +- Concept of authorization and actions along with encryption +- The future of fee management in Aztec + ## Background We'll start with the mandatory "what is AA" section that every single article on the topic has, so you can skip this if you're familiar with the topic. ### What is account abstraction? -We'll refer to AA as the _ability to set the validity conditions of a transaction programmatically_ ([source](https://fuel-labs.ghost.io/account-abstraction-for-everyone-else/)). [Starknet](https://docs.starknet.io/documentation/architecture_and_concepts/Account_Abstraction/introduction/#account_abstraction) goes one step further and splits AA into three different components: +We'll refer to AA as the _ability to set the validity conditions of a transaction programmatically_ ([source](https://fuel-labs.ghost.io/account-abstraction-for-everyone-else/)). [Starknet](https://docs.starknet.io/documentation/architecture_and_concepts/Account_Abstraction/introduction/#account_abstraction) goes one step further and splits AA into three different components: + - Signature abstraction (defining when a signature is accepted) - Fee abstraction (paying fees) - Nonce abstraction (replay protection and ordering) @@ -19,7 +27,7 @@ The benefits of AA are multiple. We're not going to reiterate them all here, but ### Implementing at protocol vs application layer -Instead of implementing it at the protocol level as in Aztec, account abstraction can be implemented at the application layer of a network using smart accounts and meta-transactions. When implementing account abstraction on Ethereum, the transaction being sent to the network is still an Ethereum transaction, but its payload is interpreted as a "transaction execution request" that is validated and run by the smart contract wallet. +Instead of implementing it at the protocol level as in Aztec, account abstraction can be implemented at the application layer of a network using smart accounts and meta-transactions. When implementing account abstraction on Ethereum, the transaction being sent to the network is still an Ethereum transaction, but its payload is interpreted as a "transaction execution request" that is validated and run by the smart contract wallet. A simple example would be Gnosis Safe (see [_Account Abstraction is NOT coming_](https://safe.mirror.xyz/9KmZjEbFkmI79s28d9xar6JWYrE50F5AHpa5CR12YGI)), where it's the multisig contract responsibility to define when an execution request is valid by checking it carries N out of M signatures, and then executing it. [Argent](https://www.argent.xyz/blog/wtf-is-account-abstraction/) has also been working on smart wallets for years, and collaborating with network teams to implement AA natively at the protocol layer. @@ -50,11 +58,11 @@ def entryPoint(payload): let { privateCalls, publicCalls, nonce, signature } = payload; let payloadHash = hash(privateCalls, publicCalls, nonce); validateSignature(this.publicKey, signature, payloadHash); - + foreach privateCall in privateCalls: let { to, data, value } = privateCall; call(to, data, value); - + foreach publicCall in publicCalls: let { to, data, value, gasLimit } = publicCall; enqueueCall(to, data, value, gasLimit); @@ -90,11 +98,11 @@ A side-effect of not having nonces at the protocol level is that it is not possi Since the `entrypoint` interface is not enshrined, there is nothing that differentiates an account contract from an application one in the protocol. This means that a transaction can be initiated in any contract. This allows implementing functions that do not need to be called by any particular user and are just intended to advance the state of a contract. -As an example, we can think of a lottery contract, where at some point a prize needs to be paid out to its winners. This `pay` action does not require authentication and does not need to be executed by any user in particular, so anyone could submit a transaction that defines the lottery contract itself as `origin` and `pay` as entrypoint function. For an example implementation of a different use case, refer to the [`pokeable_token_contract`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/main.nr) in the repository. +As an example, we can think of a lottery contract, where at some point a prize needs to be paid out to its winners. This `pay` action does not require authentication and does not need to be executed by any user in particular, so anyone could submit a transaction that defines the lottery contract itself as `origin` and `pay` as entrypoint function. For an example implementation of a different use case, refer to the [`pokeable_token_contract`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/main.nr) in the repository. ### Account initialization -The protocol requires that every account is a contract for the purposes of sending a transaction. This means that a user needs to deploy their account contract as their first action when they want to interact with the network. +The protocol requires that every account is a contract for the purposes of sending a transaction. This means that a user needs to deploy their account contract as their first action when they want to interact with the network. However, this is not required when sitting on the receiving end. A user can deterministically derive their address from their encryption public key and the account contract they intend to deploy, and share this address with other users that want to interact with them _before_ they deploy the account contract. @@ -106,7 +114,7 @@ When executing a private function, this authorization is checked by requesting a The PXE is responsible for storing these auth witnesses and returning them to the requesting account contract. Auth witnesses can belong to the current user executing the local transaction, or to another user who shared it out-of-band. -However, during a public function execution, it is not possible to retrieve a value from the local oracle. To support authorizations in public functions, account contracts should save in contract storage what actions have been pre-authorized by their owner. +However, during a public function execution, it is not possible to retrieve a value from the local oracle. To support authorizations in public functions, account contracts should save in contract storage what actions have been pre-authorized by their owner. These two patterns combined allow an account contract to answer whether an action `is_valid` for a given user both in private and public contexts. @@ -122,4 +130,4 @@ NOTE: While we entertained the idea of abstracting note encryption, where accoun Fees are not implemented in the protocol at the time of this writing. Our goal is to abstract fee payments as well. This means that a transaction, in order to be considered valid, must prove that it has locked enough funds to pay for itself. However, this does not mandate where those funds come from, opening the door for easy implementation of paymasters or payment-in-kind via on-the-fly swaps. -However, there is one major consideration around public execution reverts. In the current design, if one of the public function executions enqueued in a transaction fails, then the entire transaction is reverted. But reverting the whole transaction would also revert the fee payment, and leave the sequencer with their hands empty after running the public execution. This means we will need to enshrine an initial verification and fee payment phase that is _not_ reverted if public execution fails. \ No newline at end of file +However, there is one major consideration around public execution reverts. In the current design, if one of the public function executions enqueued in a transaction fails, then the entire transaction is reverted. But reverting the whole transaction would also revert the fee payment, and leave the sequencer with their hands empty after running the public execution. This means we will need to enshrine an initial verification and fee payment phase that is _not_ reverted if public execution fails. diff --git a/docs/docs/concepts/foundation/communication/cross_chain_calls.md b/docs/docs/concepts/foundation/communication/cross_chain_calls.md index 86554a82090..090b74aa9f7 100644 --- a/docs/docs/concepts/foundation/communication/cross_chain_calls.md +++ b/docs/docs/concepts/foundation/communication/cross_chain_calls.md @@ -8,7 +8,18 @@ import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; -In the following section, we will look at cross-chain communication, mixing L1 and L2 for composability and profits. +In Aztec, what we call _portals_ are the key element in facilitating communication between L1 and L2. While typical L2 solutions rely on synchronous communication with L1, Aztec's privacy-first nature means this is not possible. You can learn more about why in the previous section. + +Traditional L1<>L2 communication might involve direct calls between L2 nd L1 contracts. However, in Aztec, due to the privacy components and the way transactions are processed (kernel proofs built on historical data), direct calls between L1 and L2 would not be possible if we want to maintain privacy. + +Portals are the solution to this problem, acting as bridges for communication between the two layers. These portals can transmit messages from public functions in L1 to private functions in L2 and vice versa, thus enabling messaging while maintaining privacy. + +This page covers: + +- How portals enable privacy communication between L1 and L2 +- How messages are sent, received, and processed +- Message Boxes and how they work +- How and why linking of contracts between L1 and L2 occurs # Objective diff --git a/docs/docs/concepts/foundation/communication/public_private_calls.md b/docs/docs/concepts/foundation/communication/public_private_calls.md index 32b42b091dd..d175f149569 100644 --- a/docs/docs/concepts/foundation/communication/public_private_calls.md +++ b/docs/docs/concepts/foundation/communication/public_private_calls.md @@ -8,7 +8,14 @@ import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; -The following section will try to outline what _private_ and _public_ functions can do, and give some intuition to why they have the limitations they have. +Aztec operates on a model of private and public functions that are able to work together. Private functions work by providing evidence of correct execution generated locally through kernel proofs. Public functions, on the other hand, are able to utilize the latest state to manage updates and perform alterations. + +On this page, you’ll learn: + +- How private and public functions work +- The role of public functions in managing state alterations and updates +- Communication and interactions between private and public functions +- How the sequencer manages the order of operations of private functions ### Objectives diff --git a/docs/docs/concepts/foundation/contracts.md b/docs/docs/concepts/foundation/contracts.md index 03435fcf9eb..e0921750579 100644 --- a/docs/docs/concepts/foundation/contracts.md +++ b/docs/docs/concepts/foundation/contracts.md @@ -6,6 +6,17 @@ import Disclaimer from '../../misc/common/\_disclaimer.mdx'; +Smart contracts in Aztec are privacy-first, and can include both public and private elements. They are written in Noir framework called Aztec.nr, and allow high-level programs to be convered into ZK circuits. + +On this page, you’ll learn how Aztec executes smart contracts for privacy and efficiency: + +- Role and structure of smart contracts within Aztec +- Intro into Noir programming language and how it converts to circuits +- The Aztec Kernel +- Transaction flow and confidentiality + +## Defining Aztec smart contracts + A "smart contract" is defined as a set of public and private functions written as Noir circuits. These functions operate on public and private state stored by a contract. Each function is represented as a ZK SNARK verification key, where the contract is uniquely described by the set of its verification keys, and stored in the Aztec Contracts tree. [Noir](https://noir-lang.org) is a programming language designed for converting high-level programs into ZK circuits. Based on Rust, the goal is to present an idiomatic way of writing private smart contracts that is familiar to Ethereum developers. Noir is under active development adding features such as contracts, functions and storage variables. diff --git a/docs/docs/concepts/foundation/state_model.md b/docs/docs/concepts/foundation/state_model.md index 5041e310ca6..ca48c4849e3 100644 --- a/docs/docs/concepts/foundation/state_model.md +++ b/docs/docs/concepts/foundation/state_model.md @@ -8,6 +8,18 @@ import Disclaimer from '../../misc/common/\_disclaimer.mdx'; ## Private State +Every smart contract needs a way to track information over time - that's what state is. In order to have both private and public transactions and storage in Aztec, we have to have public and private state. + +On this page, you’ll learn + +- Aztec's unique interpretation of private state +- Representation of private state in an append-only database +- Concept of 'deleting' private state variables using nullifiers +- How to modify private state +- How Aztec abstracts the UTXO model from developers + +## Private State on Aztec + Private state must be treated differently from public state and this must be expressed in the semantics of Aztec.nr. Private state is encrypted and therefore is "owned" by a user or a set of users (via shared secrets) that are able to decrypt the state. diff --git a/docs/docs/dev_docs/contracts/portals/main.md b/docs/docs/dev_docs/contracts/portals/main.md index 0ff0bc24d40..6e175a033a0 100644 --- a/docs/docs/dev_docs/contracts/portals/main.md +++ b/docs/docs/dev_docs/contracts/portals/main.md @@ -5,9 +5,20 @@ description: Documentation of Aztec's Portals and Cross-chain communication. ## What is a portal -A portal is the point of contact between L1 and a specific contract on Aztec. For applications such as token bridges, this is the point where the tokens are are held on L1 while used in L2. +A portal is the point of contact between L1 and a specific contract on Aztec. For applications such as token bridges, this is the point where the tokens are are held on L1 while used in L2. -As outlined in the [foundational concepts](../../../concepts/foundation/communication/cross_chain_calls.md), an Aztec L2 contract is linked to *ONE* L1 address at time of deployment (specified by the developer). This L1 address is the only address that can send messages to that specific L2 contract, and the only address that can receive messages sent from the L2 contract to L1. Note, that a portal don't actually need to be a contract, it could be any address on L1. We say that an Aztec contract is attached to a portal. +On this page, we’ll go over: + +- The concept of "Portals" in Aztec, which act as the contact point between L1 and an Aztec L2 contract +- How to pass data to Aztec L2 from L1 via the Inbox, marking how messages are sent on the network +- The process of sending messages to L2 using the function `sendL2Message` along with the parameters it requires like recipient, deadline, content, and fee. +- The method of consuming L1 to L2 messages through the use of the `consume_l1_to_l2_message` function. +- How to send a message to L1 from an Aztec contract, using the `message_portal` function on the context. +- Strategies to handle error scenarios during cross-chain messaging, with a focus on transaction failures and implementing appropriate fallback mechanisms. + +## What is a Portal? + +As outlined in the [foundational concepts](../../../concepts/foundation/communication/cross_chain_calls.md), an Aztec L2 contract is linked to _ONE_ L1 address at time of deployment (specified by the developer). This L1 address is the only address that can send messages to that specific L2 contract, and the only address that can receive messages sent from the L2 contract to L1. Note, that a portal don't actually need to be a contract, it could be any address on L1. We say that an Aztec contract is attached to a portal. ## Passing data to the rollup @@ -17,24 +28,25 @@ The `Inbox` can be seen as a mailbox to the rollup, portals put messages into th When sending messages, we need to specify quite a bit of information beyond just the content that we are sharing. Namely we need to specify: -| Name | Type | Description | -| -------------- | ------- | ----------- | -| Recipient | `L2Actor` | The message recipient. This **MUST** match the rollup version and an Aztec contract that is **attached** to the contract making this call. If the recipient is not attached to the caller, the message cannot be consumed by it. | -| Deadline | `uint256` | The deadline for the message to be consumed. If the message has not been removed from the `Inbox` and included in a rollup block by this point, it can be *cancelled* by the portal (the portal must implement logic to cancel). | -| Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to be a single field. If the content is small enough it can just be passed along, otherwise it should be hashed and the hash passed along (you can use our [`Hash`](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Hash.sol) utilities with `sha256ToField` functions) | -| Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use the [`computeMessageSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. | -| Fee | `uint64` | The fee to the sequencer for including the message. This is the amount of ETH that the sequencer will receive for including the message. Note that it is not a full `uint256` but only `uint64`| +| Name | Type | Description | +| ----------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Recipient | `L2Actor` | The message recipient. This **MUST** match the rollup version and an Aztec contract that is **attached** to the contract making this call. If the recipient is not attached to the caller, the message cannot be consumed by it. | +| Deadline | `uint256` | The deadline for the message to be consumed. If the message has not been removed from the `Inbox` and included in a rollup block by this point, it can be _cancelled_ by the portal (the portal must implement logic to cancel). | +| Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to be a single field. If the content is small enough it can just be passed along, otherwise it should be hashed and the hash passed along (you can use our [`Hash`](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Hash.sol) utilities with `sha256ToField` functions) | +| Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use the [`computeMessageSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. | +| Fee | `uint64` | The fee to the sequencer for including the message. This is the amount of ETH that the sequencer will receive for including the message. Note that it is not a full `uint256` but only `uint64` | -With all that information at hand, we can call the `sendL2Message` function on the Inbox. The function will return a `field` (inside `bytes32`) that is the hash of the message. This hash can be used as an identifier to spot when your message has been included in a rollup block. +With all that information at hand, we can call the `sendL2Message` function on the Inbox. The function will return a `field` (inside `bytes32`) that is the hash of the message. This hash can be used as an identifier to spot when your message has been included in a rollup block. #include_code send_l1_to_l2_message l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity As time passes, a sequencer will see your tx, the juicy fee provided and include it in a rollup block. Upon inclusion, it is removed from L1, and made available to be consumed on L2. -To consume the message, we can use the `consume_l1_to_l2_message` function within the `context` struct. -- The `msg_key` is the hash of the message returned by the `sendL2Message` call and is used to help the RPC find the correct message. -- The `content` is the content of the message, limited to one Field element. For content larger than one Field, we suggest using the `sha256` hash function truncated to a single Field element. `sha256` is suggested as it is cheap on L1 while still being managable on L2. -- The `secret` is the pre-image hashed using Pedersen to compute the `secretHash`. +To consume the message, we can use the `consume_l1_to_l2_message` function within the `context` struct. + +- The `msg_key` is the hash of the message returned by the `sendL2Message` call and is used to help the RPC find the correct message. +- The `content` is the content of the message, limited to one Field element. For content larger than one Field, we suggest using the `sha256` hash function truncated to a single Field element. `sha256` is suggested as it is cheap on L1 while still being managable on L2. +- The `secret` is the pre-image hashed using Pedersen to compute the `secretHash`. - If the `content` or `secret` does not match the entry at `msg_key` the message will not be consumed, and the transaction will revert. :::info @@ -55,17 +67,17 @@ Since the message consumption is emitting a nullifier the same message cannot be To pass data to L1, we use the `Outbox`. The `Outbox` is the mailbox for L2 to L1 messages. This is the location on L1 where all the messages from L2 will live, and where they can be consumed from. -Similarly to messages going to L2 from L1, a message can only be consumed by the recipient, however note that it is up to the portal contract to ensure that the sender is as expected! +Similarly to messages going to L2 from L1, a message can only be consumed by the recipient, however note that it is up to the portal contract to ensure that the sender is as expected! Recall that we mentioned the Aztec contract specifies what portal it is attached to at deployment. This value is stored in the rollup's contract tree, hence these links are not directly readable on L1. Also, it is possible to attach multiple aztec contracts to the same portal. The portal must ensure that the sender is as expected. One way to do this, is to compute the addresses before deployment and store them as constants in the contract, however a more flexible solution is to have an `initialize` function in the portal contract which can be used to set the address of the Aztec contract. In this model, the portal contract can check that the sender matches the value it has in storage. -To send a message to L1 from your Aztec contract, you must use the `message_portal` function on the `context`. When messaging to L1, only the `content` is required (as a `Field`). +To send a message to L1 from your Aztec contract, you must use the `message_portal` function on the `context`. When messaging to L1, only the `content` is required (as a `Field`). #include_code context_message_portal /yarn-project/aztec-nr/aztec/src/context.nr rust -When sending a message from L2 to L1 we don't need to pass recipient, deadline, secret nor fees. Recipient is populated with the attached portal and the remaining values are not needed as the message is inserted into the outbox at the same time as it was included in a block (for the inbox it could be inserted and then only included in rollup block later). +When sending a message from L2 to L1 we don't need to pass recipient, deadline, secret nor fees. Recipient is populated with the attached portal and the remaining values are not needed as the message is inserted into the outbox at the same time as it was included in a block (for the inbox it could be inserted and then only included in rollup block later). :::danger Access control on the L1 portal contract is essential to prevent consumption of messages sent from the wrong L2 contract. @@ -85,36 +97,38 @@ As noted earlier, the portal contract should check that the sender is as expecte #include_code token_portal_withdraw l1-contracts/test/portals/TokenPortal.sol solidity - ## How to deploy a contract with a portal + - Deploy to L1 using Viem, Foundry or your preferred tool; - Deploy to L2 passing in the address of the L1 portal as its portal contract; ```typescript - const deploymentTx = Contract.deploy(wallet).send({portalContract: tokenPortalAddress}); + const deploymentTx = Contract.deploy(wallet).send({ + portalContract: tokenPortalAddress, + }); ``` - Initialize l1 with l2 address for access control. - ## Considerations ### Structure of messages -The application developer should consider creating messages that follow a function call structure e.g., using a function signature and arguments. This will make it easier to prevent producing messages that could be misinterpreted by the recipient. -An example of a bad format would be using `amount, token_address, recipient_address` as the message for a withdraw function and `amount, token_address, on_behalf_of_address` for a deposit function. Any deposit could then also be mapped to a withdraw or vice versa. +The application developer should consider creating messages that follow a function call structure e.g., using a function signature and arguments. This will make it easier to prevent producing messages that could be misinterpreted by the recipient. + +An example of a bad format would be using `amount, token_address, recipient_address` as the message for a withdraw function and `amount, token_address, on_behalf_of_address` for a deposit function. Any deposit could then also be mapped to a withdraw or vice versa. -```solidity +```solidity // Don't to this! bytes memory message = abi.encode( - _amount, - _token, + _amount, + _token, _to ); // Do this! bytes memory message abi.encodeWithSignature( - "withdraw(uint256,address,address)", - _amount, - _token, + "withdraw(uint256,address,address)", + _amount, + _token, _to ); ``` @@ -143,7 +157,7 @@ As this requires logic on the portal itself, it is not something that the protoc The portal can call the `cancelL2Message` at the `Inbox` when `block.timestamp > deadline` for the message. -#include_code pending_l2_cancel l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity +#include_code pending_l2_cancel l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity Building on our token example from earlier, this can be called like: @@ -152,19 +166,20 @@ Building on our token example from earlier, this can be called like: The example above ensure that the user can cancel their message if it is underpriced. ### Designated caller + Designating a caller grants the ability to specify who should be able to call a function that consumes a message. This is useful for ordering of batched messages. -When performing multiple cross-chain calls in one action it is important to consider the order of the calls. Say for example, that you want to perform a uniswap trade on L1 because you are a whale and slippage on L2 is too damn high. +When performing multiple cross-chain calls in one action it is important to consider the order of the calls. Say for example, that you want to perform a uniswap trade on L1 because you are a whale and slippage on L2 is too damn high. -You would practically, withdraw funds from the rollup, swap them on L1, and then deposit the swapped funds back into the rollup. This is a fairly simple process, but it requires that the calls are done in the correct order. For one, if the swap is called before the funds are withdrawn, the swap will fail. And if the deposit is called before the swap, the funds might get lost! +You would practically, withdraw funds from the rollup, swap them on L1, and then deposit the swapped funds back into the rollup. This is a fairly simple process, but it requires that the calls are done in the correct order. For one, if the swap is called before the funds are withdrawn, the swap will fail. And if the deposit is called before the swap, the funds might get lost! As message boxes only will allow the recipient portal to consume the message, we can use this to our advantage to ensure that the calls are done in the correct order. Say that we include a designated "caller" in the messages, and that the portal contract checks that the caller matches the designated caller or designated is address(0) (anyone can call). When the message are to be consumed on L1, it can compute the message as seen below: ```solidity bytes memory message = abi.encodeWithSignature( - "withdraw(uint256,address,address)", - _amount, - _to, + "withdraw(uint256,address,address)", + _amount, + _to, _withCaller ? msg.sender : address(0) ); ``` @@ -172,7 +187,7 @@ bytes memory message = abi.encodeWithSignature( This way, the message can be consumed by the portal contract, but only if the caller is the designated caller. By being a bit clever when specifying the designated caller, we can ensure that the calls are done in the correct order. For the Uniswap example, say that we have token portals implemented as we have done throughout this page, and a Uniswap portal implementing the designated caller. We require that the Uniswap portal is the caller of the withdraw, and that the uniswap portal implementation is executing the withdraw before the swap. -The order of execution can be constrained in the contract. Since all of the messages are emitted to L1 in the same transaction, we can leverage transaction atomicity to ensure success of failure of all messages. +The order of execution can be constrained in the contract. Since all of the messages are emitted to L1 in the same transaction, we can leverage transaction atomicity to ensure success of failure of all messages. Note, that crossing the L1/L2 chasm is asynchronous, so there could be a situation where the user has burned their assets on L2 but the swap fails on L1! This could be due to major price movements or the like. In such a case, the user could be stuck with funds on L1 that they cannot get back to L2 unless the portal contract implements a way to properly handle such errors. diff --git a/docs/docs/dev_docs/contracts/syntax/functions.md b/docs/docs/dev_docs/contracts/syntax/functions.md index f6a9197a79f..0af44cc63cb 100644 --- a/docs/docs/dev_docs/contracts/syntax/functions.md +++ b/docs/docs/dev_docs/contracts/syntax/functions.md @@ -3,6 +3,17 @@ title: Functions description: This page covers functions, private and public functions composability, as well as their differences. --- +Functions serve as the building blocks of smart contracts. Functions can be either public, ie they can interact with other contracts and the blockchain, or private for internal contract use. Every smart contract also has a private `constructor` function which is called when the contract is deployed. There are also special oracle functions, which can get data from outside of the smart contract. In the context of Aztec, oracles are often used to get user-provided inputs. + +On this page, you’ll learn more about: + +- How function visibility works in Aztec +- A detailed understanding of public, private, and unconstrained functions, and how to write them +- How constructors work and remain private +- The process of calling functions from within the same smart contract and from different contracts, including calling private functions from private functions, public from public, and even private from public +- What oracles and how Aztec smart contracts might use them +- Built-in oracles + ## Visibility In Aztec there are multiple different types of visibility that can be applied to functions. Namely we have `data visibility` and `function visibility`. @@ -307,7 +318,6 @@ When a [`Storage` struct](./storage.md) is declared within a contract, the `stor Any state variables declared in the `Storage` struct can now be accessed as normal struct members. - **Returning the function context to the kernel.** #include_code context-example-finish /yarn-project/noir-contracts/src/contracts/docs_example_contract/src/main.nr rust diff --git a/docs/docs/dev_docs/contracts/syntax/storage.md b/docs/docs/dev_docs/contracts/syntax/storage.md index 4bac605a736..d7aa8c75e52 100644 --- a/docs/docs/dev_docs/contracts/syntax/storage.md +++ b/docs/docs/dev_docs/contracts/syntax/storage.md @@ -2,12 +2,31 @@ title: Storage --- -In an Aztec.nr contract, storage is to be defined as a single struct, that contains both public and private state variables. +Smart contracts rely on storage, acting as the persistent memory on the blockchain. In Aztec, because of its privacy-first architecture, the management of this storage can be a bit more complex. + +You control this storage in Aztec using the 'Storage' struct. This struct serves as the housing unit for all your smart contract's state variables - the data it needs to keep track of and maintain. + +These state variables come in two forms: public and private. Public variables are visible to anyone, and private variables remain hidden within the contract. + +Aztec.nr has a few abstractions to help define the type of data your contract holds. These include Singletons, ImmutableSingletons, Set, and Map. + +On this page, you’ll learn: + +- How to manage a smart contract's storage structure +- The distinctions and applications of public and private state variables +- How to use Singleton, ImmutableSingleton, Set, and Map +- An overview of 'notes' and the UTXO model +- Practical implications of Storage in real smart contracts + In an Aztec.nr contract, storage is to be defined as a single struct, that contains both public and private state variables. + +## Public and private state variables As their name indicates, public state variables can be read by anyone, while private state variables can only be read by their owner, or people whom the owner has shared the data with. As mentioned earlier in the foundational concepts ([state model](./../../../concepts/foundation/state_model.md) and [private/public execution](./../../../concepts/foundation/communication/public_private_calls.md)) private state follows a UTXO model. Where note pre-images are only known to those able to decrypt them. +## Storage struct + :::info The struct **must** be called `Storage` for the Aztec.nr library to properly handle it (will be fixed in the future to support more flexibility). ::: @@ -82,12 +101,12 @@ To define that a variable is public, it is wrapped in the `PublicState` struct, #include_code public_state_struct /yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr rust -The `PublicState` struct is generic over the variable type `T` and its serialized size `T_SERIALIZED_LEN`. +The `PublicState` struct is generic over the variable type `T` and its serialized size `T_SERIALIZED_LEN`. :::info Currently, the length of the types must be specified when declaring the storage struct but the intention is that this will be inferred in the future. ::: -The struct contains a `storage_slot` which, similar to Ethereum, is used to figure out *where* in storage the variable is located. Notice that while we don't have the exact same [state model](./../../../concepts/foundation/state_model.md) as EVM chains it will look similar from the contract developers point of view. +The struct contains a `storage_slot` which, similar to Ethereum, is used to figure out _where_ in storage the variable is located. Notice that while we don't have the exact same [state model](./../../../concepts/foundation/state_model.md) as EVM chains it will look similar from the contract developers point of view. Beyond the struct, the `PublicState` also contains `serialization_methods`, which is a struct with methods that instruct the `PublicState` how to serialize and deserialize the variable. @@ -101,17 +120,18 @@ The Aztec.nr library provides serialization methods for various common types. As #include_code field_serialization /yarn-project/aztec-nr/aztec/src/types/type_serialization/field_serialization.nr rust - :::info An example using a larger struct can be found in the [lending example](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/src/contracts/lending_contract)'s use of an [`Asset`](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/src/contracts/lending_contract/src/asset.nr). ::: ### `new` + When declaring the storage for `T` as a persistent public storage variable, we use the `PublicState::new()` constructor. As seen below, this takes the `storage_slot` and the `serialization_methods` as arguments along with the [`Context`](./context.mdx), which in this case is used to share interface with other structures. #include_code public_state_struct_new /yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr rust #### Single value example + Say that we wish to add `admin` public state variable into our storage struct. In the struct we can add it as follows: #include_code storage_admin /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust @@ -121,14 +141,17 @@ And then when initializing it in the `Storage::init` function we can do it as fo #include_code storage_admin_init /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust In this case, specifying that we are dealing with a Field, and that it should be put at slot 1. This is just a single value, and would be similar to the following in solidity: + ```solidity address internal admin; ``` + :::info We know its verbose, and are working on making it less so. ::: #### Mapping example + Say we want to have a group of `minters` that are able to mint assets in our contract, and we want them in public storage, because [access control in private is quite cumbersome](./../../../concepts/foundation/communication/public_private_calls.md#a-note-on-l2-access-control). In the `Storage` struct we can add it as follows: #include_code storage_minters /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust @@ -140,13 +163,14 @@ And then when initializing it in the `Storage::init` function we can do it as fo In this case, specifying that we are dealing with a map of Fields, and that it should be put at slot 2. This would be similar to the following in solidity: + ```solidity mapping(address => bool) internal minters; ``` ### `read` -Now we have an idea of how to define storage, but storage is not really useful before we start using it, so how can we access it? +Now we have an idea of how to define storage, but storage is not really useful before we start using it, so how can we access it? Reading data from storage is straightforward. On the `PublicState` structs we have a `read` method to read the value at the location in storage and using the specified deserialization method to deserialize it. Here is the function definition in the `public_state.nr` source: @@ -158,17 +182,15 @@ For our `admin` example from earlier, this could be used as follows to check tha #include_code read_admin /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust - #### Reading from our `minters` example -As we saw in the Map earlier, a very similar operation can be done to perform a lookup in a map. +As we saw in the Map earlier, a very similar operation can be done to perform a lookup in a map. #include_code read_minter /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust - ### `write` -We figured out how to read values, but how do we write them? +We figured out how to read values, but how do we write them? Like reading, it is actually quite straight-forward. We have a `write` method on the `PublicState` struct that takes the value to write as an input and saves this in storage. It uses the serialization method defined earlier to serialize the value which inserts (possibly multiple) values into storage. @@ -183,6 +205,7 @@ Like reading, it is actually quite straight-forward. We have a `write` method on #include_code write_minter /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust ## Private State Variables + In contrast to public state, private state is persistent state that is **not** visible to the whole world. Depending on the logic of the smart contract, a private state variable's current value will only be known to one entity, or a closed group of entities. The value of a private state variable can either be shared via an [encrypted log](./events.md#encrypted-events), or offchain via web2, or completely offline: it's up to the app developer. @@ -201,7 +224,8 @@ These three structs abstract-away many of Aztec's protocol complexities, by prov Note that an app can also choose to emit data via unencrypted log, or to define a note whose data is easy to figure out, then the information is technically not private and could be visible to anyone. ::: -### Notes +### Notes + Unlike public state variables, which can be arbitrary types, private state variables operate on `NoteType`. Notes are the fundamental elements in the private world. @@ -226,9 +250,6 @@ The interplay between a private state variable and its notes can be confusing. H - To modify the "current value" of a `Set` state variable, is to [`insert`](#insert) new notes into the `Set`, or [`remove`](#remove) notes from that set. - Interestingly, if a developer requires a private state to be modifiable by users who _aren't_ privy to the value of that state, a `Set` is a very useful type. The `insert` method allows new notes to be added to the `Set` without knowing any of the other notes in the set! (Like posting an envelope into a post box, you don't know what else is in there!). - - - ## `Singleton` Singleton is a private state variable that is unique in a way. When a Singleton is initialized, a note is created to represent its value. And the way to update the value is to destroy the current note, and create a new one with the updated value. @@ -289,7 +310,7 @@ However, it's possible that at the time this function is called, the system hasn ImmutableSingleton represents a unique private state variable that, as the name suggests, is immutable. Once initialized, its value cannot be altered. -#include_code struct /yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr rust +#include_code struct /yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr rust ### `new` @@ -313,9 +334,9 @@ Once initialized, an ImmutableSingleton's value remains unchangeable. This metho Similar to the `Singleton`, we can use the `get_note` method to read the value of an ImmutableSingleton. -#include_code get_note /yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr rust +#include_code get_note /yarn-project/aztec-nr/aztec/src/state_vars/immutable_singleton.nr rust -Use this method to retrieve the value of an initialized ImmutableSingleton. +Use this method to retrieve the value of an initialized ImmutableSingleton. #include_code get_note /yarn-project/noir-contracts/src/contracts/schnorr_account_contract/src/main.nr rust @@ -327,7 +348,7 @@ This function will throw if the ImmutableSingleton hasn't been initialized. Set is used for managing a collection of notes. All notes in a set are of the same `NoteType`. But whether these notes all belong to one entity, or are accessible and editable by different entities, is totally up to the developer. Due to our state model, the set is a collection of notes inserted into the data-tree, but notes are never removed from the tree itself, they are only nullified. -#include_code struct /yarn-project/aztec-nr/aztec/src/state_vars/set.nr rust +#include_code struct /yarn-project/aztec-nr/aztec/src/state_vars/set.nr rust And can be added to the `Storage` struct as follows. Here adding a set for a custom note, the TransparentNote (useful for [public -> private communication](./functions.md#public---private)). @@ -371,13 +392,13 @@ This function is used to check existence of a note and then remove it without ha ### `assert_contains_and_remove_publicly_created` -Like above, this is used to ensure that the message exists in the data tree and then consume it. However, it differs slightly since there is currently a difference between notes that have been inserted from public and private execution. This means that you currently must use this function to consume and nullify a note that was created in a public function. This will be fixed in the future. +Like above, this is used to ensure that the message exists in the data tree and then consume it. However, it differs slightly since there is currently a difference between notes that have been inserted from public and private execution. This means that you currently must use this function to consume and nullify a note that was created in a public function. This will be fixed in the future. #include_code assert_contains_and_remove_publicly_created /yarn-project/aztec-nr/aztec/src/state_vars/set.nr rust @@ -389,7 +410,7 @@ The reason we are not reading this note ahead of time is that no [encrypted log] ### `remove` -Will remove a note from the set if it previously has been read from storage, e.g. you have fetched it through a `get_notes` call. This is useful when you want to remove a note that you have previously read from storage and do not have to read it again. If you recall from earlier, we are emitting a nullifier when reading values to make sure that they are up to date. +Will remove a note from the set if it previously has been read from storage, e.g. you have fetched it through a `get_notes` call. This is useful when you want to remove a note that you have previously read from storage and do not have to read it again. If you recall from earlier, we are emitting a nullifier when reading values to make sure that they are up to date. #include_code remove /yarn-project/aztec-nr/aztec/src/state_vars/set.nr rust @@ -403,15 +424,16 @@ This function returns the notes the account has access to: #include_code get_notes /yarn-project/aztec-nr/aztec/src/state_vars/set.nr rust -Our kernel circuits are constrained to a maximum number of notes this function can return at a time. Check [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/constants_gen.nr) and look for `MAX_READ_REQUESTS_PER_CALL` for the up-to-date number. +Our kernel circuits are constrained to a maximum number of notes this function can return at a time. Check [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/constants_gen.nr) and look for `MAX_READ_REQUESTS_PER_CALL` for the up-to-date number. Because of this limit, we should always consider using the second argument `NoteGetterOptions` to limit the number of notes we need to read and constrain in our programs. This is quite important as every extra call increases the time used to prove the program and we don't want to spend more time than necessary. -An example of such options is using the [filter_notes_min_sum](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/value-note/src/filter.nr) to get "enough" notes to cover a given value. Essentially, this function will return just enough notes to cover the amount specified such that we don't need to read all our notes. For users with a lot of notes, this becomes increasingly important. +An example of such options is using the [filter_notes_min_sum](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/value-note/src/filter.nr) to get "enough" notes to cover a given value. Essentially, this function will return just enough notes to cover the amount specified such that we don't need to read all our notes. For users with a lot of notes, this becomes increasingly important. #include_code get_notes /yarn-project/aztec-nr/easy-private-state/src/easy_private_state.nr rust ### `view_notes` + Functionally similar to [`get_notes`](#get_notes), but executed unconstrained and can be used by the wallet to fetch notes for use by front-ends etc. #include_code view_notes /yarn-project/aztec-nr/aztec/src/state_vars/set.nr rust diff --git a/docs/docs/dev_docs/wallets/writing_an_account_contract.md b/docs/docs/dev_docs/wallets/writing_an_account_contract.md index 8f14c62f1cc..82da3e113fd 100644 --- a/docs/docs/dev_docs/wallets/writing_an_account_contract.md +++ b/docs/docs/dev_docs/wallets/writing_an_account_contract.md @@ -2,6 +2,15 @@ This tutorial will take you through the process of writing your own account contract in Noir, along with the Typescript glue code required for using it within a [wallet](./main.md). +You will learn: + +- How to write a custom account contract in Aztec.nr +- The entrypoint function for transaction authentication and call execution +- The AccountActions module and EntrypointPayload struct, necessary inclusions for any account contract +- Customizing authorization validation within the 'is_valid' function (using Schnorr signatures as an example) +- Typescript glue code to format and authenticate transactions +- Deploying and testing the account contract + Writing your own account contract allows you to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed (including key rotation and recovery). In other words, writing an account contract lets you make the most out of [account abstraction](../../concepts/foundation/accounts/main.md#what-is-account-abstraction) in the Aztec network. It is highly recommended that you understand how an [account](../../concepts/foundation/accounts/main.md) is defined in Aztec, as well as the differences between privacy and authentication [keys](../../concepts/foundation/accounts/keys.md). You will also need to know how to write a [contract in Noir](../contracts/main.md), as well as some basic [Typescript](https://www.typescriptlang.org/). @@ -46,8 +55,8 @@ The `AccountActions` module provides default implementations for most of the acc #include_code is-valid yarn-project/noir-contracts/src/contracts/schnorr_hardcoded_account_contract/src/main.nr rust - For our account contract, we will take the hash of the action to authorize, request the corresponding auth witness from the oracle, and validate it against our hardcoded public key. If the signature is correct, we authorize the action. + ## The typescript side of things Now that we have a valid account contract, we need to write the typescript glue code that will take care of formatting and authenticating transactions so they can be processed by our contract, as well as deploying the contract during account setup. This takes the form of implementing the `AccountContract` interface: @@ -64,7 +73,7 @@ As you can see in the snippet above, to fill in this base class, we need to defi - The deployment arguments. - How to create an auth witness. -In our case, the auth witness will be generated by Schnorr-signing over the message identifier using the hardcoded key. To do this, we are using the `Schnorr` signer from the `@aztec/circuits.js` package to sign over the payload hash. This signer maps to exactly the same signing scheme that Noir's standard library expects in `schnorr::verify_signature`. +In our case, the auth witness will be generated by Schnorr-signing over the message identifier using the hardcoded key. To do this, we are using the `Schnorr` signer from the `@aztec/circuits.js` package to sign over the payload hash. This signer maps to exactly the same signing scheme that Noir's standard library expects in `schnorr::verify_signature`. :::info More signing schemes are available in case you want to experiment with other types of keys. Check out Noir's [documentation on cryptographic primitives](https://noir-lang.org/standard_library/cryptographic_primitives). From fcdac25eb95745538cc0211cfda050c5f412f8ea Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Wed, 4 Oct 2023 18:11:32 +0100 Subject: [PATCH 08/33] intermediate concept circuits --- docs/docs/concepts/advanced/circuits/main.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/docs/concepts/advanced/circuits/main.md b/docs/docs/concepts/advanced/circuits/main.md index 3f21cb79053..9a84f9cf60b 100644 --- a/docs/docs/concepts/advanced/circuits/main.md +++ b/docs/docs/concepts/advanced/circuits/main.md @@ -2,6 +2,12 @@ title: Circuits --- +Central to Aztec's operations are 'circuits' derived both from the core protocol and the developer-written Aztec.nr contracts. + +The core circuits enhance privacy by adding additional security checks and preserving transaction details - a characteristic Ethereum lacks. + +On this page, you’ll learn a bit more about these circuits and their integral role in promoting secure and efficient transactions within Aztec's privacy-centric framework. + ## Motivation In Aztec, circuits come from two sources: From cfc987fd415ec44735c3df88017515db154451ba Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Tue, 10 Oct 2023 16:19:45 -0400 Subject: [PATCH 09/33] remove bc deprecated --- docs/docs/dev_docs/contracts/syntax/storage.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/docs/docs/dev_docs/contracts/syntax/storage.md b/docs/docs/dev_docs/contracts/syntax/storage.md index 7e4ad48b564..cb66ea1fbb7 100644 --- a/docs/docs/dev_docs/contracts/syntax/storage.md +++ b/docs/docs/dev_docs/contracts/syntax/storage.md @@ -422,18 +422,6 @@ The usage is rather straight-forward and very similar to using the `insert` meth #include_code insert_from_public /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust -### `assert_contains_and_remove` - -This function is used to check existence of a note and then remove it without having read the note ahead of time. This can be useful for cases where the user is providing all the information needed, such as cases where the note was never emitted to the network and thereby available to the wallet. - -#include_code assert_contains_and_remove /yarn-project/aztec-nr/aztec/src/state_vars/set.nr rust - - - ### `assert_contains_and_remove_publicly_created` Like above, this is used to ensure that the message exists in the data tree and then consume it. However, it differs slightly since there is currently a difference between notes that have been inserted from public and private execution. This means that you currently must use this function to consume and nullify a note that was created in a public function. This will be fixed in the future. From 9ee37fa853fdebc91540bb5a7336f8ea8b14c341 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Thu, 19 Oct 2023 21:25:21 +0100 Subject: [PATCH 10/33] transactions and context --- docs/docs/concepts/foundation/transactions.md | 9 +++ .../dev_docs/contracts/syntax/context.mdx | 60 ++++++++++++++----- 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/docs/docs/concepts/foundation/transactions.md b/docs/docs/concepts/foundation/transactions.md index 5b5974802fa..7e44497ae07 100644 --- a/docs/docs/concepts/foundation/transactions.md +++ b/docs/docs/concepts/foundation/transactions.md @@ -2,6 +2,15 @@ title: Transactions --- +Transactions on Aztec start with a call from Aztec.js or the Aztec CLI, which creates a request containing transaction details. This request moves to the Private Execution Environment (PXE) which simulates and processes it. Then the PXE interacts with the Aztec Node which uses the sequencer to ensure that all the transaction details are enqueued properly. The sequencer then submits the block to the rollup contract, and the transaction is successfully mined. + +On this page you'll learn: + +- The step-by-step process of sending a transaction on Aztec +- The role of components like PXE, Aztec Node, ACIR simulator, and the sequencer +- The Aztec Kernel and its two circuits: private and public, and how they execute function calls +- The call stacks for private & public functions and how they determine a transaction's completion + Sending a transaction See [this diagram](https://raw.githubusercontent.com/AztecProtocol/aztec-packages/2fa143e4d88b3089ebbe2a9e53645edf66157dc8/docs/static/img/sandbox_sending_a_tx.svg) for an in-depth overview of the transaction execution process. It highlights 3 different types of transaction execution: contract deployments, private transactions and public transactions. diff --git a/docs/docs/dev_docs/contracts/syntax/context.mdx b/docs/docs/dev_docs/contracts/syntax/context.mdx index 3b8afffd983..a9aff4e0006 100644 --- a/docs/docs/dev_docs/contracts/syntax/context.mdx +++ b/docs/docs/dev_docs/contracts/syntax/context.mdx @@ -9,12 +9,23 @@ import Image from "@theme/IdealImage"; # The Function Context ## What is the context -The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](../../../concepts/advanced/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of it's side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity. -Behind the scenes, Aztec noir will pass data the kernel needs to and from a circuit, this is abstracted away from the developer. In an developer's eyes; the context is a useful structure that allows access and mutate the state of the `Aztec` blockchain. +The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](../../../concepts/advanced/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of it's side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity. + +Behind the scenes, Aztec.nr will pass data the kernel needs to and from a circuit, this is abstracted away from the developer. In an developer's eyes; the context is a useful structure that allows access and mutate the state of the `Aztec` blockchain. + +On this page, you'll learn + +- The details and functionalities of the private context in Aztec.nr +- Difference between the private and public contexts and their unified APIs +- Components of the private context, such as inputs, historic block data, and contract deployment data +- Elements like return values, read requests, new commitments, and nullifiers in transaction processing +- Differences between the private and public contexts, especially the unique features and variables in the public context ## Two context's one API -The `Aztec` blockchain contains two environments [public and private](../../../concepts/foundation/state_model.md). + +The `Aztec` blockchain contains two environments [public and private](../../../concepts/foundation/state_model.md). + - Private, for private transactions taking place on user's devices. - Public, for public transactions taking place on the network's sequencers. @@ -28,7 +39,9 @@ The code snippet below shows what is contained within the private context. #include_code private-context /yarn-project/aztec-nr/aztec/src/context.nr rust ### Private Context Broken Down + #### Inputs + The context inputs includes all of the information that is passed from the kernel circuit into the application circuit. It contains the following values. #include_code private-context-inputs /yarn-project/aztec-nr/aztec/src/abi.nr rust @@ -41,82 +54,97 @@ First of all, the call context. The call context contains information about the current call being made: - 1. Msg Sender - - The message sender is the account (Aztec Contract) that sent the message to the current context. In the first call of the kernel circuit (often the account contract call), this value will be empty. For all subsequent calls the value will be the previous call. + - The message sender is the account (Aztec Contract) that sent the message to the current context. In the first call of the kernel circuit (often the account contract call), this value will be empty. For all subsequent calls the value will be the previous call. > The graphic below illustrates how the message sender changes throughout the kernel circuit iterations. + 2. Storage contract address - - This value is the address of the current context's contract address. This value will be the value of the current contract that is being executed except for when the current call is a delegate call (Warning: This is yet to be implemented). In this case the value will be that of the sending contract. -3. Portal Contract Address - - This value stores the current contract's linked [portal contract](../portals/main.md) address. As a quick recap, this value is the value of the contracts related ethereum l1 contract address, and will be the recipient of any messages that are created by this contract. + - This value is the address of the current context's contract address. This value will be the value of the current contract that is being executed except for when the current call is a delegate call (Warning: This is yet to be implemented). In this case the value will be that of the sending contract. + +3. Portal Contract Address + - This value stores the current contract's linked [portal contract](../portals/main.md) address. As a quick recap, this value is the value of the contracts related ethereum l1 contract address, and will be the recipient of any messages that are created by this contract. 4. Flags - - Furthermore there are a series of flags that are stored within the application context: - - is_delegate_call: Denotes whether the current call is a delegate call. If true, then the storage contract address will be the address of the sender. - - is_static_call: This will be set if and only if the current call is a static call. In a static call, state changing altering operations are not allowed. - - is_contract_deployment: This will be set if and only if the current call is the contract's constructor. + - Furthermore there are a series of flags that are stored within the application context: + - is_delegate_call: Denotes whether the current call is a delegate call. If true, then the storage contract address will be the address of the sender. + - is_static_call: This will be set if and only if the current call is a static call. In a static call, state changing altering operations are not allowed. + - is_contract_deployment: This will be set if and only if the current call is the contract's constructor. ### Historic Block Data -Another structure that is contained within the context is the Historic Block Data object. This object is a special one as it contains all of the roots of Aztec's data trees. + +Another structure that is contained within the context is the Historic Block Data object. This object is a special one as it contains all of the roots of Aztec's data trees. #include_code historic-block-data /yarn-project/aztec-nr/aztec/src/abi.nr rust ### Contract Deployment Data + Just like with the `is_contract_deployment` flag mentioned earlier. This data will only be set to true when the current transaction is one in which a contract is being deployed. #include_code contract-deployment-data /yarn-project/aztec-nr/aztec/src/abi.nr rust ### Private Global Variables + In the private execution context, we only have access to a subset of the total global variables, we are restricted to those which can be reliably proven by the kernel circuits. #include_code private-global-variables /yarn-project/aztec-nr/aztec/src/abi.nr rust ### Args Hash -To allow for flexibility in the number of arguments supported by Aztec functions, all function inputs are reduced to a singular value which can be proven from within the application. + +To allow for flexibility in the number of arguments supported by Aztec functions, all function inputs are reduced to a singular value which can be proven from within the application. The `args_hash` is the result of pedersen hashing all of a function's inputs. ### Return Values + The return values are a set of values that are returned from an applications execution to be passed to other functions through the kernel. Developers do not need to worry about passing their function return values to the `context` directly as `Aztec.nr` takes care of it for you. See the documentation surrounding `Aztec.nr` [macro expansion](./functions.md#after-expansion) for more details. return_values : BoundedVec, ### Read Requests + ### New Commitments + New commitments contains an array of all of the commitments created in the current execution context. ### New Nullifiers + New nullifiers contains an array of the new nullifiers emitted from the current execution context. ### Nullified Commitments + Nullified commitments is an optimisation for introduced to help reduce state growth. There are often cases where commitments are created and nullified within the same transaction. In these cases there is no reason that these commitments should take up space on the node's commitment/nullifier trees. Keeping track of nullified commitments allows us to "cancel out" and prove these cases. ### Private Call Stack -The private call stack contains all of the external private function calls that have been created within the current context. Any function call objects are hashed and then pushed to the execution stack. + +The private call stack contains all of the external private function calls that have been created within the current context. Any function call objects are hashed and then pushed to the execution stack. The kernel circuit will orchestrate dispatching the calls and returning the values to the current context. ### Public Call Stack + The public call stack contains all of the external function calls that are created within the current context. Like the private call stack above, the calls are hashed and pushed to this stack. Unlike the private call stack, these calls are not executed client side. Whenever the function is sent to the network, it will have the public call stack attached to it. At this point the sequencer will take over and execute the transactions. ### New L2 to L1 msgs + New L2 to L1 messages contains messages that are delivered to the [l1 outbox](../../../concepts/foundation/communication/cross_chain_calls.md) on the execution of each rollup. ## Public Context + The Public Context includes all of the information passed from the `Public VM` into the execution environment. It is very similar to the [Private Context](#the-private-context), however it has some minor differences (detailed below). ### Public Context Inputs + In the current version of the system, the public context is almost a clone of the private execution context. It contains the same call context data, access to the same historic tree roots, however it does NOT have access to contract deployment data, this is due to traditional contract deployments only currently being possible from private transactions. #include_code public-context-inputs /yarn-project/aztec-nr/aztec/src/abi.nr rust - ### Public Global Variables + The public global variables are provided by the rollup sequencer and consequently contain some more values than the private global variables. #include_code public-global-variables /yarn-project/aztec-nr/aztec/src/abi.nr rust From 0284b0fa9766fbe9a8f88987b75dbe6b484b3e09 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Fri, 20 Oct 2023 09:05:45 +0100 Subject: [PATCH 11/33] remove deprecated assert_contains_and_remove --- docs/docs/dev_docs/contracts/syntax/storage.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/docs/docs/dev_docs/contracts/syntax/storage.md b/docs/docs/dev_docs/contracts/syntax/storage.md index cb66ea1fbb7..f6f011c3f57 100644 --- a/docs/docs/dev_docs/contracts/syntax/storage.md +++ b/docs/docs/dev_docs/contracts/syntax/storage.md @@ -422,18 +422,6 @@ The usage is rather straight-forward and very similar to using the `insert` meth #include_code insert_from_public /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust -### `assert_contains_and_remove_publicly_created` - -Like above, this is used to ensure that the message exists in the data tree and then consume it. However, it differs slightly since there is currently a difference between notes that have been inserted from public and private execution. This means that you currently must use this function to consume and nullify a note that was created in a public function. This will be fixed in the future. - -#include_code assert_contains_and_remove_publicly_created /yarn-project/aztec-nr/aztec/src/state_vars/set.nr rust - -While this might look intimidating, the use of the function is rather easy, and is used in the following way: - -#include_code assert_contains_and_remove_publicly_created /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust - -The reason we are not reading this note ahead of time is that no [encrypted log](./events.md#encrypted-events) was emitted for this note, since it was created in public thereby making the encrypted log useless (everyone saw the content ahead of time). - ### `remove` Will remove a note from the set if it previously has been read from storage, e.g. you have fetched it through a `get_notes` call. This is useful when you want to remove a note that you have previously read from storage and do not have to read it again. If you recall from earlier, we are emitting a nullifier when reading values to make sure that they are up to date. From b665fb68e76ec5ef2de1787c0dae3cdeaf53fd1a Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Sun, 22 Oct 2023 13:16:03 +0100 Subject: [PATCH 12/33] small restructure --- .../communication/cross_chain_calls.md | 4 +- docs/docs/dev_docs/aztecjs/main.md | 65 ++++++++ docs/docs/dev_docs/cli/cli-commands.md | 96 ++++++++++++ docs/docs/dev_docs/cli/main.md | 145 +++--------------- docs/docs/dev_docs/cli/sandbox-reference.md | 96 ++++++++++++ .../{getting_started => cli}/updating.md | 17 +- ...{sandbox.md => aztecjs-getting-started.md} | 96 +++--------- .../aztecnr-getting-started.md | 10 ++ docs/docs/dev_docs/getting_started/main.md | 8 + .../dev_docs/getting_started/quickstart.md | 80 ++-------- docs/sidebars.js | 63 +++++--- 11 files changed, 387 insertions(+), 293 deletions(-) create mode 100644 docs/docs/dev_docs/aztecjs/main.md create mode 100644 docs/docs/dev_docs/cli/cli-commands.md create mode 100644 docs/docs/dev_docs/cli/sandbox-reference.md rename docs/docs/dev_docs/{getting_started => cli}/updating.md (97%) rename docs/docs/dev_docs/getting_started/{sandbox.md => aztecjs-getting-started.md} (81%) create mode 100644 docs/docs/dev_docs/getting_started/aztecnr-getting-started.md diff --git a/docs/docs/concepts/foundation/communication/cross_chain_calls.md b/docs/docs/concepts/foundation/communication/cross_chain_calls.md index f05bba66484..34dd8bf5418 100644 --- a/docs/docs/concepts/foundation/communication/cross_chain_calls.md +++ b/docs/docs/concepts/foundation/communication/cross_chain_calls.md @@ -10,11 +10,11 @@ import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; In Aztec, what we call _portals_ are the key element in facilitating communication between L1 and L2. While typical L2 solutions rely on synchronous communication with L1, Aztec's privacy-first nature means this is not possible. You can learn more about why in the previous section. -Traditional L1<>L2 communication might involve direct calls between L2 nd L1 contracts. However, in Aztec, due to the privacy components and the way transactions are processed (kernel proofs built on historical data), direct calls between L1 and L2 would not be possible if we want to maintain privacy. +Traditional L1<-->L2 communication might involve direct calls between L2 nd L1 contracts. However, in Aztec, due to the privacy components and the way transactions are processed (kernel proofs built on historical data), direct calls between L1 and L2 would not be possible if we want to maintain privacy. Portals are the solution to this problem, acting as bridges for communication between the two layers. These portals can transmit messages from public functions in L1 to private functions in L2 and vice versa, thus enabling messaging while maintaining privacy. -This page covers: +This page covers - How portals enable privacy communication between L1 and L2 - How messages are sent, received, and processed diff --git a/docs/docs/dev_docs/aztecjs/main.md b/docs/docs/dev_docs/aztecjs/main.md new file mode 100644 index 00000000000..b3e98d0d1da --- /dev/null +++ b/docs/docs/dev_docs/aztecjs/main.md @@ -0,0 +1,65 @@ +--- +title: Aztec.js +--- + +If you are looking for the API reference, go [here](../../apis/aztec-js/index.md). + +## Introduction + +Aztec.js is a library that provides APIs for managing accounts and interacting with contracts on the Aztec network. It communicates with the [Private eXecution Environment (PXE)](https://docs.aztec.network/apis/pxe/interfaces/PXE) through a `PXE` implementation, allowing developers to easily register new accounts, deploy contracts, view functions, and send transactions. + +## Usage + +### Create a new account + +```typescript +import { getSchnorrAccount } from "@aztec/aztec.js"; +import { GrumpkinPrivateKey } from "@aztec/types"; + +const encryptionPrivateKey = GrumpkinPrivateKey.random(); +const signingPrivateKey = GrumpkinPrivateKey.random(); +const wallet = getSchnorrAccount( + pxe, + encryptionPrivateKey, + signingPrivateKey +).waitDeploy(); +console.log(`New account deployed at ${wallet.getAddress()}`); +``` + +### Deploy a contract + +```typescript +import { Contract } from "@aztec/aztec.js"; + +const contract = await Contract.deploy(wallet, MyContractArtifact, [ + ...constructorArgs, +]) + .send() + .deployed(); +console.log(`Contract deployed at ${contract.address}`); +``` + +### Send a transaction + +```typescript +import { Contract } from "@aztec/aztec.js"; + +const contract = await Contract.at(contractAddress, MyContractArtifact, wallet); +const tx = await contract.methods + .transfer(amount, recipientAddress) + .send() + .wait(); +console.log( + `Transferred ${amount} to ${recipientAddress} on block ${tx.blockNumber}` +); +``` + +### Call a view function + +```typescript +import { Contract } from "@aztec/aztec.js"; + +const contract = await Contract.at(contractAddress, MyContractArtifact, wallet); +const balance = await contract.methods.getBalance(wallet.getAddress()).view(); +console.log(`Account balance is ${balance}`); +``` diff --git a/docs/docs/dev_docs/cli/cli-commands.md b/docs/docs/dev_docs/cli/cli-commands.md new file mode 100644 index 00000000000..31de52e6bcd --- /dev/null +++ b/docs/docs/dev_docs/cli/cli-commands.md @@ -0,0 +1,96 @@ +--- +title: CLI Commands +--- + +Here you will find a reference to the commands available in the Aztec CLI. + +## Installation + +This command will install the Aztec CLI. + +```bash +npm install -g @aztec/cli +``` + +## Creating Accounts + +The first thing we want to do is create a couple of accounts. We will use the `create-account` command which will generate a new private key for us, register the account on the sandbox, and deploy a simple account contract which [uses a single key for privacy and authentication](../../concepts/foundation/accounts/keys.md): + +#include_code create-account yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +Once the account is set up, the CLI returns the resulting address, its privacy key, and partial address. You can read more about these [here](../../concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys). + +Save the Address and Private key as environment variables. We will be using them later. + +```bash +export ADDRESS=

+export PRIVATE_KEY= +``` + +Alternatively, we can also manually generate a private key and use it for creating the account, either via a `-k` option or by setting the `PRIVATE_KEY` environment variable. + +#include_code create-account-from-private-key yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +For all commands that require a user's private key, the CLI will look for the `PRIVATE_KEY` environment variable in absence of an optional argument. + +Let's double check that the accounts have been registered with the sandbox using the `get-accounts` command: + +#include_code get-accounts yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +You will see a that a number of accounts exist that we did not create. The Sandbox initializes itself with 3 default accounts. Save one of the printed accounts (not the one that you generated above) in an environment variable. We will use it later. + +```bash +export ADDRESS2= +``` + +## Deploying a Token Contract + +We will now deploy a token contract using the `deploy` command, and set an address of the admin via a constructor argument. +Make sure to replace this address with one of the two you created earlier. + +#include_code deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +Save the contract address as an environment variable. We will use it later. + +```bash +export CONTRACT_ADDRESS= +``` + +- `--args` - Arguments to the constructor of the contract. In this case we have set an address as admin. + +The CLI tells us that the contract was successfully deployed. We can use the `check-deploy` command to verify that a contract has been successfully deployed to that address: + +#include_code check-deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +## Sending a Transaction + +We can now send a transaction to the network. We will mint funds in the public domain. +To form and submit the transaction we will use the `send` command of `aztec-cli`. +The `send` command expect the function name as the first unnamed argument and the following named arguments: + +- `--args` - The list of arguments to the function call. +- `--contract-artifact` - The artifact of the contract to call. +- `--contract-address` - The deployed address of the contract to call. +- `--private-key` - The private key of the sender. + +#include_code send yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +We called the `mint_public` function and provided it with the 2 arguments it expects: the recipient's address and the amount to be minted. Make sure to replace all addresses in this command with yours. + +The command output tells us the details of the transaction such as its hash and status. We can use this hash to query the receipt of the transaction at a later time: + +#include_code get-tx-receipt yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +## Calling an Unconstrained (View) Function + +Now that the `mint_public` tx has been settled we can call the `balance_of_public` unconstrained function: + +#include_code call yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +The `call` command calls a read-only method on a contract, one that will not generate a transaction to be sent to the network. The arguments here are: + +- `--args` - The address for which we want to retrieve the balance. +- `--contract-artifact` - The artifact of the contract we are calling. +- `--contract-address` - The address of the deployed contract + +As you can see from the result, this address has a public balance of 543, as expected. diff --git a/docs/docs/dev_docs/cli/main.md b/docs/docs/dev_docs/cli/main.md index d74ff15b1cd..2c3a881eef8 100644 --- a/docs/docs/dev_docs/cli/main.md +++ b/docs/docs/dev_docs/cli/main.md @@ -1,138 +1,39 @@ --- -title: Aztec CLI +title: Sandbox and CLI --- -## Introduction +The Aztec Sandbox is an environment for local development on the Aztec Network. It's easy to get setup with just a single, simple command, and contains all the components needed to develop and test Aztec contracts and applications. The Aztec CLI will allow you to interact with the sandbox. -The Aztec CLI is a command-line tool allowing the user to interact directly with the Aztec Network. +## Components of the Aztec network -It aims to provide all of the functionality required to deploy and invoke contracts and query system state such as contract data, transactions and emitted logs. - -## Requirements - -You should have [node.js](https://nodejs.org/en/download) installed with version >= 18. - -To install the Aztec CLI run: - -```bash -npm install -g @aztec/cli -``` - -Or if you use yarn: - -```bash -yarn global add @aztec/cli -``` - -Then verify that it is installed with: - -```bash -aztec-cli -h -``` - -Once installed it is invoked via: - -`aztec-cli [options] [command]` - -## I have the Sandbox running, now what? - -Lets first establish that we are able to communicate with the Sandbox. Most commands will require the url to the Sandbox, which defaults in the CLI to `http://localhost:8080`. You can override this as an option with each command or by setting `PXE_URL` environment variable. - -To test communication with the Sandbox, let's run the command: - -#include_code block-number yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash - -You should see the current block number (1) printed to the screen! - -## Contracts - -We have shipped a number of example contracts in the `@aztec/noir-contracts` npm package. This is included with the cli by default so you are able to use these contracts to test with. To get a list of the names of the contracts run: - -#include_code example-contracts yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash - -You can see all of our example contracts in the monorepo [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/src/contracts). - -In the following sections there will be commands that require contracts as options. You can either specify the full directory path to the contract artifact, or you can use the name of one of these examples as the option value. This will become clearer later on. - -## Creating Accounts - -The first thing we want to do is create a couple of accounts. We will use the `create-account` command which will generate a new private key for us, register the account on the sandbox, and deploy a simple account contract which [uses a single key for privacy and authentication](../../concepts/foundation/accounts/keys.md): +Aztec's Layer 2 network is a fully programmable combined private/public ZK rollup. To achieve this, the network contains the following primary components: -#include_code create-account yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +- Aztec Node - Aggregates all of the 'backend' services necessary for the building and publishing of rollups. This packages is currently in development and much of the functionality is mocked. +- [Private Execution Environment (PXE)](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/pxe) - Normally residing with the end client, this decrypts and stores a client's private state, executes simulations and submits transactions to the Aztec Node. +- [Aztec.js](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec.js) - Aztec's client library for interacting with the PXE (think Ethers.js). See the getting started guide [here](../getting_started/aztecjs-getting-started.md). -Once the account is set up, the CLI returns the resulting address, its privacy key, and partial address. You can read more about these [here](../../concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys). +All of this is included in the Sandbox, with the exception of Aztec.js which you can use to interact with it. -Save the Address and Private key as environment variables. We will be using them later. +With the help of Aztec.js you will be able to: -```bash -export ADDRESS=
-export PRIVATE_KEY= -``` +- Create an account +- Deploy a contract +- Call view methods on contracts +- Simulate the calling of contract functions +- Send transactions to the network +- Be notified when transactions settle +- Query chain state such as chain id, block number etc. -Alternatively, we can also manually generate a private key and use it for creating the account, either via a `-k` option or by setting the `PRIVATE_KEY` environment variable. +## What's in the Sandbox? -#include_code create-account-from-private-key yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +The sandbox contains a local Ethereum instance running [Anvil](https://book.getfoundry.sh/anvil/), a local instance of the Aztec rollup, an aztec private execution client for handling user transactions and state, and, if using Docker, an [Otterscan](https://github.com/otterscan/otterscan) block explorer for the local Ethereum network. -For all commands that require a user's private key, the CLI will look for the `PRIVATE_KEY` environment variable in absence of an optional argument. +These provide a self contained environment which deploys Aztec on a local (empty) Ethereum network, creates 3 smart contract wallet accounts on the rollup, and allows transactions to be processed on the local Aztec sequencer. -Let's double check that the accounts have been registered with the sandbox using the `get-accounts` command: +The current sandbox does not generate or verify proofs, but provides a working end to end developer flow for writing and interacting with Aztec.nr smart contracts. -#include_code get-accounts yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +## Aztec CLI -You will see a that a number of accounts exist that we did not create. The Sandbox initializes itself with 3 default accounts. Save one of the printed accounts (not the one that you generated above) in an environment variable. We will use it later. +The Aztec CLI is a command-line tool allowing the user to interact directly with the Aztec network and sandbox. -```bash -export ADDRESS2= -``` - -## Deploying a Token Contract - -We will now deploy a token contract using the `deploy` command, and set an address of the admin via a constructor argument. -Make sure to replace this address with one of the two you created earlier. - -#include_code deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash - -Save the contract address as an environment variable. We will use it later. - -```bash -export CONTRACT_ADDRESS= -``` - -- `--args` - Arguments to the constructor of the contract. In this case we have set an address as admin. - -The CLI tells us that the contract was successfully deployed. We can use the `check-deploy` command to verify that a contract has been successfully deployed to that address: - -#include_code check-deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash - -## Sending a Transaction - -We can now send a transaction to the network. We will mint funds in the public domain. -To form and submit the transaction we will use the `send` command of `aztec-cli`. -The `send` command expect the function name as the first unnamed argument and the following named arguments: - -- `--args` - The list of arguments to the function call. -- `--contract-artifact` - The artifact of the contract to call. -- `--contract-address` - The deployed address of the contract to call. -- `--private-key` - The private key of the sender. - -#include_code send yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash - -We called the `mint_public` function and provided it with the 2 arguments it expects: the recipient's address and the amount to be minted. Make sure to replace all addresses in this command with yours. - -The command output tells us the details of the transaction such as its hash and status. We can use this hash to query the receipt of the transaction at a later time: - -#include_code get-tx-receipt yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash - -## Calling an Unconstrained (View) Function - -Now that the `mint_public` tx has been settled we can call the `balance_of_public` unconstrained function: - -#include_code call yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash - -The `call` command calls a read-only method on a contract, one that will not generate a transaction to be sent to the network. The arguments here are: - -- `--args` - The address for which we want to retrieve the balance. -- `--contract-artifact` - The artifact of the contract we are calling. -- `--contract-address` - The address of the deployed contract - -As you can see from the result, this address has a public balance of 543, as expected. \ No newline at end of file +It aims to provide all of the functionality required to deploy and invoke contracts and query system state such as contract data, transactions and emitted logs. diff --git a/docs/docs/dev_docs/cli/sandbox-reference.md b/docs/docs/dev_docs/cli/sandbox-reference.md new file mode 100644 index 00000000000..f39ff74f2e8 --- /dev/null +++ b/docs/docs/dev_docs/cli/sandbox-reference.md @@ -0,0 +1,96 @@ +--- +title: Sandbox Reference +--- + +Here you will find a reference to everything available within the Sandbox. + +## Installation + +You can run the Sandbox using either Docker or npm. + +### With Docker + +```bash +/bin/bash -c "$(curl -fsSL 'https://sandbox.aztec.network')" +``` + +This will attempt to run the Sandbox on ` localhost:8080`. You can change the port defined in `./.aztec/docker-compose.yml`. Running the command again will overwrite any changes made to the `docker-compose.yml`. + +To install a specific version of the sandbox, you can set the environment variable `SANDBOX_VERSION` + +```bash +SANDBOX_VERSION= /bin/bash -c "$(curl -fsSL 'https://sandbox.aztec.network')" +``` + +NOTE: The sandbox version should be the same as your `@aztec/cli` package to ensure compatibility. + +### With npm + +You can download and run the Sandbox package directly if you have nodejs 18 or higher installed. + +You will also need an Ethereum node like Anvil or Hardhat running locally on port 8545. + +```bash +npx @aztec/aztec-sandbox +``` + +## Running + +The installation command will run the sandbox, and once installed you can run like so: + +```bash +cd ~/.aztec && docker-compose up +``` + +## Otterscan + +If you have set up the Sandbox with Docker, you will also have Ottescan. + +You can see Ethereum Layer 1 activity through the local Otterscan on [`http://localhost:5100`](`http://localhost:5100`). This is especially useful for dapps that use L1-L2 messaging through [portal contracts](../contracts/portals/main.md). + +## Cheat Codes + +To help with testing, the sandbox is shipped with a set of cheatcodes. + +Cheatcodes allow you to change the time of the Aztec block, load certain state or more easily manipulate Ethereum instead of having to write dedicated RPC calls to anvil or hardhat. + +You can find the cheat code reference [here](../testing/cheat_codes.md). + +## Contracts + +We have shipped a number of example contracts in the `@aztec/noir-contracts` npm package. This is included with the cli by default so you are able to use these contracts to test with. To get a list of the names of the contracts run: + +```bash title="example-contracts" showLineNumbers +% aztec-cli example-contracts +BenchmarkingContractArtifact +CardGameContractArtifact +ChildContractArtifact +DocsExampleContractArtifact +EasyPrivateTokenContractArtifact +EcdsaAccountContractArtifact +EscrowContractArtifact +ImportTestContractArtifact +LendingContractArtifact +ParentContractArtifact +PendingCommitmentsContractArtifact +PokeableTokenContractArtifact +PriceFeedContractArtifact +SchnorrAccountContractArtifact +SchnorrHardcodedAccountContractArtifact +SchnorrSingleKeyAccountContractArtifact +StatefulTestContractArtifact +TestContractArtifact +TokenBridgeContractArtifact +TokenContractArtifact +UniswapContractArtifact +``` + +> Source code: /yarn-project/end-to-end/src/cli_docs_sandbox.test.ts#L95-L118 + +You can see all of our example contracts in the monorepo [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/src/contracts). + +## Boxes + +The sandbox is shipped with full-stack Aztec project templates, with example Aztec.nr contracts, testing scripts, and web interfaces. + +You can read more information about how to use boxes [here](TODO) diff --git a/docs/docs/dev_docs/getting_started/updating.md b/docs/docs/dev_docs/cli/updating.md similarity index 97% rename from docs/docs/dev_docs/getting_started/updating.md rename to docs/docs/dev_docs/cli/updating.md index cb0662ca63c..4d5291b3c3f 100644 --- a/docs/docs/dev_docs/getting_started/updating.md +++ b/docs/docs/dev_docs/cli/updating.md @@ -1,8 +1,9 @@ --- -title: Updating +title: Staying Updated --- There are 4 components whose versions need to be kept compatible: + 1. Aztec Sandbox, 2. Aztec CLI, 3. Noir compiler `nargo`, @@ -12,7 +13,9 @@ Aztec Sandbox, Aztec CLI and `aztec.nr` are using the same versioning scheme and The Noir compiler `nargo` has its own versioning scheme and its version must match the compatible nargo version specified in Sandbox. ## Updating Aztec Sandbox + To update the sandbox to the latest version, simply run the curl command we used for installation again: + ```shell /bin/bash -c "$(curl -fsSL 'https://sandbox.aztec.network')" ``` @@ -23,6 +26,7 @@ If you would like to use a fixed version of the sandbox, you can export the `SAN If you are unsure what version to use go to [aztec-packages repository](https://github.com/AztecProtocol/aztec-packages/releases) and choose the `aztec-packages` release based on the changelog. Then set the `SANDBOX_VERSION` environmental variable to the version you want to use. E.g.: + ```shell export SANDBOX_VERSION=#include_aztec_short_version ``` @@ -30,6 +34,7 @@ export SANDBOX_VERSION=#include_aztec_short_version Now when you run the curl command it will use the version you specified. To verify that it's the case check the console output of the curl command. You should see the following line: + ``` Setting up Aztec Sandbox v#include_aztec_short_version (nargo #include_noir_version), please stand by... ``` @@ -41,32 +46,39 @@ Alternatively you can open a new terminal and use aztec-cli to get the version. The sandbox version should be the same as the one we chose by setting the `SANDBOX_VERSION` environmental variable. ## Updating Aztec CLI + If the latest version was used when updating the sandbox then we can simply run the following command to update the CLI: + ```shell npm install -g @aztec/cli ``` If a specific version was set for the sandbox then we need to install the CLI with the same version: + ```shell npm install -g @aztec/cli@$SANDBOX_VERSION ``` E.g.: + ```shell npm install -g @aztec/cli@#include_aztec_short_version ``` ## Updating Noir compiler + Now we need to update the Noir compiler `nargo` to the version compatible with the sandbox. Use `aztec-cli` to get it: #include_code node-info yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash Then we install the `Compatible Nargo Version` with (replace `COMPATIBLE_NARGO_VERSION` with the version from the previous command): + ```shell noirup -v COMPATIBLE_NARGO_VERSION ``` ## Updating Noir framework + Finally we need to update the Noir framework for Aztec contracts. We need to install a version compatible with our `nargo` and Sandbox. @@ -82,7 +94,8 @@ E.g.: +value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="#include_aztec_version", directory="yarn-project/aztec-nr/value-note" } ``` -Go to the project directory and try compiling it with `aztec-cli`` to verify that the update was successful: +Go to the project directory and try compiling it with `aztec-cli` to verify that the update was successful: + ```shell cd /your/project/root aztec-cli compile ./ diff --git a/docs/docs/dev_docs/getting_started/sandbox.md b/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md similarity index 81% rename from docs/docs/dev_docs/getting_started/sandbox.md rename to docs/docs/dev_docs/getting_started/aztecjs-getting-started.md index 43acfa7f924..e6b49ec582b 100644 --- a/docs/docs/dev_docs/getting_started/sandbox.md +++ b/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md @@ -1,78 +1,28 @@ --- -title: Aztec Sandbox +title: Getting Started with Aztec.js --- import Image from "@theme/IdealImage"; -## Introduction +In this guide, we will retrieving the Sandbox and deploy a pre-written contract to it using Aztec.js. -The Aztec Sandbox aims to provide a local development system against which you can build and test Aztec.nr contracts in a fast, safe, and free environment. - -:::info -For a quickstart checkout [the Quickstart section](./quickstart.md) -::: - -Here we will walkthrough the process of retrieving the Sandbox, installing the client libraries and using it to deploy and use a fully token contract on the Aztec network using Aztec.js. - -You can find the [complete tutorial code here](https://github.com/AztecProtocol/dev-rel/tree/main/tutorials/sandbox-tutorial/token). +This guide assumes you have followed the [quickstart](./quickstart.md). ## Prerequisites -- Node.js >= v18 -- Docker and Docker Compose (Docker Desktop under WSL2 on windows) - -That's it... - -## Install the Sandbox - -In your terminal: - -```sh -/bin/bash -c "$(curl -fsSL 'https://sandbox.aztec.network')" -``` - -It will download and execute a script invoking docker compose with 2 containers: - -- Anvil -- Aztec Sandbox - -3 ports will need to be opened on your system in order for you to interact with the sandbox. -The first port is for Anvil, it defaults to 8545 and can be overridden by specifying a value in the environment variable `SANDBOX_ANVIL_PORT`. -The second one is sandbox Aztec Node port, it defaults to 8079 and can be overridden by specifying a value in the environment variable `SANDBOX_AZTEC_NODE_PORT`. -The third is the sandbox PXE port. -It defaults to value 8080 but can be overridden with environment variable `SANDBOX_PXE_PORT`. - -Within a few seconds the Sandbox should be up and running! - - - -:::info -To start anvil in a fork mode set `FORK_URL` and `FORK_BLOCK_NUMBER` environment variables before running the script. -You can do so by running: -```sh -export FORK_URL=https://mainnet.infura.io/v3/your-infura-key -export FORK_BLOCK_NUMBER=13300000 -``` -If `FORK_BLOCK_NUMBER` is not set, it defaults to genesis block number. -::: +- A running [Aztec sandbox](./quickstart.md) ## Project setup We will deploy a pre-compiled token contract, and send tokens privately, using the Sandbox. :::info -If you don't want to follow along and copy pasting step-by-step, the full code repository is available [here](https://github.com/AztecProtocol/dev-rel/tree/main/tutorials/sandbox-tutorial/token) +Find the full code [here](https://github.com/AztecProtocol/dev-rel/tree/main/tutorials/sandbox-tutorial/token) ::: -We will create a `yarn` project called `token` (although npm works fine too). If you are familiar with setting up Javascript/Typescript projects then you can skip to step 6. - -1. Ensure node version is 18 or higher by running +We will create a `yarn` project called `token` (although `npm` works fine too). -```sh -node -v -``` - -2. Initialize a yarn project +1. Initialize a yarn project ```sh mkdir token @@ -80,19 +30,19 @@ cd token yarn init -yp ``` -3. Create a `src` folder inside your new `token` directory: +2. Create a `src` folder inside your new `token` directory: ```sh mkdir src ``` -4. Add necessary yarn packages (and optionally add typescript too) +3. Add necessary yarn packages (and optionally add typescript too) ```sh yarn add @aztec/aztec.js @aztec/noir-contracts typescript @types/node ``` -5. [Optional] If creating a typescript file, add a `tsconfig.json` file into the project root, here is an example: +4. [Optional] If creating a typescript file, add a `tsconfig.json` file into the project root, here is an example: ```json { @@ -120,7 +70,7 @@ yarn add @aztec/aztec.js @aztec/noir-contracts typescript @types/node } ``` -6. Update `package.json` - Add a `scripts` section to `package.json` and set `"type": "module"`: +5. Update `package.json` - Add a `scripts` section to `package.json` and set `"type": "module"`: ```json { @@ -146,7 +96,7 @@ yarn add @aztec/aztec.js @aztec/noir-contracts typescript @types/node } ``` -7. Create an `index.ts` file in the `src` directory with the following sandbox connection setup: +6. Create an `index.ts` file in the `src` directory with the following sandbox connection setup: ```ts #include_code imports /yarn-project/end-to-end/src/e2e_sandbox_example.test.ts raw @@ -158,7 +108,7 @@ async function main() { main(); ``` -8. Finally, run the package: +7. Finally, run the package: In the project root, run @@ -166,7 +116,7 @@ In the project root, run yarn start ``` -A successful run should show: +A successful run should show something like this: ``` token Aztec Sandbox Info { @@ -217,7 +167,7 @@ Now that we have our accounts loaded, let's move on to deploy our pre-compiled t #include_code Deployment /yarn-project/end-to-end/src/e2e_sandbox_example.test.ts typescript -`yarn start` will now give the following output: +`yarn start` will now give something like this: ``` token Aztec Sandbox Info { @@ -397,7 +347,7 @@ This function takes: 1. A quantity of tokens to be minted. 2. A secret hash. -Here is the Noir code: +Here is the Aztec.nr code: #include_code mint_private /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust @@ -414,7 +364,7 @@ Let's now use these functions to mint some tokens to Bob's account using Typescr #include_code Mint /yarn-project/end-to-end/src/e2e_sandbox_example.test.ts typescript -Our complete output should now be: +Our complete output should now be something like: ``` token Aztec Sandbox Info { @@ -459,16 +409,8 @@ Our complete output should now be: token Bob's balance 10543 +43ms ``` -That's it! We have successfully deployed a token contract to an instance of the Aztec network and mined private state-transitioning transactions. We have also queried the resulting state all via the interfaces provided by the contract. - -You can find the [complete tutorial code here](https://github.com/AztecProtocol/dev-rel/tree/main/tutorials/sandbox-tutorial/token). - -### Diagram of sending a transaction - -Sending a transaction +That's it! We have successfully deployed a token contract to an instance of the Aztec network and mined private state-transitioning transactions. We have also queried the resulting state all via the interfaces provided by the contract. To see exactly what has happened here, you can learn about the transaction flow [here](../../concepts/foundation/transactions.md). ## Next Steps -Here we showed how to interact with the sandbox, but didn't go into details on how to write your own contract or any relevant setup needed for it. - -You can find more information about writing Aztec contracts [here](../contracts/main.md) on syntax, compiling, deploying and interacting with how to start writing contracts. +Learn more about writing Aztec.nr contracts in the [Aztec.nr getting started guide](./aztecnr-getting-started.md). diff --git a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md b/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md new file mode 100644 index 00000000000..6e25cfffa68 --- /dev/null +++ b/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md @@ -0,0 +1,10 @@ +--- +title: Getting Started with Aztec.nr +--- + + diff --git a/docs/docs/dev_docs/getting_started/main.md b/docs/docs/dev_docs/getting_started/main.md index 20ef05de9d5..cfa7fa20c2e 100644 --- a/docs/docs/dev_docs/getting_started/main.md +++ b/docs/docs/dev_docs/getting_started/main.md @@ -2,6 +2,14 @@ title: Getting Started --- +In this section, you will + +1. Set up the Aztec sandbox and deploy a sample first contract with the CLI +2. Deploy and interact with a contract using Aztec.js +3. Write your first smart contract in Aztec.nr + +The whole section should take you less than 60 minutes. + import DocCardList from '@theme/DocCardList'; diff --git a/docs/docs/dev_docs/getting_started/quickstart.md b/docs/docs/dev_docs/getting_started/quickstart.md index b31f4cccd18..1bc7649e197 100644 --- a/docs/docs/dev_docs/getting_started/quickstart.md +++ b/docs/docs/dev_docs/getting_started/quickstart.md @@ -2,43 +2,14 @@ title: Quickstart --- -Get started with the Aztec Sandbox. +In this guide, you will -## Introduction +1. Set up the Aztec sandbox locally +2. Install the Aztec CLI +3. Use the CLI to deploy an example contract that comes with the sandbox +4. Use the CLI to interact with the contract you just deployed -The Aztec Sandbox is an environment for local development on the Aztec Network. It's easy to get setup with just a single, simple command, and contains all the components needed to develop and test Aztec contracts and applications. - -This is a 1 page introduction to getting started with running the sandbox, and interacting with it via the CLI. We will go over how to deploy a token contract to the sandbox, mint tokens and transfer them between accounts. You will find more in depth information on the following pages in this Getting Started section. - -### Background - -Aztec's Layer 2 network is a fully programmable combined private/public ZK rollup. To achieve this, the network contains the following primary components: - -- Aztec Node - Aggregates all of the 'backend' services necessary for the building and publishing of rollups. This packages is currently in development and much of the functionality is mocked. -- [Private Execution Environment (PXE)](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/pxe) - Normally residing with the end client, this decrypts and stores a client's private state, executes simulations and submits transactions to the Aztec Node. -- [Aztec.js](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec.js) - Aztec's client library for interacting with the PXE (think Ethers.js). See the getting started guide [here](./sandbox.md). - -All of this is included in the Sandbox, with the exception of Aztec.js which you can use to interact with it. - -With the help of Aztec.js you will be able to: - -- Create an account -- Deploy a contract -- Call view methods on contracts -- Simulate the calling of contract functions -- Send transactions to the network -- Be notified when transactions settle -- Query chain state such as chain id, block number etc. - -This quickstart walks you through installing the Sandbox, deploying your first Noir contract, and verifying its execution! - -## Sandbox Contents - -The sandbox contains a local ethereum instance running [Anvil](https://book.getfoundry.sh/anvil/), a local instance of the Aztec rollup, an aztec private execution client for handling user transactions and state, and, if using Docker, an [Otterscan](https://github.com/otterscan/otterscan) block explorer for the local ethereum network. - -These provide a self contained environment which deploys Aztec on a local (empty) ethereum network, creates 3 smart contract wallet accounts on the rollup, and allows transactions to be processed on the local Aztec sequencer. - -The current sandbox does not generate or verify proofs, but provides a working end to end developer flow for writing and interacting with Aztec.nr smart contracts. +... in less than 10 minutes. ## Requirements @@ -47,41 +18,19 @@ The current sandbox does not generate or verify proofs, but provides a working e ## Sandbox Installation -You can run the Sandbox using either Docker or npm. - -### With Docker +You can run the Sandbox using either Docker or npm. In this guide we will use Docker, but you can learn more about alternative installation methods [here](../cli/sandbox-reference.md). -To install and start the Sandbox paste the line below in a macOS Terminal or Linux shell prompt. You will need to have Docker installed and running on your machine. +To install the latest Sandbox version, run: ```bash /bin/bash -c "$(curl -fsSL 'https://sandbox.aztec.network')" ``` -This will attempt to run the Sandbox on localhost:8080, so you will have to make sure nothing else is running on that port or change the port defined in `./.aztec/docker-compose.yml`. Running the command again will overwrite any changes made to the docker-compose.yml. - -To install a specific version of the sandbox, you can set the environment variable `SANDBOX_VERSION` - -```bash -SANDBOX_VERSION= /bin/bash -c "$(curl -fsSL 'https://sandbox.aztec.network')" -``` - -NOTE: If `SANDBOX_VERSION` is not defined, the script will pull the latest release of the sandbox. The sandbox version should be the same as your `@aztec/cli` package to ensure compatibility. - -Once docker is up, you can see ethereum layer 1 activity through the local [otterscan](http://localhost:5100). This is especially useful for dapps that use L1-L2 messaging through [portal contracts](../contracts/portals/main.md). - -### With npm - -You can download and run the Sandbox package directly if you have nodejs 18 or higher installed. - -You will also need an Ethereum node like Anvil or Hardhat running locally on port 8545. - -```bash -npx @aztec/aztec-sandbox -``` +This will attempt to run the Sandbox on ` localhost:8080`, so you will have to make sure nothing else is running on that port or change the port defined in `./.aztec/docker-compose.yml`. Running the command again will overwrite any changes made to the `docker-compose.yml`. ## CLI Installation -To interact with the sandbox now that it's running locally, install the [Aztec CLI](https://www.npmjs.com/package/@aztec/cli): +To interact with the Sandbox now that it's running locally, install the [Aztec CLI](https://www.npmjs.com/package/@aztec/cli): ```bash npm install -g @aztec/cli @@ -119,11 +68,8 @@ Alice and Bob should have 500 tokens. Congratulations! You are all set up with the Aztec sandbox! -## Great, but what can I do with it? +## What's next? -Aztec's Layer 2 network is a fully programmable combined private/public ZK rollup. To achieve this, the network contains the following primary components: +To start writing your first Aztec.nr smart contract, go to the [next page](aztecnr-getting-started.md). -- Aztec Node - Aggregates all of the 'backend' services necessary for the building and publishing of rollups. -- Private Execution Environment (PXE) - Normally residing with the end client, this decrypts and stores a client's private state, executes simulations and submits transactions to the Aztec Node. -- [Aztec.js](./sandbox) - Aztec's client library for interacting with the PXE (think Ethers.js). -- [Aztec.nr](../contracts/main.md) - Aztec's smart contract framework +You can also dig more into the sandbox and CLI [here](../cli/main.md). diff --git a/docs/sidebars.js b/docs/sidebars.js index 5603e6ca046..066536ff3c8 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -198,8 +198,8 @@ const sidebars = { }, items: [ "dev_docs/getting_started/quickstart", - "dev_docs/getting_started/sandbox", - "dev_docs/getting_started/updating", + "dev_docs/getting_started/aztecjs-getting-started", + "dev_docs/getting_started/aztecnr-getting-started", ], }, @@ -266,6 +266,19 @@ const sidebars = { ], }, + { + label: "Aztec Sandbox and CLI", + type: "category", + link: { + type: "doc", + id: "dev_docs/cli/main", + }, + items: [ + "dev_docs/cli/cli-commands", + "dev_docs/cli/sandbox-reference", + "dev_docs/cli/updating", + ], + }, { label: "Aztec.nr Contracts", type: "category", @@ -311,27 +324,27 @@ const sidebars = { }, "dev_docs/contracts/common_errors", { - label: "Resources", - type: "category", - items: [ - //"dev_docs/contracts/resources/style_guide", - { - label: "Common Patterns", - type: "category", - // link: { - // type: "doc", - // id: "dev_docs/contracts/resources/common_patterns/main", - // }, - items: [ + label: "Resources", + type: "category", + items: [ + //"dev_docs/contracts/resources/style_guide", + { + label: "Common Patterns", + type: "category", + // link: { + // type: "doc", + // id: "dev_docs/contracts/resources/common_patterns/main", + // }, + items: [ "dev_docs/contracts/resources/common_patterns/authwit", - // "dev_docs/contracts/resources/common_patterns/sending_tokens_to_user", - // "dev_docs/contracts/resources/common_patterns/sending_tokens_to_contract", - // "dev_docs/contracts/resources/common_patterns/access_control", - // "dev_docs/contracts/resources/common_patterns/interacting_with_l1", - ], - }, - ], - }, + // "dev_docs/contracts/resources/common_patterns/sending_tokens_to_user", + // "dev_docs/contracts/resources/common_patterns/sending_tokens_to_contract", + // "dev_docs/contracts/resources/common_patterns/access_control", + // "dev_docs/contracts/resources/common_patterns/interacting_with_l1", + ], + }, + ], + }, // { // label: "Security Considerations", // type: "category", @@ -350,7 +363,11 @@ const sidebars = { ], }, - "dev_docs/cli/main", + { + label: "Aztec.js", + type: "doc", + id: "dev_docs/aztecjs/main", + }, { label: "Testing", From 61d3477dc6cdd7e87042590dd7b76509b4271d46 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Sun, 22 Oct 2023 16:10:23 +0100 Subject: [PATCH 13/33] counter aztecnr getting started --- .../aztecjs-getting-started.md | 35 +- .../aztecnr-getting-started.md | 315 +++++++++++++++++- .../dev_docs/getting_started/quickstart.md | 10 +- 3 files changed, 323 insertions(+), 37 deletions(-) diff --git a/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md b/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md index e6b49ec582b..70b63594a9f 100644 --- a/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md +++ b/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md @@ -12,7 +12,7 @@ This guide assumes you have followed the [quickstart](./quickstart.md). - A running [Aztec sandbox](./quickstart.md) -## Project setup +## Set up the project We will deploy a pre-compiled token contract, and send tokens privately, using the Sandbox. @@ -149,7 +149,7 @@ A successful run should show something like this: Great! The Sandbox is running and we are able to interact with it. -## Accounts +## Load accounts The sandbox is preloaded with multiple accounts so you don't have to sit and create them. Let's load these accounts @@ -159,11 +159,9 @@ An explanation on accounts on Aztec can be found [here](../../concepts/foundatio If you want more accounts, you can find instructions in the [Account creation section](../wallets/creating_schnorr_accounts.md). -## Token Contract Deployment +## Deploy a contract -Writing a contract from scratch is beyond the scope of this page. Feel free to look at the [Token contract tutorial](../tutorials/writing_token_contract.md) or the section on aztec-noir contracts [here](../contracts/main.md) - -Now that we have our accounts loaded, let's move on to deploy our pre-compiled token contract. Add this to `index.ts` below the code you added earlier: +Now that we have our accounts loaded, let's move on to deploy our pre-compiled token smart contract. You can find the full code for the contract [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/src/contracts/token_contract/src). Add this to `index.ts` below the code you added earlier: #include_code Deployment /yarn-project/end-to-end/src/e2e_sandbox_example.test.ts typescript @@ -214,14 +212,10 @@ We can break this down as follows: 6. Alice mints 1,000,000 tokens to be claimed by herself in private. 7. Alice redeems the tokens privately. -## Viewing the balance of an account +## View the balance of an account A token contract wouldn't be very useful if you aren't able to query the balance of an account. As part of the deployment, tokens were minted to Alice. We can now call the contract's `balance_of_private()` function to retrieve the balances of the accounts. -Here is the `balance_of_private` code from the contract (do not to paste it into `index.ts`): - -#include_code balance_of_private /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust - Call the `balance_of_private` function using the following code (paste this): #include_code Balance /yarn-project/end-to-end/src/e2e_sandbox_example.test.ts typescript @@ -274,11 +268,11 @@ No transaction is submitted as a result but a user's state can be queried. We can see that each account has the expected balance of tokens. -### Diagram of calling an unconstrained (view) function +### Calling an unconstrained (view) function Unconstrained function call -## Creating and submitting transactions +## Create and submit a transaction Now lets transfer some funds from Alice to Bob by calling the `transfer` function on the contract. This function takes 4 arguments: @@ -287,10 +281,6 @@ Now lets transfer some funds from Alice to Bob by calling the `transfer` functio 3. The quantity of tokens to be transferred. 4. The nonce for the [authentication witness](../../concepts//foundation/accounts/main.md#authorizing-actions), or 0 if msg.sender equal sender. -Here is the Noir code for the `transfer` function (don't paste this into `index.ts`): - -#include_code transfer /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust - Here is the Typescript code to call the `transfer` function, add this to your `index.ts` at the bottom of the `main` function: #include_code Transfer /yarn-project/end-to-end/src/e2e_sandbox_example.test.ts typescript @@ -347,18 +337,9 @@ This function takes: 1. A quantity of tokens to be minted. 2. A secret hash. -Here is the Aztec.nr code: - -#include_code mint_private /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust - This function is public and it inserts a new note into the private data tree and increases the total token supply by the amount minted. -To make the note spendable the note has to be redeemed. -A user can do that by calling the `redeem_shield` function: - -#include_code redeem_shield /yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr rust - -Notice that this function is private and that it takes a secret as an input argument. +To make the note spendable the note has to be redeemed. A user can do that by calling the `redeem_shield` function. Let's now use these functions to mint some tokens to Bob's account using Typescript, add this to `index.ts`: diff --git a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md b/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md index 6e25cfffa68..4d8e2826105 100644 --- a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md +++ b/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md @@ -2,9 +2,314 @@ title: Getting Started with Aztec.nr --- - +If you already have some experience with Noir and want to build a cooler contract that utilizes both private and public state, you might want to check out the [token contract tutorial instead](../tutorials/writing_token_contract.md). + +## Prerequisites + +- You have followed the [quickstart](./quickstart.md) +- Running Aztec Sandbox + +## Install nargo + +`Aztec.nr` is a framework built on top of [Noir](https://noir-lang.org), a zero-knowledge DSL. Nargo is the build tool for Noir, similar to cargo for Rust. We need it for compiling our smart contracts. + + + +You can check it has been installed correctly by running: + +```bash +aztec-cli get-node-info +``` + +It should print something similar to: + +```bash +➜ ~ aztec-cli get-node-info + +Node Info: + +Version: 1 +Chain Id: 31337 +Rollup Address: 0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9 +Client: pxe@0.7.5 +Compatible Nargo Version: 0.16.0-aztec.0 +``` + +## Set up a project + +Create a new directory called `aztec-private-counter` + +```bash +mkdir aztec-private-counter +``` + +then create a `contracts` folder inside where our Aztec.nr contract will live: + +```bash +cd aztec-private-counter +mkdir contracts +``` + +Inside `contracts`, create a new Noir project using nargo: + +```bash +cd contracts +nargo new counter --contract +``` + +The `contract` flag will create a contract nargo project rather than using vanilla Noir. + +Your file structure should look like this: + +```bash +aztec-private-counter +|-contracts +| |--counter +| | |--src +| | | |--main.nr +| | |Nargo.toml +``` + +The file `main.nr` will soon turn into our smart contract! + +Your `Nargo.toml` file should look something like this: + +```toml +[package] +name = "counter" +type = "contract" +authors = [""] +compiler_version = "0.16.0" + +[dependencies] +``` + +Add the following dependencies under `[dependencies]`: + +```toml +aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="master", directory="yarn-project/noir-libs/aztec-noir" } +value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="master", directory="yarn-project/noir-libs/value-note"} +easy_private_state = { git="https://github.com/AztecProtocol/aztec-packages", tag="master", directory="yarn-project/noir-libs/easy-private-state"} +``` + +## Define the functions + +Go to `main.nr` and replace the code with this contract and functions: + +```rust +contract Counter { + #[aztec(private)] + fn constructor(initial_count: u120, owner: Field) {} + + #[aztec(private)] + fn increment(owner: Field) {} + + unconstrained fn getCounter(owner: Field) -> Field { + 0 + } +} +``` + +This code defines a contract called `Counter` with four functions that we will implement later - a `constructor` which is called when the contract is deployed, `increment`, and `getCounter`. + +We have annotated the functions with `#[aztec(private)]` which are ABI macros so the compiler understands it will handle private inputs. Learn more about functions and annotations [here](../contracts/syntax/functions.md). + +The `getCounter` function doesn’t need this as it will only be reading from the chain, not updating state, similar to a `view` function in Solidity. This is what `unconstrained` means. + +## Imports + +We need to define some imports. + +Write this within your contract at the top: + +```rust + use dep::aztec::{ + context::{PrivateContext, Context}, + note::{ + note_header::NoteHeader, + utils as note_utils, + }, + state_vars::map::Map, + }; + use dep::value_note::{ + balance_utils, + value_note::{ + ValueNoteMethods, + VALUE_NOTE_LEN, + }, + }; + use dep::easy_private_state::easy_private_state::EasyPrivateUint; +``` + +`context::{PrivateContext, Context}` + +Context gives us access to the environment information such as `msg.sender`. We are also importing `PrivateContext` to access necessary information for our private functions. We’ll be using it in the next step. + +`map::Map` + +Map is a private state variable that functions like a dictionary, relating Fields to other state variables. You can learn more about it [here](../contracts/syntax/). + +`value_note` + +Notes are fundamental to how Aztec manages privacy. A note is a privacy-preserving representation of an amount of tokens associated with an address, while encrypting the amount and owner. In this contract, we are using the `value_note` library. This is a type of note interface for storing a single Field, eg a balance - or, in our case, a counter. + +We are also using `balance_utils` from this import, a useful library that allows us to utilize value notes as if they are simple balances. + +`EasyPrivateUint` + +This allows us to store our counter in a way that acts as an integer, abstracting the note logic. + +## Implement a Storage struct + +In this step, we will initiate a `Storage` struct to store balances in a private way. The vast majority Aztec.nr smart contracts will need this. + +```rust +struct Storage { + counts: Map, + } +``` + +We are only storing one variable - `counts` as a `Map` of `EasyPrivateUint`. This means our `count` will act as a private integer, and we can map it to an address. + +```rust +impl Storage { + fn init(context: Context) -> pub Self { + Storage { + counters: Map::new( + context, + 1, + |context, slot| { + EasyPrivateUint::new(context, slot) + }, + ), + } + } + } +``` + +This `init` method is creating and initializing a `Storage` instance. This instance includes a `Map` named `counters`. Each entry in this `Map` represents an account's counter. + +## Keep the counter private + +Now we’ve got a mechanism for storing our private state, we can start using it to ensure the privacy of balances. + +Let’s create a `constructor` method to run on deployment that assigns an initial supply of tokens to a specified owner. In the constructor we created in the first step, write this: + +```rust + #[aztec(private)] + fn constructor(initial_counter: u120, owner: Field) { + let counts = storage.counts; + counts.at(owner).add(headstart, owner); + } +``` + +This function accesses the counts from storage. Then it assigns the passed initial counter to the `owner`'s counter privately using `at().add()`. + +## Incrementing our counter + +Now let’s implement the `increment` functio we defined in the first step. + +```rust + #[aztec(private)] + fn increment(owner: Field) { + let couners = storage.counters; + counters.at(owner).add(1, owner); + } +``` + +The `increment` function works very similarly to the `constructor`, but instead directly adds 1 to the counter rather than passing in an initial count parameter. + +## Prevent double spending + +Because our counters are private, the network can't directly verify if a note was spent or not, which could lead to double-spending. To solve this, we use a nullifier - a unique identifier generated from each spent note and its owner. Although this isn't really an issue in this simple smart contract, Aztec requires a contract that has any private functions to include this function. + +Add a new function into your contract as shown below: + +```rust +unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + preimage: [Field; VALUE_NOTE_LEN], +) -> [Field; 4] { + let note_header = NoteHeader { contract_address, nonce, storage_slot }; + note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, preimage) +} +``` + +Here, we're computing both the note hash and the nullifier. The nullifier computation uses Aztec’s `compute_note_hash_and_nullifier` function, which takes details about the note's attributes eg contract address, nonce, storage slot, and preimage. + +## Getting a counter + +The last thing we need to implement is the function in order to retrieve a counter. In the `getCounter` we defined in the first step, write this: + +```rust +unconstrained fn get_counter(owner: Field) -> Field { + let counts = storage.counters; + balance_utils::get_balance(counters.at(owner).set) +} +``` + +This function is `unconstrained` which allows us to fetch data from storage without a transaction. We retrieve a reference to the `owner`'s `counter` from the `counters` Map. The `get_balance` function then operates on the owner's counter. This yields a private counter that only the private key owner can decrypt. + +## Test with the CLI + +Now we've written a simple Aztec.nr smart contract, it's time to ensure everything works by testing with the CLI. + +### Compile the smart contract + +In the root of the `nargo` project, run this: + +```bash +aztec-cli compile . +``` + +This will compile the smart contract and create a `target` folder with a `.json` artifact inside. + +### Deploy + +You can use the previously generated artificat to deploy the smart contract. Our constructor takes two arguments - `initial_counter` and `owner` so let's make sure to pass those in. + +`initial_counter` can be any uint. In this guide we'll pick 100, but you can pick anything. + +For the `owner` you can get the account addresses in your sandbox by running: + +```bash +aztec-cli get-accounts +``` + +This will return something like this: + +```bash + +``` + +Use one of these `address`es as the `owner`. You can either copy it or export. + +To deploy the counter contract, [ensure the sandbox is running](../cli/sandbox-reference.md) and run this in the root of your nargo project: + +```bash +aztec-cli deploy target/Counter.json --args 100 0x25048e8c1b7dea68053d597ac2d920637c99523651edfb123d0632da785970d0 +``` + +You can also test the functions by applying what you learned in the [quickstart](./quickstart.md). + +Congratulations, you have now written, compiled, and deployed your first Aztec.nr smart contract! + +## What's next? + +Now you can explore. + +**Interested in learning more about how Aztec works under the hood?** + +Understand the high level architecture [here](../../concepts/foundation/main.md). + +**Want to write more advanced smart contracts?** + +Follow the token contract tutorial [here](../tutorials/writing_token_contract.md). + +**Ready to dive into Aztec and Ethereum cross-chain communication?** + +Read the [Portals page](../../concepts/foundation/communication/cross_chain_calls.md) and learn how to practically implement portals in the [token bridge tutorial](../tutorials/token_portal/main.md). diff --git a/docs/docs/dev_docs/getting_started/quickstart.md b/docs/docs/dev_docs/getting_started/quickstart.md index 1bc7649e197..feaa1611c45 100644 --- a/docs/docs/dev_docs/getting_started/quickstart.md +++ b/docs/docs/dev_docs/getting_started/quickstart.md @@ -11,12 +11,12 @@ In this guide, you will ... in less than 10 minutes. -## Requirements +## Prerequisites - Node.js >= v18 (recommend installing with [nvm](https://github.com/nvm-sh/nvm)) - Docker and Docker Compose (Docker Desktop under WSL2 on windows) -## Sandbox Installation +## Install the Sandbox You can run the Sandbox using either Docker or npm. In this guide we will use Docker, but you can learn more about alternative installation methods [here](../cli/sandbox-reference.md). @@ -28,7 +28,7 @@ To install the latest Sandbox version, run: This will attempt to run the Sandbox on ` localhost:8080`, so you will have to make sure nothing else is running on that port or change the port defined in `./.aztec/docker-compose.yml`. Running the command again will overwrite any changes made to the `docker-compose.yml`. -## CLI Installation +## Install the CLI To interact with the Sandbox now that it's running locally, install the [Aztec CLI](https://www.npmjs.com/package/@aztec/cli): @@ -36,7 +36,7 @@ To interact with the Sandbox now that it's running locally, install the [Aztec C npm install -g @aztec/cli ``` -## Deploying a contract +## Deploy a contract using the CLI The sandbox is preloaded with multiple accounts. Let's assign them to shell variables. Run the following in your terminal, so we can refer to the accounts as $ALICE and $BOB from now on: @@ -52,7 +52,7 @@ Start by deploying a token contract. After it is deployed, we check that the dep Note that the deployed contract address is exported, so we can use it as `$CONTRACT` later on. -## Calling a contract +## Call a contract with the CLI Alice is set up as the contract admin and token minter in the `_initialize` function. Let's get Alice some private tokens. From 5ff640d0602ff0663db4531a21aa9515083a202e Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Sun, 22 Oct 2023 16:35:12 +0100 Subject: [PATCH 14/33] merge with master --- docs/docs/about_aztec/history/history.mdx | 57 +++++------- docs/docs/about_aztec/overview.mdx | 12 +-- .../roadmap/cryptography_roadmap.md | 23 ++--- .../roadmap/features_initial_ldt.md | 89 +++++++++++++++++-- docs/docs/about_aztec/roadmap/main.md | 11 +-- .../circuits/kernels/private_kernel.md | 4 +- docs/docs/concepts/advanced/circuits/main.md | 6 -- .../data_structures/indexed_merkle_tree.md | 17 ++-- .../advanced/data_structures/trees.md | 18 ++-- .../docs/concepts/foundation/accounts/main.md | 24 ++--- .../communication/cross_chain_calls.md | 13 +-- .../communication/public_private_calls.md | 9 +- docs/docs/concepts/foundation/contracts.md | 11 --- docs/docs/concepts/foundation/state_model.md | 12 --- docs/docs/concepts/foundation/transactions.md | 9 -- 15 files changed, 144 insertions(+), 171 deletions(-) diff --git a/docs/docs/about_aztec/history/history.mdx b/docs/docs/about_aztec/history/history.mdx index 605508013df..9bd9c2995a1 100644 --- a/docs/docs/about_aztec/history/history.mdx +++ b/docs/docs/about_aztec/history/history.mdx @@ -9,32 +9,27 @@ import Image from "@theme/IdealImage"; --- - ## Bitcoin The original blockchain. -**Programmability**: - -- None. +**Programmability**: +- None. - Transfer bitcoin only. -**Privacy**: - +**Privacy**: - None. --- ## Ethereum -**Programmability**: - +**Programmability**: - Turing complete smart contracts. -**Privacy**: - -- Originally: None. -- Now: +**Privacy**: +- Originally: None. +- Now: - some specific apps on L1 - some specific apps, deployed via L2, like zk.money and Aztec Connect. @@ -42,54 +37,46 @@ The original blockchain. ## ZCash -**Programmability**: - -- None. +**Programmability**: +- None. - Transfer ZCash only. -**Privacy**: - +**Privacy**: - Transfers of shielded zcash are private. --- ## zk.money -**Programmability**: - +**Programmability**: - Any custom ERC20 token (on Ethereum L1) can be deposited to L2, transferred within L2, and withdrawn from L2. -**Privacy**: - +**Privacy**: - Transfers of the ERC20 tokens within the L2 are private. --- ## Aztec Connect -**Programmability**: - -- The functionality of zk.money, plus: -- Tokens can be sent from the L2 shielded pool to many L1 DeFi contracts, and the resulting tokens can be re-shielded. This gives anonymity to L1 DeFi users. +**Programmability**: +- The functionality of zk.money, plus: +- Tokens can be sent from the L2 shielded pool to many L1 defi contracts, and the resulting tokens can be re-shielded. This gives privacy to L1 defi users. -**Privacy**: - -- Transfers of the ERC20 tokens within the L2 are private. -- User DeFi interactions are anonymous. +**Privacy**: +- Transfers of the ERC20 tokens within the L2 are private. +- User defi interactions are private. --- ## Aztec -**Programmability**: - +**Programmability**: - Fully programmable private smart contracts: - - Private functions which can edit general private state - - Cheap L2 public functions + - private functions which can edit general private state + - cheap L2 public functions - L1 (public) functions. -**Privacy**: - +**Privacy**: - Executing private functions grants: - Function privacy - Input privacy diff --git a/docs/docs/about_aztec/overview.mdx b/docs/docs/about_aztec/overview.mdx index dde9f2c1192..cb727d36732 100644 --- a/docs/docs/about_aztec/overview.mdx +++ b/docs/docs/about_aztec/overview.mdx @@ -4,21 +4,21 @@ title: Overview import ReactPlayer from "react-player/youtube"; -Aztec is an L2 that brings programmable privacy to Ethereum. +The next version of our rollup, Aztec, is a privacy-preserving, programmable extension to Ethereum. It is a layer 2 zk-rollup on Ethereum that enables programable privacy via composable smart contracts. ## Private Smart Contracts on Aztec A smart contract on Aztec is a collection of functions, written as ZK-SNARK circuits. These circuits can have different modes of execution: -1. Secret Functions -- can read and write private state, read historic public state, consume or send messages to / from Ethereum, and read Ethereum state. They can call other secret functions in the same contract, or other contracts, and can call public functions. -2. Public Functions -- can read and write public state, write private state, consume or send messages to / from Ethereum and read Ethereum state. They can call other public functions on the same or other contracts. -3. Portal Contracts -- these are contracts on Ethereum that can receive messages from Aztec or send messages to Aztec from Ethereum contracts. +1. Secret Functions -- can read and write private state, read historic public state, consume or send messages to / from L1, and read Ethereum state. Can call other secret functions in the same contract, or other contracts. They can call public functions. +2. Public Functions -- can read and write public state, write private state, consume or send messages to / from L1 and read Ethereum state. Can call other public functions on the same or other contracts. +3. Portal Contracts -- these are contracts on L1 that can receive messages from L2 or allow messages to be sent to L2 from L1 contracts. Using these different modes of execution, developers can build applications with user privacy, data privacy and code privacy. User privacy -- transactions may not reveal information about the sender or the recipient. -Data privacy -- transactions may not reveal information about the payload of the transaction, e.g., the asset or value being transacted. +Data privacy -- transactions may not reveal information about the payload of the transaction, e.g the asset or value being transacted. Code privacy -- transactions may not reveal the program logic. @@ -50,7 +50,7 @@ Contributors to Aztec uphold many of the values of the Ethereum community -- bui ## Noir -Noir is a domain specific programming language for writing zero-knowledge circuits. On Aztec a smart contract is a collection of circuits that developers write using Noir. +Noir is a domain specific programming language for writing zero knowledge circuits. On Aztec a smart contract is a collection of circuits that developers write using Noir. You can find more information and resources for learning about Noir smart contracts on [this page](../dev_docs/contracts/main.md). diff --git a/docs/docs/about_aztec/roadmap/cryptography_roadmap.md b/docs/docs/about_aztec/roadmap/cryptography_roadmap.md index f24537c1a0b..0cef1ff7e37 100644 --- a/docs/docs/about_aztec/roadmap/cryptography_roadmap.md +++ b/docs/docs/about_aztec/roadmap/cryptography_roadmap.md @@ -2,23 +2,26 @@ title: Cryptography Roadmap --- -The cryptography team is currently working on [Barretenberg here.](https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg) +The cryptography team is currently working on [Barretenberg here](https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg) ## R&D projects -Publish the Honk paper, describing practical considerations for constructing our cutting-edge proving system Honk along with formal proofs of its security properties. +- Publish the Honk paper, describing practical considerations for constructing our cutting-edge proving system Honk along with formal proofs of its security properties. ## Honk -Honk is a sumcheck-based zk-SNARK protocol with blazing-fast zk proof construction. We need Honk to allow users to prove correct execution of complicated, multi-step computations using recursion in a resource constraint environment like a cell phone. This is necessary for our mission, because we need to make sure our users' sensitive information never leaves their devices! +- Honk is a sumcheck-based zk-SNARK protocol with blazing-fast zk proof construction. We need Honk to allow users to prove correct execution of complicated, multi-step computations using recursion in a resource constraint environment like a cell phone. This is necessary for our mission, because we need to make sure our users' sensitive information never leaves their devices! +- List of Honk projects + - Completed: basic Honk prover and verifier with respectable construction and verification speeds, but no optimization. + - Upcoming: + - Bringing "Ultra" functionality to Honk: lookup tables, efficient range constraints, RAM, ROM, and more will result in orders-of-magnitude improvements to Honk's prover times. + - Recursion using cycles of curves will allow for efficient recursive verification of Honk proofs. Using this technique will lower the barrier to entry of our rollup providers, resulting in a more robust set of providers and greater security for the Aztec network. -List of Honk projects: +## Goblin projects -- Completed: basic Honk prover and verifier with respectable construction and verification speeds, but no optimization. -- Upcoming: - - Bringing "Ultra" functionality to Honk: lookup tables, efficient range constraints, RAM, ROM, and more will result in orders-of-magnitude improvements to Honk's prover times. - - Recursion using cycles of curves will allow for efficient recursive verification of Honk proofs. Using this technique will lower the barrier to entry of our rollup providers, resulting in a more robust set of providers and greater security for the Aztec network. +- Goblin is a deferred verification framework thats allow for an order-of-magnitude increase in the complexity of computations that Aztec users can execute with full privacy. This corresponds to a 10x increase in the expressivity of Noir programs that can be run in practice without melting anybody's favorite phone or laptop. -## Goblin projects +Read more here. https://hackmd.io/@aztec-network/B19AA8812 -Goblin is a deferred verification framework thats allow for an order-of-magnitude increase in the complexity of computations that Aztec users can execute with full privacy. This corresponds to a 10x increase in the expressivity of Noir programs that can be run in practice without melting anybody's favorite phone or laptop. Read more [here](https://hackmd.io/@aztec-network/B19AA8812). +- List of Goblin projects + - Aside from some prototype code by Zac, we have not begun working on this yet. diff --git a/docs/docs/about_aztec/roadmap/features_initial_ldt.md b/docs/docs/about_aztec/roadmap/features_initial_ldt.md index 228cb2ee72a..7b7f96d40d8 100644 --- a/docs/docs/about_aztec/roadmap/features_initial_ldt.md +++ b/docs/docs/about_aztec/roadmap/features_initial_ldt.md @@ -1,16 +1,87 @@ --- -title: Sandbox Features +title: Initial Sandbox Features --- -The Aztec Sandbox is intended to provide developers with a lightweight and fast local node. +import Disclaimer from "../../misc/common/\_disclaimer.mdx"; + + + +The Aztec Sandbox is intended to provide developers with a lightweight & fast node, with features similar to Ethereum's Ganache or Anvil 'local node' packages. Developers should be able to quickly spin up local, emulated instances of an Ethereum blockchain and an Aztec encrypted rollup, and start deploying private contracts and submitting private txs. -The sandbox allows developers to: +Here's a summary of the features we intend to support with the first release of the Aztec Sandbox. + +## Aztec.nr Contracts + +See the source on Github [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec-nr). + +- Noir `contract` scopes. + - Declare a `contract`, containing a collection of state variables and functions. +- private state variables: + - `read`, `write`, and `delete` private state variables within private functions. +- public (non-private) state variables: + - Manipulate 'public' state in a familiar way to Ethereum state. +- private functions + - May read and modify private state. +- public functions + - May read and modify public state. +- `constructor` functions, for initialising contract state. +- `import` other Aztec.nr contracts, so their functions may be called. +- Nested function calls, for contract composability + - private functions can call private functions of other contracts, and receive return values. + - private functions can call public functions any contract. + - public functions can call private functions of any contract. + - public functions can call public functions of other contracts, and receive return values. + - private functions can be called recursively. + - public functions can be called recursively. +- Send messages from Aztec.nr contracts to Ethereum L1, for consumption by L1 smart contracts. + - Useful, for example, if writing an app to withdraw funds from L2 to L1. +- Consume messages which have been sent by: + - L1 functions. + - Useful, for example, if writing an app to deposit funds from L1 to L2. + - public L2 functions. +- Emit `event` data from a Aztec.nr Contract. + - Allows applications to subscribe to events which have been emitted by a Aztec.nr contract's functions, for example. +- Write `unconstrained` functions. + - These allow developers to write `pure` and `view` functions, which can perform calculations and retrieve state. E.g. for fetching contract-specific information, which may then be consumed by a dapp, without having to generate a zero-knowledge proof or interact with the 'network'. + +## `aztec.js` + +A typescript wrapper for making RPC calls to an Aztec Sandbox node. See the source on Github [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec.js). + +- Similar in purpose to `web3.js`/`ethers.js`/`viem`, but for interacting with Aztec Network nodes. The RPC interface for an Aztec node is necessarily different from that of an Ethereum node, because it deals with encrypted transactions and state variables. +- A library for public/private key management. +- Construct `Contract` instances from a Aztec.nr contract's JSON artifact. +- Deploy new contracts to the Aztec Sandbox. +- Construct tx requests, passing arguments to a function of a contract. +- Sign tx requests. +- Send txs to the Sandbox node, for simulating. +- Send txs to the Sandbox node, to be sent to the Sandbox network. +- Call `unconstrained` functions of a Aztec.nr contract, to perform `pure` calculations or retrieve state. + +## Aztec Sandbox Node + +A bundle of packages which emulate the actions of all eventual Aztec network participants. The goal is for developer experience to be akin to Ganache / Anvil. -- Write and deploy Aztec contracts -- Leverage private and public state variables in contracts -- Write private and public functions in contracts -- Call private and public functions on other Aztec contracts (contract composability) -- Send messages between Aztec and Ethereum contracts -- Interact with the Aztec network using a familiar Typescript SDK ([aztec.js](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec.js)) +- PXE client + - Simulate and/or execute private functions locally. +- Aztec Public Node + - Broadcasts a user's txs to the tx pool. + - Simulate public functions locally. +- Tx Pool + - An in-memory emulation of a tx pool. By default, a user's txs will be rolled-up into an L2 block immediately. +- Sequencer Node + - Reads the tx pool and bundles pending txs into a rollup block immediately. + - Orders txs. + - Executes public functions. + - Passes messages between L1 and L2. +- L1 Rollup smart contract + - Verifies the rollup's snark. + - Reconciles calldata with snark public inputs. + - Updates the rollup's state hash. +- L1 data archiver + - Gobbles up and stores all calldata, events, and state changes from L1 +- World state DB + - Reconstructs the Aztec Network's various trees. + - Allows tree state to be queried. diff --git a/docs/docs/about_aztec/roadmap/main.md b/docs/docs/about_aztec/roadmap/main.md index 587f8751d6e..5e8f320137b 100644 --- a/docs/docs/about_aztec/roadmap/main.md +++ b/docs/docs/about_aztec/roadmap/main.md @@ -1,14 +1,5 @@ ---- -title: Roadmap ---- - import DocCardList from '@theme/DocCardList'; -import Image from '@theme/IdealImage'; - -The next major milestone on the journey to mainnet is launching our testnet. - - -## Read more +# Roadmap diff --git a/docs/docs/concepts/advanced/circuits/kernels/private_kernel.md b/docs/docs/concepts/advanced/circuits/kernels/private_kernel.md index cc0632c986f..405a6163061 100644 --- a/docs/docs/concepts/advanced/circuits/kernels/private_kernel.md +++ b/docs/docs/concepts/advanced/circuits/kernels/private_kernel.md @@ -21,5 +21,5 @@ This circuit is executed by the user, on their own device. This is to ensure pri - Verifies a previous 'Private Kernel Proof', recursively, when verifying transactions which are composed of many private function calls. - Optionally can [deploy](../../contract_creation) a new private contract. -> Note: **This is the only core protocol circuit which actually needs to be "zk" (zero-knowledge)!!!** That's because this is the only core protocol circuit which handles private data, and hence the only circuit for which proofs must not leak any information about witnesses! (The private data being handled includes: details of the Aztec.nr Contract function which has been executed; the address of the user who executed the function; the intelligible inputs and outputs of that function). -> This is a really interesting point. Most so-called "zk-Rollups" do not make use of this "zero-knowledge" property. Their snarks are "snarks"; with no need for zero-knowledge, because they don't seek privacy; they only seek the 'succinct' computation-compression properties of snarks. Aztec's "zk-Rollup" actually makes use of "zero-knowledge" snarks. That's why we sometimes call it a "zk-zk-Rollup", or "_actual_ zk-Rollup". +> Note: **This is the only core protocol circuit which actually needs to be "zk" (zero knowledge)!!!** That's because this is the only core protocol circuit which handles private data, and hence the only circuit for which proofs must not leak any information about witnesses! (The private data being handled includes: details of the Aztec.nr Contract function which has been executed; the address of the user who executed the function; the intelligible inputs and outputs of that function). +> This is a really interesting point. Most so-called "zk-Rollups" do not make use of this "zero knowledge" property. Their snarks are "snarks"; with no need for zero-knowledge, because they don't seek privacy; they only seek the 'succinct' computation-compression properties of snarks. Aztec's "zk-Rollup" actually makes use of "zero knowledge" snarks. That's why we sometimes call it a "zk-zk-Rollup", or "_actual_ zk-Rollup". diff --git a/docs/docs/concepts/advanced/circuits/main.md b/docs/docs/concepts/advanced/circuits/main.md index 9a84f9cf60b..3f21cb79053 100644 --- a/docs/docs/concepts/advanced/circuits/main.md +++ b/docs/docs/concepts/advanced/circuits/main.md @@ -2,12 +2,6 @@ title: Circuits --- -Central to Aztec's operations are 'circuits' derived both from the core protocol and the developer-written Aztec.nr contracts. - -The core circuits enhance privacy by adding additional security checks and preserving transaction details - a characteristic Ethereum lacks. - -On this page, you’ll learn a bit more about these circuits and their integral role in promoting secure and efficient transactions within Aztec's privacy-centric framework. - ## Motivation In Aztec, circuits come from two sources: diff --git a/docs/docs/concepts/advanced/data_structures/indexed_merkle_tree.md b/docs/docs/concepts/advanced/data_structures/indexed_merkle_tree.md index 751b209dc9b..927a4e6a387 100644 --- a/docs/docs/concepts/advanced/data_structures/indexed_merkle_tree.md +++ b/docs/docs/concepts/advanced/data_structures/indexed_merkle_tree.md @@ -3,24 +3,17 @@ title: Indexed Merkle Tree --- import Image from "@theme/IdealImage"; +import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; -## Overview + -This article will introduce the concept of an indexed merkle tree, and how it can be used to improve the performance of nullifier trees in circuits. +## Indexed Merkle Trees -This page will answer: - -- Why we need nullifier trees at all -- How indexed merkle trees work -- How they can be used for membership exclusion proofs -- How they can leverage batch insertions -- Tradoffs of using indexed merkle trees - -The content was also covered in a presentation for the [Privacy + Scaling Explorations team at the Ethereum Foundation](https://pse.dev/). +This article will introduce the concept of an indexed merkle tree, and how it can be used to improve the performance of nullifier trees in circuits. The content was also covered in a presentation for the [Privacy + Scaling Explorations team at the Ethereum Foundation](https://pse.dev/). -## Primer on Nullifier Trees +#### Primer on Nullifier Trees Currently the only feasible way to get privacy in public blockchains is via a UTXO model. In this model, state is stored in encrypted UTXO's in merkle trees. However, to maintain privacy, state can not be updated. The very act of performing an update leaks information. In order to simulate "updating" the state, we "destroy" old UTXO's and create new ones for each state update. Resulting in a merkle tree that is append-only. diff --git a/docs/docs/concepts/advanced/data_structures/trees.md b/docs/docs/concepts/advanced/data_structures/trees.md index 97d11cc22e0..ad801b6a051 100644 --- a/docs/docs/concepts/advanced/data_structures/trees.md +++ b/docs/docs/concepts/advanced/data_structures/trees.md @@ -2,18 +2,10 @@ title: Trees --- +import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; import Image from "@theme/IdealImage"; -## Overview - -Data trees are how we keep track of all the data in the network. Each type of data is stored in it's own data tree. Different tree structures are used for different kinds of data, as the requirements for each are different. - -Data includes: - -- Private state -- Nullifiers to invalidate old private state -- Public state -- Contracts + ## Private State Tree @@ -25,7 +17,7 @@ Any function of any Aztec contract may insert new leaves into the this tree. Once inserted into this tree, a leaf's value can never be modified. We enforce this, to prevent linkability of transactions. If an observer sees that 'tx A' inserted a leaf and 'tx B' modified that leaf, then the observer knows these two transactions are related in some way. This is a big 'no no' if we want to ensure privacy. -So, if an app needs to edit a private state variable (which will be represented by one or more leaves in the tree), it may do so in a manner inspired by [zerocash](http://zerocash-project.org/media/pdf/zerocash-extended-20140518.pdf). (See [Nullifier Tree](#nullifier-tree)). This allows the leaf to be 'nullified' and a new leaf value inserted into the next empty position in the tree, in a way which prevents observers from linking the old and new leaves. +So, if an app needs to edit a private state variable (which will be represented by one or more leaves in the tree), it may do so in a manner inspired by [zerocash](http://zerocash-project.org/media/pdf/zerocash-extended-20140518.pdf). (See Nullifier Tree, further down this page). This allows the leaf to be 'nullified' and a new leaf value inserted into the next empty position in the tree, in a way which prevents observers from linking the old and new leaves. @@ -144,6 +136,6 @@ The contract tree contains information about every function of every contract de - `treeOfHistoricPrivateDataTreeRoots`: for membership checks against historic roots of the `privateDataTree` - `treeOfHistoricContractTreeRoots`: for membership checks against historic roots of the `contractTree` -## Trees of valid Kernel/Rollup circuit Verification Keys +## Trees of valid Kernel/Rollup circuit VKs -Eventually, we'll have trees of verification keys for various permutations of kernel/rollup circuits. Such permutations might be the number of public inputs, or the logic contained within the circuits. +Eventually, we'll have trees of VKs for various permutations of kernel/rollup circuits. Such permutations might be the number of public inputs, or the logic contained within the circuits. diff --git a/docs/docs/concepts/foundation/accounts/main.md b/docs/docs/concepts/foundation/accounts/main.md index 5f6b1cf8595..26f9c234a27 100644 --- a/docs/docs/concepts/foundation/accounts/main.md +++ b/docs/docs/concepts/foundation/accounts/main.md @@ -2,21 +2,13 @@ **Every account in Aztec is a smart contract** which defines the rules for whether a transaction is or is not valid. This allows implementing different schemes for transaction signing, nonce management, and fee payments. However, encryption and nullifying keys, which are specific to private blockchains, are still enshrined at the protocol level. -In this section, you’ll learn about how Aztec defines AA (account abstraction) and its correlation with encryption keys and nullifying keys. We’ll go through: - -- The importance and implications of AA -- Understanding account contracts and wallets in relation to Aztec -- Concept of authorization and actions along with encryption -- The future of fee management in Aztec - ## Background We'll start with the mandatory "what is AA" section that every single article on the topic has, so you can skip this if you're familiar with the topic. ### What is account abstraction? -We'll refer to AA as the _ability to set the validity conditions of a transaction programmatically_ ([source](https://fuel-labs.ghost.io/account-abstraction-for-everyone-else/)). [Starknet](https://docs.starknet.io/documentation/architecture_and_concepts/Account_Abstraction/introduction/#account_abstraction) goes one step further and splits AA into three different components: - +We'll refer to AA as the _ability to set the validity conditions of a transaction programmatically_ ([source](https://fuel-labs.ghost.io/account-abstraction-for-everyone-else/)). [Starknet](https://docs.starknet.io/documentation/architecture_and_concepts/Account_Abstraction/introduction/#account_abstraction) goes one step further and splits AA into three different components: - Signature abstraction (defining when a signature is accepted) - Fee abstraction (paying fees) - Nonce abstraction (replay protection and ordering) @@ -27,7 +19,7 @@ The benefits of AA are multiple. We're not going to reiterate them all here, but ### Implementing at protocol vs application layer -Instead of implementing it at the protocol level as in Aztec, account abstraction can be implemented at the application layer of a network using smart accounts and meta-transactions. When implementing account abstraction on Ethereum, the transaction being sent to the network is still an Ethereum transaction, but its payload is interpreted as a "transaction execution request" that is validated and run by the smart contract wallet. +Instead of implementing it at the protocol level as in Aztec, account abstraction can be implemented at the application layer of a network using smart accounts and meta-transactions. When implementing account abstraction on Ethereum, the transaction being sent to the network is still an Ethereum transaction, but its payload is interpreted as a "transaction execution request" that is validated and run by the smart contract wallet. A simple example would be Gnosis Safe (see [_Account Abstraction is NOT coming_](https://safe.mirror.xyz/9KmZjEbFkmI79s28d9xar6JWYrE50F5AHpa5CR12YGI)), where it's the multisig contract responsibility to define when an execution request is valid by checking it carries N out of M signatures, and then executing it. [Argent](https://www.argent.xyz/blog/wtf-is-account-abstraction/) has also been working on smart wallets for years, and collaborating with network teams to implement AA natively at the protocol layer. @@ -58,11 +50,11 @@ def entryPoint(payload): let { privateCalls, publicCalls, nonce, signature } = payload; let payloadHash = hash(privateCalls, publicCalls, nonce); validateSignature(this.publicKey, signature, payloadHash); - + foreach privateCall in privateCalls: let { to, data, value } = privateCall; call(to, data, value); - + foreach publicCall in publicCalls: let { to, data, value, gasLimit } = publicCall; enqueueCall(to, data, value, gasLimit); @@ -98,11 +90,11 @@ A side-effect of not having nonces at the protocol level is that it is not possi Since the `entrypoint` interface is not enshrined, there is nothing that differentiates an account contract from an application one in the protocol. This means that a transaction can be initiated in any contract. This allows implementing functions that do not need to be called by any particular user and are just intended to advance the state of a contract. -As an example, we can think of a lottery contract, where at some point a prize needs to be paid out to its winners. This `pay` action does not require authentication and does not need to be executed by any user in particular, so anyone could submit a transaction that defines the lottery contract itself as `origin` and `pay` as entrypoint function. For an example implementation of a different use case, refer to the [`pokeable_token_contract`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/main.nr) in the repository. +As an example, we can think of a lottery contract, where at some point a prize needs to be paid out to its winners. This `pay` action does not require authentication and does not need to be executed by any user in particular, so anyone could submit a transaction that defines the lottery contract itself as `origin` and `pay` as entrypoint function. For an example implementation of a different use case, refer to the [`pokeable_token_contract`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/main.nr) in the repository. ### Account initialization -The protocol requires that every account is a contract for the purposes of sending a transaction. This means that a user needs to deploy their account contract as their first action when they want to interact with the network. +The protocol requires that every account is a contract for the purposes of sending a transaction. This means that a user needs to deploy their account contract as their first action when they want to interact with the network. However, this is not required when sitting on the receiving end. A user can deterministically derive their address from their encryption public key and the account contract they intend to deploy, and share this address with other users that want to interact with them _before_ they deploy the account contract. @@ -114,7 +106,7 @@ When executing a private function, this authorization is checked by requesting a The PXE is responsible for storing these auth witnesses and returning them to the requesting account contract. Auth witnesses can belong to the current user executing the local transaction, or to another user who shared it out-of-band. -However, during a public function execution, it is not possible to retrieve a value from the local oracle. To support authorizations in public functions, account contracts should save in contract storage what actions have been pre-authorized by their owner. +However, during a public function execution, it is not possible to retrieve a value from the local oracle. To support authorizations in public functions, account contracts should save in contract storage what actions have been pre-authorized by their owner. These two patterns combined allow an account contract to answer whether an action `is_valid` for a given user both in private and public contexts. @@ -130,4 +122,4 @@ NOTE: While we entertained the idea of abstracting note encryption, where accoun Fees are not implemented in the protocol at the time of this writing. Our goal is to abstract fee payments as well. This means that a transaction, in order to be considered valid, must prove that it has locked enough funds to pay for itself. However, this does not mandate where those funds come from, opening the door for easy implementation of paymasters or payment-in-kind via on-the-fly swaps. -However, there is one major consideration around public execution reverts. In the current design, if one of the public function executions enqueued in a transaction fails, then the entire transaction is reverted. But reverting the whole transaction would also revert the fee payment, and leave the sequencer with their hands empty after running the public execution. This means we will need to enshrine an initial verification and fee payment phase that is _not_ reverted if public execution fails. +However, there is one major consideration around public execution reverts. In the current design, if one of the public function executions enqueued in a transaction fails, then the entire transaction is reverted. But reverting the whole transaction would also revert the fee payment, and leave the sequencer with their hands empty after running the public execution. This means we will need to enshrine an initial verification and fee payment phase that is _not_ reverted if public execution fails. \ No newline at end of file diff --git a/docs/docs/concepts/foundation/communication/cross_chain_calls.md b/docs/docs/concepts/foundation/communication/cross_chain_calls.md index 34dd8bf5418..abd37f84fcf 100644 --- a/docs/docs/concepts/foundation/communication/cross_chain_calls.md +++ b/docs/docs/concepts/foundation/communication/cross_chain_calls.md @@ -8,18 +8,7 @@ import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; -In Aztec, what we call _portals_ are the key element in facilitating communication between L1 and L2. While typical L2 solutions rely on synchronous communication with L1, Aztec's privacy-first nature means this is not possible. You can learn more about why in the previous section. - -Traditional L1<-->L2 communication might involve direct calls between L2 nd L1 contracts. However, in Aztec, due to the privacy components and the way transactions are processed (kernel proofs built on historical data), direct calls between L1 and L2 would not be possible if we want to maintain privacy. - -Portals are the solution to this problem, acting as bridges for communication between the two layers. These portals can transmit messages from public functions in L1 to private functions in L2 and vice versa, thus enabling messaging while maintaining privacy. - -This page covers - -- How portals enable privacy communication between L1 and L2 -- How messages are sent, received, and processed -- Message Boxes and how they work -- How and why linking of contracts between L1 and L2 occurs +In the following section, we will look at cross-chain communication, mixing L1 and L2 for composability and profits. # Objective diff --git a/docs/docs/concepts/foundation/communication/public_private_calls.md b/docs/docs/concepts/foundation/communication/public_private_calls.md index d175f149569..32b42b091dd 100644 --- a/docs/docs/concepts/foundation/communication/public_private_calls.md +++ b/docs/docs/concepts/foundation/communication/public_private_calls.md @@ -8,14 +8,7 @@ import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; -Aztec operates on a model of private and public functions that are able to work together. Private functions work by providing evidence of correct execution generated locally through kernel proofs. Public functions, on the other hand, are able to utilize the latest state to manage updates and perform alterations. - -On this page, you’ll learn: - -- How private and public functions work -- The role of public functions in managing state alterations and updates -- Communication and interactions between private and public functions -- How the sequencer manages the order of operations of private functions +The following section will try to outline what _private_ and _public_ functions can do, and give some intuition to why they have the limitations they have. ### Objectives diff --git a/docs/docs/concepts/foundation/contracts.md b/docs/docs/concepts/foundation/contracts.md index 0c976da2a66..49321bcb9ed 100644 --- a/docs/docs/concepts/foundation/contracts.md +++ b/docs/docs/concepts/foundation/contracts.md @@ -2,17 +2,6 @@ title: Smart Contracts --- -Smart contracts in Aztec are privacy-first, and can include both public and private elements. They are written in Noir framework called Aztec.nr, and allow high-level programs to be convered into ZK circuits. - -On this page, you’ll learn how Aztec executes smart contracts for privacy and efficiency: - -- Role and structure of smart contracts within Aztec -- Intro into Noir programming language and how it converts to circuits -- The Aztec Kernel -- Transaction flow and confidentiality - -## Defining Aztec smart contracts - A "smart contract" is defined as a set of public and private functions written as Noir circuits. These functions operate on public and private state stored by a contract. Each function is represented as a ZK SNARK verification key, where the contract is uniquely described by the set of its verification keys, and stored in the Aztec Contracts tree. [Noir](https://noir-lang.org) is a programming language designed for converting high-level programs into ZK circuits. Based on Rust, the goal is to present an idiomatic way of writing private smart contracts that is familiar to Ethereum developers. Noir is under active development adding features such as contracts, functions and storage variables. diff --git a/docs/docs/concepts/foundation/state_model.md b/docs/docs/concepts/foundation/state_model.md index b02aefaf4bb..1ecc52700bb 100644 --- a/docs/docs/concepts/foundation/state_model.md +++ b/docs/docs/concepts/foundation/state_model.md @@ -12,18 +12,6 @@ Internal to the Aztec network, public state is stored and updated by the sequenc ## Private State -Every smart contract needs a way to track information over time - that's what state is. In order to have both private and public transactions and storage in Aztec, we have to have public and private state. - -On this page, you’ll learn - -- Aztec's unique interpretation of private state -- Representation of private state in an append-only database -- Concept of 'deleting' private state variables using nullifiers -- How to modify private state -- How Aztec abstracts the UTXO model from developers - -## Private State on Aztec - Private state must be treated differently from public state and this must be expressed in the semantics of Aztec.nr. Private state is encrypted and therefore is "owned" by a user or a set of users (via shared secrets) that are able to decrypt the state. diff --git a/docs/docs/concepts/foundation/transactions.md b/docs/docs/concepts/foundation/transactions.md index 7e44497ae07..5b5974802fa 100644 --- a/docs/docs/concepts/foundation/transactions.md +++ b/docs/docs/concepts/foundation/transactions.md @@ -2,15 +2,6 @@ title: Transactions --- -Transactions on Aztec start with a call from Aztec.js or the Aztec CLI, which creates a request containing transaction details. This request moves to the Private Execution Environment (PXE) which simulates and processes it. Then the PXE interacts with the Aztec Node which uses the sequencer to ensure that all the transaction details are enqueued properly. The sequencer then submits the block to the rollup contract, and the transaction is successfully mined. - -On this page you'll learn: - -- The step-by-step process of sending a transaction on Aztec -- The role of components like PXE, Aztec Node, ACIR simulator, and the sequencer -- The Aztec Kernel and its two circuits: private and public, and how they execute function calls -- The call stacks for private & public functions and how they determine a transaction's completion - Sending a transaction See [this diagram](https://raw.githubusercontent.com/AztecProtocol/aztec-packages/2fa143e4d88b3089ebbe2a9e53645edf66157dc8/docs/static/img/sandbox_sending_a_tx.svg) for an in-depth overview of the transaction execution process. It highlights 3 different types of transaction execution: contract deployments, private transactions and public transactions. From f6d7b16a198c1bc7bf580b2ee57cc3e7f5f3c312 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Sun, 22 Oct 2023 16:40:40 +0100 Subject: [PATCH 15/33] merge master --- docs/docs/dev_docs/contracts/portals/main.md | 75 +++++++++---------- .../dev_docs/contracts/syntax/context.mdx | 60 ++++----------- .../dev_docs/contracts/syntax/functions.md | 11 --- .../docs/dev_docs/contracts/syntax/storage.md | 21 +----- docs/docs/dev_docs/limitations/main.md | 20 ++--- docs/docs/dev_docs/privacy/main.md | 25 +++++-- docs/docs/dev_docs/tutorials/main.md | 4 - .../wallets/writing_an_account_contract.md | 13 +--- docs/netlify.toml | 4 + 9 files changed, 87 insertions(+), 146 deletions(-) diff --git a/docs/docs/dev_docs/contracts/portals/main.md b/docs/docs/dev_docs/contracts/portals/main.md index 3d1448e8941..a7b7340f17c 100644 --- a/docs/docs/dev_docs/contracts/portals/main.md +++ b/docs/docs/dev_docs/contracts/portals/main.md @@ -5,9 +5,9 @@ description: Documentation of Aztec's Portals and Cross-chain communication. ## What is a portal -A portal is the point of contact between L1 and a specific contract on Aztec. For applications such as token bridges, this is the point where the tokens are are held on L1 while used in L2. +A portal is the point of contact between L1 and a specific contract on Aztec. For applications such as token bridges, this is the point where the tokens are held on L1 while used in L2. -As outlined in the [foundational concepts](../../../concepts/foundation/communication/cross_chain_calls.md), an Aztec L2 contract is linked to _ONE_ L1 address at time of deployment (specified by the developer). This L1 address is the only address that can send messages to that specific L2 contract, and the only address that can receive messages sent from the L2 contract to L1. Note, that a portal don't actually need to be a contract, it could be any address on L1. We say that an Aztec contract is attached to a portal. +As outlined in the [foundational concepts](../../../concepts/foundation/communication/cross_chain_calls.md), an Aztec L2 contract is linked to *ONE* L1 address at time of deployment (specified by the developer). This L1 address is the only address that can send messages to that specific L2 contract, and the only address that can receive messages sent from the L2 contract to L1. Note, that a portal doesn't actually need to be a contract; a portal could be any address on L1. We say that an Aztec contract is attached to a portal. ## Passing data to the rollup @@ -17,25 +17,24 @@ The `Inbox` can be seen as a mailbox to the rollup, portals put messages into th When sending messages, we need to specify quite a bit of information beyond just the content that we are sharing. Namely we need to specify: -| Name | Type | Description | -| ----------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Recipient | `L2Actor` | The message recipient. This **MUST** match the rollup version and an Aztec contract that is **attached** to the contract making this call. If the recipient is not attached to the caller, the message cannot be consumed by it. | -| Deadline | `uint256` | The deadline for the message to be consumed. If the message has not been removed from the `Inbox` and included in a rollup block by this point, it can be _cancelled_ by the portal (the portal must implement logic to cancel). | -| Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to be a single field. If the content is small enough it can just be passed along, otherwise it should be hashed and the hash passed along (you can use our [`Hash`](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Hash.sol) utilities with `sha256ToField` functions) | -| Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use the [`computeMessageSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. | -| Fee | `uint64` | The fee to the sequencer for including the message. This is the amount of ETH that the sequencer will receive for including the message. Note that it is not a full `uint256` but only `uint64` | +| Name | Type | Description | +| -------------- | ------- | ----------- | +| Recipient | `L2Actor` | The message recipient. This **MUST** match the rollup version and an Aztec contract that is **attached** to the contract making this call. If the recipient is not attached to the caller, the message cannot be consumed by it. | +| Deadline | `uint256` | The deadline for the message to be consumed. If the message has not been removed from the `Inbox` and included in a rollup block by this point, it can be *cancelled* by the portal (the portal must implement logic to cancel). | +| Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to be a single field. If the content is small enough it can just be passed along, otherwise it should be hashed and the hash passed along (you can use our [`Hash`](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Hash.sol) utilities with `sha256ToField` functions) | +| Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use the [`computeMessageSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. | +| Fee | `uint64` | The fee to the sequencer for including the message. This is the amount of ETH that the sequencer will receive for including the message. Note that it is not a full `uint256` but only `uint64`| -With all that information at hand, we can call the `sendL2Message` function on the Inbox. The function will return a `field` (inside `bytes32`) that is the hash of the message. This hash can be used as an identifier to spot when your message has been included in a rollup block. +With all that information at hand, we can call the `sendL2Message` function on the Inbox. The function will return a `field` (inside `bytes32`) that is the hash of the message. This hash can be used as an identifier to spot when your message has been included in a rollup block. #include_code send_l1_to_l2_message l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity As time passes, a sequencer will see your tx, the juicy fee provided and include it in a rollup block. Upon inclusion, it is removed from L1, and made available to be consumed on L2. -To consume the message, we can use the `consume_l1_to_l2_message` function within the `context` struct. - -- The `msg_key` is the hash of the message returned by the `sendL2Message` call and is used to help the RPC find the correct message. -- The `content` is the content of the message, limited to one Field element. For content larger than one Field, we suggest using the `sha256` hash function truncated to a single Field element. `sha256` is suggested as it is cheap on L1 while still being managable on L2. -- The `secret` is the pre-image hashed using Pedersen to compute the `secretHash`. +To consume the message, we can use the `consume_l1_to_l2_message` function within the `context` struct. +- The `msg_key` is the hash of the message returned by the `sendL2Message` call and is used to help the RPC find the correct message. +- The `content` is the content of the message, limited to one Field element. For content larger than one Field, we suggest using the `sha256` hash function truncated to a single Field element. `sha256` is suggested as it is cheap on L1 while still being managable on L2. +- The `secret` is the pre-image hashed using Pedersen to compute the `secretHash`. - If the `content` or `secret` does not match the entry at `msg_key` the message will not be consumed, and the transaction will revert. :::info @@ -70,17 +69,17 @@ Since the message consumption is emitting a nullifier the same message cannot be To pass data to L1, we use the `Outbox`. The `Outbox` is the mailbox for L2 to L1 messages. This is the location on L1 where all the messages from L2 will live, and where they can be consumed from. -Similarly to messages going to L2 from L1, a message can only be consumed by the recipient, however note that it is up to the portal contract to ensure that the sender is as expected! +Similarly to messages going to L2 from L1, a message can only be consumed by the recipient, however note that it is up to the portal contract to ensure that the sender is as expected! Recall that we mentioned the Aztec contract specifies what portal it is attached to at deployment. This value is stored in the rollup's contract tree, hence these links are not directly readable on L1. Also, it is possible to attach multiple aztec contracts to the same portal. The portal must ensure that the sender is as expected. One way to do this is to compute the addresses before deployment and store them as constants in the contract. However, a more flexible solution is to have an `initialize` function in the portal contract which can be used to set the address of the Aztec contract. In this model, the portal contract can check that the sender matches the value it has in storage. -To send a message to L1 from your Aztec contract, you must use the `message_portal` function on the `context`. When messaging to L1, only the `content` is required (as a `Field`). +To send a message to L1 from your Aztec contract, you must use the `message_portal` function on the `context`. When messaging to L1, only the `content` is required (as a `Field`). #include_code context_message_portal /yarn-project/aztec-nr/aztec/src/context.nr rust -When sending a message from L2 to L1 we don't need to pass recipient, deadline, secret nor fees. Recipient is populated with the attached portal and the remaining values are not needed as the message is inserted into the outbox at the same time as it was included in a block (for the inbox it could be inserted and then only included in rollup block later). +When sending a message from L2 to L1 we don't need to pass recipient, deadline, secret nor fees. Recipient is populated with the attached portal and the remaining values are not needed as the message is inserted into the outbox at the same time as it was included in a block (for the inbox it could be inserted and then only included in rollup block later). :::danger Access control on the L1 portal contract is essential to prevent consumption of messages sent from the wrong L2 contract. @@ -100,38 +99,36 @@ As noted earlier, the portal contract should check that the sender is as expecte #include_code token_portal_withdraw l1-contracts/test/portals/TokenPortal.sol solidity -## How to deploy a contract with a portal +## How to deploy a contract with a portal - Deploy to L1 using Viem, Foundry or your preferred tool; - Deploy to L2 passing in the address of the L1 portal as its portal contract; ```typescript - const deploymentTx = Contract.deploy(wallet).send({ - portalContract: tokenPortalAddress, - }); + const deploymentTx = Contract.deploy(wallet).send({portalContract: tokenPortalAddress}); ``` - Initialize l1 with l2 address for access control. + ## Considerations ### Structure of messages +The application developer should consider creating messages that follow a function call structure e.g., using a function signature and arguments. This will make it easier to prevent producing messages that could be misinterpreted by the recipient. -The application developer should consider creating messages that follow a function call structure e.g., using a function signature and arguments. This will make it easier to prevent producing messages that could be misinterpreted by the recipient. +An example of a bad format would be using `amount, token_address, recipient_address` as the message for a withdraw function and `amount, token_address, on_behalf_of_address` for a deposit function. Any deposit could then also be mapped to a withdraw or vice versa. -An example of a bad format would be using `amount, token_address, recipient_address` as the message for a withdraw function and `amount, token_address, on_behalf_of_address` for a deposit function. Any deposit could then also be mapped to a withdraw or vice versa. - -```solidity +```solidity // Don't to this! bytes memory message = abi.encode( - _amount, - _token, + _amount, + _token, _to ); // Do this! bytes memory message abi.encodeWithSignature( - "withdraw(uint256,address,address)", - _amount, - _token, + "withdraw(uint256,address,address)", + _amount, + _token, _to ); ``` @@ -160,7 +157,7 @@ As this requires logic on the portal itself, it is not something that the protoc The portal can call the `cancelL2Message` at the `Inbox` when `block.timestamp > deadline` for the message. -#include_code pending_l2_cancel l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity +#include_code pending_l2_cancel l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity Building on our token example from earlier, this can be called like: @@ -169,28 +166,26 @@ Building on our token example from earlier, this can be called like: The example above ensure that the user can cancel their message if it is underpriced. ### Designated caller - Designating a caller grants the ability to specify who should be able to call a function that consumes a message. This is useful for ordering of batched messages. -When performing multiple cross-chain calls in one action it is important to consider the order of the calls. Say for example, that you want to perform a uniswap trade on L1 because you are a whale and slippage on L2 is too damn high. +When performing multiple cross-chain calls in one action it is important to consider the order of the calls. Say for example, that you want to perform a uniswap trade on L1 because you are a whale and slippage on L2 is too damn high. -You would practically, withdraw funds from the rollup, swap them on L1, and then deposit the swapped funds back into the rollup. This is a fairly simple process, but it requires that the calls are done in the correct order. For one, if the swap is called before the funds are withdrawn, the swap will fail. And if the deposit is called before the swap, the funds might get lost! +Practically, you would withdraw funds from the rollup, swap them on L1, and then deposit the swapped funds back into the rollup. This is a fairly simple process, but it requires that the calls are done in the correct order. For one, if the swap is called before the funds are withdrawn, the swap will fail. And if the deposit is called before the swap, the funds might get lost! As message boxes only will allow the recipient portal to consume the message, we can use this to our advantage to ensure that the calls are done in the correct order. Say that we include a designated "caller" in the messages, and that the portal contract checks that the caller matches the designated caller or designated is address(0) (anyone can call). When the message are to be consumed on L1, it can compute the message as seen below: ```solidity bytes memory message = abi.encodeWithSignature( - "withdraw(uint256,address,address)", - _amount, - _to, + "withdraw(uint256,address,address)", + _amount, + _to, _withCaller ? msg.sender : address(0) ); ``` This way, the message can be consumed by the portal contract, but only if the caller is the designated caller. By being a bit clever when specifying the designated caller, we can ensure that the calls are done in the correct order. For the Uniswap example, say that we have token portals implemented as we have done throughout this page, and a Uniswap portal implementing the designated caller. -We require that the Uniswap portal is the caller of the withdraw, and that the uniswap portal implementation is executing the withdraw before the swap. -The order of execution can be constrained in the contract. Since all of the messages are emitted to L1 in the same transaction, we can leverage transaction atomicity to ensure success of failure of all messages. +We require that the Uniswap portal is the caller of the withdraw, and that the uniswap portal implementation is executing the withdraw before the swap. The order of execution can be constrained in the contract. Since all of the messages are emitted to L1 in the same transaction, we can leverage transaction atomicity to ensure success of failure of all messages. Note, that crossing the L1/L2 chasm is asynchronous, so there could be a situation where the user has burned their assets on L2 but the swap fails on L1! This could be due to major price movements or the like. In such a case, the user could be stuck with funds on L1 that they cannot get back to L2 unless the portal contract implements a way to properly handle such errors. diff --git a/docs/docs/dev_docs/contracts/syntax/context.mdx b/docs/docs/dev_docs/contracts/syntax/context.mdx index bab10efeac7..e772b3866e2 100644 --- a/docs/docs/dev_docs/contracts/syntax/context.mdx +++ b/docs/docs/dev_docs/contracts/syntax/context.mdx @@ -9,23 +9,12 @@ import Image from "@theme/IdealImage"; # The Function Context ## What is the context +The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](../../../concepts/advanced/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of it's side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity. -The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](../../../concepts/advanced/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of it's side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity. - -Behind the scenes, Aztec.nr will pass data the kernel needs to and from a circuit, this is abstracted away from the developer. In an developer's eyes; the context is a useful structure that allows access and mutate the state of the `Aztec` blockchain. - -On this page, you'll learn - -- The details and functionalities of the private context in Aztec.nr -- Difference between the private and public contexts and their unified APIs -- Components of the private context, such as inputs, historic block data, and contract deployment data -- Elements like return values, read requests, new commitments, and nullifiers in transaction processing -- Differences between the private and public contexts, especially the unique features and variables in the public context +Behind the scenes, Aztec noir will pass data the kernel needs to and from a circuit, this is abstracted away from the developer. In an developer's eyes; the context is a useful structure that allows access and mutate the state of the `Aztec` blockchain. ## Two context's one API - -The `Aztec` blockchain contains two environments [public and private](../../../concepts/foundation/state_model.md). - +The `Aztec` blockchain contains two environments [public and private](../../../concepts/foundation/state_model.md). - Private, for private transactions taking place on user's devices. - Public, for public transactions taking place on the network's sequencers. @@ -39,9 +28,7 @@ The code snippet below shows what is contained within the private context. #include_code private-context /yarn-project/aztec-nr/aztec/src/context.nr rust ### Private Context Broken Down - #### Inputs - The context inputs includes all of the information that is passed from the kernel circuit into the application circuit. It contains the following values. #include_code private-context-inputs /yarn-project/aztec-nr/aztec/src/abi.nr rust @@ -54,97 +41,82 @@ First of all, the call context. The call context contains information about the current call being made: + 1. Msg Sender - - The message sender is the account (Aztec Contract) that sent the message to the current context. In the first call of the kernel circuit (often the account contract call), this value will be empty. For all subsequent calls the value will be the previous call. + - The message sender is the account (Aztec Contract) that sent the message to the current context. In the first call of the kernel circuit (often the account contract call), this value will be empty. For all subsequent calls the value will be the previous call. > The graphic below illustrates how the message sender changes throughout the kernel circuit iterations. - 2. Storage contract address + - This value is the address of the current context's contract address. This value will be the value of the current contract that is being executed except for when the current call is a delegate call (Warning: This is yet to be implemented). In this case the value will be that of the sending contract. - - This value is the address of the current context's contract address. This value will be the value of the current contract that is being executed except for when the current call is a delegate call (Warning: This is yet to be implemented). In this case the value will be that of the sending contract. - -3. Portal Contract Address - - This value stores the current contract's linked [portal contract](../portals/main.md) address. As a quick recap, this value is the value of the contracts related ethereum l1 contract address, and will be the recipient of any messages that are created by this contract. +3. Portal Contract Address + - This value stores the current contract's linked [portal contract](../portals/main.md) address. As a quick recap, this value is the value of the contracts related ethereum l1 contract address, and will be the recipient of any messages that are created by this contract. 4. Flags - - Furthermore there are a series of flags that are stored within the application context: - - is_delegate_call: Denotes whether the current call is a delegate call. If true, then the storage contract address will be the address of the sender. - - is_static_call: This will be set if and only if the current call is a static call. In a static call, state changing altering operations are not allowed. - - is_contract_deployment: This will be set if and only if the current call is the contract's constructor. + - Furthermore there are a series of flags that are stored within the application context: + - is_delegate_call: Denotes whether the current call is a delegate call. If true, then the storage contract address will be the address of the sender. + - is_static_call: This will be set if and only if the current call is a static call. In a static call, state changing altering operations are not allowed. + - is_contract_deployment: This will be set if and only if the current call is the contract's constructor. ### Historic Block Data - -Another structure that is contained within the context is the Historic Block Data object. This object is a special one as it contains all of the roots of Aztec's data trees. +Another structure that is contained within the context is the Historic Block Data object. This object is a special one as it contains all of the roots of Aztec's data trees. #include_code historic-block-data /yarn-project/aztec-nr/aztec/src/abi.nr rust ### Contract Deployment Data - Just like with the `is_contract_deployment` flag mentioned earlier. This data will only be set to true when the current transaction is one in which a contract is being deployed. #include_code contract-deployment-data /yarn-project/aztec-nr/aztec/src/abi.nr rust ### Private Global Variables - In the private execution context, we only have access to a subset of the total global variables, we are restricted to those which can be reliably proven by the kernel circuits. #include_code private-global-variables /yarn-project/aztec-nr/aztec/src/abi.nr rust ### Args Hash - -To allow for flexibility in the number of arguments supported by Aztec functions, all function inputs are reduced to a singular value which can be proven from within the application. +To allow for flexibility in the number of arguments supported by Aztec functions, all function inputs are reduced to a singular value which can be proven from within the application. The `args_hash` is the result of pedersen hashing all of a function's inputs. ### Return Values - The return values are a set of values that are returned from an applications execution to be passed to other functions through the kernel. Developers do not need to worry about passing their function return values to the `context` directly as `Aztec.nr` takes care of it for you. See the documentation surrounding `Aztec.nr` [macro expansion](./functions.md#after-expansion) for more details. return_values : BoundedVec, ### Read Requests - ### New Commitments - New commitments contains an array of all of the commitments created in the current execution context. ### New Nullifiers - New nullifiers contains an array of the new nullifiers emitted from the current execution context. ### Nullified Commitments - Nullified commitments is an optimization for introduced to help reduce state growth. There are often cases where commitments are created and nullified within the same transaction. In these cases there is no reason that these commitments should take up space on the node's commitment/nullifier trees. Keeping track of nullified commitments allows us to "cancel out" and prove these cases. ### Private Call Stack - -The private call stack contains all of the external private function calls that have been created within the current context. Any function call objects are hashed and then pushed to the execution stack. +The private call stack contains all of the external private function calls that have been created within the current context. Any function call objects are hashed and then pushed to the execution stack. The kernel circuit will orchestrate dispatching the calls and returning the values to the current context. ### Public Call Stack - The public call stack contains all of the external function calls that are created within the current context. Like the private call stack above, the calls are hashed and pushed to this stack. Unlike the private call stack, these calls are not executed client side. Whenever the function is sent to the network, it will have the public call stack attached to it. At this point the sequencer will take over and execute the transactions. ### New L2 to L1 msgs - New L2 to L1 messages contains messages that are delivered to the [l1 outbox](../../../concepts/foundation/communication/cross_chain_calls.md) on the execution of each rollup. ## Public Context - The Public Context includes all of the information passed from the `Public VM` into the execution environment. It is very similar to the [Private Context](#the-private-context), however it has some minor differences (detailed below). ### Public Context Inputs - In the current version of the system, the public context is almost a clone of the private execution context. It contains the same call context data, access to the same historic tree roots, however it does NOT have access to contract deployment data, this is due to traditional contract deployments only currently being possible from private transactions. #include_code public-context-inputs /yarn-project/aztec-nr/aztec/src/abi.nr rust -### Public Global Variables +### Public Global Variables The public global variables are provided by the rollup sequencer and consequently contain some more values than the private global variables. #include_code public-global-variables /yarn-project/aztec-nr/aztec/src/abi.nr rust diff --git a/docs/docs/dev_docs/contracts/syntax/functions.md b/docs/docs/dev_docs/contracts/syntax/functions.md index 1c0868ba414..c21ce8c56af 100644 --- a/docs/docs/dev_docs/contracts/syntax/functions.md +++ b/docs/docs/dev_docs/contracts/syntax/functions.md @@ -3,17 +3,6 @@ title: Functions description: This page covers functions, private and public functions composability, as well as their differences. --- -Functions serve as the building blocks of smart contracts. Functions can be either public, ie they can interact with other contracts and the blockchain, or private for internal contract use. Every smart contract also has a private `constructor` function which is called when the contract is deployed. There are also special oracle functions, which can get data from outside of the smart contract. In the context of Aztec, oracles are often used to get user-provided inputs. - -On this page, you’ll learn more about: - -- How function visibility works in Aztec -- A detailed understanding of public, private, and unconstrained functions, and how to write them -- How constructors work and remain private -- The process of calling functions from within the same smart contract and from different contracts, including calling private functions from private functions, public from public, and even private from public -- What oracles and how Aztec smart contracts might use them -- Built-in oracles - ## Visibility In Aztec there are multiple different types of visibility that can be applied to functions. Namely we have `data visibility` and `function visibility`. diff --git a/docs/docs/dev_docs/contracts/syntax/storage.md b/docs/docs/dev_docs/contracts/syntax/storage.md index f6f011c3f57..77ae0b61338 100644 --- a/docs/docs/dev_docs/contracts/syntax/storage.md +++ b/docs/docs/dev_docs/contracts/syntax/storage.md @@ -2,31 +2,12 @@ title: Storage --- -Smart contracts rely on storage, acting as the persistent memory on the blockchain. In Aztec, because of its privacy-first architecture, the management of this storage can be a bit more complex. - -You control this storage in Aztec using the 'Storage' struct. This struct serves as the housing unit for all your smart contract's state variables - the data it needs to keep track of and maintain. - -These state variables come in two forms: public and private. Public variables are visible to anyone, and private variables remain hidden within the contract. - -Aztec.nr has a few abstractions to help define the type of data your contract holds. These include Singletons, ImmutableSingletons, Set, and Map. - -On this page, you’ll learn: - -- How to manage a smart contract's storage structure -- The distinctions and applications of public and private state variables -- How to use Singleton, ImmutableSingleton, Set, and Map -- An overview of 'notes' and the UTXO model -- Practical implications of Storage in real smart contracts - In an Aztec.nr contract, storage is to be defined as a single struct, that contains both public and private state variables. - -## Public and private state variables +In an Aztec.nr contract, storage is contained in a single struct that contains both public and private state variables. Public state variables can be read by anyone, while private state variables can only be read by their owner (or people whom the owner has shared the decrypted data/note viewing key with). Public state follows the ethereum style account model, where each contract has its own key-value datastore. Private state follows a UTXO model, where note contents (pre-images) are only known by the sender and those able to decrypt them - see ([state model](./../../../concepts/foundation/state_model.md) and [private/public execution](./../../../concepts/foundation/communication/public_private_calls.md)) for more background. -## Storage struct - :::info The struct **must** be called `Storage` for the Aztec.nr library to properly handle it (this will be relaxed in the future). ::: diff --git a/docs/docs/dev_docs/limitations/main.md b/docs/docs/dev_docs/limitations/main.md index 44a8e565989..d55bb375404 100644 --- a/docs/docs/dev_docs/limitations/main.md +++ b/docs/docs/dev_docs/limitations/main.md @@ -12,6 +12,7 @@ The Aztec Sandbox and the Aztec Smart Contract Library are **prototypes**, and s - An 'unpolished' UX; - Missing information. + ## Why participate? Front-run the future! @@ -26,23 +27,22 @@ Help shape and define: - Core protocol improvements; ## Limitations developers need to know about - - It is a testing environment, it is insecure, unaudited and does not generate any proofs, its only for testing purposes; - Constructors can not call nor alter public state - - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [constructor](../contracts/syntax/functions.md#constructor). + - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [constructor](../contracts/syntax/functions.md#constructor). - No static nor delegate calls (see [mutability](../contracts/syntax/functions.md#mutability)). - - These values are unused in the call-context. + - These values are unused in the call-context. - Beware that what you think of as a `view` could alter state ATM! Notably the account could alter state or re-enter whenever the account contract's `is_valid` function is called. - `msg_sender` is currently leaking when doing private -> public calls - The `msg_sender` will always be set, if you call a public function from the private world, the `msg_sender` will be set to the private caller's address. See [function context](../contracts/syntax/context.mdx). - The initial `msg_sender` is 0, which can be problematic for some contracts, see [function visibility](../contracts/syntax/functions.md#function-visibility). -- Unencrypted logs don't link to the contract that emitted it, so essentially just a `debug_log`` that you can match values against. +- Unencrypted logs don't link to the contract that emitted it, so essentially just a `debug_log`` that you can match values against. - A note that is created and nullified in the same transaction will still emit an encrypted log. -- A limited amount of new commitments, nullifiers and calls that are supported by a transaction, see [circuit limitations](#circuit-limitations). +- A limited amount of new commitments, nullifiers and calls that are supported by a transaction, see [circuit limitations](#circuit-limitations). ## Limitations -There are plans to resolve all of the below. +There are plans to resolve all of the below. See also the [engineering roadmap](../../about_aztec/roadmap/engineering_roadmap.md). ### It is not audited @@ -72,7 +72,7 @@ Obviously, as development continues, the so-called 'circuits' will actually beco The Sandbox will execute more quickly. The logic of all 'circuits' is still in place*. Smart contract logic will be executed, and core protocol logic will be executed*. So invalid transactions will be caught\* and rejected. -\*Note: some core protocol circuit assertions and constraints still need to be written (see [GitHub](https://github.com/AztecProtocol/aztec-packages/issues)). This would be bad in an adversarial environment, but the Sandbox is not that. Naturally, proper circuits will need to be written. +\*Note: some core protocol circuit assertions and constraints still need to be written (see [GitHub](https://github.com/AztecProtocol/aztec-packages/issues)). This would be bad in an adversarial environment, but the Sandbox is not that. Naturally, proper circuits will need to be written - see the [engineering roadmap](../../about_aztec/roadmap/engineering_roadmap.md). ### No Fees! @@ -90,7 +90,7 @@ Apps won't yet be able to allow for any L2 fee logic. Once fees are introduced, The way in which keypairs and addresses are currently derived and implemented (inside the Sandbox) is greatly over-simplified, relative to future plans. -They're so over-simplified that they're known to be insecure. Other features have been prioritised so-far in Sandbox development. +They're so over-simplified that they're known to be insecure. Other features have been prioritised so-far in Sandbox development. Please refer to the [future roadmap](../../about_aztec/roadmap/engineering_roadmap.md) #### What are the consequences? @@ -130,7 +130,7 @@ A contract can't perform a delegatecall yet (if ever). Delegatecalls are quite a Ethereum has a notion of a 'full node' which keeps-up with the blockchain and stores the full chain state. Many users don't wish to run full nodes, so rely on 3rd-party 'full-node-as-a-service' infrastructure providers, who service blockchain queries from their users. -This pattern is likely to develop in Aztec as well, except there's a problem: privacy. If a privacy-seeking user makes a query to a 3rd-party 'full node', that user might leak data about who they are, or about their historic network activity, or about their future intentions. One solution to this problem is "always run a full node", but pragmatically, not everyone will. To protect less-advanced users' privacy, research is underway to explore how a privacy-seeking user may request and receive data from a 3rd-party node without revealing what that data is, nor who is making the request. +This pattern is likely to develop in Aztec as well, except there's a problem: privacy. If a privacy-seeking user makes a query to a 3rd-party 'full node', that user might leak data about who they are, or about their historic network activity, or about their future intentions. One solution to this problem is "always run a full node", but pragmatically, not everyone will. To protect less-advanced users' privacy, [research is underway](../../about_aztec/roadmap/engineering_roadmap.md) to explore how a privacy-seeking user may request and receive data from a 3rd-party node without revealing what that data is, nor who is making the request. ### No private data authentication @@ -209,7 +209,7 @@ Not only are there limits on a _per function_ basis, there are also limits on a **In particular, these _per-transaction_ limits will limit transaction call stack depths** in the Sandbox. That means if a function call results in a cascade of nested function calls, and each of those function calls outputs lots of state reads and writes, or logs (etc.), then all of that accumulated output data might exceed the per-transaction limits that we currently have. This would cause such transactions to fail. -There are plans to relax all of this rigidity, by providing many 'sizes' of [kernel circuit](../../concepts/advanced/circuits/kernels/main.md), and introducing a 'bus' to ferry varying lengths of data between kernel iterations. But that'll all take some time. +There are [plans](../../about_aztec/roadmap/engineering_roadmap.md#proper-circuits) to relax all of this rigidity, by providing many 'sizes' of [kernel circuit](../../concepts/advanced/circuits/kernels/main.md), and introducing a 'bus' to ferry varying lengths of data between kernel iterations. But that'll all take some time. > **In the mean time**, if you encounter a per-transaction limit when testing, and you're feeling adventurous, you could 'hack' the Sandbox to increase the limits. See here (TODO: link) for a guide. **However**, the limits cannot be increased indefinitely. So although we do anticipate that we'll be able to increase them a little bit, don't go mad and provide yourself with 1 million state transitions per transaction. That would be as unrealistic as artificially increasing Ethereum gas limits to 1 trillion. diff --git a/docs/docs/dev_docs/privacy/main.md b/docs/docs/dev_docs/privacy/main.md index 2633c0ae31f..7ba987daeaa 100644 --- a/docs/docs/dev_docs/privacy/main.md +++ b/docs/docs/dev_docs/privacy/main.md @@ -24,18 +24,22 @@ Emit encrypted events, or encrypted messages from a private smart contract funct Execute a private function without the world knowing which function you've executed. + + :::danger Privacy is not guaranteed without care. Although Aztec provides the tools for private smart contracts, information can still be leaked unless the dapp developer is careful. This page outlines some best practices to aid dapp developers. ::: + --- ## Leaky practices There are many caveats to the above. Since Aztec also enables interaction with the _public_ world (public L2 functions and L1 functions), private information can be accidentally leaked if developers aren't careful. + ### Crossing the private -> public boundary Any time a private function makes a call to a public function, information is leaked. Now, that might be perfectly fine in some use cases (it's up to the smart contract developer). Indeed, most interesting apps will require some public state. But let's have a look at some leaky patterns: @@ -47,10 +51,12 @@ Any time a private function makes a call to a public function, information is le - Emitting unencrypted events from a private function. The unencrypted event name and arguments will be publicly visible. - Sending L2->L1 messages from a private function. The entire message, and the resulting L1 function execution will all be publicly visible. + ### Crossing the public -> private boundary If a public function sends a message to be consumed by a private function, the act of consuming that message might be leaked if not following recommended patterns. See [here](../contracts/portals/inbox.md) for more details. + ### Timing of transactions Information about the nature of a transaction can be leaked based on the timing of that transaction. @@ -63,6 +69,7 @@ Suppose that every time Alice sends Bob a private token, 1 minute later a transa Tl;dr: app developers should think about the _timing_ of user transactions, and how this might leak information. + ### Function Fingerprints and Tx Fingerprints A 'Function Fingerprint' is any data which is exposed by a function to the outside world. A 'Tx Fingerprint' is any data which is exposed by a tx to the outside world. We're interested in minimising leakages of information from private txs. The leakiness of a Tx Fingerprint depends on the leakiness of its consituent functions' Function Fingerprints _and_ on the appearance of the tx's Tx Fingerprint as a whole. For a private function (and by extension, for a private tx), the following information _could_ be leaked (depending on the function, of course): @@ -75,7 +82,7 @@ A 'Function Fingerprint' is any data which is exposed by a function to the outsi - The contents of L2 -> L1 messages. - All unencrypted logs (topics and arguments). - The roots of all trees which have been read from. -- The _number_ of ['side effects'](): +- The _number_ of ['side effects'](https://en.wikipedia.org/wiki/Side_effect_(computer_science)): - \# new commitments - \# new nullifiers - \# bytes of encrypted logs @@ -83,14 +90,18 @@ A 'Function Fingerprint' is any data which is exposed by a function to the outsi - \# L2->L1 messages - \# nonzero roots[^1] + + > Note: many of these were mentioned in the ["Crossing the private -> public boundary"](#crossing-the-private---public-boundary) section. > Note: the calldata submitted to L1 is [encoded](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Decoder.sol) in such a way that all categories of data are packed together, when submitted. E.g. all commitments from all txs in a block are arranged as contiguous bytes of calldata. But that _doesn't_ mean the data from a particular tx is garbled in with all other txs' calldata: the distinct Tx Fingerprint of each tx can is publicly visible when a tx is submitted to the L2 tx pool. + #### Standardising Fingerprints If each private function were to have a unique Fingerprint, then all private functions would be distinguishable from each-other, and all of the efforts of the Aztec protocol to enable 'private function execution' would have been pointless. Standards need to be developed, to encourage smart contract developers to adhere to a restricted set of Tx Fingerprints. For example, a standard might propose that the number of new commitments, nullifiers, logs, etc. must always be equal, and must always equal a power of two. Such a standard would effectively group private functions/txs into 'privacy sets', where all functions/txs in a particular 'privacy set' would look indistinguishable from each-other, when executed. + ### Data queries It's not just the broadcasting of transactions to the network that can leak data. @@ -117,18 +128,20 @@ If a user runs their own node, there's no problem: they can query the latest sib But if a user is not running their own node, they would need to query the very-latest sibling path of their note(s) from some 3rd-party node. In order to query the sibling path of a leaf, the leaf's index needs to be provided as an argument. Revealing the leaf's index to a 3rd-party trivially reveals exactly the note(s) you're about to read. And since those notes were created in some prior transaction, the 3rd-party will be able to link you with that prior transaction. Suppose then that the 3rd-party also serviced the creator of said prior transaction: the 3rd-party will slowly be able to link more and more transactions, and gain more and more insight into a network which is meant to be private! -We're researching cryptographic ways to enable users to retrieve sibling paths from 3rd-parties without revealing leaf indices. +We're [researching](../../about_aztec/roadmap/engineering_roadmap.md) cryptographic ways to enable users to retrieve sibling paths from 3rd-parties without revealing leaf indices. > \* Note: due to the non-uniformity of Aztec transactions, the 'privacy set' of a transaction might not be the entire set of transactions that came before. See here (LINK). ##### Any query -Any query to a node leaks information to that node. +Any query to a node leaks information to that node. -We're researching cryptographic ways to enable users to query any data privately. +We're [researching](../../about_aztec/roadmap/engineering_roadmap.md) cryptographic ways to enable users to query any data privately. ---- + + +--- Footnotes -[^1]: All txs should set the kernel circuit public inputs for all roots to _valid_, _up-to-date_ nonzero values, so as to mask which trees have _actually_ been read from. The Sandbox will eventually automate this (see this [issue](https://github.com/AztecProtocol/aztec-packages/issues/1676)). +[^1]: All txs should set the kernel circuit public inputs for all roots to _valid_, _up-to-date_ nonzero values, so as to mask which trees have _actually_ been read from. The Sandbox will eventually automate this (see this [issue](https://github.com/AztecProtocol/aztec-packages/issues/1676)). \ No newline at end of file diff --git a/docs/docs/dev_docs/tutorials/main.md b/docs/docs/dev_docs/tutorials/main.md index c294167c9d2..da6889b6fc8 100644 --- a/docs/docs/dev_docs/tutorials/main.md +++ b/docs/docs/dev_docs/tutorials/main.md @@ -1,7 +1,3 @@ ---- -title: Tutorials ---- - import DocCardList from '@theme/DocCardList'; diff --git a/docs/docs/dev_docs/wallets/writing_an_account_contract.md b/docs/docs/dev_docs/wallets/writing_an_account_contract.md index b1f216b298c..96639cff70d 100644 --- a/docs/docs/dev_docs/wallets/writing_an_account_contract.md +++ b/docs/docs/dev_docs/wallets/writing_an_account_contract.md @@ -2,15 +2,6 @@ This tutorial will take you through the process of writing your own account contract in Noir, along with the Typescript glue code required for using it within a [wallet](./main.md). -You will learn: - -- How to write a custom account contract in Aztec.nr -- The entrypoint function for transaction authentication and call execution -- The AccountActions module and EntrypointPayload struct, necessary inclusions for any account contract -- Customizing authorization validation within the 'is_valid' function (using Schnorr signatures as an example) -- Typescript glue code to format and authenticate transactions -- Deploying and testing the account contract - Writing your own account contract allows you to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed (including key rotation and recovery). In other words, writing an account contract lets you make the most out of [account abstraction](../../concepts/foundation/accounts/main.md#what-is-account-abstraction) in the Aztec network. It is highly recommended that you understand how an [account](../../concepts/foundation/accounts/main.md) is defined in Aztec, as well as the differences between privacy and authentication [keys](../../concepts/foundation/accounts/keys.md). You will also need to know how to write a [contract in Noir](../contracts/main.md), as well as some basic [Typescript](https://www.typescriptlang.org/). @@ -55,8 +46,8 @@ The `AccountActions` module provides default implementations for most of the acc #include_code is-valid yarn-project/noir-contracts/src/contracts/schnorr_hardcoded_account_contract/src/main.nr rust -For our account contract, we will take the hash of the action to authorize, request the corresponding auth witness from the oracle, and validate it against our hardcoded public key. If the signature is correct, we authorize the action. +For our account contract, we will take the hash of the action to authorize, request the corresponding auth witness from the oracle, and validate it against our hardcoded public key. If the signature is correct, we authorize the action. ## The typescript side of things Now that we have a valid account contract, we need to write the typescript glue code that will take care of formatting and authenticating transactions so they can be processed by our contract, as well as deploying the contract during account setup. This takes the form of implementing the `AccountContract` interface: @@ -73,7 +64,7 @@ As you can see in the snippet above, to fill in this base class, we need to defi - The deployment arguments. - How to create an auth witness. -In our case, the auth witness will be generated by Schnorr-signing over the message identifier using the hardcoded key. To do this, we are using the `Schnorr` signer from the `@aztec/circuits.js` package to sign over the payload hash. This signer maps to exactly the same signing scheme that Noir's standard library expects in `schnorr::verify_signature`. +In our case, the auth witness will be generated by Schnorr-signing over the message identifier using the hardcoded key. To do this, we are using the `Schnorr` signer from the `@aztec/circuits.js` package to sign over the payload hash. This signer maps to exactly the same signing scheme that Noir's standard library expects in `schnorr::verify_signature`. :::info More signing schemes are available in case you want to experiment with other types of keys. Check out Noir's [documentation on cryptographic primitives](https://noir-lang.org/standard_library/cryptographic_primitives). diff --git a/docs/netlify.toml b/docs/netlify.toml index 11f2bc45c62..319a61df5e0 100644 --- a/docs/netlify.toml +++ b/docs/netlify.toml @@ -98,6 +98,10 @@ from = "/aztec/cryptography/cryptography-roadmap" to = "/about_aztec/roadmap/cryptography_roadmap" +[[redirects]] + from = "/aztec/milestones" + to = "/about_aztec/roadmap/engineering_roadmap" + [[redirects]] from = "/aztec/milestones/features-initial-ldt" to = "/about_aztec/roadmap/features_initial_ldt" From 3c03445c44e3ccd81345d7a7c13b898475ebcbbe Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Sun, 22 Oct 2023 16:50:09 +0100 Subject: [PATCH 16/33] accidental change From 2d5a3e2aeb2aaf895ea2baec669daa20485cfd13 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Sun, 22 Oct 2023 16:51:35 +0100 Subject: [PATCH 17/33] accidental change From b5cb9a4b49f48b8d3ac50a34b41d1c9d15970521 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Mon, 23 Oct 2023 14:35:59 -0400 Subject: [PATCH 18/33] minor edits to quickstart --- docs/docs/dev_docs/getting_started/quickstart.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/dev_docs/getting_started/quickstart.md b/docs/docs/dev_docs/getting_started/quickstart.md index feaa1611c45..4c9625f6320 100644 --- a/docs/docs/dev_docs/getting_started/quickstart.md +++ b/docs/docs/dev_docs/getting_started/quickstart.md @@ -46,7 +46,7 @@ The default accounts that come with sandbox will likely change over time. Save t #include_code declare-accounts yarn-project/end-to-end/src/guides/up_quick_start.sh bash -Start by deploying a token contract. After it is deployed, we check that the deployment succeeded, export the deployment address to use in future commands and then call the `_initialize` function. For more detail on how the token contract works, see the [token contract tutorial](../tutorials/writing_token_contract.md). +Start by deploying a token contract. After it is deployed, we check that the deployment succeeded, and export the deployment address to use in future commands. For more detail on how the token contract works, see the [token contract tutorial](../tutorials/writing_token_contract.md). #include_code deploy yarn-project/end-to-end/src/guides/up_quick_start.sh bash @@ -56,7 +56,7 @@ Note that the deployed contract address is exported, so we can use it as `$CONTR Alice is set up as the contract admin and token minter in the `_initialize` function. Let's get Alice some private tokens. -We need to export the `SECRET` and `SECRET_HASH` values in order to privately mint tokens. Private tokens are claimable by anyone with the pre-image to a provided hash, see more about how the token contract works in the [token contract tutorial](../tutorials/writing_token_contract.md). After the tokens have been minted, the notes will have to added to the PXE to be consumed by private functions. Once added, Alice can claim them with the `redeem_shield` function. After this, Alice should have 1000 tokens in their private balance. +We need to export the `SECRET` and `SECRET_HASH` values in order to privately mint tokens. Private tokens are claimable by anyone with the pre-image to a provided hash, see more about how the token contract works in the [token contract tutorial](../tutorials/writing_token_contract.md). After the tokens have been minted, the notes will have to added to the [Private Execution Environment](../../apis/pxe/interfaces/PXE) (PXE) to be consumed by private functions. Once added, Alice can claim them with the `redeem_shield` function. After this, Alice should have 1000 tokens in their private balance. #include_code mint-private yarn-project/end-to-end/src/guides/up_quick_start.sh bash From 3c5bfaf81c2a9bc3f8e6f069e5c618f79f99ce29 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Mon, 23 Oct 2023 14:43:53 -0400 Subject: [PATCH 19/33] small edit --- docs/docs/dev_docs/getting_started/aztecjs-getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md b/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md index 70b63594a9f..e7be7d00720 100644 --- a/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md +++ b/docs/docs/dev_docs/getting_started/aztecjs-getting-started.md @@ -151,7 +151,7 @@ Great! The Sandbox is running and we are able to interact with it. ## Load accounts -The sandbox is preloaded with multiple accounts so you don't have to sit and create them. Let's load these accounts +The sandbox is preloaded with multiple accounts so you don't have to sit and create them. Let's load these accounts. Add this code to the `main()` function in `index.ts` below the code that's there: #include_code load_accounts /yarn-project/end-to-end/src/e2e_sandbox_example.test.ts typescript From 85ce60b8ffa5b82527257006d98c1bccb9b05df1 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Thu, 26 Oct 2023 16:00:35 +0100 Subject: [PATCH 20/33] include_code macro --- docs/docs/dev_docs/cli/sandbox-reference.md | 4 +- docs/docs/dev_docs/cli/updating.md | 37 +++++- docs/docs/dev_docs/contracts/compiling.md | 16 +-- docs/docs/dev_docs/contracts/deploying.md | 65 ++++++---- docs/docs/dev_docs/contracts/setup.md | 4 +- .../aztecnr-getting-started.md | 116 +++++------------- docs/docs/dev_docs/tutorials/testing.md | 2 +- .../dev_docs/tutorials/writing_dapp/main.md | 2 +- .../tutorials/writing_dapp/pxe_service.md | 2 +- .../wallets/creating_schnorr_accounts.md | 2 +- docs/sidebars.js | 12 +- .../end-to-end/src/cli_docs_sandbox.test.ts | 5 +- .../src/contracts/counter_contract/Nargo.toml | 10 ++ .../contracts/counter_contract/src/main.nr | 79 ++++++++++++ 14 files changed, 224 insertions(+), 132 deletions(-) create mode 100644 yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml create mode 100644 yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr diff --git a/docs/docs/dev_docs/cli/sandbox-reference.md b/docs/docs/dev_docs/cli/sandbox-reference.md index f39ff74f2e8..c29d89dd81f 100644 --- a/docs/docs/dev_docs/cli/sandbox-reference.md +++ b/docs/docs/dev_docs/cli/sandbox-reference.md @@ -44,7 +44,7 @@ cd ~/.aztec && docker-compose up ## Otterscan -If you have set up the Sandbox with Docker, you will also have Ottescan. +If you have set up the Sandbox with Docker, you will also have Otterscan. You can see Ethereum Layer 1 activity through the local Otterscan on [`http://localhost:5100`](`http://localhost:5100`). This is especially useful for dapps that use L1-L2 messaging through [portal contracts](../contracts/portals/main.md). @@ -58,7 +58,7 @@ You can find the cheat code reference [here](../testing/cheat_codes.md). ## Contracts -We have shipped a number of example contracts in the `@aztec/noir-contracts` npm package. This is included with the cli by default so you are able to use these contracts to test with. To get a list of the names of the contracts run: +We have shipped a number of example contracts in the `@aztec/noir-contracts` [npm package](https://www.npmjs.com/package/@aztec/noir-contracts). This is included with the cli by default so you are able to use these contracts to test with. To get a list of the names of the contracts run: ```bash title="example-contracts" showLineNumbers % aztec-cli example-contracts diff --git a/docs/docs/dev_docs/cli/updating.md b/docs/docs/dev_docs/cli/updating.md index 4d5291b3c3f..1c89e61ada3 100644 --- a/docs/docs/dev_docs/cli/updating.md +++ b/docs/docs/dev_docs/cli/updating.md @@ -1,7 +1,38 @@ --- -title: Staying Updated +title: Updating --- +## Quick Reference + +- Aztec Sandbox + +```shell + /bin/bash -c "$(curl -fsSL 'https://sandbox.aztec.network')" +``` + +- Aztec CLI + +```shell +npm install -g @aztec/cli +``` + +- nargo + +```shell +noirup +``` + +- Aztec.nr + +```toml +#nargo.toml +[dependencies] +aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="#include_aztec_version", directory="yarn-project/aztec-nr/aztec" } +value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="#include_aztec_version", directory="yarn-project/aztec-nr/value-note" } +``` + +Read on to learn about versioning and other commands. + There are 4 components whose versions need to be kept compatible: 1. Aztec Sandbox, @@ -41,6 +72,10 @@ Setting up Aztec Sandbox v#include_aztec_short_version (nargo #include_noir_vers Alternatively you can open a new terminal and use aztec-cli to get the version. +#include_code node-info-command yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +This will return something like this: + #include_code node-info yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash The sandbox version should be the same as the one we chose by setting the `SANDBOX_VERSION` environmental variable. diff --git a/docs/docs/dev_docs/contracts/compiling.md b/docs/docs/dev_docs/contracts/compiling.md index 78a871a76c1..8ac693510cc 100644 --- a/docs/docs/dev_docs/contracts/compiling.md +++ b/docs/docs/dev_docs/contracts/compiling.md @@ -123,13 +123,13 @@ export class TokenContract extends ContractBase { nonce: FieldLike, ) => ContractFunctionInteraction) & Pick; - + ... }; } ``` -Read more about interacting with contracts using `aztec.js` [here](../getting_started/sandbox.md). +Read more about interacting with contracts using `aztec.js` [here](../getting_started/aztecjs-getting-started.md). ### Aztec.nr interfaces @@ -158,7 +158,7 @@ impl TokenPrivateContextInterface { address, } } - + pub fn burn( self, context: &mut PrivateContext, @@ -173,7 +173,7 @@ impl TokenPrivateContextInterface { context.call_private_function(self.address, 0xd4fcc96e, serialized_args) } - + pub fn burn_public( self, @@ -190,7 +190,7 @@ impl TokenPrivateContextInterface { context.call_public_function(self.address, 0xb0e964d5, serialized_args) } ... - + } impl TokenPublicContextInterface { @@ -199,7 +199,7 @@ impl TokenPublicContextInterface { address, } } - + pub fn burn_public( self, context: PublicContext, @@ -214,7 +214,7 @@ impl TokenPublicContextInterface { context.call_public_function(self.address, 0xb0e964d5, serialized_args) } - + pub fn mint_private( self, @@ -229,7 +229,7 @@ impl TokenPublicContextInterface { context.call_public_function(self.address, 0x10763932, serialized_args) } - + } ``` diff --git a/docs/docs/dev_docs/contracts/deploying.md b/docs/docs/dev_docs/contracts/deploying.md index 07c0f00586c..6830a1fc314 100644 --- a/docs/docs/dev_docs/contracts/deploying.md +++ b/docs/docs/dev_docs/contracts/deploying.md @@ -3,14 +3,14 @@ Once you have [compiled](./compiling.md) your contracts you can proceed to deploying them using the aztec-cli or using aztec.js which is a Typescript client to interact with the sandbox. ## Prerequisites + - aztec-cli installed (go to [CLI main section](../cli/main.md) for installation instructions) - contract artifacts ready (go to [Compiling contracts section](./compiling.md) for instructions on how to compile contracts) -- aztec-sandbox running (go to [Sandbox section](../getting_started/sandbox.md) for instructions on how to install and run the sandbox) +- aztec-sandbox running (go to [Sandbox section](../getting_started/quickstart.md) for instructions on how to install and run the sandbox) ## Deploy -Contracts can be deployed using the `aztec-cli` or using the `aztec.js` library. - +Contracts can be deployed using the `aztec-cli` or using the `aztec.js` library. import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -28,28 +28,43 @@ aztec-cli deploy /path/to/contract/artifact.json Pre-requisite - Generate type-safe typescript classes for your contract when compiling using the `@aztec/noir-compiler` package. You can install the package by running `npm install @aztec/noir-compiler`. ```ts -import { readFileSync, writeFileSync } from 'fs'; -import { compileUsingNargo, generateTypescriptContractInterface} from '@aztec/noir-compiler'; - -const compiled: ContractArtifact[] = await compileUsingNargo(projectPathToContractFolder); +import { readFileSync, writeFileSync } from "fs"; +import { + compileUsingNargo, + generateTypescriptContractInterface, +} from "@aztec/noir-compiler"; + +const compiled: ContractArtifact[] = await compileUsingNargo( + projectPathToContractFolder +); const abiImportPath = "../target/Example.json"; -writeFileSync(tsInterfaceDestFilePath, generateTypescriptContractInterface(compiled[0], abiImportPath)); +writeFileSync( + tsInterfaceDestFilePath, + generateTypescriptContractInterface(compiled[0], abiImportPath) +); ``` + This would create a typescript file like `Example.ts` in the path specified. More details in the [compiling page](./compiling.md) Now you can import it to easily deploy and interact with the contract. + ```ts -import { ExampleContract } from './Example.js'; +import { ExampleContract } from "./Example.js"; const tx = ExampleContract.deploy(pxe).send(); await tx.wait({ interval: 0.5 }); const receipt = await tx.getReceipt(); -const exampleContract = await ExampleContract.at(receipt.contractAddress!, myWallet); +const exampleContract = await ExampleContract.at( + receipt.contractAddress!, + myWallet +); ``` + ### Deploy Arguments + There are several optional arguments that can be passed: @@ -57,13 +72,14 @@ There are several optional arguments that can be passed: `aztec-cli deploy` takes 1 mandatory argument which is the path to the contract artifact file in a JSON format (e.g. `contracts/target/PrivateToken.json`). Alternatively you can pass the name of an example contract as exported by `@aztec/noir-contracts` (run `aztec-cli example-contracts` to see the full list of contracts available). The command also takes the following optional arguments: + - `-args ` (default: `[]`): Arguments to pass to the contract constructor. - `--rpc-url ` (default: `http://localhost:8080`): URL of the PXE to connect to. - `--public-key ` (default: `undefined`): Optional encryption public key for this contract. -Set this only if this contract is expected to receive private notes (in such a case the public key is used during the note encryption). + Set this only if this contract is expected to receive private notes (in such a case the public key is used during the note encryption). - `--salt ` (default: random value): Hexadecimal string used when computing the contract address of the contract being deployed. -By default is set to a random value. -Set it, if you need a deterministic contract address (same functionality as Ethereum's `CREATE2` opcode). + By default is set to a random value. + Set it, if you need a deterministic contract address (same functionality as Ethereum's `CREATE2` opcode). @@ -72,15 +88,16 @@ The `deploy(...)` method is generated automatically with the typescript class re Its arguments are `PXE` client and contract constructor arguments. Additionally the `.send()` method can have a few optional arguments too, which are specified in an optional object: + - `portalContract?: EthAddress`: The L1 portal address to link the contract to. See the section on [Portals to learn more about them](./portals/main.md). -- `contractAddressSalt?: Fr`: A salt which is one of the inputs when computing a contract address of the contract to be deployed. -By default is set to a random value. -Set it, if you need a deterministic contract address (same functionality as Ethereum's `CREATE2` opcode). +- `contractAddressSalt?: Fr`: A salt which is one of the inputs when computing a contract address of the contract to be deployed. + By default is set to a random value. + Set it, if you need a deterministic contract address (same functionality as Ethereum's `CREATE2` opcode). ```ts -const tx = ExampleContract.deploy(pxe).send({ - portalContract: EthAddress.from("0x1234..."), - contractAddressSalt: new Fr(3n), +const tx = ExampleContract.deploy(pxe).send({ + portalContract: EthAddress.from("0x1234..."), + contractAddressSalt: new Fr(3n), }); ``` @@ -88,6 +105,7 @@ const tx = ExampleContract.deploy(pxe).send({ ### Deploying token contract + To give you a more complete example we will deploy a `Token` contract whose artifacts are included in the `@aztec/noir-contracts` package. The contract has `admin` as a constructor argument. @@ -104,7 +122,9 @@ aztec-cli deploy TokenContractArtifact --args 0x147392a39e593189902458f4303bc6e0 ```ts -const admin = AztecAddress.from("0x147392a39e593189902458f4303bc6e0a39128c5a1c1612f76527a162d36d529"); +const admin = AztecAddress.from( + "0x147392a39e593189902458f4303bc6e0a39128c5a1c1612f76527a162d36d529" +); // TokenContract is the TS interface that is automatically generated when compiling the contract with the `-ts` flag. const contract = await TokenContract.deploy(wallet, admin).send().deployed(); logger(`Contract deployed at ${contract.address}`); @@ -114,6 +134,7 @@ logger(`Contract deployed at ${contract.address}`); If everything went as expected you should see the following output (with a different address): + > Contract deployed at `0x151de6120ae6628129ee852c5fc7bcbc8531055f76d4347cdc86003bbea96906` If we pass the salt as an argument: @@ -129,7 +150,9 @@ aztec-cli deploy TokenContractArtifact --args 0x147392a39e593189902458f4303bc6e0 ```ts -const contract = await TokenContract.deploy(wallet, admin).send({ contractAddressSalt: Fr.fromString("0x123") }).deployed(); +const contract = await TokenContract.deploy(wallet, admin) + .send({ contractAddressSalt: Fr.fromString("0x123") }) + .deployed(); ``` diff --git a/docs/docs/dev_docs/contracts/setup.md b/docs/docs/dev_docs/contracts/setup.md index 0501e90195e..ac36119d759 100644 --- a/docs/docs/dev_docs/contracts/setup.md +++ b/docs/docs/dev_docs/contracts/setup.md @@ -22,13 +22,13 @@ Nargo is Noir's build tool. On your terminal, run: #### Aztec Sandbox -You need to setup the [Aztec sandbox](../getting_started/sandbox.md). +You need to setup the [Aztec sandbox](../getting_started/quickstart.md). ## Set up for aztec.nr contracts -1. Inside the yarn project you created from the [Sanbox page](../getting_started/sandbox.md), create a sub-folder where the contracts will reside. +1. Inside the yarn project you created from the [Sanbox page](../getting_started/quickstart.md), create a sub-folder where the contracts will reside. ```bash mkdir contracts diff --git a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md b/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md index 4d8e2826105..041f493d3fa 100644 --- a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md +++ b/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md @@ -89,59 +89,29 @@ compiler_version = "0.16.0" Add the following dependencies under `[dependencies]`: ```toml -aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="master", directory="yarn-project/noir-libs/aztec-noir" } -value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="master", directory="yarn-project/noir-libs/value-note"} -easy_private_state = { git="https://github.com/AztecProtocol/aztec-packages", tag="master", directory="yarn-project/noir-libs/easy-private-state"} +aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="#include_aztec_version", directory="yarn-project/aztec-nr/aztec" } +value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="#include_aztec_version", directory="yarn-project/aztec-nr/value-note"} +easy_private_state = { git="https://github.com/AztecProtocol/aztec-packages", tag="#include_aztec_version", directory="yarn-project/aztec-nr/easy-private-state"} ``` ## Define the functions -Go to `main.nr` and replace the code with this contract and functions: +Go to `main.nr` and replace the code with this contract initialization: ```rust contract Counter { - #[aztec(private)] - fn constructor(initial_count: u120, owner: Field) {} - - #[aztec(private)] - fn increment(owner: Field) {} - - unconstrained fn getCounter(owner: Field) -> Field { - 0 - } } ``` -This code defines a contract called `Counter` with four functions that we will implement later - a `constructor` which is called when the contract is deployed, `increment`, and `getCounter`. - -We have annotated the functions with `#[aztec(private)]` which are ABI macros so the compiler understands it will handle private inputs. Learn more about functions and annotations [here](../contracts/syntax/functions.md). - -The `getCounter` function doesn’t need this as it will only be reading from the chain, not updating state, similar to a `view` function in Solidity. This is what `unconstrained` means. +This defines a contract called `Counter`. ## Imports We need to define some imports. -Write this within your contract at the top: +Write this within your contract at the top -```rust - use dep::aztec::{ - context::{PrivateContext, Context}, - note::{ - note_header::NoteHeader, - utils as note_utils, - }, - state_vars::map::Map, - }; - use dep::value_note::{ - balance_utils, - value_note::{ - ValueNoteMethods, - VALUE_NOTE_LEN, - }, - }; - use dep::easy_private_state::easy_private_state::EasyPrivateUint; -``` +#include_code imports /yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr rust `context::{PrivateContext, Context}` @@ -165,29 +135,11 @@ This allows us to store our counter in a way that acts as an integer, abstractin In this step, we will initiate a `Storage` struct to store balances in a private way. The vast majority Aztec.nr smart contracts will need this. -```rust -struct Storage { - counts: Map, - } -``` +#include_code storage_struct /yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr rust We are only storing one variable - `counts` as a `Map` of `EasyPrivateUint`. This means our `count` will act as a private integer, and we can map it to an address. -```rust -impl Storage { - fn init(context: Context) -> pub Self { - Storage { - counters: Map::new( - context, - 1, - |context, slot| { - EasyPrivateUint::new(context, slot) - }, - ), - } - } - } -``` +#include_code storage_init /yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr rust This `init` method is creating and initializing a `Storage` instance. This instance includes a `Map` named `counters`. Each entry in this `Map` represents an account's counter. @@ -197,27 +149,17 @@ Now we’ve got a mechanism for storing our private state, we can start using it Let’s create a `constructor` method to run on deployment that assigns an initial supply of tokens to a specified owner. In the constructor we created in the first step, write this: -```rust - #[aztec(private)] - fn constructor(initial_counter: u120, owner: Field) { - let counts = storage.counts; - counts.at(owner).add(headstart, owner); - } -``` +#include_code constructor /yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr rust This function accesses the counts from storage. Then it assigns the passed initial counter to the `owner`'s counter privately using `at().add()`. +We have annotated this and other functions with `#[aztec(private)]` which are ABI macros so the compiler understands it will handle private inputs. Learn more about functions and annotations [here](../contracts/syntax/functions.md). + ## Incrementing our counter Now let’s implement the `increment` functio we defined in the first step. -```rust - #[aztec(private)] - fn increment(owner: Field) { - let couners = storage.counters; - counters.at(owner).add(1, owner); - } -``` +#include_code increment /yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr rust The `increment` function works very similarly to the `constructor`, but instead directly adds 1 to the counter rather than passing in an initial count parameter. @@ -227,17 +169,7 @@ Because our counters are private, the network can't directly verify if a note wa Add a new function into your contract as shown below: -```rust -unconstrained fn compute_note_hash_and_nullifier( - contract_address: Field, - nonce: Field, - storage_slot: Field, - preimage: [Field; VALUE_NOTE_LEN], -) -> [Field; 4] { - let note_header = NoteHeader { contract_address, nonce, storage_slot }; - note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, preimage) -} -``` +#include_code nullifier /yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr rust Here, we're computing both the note hash and the nullifier. The nullifier computation uses Aztec’s `compute_note_hash_and_nullifier` function, which takes details about the note's attributes eg contract address, nonce, storage slot, and preimage. @@ -245,12 +177,7 @@ Here, we're computing both the note hash and the nullifier. The nullifier comput The last thing we need to implement is the function in order to retrieve a counter. In the `getCounter` we defined in the first step, write this: -```rust -unconstrained fn get_counter(owner: Field) -> Field { - let counts = storage.counters; - balance_utils::get_balance(counters.at(owner).set) -} -``` +#include_code get_counter /yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr rust This function is `unconstrained` which allows us to fetch data from storage without a transaction. We retrieve a reference to the `owner`'s `counter` from the `counters` Map. The `get_balance` function then operates on the owner's counter. This yields a private counter that only the private key owner can decrypt. @@ -283,7 +210,20 @@ aztec-cli get-accounts This will return something like this: ```bash +➜ counter aztec-cli get-accounts +Accounts found: + +Address: 0x25048e8c1b7dea68053d597ac2d920637c99523651edfb123d0632da785970d0 +Public Key: 0x27c20118733174347b8082f578a7d8fb84b3ad38be293715eee8119ee5cd8a6d0d6b7d8124b37359663e75bcd2756f544a93b821a06f8e33fba68cc8029794d9 +Partial Address: 0x077fed6015ea2e4aabfd566b16d9528e79dc0f1d8573716a3f4de1f02962e8c9 + +Address: 0x115f123bbc6cc6af9890055821cfba23a7c4e8832377a32ccb719a1ba3a86483 +Public Key: 0x08145e8e8d46f51cda8d4c9cad81920236366abeafb8d387002bad879a3e87a81570b04ac829e4c007141d856d5a36d3b9c464e0f3c1c99cdbadaa6bb93f3257 +Partial Address: 0x092908a7140034c7add7f2fac103abc41bedd5474cf09b1c9c16e5331282de77 +Address: 0x0402655a1134f3f248e9f2032c27b26d2c3ab57eaab3189541895c13f3622eba +Public Key: 0x13e6151ea8e7386a5e7c4c5221047bf73d0b1b7a2ad14d22b7f73e57c1fa00c614bc6da69da1b581b09ee6cdc195e5d58ae4dce01b63bbb744e58f03855a94dd +Partial Address: 0x211edeb823ef3e042e91f338d0d83d0c90606dba16f678c701d8bb64e64e2be5 ``` Use one of these `address`es as the `owner`. You can either copy it or export. diff --git a/docs/docs/dev_docs/tutorials/testing.md b/docs/docs/dev_docs/tutorials/testing.md index bc6275ea0ee..aca41afc899 100644 --- a/docs/docs/dev_docs/tutorials/testing.md +++ b/docs/docs/dev_docs/tutorials/testing.md @@ -8,7 +8,7 @@ We will be using typescript to write our tests, and rely on the [`aztec.js`](htt ## A simple example -Let's start with a simple example for a test using the [Sandbox](../getting_started/sandbox.md#install-the-sandbox). We will create two accounts and deploy a token contract in a setup step, and then issue a transfer from one user to another. +Let's start with a simple example for a test using the [Sandbox](../cli/sandbox-reference.md). We will create two accounts and deploy a token contract in a setup step, and then issue a transfer from one user to another. #include_code sandbox-example /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript diff --git a/docs/docs/dev_docs/tutorials/writing_dapp/main.md b/docs/docs/dev_docs/tutorials/writing_dapp/main.md index e62d4730127..95cedf910bb 100644 --- a/docs/docs/dev_docs/tutorials/writing_dapp/main.md +++ b/docs/docs/dev_docs/tutorials/writing_dapp/main.md @@ -12,7 +12,7 @@ The full code for this tutorial is [available on the `aztec-packages` repository - Linux or OSX environment - [NodeJS](https://nodejs.org/) 18 or higher -- [Aztec Sandbox](../../getting_started/sandbox.md) +- [Aztec Sandbox](../../getting_started/quickstart.md) - [Aztec CLI](../../cli/main.md) - [Nargo](../../contracts/setup.md) for building contracts diff --git a/docs/docs/dev_docs/tutorials/writing_dapp/pxe_service.md b/docs/docs/dev_docs/tutorials/writing_dapp/pxe_service.md index 9d75d1f4a98..38a54700c6a 100644 --- a/docs/docs/dev_docs/tutorials/writing_dapp/pxe_service.md +++ b/docs/docs/dev_docs/tutorials/writing_dapp/pxe_service.md @@ -4,7 +4,7 @@ PXE is a component of the Aztec Protocol that provides a private execution envir As an app developer, the [PXE](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/pxe) interface provides you with access to the user's accounts and their private state, as well as a connection to the network for accessing public global state. -During the Sandbox phase, this role is fulfilled by the [Aztec Sandbox](../../getting_started/sandbox.md), which runs a local PXE and an Aztec Node, both connected to a local Ethereum development node like Anvil. +During the Sandbox phase, this role is fulfilled by the [Aztec Sandbox](../../cli/sandbox-reference.md), which runs a local PXE and an Aztec Node, both connected to a local Ethereum development node like Anvil. The Sandbox also includes a set of pre-initialized accounts that you can use from your app. In this section, we'll connect to the Sandbox from our project. diff --git a/docs/docs/dev_docs/wallets/creating_schnorr_accounts.md b/docs/docs/dev_docs/wallets/creating_schnorr_accounts.md index 7b0a43c0a54..d3bda7700f1 100644 --- a/docs/docs/dev_docs/wallets/creating_schnorr_accounts.md +++ b/docs/docs/dev_docs/wallets/creating_schnorr_accounts.md @@ -13,7 +13,7 @@ An in-depth explaining about accounts on aztec can be found [here](../../concept ## Pre-requisites -Have a running Sandbox and a repository that interacts with it as explained [here](../getting_started/sandbox.md). +Have a running Sandbox and a repository that interacts with it as explained [here](../getting_started/quickstart.md). Let's assume you have a file `src/index.ts` from the example used in the Sandbox page. diff --git a/docs/sidebars.js b/docs/sidebars.js index 40d0d21df69..ad1f4cc3832 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -273,11 +273,7 @@ const sidebars = { type: "doc", id: "dev_docs/cli/main", }, - items: [ - "dev_docs/cli/cli-commands", - "dev_docs/cli/sandbox-reference", - "dev_docs/cli/updating", - ], + items: ["dev_docs/cli/cli-commands", "dev_docs/cli/sandbox-reference"], }, { label: "Aztec.nr Contracts", @@ -369,6 +365,12 @@ const sidebars = { id: "dev_docs/aztecjs/main", }, + { + label: "Updating", + type: "doc", + id: "dev_docs/cli/updating", + }, + { label: "Testing", type: "category", diff --git a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts index 8a4af3d7c4b..36bccf833c7 100644 --- a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts +++ b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts @@ -26,8 +26,11 @@ describe('CLI docs sandbox', () => { const waitForSandboxWithCli = async () => { const docs = ` +// docs:start:node-info-command +aztec-cli get-node-info +// docs:end:node-info-command + // docs:start:node-info -% aztec-cli get-node-info Node Info: Sandbox Version: #include_aztec_short_version diff --git a/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml b/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml new file mode 100644 index 00000000000..c59406f6e86 --- /dev/null +++ b/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml @@ -0,0 +1,10 @@ +[package] +name = "counter_contract" +type = "bin" +authors = [""] +compiler_version = "0.1" + +[dependencies] +aztec = { path = "../../../../aztec-nr/aztec" } +value_note = { path = "../../../../aztec-nr/value-note" } +easy_private_state = { path = "../../../../aztec-nr/easy-private-state"} \ No newline at end of file diff --git a/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr new file mode 100644 index 00000000000..044c17a76a9 --- /dev/null +++ b/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr @@ -0,0 +1,79 @@ +contract Counter { +// docs:start:imports + use dep::aztec::{ + context::{PrivateContext, Context}, + note::{ + note_header::NoteHeader, + utils as note_utils, + }, + state_vars::map::Map, + }; + use dep::value_note::{ + balance_utils, + value_note::{ + ValueNoteMethods, + VALUE_NOTE_LEN, + }, + }; + use dep::easy_private_state::easy_private_state::EasyPrivateUint; +// docs:end:imports + +// docs:start:storage_struct + + struct Storage { + counters: Map, + } + +// docs:end:storage_struct + +// docs:start:storage_init + impl Storage { + fn init(context: Context) -> pub Self { + Storage { + counters: Map::new( + context, + 1, + |context, slot| { + EasyPrivateUint::new(context, slot) + }, + ), + } + } + } +// docs:end:storage_init + +// docs:start:constructor + #[aztec(private)] + fn constructor(headstart: u120, owner: Field) { + let counters = storage.counters; + counters.at(owner).add(headstart, owner); + } +// docs:end:constructor + +// docs:start:increment + #[aztec(private)] + fn increment(owner: Field) { + let couners = storage.counters; + counters.at(owner).add(1, owner); + } +// docs:end:increment + +// docs:start:get_counter + unconstrained fn get_counter(owner: Field) -> Field { + let counters = storage.counters; + balance_utils::get_balance(counters.at(owner).set) + } +// docs:end:get_counter + +// docs:start:nullifier + unconstrained fn compute_note_hash_and_nullifier( + contract_address: Field, + nonce: Field, + storage_slot: Field, + preimage: [Field; VALUE_NOTE_LEN], + ) -> [Field; 4] { + let note_header = NoteHeader::new(contract_address, nonce, storage_slot); + note_utils::compute_note_hash_and_nullifier(ValueNoteMethods, note_header, preimage) + } +// docs:end:nullifier +} \ No newline at end of file From 81b9d2f2b70203f6a644aca8fc78bb2f54c470de Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Thu, 26 Oct 2023 21:55:17 +0100 Subject: [PATCH 21/33] boxes reference --- docs/docs/dev_docs/{getting_started => cli}/blank_box.md | 0 docs/docs/dev_docs/cli/sandbox-reference.md | 2 +- .../noir-contracts/src/contracts/counter_contract/Nargo.toml | 2 +- .../noir-contracts/src/contracts/counter_contract/src/main.nr | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename docs/docs/dev_docs/{getting_started => cli}/blank_box.md (100%) diff --git a/docs/docs/dev_docs/getting_started/blank_box.md b/docs/docs/dev_docs/cli/blank_box.md similarity index 100% rename from docs/docs/dev_docs/getting_started/blank_box.md rename to docs/docs/dev_docs/cli/blank_box.md diff --git a/docs/docs/dev_docs/cli/sandbox-reference.md b/docs/docs/dev_docs/cli/sandbox-reference.md index c29d89dd81f..b5799f5ddb5 100644 --- a/docs/docs/dev_docs/cli/sandbox-reference.md +++ b/docs/docs/dev_docs/cli/sandbox-reference.md @@ -93,4 +93,4 @@ You can see all of our example contracts in the monorepo [here](https://github.c The sandbox is shipped with full-stack Aztec project templates, with example Aztec.nr contracts, testing scripts, and web interfaces. -You can read more information about how to use boxes [here](TODO) +You can read more information about how to use boxes [here](./blank_box.md) diff --git a/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml b/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml index c59406f6e86..e50f871bd06 100644 --- a/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml +++ b/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml @@ -1,8 +1,8 @@ [package] name = "counter_contract" -type = "bin" authors = [""] compiler_version = "0.1" +type = "contract" [dependencies] aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr index 044c17a76a9..18836e71827 100644 --- a/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/counter_contract/src/main.nr @@ -53,7 +53,7 @@ contract Counter { // docs:start:increment #[aztec(private)] fn increment(owner: Field) { - let couners = storage.counters; + let counters = storage.counters; counters.at(owner).add(1, owner); } // docs:end:increment From 57c7c33acc42a029295b756c102b0a1335ca6e22 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Thu, 26 Oct 2023 21:55:48 +0100 Subject: [PATCH 22/33] Update docs/docs/dev_docs/cli/updating.md Co-authored-by: josh crites --- docs/docs/dev_docs/cli/updating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev_docs/cli/updating.md b/docs/docs/dev_docs/cli/updating.md index 1c89e61ada3..c23a322c922 100644 --- a/docs/docs/dev_docs/cli/updating.md +++ b/docs/docs/dev_docs/cli/updating.md @@ -112,7 +112,7 @@ Then we install the `Compatible Nargo Version` with (replace `COMPATIBLE_NARGO_V noirup -v COMPATIBLE_NARGO_VERSION ``` -## Updating Noir framework +## Updating Aztec.nr packages Finally we need to update the Noir framework for Aztec contracts. We need to install a version compatible with our `nargo` and Sandbox. From 22ca5b083e98bac31c7361879d0142514b699343 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Thu, 26 Oct 2023 22:01:07 +0100 Subject: [PATCH 23/33] .test.cpp From 49b1fe8acbfb485c35b751d3f5d044e2ec33ebbc Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Thu, 26 Oct 2023 22:03:46 +0100 Subject: [PATCH 24/33] .test.cpp From 8f65418c8ed81a966e4fd775e3aeebafdd4b94cd Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Thu, 26 Oct 2023 22:10:47 +0100 Subject: [PATCH 25/33] josh feedback --- docs/docs/dev_docs/cli/cli-commands.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/dev_docs/cli/cli-commands.md b/docs/docs/dev_docs/cli/cli-commands.md index 31de52e6bcd..2d8c444ec12 100644 --- a/docs/docs/dev_docs/cli/cli-commands.md +++ b/docs/docs/dev_docs/cli/cli-commands.md @@ -45,7 +45,7 @@ export ADDRESS2= ## Deploying a Token Contract -We will now deploy a token contract using the `deploy` command, and set an address of the admin via a constructor argument. +We will now deploy a token contract using the `deploy` command, and set an address of the admin via a constructor argument. You can find the contract we are deploying [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr) (or write it for yourself in [this tutorial!](../tutorials/writing_token_contract.md)) Make sure to replace this address with one of the two you created earlier. #include_code deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash @@ -75,7 +75,7 @@ The `send` command expect the function name as the first unnamed argument and th #include_code send yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash -We called the `mint_public` function and provided it with the 2 arguments it expects: the recipient's address and the amount to be minted. Make sure to replace all addresses in this command with yours. +We called the [`mint_public`](https://github.com/AztecProtocol/aztec-packages/blob/87fa621347e55f82e36c70515c1824161eee5282/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr#L157C10-L157C10) function and provided it with the 2 arguments it expects: the recipient's address and the amount to be minted. Make sure to replace all addresses in this command with yours. The command output tells us the details of the transaction such as its hash and status. We can use this hash to query the receipt of the transaction at a later time: From 8ecf3c6041179e34ef3fb7ef6872650da00e8044 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Fri, 27 Oct 2023 14:37:25 +0100 Subject: [PATCH 26/33] compile counter properly --- yarn-project/noir-contracts/Nargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn-project/noir-contracts/Nargo.toml b/yarn-project/noir-contracts/Nargo.toml index 663bed76c2c..9e72509a592 100644 --- a/yarn-project/noir-contracts/Nargo.toml +++ b/yarn-project/noir-contracts/Nargo.toml @@ -3,6 +3,7 @@ members = [ "src/contracts/benchmarking_contract", "src/contracts/card_game_contract", "src/contracts/child_contract", + "src/contracts/counter_contract", "src/contracts/docs_example_contract", "src/contracts/easy_private_token_contract", "src/contracts/ecdsa_account_contract", From 7125a751cfdf3d1b9cd945921d015571abf5eb12 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Fri, 27 Oct 2023 20:00:47 +0100 Subject: [PATCH 27/33] docs broken link --- docs/docs/dev_docs/cli/blank_box.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/dev_docs/cli/blank_box.md b/docs/docs/dev_docs/cli/blank_box.md index 70a8566db18..9dfb2f2d86c 100644 --- a/docs/docs/dev_docs/cli/blank_box.md +++ b/docs/docs/dev_docs/cli/blank_box.md @@ -16,7 +16,7 @@ There are also boxes that include a basic React interface (`blank-react`) and an ## Setup -See the Quickstart page for [requirements](./quickstart.md#requirements), starting the local [Sandbox environment](./quickstart.md#sandbox-installation) and [installing the CLI](./quickstart#cli-installation). +See the Quickstart page for [requirements](../getting_started/quickstart.md#requirements), starting the local [Sandbox environment](../getting_started/quickstart.md#sandbox-installation) and [installing the CLI](../getting_started/quickstart#cli-installation). Aztec Boxes use [yarn](https://classic.yarnpkg.com/) for package management, so if you want to follow along exactly, make sure you have it [installed](https://classic.yarnpkg.com/en/docs/install). @@ -68,7 +68,7 @@ yarn ### Start the Sandbox -See the Quickstart for [installing and starting the Sandbox](./quickstart.md#sandbox-installation). +See the Quickstart for [installing and starting the Sandbox](../getting_started/quickstart.md#sandbox-installation). ### Start the frontend From b101f9e385421c8b4419087cc2913c6dff66a6c4 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Fri, 27 Oct 2023 15:56:18 -0400 Subject: [PATCH 28/33] fix broken links --- docs/docs/dev_docs/cli/sandbox-reference.md | 2 +- docs/docs/dev_docs/getting_started/aztecnr-getting-started.md | 2 +- docs/docs/intro.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/docs/dev_docs/cli/sandbox-reference.md b/docs/docs/dev_docs/cli/sandbox-reference.md index b5799f5ddb5..f9292e44a6e 100644 --- a/docs/docs/dev_docs/cli/sandbox-reference.md +++ b/docs/docs/dev_docs/cli/sandbox-reference.md @@ -46,7 +46,7 @@ cd ~/.aztec && docker-compose up If you have set up the Sandbox with Docker, you will also have Otterscan. -You can see Ethereum Layer 1 activity through the local Otterscan on [`http://localhost:5100`](`http://localhost:5100`). This is especially useful for dapps that use L1-L2 messaging through [portal contracts](../contracts/portals/main.md). +You can see Ethereum Layer 1 activity through the local Otterscan on `http://localhost:5100`. This is especially useful for dapps that use L1-L2 messaging through [portal contracts](../contracts/portals/main.md). ## Cheat Codes diff --git a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md b/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md index 041f493d3fa..02ab3114dde 100644 --- a/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md +++ b/docs/docs/dev_docs/getting_started/aztecnr-getting-started.md @@ -119,7 +119,7 @@ Context gives us access to the environment information such as `msg.sender`. We `map::Map` -Map is a private state variable that functions like a dictionary, relating Fields to other state variables. You can learn more about it [here](../contracts/syntax/). +Map is a private state variable that functions like a dictionary, relating Fields to other state variables. You can learn more about it [here](../contracts/syntax/main.md). `value_note` diff --git a/docs/docs/intro.md b/docs/docs/intro.md index f7dce2c8e8f..f6f5757ad43 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -41,9 +41,9 @@ Plus: ## Play -[Write a private smart contract today](./dev_docs/getting_started/quickstart). +Visit the [getting started](./dev_docs/getting_started/main) section for an introduction. -[Deploy to the Aztec Sandbox today](./dev_docs/getting_started/sandbox) +Go to the [Tutorials](./dev_docs/tutorials/main.md) section to dive into some more advanced walkthroughs. --- From 4b5dd4f73394d71038b8076f953f6eccbfefe555 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Fri, 27 Oct 2023 16:16:13 -0400 Subject: [PATCH 29/33] fix build and breakup outputs --- docs/docs/dev_docs/cli/cli-commands.md | 15 ++++++- .../end-to-end/src/cli_docs_sandbox.test.ts | 43 ++++++++++++++----- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/docs/docs/dev_docs/cli/cli-commands.md b/docs/docs/dev_docs/cli/cli-commands.md index 2d8c444ec12..1ac919d3cc0 100644 --- a/docs/docs/dev_docs/cli/cli-commands.md +++ b/docs/docs/dev_docs/cli/cli-commands.md @@ -17,6 +17,7 @@ npm install -g @aztec/cli The first thing we want to do is create a couple of accounts. We will use the `create-account` command which will generate a new private key for us, register the account on the sandbox, and deploy a simple account contract which [uses a single key for privacy and authentication](../../concepts/foundation/accounts/keys.md): #include_code create-account yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +#include_code create-account-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash Once the account is set up, the CLI returns the resulting address, its privacy key, and partial address. You can read more about these [here](../../concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys). @@ -29,13 +30,20 @@ export PRIVATE_KEY= Alternatively, we can also manually generate a private key and use it for creating the account, either via a `-k` option or by setting the `PRIVATE_KEY` environment variable. -#include_code create-account-from-private-key yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +#include_code generate-private-key yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +#include_code generate-private-key-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +#include_code create-account-pk yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash + +#include_code create-account-pk-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash For all commands that require a user's private key, the CLI will look for the `PRIVATE_KEY` environment variable in absence of an optional argument. Let's double check that the accounts have been registered with the sandbox using the `get-accounts` command: #include_code get-accounts yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +#include_code get-accounts-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash You will see a that a number of accounts exist that we did not create. The Sandbox initializes itself with 3 default accounts. Save one of the printed accounts (not the one that you generated above) in an environment variable. We will use it later. @@ -49,6 +57,7 @@ We will now deploy a token contract using the `deploy` command, and set an addre Make sure to replace this address with one of the two you created earlier. #include_code deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +#include_code deploy-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash Save the contract address as an environment variable. We will use it later. @@ -61,6 +70,7 @@ export CONTRACT_ADDRESS= The CLI tells us that the contract was successfully deployed. We can use the `check-deploy` command to verify that a contract has been successfully deployed to that address: #include_code check-deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +#include_code check-deploy-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash ## Sending a Transaction @@ -74,18 +84,21 @@ The `send` command expect the function name as the first unnamed argument and th - `--private-key` - The private key of the sender. #include_code send yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +#include_code send-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash We called the [`mint_public`](https://github.com/AztecProtocol/aztec-packages/blob/87fa621347e55f82e36c70515c1824161eee5282/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr#L157C10-L157C10) function and provided it with the 2 arguments it expects: the recipient's address and the amount to be minted. Make sure to replace all addresses in this command with yours. The command output tells us the details of the transaction such as its hash and status. We can use this hash to query the receipt of the transaction at a later time: #include_code get-tx-receipt yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +#include_code get-tx-receipt-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash ## Calling an Unconstrained (View) Function Now that the `mint_public` tx has been settled we can call the `balance_of_public` unconstrained function: #include_code call yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +#include_code call-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash The `call` command calls a read-only method on a contract, one that will not generate a transaction to be sent to the network. The arguments here are: diff --git a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts index 36bccf833c7..ed2a8b469f3 100644 --- a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts +++ b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts @@ -27,7 +27,7 @@ describe('CLI docs sandbox', () => { const waitForSandboxWithCli = async () => { const docs = ` // docs:start:node-info-command -aztec-cli get-node-info +% aztec-cli get-node-info // docs:end:node-info-command // docs:start:node-info @@ -145,21 +145,27 @@ UniswapContractArtifact it('creates an account from private key', async () => { const docs = ` -// docs:start:create-account-from-private-key +// docs:start:generate-private-key % aztec-cli generate-private-key +// docs:end:generate-private-key +// docs:start:generate-private-key-output Private Key: 0x12684562c8676e66be100878434b01286a757dea468233f818b906f66fb34984 Public Key: 0x1003732857c052c1d6af4dd74b5631863a056c90a586c4e3ea6d94782ee712d317cdb713ed1ba02d3df0ac2b581d269490f9e24916c1b677c7259444aa0ad66b +// docs:end:generate-private-key-output +// docs:start:create-account-pk % aztec-cli create-account --private-key 0x12684562c8676e66be100878434b01286a757dea468233f818b906f66fb34984 +// docs:end:create-account-pk +// docs:start:create-account-pk-output Created new account: Address: 0x26e831b1b146d1faf0c1d27fc72f2243887e9963cc87a6b3af64fe6481920a80 Public key: 0x1003732857c052c1d6af4dd74b5631863a056c90a586c4e3ea6d94782ee712d317cdb713ed1ba02d3df0ac2b581d269490f9e24916c1b677c7259444aa0ad66b Partial address: 0x01e5e7b2abbfb98a93b7549ae80faa6886f8ea8e8f412416fb330b565fd2b4ed -// docs:end:create-account-from-private-key +// docs:end:create-account-pk-output `; const generateCommand = docs.split('\n')[2].split('aztec-cli ')[1]; @@ -189,13 +195,16 @@ Partial address: 0x01e5e7b2abbfb98a93b7549ae80faa6886f8ea8e8f412416fb330b565fd2b let docs = ` // docs:start:create-account % aztec-cli create-account +// docs:end:create-account + +// docs:start:create-account-output Created new account: Address: 0x20d3321707d53cebb168568e25c5c62a853ae1f0766d965e00d6f6c4eb05d599 Public key: 0x02d18745eadddd496be95274367ee2cbf0bf667b81373fb6bed715c18814a09022907c273ec1c469fcc678738bd8efc3e9053fe1acbb11fa32da0d6881a1370e Private key: 0x2aba9e7de7075deee3e3f4ad1e47749f985f0f72543ed91063cc97a40d851f1e Partial address: 0x72bf7c9537875b0af267b4a8c497927e251f5988af6e30527feb16299042ed -// docs:end:create-account +// docs:end:create-account-output `; let command = docs.split('\n')[2].split('aztec-cli ')[1]; @@ -218,6 +227,9 @@ Partial address: 0x72bf7c9537875b0af267b4a8c497927e251f5988af6e30527feb16299042e docs = ` // docs:start:get-accounts % aztec-cli get-accounts +// docs:end:get-accounts + +// docs:start:get-accounts-output Accounts found: Address: 0x0c8a6673d7676cc80aaebe7fa7504cf51daa90ba906861bfad70a58a98bf5a7d @@ -235,7 +247,7 @@ Accounts found: Address: 0x01b18c2044bbedd4a2e5f67cf6858370ccfb2b869b2000abe2f4ca12d9cc166e Public Key: 0x240845f1179e3fbaa6ce587d44722b3452bbdaa11deb29553196b23534985d432b746bcf2f0e7046eb13f0ca0c4fedd027dc80b64384f50d6a14ad248faa941a Partial Address: 0x03834845fc488d1454f195abe7d52b3393f6902eee080c90cd694c63572f7160 -// docs:end:get-accounts +// docs:end:get-accounts-output `; command = docs.split('\n')[2].split('aztec-cli ')[1]; @@ -251,9 +263,11 @@ Accounts found: docs = ` // docs:start:deploy % aztec-cli deploy TokenContractArtifact --args $ADDRESS +// docs:end:deploy +// docs:start:deploy-output Contract deployed at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc54c06d0f -// docs:end:deploy +// docs:end:deploy-output `; command = docs.split('\n')[2].split('aztec-cli ')[1].replace('$ADDRESS', newAddress.toString()); @@ -269,9 +283,11 @@ Contract deployed at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc5 docs = ` // docs:start:check-deploy % aztec-cli check-deploy --contract-address $CONTRACT_ADDRESS +// docs:end:check-deploy +// docs:start:check-deploy-output Contract found at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc54c06d0f -// docs:end:check-deploy +// docs:end:check-deploy-output `; command = docs.split('\n')[2].split('aztec-cli ')[1].replace('$CONTRACT_ADDRESS', contractAddress.toString()); await run(command); @@ -289,13 +305,15 @@ Contract found at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc54c0 --contract-artifact TokenContractArtifact \ --contract-address $CONTRACT_ADDRESS \ --private-key $PRIVATE_KEY + // docs:end:send +// docs:start:send-output Transaction has been mined Transaction hash: 15c5a8e58d5f895c7e3017a706efbad693635e01f67345fa60a64a340d83c78c Status: mined Block number: 5 Block hash: 163697608599543b2bee9652f543938683e4cdd0f94ac506e5764d8b908d43d4 -// docs:end:send +// docs:end:send-output `; command = docs @@ -318,7 +336,9 @@ Block hash: 163697608599543b2bee9652f543938683e4cdd0f94ac506e5764d8b908d43d4 docs = ` // docs:start:get-tx-receipt % aztec-cli get-tx-receipt 15c5a8e58d5f895c7e3017a706efbad693635e01f67345fa60a64a340d83c78c +// docs:end:get-tx-receipt +// docs:start:get-tx-receipt-output Transaction receipt: { "txHash": "15c5a8e58d5f895c7e3017a706efbad693635e01f67345fa60a64a340d83c78c", @@ -328,7 +348,7 @@ Transaction receipt: "blockNumber": 5, "origin": "0x2337f1d5cfa6c03796db5539b0b2d5a57e9aed42665df2e0907f66820cb6eebe" } -// docs:end:get-tx-receipt +// docs:end:get-tx-receipt-output `; command = docs @@ -350,9 +370,10 @@ Transaction receipt: docs = ` // docs:start:call % aztec-cli call balance_of_public -a $ADDRESS -c TokenContractArtifact -ca $CONTRACT_ADDRESS - -View result: 543n // docs:end:call +// docs:start:call-output +View result: 543n +// docs:end:call-output `; command = docs .split('\n')[2] From ed87274db0ece7897ca4a18e7b3073839bfc4207 Mon Sep 17 00:00:00 2001 From: Josh Crites Date: Fri, 27 Oct 2023 20:25:06 -0400 Subject: [PATCH 30/33] revert some changes to get it building --- docs/docs/dev_docs/cli/cli-commands.md | 15 +----- docs/docs/dev_docs/cli/updating.md | 2 +- .../end-to-end/src/cli_docs_sandbox.test.ts | 46 +++++-------------- 3 files changed, 13 insertions(+), 50 deletions(-) diff --git a/docs/docs/dev_docs/cli/cli-commands.md b/docs/docs/dev_docs/cli/cli-commands.md index 1ac919d3cc0..2d8c444ec12 100644 --- a/docs/docs/dev_docs/cli/cli-commands.md +++ b/docs/docs/dev_docs/cli/cli-commands.md @@ -17,7 +17,6 @@ npm install -g @aztec/cli The first thing we want to do is create a couple of accounts. We will use the `create-account` command which will generate a new private key for us, register the account on the sandbox, and deploy a simple account contract which [uses a single key for privacy and authentication](../../concepts/foundation/accounts/keys.md): #include_code create-account yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash -#include_code create-account-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash Once the account is set up, the CLI returns the resulting address, its privacy key, and partial address. You can read more about these [here](../../concepts/foundation/accounts/keys.md#addresses-partial-addresses-and-public-keys). @@ -30,20 +29,13 @@ export PRIVATE_KEY= Alternatively, we can also manually generate a private key and use it for creating the account, either via a `-k` option or by setting the `PRIVATE_KEY` environment variable. -#include_code generate-private-key yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash - -#include_code generate-private-key-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash - -#include_code create-account-pk yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash - -#include_code create-account-pk-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +#include_code create-account-from-private-key yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash For all commands that require a user's private key, the CLI will look for the `PRIVATE_KEY` environment variable in absence of an optional argument. Let's double check that the accounts have been registered with the sandbox using the `get-accounts` command: #include_code get-accounts yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash -#include_code get-accounts-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash You will see a that a number of accounts exist that we did not create. The Sandbox initializes itself with 3 default accounts. Save one of the printed accounts (not the one that you generated above) in an environment variable. We will use it later. @@ -57,7 +49,6 @@ We will now deploy a token contract using the `deploy` command, and set an addre Make sure to replace this address with one of the two you created earlier. #include_code deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash -#include_code deploy-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash Save the contract address as an environment variable. We will use it later. @@ -70,7 +61,6 @@ export CONTRACT_ADDRESS= The CLI tells us that the contract was successfully deployed. We can use the `check-deploy` command to verify that a contract has been successfully deployed to that address: #include_code check-deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash -#include_code check-deploy-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash ## Sending a Transaction @@ -84,21 +74,18 @@ The `send` command expect the function name as the first unnamed argument and th - `--private-key` - The private key of the sender. #include_code send yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash -#include_code send-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash We called the [`mint_public`](https://github.com/AztecProtocol/aztec-packages/blob/87fa621347e55f82e36c70515c1824161eee5282/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr#L157C10-L157C10) function and provided it with the 2 arguments it expects: the recipient's address and the amount to be minted. Make sure to replace all addresses in this command with yours. The command output tells us the details of the transaction such as its hash and status. We can use this hash to query the receipt of the transaction at a later time: #include_code get-tx-receipt yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash -#include_code get-tx-receipt-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash ## Calling an Unconstrained (View) Function Now that the `mint_public` tx has been settled we can call the `balance_of_public` unconstrained function: #include_code call yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash -#include_code call-output yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash The `call` command calls a read-only method on a contract, one that will not generate a transaction to be sent to the network. The arguments here are: diff --git a/docs/docs/dev_docs/cli/updating.md b/docs/docs/dev_docs/cli/updating.md index c23a322c922..ff65aacebaf 100644 --- a/docs/docs/dev_docs/cli/updating.md +++ b/docs/docs/dev_docs/cli/updating.md @@ -72,7 +72,7 @@ Setting up Aztec Sandbox v#include_aztec_short_version (nargo #include_noir_vers Alternatively you can open a new terminal and use aztec-cli to get the version. -#include_code node-info-command yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash +#include_code node-info yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash This will return something like this: diff --git a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts index ed2a8b469f3..8a4af3d7c4b 100644 --- a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts +++ b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts @@ -26,11 +26,8 @@ describe('CLI docs sandbox', () => { const waitForSandboxWithCli = async () => { const docs = ` -// docs:start:node-info-command -% aztec-cli get-node-info -// docs:end:node-info-command - // docs:start:node-info +% aztec-cli get-node-info Node Info: Sandbox Version: #include_aztec_short_version @@ -145,27 +142,21 @@ UniswapContractArtifact it('creates an account from private key', async () => { const docs = ` -// docs:start:generate-private-key +// docs:start:create-account-from-private-key % aztec-cli generate-private-key -// docs:end:generate-private-key -// docs:start:generate-private-key-output Private Key: 0x12684562c8676e66be100878434b01286a757dea468233f818b906f66fb34984 Public Key: 0x1003732857c052c1d6af4dd74b5631863a056c90a586c4e3ea6d94782ee712d317cdb713ed1ba02d3df0ac2b581d269490f9e24916c1b677c7259444aa0ad66b -// docs:end:generate-private-key-output -// docs:start:create-account-pk % aztec-cli create-account --private-key 0x12684562c8676e66be100878434b01286a757dea468233f818b906f66fb34984 -// docs:end:create-account-pk -// docs:start:create-account-pk-output Created new account: Address: 0x26e831b1b146d1faf0c1d27fc72f2243887e9963cc87a6b3af64fe6481920a80 Public key: 0x1003732857c052c1d6af4dd74b5631863a056c90a586c4e3ea6d94782ee712d317cdb713ed1ba02d3df0ac2b581d269490f9e24916c1b677c7259444aa0ad66b Partial address: 0x01e5e7b2abbfb98a93b7549ae80faa6886f8ea8e8f412416fb330b565fd2b4ed -// docs:end:create-account-pk-output +// docs:end:create-account-from-private-key `; const generateCommand = docs.split('\n')[2].split('aztec-cli ')[1]; @@ -195,16 +186,13 @@ Partial address: 0x01e5e7b2abbfb98a93b7549ae80faa6886f8ea8e8f412416fb330b565fd2b let docs = ` // docs:start:create-account % aztec-cli create-account -// docs:end:create-account - -// docs:start:create-account-output Created new account: Address: 0x20d3321707d53cebb168568e25c5c62a853ae1f0766d965e00d6f6c4eb05d599 Public key: 0x02d18745eadddd496be95274367ee2cbf0bf667b81373fb6bed715c18814a09022907c273ec1c469fcc678738bd8efc3e9053fe1acbb11fa32da0d6881a1370e Private key: 0x2aba9e7de7075deee3e3f4ad1e47749f985f0f72543ed91063cc97a40d851f1e Partial address: 0x72bf7c9537875b0af267b4a8c497927e251f5988af6e30527feb16299042ed -// docs:end:create-account-output +// docs:end:create-account `; let command = docs.split('\n')[2].split('aztec-cli ')[1]; @@ -227,9 +215,6 @@ Partial address: 0x72bf7c9537875b0af267b4a8c497927e251f5988af6e30527feb16299042e docs = ` // docs:start:get-accounts % aztec-cli get-accounts -// docs:end:get-accounts - -// docs:start:get-accounts-output Accounts found: Address: 0x0c8a6673d7676cc80aaebe7fa7504cf51daa90ba906861bfad70a58a98bf5a7d @@ -247,7 +232,7 @@ Accounts found: Address: 0x01b18c2044bbedd4a2e5f67cf6858370ccfb2b869b2000abe2f4ca12d9cc166e Public Key: 0x240845f1179e3fbaa6ce587d44722b3452bbdaa11deb29553196b23534985d432b746bcf2f0e7046eb13f0ca0c4fedd027dc80b64384f50d6a14ad248faa941a Partial Address: 0x03834845fc488d1454f195abe7d52b3393f6902eee080c90cd694c63572f7160 -// docs:end:get-accounts-output +// docs:end:get-accounts `; command = docs.split('\n')[2].split('aztec-cli ')[1]; @@ -263,11 +248,9 @@ Accounts found: docs = ` // docs:start:deploy % aztec-cli deploy TokenContractArtifact --args $ADDRESS -// docs:end:deploy -// docs:start:deploy-output Contract deployed at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc54c06d0f -// docs:end:deploy-output +// docs:end:deploy `; command = docs.split('\n')[2].split('aztec-cli ')[1].replace('$ADDRESS', newAddress.toString()); @@ -283,11 +266,9 @@ Contract deployed at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc5 docs = ` // docs:start:check-deploy % aztec-cli check-deploy --contract-address $CONTRACT_ADDRESS -// docs:end:check-deploy -// docs:start:check-deploy-output Contract found at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc54c06d0f -// docs:end:check-deploy-output +// docs:end:check-deploy `; command = docs.split('\n')[2].split('aztec-cli ')[1].replace('$CONTRACT_ADDRESS', contractAddress.toString()); await run(command); @@ -305,15 +286,13 @@ Contract found at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc54c0 --contract-artifact TokenContractArtifact \ --contract-address $CONTRACT_ADDRESS \ --private-key $PRIVATE_KEY - // docs:end:send -// docs:start:send-output Transaction has been mined Transaction hash: 15c5a8e58d5f895c7e3017a706efbad693635e01f67345fa60a64a340d83c78c Status: mined Block number: 5 Block hash: 163697608599543b2bee9652f543938683e4cdd0f94ac506e5764d8b908d43d4 -// docs:end:send-output +// docs:end:send `; command = docs @@ -336,9 +315,7 @@ Block hash: 163697608599543b2bee9652f543938683e4cdd0f94ac506e5764d8b908d43d4 docs = ` // docs:start:get-tx-receipt % aztec-cli get-tx-receipt 15c5a8e58d5f895c7e3017a706efbad693635e01f67345fa60a64a340d83c78c -// docs:end:get-tx-receipt -// docs:start:get-tx-receipt-output Transaction receipt: { "txHash": "15c5a8e58d5f895c7e3017a706efbad693635e01f67345fa60a64a340d83c78c", @@ -348,7 +325,7 @@ Transaction receipt: "blockNumber": 5, "origin": "0x2337f1d5cfa6c03796db5539b0b2d5a57e9aed42665df2e0907f66820cb6eebe" } -// docs:end:get-tx-receipt-output +// docs:end:get-tx-receipt `; command = docs @@ -370,10 +347,9 @@ Transaction receipt: docs = ` // docs:start:call % aztec-cli call balance_of_public -a $ADDRESS -c TokenContractArtifact -ca $CONTRACT_ADDRESS -// docs:end:call -// docs:start:call-output + View result: 543n -// docs:end:call-output +// docs:end:call `; command = docs .split('\n')[2] From 4e5f51a74cb0e6ebf4713708c7e19d4117534990 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Sat, 28 Oct 2023 14:27:48 +0100 Subject: [PATCH 31/33] update test --- yarn-project/end-to-end/src/cli_docs_sandbox.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts index 8a4af3d7c4b..fe726fbd5f8 100644 --- a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts +++ b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts @@ -97,6 +97,7 @@ Rollup Address: 0x0dcd1bf9a1b36ce34237eeafef220932846bcd82 BenchmarkingContractArtifact CardGameContractArtifact ChildContractArtifact +CounterContractArtifact DocsExampleContractArtifact EasyPrivateTokenContractArtifact EcdsaAccountContractArtifact From 8dedde253472c1c1bada43e512203095e2de152c Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Thu, 2 Nov 2023 10:22:38 +0000 Subject: [PATCH 32/33] compiler version update --- .../noir-contracts/src/contracts/counter_contract/Nargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml b/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml index e50f871bd06..9c973675fe1 100644 --- a/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml +++ b/yarn-project/noir-contracts/src/contracts/counter_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "counter_contract" authors = [""] -compiler_version = "0.1" +compiler_version = ">=0.18.0" type = "contract" [dependencies] From 99f3372d08445a0c5eb9cf30763acab2d8844b80 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Thu, 2 Nov 2023 11:25:50 +0000 Subject: [PATCH 33/33] redirects --- docs/netlify.toml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/netlify.toml b/docs/netlify.toml index 11f2bc45c62..6c21eafd525 100644 --- a/docs/netlify.toml +++ b/docs/netlify.toml @@ -166,6 +166,17 @@ from = "/dev_docs/contracts/syntax/state_variables" to = "/dev_docs/contracts/syntax/storage" +[[redirects]] + from = "/dev_docs/getting_started/sandbox" + to = "/dev_docs/getting_started/quickstart" + +[[redirects]] + from = "/dev_docs/getting_started/blank_box" + to = "/dev_docs/cli/blank_box" + +[[redirects]] + from = "/dev_docs/getting_started/updating" + to = "/dev_docs/cli/updating" [[redirects]] from = "/misc/aztec-connect-sunset"