From 6150b4de2a3d2568e9aad8ab2fe27c16088e39d6 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 24 Nov 2023 10:54:42 -0300 Subject: [PATCH 1/3] Add TODOs for issue #3417 --- .../circuits.js/src/structs/kernel/combined_accumulated_data.ts | 1 + yarn-project/circuits.js/src/structs/public_call_request.ts | 2 ++ yarn-project/circuits.js/src/structs/tx_context.ts | 1 + yarn-project/types/src/tx/tx.ts | 1 + yarn-project/types/src/tx_execution_request.ts | 1 + 5 files changed, 6 insertions(+) diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts index 4f84c10ff55..f77a3d910c4 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts @@ -491,6 +491,7 @@ export class FinalAccumulatedData { public nullifiedCommitments: Tuple, /** * Current private call stack. + * TODO(#3417): Given this field must empty, should we just remove it? */ public privateCallStack: Tuple, /** diff --git a/yarn-project/circuits.js/src/structs/public_call_request.ts b/yarn-project/circuits.js/src/structs/public_call_request.ts index b8cb2cacd50..70556f079eb 100644 --- a/yarn-project/circuits.js/src/structs/public_call_request.ts +++ b/yarn-project/circuits.js/src/structs/public_call_request.ts @@ -27,10 +27,12 @@ export class PublicCallRequest { public contractAddress: AztecAddress, /** * Data identifying the function being called. + * TODO(#3417): Remove this since the only useful data is the function selector, which is already part of the call context. */ public functionData: FunctionData, /** * Context of the public call. + * TODO(#3417): Check if all fields of CallContext are actually needed. */ public callContext: CallContext, /** diff --git a/yarn-project/circuits.js/src/structs/tx_context.ts b/yarn-project/circuits.js/src/structs/tx_context.ts index 644c8812690..adab6ff8031 100644 --- a/yarn-project/circuits.js/src/structs/tx_context.ts +++ b/yarn-project/circuits.js/src/structs/tx_context.ts @@ -85,6 +85,7 @@ export class TxContext { constructor( /** * Whether this is a fee paying tx. If not other tx in a bundle will pay the fee. + * TODO(#3417): Remove fee and rebate payment fields. */ public isFeePaymentTx: boolean, /** diff --git a/yarn-project/types/src/tx/tx.ts b/yarn-project/types/src/tx/tx.ts index 6d49a50912a..381d0a7f782 100644 --- a/yarn-project/types/src/tx/tx.ts +++ b/yarn-project/types/src/tx/tx.ts @@ -45,6 +45,7 @@ export class Tx { /** * Contracts deployed in this tx. * Note: Portal address is always set to zero in the tx's new contracts. + * TODO(#3417): Check if portal addresses are still always set to zero */ public readonly newContracts: Tuple, ) { diff --git a/yarn-project/types/src/tx_execution_request.ts b/yarn-project/types/src/tx_execution_request.ts index b944b423af6..7cfbd9aab78 100644 --- a/yarn-project/types/src/tx_execution_request.ts +++ b/yarn-project/types/src/tx_execution_request.ts @@ -15,6 +15,7 @@ export class TxExecutionRequest { public origin: AztecAddress, /** * Function data representing the function to call. + * TODO(#3417): Remove this field and replace with a function selector. */ public functionData: FunctionData, /** From 4139a861b08491a04999fbbbdcd3778bcc5b38f8 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 24 Nov 2023 10:55:00 -0300 Subject: [PATCH 2/3] Transactions section in yellow paper --- yellow-paper/docs/transactions/index.md | 15 ++++ .../docs/transactions/local-execution.md | 31 +++++++ .../docs/transactions/public-execution.md | 16 ++++ yellow-paper/docs/transactions/tx-object.md | 84 +++++++++++++++++++ yellow-paper/docs/transactions/validity.md | 17 ++++ 5 files changed, 163 insertions(+) create mode 100644 yellow-paper/docs/transactions/index.md create mode 100644 yellow-paper/docs/transactions/local-execution.md create mode 100644 yellow-paper/docs/transactions/public-execution.md create mode 100644 yellow-paper/docs/transactions/tx-object.md create mode 100644 yellow-paper/docs/transactions/validity.md diff --git a/yellow-paper/docs/transactions/index.md b/yellow-paper/docs/transactions/index.md new file mode 100644 index 00000000000..6f72811501b --- /dev/null +++ b/yellow-paper/docs/transactions/index.md @@ -0,0 +1,15 @@ +--- +title: Transactions +--- + +# Transactions + +A transaction is the minimal action that changes the state of the network. Transactions in Aztec have a private and a public component, where the former is executed in the user's private execution environment (PXE) and the latter by the sequencer. + +A transaction is also split into three phases to [support authorization abstraction and fee payments](../gas-and-fees/gas-and-fees.md#fees): a validation and fee preparation phase, a main execution phase, and fee distribution phase. + +Users initiate a transaction by sending a _transaction request_ to their local PXE, which [locally simulates and proves the transaction](./local-execution.md) and returns a [_transaction_ object](./tx-object.md) identified by a [_transaction hash_](./tx-hash.md). This transaction object is then broadcasted to the network via an Aztec Node, which checks its [validity](./validity.md), and eventually picked up by a sequencer who [executes the public component of the transaction](./public-execution.md) and includes it in a block. + +import DocCardList from '@theme/DocCardList'; + + diff --git a/yellow-paper/docs/transactions/local-execution.md b/yellow-paper/docs/transactions/local-execution.md new file mode 100644 index 00000000000..154655706d5 --- /dev/null +++ b/yellow-paper/docs/transactions/local-execution.md @@ -0,0 +1,31 @@ +# Local Execution + +Transactions are initiated via a _transaction execution request_ sent from the user to their local _private execution environment_ (PXE). The PXE first executes the transaction locally in a _simulation_ step, and then generates a _zero-knowledge proof_ of correct execution. The PXE is then responsible for converting a _transaction execution request_ into a [_transaction_](./tx-object.md) ready to be broadcasted to the network. + +## Execution request + +A transaction execution request has the following structure. Note that, since Aztec uses full native account abstraction where every account is backed by a contract, a transaction execution request only needs to provide the contract address, function, and arguments of the initial call; nonces and signatures are arguments to the call, and thus opaque to the protocol. + +| Field | Type | Description | +|----------|----------|----------| +| origin | AztecAddress | Address of the contract where the transaction is initiated. | +| functionSelector | Field | Selector (identifier) of the function to be called as entrypoint in the origin contract. | +| argsHash | Field | Hash of the arguments to be used for calling the entrypoint function. | +| txContext | TxContext | Includes contract deployment data (if this tx is used to deploy a contract), chain id, and protocol version. | +| packedArguments | PackedArguments[] | Preimages for argument hashes. When executing a function call with the hash of the arguments, the PXE will look for the preimage of that hash in this list, and expand the arguments to execute the call. | +| authWitnesses | AuthWitness[] | Authorization witnesses. When authorizing an action identified by a hash, the PXE will look for the authorization witness identified by that hash and provide that value to the account contract. | + +## Simulation step + +Upon receiving a transaction execution request to _simulate_, the PXE will locally execute the function identified by the given `functionSelector` in the given `origin` contract with the arguments committed to by `argsHash`. We refer to this function as the _entrypoint_. During execution, contracts may request authorization witnesses or expanded arguments from the _execution oracle_, which are answered with the `packedArguments` and `authWitnesses` from the request. + +The _entrypoint_ may enqueue additional function calls, either private or public, and so forth. The simulation step will always execute all private functions in the call stack until emptied. The result of the simulation is a [_transaction_](./tx-object.md) object without an associated _proof_ which is returned to the application that requested the simulation. + +In terms of circuitry, the simulation step must execute all application circuits that correspond to private function calls, and then execute the private kernel circuit until the private call stack is empty. Note that circuits are only executed, there is no witness generation or proving involved. + +## Proving step + +The proving step is similar to the simulation step, though witnesses are generated for all circuits and proven. Note that it is not necessary to execute the simulation step before the proving step, though it is desirable in order to provide the user with info on their transaction and catch any failed assertions early. + +The output of the proving step is a [_transaction_](./tx-object.md) object with a valid _proof_ associated, ready to be broadcasted to the network. + diff --git a/yellow-paper/docs/transactions/public-execution.md b/yellow-paper/docs/transactions/public-execution.md new file mode 100644 index 00000000000..e281acad277 --- /dev/null +++ b/yellow-paper/docs/transactions/public-execution.md @@ -0,0 +1,16 @@ +# Public execution + +Transactions have a _public execution_ component. Once a transaction is picked up by a sequencer to be included in a block, the sequencer is responsible for executing all enqueued public function calls in the transaction. These are defined by the `data.accumulatedData.publicCallStack` field of the [transaction object](./tx-object.md), which are commitments to the preimages of the `enqueuedPublicFunctionCalls` in the transaction. The sequencer pops function calls from the stack, and pushes new ones as needed, until the public call stack is empty. + +## Bytecode + +Unlike private functions, which are native circuits, public functions in the Aztec Network are specified in Brillig, a zkVM-friendly bytecode. This bytecode is executed and proven in the Brillig public virtual machine. Each function call is a run of the virtual machine, and a _public kernel circuit_ aggregates these calls and produces a final proof for the transaction, which also includes the _private kernel circuit_ proof of the transaction generated during [local execution](./local-execution.md). + +## State + +Since public execution is run by the sequencer, it is run on the state of the chain as it is when the transaction is included in the block. Public functions operate on _public state_, an updateable key-value mapping, instead of notes. + +## Reverts + +Note that, unlike local private execution, public execution can _revert_ due to a failed assertion, running out of gas, trying to call a non-existing function, or other failures. If this happens, the sequencer halts execution and discards all side effects from the [transaction payload phase](../gas-and-fees/gas-and-fees.md#transaction-payload). The transaction is still included in the block and pays fees, but is flagged as reverted. + diff --git a/yellow-paper/docs/transactions/tx-object.md b/yellow-paper/docs/transactions/tx-object.md new file mode 100644 index 00000000000..c9a9b0c85c8 --- /dev/null +++ b/yellow-paper/docs/transactions/tx-object.md @@ -0,0 +1,84 @@ +# Transaction object + +The transaction object is the struct broadcasted to the p2p network, generated by [_local execution_](./local-execution.md) by the user's PXE. Sequencers pick up transactions from the p2p network to include in a block. + +## Transaction object struct + +The fields of a transaction object are the following: + +| Field | Type | Description | +|----------|----------|----------| +| data | PrivateKernelPublicInputsFinal | Public inputs (ie output) of the last iteration of the private kernel circuit for this transaction. | +| proof | Buffer | Zero-knowledge honk proof for the last iteration of the private kernel circuit for this transaction. | +| encryptedLogs | Buffer[][] | Encrypted logs emitted per function in this transaction. Position `i` contains the encrypted logs emitted by the `i`-th function execution. | +| unencryptedLogs | Buffer[][] | Equivalent to the above but for unencrypted logs. | +| enqueuedPublicFunctionCalls | PublicCallRequest[] | List of public function calls to run during public execution. | +| newContracts | ExtendedContractData[] | List of new contracts to be deployed as part of this transaction. | + +### Private kernel public inputs final + +Output of the last iteration of the private kernel circuit. Includes _accumulated data_ after recursing through all private function calls, as well as _constant data_ composed of _historic block data_ reflecting the state of the chain when such functions were executed, and the global _transaction context_. Refer to the circuits section for more info. + +**Accumulated data** + +| Field | Type | Description | +|-------|------|-------------| +| aggregationObject | AggregationObject | Aggregated proof of all the previous kernel iterations. | +| newCommitments | Field[] | The new commitments made in this transaction. | +| newNullifiers | Field[] | The new nullifiers made in this transaction. | +| nullifiedCommitments | Field[] | The commitments which are nullified by a nullifier in the above list. | +| privateCallStack | Field[] | Current private call stack. | +| publicCallStack | Field[] | Current public call stack. | +| newL2ToL1Msgs | Field[] | All the new L2 to L1 messages created in this transaction. | +| encryptedLogsHash | Field[] | Accumulated encrypted logs hash from all the previous kernel iterations. | +| unencryptedLogsHash | Field[] | Accumulated unencrypted logs hash from all the previous kernel iterations. | +| encryptedLogPreimagesLength | Field | Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations. | +| unencryptedLogPreimagesLength | Field | Total accumulated length of the unencrypted log preimages emitted in all the previous kernel iterations. | +| newContracts | NewContractData[] | All the new contracts deployed in this transaction. | + +**Historic block data** + +| Field | Type | Description | +|-------|------|-------------| +| noteHashTreeRoot | Field | Root of the note hash tree at the time of when this information was assembled. | +| nullifierTreeRoot | Field | Root of the nullifier tree at the time of when this information was assembled. | +| contractTreeRoot | Field | Root of the contract tree at the time of when this information was assembled. | +| l1ToL2MessagesTreeRoot | Field | Root of the L1 to L2 messages tree at the time of when this information was assembled. | +| blocksTreeRoot | Field | Root of the historic blocks tree at the time of when this information was assembled. | +| privateKernelVkTreeRoot | Field | Root of the private kernel VK tree at the time of when this information was assembled (future enhancement). | +| publicDataTreeRoot | Field | Current public state tree hash. | +| globalVariablesHash | Field | Previous globals hash, this value is used to recalculate the block hash. | + +### Public call request + +Each _public call request_ is the preimage of a public call stack item in the transaction's `data`, and has the following fields: + +| Field | Type | Description | +|----------|----------|----------| +| contractAddress | AztecAddress | Address of the contract on which the function is invoked. | +| callContext | CallContext | Includes function selector and caller. | +| args | Field[] | Arguments to the function call. | +| sideEffectCounter | number? | Optional counter for ordering side effects of this function call. | + +### Extended contract data + +Each _extended contract data_ corresponds to a contract being deployed by the transaction, and has the following fields: + +| Field | Type | Description | +|----------|----------|----------| +| address | AztecAddress | Address where the contract is to be deployed. | +| portalAddress | EthereumAddress | Portal address on L1 for this contract (zero if none). | +| bytecode | Buffer | Encoded Brillig bytecode for all public functions in the contract. | +| publicKey | PublicKey | Master public encryption key for this contract (zero if none). | +| partialAddress | Field | Hash of the constructor arguments, salt, and bytecode. | + +## Transaction hash + +A transaction is identified by its _transaction hash_. In order to be able to identify a transaction before it has been locally executed, the hash is computed from its [_transaction execution request_](./local-execution.md#execution-request) by hashing: + +- `origin` +- `functionSelector` +- `argsHash` +- `txContent` + +The resulting transaction hash is always emitted during local execution as the first nullifier of the transaction, in order to prevent replay attacks. This is enforced by the private kernel circuit. \ No newline at end of file diff --git a/yellow-paper/docs/transactions/validity.md b/yellow-paper/docs/transactions/validity.md new file mode 100644 index 00000000000..b8f2b4ee3bc --- /dev/null +++ b/yellow-paper/docs/transactions/validity.md @@ -0,0 +1,17 @@ +# Validity conditions + +The _validity conditions_ of a transaction define when a [_transaction object_](./tx-object.md) is valid. Nodes should check the validity of a transaction when they receive it either directly or through the p2p pool, and if they found it invalid, should drop it immediately and not broadcast it. + +In addition to being well-formed, the transaction object needs to pass the following checks: + +- **Proof is valid**: The `proof` for the given public `data` should be valid according to a protocol-wide verification key for the final private kernel circuit. +- **No double-spends**: No `nullifier` in the transaction `data` should be already present in the nullifier tree. +- **No pending private function calls**: The `data` private call stack should be empty. +- **Valid historic data**: The tree roots in the historic block data of `data` must match the tree roots of a block in the chain. +- **Preimages must match commitments in `data`**: The expanded fields in the transaction object should match the commitments (hashes) to them in the public `data`. + - The `encryptedLogs` should match the `encryptedLogsHash` and `encryptedLogPreimagesLength` in the transaction `data`. + - The `unencryptedLogs` should match the `unencryptedLogsHash` and `unencryptedLogPreimagesLength` in the transaction `data`. + - Each public call stack item in the transaction `data` should have a corresponding preimage in the `enqueuedPublicFunctionCalls`. + - Each new contract data in transaction `data` should have a corresponding preimage in the `newContracts`. + +Note that all checks but the last one are enforced by the base rollup circuit when the transaction is included in a block. \ No newline at end of file From 3bec02c0e0774e4a859f47cfbb090f92435287b4 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Wed, 29 Nov 2023 15:20:06 -0300 Subject: [PATCH 3/3] Add maxBlockNum --- yellow-paper/docs/transactions/tx-object.md | 1 + yellow-paper/docs/transactions/validity.md | 1 + 2 files changed, 2 insertions(+) diff --git a/yellow-paper/docs/transactions/tx-object.md b/yellow-paper/docs/transactions/tx-object.md index c9a9b0c85c8..38123b6ffb9 100644 --- a/yellow-paper/docs/transactions/tx-object.md +++ b/yellow-paper/docs/transactions/tx-object.md @@ -35,6 +35,7 @@ Output of the last iteration of the private kernel circuit. Includes _accumulate | encryptedLogPreimagesLength | Field | Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations. | | unencryptedLogPreimagesLength | Field | Total accumulated length of the unencrypted log preimages emitted in all the previous kernel iterations. | | newContracts | NewContractData[] | All the new contracts deployed in this transaction. | +| maxBlockNum | Field | Maximum block number (inclusive) for inclusion of this transaction in a block. | **Historic block data** diff --git a/yellow-paper/docs/transactions/validity.md b/yellow-paper/docs/transactions/validity.md index b8f2b4ee3bc..f4121e6faad 100644 --- a/yellow-paper/docs/transactions/validity.md +++ b/yellow-paper/docs/transactions/validity.md @@ -8,6 +8,7 @@ In addition to being well-formed, the transaction object needs to pass the follo - **No double-spends**: No `nullifier` in the transaction `data` should be already present in the nullifier tree. - **No pending private function calls**: The `data` private call stack should be empty. - **Valid historic data**: The tree roots in the historic block data of `data` must match the tree roots of a block in the chain. +- **Maximum block number not exceeded**: The transaction must be included in a block with height no greater than the value specified in `maxBlockNum` within the transaction's `data`. - **Preimages must match commitments in `data`**: The expanded fields in the transaction object should match the commitments (hashes) to them in the public `data`. - The `encryptedLogs` should match the `encryptedLogsHash` and `encryptedLogPreimagesLength` in the transaction `data`. - The `unencryptedLogs` should match the `unencryptedLogsHash` and `unencryptedLogPreimagesLength` in the transaction `data`.