mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-02-14 10:23:08 +00:00
Merge branch 'main' into Pravdyvy/block-parsing-validation
This commit is contained in:
commit
df58511bf0
34
Cargo.lock
generated
34
Cargo.lock
generated
@ -3815,6 +3815,7 @@ dependencies = [
|
||||
"secp256k1",
|
||||
"serde",
|
||||
"sha2",
|
||||
"test-case",
|
||||
"test_program_methods",
|
||||
"thiserror 2.0.17",
|
||||
]
|
||||
@ -5647,6 +5648,39 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
|
||||
dependencies = [
|
||||
"test-case-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case-core"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case-macros"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.114",
|
||||
"test-case-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test_program_methods"
|
||||
version = "0.1.0"
|
||||
|
||||
@ -155,6 +155,8 @@ cargo install --path wallet --force
|
||||
|
||||
Run `wallet help` to check everything went well.
|
||||
|
||||
Some completion scripts exists, see the [completions](./completions/README.md) folder.
|
||||
|
||||
## Tutorial
|
||||
|
||||
This tutorial walks you through creating accounts and executing NSSA programs in both public and private contexts.
|
||||
|
||||
BIN
artifacts/test_program_methods/changer_claimer.bin
Normal file
BIN
artifacts/test_program_methods/changer_claimer.bin
Normal file
Binary file not shown.
Binary file not shown.
135
completions/README.md
Normal file
135
completions/README.md
Normal file
@ -0,0 +1,135 @@
|
||||
# Wallet CLI Completion
|
||||
|
||||
Completion scripts for the LSSA `wallet` command.
|
||||
|
||||
## ZSH
|
||||
|
||||
Works with both vanilla zsh and oh-my-zsh.
|
||||
|
||||
### Features
|
||||
|
||||
- Full completion for all wallet subcommands
|
||||
- Contextual option completion for each command
|
||||
- Dynamic account ID completion via `wallet account list`
|
||||
- Descriptions for all commands and options
|
||||
|
||||
Note that only accounts created by the user auto-complete.
|
||||
Preconfigured accounts and accounts only with `/` (no number) are not completed.
|
||||
|
||||
e.g.:
|
||||
|
||||
```
|
||||
▶ wallet account list
|
||||
Preconfigured Public/Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw,
|
||||
Preconfigured Public/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy,
|
||||
Preconfigured Private/3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw,
|
||||
Preconfigured Private/AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX,
|
||||
/ Public/8DstRgMQrB2N9a7ymv98RDDbt8nctrP9ZzaNRSpKDZSu,
|
||||
/0 Public/2gJJjtG9UivBGEhA1Jz6waZQx1cwfYupC5yvKEweHaeH,
|
||||
/ Private/Bcv15B36bs1VqvQAdY6ZGFM1KioByNQQsB92KTNAx6u2
|
||||
```
|
||||
|
||||
Only `Public/2gJJjtG9UivBGEhA1Jz6waZQx1cwfYupC5yvKEweHaeH` is used for completion.
|
||||
|
||||
### Supported Commands
|
||||
|
||||
| Command | Description |
|
||||
|------------------------|-------------------------------------------------------------|
|
||||
| `wallet auth-transfer` | Authenticated transfer (init, send) |
|
||||
| `wallet chain-info` | Chain info queries (current-block-id, block, transaction) |
|
||||
| `wallet account` | Account management (get, list, new, sync-private) |
|
||||
| `wallet pinata` | Piñata faucet (claim) |
|
||||
| `wallet token` | Token operations (new, send) |
|
||||
| `wallet amm` | AMM operations (new, swap, add-liquidity, remove-liquidity) |
|
||||
| `wallet check-health` | Health check |
|
||||
|
||||
### Installation
|
||||
|
||||
#### Vanilla Zsh
|
||||
|
||||
1. Create a completions directory:
|
||||
|
||||
```sh
|
||||
mkdir -p ~/.zsh/completions
|
||||
```
|
||||
|
||||
2. Copy the completion file:
|
||||
|
||||
```sh
|
||||
cp ./zsh/_wallet ~/.zsh/completions/
|
||||
```
|
||||
|
||||
3. Add to your `~/.zshrc` (before any `compinit` call, or add these lines if you don't have one):
|
||||
|
||||
```sh
|
||||
fpath=(~/.zsh/completions $fpath)
|
||||
autoload -Uz compinit && compinit
|
||||
```
|
||||
|
||||
4. Reload your shell:
|
||||
|
||||
```sh
|
||||
exec zsh
|
||||
```
|
||||
|
||||
#### Oh-My-Zsh
|
||||
|
||||
1. Create the plugin directory and copy the file:
|
||||
|
||||
```sh
|
||||
mkdir -p ~/.oh-my-zsh/custom/plugins/wallet
|
||||
cp _wallet ~/.oh-my-zsh/custom/plugins/wallet/
|
||||
```
|
||||
|
||||
2. Add `wallet` to your plugins array in `~/.zshrc`:
|
||||
|
||||
```sh
|
||||
plugins=(... wallet)
|
||||
```
|
||||
|
||||
3. Reload your shell:
|
||||
|
||||
```sh
|
||||
exec zsh
|
||||
```
|
||||
|
||||
### Requirements
|
||||
|
||||
The completion script calls `wallet account list` to dynamically fetch account IDs. Ensure the `wallet` command is in your `$PATH`.
|
||||
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
# Main commands
|
||||
wallet <TAB>
|
||||
|
||||
# Account subcommands
|
||||
wallet account <TAB>
|
||||
|
||||
# Options for auth-transfer send
|
||||
wallet auth-transfer send --<TAB>
|
||||
|
||||
# Account types when creating
|
||||
wallet account new <TAB>
|
||||
# Shows: public private
|
||||
|
||||
# Account IDs (fetched dynamically)
|
||||
wallet account get --account-id <TAB>
|
||||
# Shows: Public/... Private/...
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Completions not appearing
|
||||
|
||||
1. Check that `compinit` is called in your `.zshrc`
|
||||
2. Rebuild the completion cache:
|
||||
|
||||
```sh
|
||||
rm -f ~/.zcompdump*
|
||||
exec zsh
|
||||
```
|
||||
|
||||
### Account IDs not completing
|
||||
|
||||
Ensure `wallet account list` works from your command line.
|
||||
435
completions/zsh/_wallet
Normal file
435
completions/zsh/_wallet
Normal file
@ -0,0 +1,435 @@
|
||||
#compdef wallet
|
||||
|
||||
# Zsh completion script for the wallet CLI
|
||||
# See instructions in ../README.md
|
||||
|
||||
_wallet() {
|
||||
local -a commands
|
||||
local -a subcommands
|
||||
local curcontext="$curcontext" state line
|
||||
typeset -A opt_args
|
||||
|
||||
_arguments -C \
|
||||
'(-c --continuous-run)'{-c,--continuous-run}'[Continuous run flag]' \
|
||||
'--auth[Basic authentication in the format user or user\:password]:auth:' \
|
||||
'1: :->command' \
|
||||
'*:: :->args'
|
||||
|
||||
case $state in
|
||||
command)
|
||||
commands=(
|
||||
'auth-transfer:Authenticated transfer subcommand'
|
||||
'chain-info:Generic chain info subcommand'
|
||||
'account:Account view and sync subcommand'
|
||||
'pinata:Pinata program interaction subcommand'
|
||||
'token:Token program interaction subcommand'
|
||||
'amm:AMM program interaction subcommand'
|
||||
'check-health:Check the wallet can connect to the node and builtin local programs match the remote versions'
|
||||
'config:Command to setup config, get and set config fields'
|
||||
'restore-keys:Restoring keys from given password at given depth'
|
||||
'deploy-program:Deploy a program'
|
||||
'help:Print help message or the help of the given subcommand(s)'
|
||||
)
|
||||
_describe -t commands 'wallet commands' commands
|
||||
;;
|
||||
args)
|
||||
case $line[1] in
|
||||
auth-transfer)
|
||||
_wallet_auth_transfer
|
||||
;;
|
||||
chain-info)
|
||||
_wallet_chain_info
|
||||
;;
|
||||
account)
|
||||
_wallet_account
|
||||
;;
|
||||
pinata)
|
||||
_wallet_pinata
|
||||
;;
|
||||
token)
|
||||
_wallet_token
|
||||
;;
|
||||
amm)
|
||||
_wallet_amm
|
||||
;;
|
||||
config)
|
||||
_wallet_config
|
||||
;;
|
||||
restore-keys)
|
||||
_wallet_restore_keys
|
||||
;;
|
||||
deploy-program)
|
||||
_wallet_deploy_program
|
||||
;;
|
||||
help)
|
||||
_wallet_help
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# auth-transfer subcommand
|
||||
_wallet_auth_transfer() {
|
||||
local -a subcommands
|
||||
|
||||
_arguments -C \
|
||||
'1: :->subcommand' \
|
||||
'*:: :->args'
|
||||
|
||||
case $state in
|
||||
subcommand)
|
||||
subcommands=(
|
||||
'init:Initialize account under authenticated transfer program'
|
||||
'send:Send native tokens from one account to another with variable privacy'
|
||||
'help:Print this message or the help of the given subcommand(s)'
|
||||
)
|
||||
_describe -t subcommands 'auth-transfer subcommands' subcommands
|
||||
;;
|
||||
args)
|
||||
case $line[1] in
|
||||
init)
|
||||
_arguments \
|
||||
'--account-id[Account ID to initialize]:account_id:_wallet_account_ids'
|
||||
;;
|
||||
send)
|
||||
_arguments \
|
||||
'--from[Source account ID]:from_account:_wallet_account_ids' \
|
||||
'--to[Destination account ID (for owned accounts)]:to_account:_wallet_account_ids' \
|
||||
'--to-npk[Destination nullifier public key (for foreign private accounts)]:npk:' \
|
||||
'--to-ipk[Destination viewing public key (for foreign private accounts)]:ipk:' \
|
||||
'--amount[Amount of native tokens to send]:amount:'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# chain-info subcommand
|
||||
_wallet_chain_info() {
|
||||
local -a subcommands
|
||||
|
||||
_arguments -C \
|
||||
'1: :->subcommand' \
|
||||
'*:: :->args'
|
||||
|
||||
case $state in
|
||||
subcommand)
|
||||
subcommands=(
|
||||
'current-block-id:Get current block id from sequencer'
|
||||
'block:Get block at id from sequencer'
|
||||
'transaction:Get transaction at hash from sequencer'
|
||||
'help:Print this message or the help of the given subcommand(s)'
|
||||
)
|
||||
_describe -t subcommands 'chain-info subcommands' subcommands
|
||||
;;
|
||||
args)
|
||||
case $line[1] in
|
||||
block)
|
||||
_arguments \
|
||||
'--id[Block ID to retrieve]:block_id:'
|
||||
;;
|
||||
transaction)
|
||||
_arguments \
|
||||
'--hash[Transaction hash to retrieve]:tx_hash:'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# account subcommand
|
||||
_wallet_account() {
|
||||
local -a subcommands
|
||||
|
||||
_arguments -C \
|
||||
'1: :->subcommand' \
|
||||
'*:: :->args'
|
||||
|
||||
case $state in
|
||||
subcommand)
|
||||
subcommands=(
|
||||
'get:Get account data'
|
||||
'list:List all accounts'
|
||||
'ls:List all accounts (alias for list)'
|
||||
'new:Produce new public or private account'
|
||||
'sync-private:Sync private accounts'
|
||||
'help:Print this message or the help of the given subcommand(s)'
|
||||
)
|
||||
_describe -t subcommands 'account subcommands' subcommands
|
||||
;;
|
||||
args)
|
||||
case $line[1] in
|
||||
get)
|
||||
_arguments \
|
||||
'(-r --raw)'{-r,--raw}'[Get raw account data]' \
|
||||
'(-k --keys)'{-k,--keys}'[Display keys (pk for public accounts, npk/ipk for private accounts)]' \
|
||||
'(-a --account-id)'{-a,--account-id}'[Account ID to query]:account_id:_wallet_account_ids'
|
||||
;;
|
||||
list|ls)
|
||||
_arguments \
|
||||
'(-l --long)'{-l,--long}'[Display detailed account information]'
|
||||
;;
|
||||
new)
|
||||
_arguments -C \
|
||||
'1: :->account_type' \
|
||||
'*:: :->new_args'
|
||||
case $state in
|
||||
account_type)
|
||||
compadd public private
|
||||
;;
|
||||
new_args)
|
||||
_arguments \
|
||||
'--cci[Chain index of a parent node]:chain_index:'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# pinata subcommand
|
||||
_wallet_pinata() {
|
||||
local -a subcommands
|
||||
|
||||
_arguments -C \
|
||||
'1: :->subcommand' \
|
||||
'*:: :->args'
|
||||
|
||||
case $state in
|
||||
subcommand)
|
||||
subcommands=(
|
||||
'claim:Claim tokens from the Piñata faucet'
|
||||
'help:Print this message or the help of the given subcommand(s)'
|
||||
)
|
||||
_describe -t subcommands 'pinata subcommands' subcommands
|
||||
;;
|
||||
args)
|
||||
case $line[1] in
|
||||
claim)
|
||||
_arguments \
|
||||
'--to[Destination account ID to receive claimed tokens]:to_account:_wallet_account_ids'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# token subcommand
|
||||
_wallet_token() {
|
||||
local -a subcommands
|
||||
|
||||
_arguments -C \
|
||||
'1: :->subcommand' \
|
||||
'*:: :->args'
|
||||
|
||||
case $state in
|
||||
subcommand)
|
||||
subcommands=(
|
||||
'new:Produce a new token'
|
||||
'send:Send tokens from one account to another with variable privacy'
|
||||
'burn:Burn tokens on holder, modify definition'
|
||||
'mint:Mint tokens on holder, modify definition'
|
||||
'help:Print this message or the help of the given subcommand(s)'
|
||||
)
|
||||
_describe -t subcommands 'token subcommands' subcommands
|
||||
;;
|
||||
args)
|
||||
case $line[1] in
|
||||
new)
|
||||
_arguments \
|
||||
'--name[Token name]:name:' \
|
||||
'--total-supply[Total supply of tokens to mint]:total_supply:' \
|
||||
'--definition-account-id[Account ID for token definition]:definition_account:_wallet_account_ids' \
|
||||
'--supply-account-id[Account ID to receive initial supply]:supply_account:_wallet_account_ids'
|
||||
;;
|
||||
send)
|
||||
_arguments \
|
||||
'--from[Source holding account ID]:from_account:_wallet_account_ids' \
|
||||
'--to[Destination holding account ID (for owned accounts)]:to_account:_wallet_account_ids' \
|
||||
'--to-npk[Destination nullifier public key (for foreign private accounts)]:npk:' \
|
||||
'--to-ipk[Destination viewing public key (for foreign private accounts)]:ipk:' \
|
||||
'--amount[Amount of tokens to send]:amount:'
|
||||
;;
|
||||
burn)
|
||||
_arguments \
|
||||
'--definition[Definition account ID]:definition_account:_wallet_account_ids' \
|
||||
'--holder[Holder account ID]:holder_account:_wallet_account_ids' \
|
||||
'--amount[Amount of tokens to burn]:amount:'
|
||||
;;
|
||||
mint)
|
||||
_arguments \
|
||||
'--definition[Definition account ID]:definition_account:_wallet_account_ids' \
|
||||
'--holder[Holder account ID (for owned accounts)]:holder_account:_wallet_account_ids' \
|
||||
'--holder-npk[Holder nullifier public key (for foreign private accounts)]:npk:' \
|
||||
'--holder-ipk[Holder viewing public key (for foreign private accounts)]:ipk:' \
|
||||
'--amount[Amount of tokens to mint]:amount:'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# amm subcommand
|
||||
_wallet_amm() {
|
||||
local -a subcommands
|
||||
|
||||
_arguments -C \
|
||||
'1: :->subcommand' \
|
||||
'*:: :->args'
|
||||
|
||||
case $state in
|
||||
subcommand)
|
||||
subcommands=(
|
||||
'new:Create a new liquidity pool'
|
||||
'swap:Swap tokens using the AMM'
|
||||
'add-liquidity:Add liquidity to an existing pool'
|
||||
'remove-liquidity:Remove liquidity from a pool'
|
||||
'help:Print this message or the help of the given subcommand(s)'
|
||||
)
|
||||
_describe -t subcommands 'amm subcommands' subcommands
|
||||
;;
|
||||
args)
|
||||
case $line[1] in
|
||||
new)
|
||||
_arguments \
|
||||
'--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \
|
||||
'--user-holding-b[User token B holding account ID]:holding_b:_wallet_account_ids' \
|
||||
'--user-holding-lp[User LP token holding account ID]:holding_lp:_wallet_account_ids' \
|
||||
'--balance-a[Amount of token A to deposit]:balance_a:' \
|
||||
'--balance-b[Amount of token B to deposit]:balance_b:'
|
||||
;;
|
||||
swap)
|
||||
_arguments \
|
||||
'--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \
|
||||
'--user-holding-b[User token B holding account ID]:holding_b:_wallet_account_ids' \
|
||||
'--amount-in[Amount of tokens to swap]:amount_in:' \
|
||||
'--min-amount-out[Minimum tokens expected in return]:min_amount_out:' \
|
||||
'--token-definition[Definition ID of the token being provided]:token_def:'
|
||||
;;
|
||||
add-liquidity)
|
||||
_arguments \
|
||||
'--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \
|
||||
'--user-holding-b[User token B holding account ID]:holding_b:_wallet_account_ids' \
|
||||
'--user-holding-lp[User LP token holding account ID]:holding_lp:_wallet_account_ids' \
|
||||
'--max-amount-a[Maximum amount of token A to deposit]:max_amount_a:' \
|
||||
'--max-amount-b[Maximum amount of token B to deposit]:max_amount_b:' \
|
||||
'--min-amount-lp[Minimum LP tokens to receive]:min_amount_lp:'
|
||||
;;
|
||||
remove-liquidity)
|
||||
_arguments \
|
||||
'--user-holding-a[User token A holding account ID]:holding_a:_wallet_account_ids' \
|
||||
'--user-holding-b[User token B holding account ID]:holding_b:_wallet_account_ids' \
|
||||
'--user-holding-lp[User LP token holding account ID]:holding_lp:_wallet_account_ids' \
|
||||
'--balance-lp[Amount of LP tokens to burn]:balance_lp:' \
|
||||
'--min-amount-a[Minimum token A to receive]:min_amount_a:' \
|
||||
'--min-amount-b[Minimum token B to receive]:min_amount_b:'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# config subcommand
|
||||
_wallet_config() {
|
||||
local -a subcommands
|
||||
local -a config_keys
|
||||
|
||||
config_keys=(
|
||||
'all'
|
||||
'override_rust_log'
|
||||
'sequencer_addr'
|
||||
'seq_poll_timeout_millis'
|
||||
'seq_tx_poll_max_blocks'
|
||||
'seq_poll_max_retries'
|
||||
'seq_block_poll_max_amount'
|
||||
'initial_accounts'
|
||||
'basic_auth'
|
||||
)
|
||||
|
||||
_arguments -C \
|
||||
'1: :->subcommand' \
|
||||
'*:: :->args'
|
||||
|
||||
case $state in
|
||||
subcommand)
|
||||
subcommands=(
|
||||
'get:Getter of config fields'
|
||||
'set:Setter of config fields'
|
||||
'description:Prints description of corresponding field'
|
||||
'help:Print this message or the help of the given subcommand(s)'
|
||||
)
|
||||
_describe -t subcommands 'config subcommands' subcommands
|
||||
;;
|
||||
args)
|
||||
case $line[1] in
|
||||
get|description)
|
||||
compadd -a config_keys
|
||||
;;
|
||||
set)
|
||||
_arguments \
|
||||
'1:key:compadd -a config_keys' \
|
||||
'2:value:'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# restore-keys subcommand
|
||||
_wallet_restore_keys() {
|
||||
_arguments \
|
||||
'(-d --depth)'{-d,--depth}'[How deep in tree accounts may be]:depth:'
|
||||
}
|
||||
|
||||
# deploy-program subcommand
|
||||
_wallet_deploy_program() {
|
||||
_arguments \
|
||||
'1:binary filepath:_files'
|
||||
}
|
||||
|
||||
# help subcommand
|
||||
_wallet_help() {
|
||||
local -a commands
|
||||
commands=(
|
||||
'auth-transfer:Authenticated transfer subcommand'
|
||||
'chain-info:Generic chain info subcommand'
|
||||
'account:Account view and sync subcommand'
|
||||
'pinata:Pinata program interaction subcommand'
|
||||
'token:Token program interaction subcommand'
|
||||
'amm:AMM program interaction subcommand'
|
||||
'check-health:Check the wallet can connect to the node'
|
||||
'config:Command to setup config, get and set config fields'
|
||||
'restore-keys:Restoring keys from given password at given depth'
|
||||
'deploy-program:Deploy a program'
|
||||
)
|
||||
_describe -t commands 'wallet commands' commands
|
||||
}
|
||||
|
||||
# Helper function to complete account IDs
|
||||
# Uses `wallet account list` to get available accounts
|
||||
# Only includes accounts with /N prefix (where N is a number)
|
||||
_wallet_account_ids() {
|
||||
local -a accounts
|
||||
local line
|
||||
|
||||
# Try to get accounts from wallet account list command
|
||||
# Filter to lines starting with /N (numbered accounts) and extract the account ID
|
||||
if command -v wallet &>/dev/null; then
|
||||
while IFS= read -r line; do
|
||||
# Remove trailing comma if present and add to array
|
||||
[[ -n "$line" ]] && accounts+=("${line%,}")
|
||||
done < <(wallet account list 2>/dev/null | grep '^/[0-9]' | awk '{print $2}')
|
||||
fi
|
||||
|
||||
# Provide type prefixes as fallback if command fails or returns nothing
|
||||
if (( ${#accounts} == 0 )); then
|
||||
compadd -S '' -- 'Public/' 'Private/'
|
||||
return
|
||||
fi
|
||||
|
||||
_multi_parts / accounts
|
||||
}
|
||||
|
||||
_wallet "$@"
|
||||
@ -50,7 +50,7 @@ async fn main() {
|
||||
wallet_core
|
||||
.send_privacy_preserving_tx(
|
||||
accounts,
|
||||
&Program::serialize_instruction(greeting).unwrap(),
|
||||
Program::serialize_instruction(greeting).unwrap(),
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
|
||||
@ -58,7 +58,7 @@ async fn main() {
|
||||
wallet_core
|
||||
.send_privacy_preserving_tx(
|
||||
accounts,
|
||||
&Program::serialize_instruction(instruction).unwrap(),
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
&program_with_dependencies,
|
||||
)
|
||||
.await
|
||||
|
||||
@ -101,7 +101,7 @@ async fn main() {
|
||||
wallet_core
|
||||
.send_privacy_preserving_tx(
|
||||
accounts,
|
||||
&Program::serialize_instruction(instruction).unwrap(),
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
@ -142,7 +142,7 @@ async fn main() {
|
||||
wallet_core
|
||||
.send_privacy_preserving_tx(
|
||||
accounts,
|
||||
&Program::serialize_instruction(instruction).unwrap(),
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
&program.into(),
|
||||
)
|
||||
.await
|
||||
|
||||
@ -11,11 +11,13 @@ use tokio::test;
|
||||
use wallet::cli::{
|
||||
Command, SubcommandReturnValue,
|
||||
account::{AccountSubcommand, NewSubcommand},
|
||||
programs::pinata::PinataProgramAgnosticSubcommand,
|
||||
programs::{
|
||||
native_token_transfer::AuthTransferSubcommand, pinata::PinataProgramAgnosticSubcommand,
|
||||
},
|
||||
};
|
||||
|
||||
#[test]
|
||||
async fn claim_pinata_to_public_account() -> Result<()> {
|
||||
async fn claim_pinata_to_existing_public_account() -> Result<()> {
|
||||
let mut ctx = TestContext::new().await?;
|
||||
|
||||
let pinata_prize = 150;
|
||||
@ -120,8 +122,26 @@ async fn claim_pinata_to_new_private_account() -> Result<()> {
|
||||
anyhow::bail!("Expected RegisterAccount return value");
|
||||
};
|
||||
|
||||
let winner_account_id_formatted = format_private_account_id(&winner_account_id.to_string());
|
||||
|
||||
// Initialize account under auth transfer program
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Init {
|
||||
account_id: winner_account_id_formatted.clone(),
|
||||
});
|
||||
wallet::cli::execute_subcommand(ctx.wallet_mut(), command).await?;
|
||||
|
||||
info!("Waiting for next block creation");
|
||||
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
|
||||
|
||||
let new_commitment = ctx
|
||||
.wallet()
|
||||
.get_private_account_commitment(&winner_account_id)
|
||||
.context("Failed to get private account commitment")?;
|
||||
assert!(verify_commitment_is_in_state(new_commitment, ctx.sequencer_client()).await);
|
||||
|
||||
// Claim pinata to the new private account
|
||||
let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim {
|
||||
to: format_private_account_id(&winner_account_id.to_string()),
|
||||
to: winner_account_id_formatted,
|
||||
});
|
||||
|
||||
let pinata_balance_pre = ctx
|
||||
|
||||
@ -235,16 +235,16 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction {
|
||||
]],
|
||||
);
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![sender_pre, recipient_pre],
|
||||
Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(sender_npk.clone(), sender_ss),
|
||||
(recipient_npk.clone(), recipient_ss),
|
||||
],
|
||||
&[sender_nsk],
|
||||
&[Some(proof)],
|
||||
vec![sender_nsk],
|
||||
vec![Some(proof)],
|
||||
&program.into(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -24,8 +24,9 @@ risc0-binfmt = "3.0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
test_program_methods.workspace = true
|
||||
hex-literal = "1.0.0"
|
||||
env_logger.workspace = true
|
||||
hex-literal = "1.0.0"
|
||||
test-case = "3.3.1"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@ -15,9 +15,8 @@ pub type Nonce = u128;
|
||||
|
||||
/// Account to be used both in public and private contexts
|
||||
#[derive(
|
||||
Clone, Default, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
|
||||
Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
|
||||
)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug))]
|
||||
pub struct Account {
|
||||
pub program_owner: ProgramId,
|
||||
pub balance: u128,
|
||||
@ -25,8 +24,7 @@ pub struct Account {
|
||||
pub nonce: Nonce,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug))]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct AccountWithMetadata {
|
||||
pub account: Account,
|
||||
pub is_authorized: bool,
|
||||
@ -45,6 +43,7 @@ impl AccountWithMetadata {
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
Copy,
|
||||
Clone,
|
||||
@ -56,7 +55,7 @@ impl AccountWithMetadata {
|
||||
BorshSerialize,
|
||||
BorshDeserialize,
|
||||
)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug, PartialOrd, Ord))]
|
||||
#[cfg_attr(any(feature = "host", test), derive(PartialOrd, Ord))]
|
||||
pub struct AccountId {
|
||||
value: [u8; 32],
|
||||
}
|
||||
|
||||
@ -5,8 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const DATA_MAX_LENGTH_IN_BYTES: usize = 100 * 1024; // 100 KiB
|
||||
|
||||
#[derive(Default, Clone, PartialEq, Eq, Serialize, BorshSerialize)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug))]
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, BorshSerialize)]
|
||||
pub struct Data(Vec<u8>);
|
||||
|
||||
impl Data {
|
||||
|
||||
@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Commitment, account::AccountId};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Debug, Clone, Hash))]
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[cfg_attr(any(feature = "host", test), derive(Clone, Hash))]
|
||||
pub struct NullifierPublicKey(pub [u8; 32]);
|
||||
|
||||
impl From<&NullifierPublicKey> for AccountId {
|
||||
|
||||
@ -30,6 +30,20 @@ impl PdaSeed {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_authorized_pdas(
|
||||
caller_program_id: Option<ProgramId>,
|
||||
pda_seeds: &[PdaSeed],
|
||||
) -> HashSet<AccountId> {
|
||||
caller_program_id
|
||||
.map(|caller_program_id| {
|
||||
pda_seeds
|
||||
.iter()
|
||||
.map(|pda_seed| AccountId::from((&caller_program_id, pda_seed)))
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
impl From<(&ProgramId, &PdaSeed)> for AccountId {
|
||||
fn from(value: (&ProgramId, &PdaSeed)) -> Self {
|
||||
use risc0_zkvm::sha::{Impl, Sha256};
|
||||
@ -93,6 +107,13 @@ impl AccountPostState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a post state that requests ownership of the account
|
||||
/// if the account's program owner is the default program ID.
|
||||
pub fn new_claimed_if_default(account: Account) -> Self {
|
||||
let claim = account.program_owner == DEFAULT_PROGRAM_ID;
|
||||
Self { account, claim }
|
||||
}
|
||||
|
||||
/// Returns `true` if this post state requests that the account
|
||||
/// be claimed (owned) by the executing program.
|
||||
pub fn requires_claim(&self) -> bool {
|
||||
@ -108,6 +129,11 @@ impl AccountPostState {
|
||||
pub fn account_mut(&mut self) -> &mut Account {
|
||||
&mut self.account
|
||||
}
|
||||
|
||||
/// Consumes the post state and returns the underlying account
|
||||
pub fn into_account(self) -> Account {
|
||||
self.account
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use nssa_core::{
|
||||
MembershipProof, NullifierPublicKey, NullifierSecretKey, PrivacyPreservingCircuitInput,
|
||||
PrivacyPreservingCircuitOutput, SharedSecretKey,
|
||||
account::AccountWithMetadata,
|
||||
program::{InstructionData, ProgramId, ProgramOutput},
|
||||
program::{ChainedCall, InstructionData, ProgramId, ProgramOutput},
|
||||
};
|
||||
use risc0_zkvm::{ExecutorEnv, InnerReceipt, Receipt, default_prover};
|
||||
|
||||
@ -43,27 +43,44 @@ impl From<Program> for ProgramWithDependencies {
|
||||
}
|
||||
|
||||
/// Generates a proof of the execution of a NSSA program inside the privacy preserving execution
|
||||
/// circuit
|
||||
/// circuit.
|
||||
#[expect(clippy::too_many_arguments, reason = "TODO: fix later")]
|
||||
pub fn execute_and_prove(
|
||||
pre_states: &[AccountWithMetadata],
|
||||
instruction_data: &InstructionData,
|
||||
visibility_mask: &[u8],
|
||||
private_account_nonces: &[u128],
|
||||
private_account_keys: &[(NullifierPublicKey, SharedSecretKey)],
|
||||
private_account_nsks: &[NullifierSecretKey],
|
||||
private_account_membership_proofs: &[Option<MembershipProof>],
|
||||
pre_states: Vec<AccountWithMetadata>,
|
||||
instruction_data: InstructionData,
|
||||
visibility_mask: Vec<u8>,
|
||||
private_account_nonces: Vec<u128>,
|
||||
private_account_keys: Vec<(NullifierPublicKey, SharedSecretKey)>,
|
||||
private_account_nsks: Vec<NullifierSecretKey>,
|
||||
private_account_membership_proofs: Vec<Option<MembershipProof>>,
|
||||
program_with_dependencies: &ProgramWithDependencies,
|
||||
) -> Result<(PrivacyPreservingCircuitOutput, Proof), NssaError> {
|
||||
let mut program = &program_with_dependencies.program;
|
||||
let dependencies = &program_with_dependencies.dependencies;
|
||||
let mut instruction_data = instruction_data.clone();
|
||||
let mut pre_states = pre_states.to_vec();
|
||||
let ProgramWithDependencies {
|
||||
program,
|
||||
dependencies,
|
||||
} = program_with_dependencies;
|
||||
let mut env_builder = ExecutorEnv::builder();
|
||||
let mut program_outputs = Vec::new();
|
||||
|
||||
for _i in 0..MAX_NUMBER_CHAINED_CALLS {
|
||||
let inner_receipt = execute_and_prove_program(program, &pre_states, &instruction_data)?;
|
||||
let initial_call = ChainedCall {
|
||||
program_id: program.id(),
|
||||
instruction_data: instruction_data.clone(),
|
||||
pre_states,
|
||||
pda_seeds: vec![],
|
||||
};
|
||||
|
||||
let mut chained_calls = VecDeque::from_iter([(initial_call, program)]);
|
||||
let mut chain_calls_counter = 0;
|
||||
while let Some((chained_call, program)) = chained_calls.pop_front() {
|
||||
if chain_calls_counter >= MAX_NUMBER_CHAINED_CALLS {
|
||||
return Err(NssaError::MaxChainedCallsDepthExceeded);
|
||||
}
|
||||
|
||||
let inner_receipt = execute_and_prove_program(
|
||||
program,
|
||||
&chained_call.pre_states,
|
||||
&chained_call.instruction_data,
|
||||
)?;
|
||||
|
||||
let program_output: ProgramOutput = inner_receipt
|
||||
.journal
|
||||
@ -76,39 +93,23 @@ pub fn execute_and_prove(
|
||||
// Prove circuit.
|
||||
env_builder.add_assumption(inner_receipt);
|
||||
|
||||
// TODO: Remove when multi-chain calls are supported in the circuit
|
||||
assert!(program_output.chained_calls.len() <= 1);
|
||||
// TODO: Modify when multi-chain calls are supported in the circuit
|
||||
if let Some(next_call) = program_output.chained_calls.first() {
|
||||
program = dependencies
|
||||
.get(&next_call.program_id)
|
||||
for new_call in program_output.chained_calls.into_iter().rev() {
|
||||
let next_program = dependencies
|
||||
.get(&new_call.program_id)
|
||||
.ok_or(NssaError::InvalidProgramBehavior)?;
|
||||
instruction_data = next_call.instruction_data.clone();
|
||||
// Build post states with metadata for next call
|
||||
let mut post_states_with_metadata = Vec::new();
|
||||
for (pre, post) in program_output
|
||||
.pre_states
|
||||
.iter()
|
||||
.zip(program_output.post_states)
|
||||
{
|
||||
let mut post_with_metadata = pre.clone();
|
||||
post_with_metadata.account = post.account().clone();
|
||||
post_states_with_metadata.push(post_with_metadata);
|
||||
}
|
||||
|
||||
pre_states = next_call.pre_states.clone();
|
||||
} else {
|
||||
break;
|
||||
chained_calls.push_front((new_call, next_program));
|
||||
}
|
||||
|
||||
chain_calls_counter += 1;
|
||||
}
|
||||
|
||||
let circuit_input = PrivacyPreservingCircuitInput {
|
||||
program_outputs,
|
||||
visibility_mask: visibility_mask.to_vec(),
|
||||
private_account_nonces: private_account_nonces.to_vec(),
|
||||
private_account_keys: private_account_keys.to_vec(),
|
||||
private_account_nsks: private_account_nsks.to_vec(),
|
||||
private_account_membership_proofs: private_account_membership_proofs.to_vec(),
|
||||
visibility_mask,
|
||||
private_account_nonces,
|
||||
private_account_keys,
|
||||
private_account_nsks,
|
||||
private_account_membership_proofs,
|
||||
program_id: program_with_dependencies.program.id(),
|
||||
};
|
||||
|
||||
@ -215,13 +216,13 @@ mod tests {
|
||||
let shared_secret = SharedSecretKey::new(&esk, &recipient_keys.ivk());
|
||||
|
||||
let (output, proof) = execute_and_prove(
|
||||
&[sender, recipient],
|
||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[0, 2],
|
||||
&[0xdeadbeef],
|
||||
&[(recipient_keys.npk(), shared_secret)],
|
||||
&[],
|
||||
&[None],
|
||||
vec![sender, recipient],
|
||||
Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
vec![0, 2],
|
||||
vec![0xdeadbeef],
|
||||
vec![(recipient_keys.npk(), shared_secret)],
|
||||
vec![],
|
||||
vec![None],
|
||||
&Program::authenticated_transfer_program().into(),
|
||||
)
|
||||
.unwrap();
|
||||
@ -311,16 +312,16 @@ mod tests {
|
||||
let shared_secret_2 = SharedSecretKey::new(&esk_2, &recipient_keys.ivk());
|
||||
|
||||
let (output, proof) = execute_and_prove(
|
||||
&[sender_pre.clone(), recipient],
|
||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![sender_pre.clone(), recipient],
|
||||
Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(sender_keys.npk(), shared_secret_1),
|
||||
(recipient_keys.npk(), shared_secret_2),
|
||||
],
|
||||
&[sender_keys.nsk],
|
||||
&[commitment_set.get_proof_for(&commitment_sender), None],
|
||||
vec![sender_keys.nsk],
|
||||
vec![commitment_set.get_proof_for(&commitment_sender), None],
|
||||
&program.into(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -226,6 +226,15 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn changer_claimer() -> Self {
|
||||
use test_program_methods::{CHANGER_CLAIMER_ELF, CHANGER_CLAIMER_ID};
|
||||
|
||||
Program {
|
||||
id: CHANGER_CLAIMER_ID,
|
||||
elf: CHANGER_CLAIMER_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop() -> Self {
|
||||
use test_program_methods::{NOOP_ELF, NOOP_ID};
|
||||
|
||||
@ -235,6 +244,17 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn malicious_authorization_changer() -> Self {
|
||||
use test_program_methods::{
|
||||
MALICIOUS_AUTHORIZATION_CHANGER_ELF, MALICIOUS_AUTHORIZATION_CHANGER_ID,
|
||||
};
|
||||
|
||||
Program {
|
||||
id: MALICIOUS_AUTHORIZATION_CHANGER_ID,
|
||||
elf: MALICIOUS_AUTHORIZATION_CHANGER_ELF.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modified_transfer_program() -> Self {
|
||||
use test_program_methods::MODIFIED_TRANSFER_ELF;
|
||||
// This unwrap won't panic since the `MODIFIED_TRANSFER_ELF` comes from risc0 build of
|
||||
|
||||
@ -4,7 +4,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use log::debug;
|
||||
use nssa_core::{
|
||||
account::{Account, AccountId, AccountWithMetadata},
|
||||
program::{ChainedCall, DEFAULT_PROGRAM_ID, PdaSeed, ProgramId, validate_execution},
|
||||
program::{ChainedCall, DEFAULT_PROGRAM_ID, validate_execution},
|
||||
};
|
||||
use sha2::{Digest, digest::FixedOutput};
|
||||
|
||||
@ -119,7 +119,7 @@ impl PublicTransaction {
|
||||
return Err(NssaError::MaxChainedCallsDepthExceeded);
|
||||
}
|
||||
|
||||
// Check the `program_id` corresponds to a deployed program
|
||||
// Check that the `program_id` corresponds to a deployed program
|
||||
let Some(program) = state.programs().get(&chained_call.program_id) else {
|
||||
return Err(NssaError::InvalidInput("Unknown program".into()));
|
||||
};
|
||||
@ -135,12 +135,14 @@ impl PublicTransaction {
|
||||
chained_call.program_id, program_output
|
||||
);
|
||||
|
||||
let authorized_pdas =
|
||||
self.compute_authorized_pdas(&caller_program_id, &chained_call.pda_seeds);
|
||||
let authorized_pdas = nssa_core::program::compute_authorized_pdas(
|
||||
caller_program_id,
|
||||
&chained_call.pda_seeds,
|
||||
);
|
||||
|
||||
for pre in &program_output.pre_states {
|
||||
let account_id = pre.account_id;
|
||||
// Check that the program output pre_states coinicide with the values in the public
|
||||
// Check that the program output pre_states coincide with the values in the public
|
||||
// state or with any modifications to those values during the chain of calls.
|
||||
let expected_pre = state_diff
|
||||
.get(&account_id)
|
||||
@ -198,22 +200,23 @@ impl PublicTransaction {
|
||||
chain_calls_counter += 1;
|
||||
}
|
||||
|
||||
Ok(state_diff)
|
||||
}
|
||||
|
||||
fn compute_authorized_pdas(
|
||||
&self,
|
||||
caller_program_id: &Option<ProgramId>,
|
||||
pda_seeds: &[PdaSeed],
|
||||
) -> HashSet<AccountId> {
|
||||
if let Some(caller_program_id) = caller_program_id {
|
||||
pda_seeds
|
||||
.iter()
|
||||
.map(|pda_seed| AccountId::from((caller_program_id, pda_seed)))
|
||||
.collect()
|
||||
} else {
|
||||
HashSet::new()
|
||||
// Check that all modified uninitialized accounts where claimed
|
||||
for post in state_diff.iter().filter_map(|(account_id, post)| {
|
||||
let pre = state.get_account_by_id(account_id);
|
||||
if pre.program_owner != DEFAULT_PROGRAM_ID {
|
||||
return None;
|
||||
}
|
||||
if pre == *post {
|
||||
return None;
|
||||
}
|
||||
Some(post)
|
||||
}) {
|
||||
if post.program_owner == DEFAULT_PROGRAM_ID {
|
||||
return Err(NssaError::InvalidProgramBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(state_diff)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -504,6 +504,7 @@ pub mod tests {
|
||||
self.insert_program(Program::chain_caller());
|
||||
self.insert_program(Program::amm());
|
||||
self.insert_program(Program::claimer());
|
||||
self.insert_program(Program::changer_claimer());
|
||||
self
|
||||
}
|
||||
|
||||
@ -865,13 +866,13 @@ pub mod tests {
|
||||
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender, recipient],
|
||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[0, 2],
|
||||
&[0xdeadbeef],
|
||||
&[(recipient_keys.npk(), shared_secret)],
|
||||
&[],
|
||||
&[None],
|
||||
vec![sender, recipient],
|
||||
Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
vec![0, 2],
|
||||
vec![0xdeadbeef],
|
||||
vec![(recipient_keys.npk(), shared_secret)],
|
||||
vec![],
|
||||
vec![None],
|
||||
&Program::authenticated_transfer_program().into(),
|
||||
)
|
||||
.unwrap();
|
||||
@ -912,16 +913,16 @@ pub mod tests {
|
||||
let epk_2 = EphemeralPublicKey::from_scalar(esk_2);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[1, 2],
|
||||
&new_nonces,
|
||||
&[
|
||||
vec![sender_pre, recipient_pre],
|
||||
Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
vec![1, 2],
|
||||
new_nonces.to_vec(),
|
||||
vec![
|
||||
(sender_keys.npk(), shared_secret_1),
|
||||
(recipient_keys.npk(), shared_secret_2),
|
||||
],
|
||||
&[sender_keys.nsk],
|
||||
&[state.get_proof_for_commitment(&sender_commitment), None],
|
||||
vec![sender_keys.nsk],
|
||||
vec![state.get_proof_for_commitment(&sender_commitment), None],
|
||||
&program.into(),
|
||||
)
|
||||
.unwrap();
|
||||
@ -965,13 +966,13 @@ pub mod tests {
|
||||
let epk = EphemeralPublicKey::from_scalar(esk);
|
||||
|
||||
let (output, proof) = circuit::execute_and_prove(
|
||||
&[sender_pre, recipient_pre],
|
||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[1, 0],
|
||||
&[new_nonce],
|
||||
&[(sender_keys.npk(), shared_secret)],
|
||||
&[sender_keys.nsk],
|
||||
&[state.get_proof_for_commitment(&sender_commitment)],
|
||||
vec![sender_pre, recipient_pre],
|
||||
Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
vec![1, 0],
|
||||
vec![new_nonce],
|
||||
vec![(sender_keys.npk(), shared_secret)],
|
||||
vec![sender_keys.nsk],
|
||||
vec![state.get_proof_for_commitment(&sender_commitment)],
|
||||
&program.into(),
|
||||
)
|
||||
.unwrap();
|
||||
@ -1179,13 +1180,13 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[public_account],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[0],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![0],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1206,13 +1207,13 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[public_account],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[0],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![0],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1233,13 +1234,13 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[public_account],
|
||||
&Program::serialize_instruction(()).unwrap(),
|
||||
&[0],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account],
|
||||
Program::serialize_instruction(()).unwrap(),
|
||||
vec![0],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1260,13 +1261,13 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[public_account],
|
||||
&Program::serialize_instruction(vec![0]).unwrap(),
|
||||
&[0],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account],
|
||||
Program::serialize_instruction(vec![0]).unwrap(),
|
||||
vec![0],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1289,13 +1290,13 @@ pub mod tests {
|
||||
let large_data: Vec<u8> = vec![0; nssa_core::account::data::DATA_MAX_LENGTH_IN_BYTES + 1];
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[public_account],
|
||||
&Program::serialize_instruction(large_data).unwrap(),
|
||||
&[0],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account],
|
||||
Program::serialize_instruction(large_data).unwrap(),
|
||||
vec![0],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.to_owned().into(),
|
||||
);
|
||||
|
||||
@ -1316,13 +1317,13 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[public_account],
|
||||
&Program::serialize_instruction(()).unwrap(),
|
||||
&[0],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account],
|
||||
Program::serialize_instruction(()).unwrap(),
|
||||
vec![0],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1352,13 +1353,13 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[public_account_1, public_account_2],
|
||||
&Program::serialize_instruction(()).unwrap(),
|
||||
&[0, 0],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account_1, public_account_2],
|
||||
Program::serialize_instruction(()).unwrap(),
|
||||
vec![0, 0],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1379,13 +1380,13 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[public_account],
|
||||
&Program::serialize_instruction(()).unwrap(),
|
||||
&[0],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account],
|
||||
Program::serialize_instruction(()).unwrap(),
|
||||
vec![0],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1415,13 +1416,13 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[public_account_1, public_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[0, 0],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account_1, public_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![0, 0],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1453,13 +1454,13 @@ pub mod tests {
|
||||
// Setting only one visibility mask for a circuit execution with two pre_state accounts.
|
||||
let visibility_mask = [0];
|
||||
let result = execute_and_prove(
|
||||
&[public_account_1, public_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&visibility_mask,
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account_1, public_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
visibility_mask.to_vec(),
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1486,11 +1487,11 @@ pub mod tests {
|
||||
// Setting only one nonce for an execution with two private accounts.
|
||||
let private_account_nonces = [0xdeadbeef1];
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&private_account_nonces,
|
||||
&[
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
private_account_nonces.to_vec(),
|
||||
vec![
|
||||
(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
@ -1500,8 +1501,8 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||
),
|
||||
],
|
||||
&[sender_keys.nsk],
|
||||
&[Some((0, vec![]))],
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1530,13 +1531,13 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
)];
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&private_account_keys,
|
||||
&[sender_keys.nsk],
|
||||
&[Some((0, vec![]))],
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
private_account_keys.to_vec(),
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1563,11 +1564,11 @@ pub mod tests {
|
||||
// Setting no second commitment proof.
|
||||
let private_account_membership_proofs = [Some((0, vec![]))];
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
@ -1577,8 +1578,8 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||
),
|
||||
],
|
||||
&[sender_keys.nsk],
|
||||
&private_account_membership_proofs,
|
||||
vec![sender_keys.nsk],
|
||||
private_account_membership_proofs.to_vec(),
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1605,11 +1606,11 @@ pub mod tests {
|
||||
// Setting no auth key for an execution with one non default private accounts.
|
||||
let private_account_nsks = [];
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
@ -1619,8 +1620,8 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||
),
|
||||
],
|
||||
&private_account_nsks,
|
||||
&[],
|
||||
private_account_nsks.to_vec(),
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1663,13 +1664,13 @@ pub mod tests {
|
||||
let private_account_nsks = [recipient_keys.nsk];
|
||||
let private_account_membership_proofs = [Some((0, vec![]))];
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&private_account_keys,
|
||||
&private_account_nsks,
|
||||
&private_account_membership_proofs,
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
private_account_keys.to_vec(),
|
||||
private_account_nsks.to_vec(),
|
||||
private_account_membership_proofs.to_vec(),
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1701,11 +1702,11 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
@ -1715,8 +1716,8 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||
),
|
||||
],
|
||||
&[sender_keys.nsk],
|
||||
&[Some((0, vec![]))],
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1749,11 +1750,11 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
@ -1763,8 +1764,8 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||
),
|
||||
],
|
||||
&[sender_keys.nsk],
|
||||
&[Some((0, vec![]))],
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1796,11 +1797,11 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
@ -1810,8 +1811,8 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||
),
|
||||
],
|
||||
&[sender_keys.nsk],
|
||||
&[Some((0, vec![]))],
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1843,11 +1844,11 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
@ -1857,8 +1858,8 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||
),
|
||||
],
|
||||
&[sender_keys.nsk],
|
||||
&[Some((0, vec![]))],
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1888,11 +1889,11 @@ pub mod tests {
|
||||
);
|
||||
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
@ -1902,8 +1903,8 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||
),
|
||||
],
|
||||
&[sender_keys.nsk],
|
||||
&[Some((0, vec![]))],
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1927,13 +1928,13 @@ pub mod tests {
|
||||
|
||||
let visibility_mask = [0, 3];
|
||||
let result = execute_and_prove(
|
||||
&[public_account_1, public_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&visibility_mask,
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
vec![public_account_1, public_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
visibility_mask.to_vec(),
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -1961,11 +1962,11 @@ pub mod tests {
|
||||
// accounts.
|
||||
let private_account_nonces = [0xdeadbeef1, 0xdeadbeef2, 0xdeadbeef3];
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&private_account_nonces,
|
||||
&[
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
private_account_nonces.to_vec(),
|
||||
vec![
|
||||
(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
@ -1975,8 +1976,8 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||
),
|
||||
],
|
||||
&[sender_keys.nsk],
|
||||
&[Some((0, vec![]))],
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -2017,13 +2018,13 @@ pub mod tests {
|
||||
),
|
||||
];
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&private_account_keys,
|
||||
&[sender_keys.nsk],
|
||||
&[Some((0, vec![]))],
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
vec![1, 2],
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
private_account_keys.to_vec(),
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -2053,11 +2054,11 @@ pub mod tests {
|
||||
let private_account_nsks = [sender_keys.nsk, recipient_keys.nsk];
|
||||
let private_account_membership_proofs = [Some((0, vec![])), Some((1, vec![]))];
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1, private_account_2],
|
||||
&Program::serialize_instruction(10u128).unwrap(),
|
||||
&visibility_mask,
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![private_account_1, private_account_2],
|
||||
Program::serialize_instruction(10u128).unwrap(),
|
||||
visibility_mask.to_vec(),
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[55; 32], &sender_keys.ivk()),
|
||||
@ -2067,8 +2068,8 @@ pub mod tests {
|
||||
SharedSecretKey::new(&[56; 32], &recipient_keys.ivk()),
|
||||
),
|
||||
],
|
||||
&private_account_nsks,
|
||||
&private_account_membership_proofs,
|
||||
private_account_nsks.to_vec(),
|
||||
private_account_membership_proofs.to_vec(),
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -2149,16 +2150,16 @@ pub mod tests {
|
||||
let private_account_membership_proofs = [Some((1, vec![])), Some((1, vec![]))];
|
||||
let shared_secret = SharedSecretKey::new(&[55; 32], &sender_keys.ivk());
|
||||
let result = execute_and_prove(
|
||||
&[private_account_1.clone(), private_account_1],
|
||||
&Program::serialize_instruction(100u128).unwrap(),
|
||||
&visibility_mask,
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
vec![private_account_1.clone(), private_account_1],
|
||||
Program::serialize_instruction(100u128).unwrap(),
|
||||
visibility_mask.to_vec(),
|
||||
vec![0xdeadbeef1, 0xdeadbeef2],
|
||||
vec![
|
||||
(sender_keys.npk(), shared_secret),
|
||||
(sender_keys.npk(), shared_secret),
|
||||
],
|
||||
&private_account_nsks,
|
||||
&private_account_membership_proofs,
|
||||
private_account_nsks.to_vec(),
|
||||
private_account_membership_proofs.to_vec(),
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
@ -3941,8 +3942,9 @@ pub mod tests {
|
||||
assert_eq!(to_post, expected_to_post);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_private_chained_call() {
|
||||
#[test_case::test_case(1; "single call")]
|
||||
#[test_case::test_case(2; "two calls")]
|
||||
fn test_private_chained_call(number_of_calls: u32) {
|
||||
// Arrange
|
||||
let chain_caller = Program::chain_caller();
|
||||
let auth_transfers = Program::authenticated_transfer_program();
|
||||
@ -3978,7 +3980,7 @@ pub mod tests {
|
||||
let instruction: (u128, ProgramId, u32, Option<PdaSeed>) = (
|
||||
amount,
|
||||
Program::authenticated_transfer_program().id(),
|
||||
1,
|
||||
number_of_calls,
|
||||
None,
|
||||
);
|
||||
|
||||
@ -3999,14 +4001,14 @@ pub mod tests {
|
||||
let to_new_nonce = 0xdeadbeef2;
|
||||
|
||||
let from_expected_post = Account {
|
||||
balance: initial_balance - amount,
|
||||
balance: initial_balance - number_of_calls as u128 * amount,
|
||||
nonce: from_new_nonce,
|
||||
..from_account.account.clone()
|
||||
};
|
||||
let from_expected_commitment = Commitment::new(&from_keys.npk(), &from_expected_post);
|
||||
|
||||
let to_expected_post = Account {
|
||||
balance: amount,
|
||||
balance: number_of_calls as u128 * amount,
|
||||
nonce: to_new_nonce,
|
||||
..to_account.account.clone()
|
||||
};
|
||||
@ -4014,13 +4016,13 @@ pub mod tests {
|
||||
|
||||
// Act
|
||||
let (output, proof) = execute_and_prove(
|
||||
&[to_account, from_account],
|
||||
&Program::serialize_instruction(instruction).unwrap(),
|
||||
&[1, 1],
|
||||
&[from_new_nonce, to_new_nonce],
|
||||
&[(from_keys.npk(), to_ss), (to_keys.npk(), from_ss)],
|
||||
&[from_keys.nsk, to_keys.nsk],
|
||||
&[
|
||||
vec![to_account, from_account],
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
vec![1, 1],
|
||||
vec![from_new_nonce, to_new_nonce],
|
||||
vec![(from_keys.npk(), to_ss), (to_keys.npk(), from_ss)],
|
||||
vec![from_keys.nsk, to_keys.nsk],
|
||||
vec![
|
||||
state.get_proof_for_commitment(&from_commitment),
|
||||
state.get_proof_for_commitment(&to_commitment),
|
||||
],
|
||||
@ -4255,13 +4257,13 @@ pub mod tests {
|
||||
|
||||
// Execute and prove the circuit with the authorized account but no commitment proof
|
||||
let (output, proof) = execute_and_prove(
|
||||
std::slice::from_ref(&authorized_account),
|
||||
&Program::serialize_instruction(balance).unwrap(),
|
||||
&[1],
|
||||
&[nonce],
|
||||
&[(private_keys.npk(), shared_secret)],
|
||||
&[private_keys.nsk],
|
||||
&[None],
|
||||
vec![authorized_account],
|
||||
Program::serialize_instruction(balance).unwrap(),
|
||||
vec![1],
|
||||
vec![nonce],
|
||||
vec![(private_keys.npk(), shared_secret)],
|
||||
vec![private_keys.nsk],
|
||||
vec![None],
|
||||
&program.into(),
|
||||
)
|
||||
.unwrap();
|
||||
@ -4308,13 +4310,13 @@ pub mod tests {
|
||||
|
||||
// Step 2: Execute claimer program to claim the account with authentication
|
||||
let (output, proof) = execute_and_prove(
|
||||
std::slice::from_ref(&authorized_account),
|
||||
&Program::serialize_instruction(balance).unwrap(),
|
||||
&[1],
|
||||
&[nonce],
|
||||
&[(private_keys.npk(), shared_secret)],
|
||||
&[private_keys.nsk],
|
||||
&[None],
|
||||
vec![authorized_account.clone()],
|
||||
Program::serialize_instruction(balance).unwrap(),
|
||||
vec![1],
|
||||
vec![nonce],
|
||||
vec![(private_keys.npk(), shared_secret)],
|
||||
vec![private_keys.nsk],
|
||||
vec![None],
|
||||
&claimer_program.into(),
|
||||
)
|
||||
.unwrap();
|
||||
@ -4356,16 +4358,174 @@ pub mod tests {
|
||||
|
||||
// Step 3: Try to execute noop program with authentication but without initialization
|
||||
let res = execute_and_prove(
|
||||
std::slice::from_ref(&account_metadata),
|
||||
&Program::serialize_instruction(()).unwrap(),
|
||||
&[1],
|
||||
&[nonce2],
|
||||
&[(private_keys.npk(), shared_secret2)],
|
||||
&[private_keys.nsk],
|
||||
&[None],
|
||||
vec![account_metadata],
|
||||
Program::serialize_instruction(()).unwrap(),
|
||||
vec![1],
|
||||
vec![nonce2],
|
||||
vec![(private_keys.npk(), shared_secret2)],
|
||||
vec![private_keys.nsk],
|
||||
vec![None],
|
||||
&noop_program.into(),
|
||||
);
|
||||
|
||||
assert!(matches!(res, Err(NssaError::CircuitProvingError(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_public_changer_claimer_no_data_change_no_claim_succeeds() {
|
||||
let initial_data = [];
|
||||
let mut state =
|
||||
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||
let account_id = AccountId::new([1; 32]);
|
||||
let program_id = Program::changer_claimer().id();
|
||||
// Don't change data (None) and don't claim (false)
|
||||
let instruction: (Option<Vec<u8>>, bool) = (None, false);
|
||||
|
||||
let message =
|
||||
public_transaction::Message::try_new(program_id, vec![account_id], vec![], instruction)
|
||||
.unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx);
|
||||
|
||||
// Should succeed - no changes made, no claim needed
|
||||
assert!(result.is_ok());
|
||||
// Account should remain default/unclaimed
|
||||
assert_eq!(state.get_account_by_id(&account_id), Account::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_public_changer_claimer_data_change_no_claim_fails() {
|
||||
let initial_data = [];
|
||||
let mut state =
|
||||
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||
let account_id = AccountId::new([1; 32]);
|
||||
let program_id = Program::changer_claimer().id();
|
||||
// Change data but don't claim (false) - should fail
|
||||
let new_data = vec![1, 2, 3, 4, 5];
|
||||
let instruction: (Option<Vec<u8>>, bool) = (Some(new_data), false);
|
||||
|
||||
let message =
|
||||
public_transaction::Message::try_new(program_id, vec![account_id], vec![], instruction)
|
||||
.unwrap();
|
||||
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
let tx = PublicTransaction::new(message, witness_set);
|
||||
|
||||
let result = state.transition_from_public_transaction(&tx);
|
||||
|
||||
// Should fail - cannot modify data without claiming the account
|
||||
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_private_changer_claimer_no_data_change_no_claim_succeeds() {
|
||||
let program = Program::changer_claimer();
|
||||
let sender_keys = test_private_account_keys_1();
|
||||
let private_account =
|
||||
AccountWithMetadata::new(Account::default(), true, &sender_keys.npk());
|
||||
// Don't change data (None) and don't claim (false)
|
||||
let instruction: (Option<Vec<u8>>, bool) = (None, false);
|
||||
|
||||
let result = execute_and_prove(
|
||||
vec![private_account],
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
vec![1],
|
||||
vec![2],
|
||||
vec![(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[3; 32], &sender_keys.ivk()),
|
||||
)],
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
// Should succeed - no changes made, no claim needed
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_private_changer_claimer_data_change_no_claim_fails() {
|
||||
let program = Program::changer_claimer();
|
||||
let sender_keys = test_private_account_keys_1();
|
||||
let private_account =
|
||||
AccountWithMetadata::new(Account::default(), true, &sender_keys.npk());
|
||||
// Change data but don't claim (false) - should fail
|
||||
let new_data = vec![1, 2, 3, 4, 5];
|
||||
let instruction: (Option<Vec<u8>>, bool) = (Some(new_data), false);
|
||||
|
||||
let result = execute_and_prove(
|
||||
vec![private_account],
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
vec![1],
|
||||
vec![2],
|
||||
vec![(
|
||||
sender_keys.npk(),
|
||||
SharedSecretKey::new(&[3; 32], &sender_keys.ivk()),
|
||||
)],
|
||||
vec![sender_keys.nsk],
|
||||
vec![Some((0, vec![]))],
|
||||
&program.into(),
|
||||
);
|
||||
|
||||
// Should fail - cannot modify data without claiming the account
|
||||
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_malicious_authorization_changer_should_fail_in_privacy_preserving_circuit() {
|
||||
// Arrange
|
||||
let malicious_program = Program::malicious_authorization_changer();
|
||||
let auth_transfers = Program::authenticated_transfer_program();
|
||||
let sender_keys = test_public_account_keys_1();
|
||||
let recipient_keys = test_private_account_keys_1();
|
||||
|
||||
let sender_account = AccountWithMetadata::new(
|
||||
Account {
|
||||
program_owner: auth_transfers.id(),
|
||||
balance: 100,
|
||||
..Default::default()
|
||||
},
|
||||
false,
|
||||
sender_keys.account_id(),
|
||||
);
|
||||
let recipient_account =
|
||||
AccountWithMetadata::new(Account::default(), true, &recipient_keys.npk());
|
||||
|
||||
let recipient_commitment =
|
||||
Commitment::new(&recipient_keys.npk(), &recipient_account.account);
|
||||
let state = V02State::new_with_genesis_accounts(
|
||||
&[(sender_account.account_id, sender_account.account.balance)],
|
||||
std::slice::from_ref(&recipient_commitment),
|
||||
)
|
||||
.with_test_programs();
|
||||
|
||||
let balance_to_transfer = 10u128;
|
||||
let instruction = (balance_to_transfer, auth_transfers.id());
|
||||
|
||||
let recipient_esk = [3; 32];
|
||||
let recipient = SharedSecretKey::new(&recipient_esk, &recipient_keys.ivk());
|
||||
|
||||
let mut dependencies = HashMap::new();
|
||||
dependencies.insert(auth_transfers.id(), auth_transfers);
|
||||
let program_with_deps = ProgramWithDependencies::new(malicious_program, dependencies);
|
||||
|
||||
let recipient_new_nonce = 0xdeadbeef1;
|
||||
|
||||
// Act - execute the malicious program - this should fail during proving
|
||||
let result = execute_and_prove(
|
||||
vec![sender_account, recipient_account],
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
vec![0, 1],
|
||||
vec![recipient_new_nonce],
|
||||
vec![(recipient_keys.npk(), recipient)],
|
||||
vec![recipient_keys.nsk],
|
||||
vec![state.get_proof_for_commitment(&recipient_commitment)],
|
||||
&program_with_deps,
|
||||
);
|
||||
|
||||
// Assert - should fail because the malicious program tries to manipulate is_authorized
|
||||
assert!(matches!(result, Err(NssaError::CircuitProvingError(_))));
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ fn main() {
|
||||
instruction_words,
|
||||
vec![pinata, winner],
|
||||
vec![
|
||||
AccountPostState::new(pinata_post),
|
||||
AccountPostState::new_claimed_if_default(pinata_post),
|
||||
AccountPostState::new(winner_post),
|
||||
],
|
||||
);
|
||||
|
||||
@ -1,12 +1,18 @@
|
||||
use std::collections::HashMap;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet, VecDeque, hash_map::Entry},
|
||||
convert::Infallible,
|
||||
};
|
||||
|
||||
use nssa_core::{
|
||||
Commitment, CommitmentSetDigest, DUMMY_COMMITMENT_HASH, EncryptionScheme, Nullifier,
|
||||
NullifierPublicKey, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput,
|
||||
account::{Account, AccountId, AccountWithMetadata},
|
||||
Commitment, CommitmentSetDigest, DUMMY_COMMITMENT_HASH, EncryptionScheme, MembershipProof,
|
||||
Nullifier, NullifierPublicKey, NullifierSecretKey, PrivacyPreservingCircuitInput,
|
||||
PrivacyPreservingCircuitOutput, SharedSecretKey,
|
||||
account::{Account, AccountId, AccountWithMetadata, Nonce},
|
||||
compute_digest_for_path,
|
||||
encryption::Ciphertext,
|
||||
program::{DEFAULT_PROGRAM_ID, MAX_NUMBER_CHAINED_CALLS, validate_execution},
|
||||
program::{
|
||||
AccountPostState, ChainedCall, DEFAULT_PROGRAM_ID, MAX_NUMBER_CHAINED_CALLS, ProgramId,
|
||||
ProgramOutput, validate_execution,
|
||||
},
|
||||
};
|
||||
use risc0_zkvm::{guest::env, serde::to_vec};
|
||||
|
||||
@ -18,118 +24,224 @@ fn main() {
|
||||
private_account_keys,
|
||||
private_account_nsks,
|
||||
private_account_membership_proofs,
|
||||
mut program_id,
|
||||
program_id,
|
||||
} = env::read();
|
||||
|
||||
let mut pre_states: Vec<AccountWithMetadata> = Vec::new();
|
||||
let mut state_diff: HashMap<AccountId, Account> = HashMap::new();
|
||||
let execution_state = ExecutionState::derive_from_outputs(program_id, program_outputs);
|
||||
|
||||
let num_calls = program_outputs.len();
|
||||
if num_calls > MAX_NUMBER_CHAINED_CALLS {
|
||||
panic!("Max chained calls depth is exceeded");
|
||||
}
|
||||
let output = compute_circuit_output(
|
||||
execution_state,
|
||||
&visibility_mask,
|
||||
&private_account_nonces,
|
||||
&private_account_keys,
|
||||
&private_account_nsks,
|
||||
&private_account_membership_proofs,
|
||||
);
|
||||
|
||||
let Some(last_program_call) = program_outputs.last() else {
|
||||
panic!("Program outputs is empty")
|
||||
};
|
||||
env::commit(&output);
|
||||
}
|
||||
|
||||
if !last_program_call.chained_calls.is_empty() {
|
||||
panic!("Call stack is incomplete");
|
||||
}
|
||||
/// State of the involved accounts before and after program execution.
|
||||
struct ExecutionState {
|
||||
pre_states: Vec<AccountWithMetadata>,
|
||||
post_states: HashMap<AccountId, Account>,
|
||||
}
|
||||
|
||||
for window in program_outputs.windows(2) {
|
||||
let caller = &window[0];
|
||||
let callee = &window[1];
|
||||
|
||||
if caller.chained_calls.len() > 1 {
|
||||
panic!("Privacy Multi-chained calls are not supported yet");
|
||||
}
|
||||
|
||||
// TODO: Modify when multi-chain calls are supported in the circuit
|
||||
let Some(caller_chained_call) = &caller.chained_calls.first() else {
|
||||
panic!("Expected chained call");
|
||||
impl ExecutionState {
|
||||
/// Validate program outputs and derive the overall execution state.
|
||||
pub fn derive_from_outputs(program_id: ProgramId, program_outputs: Vec<ProgramOutput>) -> Self {
|
||||
let Some(first_output) = program_outputs.first() else {
|
||||
panic!("No program outputs provided");
|
||||
};
|
||||
|
||||
// Check that instruction data in caller is the instruction data in callee
|
||||
if caller_chained_call.instruction_data != callee.instruction_data {
|
||||
panic!("Invalid instruction data");
|
||||
}
|
||||
|
||||
// Check that account pre_states in caller are the ones in calle
|
||||
if caller_chained_call.pre_states != callee.pre_states {
|
||||
panic!("Invalid pre states");
|
||||
}
|
||||
}
|
||||
|
||||
for (i, program_output) in program_outputs.iter().enumerate() {
|
||||
let mut program_output = program_output.clone();
|
||||
|
||||
// Check that `program_output` is consistent with the execution of the corresponding
|
||||
// program.
|
||||
let program_output_words =
|
||||
&to_vec(&program_output).expect("program_output must be serializable");
|
||||
env::verify(program_id, program_output_words)
|
||||
.expect("program output must match the program's execution");
|
||||
|
||||
// Check that the program is well behaved.
|
||||
// See the # Programs section for the definition of the `validate_execution` method.
|
||||
if !validate_execution(
|
||||
&program_output.pre_states,
|
||||
&program_output.post_states,
|
||||
let initial_call = ChainedCall {
|
||||
program_id,
|
||||
) {
|
||||
panic!("Bad behaved program");
|
||||
}
|
||||
instruction_data: first_output.instruction_data.clone(),
|
||||
pre_states: first_output.pre_states.clone(),
|
||||
pda_seeds: Vec::new(),
|
||||
};
|
||||
let mut chained_calls = VecDeque::from_iter([(initial_call, None)]);
|
||||
|
||||
// The invoked program claims the accounts with default program id.
|
||||
for post in program_output
|
||||
.post_states
|
||||
.iter_mut()
|
||||
.filter(|post| post.requires_claim())
|
||||
{
|
||||
// The invoked program can only claim accounts with default program id.
|
||||
if post.account().program_owner == DEFAULT_PROGRAM_ID {
|
||||
post.account_mut().program_owner = program_id;
|
||||
} else {
|
||||
panic!("Cannot claim an initialized account")
|
||||
let mut execution_state = ExecutionState {
|
||||
pre_states: Vec::new(),
|
||||
post_states: HashMap::new(),
|
||||
};
|
||||
|
||||
let mut program_outputs_iter = program_outputs.into_iter();
|
||||
let mut chain_calls_counter = 0;
|
||||
|
||||
while let Some((chained_call, caller_program_id)) = chained_calls.pop_front() {
|
||||
assert!(
|
||||
chain_calls_counter <= MAX_NUMBER_CHAINED_CALLS,
|
||||
"Max chained calls depth is exceeded"
|
||||
);
|
||||
|
||||
let Some(program_output) = program_outputs_iter.next() else {
|
||||
panic!("Insufficient program outputs for chained calls");
|
||||
};
|
||||
|
||||
// Check that instruction data in chained call is the instruction data in program output
|
||||
assert_eq!(
|
||||
chained_call.instruction_data, program_output.instruction_data,
|
||||
"Mismatched instruction data between chained call and program output"
|
||||
);
|
||||
|
||||
// Check that `program_output` is consistent with the execution of the corresponding
|
||||
// program.
|
||||
let program_output_words =
|
||||
&to_vec(&program_output).expect("program_output must be serializable");
|
||||
env::verify(chained_call.program_id, program_output_words).unwrap_or_else(
|
||||
|_: Infallible| unreachable!("Infallible error is never constructed"),
|
||||
);
|
||||
|
||||
// Check that the program is well behaved.
|
||||
// See the # Programs section for the definition of the `validate_execution` method.
|
||||
let execution_valid = validate_execution(
|
||||
&program_output.pre_states,
|
||||
&program_output.post_states,
|
||||
chained_call.program_id,
|
||||
);
|
||||
assert!(execution_valid, "Bad behaved program");
|
||||
|
||||
for next_call in program_output.chained_calls.iter().rev() {
|
||||
chained_calls.push_front((next_call.clone(), Some(chained_call.program_id)));
|
||||
}
|
||||
|
||||
let authorized_pdas = nssa_core::program::compute_authorized_pdas(
|
||||
caller_program_id,
|
||||
&chained_call.pda_seeds,
|
||||
);
|
||||
execution_state.validate_and_sync_states(
|
||||
chained_call.program_id,
|
||||
authorized_pdas,
|
||||
program_output.pre_states,
|
||||
program_output.post_states,
|
||||
);
|
||||
chain_calls_counter += 1;
|
||||
}
|
||||
|
||||
for (pre, post) in program_output
|
||||
assert!(
|
||||
program_outputs_iter.next().is_none(),
|
||||
"Inner call without a chained call found",
|
||||
);
|
||||
|
||||
// Check that all modified uninitialized accounts were claimed
|
||||
for (account_id, post) in execution_state
|
||||
.pre_states
|
||||
.iter()
|
||||
.zip(&program_output.post_states)
|
||||
.filter(|a| a.account.program_owner == DEFAULT_PROGRAM_ID)
|
||||
.map(|a| {
|
||||
let post = execution_state
|
||||
.post_states
|
||||
.get(&a.account_id)
|
||||
.expect("Post state must exist for pre state");
|
||||
(a, post)
|
||||
})
|
||||
.filter(|(pre_default, post)| pre_default.account != **post)
|
||||
.map(|(pre, post)| (pre.account_id, post))
|
||||
{
|
||||
if let Some(account_pre) = state_diff.get(&pre.account_id) {
|
||||
if account_pre != &pre.account {
|
||||
panic!("Invalid input");
|
||||
}
|
||||
} else {
|
||||
pre_states.push(pre.clone());
|
||||
}
|
||||
state_diff.insert(pre.account_id, post.account().clone());
|
||||
assert_ne!(
|
||||
post.program_owner, DEFAULT_PROGRAM_ID,
|
||||
"Account {account_id:?} was modified but not claimed"
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Modify when multi-chain calls are supported in the circuit
|
||||
if let Some(next_chained_call) = &program_output.chained_calls.first() {
|
||||
program_id = next_chained_call.program_id;
|
||||
} else if i != program_outputs.len() - 1 {
|
||||
panic!("Inner call without a chained call found")
|
||||
};
|
||||
execution_state
|
||||
}
|
||||
|
||||
let n_accounts = pre_states.len();
|
||||
if visibility_mask.len() != n_accounts {
|
||||
panic!("Invalid visibility mask length");
|
||||
/// Validate program pre and post states and populate the execution state.
|
||||
fn validate_and_sync_states(
|
||||
&mut self,
|
||||
program_id: ProgramId,
|
||||
authorized_pdas: HashSet<AccountId>,
|
||||
pre_states: Vec<AccountWithMetadata>,
|
||||
post_states: Vec<AccountPostState>,
|
||||
) {
|
||||
for (pre, mut post) in pre_states.into_iter().zip(post_states) {
|
||||
let pre_account_id = pre.account_id;
|
||||
let post_states_entry = self.post_states.entry(pre.account_id);
|
||||
match &post_states_entry {
|
||||
Entry::Occupied(occupied) => {
|
||||
// Ensure that new pre state is the same as known post state
|
||||
assert_eq!(
|
||||
occupied.get(),
|
||||
&pre.account,
|
||||
"Inconsistent pre state for account {pre_account_id:?}",
|
||||
);
|
||||
|
||||
let previous_is_authorized = self
|
||||
.pre_states
|
||||
.iter()
|
||||
.find(|acc| acc.account_id == pre_account_id)
|
||||
.map(|acc| acc.is_authorized)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Pre state must exist in execution state for account {pre_account_id:?}",
|
||||
)
|
||||
});
|
||||
|
||||
let is_authorized =
|
||||
previous_is_authorized || authorized_pdas.contains(&pre_account_id);
|
||||
|
||||
assert_eq!(
|
||||
pre.is_authorized, is_authorized,
|
||||
"Inconsistent authorization for account {pre_account_id:?}",
|
||||
);
|
||||
}
|
||||
Entry::Vacant(_) => {
|
||||
self.pre_states.push(pre);
|
||||
}
|
||||
}
|
||||
|
||||
if post.requires_claim() {
|
||||
// The invoked program can only claim accounts with default program id.
|
||||
if post.account().program_owner == DEFAULT_PROGRAM_ID {
|
||||
post.account_mut().program_owner = program_id;
|
||||
} else {
|
||||
panic!("Cannot claim an initialized account {pre_account_id:?}");
|
||||
}
|
||||
}
|
||||
|
||||
post_states_entry.insert_entry(post.into_account());
|
||||
}
|
||||
}
|
||||
|
||||
// These lists will be the public outputs of this circuit
|
||||
// and will be populated next.
|
||||
let mut public_pre_states: Vec<AccountWithMetadata> = Vec::new();
|
||||
let mut public_post_states: Vec<Account> = Vec::new();
|
||||
let mut ciphertexts: Vec<Ciphertext> = Vec::new();
|
||||
let mut new_commitments: Vec<Commitment> = Vec::new();
|
||||
let mut new_nullifiers: Vec<(Nullifier, CommitmentSetDigest)> = Vec::new();
|
||||
/// Get an iterator over pre and post states of each account involved in the execution.
|
||||
pub fn into_states_iter(
|
||||
mut self,
|
||||
) -> impl ExactSizeIterator<Item = (AccountWithMetadata, Account)> {
|
||||
self.pre_states.into_iter().map(move |pre| {
|
||||
let post = self
|
||||
.post_states
|
||||
.remove(&pre.account_id)
|
||||
.expect("Account from pre states should exist in state diff");
|
||||
(pre, post)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_circuit_output(
|
||||
execution_state: ExecutionState,
|
||||
visibility_mask: &[u8],
|
||||
private_account_nonces: &[Nonce],
|
||||
private_account_keys: &[(NullifierPublicKey, SharedSecretKey)],
|
||||
private_account_nsks: &[NullifierSecretKey],
|
||||
private_account_membership_proofs: &[Option<MembershipProof>],
|
||||
) -> PrivacyPreservingCircuitOutput {
|
||||
let mut output = PrivacyPreservingCircuitOutput {
|
||||
public_pre_states: Vec::new(),
|
||||
public_post_states: Vec::new(),
|
||||
ciphertexts: Vec::new(),
|
||||
new_commitments: Vec::new(),
|
||||
new_nullifiers: Vec::new(),
|
||||
};
|
||||
|
||||
let states_iter = execution_state.into_states_iter();
|
||||
assert_eq!(
|
||||
visibility_mask.len(),
|
||||
states_iter.len(),
|
||||
"Invalid visibility mask length"
|
||||
);
|
||||
|
||||
let mut private_nonces_iter = private_account_nonces.iter();
|
||||
let mut private_keys_iter = private_account_keys.iter();
|
||||
@ -137,141 +249,156 @@ fn main() {
|
||||
let mut private_membership_proofs_iter = private_account_membership_proofs.iter();
|
||||
|
||||
let mut output_index = 0;
|
||||
for i in 0..n_accounts {
|
||||
match visibility_mask[i] {
|
||||
for (visibility_mask, (pre_state, post_state)) in
|
||||
visibility_mask.iter().copied().zip(states_iter)
|
||||
{
|
||||
match visibility_mask {
|
||||
0 => {
|
||||
// Public account
|
||||
public_pre_states.push(pre_states[i].clone());
|
||||
|
||||
let mut post = state_diff.get(&pre_states[i].account_id).unwrap().clone();
|
||||
|
||||
if post.program_owner == DEFAULT_PROGRAM_ID {
|
||||
// Claim account
|
||||
post.program_owner = program_id;
|
||||
}
|
||||
public_post_states.push(post);
|
||||
output.public_pre_states.push(pre_state);
|
||||
output.public_post_states.push(post_state);
|
||||
}
|
||||
1 | 2 => {
|
||||
let new_nonce = private_nonces_iter.next().expect("Missing private nonce");
|
||||
let (npk, shared_secret) = private_keys_iter.next().expect("Missing keys");
|
||||
let Some((npk, shared_secret)) = private_keys_iter.next() else {
|
||||
panic!("Missing private account key");
|
||||
};
|
||||
|
||||
if AccountId::from(npk) != pre_states[i].account_id {
|
||||
panic!("AccountId mismatch");
|
||||
}
|
||||
assert_eq!(
|
||||
AccountId::from(npk),
|
||||
pre_state.account_id,
|
||||
"AccountId mismatch"
|
||||
);
|
||||
|
||||
if visibility_mask[i] == 1 {
|
||||
let new_nullifier = if visibility_mask == 1 {
|
||||
// Private account with authentication
|
||||
let nsk = private_nsks_iter.next().expect("Missing nsk");
|
||||
|
||||
let Some(nsk) = private_nsks_iter.next() else {
|
||||
panic!("Missing private account nullifier secret key");
|
||||
};
|
||||
|
||||
// Verify the nullifier public key
|
||||
let expected_npk = NullifierPublicKey::from(nsk);
|
||||
if &expected_npk != npk {
|
||||
panic!("Nullifier public key mismatch");
|
||||
}
|
||||
assert_eq!(
|
||||
npk,
|
||||
&NullifierPublicKey::from(nsk),
|
||||
"Nullifier public key mismatch"
|
||||
);
|
||||
|
||||
// Check pre_state authorization
|
||||
if !pre_states[i].is_authorized {
|
||||
panic!("Pre-state not authorized");
|
||||
}
|
||||
assert!(
|
||||
pre_state.is_authorized,
|
||||
"Pre-state not authorized for authenticated private account"
|
||||
);
|
||||
|
||||
let membership_proof_opt = private_membership_proofs_iter
|
||||
.next()
|
||||
.expect("Missing membership proof");
|
||||
let (nullifier, set_digest) = membership_proof_opt
|
||||
.as_ref()
|
||||
.map(|membership_proof| {
|
||||
// Compute commitment set digest associated with provided auth path
|
||||
let commitment_pre = Commitment::new(npk, &pre_states[i].account);
|
||||
let set_digest =
|
||||
compute_digest_for_path(&commitment_pre, membership_proof);
|
||||
let Some(membership_proof_opt) = private_membership_proofs_iter.next() else {
|
||||
panic!("Missing membership proof");
|
||||
};
|
||||
|
||||
// Compute update nullifier
|
||||
let nullifier = Nullifier::for_account_update(&commitment_pre, nsk);
|
||||
(nullifier, set_digest)
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
if pre_states[i].account != Account::default() {
|
||||
panic!("Found new private account with non default values.");
|
||||
}
|
||||
|
||||
// Compute initialization nullifier
|
||||
let nullifier = Nullifier::for_account_initialization(npk);
|
||||
(nullifier, DUMMY_COMMITMENT_HASH)
|
||||
});
|
||||
new_nullifiers.push((nullifier, set_digest));
|
||||
compute_nullifier_and_set_digest(
|
||||
membership_proof_opt.as_ref(),
|
||||
&pre_state.account,
|
||||
npk,
|
||||
nsk,
|
||||
)
|
||||
} else {
|
||||
// Private account without authentication
|
||||
if pre_states[i].account != Account::default() {
|
||||
panic!("Found new private account with non default values.");
|
||||
}
|
||||
|
||||
if pre_states[i].is_authorized {
|
||||
panic!("Found new private account marked as authorized.");
|
||||
}
|
||||
assert_eq!(
|
||||
pre_state.account,
|
||||
Account::default(),
|
||||
"Found new private account with non default values",
|
||||
);
|
||||
|
||||
assert!(
|
||||
!pre_state.is_authorized,
|
||||
"Found new private account marked as authorized."
|
||||
);
|
||||
|
||||
let Some(membership_proof_opt) = private_membership_proofs_iter.next() else {
|
||||
panic!("Missing membership proof");
|
||||
};
|
||||
|
||||
let membership_proof_opt = private_membership_proofs_iter
|
||||
.next()
|
||||
.expect("Missing membership proof");
|
||||
assert!(
|
||||
membership_proof_opt.is_none(),
|
||||
"Membership proof must be None for unauthorized accounts"
|
||||
);
|
||||
|
||||
let nullifier = Nullifier::for_account_initialization(npk);
|
||||
new_nullifiers.push((nullifier, DUMMY_COMMITMENT_HASH));
|
||||
}
|
||||
(nullifier, DUMMY_COMMITMENT_HASH)
|
||||
};
|
||||
output.new_nullifiers.push(new_nullifier);
|
||||
|
||||
// Update post-state with new nonce
|
||||
let mut post_with_updated_values =
|
||||
state_diff.get(&pre_states[i].account_id).unwrap().clone();
|
||||
post_with_updated_values.nonce = *new_nonce;
|
||||
|
||||
if post_with_updated_values.program_owner == DEFAULT_PROGRAM_ID {
|
||||
// Claim account
|
||||
post_with_updated_values.program_owner = program_id;
|
||||
}
|
||||
let mut post_with_updated_nonce = post_state;
|
||||
let Some(new_nonce) = private_nonces_iter.next() else {
|
||||
panic!("Missing private account nonce");
|
||||
};
|
||||
post_with_updated_nonce.nonce = *new_nonce;
|
||||
|
||||
// Compute commitment
|
||||
let commitment_post = Commitment::new(npk, &post_with_updated_values);
|
||||
let commitment_post = Commitment::new(npk, &post_with_updated_nonce);
|
||||
|
||||
// Encrypt and push post state
|
||||
let encrypted_account = EncryptionScheme::encrypt(
|
||||
&post_with_updated_values,
|
||||
&post_with_updated_nonce,
|
||||
shared_secret,
|
||||
&commitment_post,
|
||||
output_index,
|
||||
);
|
||||
|
||||
new_commitments.push(commitment_post);
|
||||
ciphertexts.push(encrypted_account);
|
||||
output.new_commitments.push(commitment_post);
|
||||
output.ciphertexts.push(encrypted_account);
|
||||
output_index += 1;
|
||||
}
|
||||
_ => panic!("Invalid visibility mask value"),
|
||||
}
|
||||
}
|
||||
|
||||
if private_nonces_iter.next().is_some() {
|
||||
panic!("Too many nonces");
|
||||
}
|
||||
assert!(private_nonces_iter.next().is_none(), "Too many nonces");
|
||||
|
||||
if private_keys_iter.next().is_some() {
|
||||
panic!("Too many private account keys");
|
||||
}
|
||||
assert!(
|
||||
private_keys_iter.next().is_none(),
|
||||
"Too many private account keys"
|
||||
);
|
||||
|
||||
if private_nsks_iter.next().is_some() {
|
||||
panic!("Too many private account authentication keys");
|
||||
}
|
||||
assert!(
|
||||
private_nsks_iter.next().is_none(),
|
||||
"Too many private account nullifier secret keys"
|
||||
);
|
||||
|
||||
if private_membership_proofs_iter.next().is_some() {
|
||||
panic!("Too many private account membership proofs");
|
||||
}
|
||||
assert!(
|
||||
private_membership_proofs_iter.next().is_none(),
|
||||
"Too many private account membership proofs"
|
||||
);
|
||||
|
||||
let output = PrivacyPreservingCircuitOutput {
|
||||
public_pre_states,
|
||||
public_post_states,
|
||||
ciphertexts,
|
||||
new_commitments,
|
||||
new_nullifiers,
|
||||
};
|
||||
|
||||
env::commit(&output);
|
||||
output
|
||||
}
|
||||
|
||||
fn compute_nullifier_and_set_digest(
|
||||
membership_proof_opt: Option<&MembershipProof>,
|
||||
pre_account: &Account,
|
||||
npk: &NullifierPublicKey,
|
||||
nsk: &NullifierSecretKey,
|
||||
) -> (Nullifier, CommitmentSetDigest) {
|
||||
membership_proof_opt
|
||||
.as_ref()
|
||||
.map(|membership_proof| {
|
||||
// Compute commitment set digest associated with provided auth path
|
||||
let commitment_pre = Commitment::new(npk, pre_account);
|
||||
let set_digest = compute_digest_for_path(&commitment_pre, membership_proof);
|
||||
|
||||
// Compute update nullifier
|
||||
let nullifier = Nullifier::for_account_update(&commitment_pre, nsk);
|
||||
(nullifier, set_digest)
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
assert_eq!(
|
||||
*pre_account,
|
||||
Account::default(),
|
||||
"Found new private account with non default values"
|
||||
);
|
||||
|
||||
// Compute initialization nullifier
|
||||
let nullifier = Nullifier::for_account_initialization(npk);
|
||||
(nullifier, DUMMY_COMMITMENT_HASH)
|
||||
})
|
||||
}
|
||||
|
||||
38
test_program_methods/guest/src/bin/changer_claimer.rs
Normal file
38
test_program_methods/guest/src/bin/changer_claimer.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use nssa_core::program::{AccountPostState, ProgramInput, read_nssa_inputs, write_nssa_outputs};
|
||||
|
||||
type Instruction = (Option<Vec<u8>>, bool);
|
||||
|
||||
/// A program that optionally modifies the account data and optionally claims it.
|
||||
fn main() {
|
||||
let (
|
||||
ProgramInput {
|
||||
pre_states,
|
||||
instruction: (data_opt, should_claim),
|
||||
},
|
||||
instruction_words,
|
||||
) = read_nssa_inputs::<Instruction>();
|
||||
|
||||
let [pre] = match pre_states.try_into() {
|
||||
Ok(array) => array,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let account_pre = &pre.account;
|
||||
let mut account_post = account_pre.clone();
|
||||
|
||||
// Update data if provided
|
||||
if let Some(data) = data_opt {
|
||||
account_post.data = data
|
||||
.try_into()
|
||||
.expect("provided data should fit into data limit");
|
||||
}
|
||||
|
||||
// Claim or not based on the boolean flag
|
||||
let post_state = if should_claim {
|
||||
AccountPostState::new_claimed(account_post)
|
||||
} else {
|
||||
AccountPostState::new(account_post)
|
||||
};
|
||||
|
||||
write_nssa_outputs(instruction_words, vec![pre], vec![post_state]);
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
use nssa_core::{
|
||||
account::AccountWithMetadata,
|
||||
program::{
|
||||
AccountPostState, ChainedCall, ProgramId, ProgramInput, read_nssa_inputs,
|
||||
write_nssa_outputs_with_chained_call,
|
||||
},
|
||||
};
|
||||
use risc0_zkvm::serde::to_vec;
|
||||
|
||||
type Instruction = (u128, ProgramId);
|
||||
|
||||
/// A malicious test program that attempts to change authorization status.
|
||||
/// It accepts two accounts and executes a native token transfer program via chain call,
|
||||
/// but sets the `is_authorized` field of the first account to true.
|
||||
fn main() {
|
||||
let (
|
||||
ProgramInput {
|
||||
pre_states,
|
||||
instruction: (balance, transfer_program_id),
|
||||
},
|
||||
instruction_words,
|
||||
) = read_nssa_inputs::<Instruction>();
|
||||
|
||||
let [sender, receiver] = match pre_states.try_into() {
|
||||
Ok(array) => array,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
// Maliciously set is_authorized to true for the first account
|
||||
let authorised_sender = AccountWithMetadata {
|
||||
is_authorized: true,
|
||||
..sender.clone()
|
||||
};
|
||||
|
||||
let instruction_data = to_vec(&balance).unwrap();
|
||||
|
||||
let chained_call = ChainedCall {
|
||||
program_id: transfer_program_id,
|
||||
instruction_data,
|
||||
pre_states: vec![authorised_sender.clone(), receiver.clone()],
|
||||
pda_seeds: vec![],
|
||||
};
|
||||
|
||||
write_nssa_outputs_with_chained_call(
|
||||
instruction_words,
|
||||
vec![sender.clone(), receiver.clone()],
|
||||
vec![
|
||||
AccountPostState::new(sender.account),
|
||||
AccountPostState::new(receiver.account),
|
||||
],
|
||||
vec![chained_call],
|
||||
);
|
||||
}
|
||||
@ -3,7 +3,7 @@ use base58::ToBase58;
|
||||
use clap::Subcommand;
|
||||
use itertools::Itertools as _;
|
||||
use key_protocol::key_management::key_tree::chain_index::ChainIndex;
|
||||
use nssa::{Account, program::Program};
|
||||
use nssa::{Account, PublicKey, program::Program};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
@ -20,6 +20,9 @@ pub enum AccountSubcommand {
|
||||
/// Flag to get raw account data
|
||||
#[arg(short, long)]
|
||||
raw: bool,
|
||||
/// Display keys (pk for public accounts, npk/ipk for private accounts)
|
||||
#[arg(short, long)]
|
||||
keys: bool,
|
||||
/// Valid 32 byte base58 string with privacy prefix
|
||||
#[arg(short, long)]
|
||||
account_id: String,
|
||||
@ -64,9 +67,18 @@ impl WalletSubcommand for NewSubcommand {
|
||||
NewSubcommand::Public { cci } => {
|
||||
let (account_id, chain_index) = wallet_core.create_new_account_public(cci);
|
||||
|
||||
let private_key = wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.get_pub_account_signing_key(&account_id)
|
||||
.unwrap();
|
||||
|
||||
let public_key = PublicKey::new_from_private_key(private_key);
|
||||
|
||||
println!(
|
||||
"Generated new account with account_id Public/{account_id} at path {chain_index}"
|
||||
);
|
||||
println!("With pk {}", hex::encode(public_key.value()));
|
||||
|
||||
wallet_core.store_persistent_data().await?;
|
||||
|
||||
@ -201,7 +213,11 @@ impl WalletSubcommand for AccountSubcommand {
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
AccountSubcommand::Get { raw, account_id } => {
|
||||
AccountSubcommand::Get {
|
||||
raw,
|
||||
keys,
|
||||
account_id,
|
||||
} => {
|
||||
let (account_id, addr_kind) = parse_addr_with_privacy_prefix(&account_id)?;
|
||||
|
||||
let account_id = account_id.parse()?;
|
||||
@ -215,9 +231,43 @@ impl WalletSubcommand for AccountSubcommand {
|
||||
.ok_or(anyhow::anyhow!("Private account not found in storage"))?,
|
||||
};
|
||||
|
||||
// Helper closure to display keys for the account
|
||||
let display_keys = |wallet_core: &WalletCore| -> Result<()> {
|
||||
match addr_kind {
|
||||
AccountPrivacyKind::Public => {
|
||||
let private_key = wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.get_pub_account_signing_key(&account_id)
|
||||
.ok_or(anyhow::anyhow!("Public account not found in storage"))?;
|
||||
|
||||
let public_key = PublicKey::new_from_private_key(private_key);
|
||||
println!("pk {}", hex::encode(public_key.value()));
|
||||
}
|
||||
AccountPrivacyKind::Private => {
|
||||
let (key, _) = wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.get_private_account(&account_id)
|
||||
.ok_or(anyhow::anyhow!("Private account not found in storage"))?;
|
||||
|
||||
println!("npk {}", hex::encode(key.nullifer_public_key.0));
|
||||
println!(
|
||||
"ipk {}",
|
||||
hex::encode(key.incoming_viewing_public_key.to_bytes())
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
|
||||
if account == Account::default() {
|
||||
println!("Account is Uninitialized");
|
||||
|
||||
if keys {
|
||||
display_keys(wallet_core)?;
|
||||
}
|
||||
|
||||
return Ok(SubcommandReturnValue::Empty);
|
||||
}
|
||||
|
||||
@ -232,6 +282,10 @@ impl WalletSubcommand for AccountSubcommand {
|
||||
println!("{description}");
|
||||
println!("{json_view}");
|
||||
|
||||
if keys {
|
||||
display_keys(wallet_core)?;
|
||||
}
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
AccountSubcommand::New(new_subcommand) => {
|
||||
@ -288,7 +342,7 @@ impl WalletSubcommand for AccountSubcommand {
|
||||
.iter()
|
||||
.map(|(id, chain_index)| format!("{chain_index} Private/{id}")),
|
||||
)
|
||||
.format(",\n");
|
||||
.format("\n");
|
||||
|
||||
println!("{accounts}");
|
||||
return Ok(SubcommandReturnValue::Empty);
|
||||
|
||||
@ -375,7 +375,7 @@ impl WalletCore {
|
||||
pub async fn send_privacy_preserving_tx(
|
||||
&self,
|
||||
accounts: Vec<PrivacyPreservingAccount>,
|
||||
instruction_data: &InstructionData,
|
||||
instruction_data: InstructionData,
|
||||
program: &ProgramWithDependencies,
|
||||
) -> Result<(SendTxResponse, Vec<SharedSecretKey>), ExecutionFailureKind> {
|
||||
self.send_privacy_preserving_tx_with_pre_check(accounts, instruction_data, program, |_| {
|
||||
@ -387,7 +387,7 @@ impl WalletCore {
|
||||
pub async fn send_privacy_preserving_tx_with_pre_check(
|
||||
&self,
|
||||
accounts: Vec<PrivacyPreservingAccount>,
|
||||
instruction_data: &InstructionData,
|
||||
instruction_data: InstructionData,
|
||||
program: &ProgramWithDependencies,
|
||||
tx_pre_check: impl FnOnce(&[&Account]) -> Result<(), ExecutionFailureKind>,
|
||||
) -> Result<(SendTxResponse, Vec<SharedSecretKey>), ExecutionFailureKind> {
|
||||
@ -403,16 +403,16 @@ impl WalletCore {
|
||||
|
||||
let private_account_keys = acc_manager.private_account_keys();
|
||||
let (output, proof) = nssa::privacy_preserving_transaction::circuit::execute_and_prove(
|
||||
&pre_states,
|
||||
pre_states,
|
||||
instruction_data,
|
||||
acc_manager.visibility_mask(),
|
||||
&produce_random_nonces(private_account_keys.len()),
|
||||
&private_account_keys
|
||||
acc_manager.visibility_mask().to_vec(),
|
||||
produce_random_nonces(private_account_keys.len()),
|
||||
private_account_keys
|
||||
.iter()
|
||||
.map(|keys| (keys.npk.clone(), keys.ssk))
|
||||
.collect::<Vec<_>>(),
|
||||
&acc_manager.private_account_auth(),
|
||||
&acc_manager.private_account_membership_proofs(),
|
||||
acc_manager.private_account_auth(),
|
||||
acc_manager.private_account_membership_proofs(),
|
||||
&program.to_owned(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -19,7 +19,7 @@ impl NativeTokenTransfer<'_> {
|
||||
PrivacyPreservingAccount::PrivateOwned(from),
|
||||
PrivacyPreservingAccount::Public(to),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
)
|
||||
|
||||
@ -17,7 +17,7 @@ impl NativeTokenTransfer<'_> {
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![PrivacyPreservingAccount::PrivateOwned(from)],
|
||||
&Program::serialize_instruction(instruction).unwrap(),
|
||||
Program::serialize_instruction(instruction).unwrap(),
|
||||
&Program::authenticated_transfer_program().into(),
|
||||
)
|
||||
.await
|
||||
@ -46,7 +46,7 @@ impl NativeTokenTransfer<'_> {
|
||||
ipk: to_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
)
|
||||
@ -73,7 +73,7 @@ impl NativeTokenTransfer<'_> {
|
||||
PrivacyPreservingAccount::PrivateOwned(from),
|
||||
PrivacyPreservingAccount::PrivateOwned(to),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
)
|
||||
|
||||
@ -20,7 +20,7 @@ impl NativeTokenTransfer<'_> {
|
||||
PrivacyPreservingAccount::Public(from),
|
||||
PrivacyPreservingAccount::PrivateOwned(to),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
)
|
||||
@ -52,7 +52,7 @@ impl NativeTokenTransfer<'_> {
|
||||
ipk: to_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&program.into(),
|
||||
tx_pre_check,
|
||||
)
|
||||
|
||||
@ -37,7 +37,7 @@ impl Pinata<'_> {
|
||||
PrivacyPreservingAccount::Public(pinata_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(winner_account_id),
|
||||
],
|
||||
&nssa::program::Program::serialize_instruction(solution).unwrap(),
|
||||
nssa::program::Program::serialize_instruction(solution).unwrap(),
|
||||
&nssa::program::Program::pinata().into(),
|
||||
)
|
||||
.await
|
||||
|
||||
@ -52,7 +52,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(supply_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -82,7 +82,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::Public(supply_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -112,7 +112,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(supply_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -180,7 +180,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::PrivateOwned(sender_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(recipient_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -212,7 +212,7 @@ impl Token<'_> {
|
||||
ipk: recipient_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -240,7 +240,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::PrivateOwned(sender_account_id),
|
||||
PrivacyPreservingAccount::Public(recipient_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -269,7 +269,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::Public(sender_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(recipient_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -302,7 +302,7 @@ impl Token<'_> {
|
||||
ipk: recipient_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -365,7 +365,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -393,7 +393,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::Public(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -422,7 +422,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -491,7 +491,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -523,7 +523,7 @@ impl Token<'_> {
|
||||
ipk: holder_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -551,7 +551,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::PrivateOwned(definition_account_id),
|
||||
PrivacyPreservingAccount::Public(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -580,7 +580,7 @@ impl Token<'_> {
|
||||
PrivacyPreservingAccount::Public(definition_account_id),
|
||||
PrivacyPreservingAccount::PrivateOwned(holder_account_id),
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
@ -613,7 +613,7 @@ impl Token<'_> {
|
||||
ipk: holder_ipk,
|
||||
},
|
||||
],
|
||||
&instruction_data,
|
||||
instruction_data,
|
||||
&Program::token().into(),
|
||||
)
|
||||
.await
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user