|
@@ -4,8 +4,8 @@
|
|
|
|
|
|
|
|
Every full node is a **verifier**.
|
|
Every full node is a **verifier**.
|
|
|
|
|
|
|
|
-**Prover** is the person executing the smart contract function on their secret witness data.
|
|
|
|
|
-They are also verifiers in our model.
|
|
|
|
|
|
|
+**Prover** is the person executing the smart contract function on
|
|
|
|
|
+their secret witness data. They are also verifiers in our model.
|
|
|
|
|
|
|
|
Lets take a pseudocode smart contract:
|
|
Lets take a pseudocode smart contract:
|
|
|
|
|
|
|
@@ -28,13 +28,15 @@ contract Dao {
|
|
|
|
|
|
|
|
## Important Invariants
|
|
## Important Invariants
|
|
|
|
|
|
|
|
-1. The state of a contract (the contract member values) is globally readable but
|
|
|
|
|
- *only* writable by that contract's functions.
|
|
|
|
|
-2. Transactions are atomic. If a subsequent contract function call fails then the earlier
|
|
|
|
|
- ones are also invalid. The entire tx will be rolled back.
|
|
|
|
|
-3. `foo_contract::bar_func::validate::state_transition()` is able to access the entire
|
|
|
|
|
- transaction to perform validation on its structure. It might need to enforce requirements
|
|
|
|
|
- on the calldata of other function calls within the same tx. See `DAO::exec()`.
|
|
|
|
|
|
|
+1. The state of a contract (the contract member values) is globally
|
|
|
|
|
+ readable but *only* writable by that contract's functions.
|
|
|
|
|
+2. Transactions are atomic. If a subsequent contract function call
|
|
|
|
|
+ fails then the earlier ones are also invalid. The entire tx will be
|
|
|
|
|
+ rolled back.
|
|
|
|
|
+3. `foo_contract::bar_func::validate::state_transition()` is able to
|
|
|
|
|
+ access the entire transaction to perform validation on its structure.
|
|
|
|
|
+ It might need to enforce requirements on the calldata of other
|
|
|
|
|
+ function calls within the same tx. See `DAO::exec()`.
|
|
|
|
|
|
|
|
## Global Smart Contract State
|
|
## Global Smart Contract State
|
|
|
|
|
|
|
@@ -76,17 +78,21 @@ mod dao_contract {
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-There is a pipeline where the prover runs `MintCall::make()` to create the `MintParams` object that
|
|
|
|
|
-is then broadcast to the verifiers through the p2p network.
|
|
|
|
|
|
|
+There is a pipeline where the prover runs `MintCall::make()` to create
|
|
|
|
|
+the `MintParams` object that is then broadcast to the verifiers through
|
|
|
|
|
+the p2p network.
|
|
|
|
|
|
|
|
-The `CallData` usually is the public values exported from a ZK proof. Essentially it is the data
|
|
|
|
|
-used by the verifier to check the function call for `DAO::mint()`.
|
|
|
|
|
|
|
+The `CallData` usually is the public values exported from a ZK proof.
|
|
|
|
|
+Essentially it is the data used by the verifier to check the function
|
|
|
|
|
+call for `DAO::mint()`.
|
|
|
|
|
|
|
|
## Atomic Transactions
|
|
## Atomic Transactions
|
|
|
|
|
|
|
|
-Transactions represent several function call invocations that are atomic. If any function call fails,
|
|
|
|
|
-the entire tx is rejected. Additionally some smart contracts might impose additional conditions
|
|
|
|
|
-on the transaction's structure or other function calls (such as their call data).
|
|
|
|
|
|
|
+Transactions represent several function call invocations
|
|
|
|
|
+that are atomic. If any function call fails, the entire tx is
|
|
|
|
|
+rejected. Additionally some smart contracts might impose additional
|
|
|
|
|
+conditions on the transaction's structure or other function calls
|
|
|
|
|
+(such as their call data).
|
|
|
|
|
|
|
|
```rust
|
|
```rust
|
|
|
{{#include ../../../src/tx/mod.rs:transaction}}
|
|
{{#include ../../../src/tx/mod.rs:transaction}}
|
|
@@ -101,17 +107,24 @@ Function calls represent mutations of the current active state to a new state.
|
|
|
The `contract_id` corresponds to the top level module for the contract which
|
|
The `contract_id` corresponds to the top level module for the contract which
|
|
|
includes the global `State`.
|
|
includes the global `State`.
|
|
|
|
|
|
|
|
-The `func_id` of a function call corresponds to predefined objects in the submodules:
|
|
|
|
|
|
|
+The `func_id` of a function call corresponds to predefined objects
|
|
|
|
|
+in the submodules:
|
|
|
|
|
+
|
|
|
* `Builder` creates the anonymized `CallData`. Ran by the prover.
|
|
* `Builder` creates the anonymized `CallData`. Ran by the prover.
|
|
|
-* `CallData` is the parameters used by the anonymized function call invocation.
|
|
|
|
|
|
|
+* `CallData` is the parameters used by the anonymized function call
|
|
|
|
|
+ invocation.
|
|
|
Verifiers have this.
|
|
Verifiers have this.
|
|
|
-* `state_transition()` that runs the function call on the current state using the `CallData`.
|
|
|
|
|
-* `apply()` commits the update to the current state taking it to the next state.
|
|
|
|
|
|
|
+* `state_transition()` that runs the function call on the current state
|
|
|
|
|
+ using the `CallData`.
|
|
|
|
|
+* `apply()` commits the update to the current state taking it to the
|
|
|
|
|
+ next state.
|
|
|
|
|
|
|
|
-An example of a `contract_id` could represent `DAO` or `Money`. Examples of `func_id` could
|
|
|
|
|
-represent `DAO::mint()` or `Money::transfer()`.
|
|
|
|
|
|
|
+An example of a `contract_id` could represent `DAO` or `Money`.
|
|
|
|
|
+Examples of `func_id` could represent `DAO::mint()` or
|
|
|
|
|
+`Money::transfer()`.
|
|
|
|
|
|
|
|
-Each function call invocation is ran using its own `state_transition()` function.
|
|
|
|
|
|
|
+Each function call invocation is ran using its own
|
|
|
|
|
+`state_transition()` function.
|
|
|
|
|
|
|
|
```rust
|
|
```rust
|
|
|
mod dao_contract {
|
|
mod dao_contract {
|
|
@@ -141,16 +154,20 @@ mod dao_contract {
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-The `state_transition()` has access to the entire atomic transaction to enforce correctness. For example
|
|
|
|
|
-chaining of function calls is used by the `DAO::exec()` smart contract function to execute moving money out
|
|
|
|
|
|
|
+The `state_transition()` has access to the entire atomic transaction to
|
|
|
|
|
+enforce correctness. For example chaining of function calls is used by
|
|
|
|
|
+the `DAO::exec()` smart contract function to execute moving money out
|
|
|
of the treasury using `Money::transfer()` within the same transaction.
|
|
of the treasury using `Money::transfer()` within the same transaction.
|
|
|
|
|
|
|
|
-Additionally `StateRegistry` gives smart contracts access to the global states of all smart contracts on the network,
|
|
|
|
|
-which is needed for some contracts.
|
|
|
|
|
|
|
+Additionally `StateRegistry` gives smart contracts access to the
|
|
|
|
|
+global states of all smart contracts on the network, which is needed
|
|
|
|
|
+for some contracts.
|
|
|
|
|
|
|
|
-Note that during this step, the state is *not* modified. Modification happens after the `state_transition()` is run
|
|
|
|
|
-for all function call invocations within the transaction. Assuming they all pass successfully, the updates are then
|
|
|
|
|
-applied at the end. This ensures atomicity property of transactions.
|
|
|
|
|
|
|
+Note that during this step, the state is *not* modified. Modification
|
|
|
|
|
+happens after the `state_transition()` is run for all function
|
|
|
|
|
+call invocations within the transaction. Assuming they all pass
|
|
|
|
|
+successfully, the updates are then applied at the end. This ensures
|
|
|
|
|
+atomicity property of transactions.
|
|
|
|
|
|
|
|
```rust
|
|
```rust
|
|
|
mod dao_contract {
|
|
mod dao_contract {
|
|
@@ -171,11 +188,15 @@ mod dao_contract {
|
|
|
The transaction verification pipeline roughly looks like this:
|
|
The transaction verification pipeline roughly looks like this:
|
|
|
|
|
|
|
|
1. Loop through all function call invocations within the transaction:
|
|
1. Loop through all function call invocations within the transaction:
|
|
|
- 1. Lookup their respective `state_transition()` function based off their `contract_id` and `func_id`.
|
|
|
|
|
- The `contract_id` and `func_id` corresponds to the contract and specific function, such as `DAO::mint()`.
|
|
|
|
|
- 2. Call the `state_transition()` function and store the update. Halt if this function fails.
|
|
|
|
|
|
|
+ 1. Lookup their respective `state_transition()` function based off
|
|
|
|
|
+ their `contract_id` and `func_id`. The `contract_id` and
|
|
|
|
|
+ `func_id` corresponds to the contract and specific function,
|
|
|
|
|
+ such as `DAO::mint()`.
|
|
|
|
|
+ 2. Call the `state_transition()` function and store the update.
|
|
|
|
|
+ Halt if this function fails.
|
|
|
2. Loop through all updates
|
|
2. Loop through all updates
|
|
|
- 1. Lookup specific `apply()` function based off the `contract_id` and `func_id`.
|
|
|
|
|
|
|
+ 1. Lookup specific `apply()` function based off the `contract_id`
|
|
|
|
|
+ and `func_id`.
|
|
|
2. Call `apply(update)` to finalize the change.
|
|
2. Call `apply(update)` to finalize the change.
|
|
|
|
|
|
|
|
## ZK Proofs and Signatures
|
|
## ZK Proofs and Signatures
|
|
@@ -192,33 +213,37 @@ And corresponding function calls.
|
|
|
{{#include ../../../src/sdk/src/tx.rs:contractcall}}
|
|
{{#include ../../../src/sdk/src/tx.rs:contractcall}}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-As we can see the ZK proofs and signatures are separate from the actuall `call_data` interpreted
|
|
|
|
|
-by `state_transition()`. They are both automatically verified by the VM.
|
|
|
|
|
|
|
+As we can see the ZK proofs and signatures are separate from the
|
|
|
|
|
+actuall `call_data` interpreted by `state_transition()`. They are
|
|
|
|
|
+both automatically verified by the VM.
|
|
|
|
|
|
|
|
-However for verification to work, the ZK proofs also need corresponding public values, and
|
|
|
|
|
-the signatures need the public keys. We do this in the `CallDataBase` trait by exporting these
|
|
|
|
|
-methods:
|
|
|
|
|
|
|
+However for verification to work, the ZK proofs also need corresponding
|
|
|
|
|
+public values, and the signatures need the public keys. We do this
|
|
|
|
|
+in the `CallDataBase` trait by exporting these methods:
|
|
|
|
|
|
|
|
-```rust
|
|
|
|
|
-{{#include ../../../bin/dao/daod/src/util.rs:calldatabase_trait}}
|
|
|
|
|
|
|
+```
|
|
|
|
|
+TODO
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-These methods export the required values needed for the ZK proofs and signature verification
|
|
|
|
|
-from the actual call data itself.
|
|
|
|
|
|
|
+These methods export the required values needed for the ZK proofs
|
|
|
|
|
+and signature verification from the actual call data itself.
|
|
|
|
|
|
|
|
-For signature verification, the data we are verifying is simply the entire transactions minus
|
|
|
|
|
-the actual signatures. That's why the signatures are a separate top level field in the
|
|
|
|
|
-transaction.
|
|
|
|
|
|
|
+For signature verification, the data we are verifying is simply
|
|
|
|
|
+the entire transactions minus the actual signatures. That's why the
|
|
|
|
|
+signatures are a separate top level field in the transaction.
|
|
|
|
|
|
|
|
## Parallelisation Techniques
|
|
## Parallelisation Techniques
|
|
|
|
|
|
|
|
-Since verification is done through `state_transition()` which returns an update that is then committed
|
|
|
|
|
-to the state using `apply()`, we can verify all transactions in a block in parallel.
|
|
|
|
|
|
|
+Since verification is done through `state_transition()` which returns
|
|
|
|
|
+an update that is then committed to the state using `apply()`, we
|
|
|
|
|
+can verify all transactions in a block in parallel.
|
|
|
|
|
|
|
|
-To enable calling another transaction within the same block (such as flashloans), we can add a special
|
|
|
|
|
-depends field within the tx that makes a tx wait on another tx before being allowed to verify.
|
|
|
|
|
-This causes a small deanonymization to occur but brings a massive scalability benefit
|
|
|
|
|
-to the entire system.
|
|
|
|
|
|
|
+To enable calling another transaction within the same block (such
|
|
|
|
|
+as flashloans), we can add a special depends field within the tx
|
|
|
|
|
+that makes a tx wait on another tx before being allowed to verify.
|
|
|
|
|
+This causes a small deanonymization to occur but brings a massive
|
|
|
|
|
+scalability benefit to the entire system.
|
|
|
|
|
|
|
|
-ZK proof verification should be done automatically by the system. Any proof that fails marks the entire
|
|
|
|
|
-tx as invalid, and the tx is discarded. This should also be parallelized.
|
|
|
|
|
|
|
+ZK proof verification should be done automatically by the system. Any
|
|
|
|
|
+proof that fails marks the entire tx as invalid, and the tx is
|
|
|
|
|
+discarded. This should also be parallelized.
|