Compare commits

...

1286 Commits

Author SHA1 Message Date
Daniil Polyakov
1d09afd9e0
Merge pull request #245 from logos-blockchain/Pravdyvy/amm-wallet-integration
AMM-wallet integration (Public part)
2025-12-26 23:52:10 +03:00
Daniil Polyakov
2d1ee4b279 Merge branch 'main' into Pravdyvy/amm-wallet-integration 2025-12-26 23:07:48 +03:00
Daniil Polyakov
f2235548da
Merge pull request #237 from logos-blockchain/Pravdyvy/token-burn-mint-wallet-update
Token burn mint wallet update
2025-12-26 22:48:27 +03:00
Daniil Polyakov
48d1d0e858 fix: adjust to a new token vec instruction 2025-12-26 20:56:34 +03:00
Daniil Polyakov
bece9a9108 Merge branch 'main' into Pravdyvy/token-burn-mint-wallet-update 2025-12-26 13:38:34 +03:00
Daniil Polyakov
f4a8429461
Merge pull request #232 from logos-blockchain/marvin/nfts
initialize nft branch
2025-12-26 01:00:50 +03:00
Daniil Polyakov
9d37a88069 fix: proper type for token program instruction 2025-12-26 00:24:55 +03:00
Daniil Polyakov
de751952af fix: fmt and lints 2025-12-25 17:05:06 +03:00
Daniil Polyakov
e81d7f099d Merge branch 'main' into marvin/nfts 2025-12-25 17:01:46 +03:00
Daniil Polyakov
5d30de695f fix: use u128::MAX instead of overflowing 2.pow(128) 2025-12-25 16:59:49 +03:00
Daniil Polyakov
cecf39cecd
Merge pull request #254 from logos-blockchain/schouhy/amm-wallet-integration-readme
Add amm section to the readme
2025-12-24 23:20:35 +03:00
Daniil Polyakov
28b64e87f5
Merge pull request #152 from logos-blockchain/simple_amm
initialize amm program PR
2025-12-24 23:03:14 +03:00
Daniil Polyakov
2e82d2ddb8 chore: fix lints, fmt and artifacts 2025-12-24 03:39:39 +03:00
jonesmarvin8
e6a73a02b5 artifacts commitment 2025-12-23 18:03:00 -05:00
jonesmarvin8
c6531aaab4 accountid removed conflict 2025-12-23 17:36:58 -05:00
jonesmarvin8
c25e93edd5 cargo fmt and clippy 2025-12-23 17:31:03 -05:00
jonesmarvin8
fcdd6e96a5 clippy and fmt 2025-12-23 17:26:38 -05:00
jonesmarvin8
c5e640d56c Merge branch 'main' into marvin/nfts 2025-12-23 14:01:28 -05:00
jonesmarvin8
56151e9d3d remove unused file from merge
Accidental inclusion
2025-12-23 11:06:18 -05:00
jonesmarvin8
8289c07b28 Merge branch 'main' into simple_amm 2025-12-23 11:03:11 -05:00
jonesmarvin8
a84057561e various fixes from comments 2025-12-22 19:52:39 -05:00
jonesmarvin8
072cf5cd0f various fixes from comments 2025-12-22 19:51:41 -05:00
jonesmarvin8
5baa759283
Update nssa/program_methods/guest/src/bin/token.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-22 18:26:33 -05:00
jonesmarvin8
ca7cc10f7c
Update nssa/program_methods/guest/src/bin/token.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-22 18:26:19 -05:00
jonesmarvin8
c49a3afec7
Update nssa/program_methods/guest/src/bin/token.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-22 18:25:21 -05:00
jonesmarvin8
fe3c11fd3e
Update nssa/program_methods/guest/src/bin/token.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-22 18:24:59 -05:00
Pravdyvy
639c282c61 fix: suggestions fix 2 2025-12-22 19:34:47 +02:00
jonesmarvin8
05d34bf9ec
Update nssa/program_methods/guest/src/bin/amm.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-22 11:41:44 -05:00
jonesmarvin8
32de4e2990
Update nssa/program_methods/guest/src/bin/amm.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-22 11:41:19 -05:00
Pravdyvy
0a1bbb9d21 fix: merge fix 2025-12-22 05:12:48 +02:00
Pravdyvy
22c60cb97f fix: lock update 2025-12-22 05:01:04 +02:00
Pravdyvy
22f6d92ca6 Merge branch 'main' into Pravdyvy/amm-wallet-integration 2025-12-22 05:00:50 +02:00
Pravdyvy
c1a999c02e fix: new artifacts 2025-12-22 04:55:15 +02:00
Pravdyvy
4f15237446 fix: suggestions fix 2025-12-22 04:42:32 +02:00
Pravdyvy
e351279278 fix: merge ci fix 2025-12-22 04:14:54 +02:00
Pravdyvy
c95c4b2f16 Merge branch 'main' into Pravdyvy/token-burn-mint-wallet-update 2025-12-22 04:04:09 +02:00
Pravdyvy
f6c787e15f fix: suggestions fix 2025-12-22 04:02:12 +02:00
jonesmarvin8
c30ba4be1a various fixes 2025-12-19 20:08:05 -05:00
jonesmarvin8
9601e0053e removed enums 2025-12-19 20:05:42 -05:00
Sergio Chouhy
9adc88f8c8 add lp fees note 2025-12-19 17:32:38 -03:00
Sergio Chouhy
5a03ad431d nit 2025-12-19 17:21:26 -03:00
Sergio Chouhy
3581c97424 add amm section to the readme 2025-12-19 17:10:33 -03:00
Daniil Polyakov
9b37a2a8b7
Merge pull request #248 from logos-blockchain/arjentix/build-docker-image
Publish sequencer_runner Docker image with CI
2025-12-19 21:05:28 +03:00
Pravdyvy
d427d49c65 fix: suggestions added 2025-12-19 19:12:58 +02:00
Pravdyvy
1b0dea11f6
Update wallet/src/cli/programs/amm.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-12-19 19:02:39 +02:00
Sergio Chouhy
a280551ee3
Merge pull request #241 from logos-blockchain/schouhy/add-program-deployment-example-pda
Add example and instructions for pda and privacy tail calls
2025-12-19 13:41:26 -03:00
Daniil Polyakov
10b6cfcf93 fixup! fix: commit Cargo lock 2025-12-19 18:48:19 +03:00
Daniil Polyakov
6997a8da54 fix: give permissions to non-root docker user 2025-12-19 18:48:19 +03:00
Daniil Polyakov
621b7c0bfa fix: commit Cargo lock 2025-12-19 18:48:19 +03:00
Daniil Polyakov
45670902d1 fix: build risc0 bins to different target directories 2025-12-19 18:48:19 +03:00
Daniil Polyakov
56f8df1d2b fix: add ref to CI checkout action 2025-12-19 18:48:19 +03:00
Daniil Polyakov
6075e03d06 feat: more granular tests in CI 2025-12-19 18:48:19 +03:00
Daniil Polyakov
172b13d03a feat: add logs for program pre_states and output 2025-12-19 18:48:19 +03:00
Daniil Polyakov
9b729d6c3e feat: use nextest in CI 2025-12-19 18:48:19 +03:00
Daniil Polyakov
d6d722c016 fix: fix token program unit test in debug mode 2025-12-19 18:48:19 +03:00
Daniil Polyakov
0ac7b5c702 feat: publish sequencer_runner docker image with CI 2025-12-19 18:48:13 +03:00
Daniil Polyakov
dc38b8ea2d feat: add artifacts of program_methods and remove no_docker feature 2025-12-19 18:30:40 +03:00
Daniil Polyakov
d425d70d4c feat: use actions/checkout@v5 2025-12-19 18:30:40 +03:00
Daniil Polyakov
ddf6e707ec feat: add cargo machete check to CI 2025-12-19 18:30:40 +03:00
Daniil Polyakov
d126dac303 feat: make CI more granular 2025-12-19 18:30:40 +03:00
Daniil Polyakov
081a366c16 feat: add programs check in ci 2025-12-19 18:30:40 +03:00
Daniil Polyakov
87f45b8215 feat: move all crates into workspace 2025-12-19 18:30:40 +03:00
Daniil Polyakov
90a1ee994f refactor: move program_methods to the root of repo 2025-12-19 18:30:40 +03:00
Sergio Chouhy
44f6f44fa2 Merge branch 'main' into schouhy/add-program-deployment-example-pda 2025-12-19 10:45:48 -03:00
jonesmarvin8
e73e4b0558
Merge pull request #250 from logos-blockchain/main
merge main into simple amm
2025-12-19 08:36:08 -05:00
Pravdyvy
144c037114 Merge branch 'main' into Pravdyvy/token-burn-mint-wallet-update 2025-12-19 12:13:43 +02:00
Pravdyvy
7d12502542
Merge pull request #239 from logos-blockchain/Pravdyvy/merge-template-update
fix: template update
2025-12-19 11:32:50 +02:00
jonesmarvin8
a5496eb5d5 various comments addressed 2025-12-18 18:45:57 -05:00
Daniil Polyakov
2b15bed3fa
Merge pull request #240 from logos-blockchain/arjentix/private-acc-init-with-is-authorized
Allow private authorized uninitialized accounts
2025-12-19 01:39:15 +03:00
Daniil Polyakov
f729072fae feat: allow private authorized uninitialized accounts 2025-12-18 21:48:37 +03:00
Sergio Chouhy
ef97fade99 feat: unzip init proofs from nsk 2025-12-18 17:57:13 +03:00
Daniil Polyakov
2975d9d878 chore: make more clear error messages in authenticated_transfer 2025-12-18 17:57:13 +03:00
Pravdyvy
c1283d4a0c fix: public execution finalized 2025-12-18 11:44:38 +02:00
Pravdyvy
cde11e75d6 fix: state test update 2025-12-17 15:58:25 +02:00
Daniil Polyakov
8dc709a6e0
Merge pull request #247 from logos-blockchain/arjentix/fix-macos-rocksdb
fix: add `bindgen-runtime` feature of rocksdb
2025-12-17 16:34:29 +03:00
Pravdyvy
92b5dffec2 fix: public swaps 2025-12-17 14:21:36 +02:00
Pravdyvy
b3dca76b67 fix: intercommit 2025-12-17 11:44:52 +02:00
Daniil Polyakov
cd99318bf0
Merge pull request #231 from logos-blockchain/arjentix/ci-deploy
feat: deploy with ci
2025-12-17 01:28:49 +03:00
Daniil Polyakov
bbc02f0cf3 fix: add bindgen-runtime feature of rocksdb 2025-12-17 01:10:25 +03:00
Pravdyvy
d4a471e948 feat: swaps, add/rem liq 2025-12-16 14:05:34 +02:00
Moudy
e52e7d9ee9
Merge pull request #227 from fryorcraken/chore/rocksdb
Upgrade rocksdb
2025-12-16 11:53:16 +01:00
Pravdyvy
c5cca4376e Merge branch 'simple_amm' into Pravdyvy/amm-wallet-integration 2025-12-16 09:27:34 +02:00
jonesmarvin8
c3cd110688 data field fixes 2025-12-15 18:55:38 -05:00
jonesmarvin8
d78d97c815 Reapply "Merge branch 'main' into simple_amm"
This reverts commit 2419d4a1126afa9882b3fefbe518582ae130a817.
2025-12-15 18:13:31 -05:00
jonesmarvin8
2419d4a112 Revert "Merge branch 'main' into simple_amm"
This reverts commit 8dd1c2d84677aa5efe00ca820ec634a19b73de07, reversing
changes made to 2e37e20014fc8ddaa4559cbdf2c13ec8eb356f24.
2025-12-15 17:53:20 -05:00
jonesmarvin8
8dd1c2d846 Merge branch 'main' into simple_amm 2025-12-15 17:41:45 -05:00
Pravdyvy
4389364b55 fix: last md update 2025-12-15 15:39:26 +02:00
Pravdyvy
bb6cf322a0 Merge branch 'main' into Pravdyvy/amm-wallet-integration 2025-12-15 10:40:46 +02:00
Pravdyvy
93b616a434 fix: lock updates 2025-12-15 10:00:19 +02:00
Pravdyvy
1599bd41ce Merge branch 'main' into Pravdyvy/token-burn-mint-wallet-update 2025-12-15 09:52:10 +02:00
jonesmarvin8
de1bf770f0 update comments 2025-12-12 19:09:59 -05:00
Sergio Chouhy
165e331aea clippy 2025-12-12 20:10:10 -03:00
Sergio Chouhy
5fe29016b7
Merge pull request #233 from logos-blockchain/schouhy/add-program-deployment-example
Program deployment tutorial and examples
2025-12-12 20:07:46 -03:00
jonesmarvin8
3acc51ac87 rebased with main token program 2025-12-12 16:50:13 -05:00
jonesmarvin8
e76800e283 Merge branch 'main' into marvin/nfts 2025-12-12 16:35:23 -05:00
jonesmarvin8
aa81a311ac Update token.rs 2025-12-12 16:30:54 -05:00
jonesmarvin8
213e8dfb82
Merge pull request #224 from logos-blockchain/marvin/token_burn_mint
add burn and mint to Token Program
2025-12-12 16:29:07 -05:00
jonesmarvin8
ae50ff65fa fixed conflicts with token rs from main 2025-12-12 16:27:27 -05:00
jonesmarvin8
fac1dc19e2 merge main minus token rs 2025-12-12 16:13:13 -05:00
jonesmarvin8
30b4c8036e
Merge pull request #238 from logos-blockchain/marvin/privacy_nonce_rearrangement
Rearrange nonce increment for privacy transactions
2025-12-12 15:53:58 -05:00
Sergio Chouhy
a360df29bf Merge branch 'schouhy/add-program-deployment-example' into schouhy/add-program-deployment-example-pda 2025-12-12 17:35:01 -03:00
Sergio Chouhy
40bb718527 fmt 2025-12-12 17:04:51 -03:00
Sergio Chouhy
63f102643b add instructions to get the hello world program id in hex 2025-12-12 14:30:36 -03:00
Sergio Chouhy
77fd189010 refactor to use privacy tail calls from send_privacy_preserving_tx and add the example runner 2025-12-12 14:21:07 -03:00
Sergio Chouhy
89c1a97798 add example and instructions for pda 2025-12-12 13:00:16 -03:00
Sergio Chouhy
7453734dbe add important note 2025-12-12 10:55:03 -03:00
Sergio Chouhy
3e3ee9ba36 taplo fmt 2025-12-12 10:30:57 -03:00
Pravdyvy
31405af143 fix: template update 2025-12-12 14:49:24 +02:00
Pravdyvy
5212d456ab fix: integration tests 2025-12-12 13:40:56 +02:00
jonesmarvin8
9f443b92a8 modifications 2025-12-11 19:19:22 -05:00
Sergio Chouhy
bb58f7dd0a revert changes 2025-12-11 21:15:57 -03:00
Sergio Chouhy
8c92a58bbc add program deployment examples 2025-12-11 20:59:37 -03:00
Daniil Polyakov
d019c26578 feat: deploy with ci 2025-12-11 17:28:26 +03:00
jonesmarvin8
2d8722b7d0 nonce code shifting 2025-12-11 08:59:28 -05:00
Pravdyvy
0be88d4343 fix: fmt 2025-12-11 14:47:11 +02:00
Pravdyvy
f77481f3b5 feat: mint and burn 2025-12-11 14:46:16 +02:00
Sergio Chouhy
abb1fc5e45
Merge pull request #151 from logos-blockchain/schouhy/implement-privacy-preserving-tail-calls
Implement privacy preserving tail calls
2025-12-11 08:08:23 -03:00
Pravdyvy
7e8b8c7624 Merge branch 'main' into Pravdyvy/token-burn-mint-wallet-update 2025-12-11 12:06:47 +02:00
Sergio Chouhy
1b2962fa03 add missing check on pre_states for privacy tail calls 2025-12-10 23:10:25 -03:00
jonesmarvin8
1b7afbecdc updates 2025-12-10 20:21:11 -05:00
Sergio Chouhy
33ee1fc72e
Merge pull request #236 from logos-blockchain/schouhy/move-modified-transfer-to-test-methods
Move modified transfer program to test programs
2025-12-10 18:13:47 -03:00
Sergio Chouhy
d7f0346671 fix test 2025-12-10 15:57:43 -03:00
Sergio Chouhy
5276cc8f07 Merge branch 'schouhy/move-modified-transfer-to-test-methods' into schouhy/implement-privacy-preserving-tail-calls 2025-12-10 14:51:46 -03:00
Sergio Chouhy
e9c9058827 move modified transfer program to test programs 2025-12-10 14:07:06 -03:00
Sergio Chouhy
c6f0782d26
Merge pull request #221 from logos-blockchain/schouhy/add-wallet-deploy-command
Add deploy program command to wallet
2025-12-10 13:57:12 -03:00
jonesmarvin8
340c9c4ce6 redundant underflow check added 2025-12-10 08:12:17 -05:00
Sergio Chouhy
9637b8b666 Merge branch 'main' into schouhy/add-wallet-deploy-command 2025-12-10 09:58:45 -03:00
Daniil Polyakov
cd2430c2ee
Merge pull request #229 from logos-blockchain/arjentix/iss-186-fix-wallet-sync-print-spam
Remove print spam when running wallet account sync-private
2025-12-10 14:24:26 +03:00
Pravdyvy
0ac5cbb35d
Merge pull request #215 from logos-blockchain/Pravdyvy/tree-ux-updates
KeyTree UX updates
2025-12-10 11:33:06 +02:00
Pravdyvy
45e3223d51 fix: merge fix 2025-12-10 10:25:33 +02:00
Pravdyvy
81316f6766 Merge branch 'main' into Pravdyvy/tree-ux-updates 2025-12-10 10:18:07 +02:00
Pravdyvy
81393925d0
Merge pull request #211 from logos-blockchain/Pravdyvy/private-definition-token
Private TokenDefinition support
2025-12-10 10:03:42 +02:00
Pravdyvy
dc277b7e71
Merge pull request #153 from logos-blockchain/Pravdyvy/keys-restoration-from-mnemonic
Keys restoration from mnemonic
2025-12-10 10:02:47 +02:00
Pravdyvy
8e2b1c5993 Merge branch 'Pravdyvy/keys-restoration-from-mnemonic' into Pravdyvy/tree-ux-updates 2025-12-10 08:46:39 +02:00
Pravdyvy
1309185ecc Merge branch 'main' into Pravdyvy/keys-restoration-from-mnemonic 2025-12-10 08:34:01 +02:00
Sergio Chouhy
f54cdf4a4c Merge branch 'main' into schouhy/implement-privacy-preserving-tail-calls 2025-12-09 23:53:27 -03:00
jonesmarvin8
22440cf95d initialize nft branch 2025-12-09 17:38:02 -05:00
jonesmarvin8
2e37e20014 format 2025-12-09 15:36:46 -05:00
jonesmarvin8
70c228dbec fixed formatting and added overflow/underflow 2025-12-09 15:28:32 -05:00
jonesmarvin8
471611f848 fixed new definition 2025-12-09 14:42:58 -05:00
jonesmarvin8
8c493a0155
Update nssa/program_methods/guest/src/bin/token.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-09 13:31:44 -05:00
jonesmarvin8
cf4d7ba80b
Update nssa/program_methods/guest/src/bin/token.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-09 13:31:13 -05:00
jonesmarvin8
17f77f9ae7
Update nssa/program_methods/guest/src/bin/token.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-09 13:31:02 -05:00
Daniil Polyakov
1ff5de1443
Merge pull request #220 from logos-blockchain/arjentix/iss-190-tx-size-limit
Account data size limit
2025-12-09 21:27:45 +03:00
Sergio Chouhy
79b4dc0333 Merge branch 'schouhy/add-wallet-deploy-command' of github.com:logos-blockchain/lssa into schouhy/add-wallet-deploy-command 2025-12-09 15:22:30 -03:00
Sergio Chouhy
ab6ea1f4c0 use pathbuf and context 2025-12-09 15:18:48 -03:00
Sergio Chouhy
8cfb586bee
Update wallet/src/cli/mod.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-09 14:55:12 -03:00
Daniil Polyakov
31e7016948 feat: introduce parameter to data_changer and add test for account data 2025-12-09 20:26:02 +03:00
Daniil Polyakov
4574acfc49 feat: introduce account data size limit 2025-12-09 20:26:02 +03:00
Daniil Polyakov
f6e2bcaad7
Merge pull request #228 from logos-blockchain/arjentix/wallet-basic-auth
Add basic auth to wallet
2025-12-09 20:25:35 +03:00
Daniil Polyakov
2518199be2
Merge pull request #223 from logos-blockchain/arjentix/fix-token-native-minting-bug
Fix token native minting bug
2025-12-09 20:23:44 +03:00
Daniil Polyakov
e5cbd82343 fix: add overflow check for balance sum validation 2025-12-09 18:28:58 +03:00
Daniil Polyakov
46ac451284 feat: add basic auth to wallet 2025-12-09 18:20:50 +03:00
jonesmarvin8
e0c6baf1ff added mint overflow protection 2025-12-09 08:11:15 -05:00
Pravdyvy
e1eff07478 fix: layered autobalancing 2025-12-09 11:51:44 +02:00
Pravdyvy
eed485bd2c fix: tomil fix 2025-12-09 11:10:40 +02:00
Pravdyvy
47ff7f0b64 fix: layered automatization 2025-12-09 11:09:15 +02:00
Pravdyvy
26fb822da1 Merge branch 'Pravdyvy/keys-restoration-from-mnemonic' into Pravdyvy/tree-ux-updates 2025-12-09 10:46:28 +02:00
Pravdyvy
d0064a4b0b Merge branch 'main' into Pravdyvy/tree-ux-updates 2025-12-09 10:40:35 +02:00
jonesmarvin8
5169e8fda4 cargo fix 2025-12-08 22:12:02 -05:00
jonesmarvin8
6bc983d50b added pda support 2025-12-08 22:05:51 -05:00
Daniil Polyakov
80a188e6a3 feat: remove print spam when running wallet account sync-private 2025-12-09 00:07:10 +03:00
jonesmarvin8
65681a5b74 minor fixes (does not run/test) 2025-12-08 13:19:30 -05:00
Pravdyvy
ea19ad0c1f fix: comments fix 2025-12-08 13:00:03 +02:00
Pravdyvy
ddeeab7d80
Apply suggestions from code review
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-12-08 12:50:41 +02:00
Pravdyvy
f1760b67ee fix: revert difficulty 2025-12-08 12:46:43 +02:00
Pravdyvy
01f7acb4d6 fix: remove unused enum 2025-12-08 12:13:03 +02:00
Pravdyvy
40991cf6d1 fix: layered cleanup 2025-12-08 12:11:11 +02:00
fryorcraken
beab5f9e96
fix ci for rocksdb 2025-12-08 18:09:10 +11:00
fryorcraken
ad7f773632
chore: upgrade rocksdb
To avoid issues with gcc 14+
2025-12-08 18:09:01 +11:00
jonesmarvin8
d77185ded4 uses burn/mint/AccountPostState 2025-12-07 20:34:26 -05:00
jonesmarvin8
4bcfbb9bee Merge branch 'marvin/token_burn_mint' into simple_amm 2025-12-07 20:31:16 -05:00
jonesmarvin8
5a1d37d607 update burn/mint to use AccountPostState 2025-12-07 20:29:25 -05:00
jonesmarvin8
c6e68ff9b1
Merge pull request #226 from logos-blockchain/main
main into burn
2025-12-07 20:27:27 -05:00
jonesmarvin8
8506f5948f Merge branch 'main' into simple_amm 2025-12-06 20:07:12 -05:00
jonesmarvin8
a11155e441 Merge branch 'simple_amm' of https://github.com/logos-blockchain/lssa into simple_amm 2025-12-06 20:03:14 -05:00
jonesmarvin8
3a3c6f5507 state tests fixed and clean up 2025-12-06 20:03:05 -05:00
jonesmarvin8
106b33a57f
Merge pull request #225 from logos-blockchain/marvin/token_burn_mint
Marvin/token burn mint
2025-12-06 16:45:11 -05:00
jonesmarvin8
ea27eeb929 fixed add and remove logic, and tests 2025-12-06 14:52:18 -05:00
jonesmarvin8
1ae10f553b test: add test for malicious program performing balance overflow attack 2025-12-06 21:28:45 +03:00
jonesmarvin8
c6cde35203 added burn/mint and tests 2025-12-05 21:01:36 -05:00
Sergio Chouhy
7825f69e06 remove unused import 2025-12-05 17:57:48 -03:00
Sergio Chouhy
cc08e0a614 add deploy program command 2025-12-05 17:54:51 -03:00
Sergio Chouhy
3e303f2c95
Merge pull request #202 from logos-blockchain/schouhy/implement-pda-for-public-accounts
Implement PDA for public executions
2025-12-05 15:15:37 -03:00
Sergio Chouhy
7e971a6c4d Merge branch 'main' into schouhy/implement-pda-for-public-accounts 2025-12-05 10:00:23 -03:00
Sergio Chouhy
09116830c9
Merge pull request #214 from vacp2p/schouhy/fix-claiming-mechanism-on-chained-calls
Fix claiming mechanism on chained calls
2025-12-05 09:37:37 -03:00
Pravdyvy
80d9ce8553
Merge pull request #216 from vacp2p/Pravdyvy/correct-token-names-print
Correct tokens names
2025-12-05 14:20:44 +02:00
Pravdyvy
d2dc255bc5 fix: merge fix 2025-12-05 09:36:53 +02:00
Pravdyvy
f0066bc2aa Merge branch 'main' into Pravdyvy/keys-restoration-from-mnemonic 2025-12-05 09:32:54 +02:00
Pravdyvy
29c3737704 fix: lint fix comments addressed 2025-12-05 07:46:59 +02:00
jonesmarvin8
97f2e93f8a initialize branch 2025-12-04 21:55:12 -05:00
jonesmarvin8
b1ad51f5b9 logic fixes and streamlining examples
fixed remove_liquidity logic and added enum/constructors for examples
2025-12-04 21:53:58 -05:00
Sergio Chouhy
7236a7074c
Merge pull request #204 from vacp2p/schouhy/add-readme-explainers
Add readme explainers
2025-12-04 21:39:46 -03:00
Sergio Chouhy
925ae8d0c1 fmt 2025-12-04 21:34:47 -03:00
Sergio Chouhy
a84b18f22c remove unnecessary type annotation 2025-12-04 16:46:43 -03:00
Sergio Chouhy
b5589d53bb use filter 2025-12-04 16:29:00 -03:00
Sergio Chouhy
cf9c567e29 remove pub attribute 2025-12-04 16:26:40 -03:00
Daniil Polyakov
f1aed0b632
Merge pull request #217 from vacp2p/arjentix/iss-188-fix-wallet-long-sync 2025-12-04 22:13:14 +03:00
Sergio Chouhy
35bf943244 Merge branch 'main' into schouhy/implement-pda-for-public-accounts 2025-12-04 16:03:23 -03:00
Pravdyvy
926a292c9c fix: constraint added 2025-12-04 16:49:10 +02:00
Sergio Chouhy
068bfa0ec5 add docstrings. Remove unused method 2025-12-04 10:10:01 -03:00
Sergio Chouhy
686eb787c9 fix test names 2025-12-04 10:02:29 -03:00
fryorcraken
95ddea9fb0
Merge pull request #218 from vacp2p/fix/fedora
Add instructions for Fedora
2025-12-04 23:43:22 +11:00
Pravdyvy
fe83a20c4d fix: suggestion 1 2025-12-04 14:34:11 +02:00
Pravdyvy
2453ae095f fix: cleanup fixing 2025-12-04 14:31:52 +02:00
Daniil Polyakov
1412ad4da4 refactor: remove redundant request and response types 2025-12-04 14:55:58 +03:00
Daniil Polyakov
03e911ecd5 feat: apply base64 encoding for large binary data transfer 2025-12-04 14:55:58 +03:00
Daniil Polyakov
6b26811229 feat: implement multiple blocks polling 2025-12-04 14:55:45 +03:00
fryorcraken
4ed86ce182
Add instructions for Fedora 2025-12-04 21:00:29 +11:00
Sergio Chouhy
3393c55768 fix program deployment integration test 2025-12-03 19:59:58 -03:00
Sergio Chouhy
ed949c07b1 nit 2025-12-03 17:38:45 -03:00
Sergio Chouhy
44b4c53d04 add test that initialized accounts cannot be claimed 2025-12-03 17:36:53 -03:00
Sergio Chouhy
91fe8ced6e add test 2025-12-03 17:07:31 -03:00
Sergio Chouhy
8a269858c5 improve struct interface 2025-12-03 16:54:57 -03:00
Sergio Chouhy
d677db7f4e add account post state struct with claiming request field 2025-12-03 15:17:33 -03:00
Daniil Polyakov
91c898f19c refactor: split block polling 2025-12-03 18:30:22 +03:00
Pravdyvy
282b932a8e fix: correct feature 2025-12-03 14:30:23 +02:00
Pravdyvy
78ce57e19b fix: correct tokens names 2025-12-03 13:50:10 +02:00
Pravdyvy
b81aafbc23 feat: UX improvements 2025-12-03 13:10:07 +02:00
Pravdyvy
33264ba59a Merge branch 'main' into Pravdyvy/keys-restoration-from-mnemonic 2025-12-03 07:13:35 +02:00
Pravdyvy
5affa4f9fd fix: suggestions fix 2025-12-03 07:05:23 +02:00
jonesmarvin8
90d6580377 simplified swap logic
removed branching logic from swap logic, and adjusted tests accordingly.
2025-12-02 17:21:49 -05:00
jonesmarvin8
c0c1228e10 fixed accountId 2025-12-02 15:20:16 -05:00
Sergio Chouhy
d16908d463 remove pinata instructions 2025-12-02 16:48:12 -03:00
Sergio Chouhy
c360db9698 Merge branch 'main' into schouhy/add-readme-explainers 2025-12-02 16:40:26 -03:00
Sergio Chouhy
407c3f3c95 improve expect message 2025-12-02 16:27:22 -03:00
jonesmarvin8
3e9f0f9384 fixed omitted vault checks
Previous versions mistakenly used token_definition instead of vault account id to check for vaults.

Functions and corresponding tests fixed.

Minor error in arithmetic in state.rs for remove_liquidity fixed.
2025-12-02 13:40:54 -05:00
jonesmarvin8
863ed888ad minor fix to remove_liquidity
Fixed line 2767 to use delta_lp in liquidity_pool_cap
2025-12-02 13:40:54 -05:00
jonesmarvin8
93ee75a339 additional tests
Tests for chain_calls included in amm.rs,
All tests in state.rs
2025-12-02 13:40:53 -05:00
jonesmarvin8
352b97910a state tests written 2025-12-02 13:40:11 -05:00
jonesmarvin8
0a645281c6 token_program non-deterministic issue 2025-12-02 13:40:11 -05:00
jonesmarvin8
9da684b7c6 fixed some deterministic issues 2025-12-02 13:40:11 -05:00
jonesmarvin8
5547f0635c attempted test functions in state.rs
Additional minor clean up in amm.rs
2025-12-02 13:40:10 -05:00
jonesmarvin8
2166bbfe03 test fixes and comments 2025-12-02 13:37:40 -05:00
jonesmarvin8
853d4d6b59 Tests written 2025-12-02 13:36:07 -05:00
jonesmarvin8
a426839b3b Updated based on chain calls fixes 2025-12-02 13:36:07 -05:00
jonesmarvin8
10d42f352b AMM functions written 2025-12-02 13:33:00 -05:00
jonesmarvin8
e8f1bca17e initialize amm program PR 2025-12-02 13:31:38 -05:00
Sergio Chouhy
2d34925725
Merge pull request #163 from vacp2p/schouhhy/expand-readme
Update Readme with documentation
2025-12-02 12:20:58 -03:00
Sergio Chouhy
dcef017f9b nit 2025-12-02 12:12:56 -03:00
Sergio Chouhy
468b39bc32
Merge pull request #203 from vacp2p/schouhy/add-init-function-to-token-program
Add init function to the token program
2025-12-02 12:11:49 -03:00
Sergio Chouhy
ce9cadc46d Merge branch 'schouhy/implement-pda-for-public-accounts' of github.com:vacp2p/nescience-testnet into schouhy/implement-pda-for-public-accounts 2025-12-02 10:50:43 -03:00
Sergio Chouhy
fdc53927ca
Update nssa/src/program.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-12-02 10:50:06 -03:00
Sergio Chouhy
3d529d19fa solve comments 2025-12-02 10:48:21 -03:00
Pravdyvy
2fd4a37ee4 fix: private definition support 2025-12-02 15:27:20 +02:00
Pravdyvy
4fb6ba9530 Merge branch 'main' into Pravdyvy/private-definition-token 2025-12-02 07:53:47 +02:00
Daniil Polyakov
04ab7444a4
Merge pull request #205 from vacp2p/arjentix/iss-200-wallet-compute-pinata-solution
Refactor wallet & compute pinata solution in wallet
2025-12-02 02:42:28 +03:00
Daniil Polyakov
df88d8bad6 feat: compute pinata solution in wallet 2025-12-02 01:21:34 +03:00
Daniil Polyakov
4afbd65e3b feat: add transaction output after pinata call 2025-12-01 17:08:07 +03:00
Daniil Polyakov
0c44785a07 refactor: small adjustments to privacy preserving tx sending 2025-12-01 17:08:07 +03:00
Daniil Polyakov
55fc4e9777 refactor: implement program interactions as facades 2025-12-01 17:08:07 +03:00
Daniil Polyakov
df64f8864f refactor: implement universal interface for privacy-preserving transactions 2025-12-01 17:08:07 +03:00
Daniil Polyakov
aee6f45a8b refactor: move some stuff to a more suitable place 2025-12-01 17:08:07 +03:00
Sergio Chouhy
500e0862f3 s/address/account_id/ 2025-12-01 10:48:43 -03:00
Sergio Chouhy
ed38be57bb add explainers 2025-12-01 10:42:59 -03:00
Sergio Chouhy
c937cb591e wip 2025-12-01 10:25:23 -03:00
Pravdyvy
b1b7bc4463 fix: fmt 2025-12-01 14:19:25 +02:00
Pravdyvy
38acb89b93 Merge branch 'main' into Pravdyvy/private-definition-token 2025-12-01 14:19:01 +02:00
Pravdyvy
28c20f4d21 Merge branch 'main' into Pravdyvy/keys-restoration-from-mnemonic 2025-12-01 14:02:02 +02:00
Pravdyvy
fa73a0a704
Merge pull request #149 from vacp2p/Pravdyvy/deterministic-key-derivation
Deterministic key derivation
2025-12-01 13:59:55 +02:00
Pravdyvy
0f617a8601 Merge branch 'Pravdyvy/deterministic-key-derivation' into Pravdyvy/keys-restoration-from-mnemonic 2025-12-01 12:01:45 +02:00
Daniil Polyakov
5801073f84 feat: compute pinata solution in wallet 2025-11-30 03:56:24 +03:00
Daniil Polyakov
2cf60fff10 feat: add transaction output after pinata call 2025-11-30 03:56:12 +03:00
Daniil Polyakov
a8abec196b refactor: small adjustments to privacy preserving tx sending 2025-11-30 03:55:27 +03:00
Daniil Polyakov
777486ce2c refactor: implement program interactions as facades 2025-11-30 03:16:54 +03:00
Daniil Polyakov
41a833c258 refactor: implement universal interface for privacy-preserving transactions 2025-11-30 03:16:54 +03:00
Daniil Polyakov
c94d353b54 refactor: move some stuff to a more suitable place 2025-11-30 03:16:54 +03:00
Sergio Chouhy
7ab44507f5 test 2025-11-29 00:06:06 -03:00
Sergio Chouhy
640ed18f90 Merge branch 'main' into schouhy/add-readme-explainers 2025-11-28 23:38:43 -03:00
Sergio Chouhy
bfbd50e8cb add docs 2025-11-28 17:09:38 -03:00
Sergio Chouhy
c7bcd20a38 add init function to the token program 2025-11-28 14:16:54 -03:00
Sergio Chouhy
ed00876800 Merge branch 'schouhy/add-init-function-to-token-program' into schouhy/implement-pda-for-public-accounts 2025-11-28 14:16:26 -03:00
Sergio Chouhy
dd5db5b32c add init function to the token program 2025-11-28 11:52:02 -03:00
Sergio Chouhy
1989fd25a1 add pinata token example and test 2025-11-28 11:10:00 -03:00
Pravdyvy
c7ce31d00c fix: fmt 2025-11-28 09:49:05 +02:00
Pravdyvy
46515ce695 Merge branch 'main' into Pravdyvy/deterministic-key-derivation 2025-11-28 09:18:02 +02:00
Pravdyvy
64e2fb73a8 fix: merge update 2025-11-28 08:48:11 +02:00
Sergio Chouhy
e61a971790 add test and refactor chain_caller program 2025-11-27 13:53:25 -03:00
Sergio Chouhy
449ba3e3a9 Merge branch 'main' into schouhy/implement-pda-for-public-accounts 2025-11-27 13:10:57 -03:00
Sergio Chouhy
3fbf1e1fec add pda mechanism 2025-11-27 13:10:38 -03:00
Sergio Chouhy
702882c6ee
Merge pull request #161 from vacp2p/schouhy/add-multi-chain-calls
Add multi chain calls
2025-11-27 12:39:23 -03:00
Sergio Chouhy
d82f06593d add pda_seeds field 2025-11-27 12:08:27 -03:00
Sergio Chouhy
a3e07347a4 Merge branch 'schouhy/add-multi-chain-calls' into schouhy/implement-pda-for-public-accounts 2025-11-27 12:05:09 -03:00
Sergio Chouhy
409ec19959 fix concatenation of call stack 2025-11-27 10:53:25 -03:00
Sergio Chouhy
f46d7ee426 nit 2025-11-27 10:46:35 -03:00
Sergio Chouhy
aba1d844f8 consume call stack from the other end 2025-11-27 10:42:58 -03:00
Sergio Chouhy
103332f6cd nit 2025-11-27 09:56:52 -03:00
Sergio Chouhy
577fad6d5f refactor call stack execution loop 2025-11-27 09:54:14 -03:00
Daniil Polyakov
6a507fdad1
Merge pull request #198 from vacp2p/arjentix/iss-185-wallet-list-all-accounts
feat: add list account subcommand
2025-11-27 15:08:38 +03:00
Pravdyvy
055c5388e0 Merge branch 'main' into Pravdyvy/deterministic-key-derivation 2025-11-27 13:49:00 +02:00
Pravdyvy
6c409b6fb1 Merge branch 'main' into Pravdyvy/deterministic-key-derivation 2025-11-27 13:46:35 +02:00
Pravdyvy
a99aec05eb
Merge pull request #166 from vacp2p/Pravdyvy/iss131-error-handling
Borsh derivation in place of previous manual encodings
2025-11-27 11:45:53 +02:00
Pravdyvy
b26b972d3d
Merge pull request #199 from vacp2p/Pravdyvy/fix-main
Fmt fix
2025-11-27 11:41:23 +02:00
Pravdyvy
00386eba24 fix: fmt 2025-11-27 06:03:43 +02:00
Pravdyvy
bce0ac79cb fix: fmt fix 2025-11-27 05:55:25 +02:00
Pravdyvy
72d389a7c3 Merge branch 'main' into Pravdyvy/iss131-error-handling 2025-11-27 05:53:03 +02:00
Daniil Polyakov
d7331455fc feat: add list account subcommand 2025-11-27 04:22:49 +03:00
Sergio Chouhy
d1d2292028 fmt 2025-11-26 20:13:23 -03:00
Sergio Chouhy
1df24eb11f call write_nssa_outputs function once 2025-11-26 17:41:49 -03:00
Sergio Chouhy
bc24f006ef use window 2025-11-26 17:37:22 -03:00
Sergio Chouhy
12e21c935c Merge branch 'main' into schouhy/add-multi-chain-calls 2025-11-26 17:12:35 -03:00
Sergio Chouhy
97209caa9c Merge branch 'main' into schouhy/implement-privacy-preserving-tail-calls 2025-11-26 16:37:23 -03:00
Pravdyvy
d78c83b7d3
Merge pull request #196 from vacp2p/Pravdyvy/commenting-of-troublesome-test
Turn off test test_success_private_transfer_to_another_owned_account_cont_run_path
2025-11-26 20:54:33 +02:00
Daniil Polyakov
8568302f38
Merge pull request #195 from vacp2p/arjentix/toolchain-and-fmt-improvements 2025-11-26 21:35:28 +03:00
Pravdyvy
c9b911836b fix: test commented 2025-11-26 15:13:40 +02:00
Pravdyvy
30f19b245d fix: suggestions fix 3 2025-11-26 14:53:26 +02:00
Pravdyvy
77570c48e9 fix: suggestions 2 2025-11-26 14:27:09 +02:00
Pravdyvy
e9d7e224b0 fix: ci test 1 2025-11-26 13:34:58 +02:00
Pravdyvy
fc531021fb fix: comments fix 1 2025-11-26 07:32:35 +02:00
Pravdyvy
0d11c3688e fix: suggestions hotfix 2025-11-26 07:18:25 +02:00
Pravdyvy
463942df80
Apply suggestions from code review 1
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-11-26 07:07:58 +02:00
Pravdyvy
4d1d765cbe Merge branch 'main' into Pravdyvy/iss131-error-handling 2025-11-26 06:49:46 +02:00
Daniil Polyakov
a714e3c563 feat: enhance rustfmt config 2025-11-26 00:33:09 +03:00
Daniil Polyakov
72d20a3546 feat: setup current stable toolchain 2025-11-26 00:27:26 +03:00
Daniil Polyakov
1910d68430
Merge pull request #184 from vacp2p/arjentix/iss-134-rename-address-to-account-id
refactor: rename `Address` to `AccountId`
2025-11-25 23:31:29 +03:00
Pravdyvy
819f96da6c fix: try other tests 2025-11-25 21:01:00 +02:00
Daniil Polyakov
ea9c659fb1 refactor: rename Address to AccountId 2025-11-25 21:38:07 +03:00
Sergio Chouhy
a3061afebe replace unwrap with expect 2025-11-25 15:15:14 -03:00
Sergio Chouhy
ba556bee0b nit 2025-11-25 15:03:17 -03:00
Sergio Chouhy
58933a8270 Merge branch 'schouhy/implement-privacy-preserving-tail-calls' of github.com:vacp2p/nescience-testnet into schouhy/implement-privacy-preserving-tail-calls 2025-11-25 14:52:16 -03:00
Sergio Chouhy
3f636465f6 avoid using manual indexing in vector 2025-11-25 14:51:28 -03:00
Sergio Chouhy
8e1c53bd4e use instruction_words from read in pinata 2025-11-25 14:51:02 -03:00
Sergio Chouhy
425f0ccc1b
Update nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs
Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
2025-11-25 14:20:56 -03:00
Pravdyvy
3779372674 fix: ci test 2025-11-25 17:14:19 +02:00
Pravdyvy
a0e1bdb963 fix: more extension for test 2025-11-25 14:45:37 +02:00
Sergio Chouhy
893011e7bf hot fix for integration test 2025-11-25 09:37:46 -03:00
Pravdyvy
4fc01afbaa fix: test time extension test 2025-11-25 10:40:55 +02:00
Pravdyvy
46fad3c5e7 fix: comments fix 1 2025-11-25 09:40:46 +02:00
Pravdyvy
adcf70da76 fix: test run 2025-11-25 08:58:15 +02:00
Sergio Chouhy
8af6365c5d noop 2025-11-24 08:47:33 -03:00
Sergio Chouhy
8c9b46b0df hot fix for integration test 2025-11-24 08:01:23 -03:00
Sergio Chouhy
0054ce5847 nit 2025-11-22 18:39:02 -03:00
Sergio Chouhy
d73fcbd2b3 add docstrings 2025-11-22 18:30:15 -03:00
Sergio Chouhy
47a7656ec4 add asserts in test 2025-11-22 17:48:43 -03:00
Sergio Chouhy
386d958c88 fmt, clippy 2025-11-22 16:40:16 -03:00
Sergio Chouhy
bfe38b012e small refactor 2025-11-22 16:39:34 -03:00
Sergio Chouhy
b59cd0da92 wip 2025-11-22 15:16:43 -03:00
Daniil Polyakov
3355d23218
Merge pull request #167 from vacp2p/iss145-fix-mempool-locks
Fix locking on high transaction amount, refactor sequencer & mempool
2025-11-21 13:22:10 +03:00
Pravdyvy
dc57f6b027 fix: ci test 5 2025-11-21 09:22:23 +02:00
Pravdyvy
05e01f3a76 fix: ci test 4 2025-11-21 09:06:30 +02:00
Pravdyvy
effbfac7d9 fix: ci test 3 2025-11-21 08:49:56 +02:00
Pravdyvy
8839edc377 fix: ci test 2 2025-11-21 08:27:16 +02:00
Pravdyvy
e3ce522588 Merge branch 'main' into Pravdyvy/iss131-error-handling 2025-11-20 15:49:27 +02:00
Daniil Polyakov
110589d332 refactor: remove RpcRollingConfig 2025-11-20 15:40:32 +03:00
Daniil Polyakov
95ec42bba7 chore: left some comments 2025-11-20 15:40:32 +03:00
Daniil Polyakov
d15d208ad3 fix: typo 2025-11-20 15:40:32 +03:00
Daniil Polyakov
c1fabb2181 refactor: sequencer & mempool 2025-11-20 15:40:32 +03:00
Daniil Polyakov
6280110c9f refactor: rename helperstruct to response 2025-11-20 15:40:32 +03:00
Sergio Chouhy
b90837edb6 add test wip 2025-11-20 01:40:05 -03:00
Sergio Chouhy
1214bf6e7e Merge branch 'main' into schouhhy/expand-readme 2025-11-20 00:21:15 -03:00
Pravdyvy
e3d095464c Merge branch 'main' into Pravdyvy/deterministic-key-derivation 2025-11-19 18:45:56 +02:00
Pravdyvy
4847c84347
Merge pull request #148 from vacp2p/Pravdyvy/wallet-personalization
Wallet personalization
2025-11-19 18:44:56 +02:00
Pravdyvy
899b1b79a5 fix: ci test 1 2025-11-19 17:05:20 +02:00
Pravdyvy
2f07853975 fix: borsh integrated into transactions 2025-11-19 14:28:18 +02:00
Pravdyvy
e44c0a8250 Merge branch 'main' into Pravdyvy/wallet-personalization 2025-11-19 14:05:20 +02:00
Pravdyvy
7ace27c4f9
Merge pull request #147 from vacp2p/Pravdyvy/default-wallet-config-path
Default wallet config path
2025-11-19 14:04:27 +02:00
Pravdyvy
30bcd20ac5 fix: privacy-preserving test 2025-11-19 09:00:32 +02:00
Pravdyvy
ef73336aa5 fix: borsh derivation on publci transactions 2025-11-18 17:52:46 +02:00
Sergio Chouhy
4f650e939f add instruction to the program output 2025-11-18 01:38:47 -03:00
Sergio Chouhy
38490a6163 wip 2025-11-18 00:04:53 -03:00
Sergio Chouhy
fd4ebde1fb fix account passing mechanism 2025-11-17 15:43:01 -03:00
Pravdyvy
10731e326d fix: suggestion upfix 2025-11-17 14:43:44 +02:00
Pravdyvy
20a31bd364 fix: suggestion fix 2025-11-17 14:43:33 +02:00
Sergio Chouhy
0ad6d290ae fix 2025-11-15 02:27:06 -03:00
Sergio Chouhy
f2fb98608a Add pinata program instructions 2025-11-15 02:21:57 -03:00
Sergio Chouhy
521ba5adbd add commands 2025-11-15 01:50:01 -03:00
Sergio Chouhy
ee47d98300 add section token program 2025-11-15 01:28:00 -03:00
Sergio Chouhy
e707b1b74f add tutorial sections 2025-11-13 22:18:39 -03:00
Sergio Chouhy
0ea46f5048 update Readme 2025-11-13 17:50:15 -03:00
Sergio Chouhy
c7b415b2f4 add max depth reached error for chained calls 2025-11-12 19:55:02 -03:00
Sergio Chouhy
a94440fa1f rename 2025-11-12 19:18:04 -03:00
Sergio Chouhy
2e582e7874 add multi chain calls 2025-11-12 19:08:46 -03:00
Pravdyvy
e92ad2132f feat: keys restoration from mnemonic 2025-11-12 08:26:25 +02:00
Pravdyvy
6cbc5028cf feat: tree construction 2025-11-11 17:25:08 +02:00
Pravdyvy
fcb3993a47 fix: merge fix 2025-11-11 15:41:32 +02:00
Pravdyvy
a8462ab5a3 Merge branch 'main' into Pravdyvy/deterministic-key-derivation 2025-11-11 15:40:33 +02:00
Pravdyvy
ec149d3227 feat: deterministic keys 2025-11-11 12:15:20 +02:00
Pravdyvy
20c276e63e fix: continuation of integration 2025-11-10 16:29:33 +02:00
Sergio Chouhy
ef7a5b6610 wip 2025-11-07 20:42:00 -03:00
Sergio Chouhy
ffe2ae4e0b Merge branch 'main' into schouhy/implement-privacy-preserving-tail-calls 2025-11-07 19:32:42 -03:00
Sergio Chouhy
d69e8a292e
Merge pull request #150 from vacp2p/schouhy/update-readme
Update README
2025-11-07 14:42:48 -03:00
Sergio Chouhy
a048fad7cd Update readme 2025-11-07 13:16:01 -03:00
Pravdyvy
d9a130cc55 feat: private tree 2025-11-07 16:21:14 +02:00
Sergio Chouhy
dfd45c8678 wip 2025-11-06 19:35:47 -03:00
Pravdyvy
4a430622f4 fix: testing and debugging 2025-11-06 16:50:32 +02:00
Pravdyvy
af1e129b6b feat: public keys tree 2025-11-05 15:15:29 +02:00
Pravdyvy
9788f189b1 feat: stat of deterministic passwords 2025-11-04 16:09:04 +02:00
Sergio Chouhy
5e22357f9a
Merge pull request #143 from vacp2p/schouhy/node-state-reconstruction
Node state reconstruction from block storage
2025-11-04 01:17:37 -03:00
Sergio Chouhy
51c1b7f31f
Merge pull request #142 from vacp2p/schouhy/add-sequencer-tps-test
Add tps integration test
2025-11-03 23:37:10 -03:00
Sergio Chouhy
883fdc583a Merge branch 'main' into schouhy/node-state-reconstruction 2025-11-03 23:36:42 -03:00
Sergio Chouhy
343f8c4864 Merge branch 'main' into schouhy/add-sequencer-tps-test 2025-11-03 13:47:57 -03:00
Pravdyvy
2920953184 Merge branch 'main' into Pravdyvy/default-wallet-config-path 2025-11-03 15:49:10 +02:00
Pravdyvy
f593e6be94 Merge branch 'main' into Pravdyvy/wallet-personalization 2025-11-03 15:47:51 +02:00
Oleksandr Pravdyvyi
9d31b143ed
feat: config command added 2025-11-03 15:45:50 +02:00
Sergio Chouhy
4be1977925
Merge pull request #146 from vacp2p/schouhy/add-tail-call-mechanism
Add tail call mechanism for public executions
2025-11-03 10:36:39 -03:00
Pravdyvy
aa36cc09fa
Merge pull request #141 from vacp2p/Pravdyvy/cli-refactor
CLI refactor
2025-11-03 15:35:30 +02:00
Oleksandr Pravdyvyi
f635f07ebd
feat: config subcommand 2025-10-31 16:23:01 +02:00
Oleksandr Pravdyvyi
18dca9407c
fix: config update 2025-10-31 10:16:15 +02:00
Oleksandr Pravdyvyi
e40d387475
fix: sequencer config update 2025-10-31 10:14:12 +02:00
Sergio Chouhy
12974f6f6b refactor 2025-10-30 14:10:33 -03:00
Oleksandr Pravdyvyi
228f7591d5
fix: lint and fmt 2025-10-30 17:23:50 +02:00
Sergio Chouhy
0fb72e452f fix claiming mechanism for chained calls 2025-10-30 10:52:53 -03:00
Oleksandr Pravdyvyi
2c21abc2d9
fix: default config paths agnostic 2025-10-30 15:33:58 +02:00
Oleksandr Pravdyvyi
c2b8459645
fix: suggestions fix 1 2025-10-30 15:00:21 +02:00
Sergio Chouhy
48fc643952 add chained call test 2025-10-30 09:36:20 -03:00
Sergio Chouhy
3a27719392 add tail-chain logic for public transactions 2025-10-29 13:40:56 -03:00
Oleksandr Pravdyvyi
813868f16f
feat: linux default config paths 2025-10-29 13:23:07 +02:00
Oleksandr Pravdyvyi
a903c221db
fix: tests fix 2025-10-29 12:02:41 +02:00
Sergio Chouhy
6d9d6b3d28 add chained_call field to program output 2025-10-29 00:40:56 -03:00
Sergio Chouhy
e96bbb84a4 remove unnecesary line 2025-10-28 23:35:16 -03:00
Sergio Chouhy
719a8dcafe refactor tps test 2025-10-28 16:45:16 -03:00
Sergio Chouhy
ad9ad8d1d3 Merge branch 'main' into schouhy/add-sequencer-tps-test 2025-10-28 16:39:38 -03:00
Sergio Chouhy
43cf732ad4 Merge branch 'main' into schouhy/node-state-reconstruction 2025-10-28 15:56:05 -03:00
Sergio Chouhy
97eb110f0e
Merge pull request #144 from vacp2p/schouhy/add-progam-methods-guest-cargo-lock-for-determinism
Add `nssa/program_methods/guest/Cargo.lock` for nssa program deterministic builds
2025-10-28 13:12:11 -03:00
Sergio Chouhy
4a23accbde refactor 2025-10-28 13:08:05 -03:00
Pravdyvy
e41ffeac68 Merge branch 'main' into Pravdyvy/cli-refactor 2025-10-28 16:54:39 +02:00
Pravdyvy
785ed5f169 doc: cli docs added 2025-10-28 16:53:39 +02:00
Pravdyvy
39f48cd74e
Merge pull request #140 from vacp2p/Pravdyvy/test-suite-proc-macro
Test suite proc macro
2025-10-28 16:50:24 +02:00
Oleksandr Pravdyvyi
5840f9b779
fix: cli full refactor 2025-10-28 16:02:30 +02:00
Oleksandr Pravdyvyi
b3e4b9a8ca
Merge branch 'Pravdyvy/test-suite-proc-macro' into Pravdyvy/cli-refactor 2025-10-28 14:41:34 +02:00
Oleksandr Pravdyvyi
5b3732d9f2
Merge branch 'main' into Pravdyvy/test-suite-proc-macro 2025-10-28 14:40:59 +02:00
Oleksandr Pravdyvyi
27bb5bbb0f
temp: temp changes 2025-10-28 14:40:16 +02:00
Pravdyvy
60b7c58af8
Merge pull request #137 from vacp2p/Pravdyvy/usability-updates
Boilerplate refactor
2025-10-28 14:39:30 +02:00
Oleksandr Pravdyvyi
bf25c92b30
fix: suggestions fix 2025-10-28 10:41:40 +02:00
Sergio Chouhy
6b75609012 fix block id 2025-10-27 20:07:15 -03:00
Sergio Chouhy
1ad93c2977 fmt 2025-10-27 16:04:12 -03:00
Oleksandr Pravdyvyi
62668161b2
feat: transfers changes 2025-10-27 14:32:28 +02:00
Sergio Chouhy
a14b15d123 add Cargo.lock 2025-10-25 00:34:02 -03:00
Sergio Chouhy
7f075fcdd3 wip 2025-10-25 00:30:04 -03:00
Sergio Chouhy
4648f46f51 minor changes 2025-10-24 23:09:10 -03:00
Sergio Chouhy
c47693b9b0 add tps integration test 2025-10-24 16:17:00 -03:00
Oleksandr Pravdyvyi
66ee0c5449
fix: account subcommand updated 2025-10-24 15:26:30 +03:00
Oleksandr Pravdyvyi
0384efc38f
fix: base58 adoption fixes 2025-10-24 11:12:32 +03:00
Oleksandr Pravdyvyi
a12d3cc354
Merge branch 'Pravdyvy/test-suite-proc-macro' into Pravdyvy/cli-refactor 2025-10-24 09:11:46 +03:00
Oleksandr Pravdyvyi
13232200c0
Merge branch 'Pravdyvy/usability-updates' into Pravdyvy/test-suite-proc-macro 2025-10-24 09:08:46 +03:00
Oleksandr Pravdyvyi
5c6c7d1c3e
Merge branch 'main' into Pravdyvy/usability-updates 2025-10-23 17:38:09 +03:00
Oleksandr Pravdyvyi
4e36ae4679
fix; first refactor 2025-10-23 17:33:25 +03:00
Sergio Chouhy
f96f4d9117
Merge pull request #136 from vacp2p/schouhy/code-cleanup
Code cleanup
2025-10-23 11:09:29 -03:00
Oleksandr Pravdyvyi
d7089eac96
fix: taplo fmt 2025-10-22 16:28:19 +03:00
Oleksandr Pravdyvyi
4ecd0430b8
Merge branch 'main' into Pravdyvy/test-suite-proc-macro 2025-10-22 14:11:49 +03:00
Oleksandr Pravdyvyi
31783d9b78
fix: test suite proc macro 2025-10-22 13:55:35 +03:00
Sergio Chouhy
8ced04ae97
Merge pull request #138 from vacp2p/schouhy/fix-merge-error
Fix merge compilation error
2025-10-21 10:45:13 -03:00
Sergio Chouhy
32b7780ff3 remove unused dep 2025-10-21 09:28:00 -03:00
Sergio Chouhy
d99fbde101 Merge branch 'main' into schouhy/code-cleanup 2025-10-21 09:27:19 -03:00
Oleksandr Pravdyvyi
37360e6d8c
fix: merge fix 2025-10-21 15:17:44 +03:00
Oleksandr Pravdyvyi
941738c26f
Merge branch 'main' into Pravdyvy/usability-updates 2025-10-21 15:16:44 +03:00
Oleksandr Pravdyvyi
a01bfe3688
fix: private account preparation unified 2025-10-21 15:15:41 +03:00
Sergio Chouhy
3b3493df94 add await 2025-10-21 09:14:29 -03:00
Sergio Chouhy
bdb0c576a3
Merge pull request #128 from vacp2p/schouhy/add-program-deployment-transactions
Add program deployment transaction types
2025-10-21 09:10:24 -03:00
Sergio Chouhy
04f7e67384
Merge pull request #127 from vacp2p/Pravdyvy/various-updates
Wallet updates
2025-10-21 09:10:06 -03:00
Oleksandr Pravdyvyi
5b7e162e4d
fix: wallet transaction creation refactor 2025-10-21 10:32:42 +03:00
Oleksandr Pravdyvyi
bbab0399cd
Merge branch 'main' into Pravdyvy/various-updates 2025-10-21 07:09:42 +03:00
Sergio Chouhy
1e3f7038ee Merge branch 'main' into schouhy/code-cleanup 2025-10-20 22:51:38 -03:00
Sergio Chouhy
2da861c2d2 Merge branch 'main' into schouhy/add-program-deployment-transactions 2025-10-20 22:47:18 -03:00
Sergio Chouhy
17e87a5f53
Merge pull request #126 from vacp2p/schouhy/add-authenticated-transfer-program-init-function
Add account initialization function to the authenticated transfer program
2025-10-20 20:42:58 -03:00
Sergio Chouhy
e3a498faf0 Merge branch 'main' into schouhy/add-program-deployment-transactions 2025-10-20 19:19:18 -03:00
Sergio Chouhy
86bbbcdda8
Merge pull request #125 from vacp2p/schouhy/reproducible-builds-of-guest-programs
Reproducible builds through `nssa/build.rs`
2025-10-20 19:05:16 -03:00
Sergio Chouhy
fd7907f893 Merge branch 'main' into schouhy/add-authenticated-transfer-program-init-function 2025-10-20 19:03:51 -03:00
Sergio Chouhy
204e5444c8 Merge branch 'main' into schouhy/reproducible-builds-of-guest-programs 2025-10-20 17:47:59 -03:00
Sergio Chouhy
2c138cb027
Merge pull request #124 from vacp2p/Pravdyvy/token-program-private
Private token program wallet interactions
2025-10-20 17:45:00 -03:00
Sergio Chouhy
348156043a
Merge pull request #123 from vacp2p/schouhy/wallet-fetch-programs
Add wallet command to check program ids match the ones used by the node
2025-10-20 17:44:40 -03:00
Sergio Chouhy
79606f81ed Merge branch 'main' into schouhy/wallet-fetch-programs 2025-10-20 15:21:06 -03:00
Sergio Chouhy
1ded99c7de
Merge pull request #122 from vacp2p/Pravdyvy/wallet-pinata-private
Wallet pinata program private execution
2025-10-20 15:18:23 -03:00
Oleksandr Pravdyvyi
28c1fd39a4
fix: suggestions added 1 2025-10-20 10:01:54 +03:00
Oleksandr Pravdyvyi
ff448cbb3c
fix: fmt 2025-10-20 09:20:22 +03:00
Oleksandr Pravdyvyi
833d6bf932
Merge branch 'Pravdyvy/token-program-private' into Pravdyvy/various-updates 2025-10-20 09:19:53 +03:00
Oleksandr Pravdyvyi
e5a6acf28d
fix; shielded and deshielded transfers 2025-10-20 09:10:54 +03:00
Sergio Chouhy
7724b7a2db remove dup test 2025-10-17 17:39:03 -03:00
Sergio Chouhy
e1085e1907 fmt 2025-10-17 16:20:31 -03:00
Sergio Chouhy
6447f8fbf7 remove unused dependencies 2025-10-17 16:17:15 -03:00
Sergio Chouhy
fd0e783176 remove unused error type 2025-10-17 16:16:54 -03:00
Sergio Chouhy
93fd485622 move common errors to own module. Remove unused ExecutionFailureKind variants 2025-10-17 16:16:11 -03:00
Sergio Chouhy
7d85424948 remove unnecessary rs_merkle dep 2025-10-17 16:07:59 -03:00
Sergio Chouhy
b93c0aa390 rename TreeHashType to HashType 2025-10-17 16:04:09 -03:00
Sergio Chouhy
217551f960 remove outdated env.sh file 2025-10-17 15:58:28 -03:00
Sergio Chouhy
9e03507dd4 remove unused error codes 2025-10-17 15:56:26 -03:00
Sergio Chouhy
b3822c4b75 remove outdated sc methods in rocksdb 2025-10-17 15:52:00 -03:00
Sergio Chouhy
c3ca1c4804 remove unused common/src/utxo_commitment.rs file 2025-10-17 15:39:17 -03:00
Sergio Chouhy
f669f10d9e remove outdated common/src/execution_input.rs file 2025-10-17 15:37:57 -03:00
Sergio Chouhy
983865d31f remove outdated common/src/commitment.rs file 2025-10-17 15:36:04 -03:00
Sergio Chouhy
e0fd94152a remove outdated common/sec/nullifier.rs file 2025-10-17 15:35:06 -03:00
Sergio Chouhy
0b44afa4f6 remove unused code 2025-10-17 15:29:09 -03:00
Sergio Chouhy
323f58d566 clippy 2025-10-17 11:05:58 -03:00
Sergio Chouhy
25ecfa733f remove double test in ci 2025-10-17 07:59:32 -03:00
Sergio Chouhy
6b18168c3c remove unused type alias 2025-10-16 17:03:01 -03:00
Sergio Chouhy
6157e3023b add execution of deployed program in integration test 2025-10-16 16:54:34 -03:00
Sergio Chouhy
19215ee009 rename V01State to V02State 2025-10-16 16:24:18 -03:00
Sergio Chouhy
f3fbae66b5 fmt 2025-10-16 16:20:29 -03:00
Sergio Chouhy
ba20728f40 update version tags in domain separator 2025-10-16 16:19:03 -03:00
Oleksandr Pravdyvyi
9614c3143b
feat: integration test and async fs 2025-10-16 15:58:35 +03:00
Sergio Chouhy
942e90ae2a add sequencer methods 2025-10-15 20:14:19 -03:00
Sergio Chouhy
bfde33d78d add add canonical serialization for program deployment txs 2025-10-15 18:00:35 -03:00
Sergio Chouhy
da28f3317b add transition function for program deployment 2025-10-15 17:28:50 -03:00
Oleksandr Pravdyvyi
28fe9e2113
fix: merge updates 2025-10-15 15:44:52 +03:00
Oleksandr Pravdyvyi
5f00c89c0a
Merge branch 'Pravdyvy/token-program-private' into Pravdyvy/various-updates 2025-10-15 15:32:15 +03:00
Oleksandr Pravdyvyi
5010c6c370
fix: merge update 2025-10-15 15:29:28 +03:00
Oleksandr Pravdyvyi
8e3fb2f67b
Merge branch 'Pravdyvy/wallet-pinata-private' into Pravdyvy/token-program-private 2025-10-15 15:26:36 +03:00
Oleksandr Pravdyvyi
1428dc4a90
fix: suggestion fix 2 2025-10-15 15:25:36 +03:00
Oleksandr Pravdyvyi
88446b17f9
feat: automatic mode added 2025-10-15 15:17:30 +03:00
Sergio Chouhy
54c54199d7 wip 2025-10-14 17:15:04 -03:00
Oleksandr Pravdyvyi
c39c9ad4ca
feat: cli refactor 2025-10-14 15:29:18 +03:00
Oleksandr Pravdyvyi
4b7319afe9
fix: merge updates 2025-10-14 10:18:54 +03:00
Oleksandr Pravdyvyi
d05093f84f
Merge branch 'Pravdyvy/wallet-pinata-private' into Pravdyvy/token-program-private 2025-10-14 09:40:16 +03:00
Oleksandr Pravdyvyi
d556c9b699
fix: lint build fix 1 2025-10-14 09:36:21 +03:00
Oleksandr Pravdyvyi
d4a8cbd8d8
fix: suggestions 1 2025-10-14 08:33:20 +03:00
Sergio Chouhy
9559fb4bf0 remove unused Nonce type alias 2025-10-13 19:05:08 -03:00
Sergio Chouhy
fb4bb02f1a add docstrings 2025-10-13 18:06:02 -03:00
Sergio Chouhy
a2b9aef152 minor refactor 2025-10-13 17:45:03 -03:00
Sergio Chouhy
c772f1b0fe add init function 2025-10-13 17:08:29 -03:00
Sergio Chouhy
6274addad9 Remove unused Nonce alias 2025-10-13 16:25:59 -03:00
Sergio Chouhy
cf9d296d08 remove redundant test in ci 2025-10-13 15:26:14 -03:00
Sergio Chouhy
ba35fafad4 fmt 2025-10-13 15:15:38 -03:00
Oleksandr Pravdyvyi
898c5e9bcf
fix: structured subcommand approach 2025-10-13 17:25:36 +03:00
Oleksandr Pravdyvyi
577171bc5c
fix: try generic array dep 2025-10-13 16:12:43 +03:00
Oleksandr Pravdyvyi
a205cc1505
feat: private token program transfers 2025-10-13 13:29:32 +03:00
Sergio Chouhy
35806f1036 fmt 2025-10-10 18:24:11 -03:00
Sergio Chouhy
d7240e073a fix integration tests 2025-10-10 18:20:47 -03:00
Sergio Chouhy
766d72bd75 remove get programs 2025-10-10 17:44:42 -03:00
Sergio Chouhy
f200f39779 minor fix 2025-10-10 16:48:12 -03:00
Sergio Chouhy
69b610269b use risc0 method for image_id computaiton 2025-10-10 16:46:12 -03:00
Oleksandr Pravdyvyi
7213da587c
fix: token creation test 2025-10-10 11:12:47 +03:00
Oleksandr Pravdyvyi
0635bd201d
feat: private token definitions 2025-10-09 14:40:06 +03:00
Oleksandr Pravdyvyi
359e545b69
fix: pinata test fix 2025-10-09 09:44:13 +03:00
Sergio Chouhy
e8f660c2c7 wip 2025-10-08 20:27:09 -03:00
Oleksandr Pravdyvyi
4c45fa7768
Merge branch 'main' into Pravdyvy/wallet-pinata-private 2025-10-08 16:02:22 +03:00
Oleksandr Pravdyvyi
566df336f5
feat: wallet method for private pinata claim 2025-10-08 16:01:35 +03:00
Sergio Chouhy
a071340564
Merge pull request #121 from vacp2p/schouhy/fix-non-uniqueness-of-private-account-ids
Proposal for enforcing uniqueness of private account ids
2025-10-07 14:58:14 -03:00
Sergio Chouhy
667ad5a532 Merge branch 'main' into schouhy/fix-non-uniqueness-of-private-account-ids 2025-10-07 12:56:57 -03:00
Sergio Chouhy
1645dacd1f
Merge pull request #120 from vacp2p/schouhy/add-check-for-repeated-account-ids-in-circuit
Fix repeated ids inflation bug
2025-10-07 11:43:29 -03:00
Sergio Chouhy
ed9682bf58 Merge branch 'main' into schouhy/add-check-for-repeated-account-ids-in-circuit 2025-10-07 09:49:53 -03:00
Sergio Chouhy
e101a9311c
Merge pull request #119 from vacp2p/schouhy/wallet-minor-improvements
Wallet improvements
2025-10-07 09:41:36 -03:00
Oleksandr Pravdyvyi
e041b57807
feat: private pinata claim method on wallet 2025-10-07 10:40:06 +03:00
Sergio Chouhy
4bb8bc94ff Merge branch 'main' into schouhy/wallet-minor-improvements 2025-10-06 16:08:06 -03:00
Sergio Chouhy
cbbc3cfb9e
Merge pull request #118 from vacp2p/Pravdyvy/serde-json-removal-from-db
serde-json removal from db storage
2025-10-06 13:39:42 -03:00
Oleksandr Pravdyvyi
33e3db9f19
fix: merge fix 2025-10-06 13:25:05 +03:00
Oleksandr Pravdyvyi
bc01fe0dc7
fix: merge dep fix 2025-10-06 13:20:56 +03:00
Pravdyvy
468b669c14
Merge branch 'main' into Pravdyvy/serde-json-removal-from-db 2025-10-06 11:43:03 +03:00
Sergio Chouhy
b2e51990c9 remove commented code 2025-10-03 23:05:11 -03:00
Sergio Chouhy
4e51a9c778 add code comment 2025-10-03 23:04:36 -03:00
Sergio Chouhy
63436955c6 add nullifier for private account initialization 2025-10-03 20:47:37 -03:00
Sergio Chouhy
8b70da517c add check and test 2025-10-03 18:43:09 -03:00
Sergio Chouhy
f8153c6fb9 fmt, clippy 2025-10-03 17:07:15 -03:00
Sergio Chouhy
313425f6f8 rename 2025-10-03 17:06:45 -03:00
Sergio Chouhy
8f874a6b4f refactor 2025-10-03 16:50:23 -03:00
Sergio Chouhy
b6e7019588 use account with metadata constructor 2025-10-03 08:44:15 -03:00
Sergio Chouhy
46f899ac95 fmt 2025-10-03 08:11:55 -03:00
Sergio Chouhy
9141fbf06c use random nonces for private accounts in wallet 2025-10-03 01:30:40 -03:00
Sergio Chouhy
d54ea96bba remove resetting program owner in wallet privacy commands 2025-10-03 00:44:46 -03:00
Sergio Chouhy
e69fb8b1b8 fix eph key computation 2025-10-02 22:30:33 -03:00
Sergio Chouhy
ddc127f591 machete 2025-10-02 09:17:19 -03:00
Sergio Chouhy
aa8b138945 fmt clippy 2025-10-02 08:58:57 -03:00
Sergio Chouhy
86f61e5ac9 fix impl 2025-10-02 08:40:52 -03:00
Sergio Chouhy
a00773d5aa wip 2025-09-30 17:14:09 -03:00
Sergio Chouhy
6070213232 wip 2025-09-30 16:45:25 -03:00
Sergio Chouhy
4bd5494370 wip 2025-09-30 15:30:28 -03:00
Sergio Chouhy
64048ccf1d rename 2025-09-30 14:44:43 -03:00
Sergio Chouhy
dfab1d6fa8 minor refactor 2025-09-30 14:31:04 -03:00
Sergio Chouhy
23afa1e05a nit 2025-09-30 14:17:46 -03:00
Sergio Chouhy
f707d3893d remove unused function 2025-09-30 14:15:50 -03:00
Sergio Chouhy
f49d79d0e4 Rename GetProofForCommitment 2025-09-30 14:13:12 -03:00
Sergio Chouhy
fea132ef24
Merge pull request #116 from vacp2p/schouhy/add-token-program
Add token program
2025-09-29 21:31:02 -03:00
Sergio Chouhy
36beca9c7c Merge branch 'main' into schouhy/add-token-program 2025-09-29 16:00:53 -03:00
Sergio Chouhy
01638ad7be
Merge pull request #115 from vacp2p/Pravdyvy/wallet-privacy-preserving-transactions
Privacy preserving transactions in wallet
2025-09-29 14:29:18 -03:00
Oleksandr Pravdyvyi
c3ae7ab0a2
fix: account id merge fix 2025-09-26 09:50:09 +03:00
Oleksandr Pravdyvyi
8d9e7764aa
Merge branch 'main' into Pravdyvy/wallet-privacy-preserving-transactions 2025-09-26 09:15:25 +03:00
Oleksandr Pravdyvyi
3b99bf60c7
fix: ci simplification 2025-09-26 08:51:24 +03:00
Sergio Chouhy
cc927d2e43
Merge pull request #114 from vacp2p/schouhy/change-authorization-mechanism
Make addresses available to programs
2025-09-25 13:30:00 -03:00
Sergio Chouhy
bedcccb633 Merge branch 'schouhy/change-authorization-mechanism' into schouhy/add-token-program 2025-09-25 12:52:17 -03:00
Sergio Chouhy
4a755a0c23 Merge branch 'main' into schouhy/change-authorization-mechanism 2025-09-25 12:39:13 -03:00
Oleksandr Pravdyvyi
c58ef27224
feat: first db update 2025-09-25 11:53:42 +03:00
Oleksandr Pravdyvyi
1cdec1e05f
fix: tests fix 2025-09-25 06:56:21 +03:00
Oleksandr Pravdyvyi
6f2a193a50
fix: claiming path 2025-09-25 05:54:32 +03:00
Oleksandr Pravdyvyi
49b2069f0f
fix: fmt 2025-09-24 16:53:45 +03:00
Oleksandr Pravdyvyi
2ce773705d
Merge branch 'main' into Pravdyvy/wallet-privacy-preserving-transactions 2025-09-24 16:53:22 +03:00
Oleksandr Pravdyvyi
0e5087ca8f
fix: tests run 1 2025-09-24 16:44:03 +03:00
Sergio Chouhy
ae0c589d1e
Merge pull request #111 from vacp2p/schouhy/add-pinata-program
Add piñata program
2025-09-24 09:44:53 -03:00
Oleksandr Pravdyvyi
21e68b6b4a
fix: proving in dev mode 2025-09-24 15:24:20 +03:00
Oleksandr Pravdyvyi
a7c60a56b7
fix: try unify program id 2025-09-24 14:29:56 +03:00
Oleksandr Pravdyvyi
d7c577061e
fix: removal of locks 2025-09-24 12:57:17 +03:00
Oleksandr Pravdyvyi
bc5b9478df
fix: gitignore update 2025-09-24 12:25:25 +03:00
Oleksandr Pravdyvyi
476d5a9b14
fix: swanitem revert try 2025-09-24 12:15:59 +03:00
Oleksandr Pravdyvyi
0d68bec358
Merge branch 'main' into Pravdyvy/wallet-privacy-preserving-transactions 2025-09-23 15:50:06 +03:00
Oleksandr Pravdyvyi
3d704bd321
fix: account storage 2025-09-23 14:47:18 +03:00
Oleksandr Pravdyvyi
e0f5ac9e7c
fix: all execution types tests added 2025-09-23 09:54:33 +03:00
Oleksandr Pravdyvyi
d3742867ed
fix: more integration tests 2025-09-22 16:38:25 +03:00
Pravdyvy
6fda3d84dd
Merge pull request #110 from vacp2p/Pravdyvy/key-protocol-update-private
Key protocol update (private)
2025-09-20 04:57:35 +03:00
Sergio Chouhy
f5f5ab4ef1 add token program tests to ci tests 2025-09-19 12:52:21 -03:00
Sergio Chouhy
2de7e49eeb fmt 2025-09-19 12:37:24 -03:00
Sergio Chouhy
fcebd5f726 add tests 2025-09-19 12:22:28 -03:00
Oleksandr Pravdyvyi
c204915e1d
fix: ci try 1 2025-09-19 17:05:37 +03:00
Oleksandr Pravdyvyi
6114ff0d3c
fix: adding test to all tests 2025-09-19 15:50:43 +03:00
Sergio Chouhy
aded05f493 fix token program logic and add explicit panic on balance overflow 2025-09-19 09:49:18 -03:00
Oleksandr Pravdyvyi
76d374a453
fix: first integration test for privacy-preserving tx 2025-09-19 15:03:01 +03:00
Sergio Chouhy
4f67ff0c35 Merge branch 'main' into schouhy/change-authorization-mechanism 2025-09-18 17:09:02 -03:00
Sergio Chouhy
cca835e016 Merge branch 'main' into schouhy/add-pinata-program 2025-09-18 16:50:52 -03:00
Sergio Chouhy
ec55e00049
Merge pull request #109 from vacp2p/schouhy/fix-sequencer-runner
Fix sequencer runner
2025-09-18 12:12:21 -03:00
Sergio Chouhy
b7c2e8a3ec
Merge pull request #108 from vacp2p/schouhy/add-privacy-preserving-circuit-tests
Add privacy preserving circuit tests
2025-09-18 12:11:53 -03:00
Oleksandr Pravdyvyi
0e720dd9d3
fix: configs and tests updates 2025-09-18 15:59:17 +03:00
Oleksandr Pravdyvyi
f1de182ec6
fix: tests fix 2025-09-17 13:57:31 +03:00
Oleksandr Pravdyvyi
2178a3a408
Merge branch 'main' into Pravdyvy/key-protocol-update-private 2025-09-17 11:32:44 +03:00
Pravdyvy
0e81035039
Merge pull request #105 from vacp2p/Pravdyvy/sequencer-update
Sequencer specs implementation
2025-09-17 11:28:10 +03:00
Oleksandr Pravdyvyi
f75fab89b0
fix: lint fix 2025-09-17 09:38:46 +03:00
Oleksandr Pravdyvyi
9336a6c130
Merge branch 'Pravdyvy/key-protocol-update-private' into Pravdyvy/wallet-privacy-preserving-transactions 2025-09-17 09:04:43 +03:00
Oleksandr Pravdyvyi
85a16a2f04
fix: revers of scalar dep 2025-09-17 08:59:14 +03:00
Oleksandr Pravdyvyi
931b8c7176
Merge branch 'Pravdyvy/sequencer-update' into Pravdyvy/key-protocol-update-private 2025-09-17 08:45:21 +03:00
Oleksandr Pravdyvyi
f83fca56d0
Merge branch 'main' into Pravdyvy/sequencer-update 2025-09-17 08:43:42 +03:00
Sergio Chouhy
9aab707ec7 finish test 2025-09-16 11:39:29 -03:00
Sergio Chouhy
473a5fd98b add integratin tests wip 2025-09-16 11:38:26 -03:00
Sergio Chouhy
5979d8d0cf fmt 2025-09-16 11:37:36 -03:00
Sergio Chouhy
24f3952c49 minor change 2025-09-16 11:37:36 -03:00
Sergio Chouhy
afc977e044 change validate_execution logic 2025-09-16 11:37:36 -03:00
Sergio Chouhy
856114019e fix 2025-09-16 11:37:36 -03:00
Sergio Chouhy
b9e0ff230f add token program 2025-09-16 11:37:36 -03:00
Sergio Chouhy
29914b3220 fmt 2025-09-16 11:37:36 -03:00
Sergio Chouhy
37b4d0d6e2 add tests 2025-09-16 11:37:36 -03:00
Sergio Chouhy
bfbb5e2870 rename fingerprint to account_id 2025-09-16 11:37:36 -03:00
Sergio Chouhy
32910e76e3 refactor 2025-09-16 11:37:36 -03:00
Sergio Chouhy
c3b2f4691b fmt, clippy 2025-09-16 11:37:36 -03:00
Sergio Chouhy
3d240c72f8 wip 2025-09-16 11:37:36 -03:00
Sergio Chouhy
80505f0440 rollback to is_authorized field 2025-09-16 11:37:36 -03:00
Sergio Chouhy
cee882502c wip 2025-09-16 11:37:36 -03:00
Sergio Chouhy
bf95a4112e
Merge pull request #117 from vacp2p/schouhy/add-get-account-command
Add `get-account` wallet command.
2025-09-16 11:15:43 -03:00
Oleksandr Pravdyvyi
08526d47bf
feat: shielded+deshielded token transfers 2025-09-16 14:53:00 +03:00
Sergio Chouhy
75b7fdd069 add domain separation for private and public account ids 2025-09-16 07:51:40 -03:00
Oleksandr Pravdyvyi
ae70baf5c4
Merge branch 'Pravdyvy/key-protocol-update-private' into Pravdyvy/wallet-privacy-preserving-transactions 2025-09-16 08:49:10 +03:00
Sergio Chouhy
37b5aec264 fmt 2025-09-15 18:39:36 -03:00
Sergio Chouhy
2d22b170d4 add test 2025-09-15 18:38:45 -03:00
Sergio Chouhy
d796d7baf1 add get-account wallet command. Small refactor 2025-09-15 18:13:08 -03:00
Oleksandr Pravdyvyi
d07b813739
fix: deviations adjustments 2025-09-15 14:04:49 +03:00
Oleksandr Pravdyvyi
93fcbb8f61
Merge branch 'Pravdyvy/sequencer-update' into Pravdyvy/key-protocol-update-private 2025-09-15 10:49:48 +03:00
Oleksandr Pravdyvyi
a11f372091
fix: comments fix 2025-09-15 10:39:57 +03:00
Oleksandr Pravdyvyi
eb9c45bbb7
feat: private token transfer 2025-09-12 16:00:57 +03:00
Sergio Chouhy
d91b07a785 fmt 2025-09-12 09:39:08 -03:00
Sergio Chouhy
2c2c4fed76 add tests 2025-09-12 09:36:26 -03:00
Sergio Chouhy
f31bbe4876 rename fingerprint to account_id 2025-09-12 09:18:40 -03:00
Oleksandr Pravdyvyi
d81fb2665f
fix: commnets fix cleanup 2025-09-12 15:06:49 +03:00
Sergio Chouhy
e12fe4492b refactor 2025-09-11 16:39:07 -03:00
Sergio Chouhy
e8ace6838f fmt, clippy 2025-09-11 15:54:25 -03:00
Oleksandr Pravdyvyi
854d96af72
fix; privacy preserving tx gen 1 2025-09-11 18:32:46 +03:00
Sergio Chouhy
3a9d9af815 wip 2025-09-10 18:56:34 -03:00
Oleksandr Pravdyvyi
65dfbd8bbb
fix merge fix 2025-09-10 13:52:28 +03:00
Oleksandr Pravdyvyi
4a3af34c6a
Merge branch 'Pravdyvy/key-protocol-update-private' into Pravdyvy/wallet-privacy-preserving-transactions 2025-09-10 08:30:55 +03:00
Oleksandr Pravdyvyi
6552e6d015
Merge branch 'Pravdyvy/sequencer-update' into Pravdyvy/wallet-privacy-preserving-transactions 2025-09-10 08:27:58 +03:00
Sergio Chouhy
d63cde85b9 rollback to is_authorized field 2025-09-09 17:03:58 -03:00
Oleksandr Pravdyvyi
ef32f7179e
fix: cache test 2025-09-09 15:41:14 +03:00
Oleksandr Pravdyvyi
54590f8157
fix: ci test run 3 2025-09-09 14:53:34 +03:00
Oleksandr Pravdyvyi
125fac770a
fix: ci test run 2 2025-09-09 14:49:56 +03:00
Oleksandr Pravdyvyi
95032e8e06
feat: ci cache test run 2025-09-09 14:43:48 +03:00
Sergio Chouhy
d24969387c wip 2025-09-08 19:29:56 -03:00
Oleksandr Pravdyvyi
23e79d3e17
fix: fmt 2025-09-08 15:23:32 +03:00
Oleksandr Pravdyvyi
4837413989
fix: merge fix 2025-09-08 15:03:02 +03:00
Oleksandr Pravdyvyi
a5123992c9
Merge branch 'main' into Pravdyvy/key-protocol-update-private 2025-09-08 14:53:22 +03:00
Oleksandr Pravdyvyi
33783e06d8
fix: keys structures updates 2025-09-08 14:48:58 +03:00
Oleksandr Pravdyvyi
0e1905ad22
fix: suggestions fix 2025-09-08 10:11:04 +03:00
Oleksandr Pravdyvyi
5747070e39
fix: merge fixes 2025-09-08 09:09:32 +03:00
Oleksandr Pravdyvyi
8ceb27421e
Merge branch 'main' into Pravdyvy/sequencer-update 2025-09-08 09:03:39 +03:00
Sergio Chouhy
e2d596be20 clippy 2025-09-05 23:49:25 -03:00
Sergio Chouhy
a432019b23 wip 2025-09-05 23:43:15 -03:00
Sergio Chouhy
df2026f107
Merge pull request #113 from vacp2p/comments_commitments
added comments related to commitments
2025-09-05 22:40:53 -03:00
jonesmarvin8
c055941738
Update nssa/src/state.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-09-05 20:48:56 -04:00
jonesmarvin8
4a0a99e264
Update nssa/src/state.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-09-05 20:48:47 -04:00
jonesmarvin8
4ae2af21a5
Update nssa/src/state.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-09-05 20:48:26 -04:00
jonesmarvin8
49019eaee2
Update nssa/core/src/commitment.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-09-05 20:48:11 -04:00
Sergio Chouhy
41f7ea654e
Merge pull request #112 from vacp2p/comments_merkle_trees
added comments for Merkle tree
2025-09-05 19:54:06 -03:00
jonesmarvin8
5dea03027a minor corrections 2025-09-05 16:38:34 -04:00
jonesmarvin8
26acdbed61
Update nssa/src/merkle_tree/mod.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-09-05 16:28:13 -04:00
jonesmarvin8
1e7c3e1555
Update nssa/src/merkle_tree/mod.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-09-05 16:27:55 -04:00
jonesmarvin8
73c11600ba
Update nssa/src/merkle_tree/mod.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-09-05 16:27:43 -04:00
jonesmarvin8
6e7520bfea
Update nssa/src/merkle_tree/mod.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-09-05 16:27:03 -04:00
jonesmarvin8
45b31d304c
Update nssa/src/merkle_tree/mod.rs
Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com>
2025-09-05 16:26:56 -04:00
jonesmarvin8
5eeb925384 added comments related to commitments 2025-09-05 16:21:46 -04:00
jonesmarvin8
4e122abbce added comments for Merkle tree 2025-09-05 16:03:49 -04:00
Oleksandr Pravdyvyi
324f477b63
fix: keys corect generatin 2025-09-05 14:47:58 +03:00
Sergio Chouhy
e2494467ea Merge branch 'main' into schouhy/add-pinata-program 2025-09-04 12:44:37 -03:00
Sergio Chouhy
4a44b12384 wip 2025-09-04 12:44:22 -03:00
Oleksandr Pravdyvyi
ebe616247f
fix: seed generation from mnemonic 2025-09-04 17:49:55 +03:00
Pravdyvy
cab8153201
Merge pull request #101 from vacp2p/Pravdyvy/accounts-dump-fetch
Wallet CLI extension
2025-09-04 17:37:07 +03:00
Oleksandr Pravdyvyi
b1d3b71df7
fix: tests fix 2025-09-04 16:46:20 +03:00
Oleksandr Pravdyvyi
57045fa8e1
fix: merge upfix 2025-09-04 15:15:14 +03:00
Oleksandr Pravdyvyi
00c76df04b
Merge branch 'main' into Pravdyvy/accounts-dump-fetch 2025-09-04 15:14:28 +03:00
Oleksandr Pravdyvyi
d402cfca52
fix: direct log dependency 2025-09-04 15:12:01 +03:00
Oleksandr Pravdyvyi
762a0d760e
fix: resolver 3 2025-09-04 14:54:48 +03:00
Oleksandr Pravdyvyi
7052bccfbc
fix: try edition 2024 2025-09-04 14:38:41 +03:00
Oleksandr Pravdyvyi
ee91d7d79c
fix: ci fix 1 2025-09-04 14:18:44 +03:00
Oleksandr Pravdyvyi
1d627ce5b9
fix: suggestions 1 2025-09-04 13:33:17 +03:00
Sergio Chouhy
efb7108c58 add more tests 2025-09-03 16:44:55 -03:00
Sergio Chouhy
63517b6b1c add circuit tests 2025-09-03 16:25:02 -03:00
Sergio Chouhy
83542b310c fix double nonce increment in privacy preserving tx 2025-09-03 15:20:40 -03:00
Sergio Chouhy
9b4506de3b fix sequencer runner 2025-09-03 14:47:35 -03:00
Sergio Chouhy
e07733e5c3
Merge pull request #107 from vacp2p/schouhy/remove-unused-dependencies
Remove unused dependencies
2025-09-03 09:16:37 -03:00
Oleksandr Pravdyvyi
82f4df638e
Merge branch 'Pravdyvy/accounts-dump-fetch' into Pravdyvy/sequencer-update 2025-09-03 15:11:14 +03:00
Oleksandr Pravdyvyi
55d207ac9a
Merge branch 'main' into Pravdyvy/sequencer-update 2025-09-03 10:31:50 +03:00
Oleksandr Pravdyvyi
b4f21b2f09
fix: checks added 2025-09-03 10:29:51 +03:00
Sergio Chouhy
4f9ee9f19f remove unused dependencies 2025-09-02 16:29:56 -03:00
Sergio Chouhy
82070f9918
Merge pull request #106 from vacp2p/schouhy/add-tag-computation
Add view tag computation
2025-09-02 14:51:44 -03:00
Sergio Chouhy
f08ed17509 test incorrect number of masks in visibility mask list 2025-09-02 14:50:16 -03:00
Sergio Chouhy
a1e4c06bc7 add tests 2025-09-02 14:09:50 -03:00
Sergio Chouhy
f3d63806c3 fix tests 2025-09-02 12:56:01 -03:00
Sergio Chouhy
5190b486c4 fix circuit and add test 2025-09-02 12:45:30 -03:00
Oleksandr Pravdyvyi
ea426d6650
Merge branch 'main' into Pravdyvy/accounts-dump-fetch 2025-09-02 17:12:14 +03:00
Pravdyvy
c297186aee
Merge pull request #104 from vacp2p/Pravdyvy/key-protocol-update-public-part
Key protocol update public part
2025-09-02 17:10:02 +03:00
Oleksandr Pravdyvyi
570a516cbf
fix: merge fix 2025-09-02 16:22:40 +03:00
Oleksandr Pravdyvyi
4ac2196ddf
fix: lock update 2025-09-02 16:11:27 +03:00
Oleksandr Pravdyvyi
348ec65059
Merge branch 'main' into Pravdyvy/key-protocol-update-public-part 2025-09-02 16:11:08 +03:00
Sergio Chouhy
2bcee59d39
Merge pull request #103 from vacp2p/schouhy/implement-nssa-v0.1-private-state
Implement NSSA v0.1 Private State
2025-09-02 06:46:26 -03:00
Oleksandr Pravdyvyi
6efac43210
fix: block interfix 2025-09-02 11:06:41 +03:00
Oleksandr Pravdyvyi
211b6f9115
Merge branch 'Pravdyvy/accounts-dump-fetch' into Pravdyvy/sequencer-update 2025-09-02 10:17:48 +03:00
Oleksandr Pravdyvyi
fbcc9cf3e2
fix: encoding updates 2025-09-02 10:17:00 +03:00
Oleksandr Pravdyvyi
6967c0c22f
fix: update to pr 104 2025-09-02 09:01:33 +03:00
Oleksandr Pravdyvyi
4363a16a62
Merge branch 'Pravdyvy/key-protocol-update-public-part' into Pravdyvy/accounts-dump-fetch 2025-09-02 08:25:00 +03:00
Oleksandr Pravdyvyi
7c42b3de10
fix: lint fix 1 2025-09-02 07:51:49 +03:00
Oleksandr Pravdyvyi
5de28e999e
fix: fmt fix 2025-09-02 07:44:24 +03:00
Oleksandr Pravdyvyi
9993590d45
fix: comments fix 2 2025-09-02 07:32:39 +03:00
Sergio Chouhy
786d0b2899 add tag computation 2025-09-01 18:25:25 -03:00
Oleksandr Pravdyvyi
5c3418ca8e
fix: comments fix 2 2025-09-01 14:17:16 +03:00
Oleksandr Pravdyvyi
22cdce5102
fix: comments fix 2025-09-01 14:06:43 +03:00
Oleksandr Pravdyvyi
ca131b2c26
fix: block structs update 2025-08-28 12:00:04 +03:00
Oleksandr Pravdyvyi
512d96d384
Merge branch 'schouhy/implement-nssa-v0.1-private-state' into Pravdyvy/sequencer-update 2025-08-28 07:39:01 +03:00
Sergio Chouhy
a36592485c remove builtin programs check 2025-08-27 19:25:03 -03:00
Sergio Chouhy
87577726ec add program_id check 2025-08-27 18:31:13 -03:00
Sergio Chouhy
5bd45b685f bump r0 version 2025-08-27 18:02:10 -03:00
Sergio Chouhy
8dbb636a14 add dev mode to ci rust tests 2025-08-27 17:24:59 -03:00
Sergio Chouhy
0a3f093d60 fmt and clippy 2025-08-27 17:22:09 -03:00
Sergio Chouhy
66b5efaacb file refactor 2025-08-27 17:22:03 -03:00
Sergio Chouhy
fd74216249 add commit to kdf 2025-08-26 14:14:08 -03:00
Sergio Chouhy
e508547914 add npk to kdf 2025-08-26 13:50:52 -03:00
Oleksandr Pravdyvyi
f47692773c
fix: merge fix 2025-08-26 14:09:33 +03:00
Oleksandr Pravdyvyi
562480225c
Merge branch 'schouhy/implement-nssa-v0.1-private-state' into Pravdyvy/sequencer-update 2025-08-26 14:06:49 +03:00
Oleksandr Pravdyvyi
ab35d37766
fix: suggestions fix 2025-08-26 09:16:46 +03:00
Sergio Chouhy
d623812c24 remove shared secrete derivation from r0 2025-08-25 17:45:59 -03:00
Sergio Chouhy
20897596b0 add root history 2025-08-25 09:58:02 -03:00
Sergio Chouhy
9ff6a5bc85 fix 2025-08-25 07:57:35 -03:00
Sergio Chouhy
2e371300d3 refactor mt 2025-08-25 07:44:56 -03:00
Sergio Chouhy
f2a7c574e5 fix nonce in circuit 2025-08-22 18:49:46 -03:00
Sergio Chouhy
96ca181f2d implement encryption/decryption of private outputs 2025-08-22 18:11:45 -03:00
Sergio Chouhy
d00c551027 minor refactor 2025-08-22 13:42:37 -03:00
Sergio Chouhy
75211903d7 polish tests 2025-08-22 12:29:45 -03:00
Sergio Chouhy
f7e1b85091 add transition from privacy preserving transaction deshielded 2025-08-22 11:03:10 -03:00
Oleksandr Pravdyvyi
fedf63b759
fix: risk0 bump 2025-08-22 16:36:38 +03:00
Sergio Chouhy
1d2b0bbed7 add test for transition from private transaction 2025-08-22 10:35:01 -03:00
Oleksandr Pravdyvyi
41af90e2eb
fix: tests addded-fixed 2025-08-22 15:58:43 +03:00
Sergio Chouhy
1ca3d68d7e remove serde for nssa::address 2025-08-22 08:53:40 -03:00
Sergio Chouhy
02ad6129d6 refactor merkle tree into file 2025-08-22 08:34:47 -03:00
Sergio Chouhy
79727f0195 refactor circuit module into file 2025-08-22 08:32:05 -03:00
Sergio Chouhy
d53edf7b61 remove unused dep 2025-08-22 08:28:38 -03:00
Sergio Chouhy
48a70cb6e5 Merge branch 'main' into schouhy/implement-nssa-v0.1-private-state 2025-08-22 08:27:19 -03:00
Sergio Chouhy
9b7c2587fe minor changes 2025-08-21 15:52:35 -03:00
Sergio Chouhy
b6cabe8fb8 refactor. Add test for state transition from privacy preserving transaction 2025-08-21 14:32:57 -03:00
Sergio Chouhy
a5dc01d85e improve test to match exact new commitments and new nullifiers 2025-08-21 10:52:52 -03:00
Sergio Chouhy
8a0e2d780a fix test with valid merkle proofs 2025-08-21 10:19:50 -03:00
Oleksandr Pravdyvyi
914cbfb9dc
fix: complete cli intefaces 2025-08-21 15:58:31 +03:00
Sergio Chouhy
6d56ee51db add verification reference impl and tests 2025-08-21 08:11:33 -03:00
Sergio Chouhy
0554500f2f remove vec attribute 2025-08-20 20:25:56 -03:00
Sergio Chouhy
e9fbce2106 add test 2025-08-20 20:02:28 -03:00
Sergio Chouhy
096a404859 add auth paths 2025-08-20 19:57:44 -03:00
Sergio Chouhy
44a4f2f9f3 fix 2025-08-20 19:13:32 -03:00
Sergio Chouhy
b3f6b2756e add extend capacity 2025-08-20 18:26:54 -03:00
Sergio Chouhy
499b23c335 refactor 2025-08-20 16:21:05 -03:00
Sergio Chouhy
c41eb6b517 add with_capacity 2025-08-20 15:27:57 -03:00
Oleksandr Pravdyvyi
612a67f5ed
Merge branch 'main' into Pravdyvy/key-protocol-update-public-part 2025-08-20 17:53:09 +03:00
Pravdyvy
6547d0efb4
Merge pull request #102 from vacp2p/Pravdyvy/structural-improvements
Structural improvements
2025-08-20 17:51:57 +03:00
Oleksandr Pravdyvyi
0c7456d7a0
fix: first batch of wallet methods 2025-08-20 17:16:51 +03:00
Oleksandr Pravdyvyi
0abb23e26a
Merge branch 'Pravdyvy/key-protocol-update-public-part' into Pravdyvy/accounts-dump-fetch 2025-08-20 08:22:47 +03:00
Sergio Chouhy
15e2c131b2 add merkle tests 2025-08-19 16:39:32 -03:00
Sergio Chouhy
ceba630cff merkle tree wip 2025-08-19 15:22:35 -03:00
Sergio Chouhy
8239855e88 add test. refactor 2025-08-19 12:52:52 -03:00
Sergio Chouhy
538bb72556 encapsulate proof 2025-08-19 10:47:24 -03:00
Sergio Chouhy
769e372e8f add test of privacy preserving circuit proof generation 2025-08-19 10:39:47 -03:00
Oleksandr Pravdyvyi
80620b6aac
fix: wallet fix 2025-08-19 14:14:09 +03:00
Oleksandr Pravdyvyi
d2ab8dd4d4
fix: comments fix 2025-08-19 06:41:36 +03:00
Sergio Chouhy
f905e79f4c wip 2025-08-18 19:57:21 -03:00
Sergio Chouhy
562fe2e5e6 wip execute offchain 2025-08-18 18:54:47 -03:00
Sergio Chouhy
330d79379f add message serialization roundtrip test 2025-08-18 14:55:50 -03:00
Sergio Chouhy
a185e52203 add encodings 2025-08-18 14:28:26 -03:00
Sergio Chouhy
1e1ab787bc add nullifier pk from secret 2025-08-18 11:53:43 -03:00
Oleksandr Pravdyvyi
e617cac69c
fix: key proctocol crate updated 2025-08-18 16:15:25 +03:00
Sergio Chouhy
2813d536bb add nullifier constructor 2025-08-18 09:50:11 -03:00
Sergio Chouhy
acbde736f0 wip 2025-08-18 09:21:07 -03:00
Sergio Chouhy
b20a97e5a1 wip 2025-08-18 07:39:41 -03:00
Oleksandr Pravdyvyi
4268830d18
Merge branch 'main' into Pravdyvy/key-protocol-update-public-part 2025-08-15 14:29:05 +03:00
Oleksandr Pravdyvyi
1cdf058938
Merge branch 'main' into Pravdyvy/structural-improvements 2025-08-15 14:28:31 +03:00
Oleksandr Pravdyvyi
35b636a27d
fix: clearing and renaming 2025-08-15 14:27:36 +03:00
Sergio Chouhy
97f69f9498
Merge pull request #100 from vacp2p/schouhy/implement-nssa-v0.1-public-state
Implement NSSA v0.1 Public State
2025-08-15 08:19:59 -03:00
Sergio Chouhy
1a10dade25 add priv preserving tx validation criteria scaffolding 2025-08-14 16:20:09 -03:00
Sergio Chouhy
507988832f add transition_from_privacy_preserving_transaction method and relevant scaffolding 2025-08-14 15:34:21 -03:00
Sergio Chouhy
a694e705ea move claiming accounts logic to state transition 2025-08-14 14:48:20 -03:00
Sergio Chouhy
d1ebb831ef refactor program input 2025-08-14 14:30:04 -03:00
Sergio Chouhy
c5a4e83e3e add pre states to program output 2025-08-14 14:09:04 -03:00
Sergio Chouhy
035f950229 add execute_and_prove 2025-08-14 13:28:23 -03:00
Sergio Chouhy
35ffb65df0 add privacy preserving transaction scaffolding 2025-08-14 12:10:27 -03:00
Oleksandr Pravdyvyi
74f0c983d3
fix: comments fix 2025-08-14 14:03:48 +03:00
Sergio Chouhy
fe06a22589 remove serialize and deserialize from message 2025-08-13 19:24:26 -03:00
Oleksandr Pravdyvyi
6cada5bd09
fix: nonces fix 2025-08-13 16:23:00 +03:00
Oleksandr Pravdyvyi
e589ddae5a
fix: test fix 2 2025-08-13 16:17:52 +03:00
Sergio Chouhy
9d8c74ec1e taplo 2025-08-13 10:01:44 -03:00
Oleksandr Pravdyvyi
d7acffd8da
fix: test fix 1 2025-08-13 15:11:24 +03:00
Oleksandr Pravdyvyi
a9d81b19ed
fix: lints and merge fixes 2025-08-13 14:15:05 +03:00
Oleksandr Pravdyvyi
494cc7fb1e
Merge branch 'Pravdyvy/structural-upgrades' into Pravdyvy/structural-improvements 2025-08-13 13:48:01 +03:00
Oleksandr Pravdyvyi
fed2d50a9a
Revert "fix: AccountAddress wrapped into struct"
This reverts commit 6bced517644b1ab3879aa35d5c4695edb5f3bcb2.
2025-08-13 13:44:41 +03:00
Oleksandr Pravdyvyi
939553cc85
fix: structural upgrades finalized 2025-08-13 13:42:00 +03:00
Sergio Chouhy
490ac908b8 nit 2025-08-13 03:02:32 -03:00
Sergio Chouhy
df78d5f162 fix integration tests 2025-08-13 02:25:19 -03:00
Sergio Chouhy
b22de50107 fmt clippy 2025-08-13 01:59:29 -03:00
Sergio Chouhy
63cca0f30f add tests 2025-08-13 01:55:56 -03:00
Sergio Chouhy
4bdd2c6d9f add try_new test 2025-08-13 01:49:17 -03:00
Sergio Chouhy
2c0c417c22 improve attribute visibility 2025-08-13 01:36:19 -03:00
Sergio Chouhy
504eb00819 refactor tests 2025-08-13 01:33:11 -03:00
Sergio Chouhy
acaf62f31f fmt clippy 2025-08-13 00:51:54 -03:00
Sergio Chouhy
24a3165634 add tests 2025-08-13 00:43:17 -03:00
Sergio Chouhy
d0a1cd5fa0 add tests 2025-08-13 00:15:22 -03:00
Sergio Chouhy
d3827fc823 add tests. refactor 2025-08-12 23:31:41 -03:00
Sergio Chouhy
2d9896f6ed error handling for encoding 2025-08-12 22:50:21 -03:00
Sergio Chouhy
0dcdb2188a refactor. add tests 2025-08-12 21:27:27 -03:00
Sergio Chouhy
b2f79e2965 add all tests 2025-08-12 17:58:48 -03:00
Sergio Chouhy
0b2650127a clippy 2025-08-12 16:56:16 -03:00
Sergio Chouhy
2884fdd00a fmt 2025-08-12 16:48:53 -03:00
Sergio Chouhy
82818db873 fix test 2025-08-12 16:48:32 -03:00
Sergio Chouhy
066aa8f3f7 add test vectors 2025-08-12 16:45:07 -03:00
Sergio Chouhy
927254f6ce add bip340 test vectors for public keys 2025-08-12 15:20:35 -03:00
Sergio Chouhy
e8e565fe8c refactor encoding 2025-08-12 13:10:46 -03:00
Sergio Chouhy
82907f5d8f refactor all 2025-08-12 12:18:13 -03:00
Sergio Chouhy
bab1112251 refactor encoding/decoding for public transactions without serde 2025-08-12 10:16:04 -03:00
Oleksandr Pravdyvyi
6bced51764
fix: AccountAddress wrapped into struct 2025-08-12 14:35:10 +03:00
Sergio Chouhy
a5d0c27d6b fix 2025-08-11 20:38:29 -03:00
Sergio Chouhy
5bc1c9c688 add signatures 2025-08-11 20:22:41 -03:00
Sergio Chouhy
703a127f0e implement public and private keys 2025-08-11 19:14:12 -03:00
Sergio Chouhy
54dd9aa814 minor refactor 2025-08-11 12:07:30 -03:00
Oleksandr Pravdyvyi
f32d7a7daf
Merge branch 'main' into Pravdyvy/accounts-dump-fetch 2025-08-11 15:25:24 +03:00
Sergio Chouhy
96b256bd4c Merge branch 'main' into schouhy/implement-nssa-v0.1-public-state-tmp 2025-08-11 09:08:06 -03:00
Pravdyvy
4581dcc1d1
Merge pull request #99 from vacp2p/Pravdyvy/node-wallet-rewrite
Data storage removal and node refactor.
2025-08-11 14:52:51 +03:00
Oleksandr Pravdyvyi
a3444f0c5c
fix: tests updates 2025-08-11 14:01:13 +03:00
Oleksandr Pravdyvyi
b5011d6b1d
fix: ci fix 1 2025-08-11 10:03:20 +03:00
Oleksandr Pravdyvyi
8727dabe27
fix: merge fixes 2025-08-11 09:05:18 +03:00
Oleksandr Pravdyvyi
56ac4ab982
Merge branch 'Pravdyvy/node-wallet-rewrite' into Pravdyvy/accounts-dump-fetch 2025-08-11 08:59:04 +03:00
Oleksandr Pravdyvyi
c3b5d62ea6
fix: comments fix 2025-08-11 08:55:08 +03:00
Sergio Chouhy
43058193df minor change 2025-08-10 19:53:05 -03:00
Sergio Chouhy
9d19183786 minor refactor 2025-08-10 19:08:18 -03:00
Sergio Chouhy
102d2e13f9 add general instruction data 2025-08-10 18:51:55 -03:00
Sergio Chouhy
48fe6f2740 refactor logic 2025-08-10 14:44:27 -03:00
Sergio Chouhy
15ca5ad4ec refactor public_transaction module into folder 2025-08-10 14:10:11 -03:00
Sergio Chouhy
dacf880b88 add test for balance invariance after program execution 2025-08-10 12:36:11 -03:00
Sergio Chouhy
f86719f54c add test for invalid data modification 2025-08-10 11:17:15 -03:00
Sergio Chouhy
ad47f48a79 add test for invalid balance transfers 2025-08-10 11:02:59 -03:00
Sergio Chouhy
3594c846da add test program owner changer 2025-08-10 10:36:55 -03:00
Sergio Chouhy
a3b64e4021 add test for missing outputs 2025-08-10 10:09:23 -03:00
Sergio Chouhy
ecdb4ba130 add test for extra outputs 2025-08-10 09:57:10 -03:00
Sergio Chouhy
bfdf039ef3 add test folder 2025-08-10 01:27:37 -03:00
Sergio Chouhy
4f7bde100c minor change 2025-08-09 21:14:13 -03:00
Sergio Chouhy
6030e54cd7 refactor program 2025-08-09 20:28:34 -03:00
Sergio Chouhy
51d8ac47cf refactor program 2025-08-09 20:16:18 -03:00
Sergio Chouhy
55e241dc97 add error handling 2025-08-09 19:49:07 -03:00
Sergio Chouhy
04f6474799 clippy 2025-08-09 19:20:19 -03:00
Sergio Chouhy
7d23983309 fix test 2025-08-09 19:13:44 -03:00
Sergio Chouhy
00773d7457 clippy 2025-08-09 18:49:05 -03:00
Sergio Chouhy
fcb90f6f11 clippy 2025-08-09 18:37:04 -03:00
Sergio Chouhy
3188f98117 early returns instead of panicking in program methods 2025-08-09 18:30:34 -03:00
Sergio Chouhy
20a7dad9a0 Merge branch 'Pravdyvy/node-wallet-rewrite' into schouhy/implement-nssa-v0.1-public-state-tmp 2025-08-09 18:00:58 -03:00
Sergio Chouhy
13cc82e3ed remove unnecessary mempoolitem trait 2025-08-08 16:53:15 -03:00
Sergio Chouhy
22c16c1ec9 improve tests function to avoid manual entry of hex string in test 2025-08-08 16:37:20 -03:00
Sergio Chouhy
002ad048b0 refactor programs. Add builtin programs. Implement account claim logic 2025-08-08 16:19:50 -03:00
Sergio Chouhy
3dfcb47534 add tests for default account 2025-08-08 13:32:50 -03:00
Oleksandr Pravdyvyi
dbb276e470
fix: fmt 2025-08-08 17:01:21 +03:00
Sergio Chouhy
ef6af9a967 solve linking problem 2025-08-08 10:51:23 -03:00
Oleksandr Pravdyvyi
c0318de646
fix: restore and dump methods 2025-08-08 15:22:04 +03:00
Oleksandr Pravdyvyi
99640bd70c
feat: dump command 2025-08-08 10:07:10 +03:00
Sergio Chouhy
ec909a1625 adapt sequencer to use nssa 2025-08-07 15:19:06 -03:00
Sergio Chouhy
ae9963aec3 add test 2025-08-07 09:33:54 -03:00
Oleksandr Pravdyvyi
17b6851d00
fix: cleanup 2025-08-07 14:07:34 +03:00
Sergio Chouhy
aba8f3549f public transactions wip 2025-08-06 20:05:04 -03:00
Sergio Chouhy
a06af6da0a nssa basic project structure 2025-08-06 13:39:09 -03:00
Oleksandr Pravdyvyi
c5097ab879
fix: cli added 2025-08-06 14:56:58 +03:00
Oleksandr Pravdyvyi
7be870369c
fix: fmt 2025-08-05 15:44:52 +03:00
Oleksandr Pravdyvyi
4f95cef08f
fix: code cleanup and final removals 2025-08-05 14:59:20 +03:00
Oleksandr Pravdyvyi
6565e0af18
breaking: initial cuts 2025-08-04 15:09:28 +03:00
Pravdyvy
ebec84b3c0
Merge pull request #96 from vacp2p/Pravdyvy/integration-tests
Integration tests
2025-08-04 14:52:25 +03:00
Oleksandr Pravdyvyi
2657e64df8
fix: ci fix 2025-08-04 13:46:41 +03:00
Oleksandr Pravdyvyi
418ce51805
Merge branch 'main' into Pravdyvy/integration-tests 2025-08-04 13:20:54 +03:00
Oleksandr Pravdyvyi
c17160602c
fix: ci try retry 2025-08-04 10:40:08 +03:00
Oleksandr Pravdyvyi
5d42e53b18
fix: comments fix 2025-08-01 18:32:30 +03:00
Sergio Chouhy
7f97340667
Merge pull request #97 from vacp2p/schouhy/prevent-replay-attacks-with-nonces
Prevent replay attacks with nonce mechanism
2025-07-31 16:31:19 -03:00
Oleksandr Pravdyvyi
f5d9990cc8
fix: macro for test functions 2025-07-31 15:41:36 +03:00
Oleksandr Pravdyvyi
7a6a958179
fix: integration tests added 2025-07-31 14:40:23 +03:00
Oleksandr Pravdyvyi
aa142eed07
fix: fmt commit 2025-07-30 14:14:46 +03:00
Oleksandr Pravdyvyi
6df4a04f84
feat: first scenario implemented 2025-07-30 14:01:40 +03:00
Oleksandr Pravdyvyi
28317b6227
Merge branch 'main' into Pravdyvy/integration-tests 2025-07-30 10:10:36 +03:00
Sergio Chouhy
18489be4d1 nit 2025-07-29 16:48:50 -03:00
Sergio Chouhy
c6fb383adf fix increase nonce and add test 2025-07-29 16:42:22 -03:00
Sergio Chouhy
e9b11af986 move nonce to public execution input 2025-07-29 16:09:21 -03:00
Sergio Chouhy
6a38c2eaa2 ad test 2025-07-29 15:41:57 -03:00
Sergio Chouhy
a1d53ee6f0 use tempdir for tests 2025-07-29 15:29:00 -03:00
Sergio Chouhy
6ed4369647 clippy 2025-07-29 15:26:08 -03:00
Sergio Chouhy
4300e87485 refactor address to avoid code repetition in computing addresses from public keys 2025-07-29 15:23:54 -03:00
Sergio Chouhy
76a023c33a remove unused nonce method 2025-07-29 12:51:33 -03:00
Sergio Chouhy
966a5c9a04 Merge branch 'Pravdyvy/state-transition-token-transfer' into schouhy/prevent-replay-attacks-with-nonces
fix test
2025-07-29 12:50:30 -03:00
Pravdyvy
72b5035733
Merge pull request #92 from vacp2p/Pravdyvy/state-transition-token-transfer
State transition for token transfer
2025-07-29 18:32:38 +03:00
Oleksandr Pravdyvyi
e72df20b60
fix: test fix 2025-07-29 15:04:38 +03:00
Oleksandr Pravdyvyi
5d7d6278ee
fix: updates and tests 2025-07-29 14:20:03 +03:00
Sergio Chouhy
f21c0df652 wip: added nonces and test 2025-07-28 16:09:03 -03:00
Sergio Chouhy
484c22b649 Merge branch 'Pravdyvy/state-transition-token-transfer' into schouhy/prevent-replay-attacks-with-nonces 2025-07-28 15:22:19 -03:00
Sergio Chouhy
70b31856e9 wip 2025-07-28 15:21:35 -03:00
Oleksandr Pravdyvyi
d181ce73e6
fix: node and sequencer startup 2025-07-28 16:31:43 +03:00
Oleksandr Pravdyvyi
c546af7865
fix: correct sender check fix 2025-07-25 19:46:23 +03:00
Oleksandr Pravdyvyi
6d947710d1
feat:int test 2025-07-25 19:42:29 +03:00
Oleksandr Pravdyvyi
e0b1ec165c
fix: fmt commit 2025-07-25 10:46:32 +03:00
Oleksandr Pravdyvyi
7695e8e46e
fix: merge fix 2025-07-25 10:09:34 +03:00
Oleksandr Pravdyvyi
3de86d975e
Merge branch 'main' into Pravdyvy/state-transition-token-transfer 2025-07-25 10:04:31 +03:00
Oleksandr Pravdyvyi
d232cecbb0
fix: comments fix 2 2025-07-25 10:00:27 +03:00
Sergio Chouhy
00f1490eff
Merge pull request #95 from vacp2p/schouhy/add-get-transaction-rpc-method
Add get transaction by hash method to RPC server
2025-07-24 15:06:26 -03:00
Oleksandr Pravdyvyi
494ff2ac71
fix: ToDo doc 2025-07-24 17:31:53 +03:00
Oleksandr Pravdyvyi
41b65521f9
fix: comments fix 1 2025-07-24 16:05:27 +03:00
Sergio Chouhy
eaaf485325 Merge branch 'main' into schouhy/add-get-transaction-rpc-method 2025-07-24 10:02:01 -03:00
Sergio Chouhy
8a31522444 Merge branch 'main' into schouhy/add-get-transaction-rpc-method 2025-07-24 08:35:32 -03:00
Sergio Chouhy
6ede7eac16 add TODO 2025-07-24 08:21:20 -03:00
Oleksandr Pravdyvyi
95fec47897
fix: merge lint test fixes 2025-07-24 09:14:38 +03:00
Oleksandr Pravdyvyi
88872f31dd
Merge branch 'main' into Pravdyvy/state-transition-token-transfer 2025-07-24 08:41:34 +03:00
Sergio Chouhy
ef0b659ad1
Merge pull request #94 from vacp2p/schouhy/add-get-account-balance-rpc-method
Add get account balance method to sequencer RPC server
2025-07-23 15:14:49 -03:00
Sergio Chouhy
af6608585c Merge branch 'main' into schouhy/add-get-account-balance-rpc-method 2025-07-23 13:18:12 -03:00
Oleksandr Pravdyvyi
262531799b
Merge branch 'main' into Pravdyvy/state-transition-token-transfer 2025-07-23 19:03:54 +03:00
Pravdyvy
645429d8d8
Merge pull request #78 from vacp2p/schouhy/add-clippy-to-ci
Add clippy to CI
2025-07-23 18:53:18 +03:00
Oleksandr Pravdyvyi
872986926e
fix: merge clippy fix 2025-07-23 17:44:40 +03:00
Oleksandr Pravdyvyi
d9ced25e98
Merge branch 'main' into schouhy/add-clippy-to-ci 2025-07-23 17:41:40 +03:00
Pravdyvy
128b58127b
Merge pull request #91 from vacp2p/schouhy/add-signatures-to-transactions
Add signature validation for transactions in sequencer
2025-07-23 17:36:59 +03:00
Oleksandr Pravdyvyi
dfb28abbe7
fix: ci rerun 2025-07-23 16:12:37 +03:00
Oleksandr Pravdyvyi
8604a672bd
fix: merge fix 2025-07-23 15:53:00 +03:00
Oleksandr Pravdyvyi
0f82c0ec05
Merge branch 'main' into schouhy/add-clippy-to-ci 2025-07-23 15:41:53 +03:00
Oleksandr Pravdyvyi
5b2af29efd
fix: fixes and retrieval methods 2025-07-23 15:16:53 +03:00
Sergio Chouhy
bf139aa634 improve error messages 2025-07-22 13:56:56 -03:00
Sergio Chouhy
db5815ec09 add docstrings 2025-07-22 13:44:52 -03:00
Sergio Chouhy
693aa0c9f7 improve error messages 2025-07-22 13:36:12 -03:00
Sergio Chouhy
3e54156abf improve test so that it covers the map update logic 2025-07-22 13:25:15 -03:00
Sergio Chouhy
5dd7d25762 nit 2025-07-22 12:58:54 -03:00
Sergio Chouhy
98631721fa add test 2025-07-22 12:27:42 -03:00
Sergio Chouhy
c9574b0d09 add test 2025-07-22 11:13:19 -03:00
Sergio Chouhy
1afb77e63e use correct rpc error 2025-07-22 10:37:04 -03:00
Sergio Chouhy
13536e69af add test 2025-07-22 10:34:57 -03:00
Sergio Chouhy
9d85ea234e add get transaction by hash rpc method 2025-07-22 10:23:52 -03:00
Oleksandr Pravdyvyi
9f8724ee4c
feat: native token transactions 2 2025-07-22 15:22:20 +03:00
Sergio Chouhy
cab71a0e00 return parse error for invalid addresses 2025-07-22 09:13:41 -03:00
Sergio Chouhy
d1cd653ed5 fmt 2025-07-22 08:45:47 -03:00
Sergio Chouhy
f3aaacb6ca add get_balance rpc method 2025-07-22 08:40:04 -03:00
Oleksandr Pravdyvyi
3eee533a17
Merge branch 'schouhy/add-signatures-to-transactions' into Pravdyvy/state-transition-token-transfer 2025-07-22 12:27:35 +03:00
Sergio Chouhy
5de28c062e remove usage of prehash sinc it is hazard material. Prefer use of secure api 2025-07-21 21:07:16 -03:00
Sergio Chouhy
71fdce8050 remove unused dependencies 2025-07-21 19:13:43 -03:00
Sergio Chouhy
361e3b6f76 fmt 2025-07-21 19:08:47 -03:00
Sergio Chouhy
b3323c78cf clippy 2025-07-21 18:46:50 -03:00
Sergio Chouhy
a6cb55221b Merge branch 'main' into schouhy/add-signatures-to-transactions 2025-07-21 17:58:02 -03:00
Sergio Chouhy
39b4c866a1 fix double-hashing bug 2025-07-21 17:50:08 -03:00
Sergio Chouhy
4580812b64
Merge pull request #89 from vacp2p/schouhy/remove-precomputed-hash-from-transaction
Remove precomputed hash from Transaction
2025-07-21 14:41:44 -03:00
Oleksandr Pravdyvyi
5e3476673e
fix: build substraction 2025-07-21 12:48:22 +03:00
Oleksandr Pravdyvyi
ca3a63a885
fix: ci update test 2025-07-21 11:46:01 +03:00
Oleksandr Pravdyvyi
59501f2ca5
fix: run retry 2025-07-18 15:36:01 +03:00
Oleksandr Pravdyvyi
9646152550
fix: more lints fix 2025-07-18 14:07:06 +03:00
Pravdyvy
7d11c95be8
Update lint-ubuntu.sh 2025-07-18 12:36:53 +03:00
Oleksandr Pravdyvyi
140a051fc9 Merge branch 'main' into Pravdyvy/state-transition-token-transfer 2025-07-18 12:35:34 +03:00
Oleksandr Pravdyvyi
3bc2f6aba7 fix: refetch 2025-07-18 12:29:32 +03:00
Oleksandr Pravdyvyi
eb16534ad9 fix: fmt 2025-07-18 11:25:50 +03:00
Oleksandr Pravdyvyi
b9d3f921e9 fix: latest lint fixes 2025-07-18 11:13:45 +03:00
Oleksandr Pravdyvyi
1c4ec47f1a Merge branch 'main' into schouhy/add-clippy-to-ci 2025-07-18 10:11:50 +03:00
Sergio Chouhy
6d5e2a1a9f change variable name 2025-07-17 08:36:46 -03:00
Sergio Chouhy
5b49156a5f Merge branch 'main' into schouhy/remove-precomputed-hash-from-transaction 2025-07-17 08:17:32 -03:00
Sergio Chouhy
a4deb42d3d Merge branch 'main' into schouhy/add-signatures-to-transactions 2025-07-17 08:09:46 -03:00
Pravdyvy
103804683d
Merge pull request #86 from vacp2p/Pravdyvy/utxo-nullifier-fix
UTXO nullifier calculation fix and circuits updates
2025-07-17 13:48:49 +03:00
Pravdyvy
50fed7ae42
Merge pull request #88 from vacp2p/Pravdyvy/sequencer-account-store-modifications
SequencerAccountsStore updates
2025-07-17 13:46:57 +03:00
Pravdyvy
da7285856c
Merge pull request #87 from vacp2p/zkvm_tests
Zkvm tests
2025-07-17 13:46:25 +03:00
Oleksandr Pravdyvyi
de8462803d fix: api rate limit refetch 2025-07-17 11:51:46 +03:00
Oleksandr Pravdyvyi
9097762a53 feat: node side of public native token transfer 1 2025-07-17 11:47:38 +03:00
Pravdyvy
9954f8e0da
Update Cargo.toml 2025-07-17 09:04:24 +03:00
Pravdyvy
085d7b4c95
Update Cargo.toml 2025-07-17 09:04:00 +03:00
Pravdyvy
d1a7b03b55
Update Cargo.toml 2025-07-17 09:02:27 +03:00
Pravdyvy
14da838637
Update Cargo.toml 2025-07-17 09:01:26 +03:00
Pravdyvy
0211ff78e1
Update Cargo.toml 2025-07-17 08:56:11 +03:00
Oleksandr Pravdyvyi
8b6769d7e8 fix: comments fix 2 2025-07-17 08:22:04 +03:00
Oleksandr Pravdyvyi
00532b564b fix: comments fix 1 2025-07-17 08:09:27 +03:00
Oleksandr Pravdyvyi
19de364958 fix: zkvm version bump 2025-07-17 07:53:03 +03:00
Sergio Chouhy
91ca3af477
Merge pull request #93 from vacp2p/schouhy-add-mit-license
Add MIT LICENSE
2025-07-16 17:50:47 -03:00
Sergio Chouhy
079b343981 remove unused hash parameter in dummy function 2025-07-16 13:51:13 -03:00
Sergio Chouhy
c60c7235c1 add getter for transaction body and test it 2025-07-16 13:30:30 -03:00
Sergio Chouhy
e79c30f765 add test for signing key getter 2025-07-16 13:30:30 -03:00
Sergio Chouhy
b6ea00daa4 add transactions tests 2025-07-16 13:30:30 -03:00
Sergio Chouhy
ab06501e04 rename scenarios 2025-07-16 13:30:30 -03:00
Sergio Chouhy
8b1d3b478c minor refactor 2025-07-16 13:30:30 -03:00
Sergio Chouhy
b1724ec235 move mempool checks outside transaction check function 2025-07-16 13:30:30 -03:00
Sergio Chouhy
1ef7be0af6 add pem feature to k256 and remove manual impls of Serialize and Deserialize 2025-07-16 13:30:28 -03:00
Sergio Chouhy
e7b727c0ba make sequencer validate transaction signatures before adding transactions to blocks 2025-07-16 13:30:28 -03:00
Sergio Chouhy
6e48bcfd9e sign transactions from node's end 2025-07-16 13:30:24 -03:00
Sergio Chouhy
f02c97e622 rename structs. Implement serde for AuthenticatedTransaction 2025-07-16 13:30:24 -03:00
Sergio Chouhy
a174eb4b85 add un/verified signed transaction structs 2025-07-16 13:30:18 -03:00
Sergio Chouhy
f0c8e19e64
Create MIT LICENSE 2025-07-16 10:38:59 -03:00
Oleksandr Pravdyvyi
14b35a93c0 feat: new public transaction kind 2025-07-16 12:31:47 +03:00
Oleksandr Pravdyvyi
38b57df883 fix: rate limit refetch 2025-07-16 08:18:44 +03:00
Oleksandr Pravdyvyi
eee7cc1397 fix: comments fix 2025-07-16 08:10:49 +03:00
Oleksandr Pravdyvyi
90205c6330 fix: account masks updates to safe state 2025-07-15 12:49:19 +03:00
Oleksandr Pravdyvyi
2078867d7b Merge branch 'schouhy/update-risc0-version' into Pravdyvy/utxo-nullifier-fix 2025-07-15 12:33:43 +03:00
Oleksandr Pravdyvyi
a24a40f4bc fix: docs added 2025-07-14 13:25:40 +03:00
Oleksandr Pravdyvyi
5f4d6c0f8d fix: additional test with other accounts 2025-07-14 13:17:46 +03:00
Oleksandr Pravdyvyi
a43a32fc55 feat: initial accounts configuration 2025-07-14 10:43:35 +03:00
Moudy
d76358c37f
Update README.md 2025-07-13 23:12:31 +02:00
Oleksandr Pravdyvyi
5e9c6a0677 feat: preset accounts in sequencer account store 2025-07-11 10:34:13 +03:00
Oleksandr Pravdyvyi
b115313955 Merge branch 'schouhy/update-risc0-version' into Pravdyvy/sequencer-account-store-modifications 2025-07-11 07:52:53 +03:00
Sergio Chouhy
b49f38ca4b avoid computing hash multiple times in transaction_pre_check 2025-07-10 14:35:41 -03:00
Sergio Chouhy
e79261a566 Merge branch 'schouhy/update-risc0-version' into schouhy/remove-precomputed-hash-from-transaction 2025-07-10 14:16:55 -03:00
Sergio Chouhy
1d4548fb3b bump risc0 version to 2.2 2025-07-10 14:15:07 -03:00
Sergio Chouhy
e286108bb5 add TODO to remove unwrap 2025-07-10 13:00:27 -03:00
Sergio Chouhy
81b6d34693 add Transaction::hash inline docs 2025-07-10 12:52:48 -03:00
Sergio Chouhy
b16575b407 fmt 2025-07-10 12:16:05 -03:00
Sergio Chouhy
f01be72d8f move impl of hash to existing impl Transaction block 2025-07-10 12:15:37 -03:00
Sergio Chouhy
e1e018fcfc remove redundant TransactionPayload struct 2025-07-10 12:13:36 -03:00
Sergio Chouhy
16e3a682fe add test for hash function 2025-07-10 12:09:01 -03:00
Sergio Chouhy
789dec673e remove hash attribute from Transaction and use a method instead 2025-07-10 11:35:46 -03:00
Oleksandr Pravdyvyi
54284be74b fix: account data public only for sequencer 2025-07-09 16:03:30 +03:00
Oleksandr Pravdyvyi
8e987847ee feat: AccountPublicData struct changed 2025-07-09 08:16:12 +03:00
Rostyslav Tyshko
28005ae633 fmt 2025-06-26 23:18:30 -04:00
Rostyslav Tyshko
b31f753c11 add test_prove_send_utxo_multiple_assets_one_receiver 2025-06-26 23:18:18 -04:00
Rostyslav Tyshko
a5c8e5125c add test_prove_send_utxo_shielded 2025-06-26 23:17:58 -04:00
Rostyslav Tyshko
553e37b701 add test_prove_send_utxo_deshielded 2025-06-26 23:17:34 -04:00
Rostyslav Tyshko
90231f76cc add test_prove_send_utxo 2025-06-26 23:17:14 -04:00
Rostyslav Tyshko
d9696e77eb add test_prove_mint_utxo 2025-06-26 23:16:56 -04:00
Rostyslav Tyshko
d0c5040fe9 add test_execute_mint_utxo 2025-06-26 23:16:37 -04:00
Rostyslav Tyshko
eb14d632d9 add test_gas_limits_check_insufficient_funds 2025-06-26 23:15:45 -04:00
Rostyslav Tyshko
2fadf0c82f add test_gas_limits_check_sufficient_funds 2025-06-26 23:15:14 -04:00
Rostyslav Tyshko
c1aa0d0004 fix unused results 2025-06-26 22:19:10 -04:00
Oleksandr Pravdyvyi
5d5dde33b7 fix: utxo nullifier calculation fix and circuits updates 2025-06-26 07:21:31 +03:00
tyshko-rostyslav
5172a95f53
Merge pull request #85 from vacp2p/schouhy/add-pr-template
Add PR template
2025-06-20 07:09:53 +02:00
Sergio Chouhy
352c97f25c update with suggestions 2025-06-19 09:20:44 -03:00
Oleksandr Pravdyvyi
3f9d671fb1 fix: lint fix probably latest 2025-06-18 17:26:57 +03:00
Oleksandr Pravdyvyi
ac697c0bd8 fix: lint fix 5 2025-06-18 16:59:29 +03:00
Oleksandr Pravdyvyi
48a43eb268 fix: lint fix 4 2025-06-18 15:58:15 +03:00
Sergio Chouhy
a870650faf add how to test 2025-06-18 09:26:58 -03:00
Sergio Chouhy
7fd44d0247 add PR template 2025-06-18 09:20:41 -03:00
Oleksandr Pravdyvyi
f9eee73ef4 fix: lint fix 3 2025-06-18 14:52:02 +03:00
Oleksandr Pravdyvyi
f491266105 fix: lint fix 2 2025-06-18 14:32:30 +03:00
Oleksandr Pravdyvyi
cdd1bdbfbd fix: lints fix 2025-06-18 13:56:09 +03:00
Oleksandr Pravdyvyi
411d8e9034 Merge branch 'main' into Pravdyvy/lints-fix 2025-06-18 12:44:09 +03:00
tyshko-rostyslav
e826fc4a31
Merge pull request #82 from vacp2p/start_from_block
Start from snapshot block
2025-06-18 11:35:24 +02:00
Rostyslav Tyshko
5e3fd4bbf8 update risc0 version 2025-06-11 02:08:36 -04:00
Rostyslav Tyshko
adb802f28e redundunt 2025-06-11 01:46:35 -04:00
Rostyslav Tyshko
31722b2f72 fmt 2025-06-11 01:25:47 -04:00
Rostyslav Tyshko
a65dcd518d add test_new_recovers_from_snapshot 2025-06-11 01:23:28 -04:00
Rostyslav Tyshko
b62821cb74 add test_new_initializes_correctly 2025-06-11 01:23:12 -04:00
Rostyslav Tyshko
62f06582ef AccMap struct for HashMap<[u8;32], Account>, serialization 2025-06-11 01:22:48 -04:00
Rostyslav Tyshko
222b0136bf AccountForSerialization struct for Account serialization 2025-06-11 01:20:46 -04:00
Rostyslav Tyshko
720263ae2d fix after merge 2025-06-10 01:39:11 -04:00
Rostyslav Tyshko
b77289937f Merge branch 'main' into start_from_block 2025-06-10 01:33:19 -04:00
tyshko-rostyslav
bf4097aa60
Merge pull request #81 from vacp2p/Pravdyvyi/periodic-snapshots-storing
Periodic snapshooting
2025-06-10 07:17:23 +02:00
Rostyslav Tyshko
d755a529ef fmt 2025-05-30 16:19:54 -04:00
Rostyslav Tyshko
79d8bfb864 fix test_open_db_restart 2025-05-30 16:19:40 -04:00
Rostyslav Tyshko
b57d6f5d21 rm test for useless case 2025-05-30 15:58:57 -04:00
Rostyslav Tyshko
baf43f9780 fix build CI 2025-05-30 15:38:48 -04:00
Rostyslav Tyshko
4d7cda0001 Merge branch 'main' into start_from_block 2025-05-30 15:28:31 -04:00
Rostyslav Tyshko
0c9bbb5dde fmt 2025-05-30 15:25:21 -04:00
Rostyslav Tyshko
9cd81c62eb fix start_from_config_update_chain fn 2025-05-30 15:25:02 -04:00
Rostyslav Tyshko
9609595525 fix NodeChainStore's new fn according to snapshoting logic 2025-05-30 15:24:40 -04:00
Rostyslav Tyshko
6a351419d6 imports 2025-05-30 15:24:06 -04:00
Rostyslav Tyshko
a9f8dff7e9 same 2025-05-30 15:23:55 -04:00
Rostyslav Tyshko
9b8ddb0580 add deserialization of nullifier and transaction from snapshot 2025-05-30 15:23:41 -04:00
Rostyslav Tyshko
87e6363686 addblock id getter, deserialization of account and commintmant from snapshot 2025-05-30 15:23:09 -04:00
Rostyslav Tyshko
88da732d5c clear out situation when one tries to start a DB without a block 2025-05-30 15:22:15 -04:00
Rostyslav Tyshko
13d8c72a82 serialize/deserialize TopSecretKeyHolder and UTXOSecretKeyHolder 2025-05-30 15:20:52 -04:00
Rostyslav Tyshko
fe79365c63 serialize/deserialize AddressKeyHolder 2025-05-30 15:20:29 -04:00
Rostyslav Tyshko
5e9499873d serialize/deserialize Account 2025-05-30 15:20:14 -04:00
Oleksandr Pravdyvyi
8cbb8089fb fix: suggestion added 2 2025-05-30 19:26:59 +03:00
Oleksandr Pravdyvyi
5df8763166 fix: suggestion added 1 2025-05-30 14:08:06 +03:00
tyshko-rostyslav
6a5ec2d953
Merge pull request #77 from vacp2p/schouhy/update-utxo-crate-3-add-randomness
3/3 Update utxo crate: Add randomness to UTXO
2025-05-30 08:45:39 +02:00
Oleksandr Pravdyvyi
7e47ecd91e fix: warn fix 2025-05-30 09:29:56 +03:00
Oleksandr Pravdyvyi
894ba19345 fix: fmt 2025-05-30 09:06:39 +03:00
Oleksandr Pravdyvyi
9d3bda9bce fix: fmt 2025-05-30 08:50:35 +03:00
Sergio Chouhy
014cbc3c4d Merge branch 'main' into schouhy/update-utxo-crate-3-add-randomness 2025-05-29 11:06:24 -03:00
Oleksandr Pravdyvyi
66def746e6 feat: periodic snapshooting 2025-05-29 12:00:50 +03:00
Pravdyvy
0d577da288
Merge pull request #73 from vacp2p/Pravdyvy/sparse-merkle-tree-storage-preparation
Sparse Merkle Tree -> HashSet Migration
2025-05-28 21:17:40 +03:00
Oleksandr Pravdyvyi
9ad013253a fix: suggestions added 2 2025-05-28 20:32:43 +03:00
tyshko-rostyslav
81ae388ac4
Merge pull request #74 from vacp2p/storage-merkle-tree-preparation
Hash Storage merkle tree serialization
2025-05-28 07:29:34 +02:00
tyshko-rostyslav
880c0e6802
Merge pull request #80 from vacp2p/snapshhot_preparation
DB Snapshot preparation
2025-05-28 07:26:18 +02:00
Oleksandr Pravdyvyi
8d3ee36392 fix: suggersion added 1 2025-05-28 08:23:54 +03:00
Rostyslav Tyshko
a642946665 add asserts to test 2025-05-28 01:05:44 -04:00
tyshko-rostyslav
895c6490bb
Merge pull request #76 from vacp2p/schouhy/update-utxo-crate-2-remove-nullifier-attribute
2/3 Update utxo crate: Remove nullifier attribute from UTXO
2025-05-27 07:04:50 +02:00
Rostyslav Tyshko
0b1a1c03dc fmt 2025-05-23 15:51:31 -04:00
Rostyslav Tyshko
b69969942a add out fn for transaction, nullifier and account 2025-05-23 15:51:21 -04:00
Rostyslav Tyshko
c71e1b9f8b add out fn for block_id and commitment 2025-05-23 15:50:51 -04:00
Rostyslav Tyshko
611436a943 add getters for account 2025-05-23 15:50:16 -04:00
Rostyslav Tyshko
ee26147dde add getters for transaction and nullifier 2025-05-23 15:49:59 -04:00
Rostyslav Tyshko
4350b69a18 add getters for block_id and commitment 2025-05-23 15:49:27 -04:00
Rostyslav Tyshko
caaa6108d8 add handle for snapshot 2025-05-23 15:48:09 -04:00
Rostyslav Tyshko
a53e8f708c fix destroy fn 2025-05-23 15:47:51 -04:00
Rostyslav Tyshko
d9e82f4ffc fix new fn 2025-05-23 15:47:39 -04:00
Rostyslav Tyshko
b89dcb7fca add new db keys 2025-05-23 15:47:20 -04:00
Rostyslav Tyshko
e94173aa12 add new column family 2025-05-23 15:46:52 -04:00
Oleksandr Pravdyvyi
958e1dcb9c fix: tests fix 2025-05-23 09:10:34 +03:00
Oleksandr Pravdyvyi
9bf0ec9de7 fix: fmt 2025-05-23 09:07:53 +03:00
Oleksandr Pravdyvyi
cb22a95df2 fix: smt/imt replaced with sets 2025-05-23 09:04:04 +03:00
Oleksandr Pravdyvyi
00297db3ab feat: indexed tree migration 1 2025-05-22 00:13:17 +03:00
Oleksandr Pravdyvyi
00fe02c1d1 fix: merge updates 2025-05-21 08:34:03 +03:00
Oleksandr Pravdyvyi
77062e2e4e Merge branch 'main' into Pravdyvy/sparse-merkle-tree-storage-preparation 2025-05-21 08:31:15 +03:00
tyshko-rostyslav
f33c2f14e5
Merge pull request #75 from vacp2p/schouhy/update-utxo-crate-1-remove-utxo-tree
1/3 Update utxo crate: Remove UTXO Tree
2025-05-20 13:36:44 +02:00
tyshko-rostyslav
e6184e4bd8
Merge pull request #67 from vacp2p/schouhy/fix-shared-key-derivation
Fix AES key derivation for encryption / decryption
2025-05-20 13:36:27 +02:00
Sergio Chouhy
f8c925c265 add clippy to CI 2025-05-17 18:10:57 -03:00
Sergio Chouhy
da5a0c8749 clippy 2025-05-17 17:01:50 -03:00
Sergio Chouhy
ecaa6874ce fix imports 2025-05-17 17:00:41 -03:00
Sergio Chouhy
67422a5cd8 fmt 2025-05-16 22:33:38 -03:00
Sergio Chouhy
81f0cf72ae fix unused imports 2025-05-16 22:25:28 -03:00
Sergio Chouhy
ef5d026074 fix tests 2025-05-16 22:23:35 -03:00
Sergio Chouhy
b6700f8adb fmt 2025-05-16 22:21:43 -03:00
Sergio Chouhy
efcd797648 fmt 2025-05-16 22:07:34 -03:00
Sergio Chouhy
f4b9aaffef Remove nullifier attribute 2025-05-16 22:07:34 -03:00
Sergio Chouhy
6aa6c9d34f fmt 2025-05-16 22:06:06 -03:00
Sergio Chouhy
1490b51f71 add randomness to UTXO 2025-05-16 21:55:25 -03:00
Sergio Chouhy
4524177931 fmt 2025-05-16 20:54:11 -03:00
Sergio Chouhy
f1643492bc Remove nullifier attribute 2025-05-16 20:46:55 -03:00
Sergio Chouhy
b565c65628 fmt 2025-05-16 20:46:40 -03:00
Sergio Chouhy
c6a4a00fda remove utxo tree 2025-05-16 20:25:23 -03:00
Rostyslav Tyshko
4ba4c12a87 rm unused 2025-05-16 19:16:45 -04:00
Sergio Chouhy
f50ef5be9a wip 2025-05-16 19:59:51 -03:00
Rostyslav Tyshko
b4c0fb9351 fmt 2025-05-16 18:40:45 -04:00
Rostyslav Tyshko
2346f06d23 add a test 2025-05-16 18:39:39 -04:00
Rostyslav Tyshko
cdb8e3a08a impleDeserialize for HashStorageMerkleTree 2025-05-16 18:39:24 -04:00
Rostyslav Tyshko
9df2b51813 imple Visitor for HashStorageMerkleTreeDeserializer 2025-05-16 18:38:36 -04:00
Rostyslav Tyshko
0daffaf4ad HashStorageMerkleTreeDeserializer 2025-05-16 18:37:58 -04:00
Rostyslav Tyshko
96dc9bd840 serialize for HashStorageMerkleTree 2025-05-16 18:37:38 -04:00
Oleksandr Pravdyvyi
cde9f0a5c8 feat: sparse trees preparation for serialization 2025-05-15 11:38:37 +03:00
tyshko-rostyslav
25ef949a97
Merge pull request #63 from vacp2p/Pravdyvyi/issue-fix
Various qol and fixes
2025-05-08 17:04:16 +02:00
tyshko-rostyslav
7b2c22f0ba
Merge pull request #62 from vacp2p/schouhy/fix-register-account
Fix register account method
2025-05-08 16:52:11 +02:00
Sergio Chouhy
74d8fd54d9 fix tests 2025-05-07 16:52:08 -03:00
Sergio Chouhy
7572188ab0 fmt 2025-05-07 16:37:03 -03:00
Sergio Chouhy
7a117150ef remove usage of deprecated function 2025-05-07 16:36:30 -03:00
Sergio Chouhy
837cc31a93 use x coordinate as key for aes 2025-05-07 16:34:52 -03:00
Oleksandr Pravdyvyi
aa88d1c8f4 fix: fmt fix 2025-04-25 09:08:43 +03:00
Oleksandr Pravdyvyi
456016959a fix: warning fix 2025-04-25 08:48:30 +03:00
Oleksandr Pravdyvyi
825e80a5a0 fix: issue fix 2025-04-24 15:51:34 +03:00
Sergio Chouhy
7760b95a41 Fix register account method 2025-04-23 11:26:47 -03:00
Oleksandr Pravdyvyi
73d0f75844 Merge branch 'main' into Pravdyvyi/issue-fix 2025-04-23 10:09:14 +03:00
tyshko-rostyslav
a9b7f061fe
Merge pull request #60 from vacp2p/refactor-cont
Refactor continued
2025-04-23 08:56:46 +02:00
tyshko-rostyslav
72bf31a828
Merge pull request #59 from vacp2p/Pravdyvy/refactor-1
Storage primitives split
2025-04-23 08:56:24 +02:00
Oleksandr Pravdyvyi
a959ff78c9 fix: eph key deser fix 2025-04-23 09:27:06 +03:00
Rostyslav Tyshko
257044b210 fmt 2025-04-18 11:45:01 -04:00
Rostyslav Tyshko
92b9fe252a fix ci scripts 2025-04-18 08:17:56 -04:00
Rostyslav Tyshko
9f5ac1af94 add env file 2025-04-18 08:17:46 -04:00
Rostyslav Tyshko
b85633fa6e fix const use 2025-04-18 08:17:40 -04:00
Rostyslav Tyshko
35cc38a947 nullifier and viewing consts 2025-04-18 08:17:28 -04:00
Rostyslav Tyshko
bcef0650dc add lazy_static to toml file 2025-04-18 08:16:56 -04:00
Rostyslav Tyshko
1a33d464f0 rm unused 2025-04-18 08:16:26 -04:00
Rostyslav Tyshko
56bb3dba6a fix public context rs 2025-04-18 08:16:13 -04:00
Rostyslav Tyshko
4f86b3cd31 fix process rs node rs 2025-04-18 08:15:46 -04:00
Rostyslav Tyshko
c27be69d92 rm unused 2025-04-18 08:15:29 -04:00
Rostyslav Tyshko
d48924ed01 rm unused 2025-04-18 08:15:21 -04:00
Rostyslav Tyshko
3921841630 fix net_utils rs 2025-04-18 08:15:11 -04:00
Rostyslav Tyshko
c617fcc6e4 fix process rs 2025-04-18 08:14:57 -04:00
Rostyslav Tyshko
93ef263c5e leftover 2025-04-18 08:14:43 -04:00
Rostyslav Tyshko
e09735a3c2 fix rust_log 2025-04-18 08:14:31 -04:00
Rostyslav Tyshko
c6b784266b rm parse rs 2025-04-18 08:14:18 -04:00
Rostyslav Tyshko
7336ccb660 rm core primitives 2025-04-18 08:14:09 -04:00
tyshko-rostyslav
373e3b953d
Merge pull request #57 from vacp2p/provability
Implementation of Public State Provability
2025-04-16 12:27:31 -04:00
tyshko-rostyslav
e430c02c7f
Merge pull request #58 from vacp2p/Pravdyvy/deterministic-serilization-of-context-fix
Deterministic serialization of public sc context
2025-04-16 12:27:19 -04:00
Oleksandr Pravdyvyi
8e4956891c fix: refactor 1 2025-04-16 16:17:53 +03:00
Oleksandr Pravdyvyi
46361868ed fix: additional tests for context serialization 2025-04-14 01:50:44 +03:00
Oleksandr Pravdyvyi
80192ea42a fix: PublicSCContext stable serialization 2025-04-10 15:57:33 +03:00
Rostyslav Tyshko
7b82c5b00c fmt 2025-04-09 02:20:27 -04:00
Rostyslav Tyshko
e75db3b73d fix tests 2025-04-09 02:03:01 -04:00
Rostyslav Tyshko
b3d96d8b53 taplo 2025-04-09 02:01:18 -04:00
Rostyslav Tyshko
0db4a60399 lint 2025-04-09 01:38:57 -04:00
Rostyslav Tyshko
bc99026521 fmt 2025-04-09 01:38:22 -04:00
Rostyslav Tyshko
2779e2e18c style 2025-04-09 01:38:02 -04:00
Rostyslav Tyshko
0b37cb6634 split_utxo add commitments 2025-04-09 01:36:44 -04:00
Rostyslav Tyshko
cce349ff15 transfer_utxo_deshielded add commitments 2025-04-09 01:36:23 -04:00
Rostyslav Tyshko
9f5276a497 transfer_balance_shielded add commitments 2025-04-09 01:36:07 -04:00
Rostyslav Tyshko
e9a2cf361d transfer_utxo_multiple_assets_private add commitments 2025-04-09 01:35:44 -04:00
Rostyslav Tyshko
8a4606f5d3 transfer_utxo_private add commitments 2025-04-09 01:35:19 -04:00
Rostyslav Tyshko
e7249002e5 mint_utxo_multiple_assets_private add commitments 2025-04-09 01:34:57 -04:00
Rostyslav Tyshko
7a57b4f51c vec_u8_to_vec_u64 helper 2025-04-09 01:34:21 -04:00
Rostyslav Tyshko
10e779c1e9 mint_utxo_private commitments 2025-04-09 01:34:03 -04:00
Rostyslav Tyshko
3d56c52291 lock file 2025-04-09 01:33:27 -04:00
Rostyslav Tyshko
def10dea18 serialiaze AccountPublicMask 2025-04-09 01:33:20 -04:00
Rostyslav Tyshko
8b811ae65f add dependency to core_primitives 2025-04-09 01:33:09 -04:00
Rostyslav Tyshko
94493d1051 fix core primitives 2025-04-09 01:32:57 -04:00
Rostyslav Tyshko
593235a09f add dependency to sequencer_core 2025-04-09 01:32:34 -04:00
Rostyslav Tyshko
6447545ec4 serialiaze PublicSCContext 2025-04-09 01:32:16 -04:00
Rostyslav Tyshko
d6b6d92122 add dependency to storage 2025-04-09 01:31:52 -04:00
Rostyslav Tyshko
ded84933b2 get_sc_sc_state for NodeBlockStore 2025-04-09 01:31:39 -04:00
Rostyslav Tyshko
aa93d26b80 function to create pedersen commitments for multiple values 2025-04-09 01:31:20 -04:00
Rostyslav Tyshko
31655f2c35 function to create pedersen commitments 2025-04-09 01:31:05 -04:00
Rostyslav Tyshko
97aeb48109 rpc error pushthrough 2025-04-09 01:30:26 -04:00
Rostyslav Tyshko
bbb84cd849 add new type of error, since we have a new interaction 2025-04-09 01:30:10 -04:00
Rostyslav Tyshko
0113925b92 fix rtansaction for tests 2025-04-09 01:29:35 -04:00
Rostyslav Tyshko
250dec1ae6 fix transaction payload 2025-04-09 01:29:19 -04:00
Rostyslav Tyshko
8fc244b271 add pedersen commitments to Transaction and TransactionPayload struct 2025-04-09 01:28:56 -04:00
tyshko-rostyslav
bfe39185fa
Merge pull request #56 from vacp2p/serde_json_vs_group_encoding
`serde_json` instead of `GroupEncoding` serialization
2025-04-08 14:25:09 -04:00
tyshko-rostyslav
45555782c6
Merge pull request #55 from vacp2p/Pravdyvyi/sc-public-context
Smart contract public context
2025-04-08 14:24:56 -04:00
tyshko-rostyslav
a893cce2f7
Merge pull request #54 from vacp2p/bug-fix-sc-storage
SC public stage storage testing
2025-04-08 14:23:41 -04:00
tyshko-rostyslav
df57293ebb
Merge pull request #53 from vacp2p/Pravdyvy/db-sc-public-data-storage
Smart contract public state storage in DB
2025-04-08 14:23:24 -04:00
Rostyslav Tyshko
33934f1e05 fmt 2025-04-04 15:23:19 -04:00
Rostyslav Tyshko
a9bd1a1a5c replace serilization in sequencer 2025-04-04 15:02:12 -04:00
Rostyslav Tyshko
6066554a7a replace serilization in key_management secret holder 2025-04-04 15:02:03 -04:00
Rostyslav Tyshko
59e6ee8240 replace serilization in key_management ephm key holder 2025-04-04 14:56:30 -04:00
Rostyslav Tyshko
2f3a6ab921 replace serilization in key_management 2025-04-04 14:55:50 -04:00
Rostyslav Tyshko
bd35f5e025 fix log 2025-04-04 14:39:37 -04:00
Rostyslav Tyshko
a1ba0894d9 build fix 2025-04-04 14:39:27 -04:00
Rostyslav Tyshko
4b0666c617 fmt 2025-04-04 14:14:04 -04:00
Rostyslav Tyshko
ef3125b48e fix eph_key_compressed AffinePoint serialization 2025-04-04 14:13:51 -04:00
Rostyslav Tyshko
691bc1d4e6 change serialization in node core lib rs 2025-04-04 14:12:46 -04:00
Oleksandr Pravdyvyi
88c30645e7 fix: warning fix 2025-04-04 13:01:41 +03:00
Oleksandr Pravdyvyi
0b1df5b3d5 fix: public context structure added 2025-04-04 12:11:54 +03:00
Rostyslav Tyshko
4ff5fe895b fix bug 2025-04-03 18:37:36 -04:00
Rostyslav Tyshko
ae5645251d add test_compare_blob_lists_modified 2025-04-03 18:37:23 -04:00
Rostyslav Tyshko
6b302a051f add test_compare_blob_lists_deleted 2025-04-03 18:37:05 -04:00
Rostyslav Tyshko
2aec310c1e add test_compare_blob_lists_created 2025-04-03 18:36:44 -04:00
Rostyslav Tyshko
dc1f975f13 add test_produce_blob_list_from_sc_public_state 2025-04-03 18:36:24 -04:00
Rostyslav Tyshko
5b2098c9f7 add test_produce_blob_from_fit_vec_panic 2025-04-03 18:36:06 -04:00
Rostyslav Tyshko
4193094232 add test_produce_blob_from_fit_vec 2025-04-03 18:35:41 -04:00
Oleksandr Pravdyvyi
d84a134904 fix: merge fix 2025-04-03 10:36:38 +03:00
Oleksandr Pravdyvyi
a05cde7256 Merge branch 'main' into Pravdyvy/db-sc-public-data-storage 2025-04-03 10:34:32 +03:00
tyshko-rostyslav
ea20f0be48
Merge pull request #52 from vacp2p/Pravdyvy/UTXO-encoded-with-a-tag
UTXO with tags
2025-04-03 00:22:34 -04:00
tyshko-rostyslav
dd3bcc8f73
Merge pull request #51 from vacp2p/Pravdyvy/core-primitives
Core primitives
2025-04-02 22:51:08 -04:00
Oleksandr Pravdyvyi
dadf6ffb1d fix: rosc0 version fix 2025-04-02 13:19:45 +03:00
Oleksandr Pravdyvyi
7083e77d9c fix: risc0 version bump 2025-04-02 12:43:14 +03:00
Oleksandr Pravdyvyi
dd976dee00 fix: db public sc data added 2025-04-02 12:16:02 +03:00
Oleksandr Pravdyvyi
305e8d7296 fix: risc0 version bump 2025-03-28 17:45:02 +02:00
Oleksandr Pravdyvyi
437a3a5700 feat: making tags for utxo to privately filter decoding attempts 2025-03-28 17:12:28 +02:00
Oleksandr Pravdyvyi
2c7326d3fc fix: warning fix 2025-03-17 13:41:53 +02:00
Oleksandr Pravdyvyi
7f512474dc fix: adding core primitives crate 2025-03-17 13:18:44 +02:00
tyshko-rostyslav
90c8b50689
Merge pull request #50 from vacp2p/sc_core_crypto
Sc core cryptography and usage
2025-03-17 07:16:21 -04:00
Rostyslav Tyshko
e808422320 warnings 2025-03-16 11:37:23 -04:00
Rostyslav Tyshko
45cb6b21a2 fmt 2025-03-16 11:05:55 -04:00
Rostyslav Tyshko
5708735ca8 sc_core reuse in node_core 2025-03-16 11:05:44 -04:00
Rostyslav Tyshko
bcbe8a73b8 other deps for cryptography 2025-03-16 11:05:27 -04:00
Rostyslav Tyshko
c5a9c81642 crypto dn added 2025-03-16 11:05:08 -04:00
Rostyslav Tyshko
75e5652bf6 deps for cryptography 2025-03-16 11:04:48 -04:00
tyshko-rostyslav
af458635e2
Merge pull request #49 from vacp2p/Pravdyvy/sc-core-helpers
Sc Core helperfunctions
2025-03-14 03:54:54 +01:00
Oleksandr Pravdyvyi
847e77ff72 fix: r0vm version fix 2025-03-07 08:51:36 +02:00
Oleksandr Pravdyvyi
f4aa3e7c18 feat: sc core helpers and manipulators 2025-03-07 05:37:15 +02:00
Pravdyvy
37ce873db8
Merge pull request #48 from vacp2p/Pravdyvy/gas-modeling
Gas Calculation Model
2025-03-05 10:22:44 +02:00
Oleksandr Pravdyvyi
ace1021959 fix: updated rosc0 version 2025-02-28 13:07:22 +02:00
Oleksandr Pravdyvyi
470d1ae3ec fix: gas calculation model 2025-02-28 12:32:54 +02:00
tyshko-rostyslav
c3b5921d14
Merge pull request #47 from vacp2p/Pravdyvy/fixed-error-propagation
Fixed error propagation
2025-02-21 14:52:38 +01:00
Oleksandr Pravdyvyi
9300b786f8 fix: taplo fmt 2025-02-14 11:08:28 +02:00
Oleksandr Pravdyvyi
443ee9bb4e fix: merge fix 2025-02-14 10:58:54 +02:00
Oleksandr Pravdyvyi
620aefec23 Merge branch 'main' into Pravdyvy/fixed-error-propagation 2025-02-14 10:49:34 +02:00
tyshko-rostyslav
b925b3e639
Merge pull request #46 from vacp2p/redundunt
Remove redundunt code
2025-02-14 05:52:17 +01:00
tyshko-rostyslav
09835b0462
Merge pull request #45 from vacp2p/error-handling
Error handling
2025-02-14 05:51:57 +01:00
Rostyslav Tyshko
b88358949c fmt 2025-02-09 11:46:08 -05:00
Rostyslav Tyshko
9c5b4fb3d4 fix imports 2025-02-09 11:45:53 -05:00
Rostyslav Tyshko
e8c14f9185 rm node_rps redundunt code 2025-02-09 11:45:45 -05:00
Rostyslav Tyshko
a0580238a6 add needed deps 2025-02-09 11:45:31 -05:00
Rostyslav Tyshko
01b370d9b6 create common requests module 2025-02-09 11:45:16 -05:00
Rostyslav Tyshko
8815eb836c unused 2025-02-09 11:45:01 -05:00
Rostyslav Tyshko
f472c25349 rm node_core reduncunt code 2025-02-09 11:44:55 -05:00
Rostyslav Tyshko
809cc090e5 rm parse 2025-02-09 11:44:41 -05:00
Rostyslav Tyshko
d34d87c274 rm redundunt structures in json 2025-02-09 11:44:24 -05:00
Rostyslav Tyshko
c4bff550bb lock file changes 2025-02-09 11:44:10 -05:00
Rostyslav Tyshko
818f58e2f9 fmt 2025-02-07 15:17:55 -05:00
Rostyslav Tyshko
bfb79e38d6 propagation in node_core 2025-02-07 15:17:42 -05:00
Rostyslav Tyshko
a52bf50a0f errors in account_core 2025-02-07 15:17:20 -05:00
Rostyslav Tyshko
49750b600f propagation in utxo_core 2025-02-07 15:17:03 -05:00
Rostyslav Tyshko
ffad7c48d2 errors in utxo_tree 2025-02-07 15:16:47 -05:00
Rostyslav Tyshko
43bd2a8314 fix error handing in zkvm module 2025-02-07 15:16:31 -05:00
Oleksandr Pravdyvyi
e96d640082 Merge branch 'main' into Pravdyvy/fixed-error-propagation 2025-02-06 11:52:37 +02:00
tyshko-rostyslav
df9d90d017
Merge pull request #43 from vacp2p/Pravdyvy/node-rpc-docs
JSON RPC DOCS for node RPC
2025-02-06 04:51:09 -05:00
tyshko-rostyslav
bbad30b86d
Merge pull request #42 from vacp2p/chain_state_tests
Chain state validation tests
2025-02-06 04:37:01 -05:00
tyshko-rostyslav
86c12d13a7
Merge pull request #44 from vacp2p/fix_warnings
Fix warnings
2025-02-05 17:45:01 -05:00
Oleksandr Pravdyvyi
bd8b4b8fa8 fix: error propagation 2025-02-05 12:24:09 +02:00
Pravdyvy
4ecb87658b
fix: PATH clarification 2025-02-04 18:20:12 +02:00
Oleksandr Pravdyvyi
c1e8153871 fix: more links 2025-02-04 14:10:36 +02:00
Pravdyvy
d54b0ca556
fix: fix link 2025-02-04 14:06:53 +02:00
Oleksandr Pravdyvyi
c67969efa2 fix: link added, risc0 toockain install instructions added 2025-02-04 14:05:42 +02:00
Rostyslav Tyshko
2f9ce0c5cf fmt 2025-01-31 17:02:44 -05:00
Rostyslav Tyshko
ec702ddc05 build scripts now check for warnings 2025-01-31 17:02:32 -05:00
Rostyslav Tyshko
98ba83e0a4 storage fix warnings 2025-01-31 17:02:17 -05:00
Rostyslav Tyshko
37938a022c sequencer_rpc fix warnings 2025-01-31 17:02:08 -05:00
Rostyslav Tyshko
7ee5f0d448 account_core fix 2025-01-31 17:01:50 -05:00
Rostyslav Tyshko
b98de3d992 var naming 2025-01-31 17:01:39 -05:00
Rostyslav Tyshko
2670fb1b4f lib.rs fix warnings 2025-01-31 16:50:00 -05:00
Rostyslav Tyshko
360981b77d se fix warnings 2025-01-31 16:49:53 -05:00
Rostyslav Tyshko
c693ad434a de fix warnings 2025-01-31 16:49:47 -05:00
Rostyslav Tyshko
67bb04c6c2 private_exec fix warnings 2025-01-31 16:49:41 -05:00
Rostyslav Tyshko
764669398c node_rpc fix warnings 2025-01-31 16:45:55 -05:00
Oleksandr Pravdyvyi
cc3db7d323 fix: format fix 2025-01-31 10:02:09 +02:00
Oleksandr Pravdyvyi
bd7809bc17 fix: rpc docs added 2025-01-31 09:54:19 +02:00
Rostyslav Tyshko
0e30e64534 fmt 2025-01-27 13:51:27 +01:00
Rostyslav Tyshko
01d51c6e45 add test_produce_new_block_with_mempool_transactions 2025-01-27 13:45:01 +01:00
Rostyslav Tyshko
8d63de52f9 add test_push_tx_into_mempool_pre_check 2025-01-27 13:44:45 +01:00
Rostyslav Tyshko
f2a781545b add test_transaction_pre_check_fail_mempool_full 2025-01-27 13:44:30 +01:00
Rostyslav Tyshko
671a1f2923 add test_transaction_pre_check_pass 2025-01-27 13:44:07 +01:00
Rostyslav Tyshko
ef1d95ea2d add test_get_tree_roots 2025-01-27 13:43:45 +01:00
Rostyslav Tyshko
182adad9d2 add test_start_from_config 2025-01-27 13:43:17 +01:00
Rostyslav Tyshko
91de70b7dc add common_setup for tests 2025-01-27 13:42:43 +01:00
Rostyslav Tyshko
aa74dae70f add create_dummy_transaction for tests 2025-01-27 13:42:27 +01:00
Rostyslav Tyshko
4f61d792bc add setup_sequencer_config for tests 2025-01-27 13:42:11 +01:00
tyshko-rostyslav
603461f19a
Merge pull request #41 from vacp2p/Pravdyvy/chain-state-validation
Chain state validation
2025-01-27 12:12:19 +01:00
Oleksandr Pravdyvyi
4a535085c5 fix:chain state validation 2025-01-24 09:10:42 +02:00
284 changed files with 38897 additions and 11383 deletions

36
.dockerignore Normal file
View File

@ -0,0 +1,36 @@
# Build artifacts
target/
**/target/
# RocksDB data
rocksdb/
**/rocksdb/
# Git
.git/
.gitignore
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# CI/CD
.github/
ci_scripts/
# Documentation
*.md
!README.md
# Configs (copy selectively if needed)
configs/
# License
LICENSE

View File

@ -0,0 +1,10 @@
name: Install risc0
description: Installs risc0 in the environment
runs:
using: "composite"
steps:
- name: Install risc0
run: |
curl -L https://risczero.com/install | bash
/home/runner/.risc0/bin/rzup install
shell: bash

View File

@ -0,0 +1,10 @@
name: Install system dependencies
description: Installs system dependencies in the environment
runs:
using: "composite"
steps:
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential clang libclang-dev libssl-dev pkg-config
shell: bash

43
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,43 @@
## 🎯 Purpose
*What problem does this PR solve or what feature does it add? Mention issues related to it*
TO COMPLETE
## ⚙️ Approach
*Describe the core changes introduced by this PR.*
TO COMPLETE
- [ ] Change ...
- [ ] Add ...
- [ ] Fix ...
- [ ] ...
## 🧪 How to Test
*How to verify that this PR works as intended.*
TO COMPLETE
## 🔗 Dependencies
*Link PRs that must be merged before this one.*
TO COMPLETE IF APPLICABLE
## 🔜 Future Work
*List any work intentionally left out of this PR, whether due to scope, prioritization, or pending decisions.*
TO COMPLETE IF APPLICABLE
## 📋 PR Completion Checklist
*Mark only completed items. A complete PR should have all boxes ticked.*
- [ ] Complete PR description
- [ ] Implement the core functionality
- [ ] Add/update tests
- [ ] Add/update documentation and inline comments

View File

@ -1,7 +1,7 @@
on:
push:
branches:
- master
- main
paths-ignore:
- "**.md"
- "!.github/workflows/*.yml"
@ -14,64 +14,164 @@ on:
name: General
jobs:
build-ubuntu-latest:
fmt-rs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.head_ref }}
- name: Install nightly toolchain for rustfmt
run: rustup install nightly --profile minimal --component rustfmt
- name: Check Rust files are formatted
run: cargo +nightly fmt --check
fmt-toml:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.head_ref }}
- name: Install taplo-cli
run: cargo install --locked taplo-cli
- name: Check TOML files are formatted
run: taplo fmt --check .
machete:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.head_ref }}
- name: Install active toolchain
run: rustup install
- name: Install cargo-machete
run: cargo install cargo-machete
- name: Check for unused dependencies
run: cargo machete
lint:
runs-on: ubuntu-latest
timeout-minutes: 60
name: build - ubuntu-latest
name: lint
steps:
- uses: actions/checkout@v3
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
- uses: actions/checkout@v5
with:
profile: minimal
toolchain: nightly
override: true
- name: build - ubuntu-latest
if: success() || failure()
run: chmod 777 ./ci_scripts/build-ubuntu.sh && ./ci_scripts/build-ubuntu.sh
ref: ${{ github.head_ref }}
- uses: ./.github/actions/install-system-deps
lint:
strategy:
matrix:
platform: [ ubuntu-latest ]
runs-on: ${{ matrix.platform }}
- uses: ./.github/actions/install-risc0
- name: Install active toolchain
run: rustup install
- name: Lint workspace
env:
RISC0_SKIP_BUILD: "1"
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
- name: Lint programs
env:
RISC0_SKIP_BUILD: "1"
run: cargo clippy -p "*programs" -- -D warnings
unit-tests:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.head_ref }}
- uses: ./.github/actions/install-system-deps
- uses: ./.github/actions/install-risc0
- name: Install active toolchain
run: rustup install
- name: Install nextest
run: cargo install cargo-nextest
- name: Run unit tests
env:
RISC0_DEV_MODE: "1"
run: cargo nextest run --no-fail-fast
valid-proof-test:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.head_ref }}
- uses: ./.github/actions/install-system-deps
- uses: ./.github/actions/install-risc0
- name: Install active toolchain
run: rustup install
- name: Test valid proof
env:
NSSA_WALLET_HOME_DIR: ./integration_tests/configs/debug/wallet
RUST_LOG: "info"
run: cargo run --bin integration_tests -- ./integration_tests/configs/debug/ test_success_private_transfer_to_another_owned_account
integration-tests:
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.head_ref }}
- uses: ./.github/actions/install-system-deps
- uses: ./.github/actions/install-risc0
- name: Install active toolchain
run: rustup install
- name: Run integration tests
env:
NSSA_WALLET_HOME_DIR: ./integration_tests/configs/debug/wallet
RUST_LOG: "info"
RISC0_DEV_MODE: "1"
run: cargo run --bin integration_tests -- ./integration_tests/configs/debug/ all
artifacts:
runs-on: ubuntu-latest
timeout-minutes: 60
name: lint - ${{ matrix.crate }} - ${{ matrix.platform }}
name: artifacts
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
- uses: actions/checkout@v5
with:
profile: minimal
toolchain: nightly
override: true
components: rustfmt, clippy
- name: lint - ubuntu-latest
if: success() || failure()
run: chmod 777 ./ci_scripts/lint-ubuntu.sh && ./ci_scripts/lint-ubuntu.sh
ref: ${{ github.head_ref }}
- uses: ./.github/actions/install-risc0
test:
strategy:
matrix:
platform: [ ubuntu-latest ]
runs-on: ${{ matrix.platform }}
timeout-minutes: 60
- name: Install just
run: cargo install just
name: test - ${{ matrix.crate }} - ${{ matrix.platform }}
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
- name: test ubuntu-latest
if: success() || failure()
run: chmod 777 ./ci_scripts/test-ubuntu.sh && ./ci_scripts/test-ubuntu.sh
- name: Build artifacts
run: just build-artifacts
- name: Check if artifacts match repository
run: |
if ! git diff --exit-code artifacts/; then
echo "❌ Artifacts in the repository are out of date!"
echo "Please run 'just build-artifacts' and commit the changes."
exit 1
fi
echo "✅ Artifacts are up to date"

23
.github/workflows/deploy.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: Deploy Sequencer
on:
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Deploy to server
uses: appleboy/ssh-action@v1.2.4
with:
host: ${{ secrets.DEPLOY_SSH_HOST }}
username: ${{ secrets.DEPLOY_SSH_USERNAME }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
envs: GITHUB_ACTOR
script_path: ci_scripts/deploy.sh

44
.github/workflows/publish_image.yml vendored Normal file
View File

@ -0,0 +1,44 @@
name: Publish Sequencer Runner Image
on:
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.DOCKER_REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ secrets.DOCKER_REGISTRY }}/${{ github.repository }}/sequencer_runner
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./sequencer_runner/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

2
.gitignore vendored
View File

@ -6,3 +6,5 @@ data/
.idea/
.vscode/
rocksdb
sequencer_runner/data/
storage.json

4052
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,87 +1,97 @@
[workspace]
resolver = "2"
resolver = "3"
members = [
"node_runner",
"integration_tests",
"sequencer_runner",
"storage",
"accounts",
"utxo",
"vm",
"networking",
"consensus",
"node_rpc",
"key_protocol",
"sequencer_rpc",
"mempool",
"zkvm",
"node_core",
"wallet",
"sequencer_core",
"rpc_primitives",
"common",
"nssa",
"nssa/core",
"program_methods",
"program_methods/guest",
"test_program_methods",
"test_program_methods/guest",
"integration_tests/proc_macro_test_attribute",
"examples/program_deployment",
"examples/program_deployment/methods",
"examples/program_deployment/methods/guest",
]
[workspace.dependencies]
anyhow = "1.0"
nssa = { path = "nssa" }
nssa_core = { path = "nssa/core" }
common = { path = "common" }
mempool = { path = "mempool" }
storage = { path = "storage" }
key_protocol = { path = "key_protocol" }
sequencer_core = { path = "sequencer_core" }
sequencer_rpc = { path = "sequencer_rpc" }
sequencer_runner = { path = "sequencer_runner" }
wallet = { path = "wallet" }
test_program_methods = { path = "test_program_methods" }
tokio = { version = "1.28.2", features = [
"net",
"rt-multi-thread",
"sync",
"fs",
] }
risc0-zkvm = { version = "3.0.3", features = ['std'] }
risc0-build = "3.0.3"
anyhow = "1.0.98"
num_cpus = "1.13.1"
openssl = { version = "0.10", features = ["vendored"] }
openssl-probe = { version = "0.1.2" }
serde = { version = "1.0.60", default-features = false, features = ["derive"] }
serde_json = "1.0.81"
actix = "0.13.0"
actix-cors = "0.6.1"
futures = "0.3"
actix-rt = "*"
lazy_static = "1.5.0"
env_logger = "0.10"
log = "0.4"
log = "0.4.28"
lru = "0.7.8"
thiserror = "1.0"
rs_merkle = "1.4"
thiserror = "2.0.12"
sha2 = "0.10.8"
monotree = "0.1.5"
hex = "0.4.3"
bytemuck = "1.24.0"
aes-gcm = "0.10.3"
toml = "0.7.4"
secp256k1-zkp = "0.11.0"
bincode = "1.3.3"
tempfile = "3.14.0"
light-poseidon = "0.3.0"
ark-bn254 = "0.5.0"
ark-ff = "0.5.0"
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
base64 = "0.22.1"
bip39 = "2.2.0"
hmac-sha512 = "1.1.7"
chrono = "0.4.41"
borsh = "1.5.7"
base58 = "0.2.0"
itertools = "0.14.0"
rocksdb = { version = "0.21.0", default-features = false, features = [
rocksdb = { version = "0.24.0", default-features = false, features = [
"snappy",
"bindgen-runtime",
] }
[workspace.dependencies.rand]
features = ["std", "std_rng", "getrandom"]
version = "0.8.5"
[workspace.dependencies.k256]
features = ["ecdsa-core", "arithmetic", "expose-field"]
version = "0.13.4"
[workspace.dependencies.elliptic-curve]
features = ["arithmetic"]
version = "0.13.8"
[workspace.dependencies.serde]
features = ["derive"]
version = "1.0.60"
[workspace.dependencies.actix-web]
default-features = false
version = "=4.1.0"
[workspace.dependencies.clap]
features = ["derive", "env"]
version = "3.1.6"
[workspace.dependencies.tokio-retry]
version = "0.3.0"
[workspace.dependencies.reqwest]
features = ["json"]
version = "0.11.16"
[workspace.dependencies.tokio]
features = ["net", "rt-multi-thread", "sync", "fs"]
version = "1.28.2"
[workspace.dependencies.tracing]
features = ["std"]
version = "0.1.13"
rand = { version = "0.8.5", features = ["std", "std_rng", "getrandom"] }
k256 = { version = "0.13.3", features = [
"ecdsa-core",
"arithmetic",
"expose-field",
"serde",
"pem",
] }
elliptic-curve = { version = "0.13.8", features = ["arithmetic"] }
actix-web = { version = "=4.1.0", default-features = false, features = [
"macros",
] }
clap = { version = "4.5.42", features = ["derive", "env"] }
reqwest = { version = "0.11.16", features = ["json"] }

19
Justfile Normal file
View File

@ -0,0 +1,19 @@
set shell := ["bash", "-eu", "-o", "pipefail", "-c"]
default:
@just --list
# ---- Configuration ----
METHODS_PATH := "program_methods"
TEST_METHODS_PATH := "test_program_methods"
ARTIFACTS := "artifacts"
# ---- Artifacts build ----
build-artifacts:
@echo "🔨 Building artifacts"
@for methods_path in {{METHODS_PATH}} {{TEST_METHODS_PATH}}; do \
echo "Building artifacts for $methods_path"; \
CARGO_TARGET_DIR=target/$methods_path cargo risczero build --manifest-path $methods_path/guest/Cargo.toml; \
mkdir -p {{ARTIFACTS}}/$methods_path; \
cp target/$methods_path/riscv32im-risc0-zkvm-elf/docker/*.bin {{ARTIFACTS}}/$methods_path; \
done

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Vac
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

753
README.md
View File

@ -1,2 +1,751 @@
# nescience-testnet
This repo serves for Nescience Node testnet
# Nescience
Nescience State Separation Architecture (NSSA) is a programmable blockchain system that introduces a clean separation between public and private states, while keeping them fully interoperable. It lets developers build apps that can operate across both transparent and privacy-preserving accounts. Privacy is handled automatically by the protocol through zero-knowledge proofs (ZKPs). The result is a programmable blockchain where privacy comes built-in.
## Background
Typically, public blockchains maintain a fully transparent state, where the mapping from account IDs to account values is entirely visible. In NSSA, we introduce a parallel *private state*, a new layer of accounts that coexists with the public one. The public and private states can be viewed as a partition of the account ID space: accounts with public IDs are openly visible, while private accounts are accessible only to holders of the corresponding viewing keys. Consistency across both states is enforced through zero-knowledge proofs (ZKPs).
Public accounts are represented on-chain as a visible map from IDs to account states and are modified in-place when their values change. Private accounts, by contrast, are never stored in raw form on-chain. Each update creates a new commitment, which cryptographically binds the current value of the account while preserving privacy. Commitments of previous valid versions remain on-chain, but a nullifier set is maintained to mark old versions as spent, ensuring that only the most up-to-date version of each private account can be used in any execution.
### Programmability and selective privacy
Our goal is to enable full programmability within this hybrid model, matching the flexibility and composability of public blockchains. Developers write and deploy programs in NSSA just as they would on any other blockchain. Privacy, along with the ability to execute programs involving any combination of public and private accounts, is handled entirely at the protocol level and available out of the box for all programs. From the programs perspective, all accounts are indistinguishable. This abstraction allows developers to focus purely on business logic, while the system transparently enforces privacy and consistency guarantees.
To the best of our knowledge, this approach is unique to Nescience. Other programmable blockchains with a focus on privacy typically adopt a developer-driven model for private execution, meaning that dApp logic must explicitly handle private inputs correctly. In contrast, Nescience handles privacy at the protocol level, so developers do not need to modify their programs—private and public accounts are treated uniformly, and privacy-preserving execution is available out of the box.
### Example: creating and transferring tokens across states
1. Token creation (public execution):
- Alice submits a transaction to execute the token program `New` function on-chain.
- A new public token account is created, representing the token.
- The minted tokens are recorded on-chain and fully visible on Alice's public account.
2. Transfer from public to private (local / privacy-preserving execution)
- Alice executes the token program `Transfer` function locally, specifying a Bobs private account as recipient.
- A ZKP of correct execution is generated.
- The proof is submitted to the blockchain, and validator nodes verify it.
- Alice's public account balance is modified accordingly.
- Bobs private account and balance remain hidden, while the transfer is provably valid.
3. Transferring private to public (local / privacy-preserving execution)
- Bob executes the token program `Transfer` function locally, specifying a Charlies public account as recipient.
- A ZKP of correct execution is generated.
- Bobs private account and balance still remain hidden.
- Charlie's public account is modified with the new tokens added.
4. Transferring public to public (public execution):
- Alice submits a transaction to execute the token program `Transfer` function on-chain, specifying Charlie's public account as recipient.
- The execution is handled on-chain without ZKPs involved.
- Alice's and Charlie's accounts are modified according to the transaction.
#### Key points:
- The same token program is used in all executions.
- The difference lies in execution mode: public executions update visible accounts on-chain, while private executions rely on ZKPs.
- Validators only need to verify proofs for privacy-preserving transactions, keeping processing efficient.
### The accounts model
To achieve both state separation and full programmability, NSSA adopts a stateless program model. Programs do not hold internal state. Instead, all persistent data resides in accounts explicitly passed to the program during execution. This design enables fine-grained control over access and visibility while maintaining composability across public and private states.
### Execution types
Execution is divided into two fundamentally distinct types based on how they are processed: public execution, which is executed transparently on-chain, and private execution, which occurs off-chain. For private execution, the blockchain relies on ZKPs to verify the correctness of execution and ensure that all system invariants are preserved.
Both public and private executions of the same program are enforced to use the same Risc0 VM bytecode. For public transactions, programs are executed directly on-chain like any standard RISC-V VM execution, without generating or verifying proofs. For privacy-preserving transactions, users generate Risc0 ZKPs of correct execution, and validator nodes only verify these proofs rather than re-executing the program. This design ensures that from a validators perspective, public transactions are processed as quickly as any RISC-Vbased VM, while verification of ZKPs keeps privacy-preserving transactions efficient as well. Additionally, the system naturally supports parallel execution similar to Solana, further increasing throughput. The main computational bottleneck for privacy-preserving transactions lies on the user side, in generating zk proofs.
### Resources
- [IFT Research call](https://forum.vac.dev/t/ift-research-call-september-10th-2025-updates-on-the-development-of-nescience/566)
- [NSSA v0.2 specs](https://www.notion.so/NSSA-v0-2-specifications-2848f96fb65c800c9818e6f66d9be8f2)
- [Choice of VM/zkVM](https://www.notion.so/Conclusion-on-the-chosen-VM-and-zkVM-for-NSSA-2318f96fb65c806a810ed1300f56992d)
- [NSSA vs other privacy projects](https://www.notion.so/Privacy-projects-comparison-2688f96fb65c8096b694ecf7e4deca30)
- [NSSA state model](https://www.notion.so/Public-state-model-decision-2388f96fb65c80758b20c76de07b1fcc)
- [NSSA sequencer specs](https://www.notion.so/Sequencer-specs-2428f96fb65c802da2bfea7b0b214ecb)
- [NSSA sequencer code](https://www.notion.so/NSSA-sequencer-pseudocode-2508f96fb65c805e8859e047dffd6785)
- [NSSA Token program desing](https://www.notion.so/Token-program-design-2538f96fb65c80a1b4bdc4fd9dd162d7)
- [NSSA cross program calls](https://www.notion.so/NSSA-cross-program-calls-Tail-call-model-proposal-extended-version-2838f96fb65c8096b3a2d390444193b6)
# Install dependencies
Install build dependencies
- On Linux
Ubuntu / Debian
```sh
apt install build-essential clang libclang-dev libssl-dev pkg-config
```
Fedora
```sh
sudo dnf install clang clang-devel openssl-devel pkgconf
```
- On Mac
```sh
xcode-select --install
brew install pkg-config openssl
```
Install Rust
```sh
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
Install Risc0
```sh
curl -L https://risczero.com/install | bash
```
Then restart your shell and run
```sh
rzup install
```
# Run tests
The NSSA repository includes both unit and integration test suites.
### Unit tests
```bash
# RISC0_DEV_MODE=1 is used to skip proof generation and reduce test runtime overhead
RISC0_DEV_MODE=1 cargo test --release
```
### Integration tests
```bash
export NSSA_WALLET_HOME_DIR=$(pwd)/integration_tests/configs/debug/wallet/
cd integration_tests
# RISC0_DEV_MODE=1 skips proof generation; RUST_LOG=info enables runtime logs
RUST_LOG=info RISC0_DEV_MODE=1 cargo run $(pwd)/configs/debug all
```
# Run the sequencer
The sequencer can be run locally:
```bash
cd sequencer_runner
RUST_LOG=info cargo run --release configs/debug
```
If everything went well you should see an output similar to this:
```bash
[2025-11-13T19:50:29Z INFO sequencer_runner] Sequencer core set up
[2025-11-13T19:50:29Z INFO network] Starting http server at 0.0.0.0:3040
[2025-11-13T19:50:29Z INFO actix_server::builder] starting 8 workers
[2025-11-13T19:50:29Z INFO sequencer_runner] HTTP server started
[2025-11-13T19:50:29Z INFO sequencer_runner] Starting main sequencer loop
[2025-11-13T19:50:29Z INFO actix_server::server] Tokio runtime found; starting in existing Tokio runtime
[2025-11-13T19:50:29Z INFO actix_server::server] starting service: "actix-web-service-0.0.0.0:3040", workers: 8, listening on: 0.0.0.0:3040
[2025-11-13T19:50:39Z INFO sequencer_runner] Collecting transactions from mempool, block creation
[2025-11-13T19:50:39Z INFO sequencer_core] Created block with 0 transactions in 0 seconds
[2025-11-13T19:50:39Z INFO sequencer_runner] Block with id 2 created
[2025-11-13T19:50:39Z INFO sequencer_runner] Waiting for new transactions
```
# Try the Wallet CLI
## Install
This repository includes a CLI for interacting with the Nescience sequencer. To install it, run the following command from the root of the repository:
```bash
cargo install --path wallet --force
```
Run `wallet help` to check everything went well.
## Tutorial
This tutorial walks you through creating accounts and executing NSSA programs in both public and private contexts.
> [!NOTE]
> The NSSA state is split into two separate but interconnected components: the public state and the private state.
> The public state is an on-chain, publicly visible record of accounts indexed by their Account IDs
> The private state mirrors this, but the actual account values are stored locally by each account owner. On-chain, only a hidden commitment to each private account state is recorded. This allows the chain to enforce freshness (i.e., prevent the reuse of stale private states) while preserving privacy and unlinkability across executions and private accounts.
>
> Every piece of state in NSSA is stored in an account (public or private). Accounts are either uninitialized or are owned by a program, and programs can only modify the accounts they own.
>
> In NSSA, accounts can only be modified through program execution. A program is the sole mechanism that can change an accounts value.
> Programs run publicly when all involved accounts are public, and privately when at least one private account participates.
### Health-check
Verify that the node is running and that the wallet can connect to it:
```bash
wallet check-health
```
You should see `✅ All looks good!`.
### The commands
The wallet provides several commands to interact with the node and query state. To see the full list, run `wallet help`:
```bash
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
```
### Accounts
> [!NOTE]
> Accounts are the basic unit of state in NSSA. They essentially hold native tokens and arbitrary data managed by some program.
The CLI provides commands to manage accounts. Run `wallet account` to see the options available:
```bash
Commands:
get Get account data
new Produce new public or private account
sync-private Sync private accounts
help Print this message or the help of the given subcommand(s)
```
#### Create a new public account
You can create both public and private accounts through the CLI. For example:
```bash
wallet account new public
# Output:
Generated new account with account_id Public/9ypzv6GGr3fwsgxY7EZezg5rz6zj52DPCkmf1vVujEiJ
```
This id is required when executing any program that interacts with the account.
> [!NOTE]
> Public accounts live on-chain and are identified by a 32-byte Account ID.
> Running `wallet account new public` generates a fresh keypair for the signature scheme used in NSSA.
> The account ID is derived from the public key. The private key is used to sign transactions and to authorize the account in program executions.
#### Account initialization
To query the accounts current status, run:
```bash
# Replace the id with yours
wallet account get --account-id Public/9ypzv6GGr3fwsgxY7EZezg5rz6zj52DPCkmf1vVujEiJ
# Output:
Account is Uninitialized
```
> [!NOTE]
> New accounts begin in an uninitialized state, meaning they are not yet owned by any program. A program may claim an uninitialized account; once claimed, the account becomes owned by that program.
> Owned accounts can only be modified through executions of the owning program. The only exception is native-token credits: any program may credit native tokens to any account.
> However, debiting native tokens from an account must always be performed by its owning program.
In this example, we will initialize the account for the Authenticated transfer program, which securely manages native token transfers by requiring authentication for debits.
Initialize the account by running:
```bash
# This command submits a public transaction executing the `init` function of the
# Authenticated-transfer program. The wallet polls the sequencer until the
# transaction is included in a block, which may take several seconds.
wallet auth-transfer init --account-id Public/9ypzv6GGr3fwsgxY7EZezg5rz6zj52DPCkmf1vVujEiJ
```
After it completes, check the updated account status:
```bash
wallet account get --account-id Public/9ypzv6GGr3fwsgxY7EZezg5rz6zj52DPCkmf1vVujEiJ
# Output:
Account owned by authenticated transfer program
{"balance":0}
```
### Funding the account: executing the Piñata program
Now that we have a public account initialized by the authenticated transfer program, we need to fund it. For that, the testnet provides the Piñata program.
```bash
# Complete with your id
wallet pinata claim --to Public/9ypzv6GGr3fwsgxY7EZezg5rz6zj52DPCkmf1vVujEiJ
```
After the claim succeeds, the account will be funded with some tokens:
```bash
wallet account get --account-id Public/9ypzv6GGr3fwsgxY7EZezg5rz6zj52DPCkmf1vVujEiJ
# Output:
Account owned by authenticated transfer program
{"balance":150}
```
### Native token transfers: executing the Authenticated transfers program
NSSA comes with a program for managing and transferring native tokens. Run `wallet auth-transfer` to see the options available:
```bash
Commands:
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)
```
We have already used the `init` command. The `send` command is used to execute the `Transfer` function of the authenticated program.
Let's try it. For that we need to create another account for the recipient of the transfer.
```bash
wallet account new public
# Output:
Generated new account with account_id Public/Ev1JprP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPAWS
```
> [!NOTE]
> The new account is uninitialized. The authenticated transfers program will claim any uninitialized account used in a transfer. So we don't need to manually initialize the recipient account.
Let's send 37 tokens to the new account.
```bash
wallet auth-transfer send \
--from Public/9ypzv6GGr3fwsgxY7EZezg5rz6zj52DPCkmf1vVujEiJ \
--to Public/Ev1JprP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPAWS \
--amount 37
```
Once that succeeds we can check the states.
```bash
# Sender account
wallet account get --account-id Public/HrA8TVjBS8UVf9akV7LRhyh6k4c7F6PS7PvqgtPmKAT8
# Output:
Account owned by authenticated transfer program
{"balance":113}
```
```bash
# Recipient account
wallet account get --account-id Public/Ev1JprP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPAWS
# Output:
Account owned by authenticated transfer program
{"balance":37}
```
#### Create a new private account
> [!NOTE]
> Private accounts are structurally identical to public accounts; they differ only in how their state is stored off-chain and represented on-chain.
> The raw values of a private account are never stored on-chain. Instead, the chain only holds a 32-byte commitment (a hash-like binding to the actual values). Transactions include encrypted versions of the private values so that users can recover them from the blockchain. The decryption keys are known only to the user and are never shared.
> Private accounts are not managed through the usual signature mechanism used for public accounts. Instead, each private account is associated with two keypairs:
> - *Nullifier keys*, for using the corresponding private account in privacy preserving executions.
> - *Viewing keys*, used for encrypting and decrypting the values included in transactions.
>
> Private accounts also have a 32-byte identifier, derived from the nullifier public key.
>
> Just like public accounts, private accounts can only be initialized once. Any user can initialize them without knowing the owner's secret keys. However, modifying an initialized private account through an off-chain program execution requires knowledge of the owners secret keys.
>
> Transactions that modify the values of a private account include a commitment to the new values, which will be added to the on-chain commitment set. They also include a nullifier that marks the previous version as old.
> The nullifier is constructed so that it cannot be linked to any prior commitment, ensuring that updates to the same private account cannot be correlated.
Now lets switch to the private state and create a private account.
```bash
wallet account new private
# Output:
Generated new account with account_id Private/HacPU3hakLYzWtSqUPw6TUr8fqoMieVWovsUR6sJf7cL
With npk e6366f79d026c8bd64ae6b3d601f0506832ec682ab54897f205fffe64ec0d951
With ipk 02ddc96d0eb56e00ce14994cfdaec5ae1f76244180a919545983156e3519940a17
```
For now, focus only on the account id. Ignore the `npk` and `ipk` values. These are the Nullifier public key and the Viewing public key. They are stored locally in the wallet and are used internally to build privacy-preserving transactions.
Also, the account id for private accounts is derived from the `npk` value. But we won't need them now.
Just like public accounts, new private accounts start out uninitialized:
```bash
wallet account get --account-id Private/HacPU3hakLYzWtSqUPw6TUr8fqoMieVWovsUR6sJf7cL
# Output:
Account is Uninitialized
```
Unlike public accounts, private accounts are never visible to the network. They exist only in your local wallet storage.
#### Sending tokens from the public account to the private account
Sending tokens to an uninitialized private account causes the Authenticated-Transfers program to claim it. Just like with public accounts.
This happens because program execution logic does not depend on whether the involved accounts are public or private.
Lets send 17 tokens to the new private account.
The syntax is identical to the public-to-public transfer; just set the private ID as the recipient.
This command will run the Authenticated-Transfer program locally, generate a proof, and submit it to the sequencer. Depending on your machine, this can take from 30 seconds to 4 minutes.
```bash
wallet auth-transfer send \
--from Public/Ev1JprP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPAWS \
--to Private/HacPU3hakLYzWtSqUPw6TUr8fqoMieVWovsUR6sJf7cL \
--amount 17
```
After it succeeds, check both accounts:
```bash
# Public sender account
wallet account get --account-id Public/Ev1JprP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPAWS
# Output:
Account owned by authenticated transfer program
{"balance":20}
```
```bash
# Private recipient account
wallet account get --account-id Private/HacPU3hakLYzWtSqUPw6TUr8fqoMieVWovsUR6sJf7cL
# Output:
Account owned by authenticated transfer program
{"balance":17}
```
> [!NOTE]
> The last command does not query the network.
> It works even offline because private account data lives only in your wallet storage. Other users cannot read your private balances.
#### Digression: modifying private accounts
As a general rule, private accounts can only be modified through a program execution performed by their owner. That is, the person who holds the private key for that account. There is one exception: an uninitialized private account may be initialized by any user, without requiring the private key. After initialization, only the owner can modify it.
This mechanism enables a common use case: transferring funds from any account (public or private) to a private account owned by someone else. For such transfers, the recipients private account must be uninitialized.
#### Sending tokens from the public account to a private account owned by someone else
For this tutorial, well simulate that scenario by creating a new private account that we own, but well treat it as if it belonged to someone else.
Let's create a new (uninitialized) private account like before:
```bash
wallet account new private
# Output:
Generated new account with account_id Private/AukXPRBmrYVqoqEW2HTs7N3hvTn3qdNFDcxDHVr5hMm5
With npk 0c95ebc4b3830f53da77bb0b80a276a776cdcf6410932acc718dcdb3f788a00e
With ipk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72
```
Now we'll ignore the private account ID and focus on the `npk` and `ipk` values. We'll need this to send tokens to a foreign private account. Syntax is very similar.
```bash
wallet auth-transfer send \
--from Public/Ev1JprP9BmhbFVQyBcbznU8bAXcwrzwRoPTetXdQPAWS \
--to-npk 0c95ebc4b3830f53da77bb0b80a276a776cdcf6410932acc718dcdb3f788a00e \
--to-ipk 039fd12a3674a880d3e917804129141e4170d419d1f9e28a3dcf979c1f2369cb72 \
--amount 3
```
The command above produces a privacy-preserving transaction, which may take a few minutes to complete. The updated values of the private account are encrypted and included in the transaction.
Once the transaction is accepted, the recipient must run `wallet account sync-private`. This command scans the chain for encrypted values that belong to their private accounts and updates the local versions accordingly.
#### Transfers in other combinations of public and private accounts
Weve shown how to use the authenticated-transfers program for transfers between two public accounts, and for transfers from a public sender to a private recipient. Sending tokens from a private account (whether to a public account or to another private account) works in essentially the same way.
### The token program
So far, weve made transfers using the authenticated-transfers program, which handles native token transfers. The Token program, on the other hand, is used for creating and managing custom tokens.
> [!NOTE]
> The token program is a single program responsible for creating and managing all tokens. There is no need to deploy new programs to introduce new tokens. All token-related operations are performed by invoking the appropriate functions of the token program.
The CLI provides commands to execute the token program. To see the options available run `wallet token`:
```bash
Commands:
new Produce a new token
send Send tokens from one account to another with variable privacy
help Print this message or the help of the given subcommand(s)
```
> [!NOTE]
> The Token program manages its accounts in two categories. Meaning, all accounts owned by the Token program fall into one of these types.
> - Token definition accounts: these accounts store metadata about a token, such as its name, total supply, and other identifying properties. They act as the tokens unique identifier.
> - Token holding accounts: these accounts hold actual token balances. In addition to the balance, they also record which token definition they belong to.
#### Creating a new token
To create a new token, simply run `wallet token new`. This will create a transaction to execute the `New` function of the token program.
The command expects a name, the desired total supply, and two uninitialized accounts:
- One that will be initialized as the token definition account for the new token.
- Another that will be initialized as a token holding account and receive the tokens entire initial supply.
##### New token with both definition and supply accounts set as public
For example, let's create two new (uninitialized) public accounts and then use them to create a new token.
```bash
wallet account new public
# Output:
Generated new account with account_id Public/4X9kAcnCZ1Ukkbm3nywW9xfCNPK8XaMWCk3zfs1sP4J7
```
```bash
wallet account new public
# Output:
Generated new account with account_id Public/9RRSMm3w99uCD2Jp2Mqqf6dfc8me2tkFRE9HeU2DFftw
```
Now we use them to create a new token. Let's call it the "Token A"
```bash
wallet token new \
--name TOKENA \
--total-supply 1337 \
--definition-account-id Public/4X9kAcnCZ1Ukkbm3nywW9xfCNPK8XaMWCk3zfs1sP4J7 \
--supply-account-id Public/9RRSMm3w99uCD2Jp2Mqqf6dfc8me2tkFRE9HeU2DFftw
```
After it succeeds, we can inspect the two accounts to see how they were initialized.
```bash
wallet account get --account-id Public/4X9kAcnCZ1Ukkbm3nywW9xfCNPK8XaMWCk3zfs1sP4J7
# Output:
Definition account owned by token program
{"account_type":"Token definition","name":"TOKENA","total_supply":1337}
```
```bash
wallet account get --account-id Public/9RRSMm3w99uCD2Jp2Mqqf6dfc8me2tkFRE9HeU2DFftw
# Output:
Holding account owned by token program
{"account_type":"Token holding","definition_id":"4X9kAcnCZ1Ukkbm3nywW9xfCNPK8XaMWCk3zfs1sP4J7","balance":1337}
```
##### New token with public account definition but private holding account for initial supply
Lets create a new token, but this time using a public definition account and a private holding account to store the entire supply.
Since we cant reuse the accounts from the previous example, we need to create fresh ones for this case.
```bash
wallet account new public
# Output:
Generated new account with account_id Public/GQ3C8rbprTtQUCvkuVBRu3v9wvUvjafCMFqoSPvTEVii
```
```bash
wallet account new private
# Output:
Generated new account with account_id Private/HMRHZdPw4pbyPVZHNGrV6K5AA95wACFsHTRST84fr3CF
With npk 6a2dfe433cf28e525aa0196d719be3c16146f7ee358ca39595323f94fde38f93
With ipk 03d59abf4bee974cc12ddb44641c19f0b5441fef39191f047c988c29a77252a577
```
And we use them to create the token.
Now we use them to create a new token. Let's call it "Token B".
```bash
wallet token new \
--name TOKENB \
--total-supply 7331 \
--definition-account-id Public/GQ3C8rbprTtQUCvkuVBRu3v9wvUvjafCMFqoSPvTEVii \
--supply-account-id Private/HMRHZdPw4pbyPVZHNGrV6K5AA95wACFsHTRST84fr3CF
```
After it succeeds, we can check their values
```bash
wallet account get --account-id Public/GQ3C8rbprTtQUCvkuVBRu3v9wvUvjafCMFqoSPvTEVii
# Output:
Definition account owned by token program
{"account_type":"Token definition","name":"TOKENB","total_supply":7331}
```
```bash
wallet account get --account-id Private/HMRHZdPw4pbyPVZHNGrV6K5AA95wACFsHTRST84fr3CF
# Output:
Holding account owned by token program
{"account_type":"Token holding","definition_id":"GQ3C8rbprTtQUCvkuVBRu3v9wvUvjafCMFqoSPvTEVii","balance":7331}
```
Like any other private account owned by us, it cannot be seen by other users.
#### Custom token transfers
The Token program has a function to move funds from one token holding account to another one. If executed with an uninitialized account as the recipient, this will be automatically claimed by the token program.
The transfer function can be executed with the `wallet token send` command.
Let's create a new public account for the recipient.
```bash
wallet account new public
# Output:
Generated new account with account_id Public/88f2zeTgiv9LUthQwPJbrmufb9SiDfmpCs47B7vw6Gd6
```
Let's send 1000 B tokens to this new account. We'll debit this from the supply account used in the creation of the token.
```bash
wallet token send \
--from Private/HMRHZdPw4pbyPVZHNGrV6K5AA95wACFsHTRST84fr3CF \
--to Public/88f2zeTgiv9LUthQwPJbrmufb9SiDfmpCs47B7vw6Gd6 \
--amount 1000
```
Let's inspect the public account:
```bash
wallet account get --account-id Public/88f2zeTgiv9LUthQwPJbrmufb9SiDfmpCs47B7vw6Gd6
# Output:
Holding account owned by token program
{"account_type":"Token holding","definition_id":"GQ3C8rbprTtQUCvkuVBRu3v9wvUvjafCMFqoSPvTEVii","balance":1000}
```
### Chain information
The wallet provides some commands to query information about the chain. These are under the `wallet chain-info` command.
```bash
Commands:
current-block-id Get current block id from sequencer
block Get block at id from sequencer
transaction Get transaction at hash from sequencer
```
For example, run this to find the current block id.
```bash
wallet chain-info current-block-id
# Output:
Last block id is 65537
```
### Automated Market Maker (AMM)
NSSA includes an AMM program that manages liquidity pools and enables swaps between custom tokens. To test this functionality, we first need to create a liquidity pool.
#### Creating a liquidity pool for a token pair
We start by creating a new pool for the tokens previously created. In return for providing liquidity, we will receive liquidity provider (LP) tokens, which represent our share of the pool and are required to withdraw liquidity later.
>[!NOTE]
> The AMM program does not currently charge swap fees or distribute rewards to liquidity providers. LP tokens therefore only represent a proportional share of the pool reserves and do not provide additional value from swap activity. Fee support for liquidity providers will be added in future versions of the AMM program.
To hold these LP tokens, we first create a new account:
```bash
wallet account new public
# Output:
Generated new account with account_id Public/FHgLW9jW4HXMV6egLWbwpTqVAGiCHw2vkg71KYSuimVf
```
Next, we initialize the liquidity pool by depositing tokens A and B and specifying the account that will receive the LP tokens:
```bash
wallet amm new \
--user-holding-a Public/9RRSMm3w99uCD2Jp2Mqqf6dfc8me2tkFRE9HeU2DFftw \
--user-holding-b Public/88f2zeTgiv9LUthQwPJbrmufb9SiDfmpCs47B7vw6Gd6 \
--user-holding-lp Public/FHgLW9jW4HXMV6egLWbwpTqVAGiCHw2vkg71KYSuimVf \
--balance-a 100 \
--balance-b 200
```
The newly created account is owned by the token program, meaning that LP tokens are managed by the same token infrastructure as regular tokens.
```bash
wallet account get --account-id Public/FHgLW9jW4HXMV6egLWbwpTqVAGiCHw2vkg71KYSuimVf
# Output:
Holding account owned by token program
{"account_type":"Token holding","definition_id":"7BeDS3e28MA5Err7gBswmR1fUKdHXqmUpTefNPu3pJ9i","balance":100}
```
If you inspect the `user-holding-a` and `user-holding-b` accounts passed to the `wallet amm new` command, you will see that 100 and 200 tokens were deducted, respectively. These tokens now reside in the liquidity pool and are available for swaps by any user.
#### Swaping
Token swaps can be performed using the wallet amm swap command:
```bash
wallet amm swap \
--user-holding-a Public/9RRSMm3w99uCD2Jp2Mqqf6dfc8me2tkFRE9HeU2DFftw \
--user-holding-b Public/88f2zeTgiv9LUthQwPJbrmufb9SiDfmpCs47B7vw6Gd6 \
# The amount of tokens to swap
--amount-in 5 \
# The minimum number of tokens expected in return
--min-amount-out 8 \
# The definition ID of the token being provided to the swap
# In this case, we are swapping from TOKENA to TOKENB, and so this is the definition ID of TOKENA
--token-definition 4X9kAcnCZ1Ukkbm3nywW9xfCNPK8XaMWCk3zfs1sP4J7
```
Once executed, 5 tokens are deducted from the Token A holding account and the corresponding amount (determined by the pools pricing function) is credited to the Token B holding account.
#### Withdrawing liquidity from the pool
Liquidity providers can withdraw assets from the pool by redeeming (burning) LP tokens. The amount of tokens received is proportional to the share of LP tokens being redeemed relative to the total LP supply.
This operation is performed using the `wallet amm remove-liquidity` command:
```bash
wallet amm remove-liquidity \
--user-holding-a Public/9RRSMm3w99uCD2Jp2Mqqf6dfc8me2tkFRE9HeU2DFftw \
--user-holding-b Public/88f2zeTgiv9LUthQwPJbrmufb9SiDfmpCs47B7vw6Gd6 \
--user-holding-lp Public/FHgLW9jW4HXMV6egLWbwpTqVAGiCHw2vkg71KYSuimVf \
--balance-lp 20 \
--min-amount-a 1 \
--min-amount-b 1
```
This instruction burns `balance-lp` LP tokens from the users LP holding account. In exchange, the AMM transfers tokens A and B from the pools vault accounts to the users holding accounts, according to the current pool reserves.
The `min-amount-a` and `min-amount-b` parameters specify the minimum acceptable amounts of tokens A and B to be received. If the computed outputs fall below either threshold, the instruction fails, protecting the user against unfavorable pool state changes.
#### Adding liquidity to the pool
Additional liquidity can be added to an existing pool by depositing tokens A and B in the ratio implied by the current pool reserves. In return, new LP tokens are minted to represent the users proportional share of the pool.
This is done using the `wallet amm add-liquidity` command:
```bash
wallet amm add-liquidity \
--user-holding-a Public/9RRSMm3w99uCD2Jp2Mqqf6dfc8me2tkFRE9HeU2DFftw \
--user-holding-b Public/88f2zeTgiv9LUthQwPJbrmufb9SiDfmpCs47B7vw6Gd6 \
--user-holding-lp Public/FHgLW9jW4HXMV6egLWbwpTqVAGiCHw2vkg71KYSuimVf \
--min-amount-lp 1 \
--max-amount-a 10 \
--max-amount-b 10
```
In this instruction, `max-amount-a` and `max-amount-b` define upper bounds on the number of tokens A and B that may be withdrawn from the users accounts. The AMM computes the actual required amounts based on the pools reserve ratio.
The `min-amount-lp` parameter specifies the minimum number of LP tokens that must be minted for the transaction to succeed. If the resulting LP token amount is below this threshold, the instruction fails.

View File

@ -1,23 +0,0 @@
[package]
name = "accounts"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true
serde.workspace = true
k256.workspace = true
sha2.workspace = true
rand.workspace = true
elliptic-curve.workspace = true
hex.workspace = true
aes-gcm.workspace = true
[dependencies.storage]
path = "../storage"
[dependencies.utxo]
path = "../utxo"

View File

@ -1,205 +0,0 @@
use std::collections::HashMap;
use anyhow::Result;
use k256::AffinePoint;
use log::info;
use serde::{Deserialize, Serialize};
use storage::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier};
use utxo::{
utxo_core::{UTXOPayload, UTXO},
utxo_tree::UTXOSparseMerkleTree,
};
use crate::key_management::{
constants_types::{CipherText, Nonce},
ephemeral_key_holder::EphemeralKeyHolder,
AddressKeyHolder,
};
pub type PublicKey = AffinePoint;
pub type AccountAddress = TreeHashType;
pub struct Account {
pub key_holder: AddressKeyHolder,
pub address: AccountAddress,
pub balance: u64,
pub utxo_tree: UTXOSparseMerkleTree,
}
impl Account {
pub fn new() -> Self {
let key_holder = AddressKeyHolder::new_os_random();
let address = key_holder.address;
let balance = 0;
let utxo_tree = UTXOSparseMerkleTree::new();
Self {
key_holder,
address,
balance,
utxo_tree,
}
}
pub fn new_with_balance(balance: u64) -> Self {
let key_holder = AddressKeyHolder::new_os_random();
let address = key_holder.address;
let utxo_tree = UTXOSparseMerkleTree::new();
Self {
key_holder,
address,
balance,
utxo_tree,
}
}
pub fn produce_ephemeral_key_holder(&self) -> EphemeralKeyHolder {
self.key_holder.produce_ephemeral_key_holder()
}
pub fn encrypt_data(
ephemeral_key_holder: &EphemeralKeyHolder,
viewing_public_key_receiver: AffinePoint,
data: &[u8],
) -> (CipherText, Nonce) {
ephemeral_key_holder.encrypt_data(viewing_public_key_receiver, data)
}
pub fn decrypt_data(
&self,
ephemeral_public_key_sender: AffinePoint,
ciphertext: CipherText,
nonce: Nonce,
) -> Result<Vec<u8>, aes_gcm::Error> {
self.key_holder
.decrypt_data(ephemeral_public_key_sender, ciphertext, nonce)
}
pub fn mark_spent_utxo(
&mut self,
utxo_nullifier_map: HashMap<TreeHashType, UTXONullifier>,
) -> Result<()> {
for (hash, nullifier) in utxo_nullifier_map {
if let Some(utxo_entry) = self.utxo_tree.store.get_mut(&hash) {
utxo_entry.consume_utxo(nullifier)?;
}
}
Ok(())
}
pub fn add_new_utxo_outputs(&mut self, utxos: Vec<UTXO>) -> Result<()> {
Ok(self.utxo_tree.insert_items(utxos)?)
}
pub fn update_public_balance(&mut self, new_balance: u64) {
self.balance = new_balance;
}
pub fn add_asset<Asset: Serialize>(
&mut self,
asset: Asset,
amount: u128,
privacy_flag: bool,
) -> Result<()> {
let payload_with_asset = UTXOPayload {
owner: self.address,
asset: serde_json::to_vec(&asset)?,
amount,
privacy_flag,
};
let asset_utxo = UTXO::create_utxo_from_payload(payload_with_asset);
self.utxo_tree.insert_item(asset_utxo)?;
Ok(())
}
pub fn log(&self) {
info!("Keys generated");
info!("Account address is {:?}", hex::encode(self.address));
info!("Account balance is {:?}", self.balance);
}
}
impl Default for Account {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn generate_dummy_utxo_nullifier() -> UTXONullifier {
UTXONullifier::default()
}
fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> UTXO {
let payload = UTXOPayload {
owner: address,
asset: vec![],
amount,
privacy_flag: false,
};
UTXO::create_utxo_from_payload(payload)
}
#[test]
fn test_new_account() {
let account = Account::new();
assert_eq!(account.balance, 0);
assert!(account.key_holder.address != [0u8; 32]); // Check if the address is not empty
}
#[test]
fn test_mark_spent_utxo() {
let mut account = Account::new();
let utxo = generate_dummy_utxo(account.address, 100);
account.add_new_utxo_outputs(vec![utxo]).unwrap();
let mut utxo_nullifier_map = HashMap::new();
utxo_nullifier_map.insert(account.address, generate_dummy_utxo_nullifier());
let result = account.mark_spent_utxo(utxo_nullifier_map);
assert!(result.is_ok());
assert!(account.utxo_tree.store.get(&account.address).is_none());
}
#[test]
fn test_add_new_utxo_outputs() {
let mut account = Account::new();
let utxo1 = generate_dummy_utxo(account.address, 100);
let utxo2 = generate_dummy_utxo(account.address, 200);
let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]);
assert!(result.is_ok());
assert_eq!(account.utxo_tree.store.len(), 2);
}
#[test]
fn test_update_public_balance() {
let mut account = Account::new();
account.update_public_balance(500);
assert_eq!(account.balance, 500);
}
#[test]
fn test_add_asset() {
let mut account = Account::new();
let asset = "dummy_asset";
let amount = 1000u128;
let result = account.add_asset(asset, amount, false);
assert!(result.is_ok());
assert_eq!(account.utxo_tree.store.len(), 1);
}
}

View File

@ -1,17 +0,0 @@
use elliptic_curve::{
consts::{B0, B1},
generic_array::GenericArray,
};
use sha2::digest::typenum::{UInt, UTerm};
pub const NULLIFIER_SECRET_CONST: [u8; 32] = [
38, 29, 97, 210, 148, 172, 75, 220, 36, 249, 27, 111, 73, 14, 250, 38, 55, 87, 164, 169, 95,
101, 135, 28, 212, 241, 107, 46, 162, 60, 59, 93,
];
pub const VIEVING_SECRET_CONST: [u8; 32] = [
97, 23, 175, 117, 11, 48, 215, 162, 150, 103, 46, 195, 179, 178, 93, 52, 137, 190, 202, 60,
254, 87, 112, 250, 57, 242, 117, 206, 195, 149, 213, 206,
];
pub type CipherText = Vec<u8>;
pub type Nonce = GenericArray<u8, UInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>, B0>>;

View File

@ -1,62 +0,0 @@
use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, Key, KeyInit};
use elliptic_curve::group::GroupEncoding;
use elliptic_curve::PrimeField;
use k256::{AffinePoint, FieldBytes, Scalar};
use log::info;
use rand::{rngs::OsRng, RngCore};
use super::constants_types::{CipherText, Nonce};
#[derive(Debug)]
///Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral public keys. Can produce shared secret for sender.
pub struct EphemeralKeyHolder {
ephemeral_secret_key: Scalar,
}
impl EphemeralKeyHolder {
pub fn new_os_random() -> Self {
let mut bytes = FieldBytes::default();
OsRng.fill_bytes(&mut bytes);
Self {
ephemeral_secret_key: Scalar::from_repr(bytes).unwrap(),
}
}
pub fn generate_ephemeral_public_key(&self) -> AffinePoint {
(AffinePoint::GENERATOR * self.ephemeral_secret_key).into()
}
pub fn calculate_shared_secret_sender(
&self,
viewing_public_key_receiver: AffinePoint,
) -> AffinePoint {
(viewing_public_key_receiver * self.ephemeral_secret_key).into()
}
pub fn encrypt_data(
&self,
viewing_public_key_receiver: AffinePoint,
data: &[u8],
) -> (CipherText, Nonce) {
let key_point = self.calculate_shared_secret_sender(viewing_public_key_receiver);
let binding = key_point.to_bytes();
let key_raw = &binding.as_slice()[..32];
let key_raw_adjust: [u8; 32] = key_raw.try_into().unwrap();
let key: Key<Aes256Gcm> = key_raw_adjust.into();
let cipher = Aes256Gcm::new(&key);
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
(cipher.encrypt(&nonce, data).unwrap(), nonce)
}
pub fn log(&self) {
info!(
"Ephemeral private key is {:?}",
hex::encode(self.ephemeral_secret_key.to_bytes())
);
}
}

View File

@ -1,383 +0,0 @@
use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit};
use constants_types::{CipherText, Nonce};
use elliptic_curve::group::GroupEncoding;
use ephemeral_key_holder::EphemeralKeyHolder;
use k256::AffinePoint;
use log::info;
use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder};
use storage::merkle_tree_public::TreeHashType;
use crate::account_core::PublicKey;
pub mod constants_types;
pub mod ephemeral_key_holder;
pub mod secret_holders;
#[derive(Clone)]
///Entrypoint to key management
pub struct AddressKeyHolder {
//Will be useful in future
#[allow(dead_code)]
top_secret_key_holder: TopSecretKeyHolder,
pub utxo_secret_key_holder: UTXOSecretKeyHolder,
pub address: TreeHashType,
pub nullifer_public_key: PublicKey,
pub viewing_public_key: PublicKey,
}
impl AddressKeyHolder {
pub fn new_os_random() -> Self {
//Currently dropping SeedHolder at the end of initialization.
//Now entirely sure if we need it in the future.
let seed_holder = SeedHolder::new_os_random();
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
let utxo_secret_key_holder = top_secret_key_holder.produce_utxo_secret_holder();
let address = utxo_secret_key_holder.generate_address();
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
Self {
top_secret_key_holder,
utxo_secret_key_holder,
address,
nullifer_public_key,
viewing_public_key,
}
}
pub fn calculate_shared_secret_receiver(
&self,
ephemeral_public_key_sender: AffinePoint,
) -> AffinePoint {
(ephemeral_public_key_sender * self.utxo_secret_key_holder.viewing_secret_key).into()
}
pub fn produce_ephemeral_key_holder(&self) -> EphemeralKeyHolder {
EphemeralKeyHolder::new_os_random()
}
pub fn decrypt_data(
&self,
ephemeral_public_key_sender: AffinePoint,
ciphertext: CipherText,
nonce: Nonce,
) -> Result<Vec<u8>, aes_gcm::Error> {
let key_point = self.calculate_shared_secret_receiver(ephemeral_public_key_sender);
let binding = key_point.to_bytes();
let key_raw = &binding.as_slice()[..32];
let key_raw_adjust: [u8; 32] = key_raw.try_into().unwrap();
let key: Key<Aes256Gcm> = key_raw_adjust.into();
let cipher = Aes256Gcm::new(&key);
cipher.decrypt(&nonce, ciphertext.as_slice())
}
pub fn log(&self) {
info!(
"Secret spending key is {:?}",
hex::encode(self.top_secret_key_holder.secret_spending_key.to_bytes()),
);
info!(
"Nulifier secret key is {:?}",
hex::encode(self.utxo_secret_key_holder.nullifier_secret_key.to_bytes()),
);
info!(
"Viewing secret key is {:?}",
hex::encode(self.utxo_secret_key_holder.viewing_secret_key.to_bytes()),
);
info!(
"Nullifier public key is {:?}",
hex::encode(self.nullifer_public_key.to_bytes()),
);
info!(
"Viewing public key is {:?}",
hex::encode(self.viewing_public_key.to_bytes()),
);
}
}
#[cfg(test)]
mod tests {
use aes_gcm::{
aead::{Aead, KeyInit, OsRng},
Aes256Gcm,
};
use constants_types::{CipherText, Nonce};
use constants_types::{NULLIFIER_SECRET_CONST, VIEVING_SECRET_CONST};
use elliptic_curve::ff::Field;
use elliptic_curve::group::prime::PrimeCurveAffine;
use elliptic_curve::group::GroupEncoding;
use k256::{AffinePoint, ProjectivePoint, Scalar};
use super::*;
#[test]
fn test_new_os_random() {
// Ensure that a new AddressKeyHolder instance can be created without errors.
let address_key_holder = AddressKeyHolder::new_os_random();
// Check that key holder fields are initialized with expected types
assert!(!Into::<bool>::into(
address_key_holder.nullifer_public_key.is_identity()
));
assert!(!Into::<bool>::into(
address_key_holder.viewing_public_key.is_identity()
));
}
#[test]
fn test_calculate_shared_secret_receiver() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Generate a random ephemeral public key sender
let scalar = Scalar::random(&mut OsRng);
let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine();
// Calculate shared secret
let shared_secret =
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
// Ensure the shared secret is not an identity point (suggesting non-zero output)
assert!(!Into::<bool>::into(shared_secret.is_identity()));
}
#[test]
fn test_decrypt_data() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Generate an ephemeral key and shared secret
let scalar = Scalar::random(OsRng);
let ephemeral_public_key_sender = address_key_holder
.produce_ephemeral_key_holder()
.generate_ephemeral_public_key();
let shared_secret =
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
// Prepare the encryption key from shared secret
let key_raw = shared_secret.to_bytes();
let key_raw_adjust_pre = &key_raw.as_slice()[..32];
let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap();
let key: Key<Aes256Gcm> = key_raw_adjust.into();
let cipher = Aes256Gcm::new(&key);
// Encrypt sample data
let nonce = Nonce::from_slice(b"unique nonce");
let plaintext = b"Sensitive data";
let ciphertext = cipher
.encrypt(nonce, plaintext.as_ref())
.expect("encryption failure");
// Attempt decryption
let decrypted_data: Vec<u8> = address_key_holder
.decrypt_data(
ephemeral_public_key_sender,
CipherText::from(ciphertext),
nonce.clone(),
)
.unwrap();
// Verify decryption is successful and matches original plaintext
assert_eq!(decrypted_data, plaintext);
}
#[test]
fn test_new_os_random_initialization() {
// Ensure that AddressKeyHolder is initialized correctly
let address_key_holder = AddressKeyHolder::new_os_random();
// Check that key holder fields are initialized with expected types and values
assert!(!Into::<bool>::into(
address_key_holder.nullifer_public_key.is_identity()
));
assert!(!Into::<bool>::into(
address_key_holder.viewing_public_key.is_identity()
));
assert!(address_key_holder.address.as_slice().len() > 0); // Assume TreeHashType has non-zero length for a valid address
}
#[test]
fn test_calculate_shared_secret_with_identity_point() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Use identity point as ephemeral public key
let identity_point = AffinePoint::identity();
// Calculate shared secret
let shared_secret = address_key_holder.calculate_shared_secret_receiver(identity_point);
// The shared secret with the identity point should also result in the identity point
assert!(Into::<bool>::into(shared_secret.is_identity()));
}
#[test]
#[should_panic]
fn test_decrypt_data_with_incorrect_nonce() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Generate ephemeral public key and shared secret
let scalar = Scalar::random(OsRng);
let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine();
let shared_secret =
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
// Prepare the encryption key from shared secret
let key_raw = shared_secret.to_bytes();
let key_raw_adjust_pre = &key_raw.as_slice()[..32];
let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap();
let key: Key<Aes256Gcm> = key_raw_adjust.into();
let cipher = Aes256Gcm::new(&key);
// Encrypt sample data with a specific nonce
let nonce = Nonce::from_slice(b"unique nonce");
let plaintext = b"Sensitive data";
let ciphertext = cipher
.encrypt(nonce, plaintext.as_ref())
.expect("encryption failure");
// Attempt decryption with an incorrect nonce
let incorrect_nonce = Nonce::from_slice(b"wrong nonce");
let decrypted_data = address_key_holder
.decrypt_data(
ephemeral_public_key_sender,
CipherText::from(ciphertext.clone()),
incorrect_nonce.clone(),
)
.unwrap();
// The decryption should fail or produce incorrect output due to nonce mismatch
assert_ne!(decrypted_data, plaintext);
}
#[test]
#[should_panic]
fn test_decrypt_data_with_incorrect_ciphertext() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Generate ephemeral public key and shared secret
let scalar = Scalar::random(OsRng);
let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine();
let shared_secret =
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
// Prepare the encryption key from shared secret
let key_raw = shared_secret.to_bytes();
let key_raw_adjust_pre = &key_raw.as_slice()[..32];
let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap();
let key: Key<Aes256Gcm> = key_raw_adjust.into();
let cipher = Aes256Gcm::new(&key);
// Encrypt sample data
let nonce = Nonce::from_slice(b"unique nonce");
let plaintext = b"Sensitive data";
let ciphertext = cipher
.encrypt(nonce, plaintext.as_ref())
.expect("encryption failure");
// Tamper with the ciphertext to simulate corruption
let mut corrupted_ciphertext = ciphertext.clone();
corrupted_ciphertext[0] ^= 1; // Flip a bit in the ciphertext
// Attempt decryption
let result = address_key_holder
.decrypt_data(
ephemeral_public_key_sender,
CipherText::from(corrupted_ciphertext),
nonce.clone(),
)
.unwrap();
// The decryption should fail or produce incorrect output due to tampered ciphertext
assert_ne!(result, plaintext);
}
#[test]
fn test_encryption_decryption_round_trip() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Generate ephemeral key and shared secret
let scalar = Scalar::random(OsRng);
let ephemeral_public_key_sender = (ProjectivePoint::generator() * scalar).to_affine();
// Encrypt sample data
let plaintext = b"Round-trip test data";
let nonce = Nonce::from_slice(b"unique nonce");
let shared_secret =
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
// Prepare the encryption key from shared secret
let key_raw = shared_secret.to_bytes();
let key_raw_adjust_pre = &key_raw.as_slice()[..32];
let key_raw_adjust: [u8; 32] = key_raw_adjust_pre.try_into().unwrap();
let key: Key<Aes256Gcm> = key_raw_adjust.into();
let cipher = Aes256Gcm::new(&key);
let ciphertext = cipher
.encrypt(nonce, plaintext.as_ref())
.expect("encryption failure");
// Decrypt the data using the `AddressKeyHolder` instance
let decrypted_data = address_key_holder
.decrypt_data(
ephemeral_public_key_sender,
CipherText::from(ciphertext),
nonce.clone(),
)
.unwrap();
// Verify the decrypted data matches the original plaintext
assert_eq!(decrypted_data, plaintext);
}
#[test]
fn key_generation_test() {
let seed_holder = SeedHolder::new_os_random();
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
let utxo_secret_key_holder = top_secret_key_holder.produce_utxo_secret_holder();
let address = utxo_secret_key_holder.generate_address();
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
println!("======Prerequisites======");
println!();
println!(
"Group generator {:?}",
hex::encode(AffinePoint::GENERATOR.to_bytes())
);
println!(
"Nullifier constant {:?}",
hex::encode(NULLIFIER_SECRET_CONST)
);
println!("Viewing constatnt {:?}", hex::encode(VIEVING_SECRET_CONST));
println!();
println!("======Holders======");
println!();
println!("{seed_holder:?}");
println!("{top_secret_key_holder:?}");
println!("{utxo_secret_key_holder:?}");
println!();
println!("======Public data======");
println!();
println!("Address{:?}", hex::encode(address));
println!(
"Nulifier public key {:?}",
hex::encode(nullifer_public_key.to_bytes())
);
println!(
"Viewing public key {:?}",
hex::encode(viewing_public_key.to_bytes())
);
}
}

View File

@ -1,113 +0,0 @@
use elliptic_curve::group::GroupEncoding;
use elliptic_curve::PrimeField;
use k256::{AffinePoint, FieldBytes, Scalar};
use rand::{rngs::OsRng, RngCore};
use sha2::{digest::FixedOutput, Digest};
use storage::merkle_tree_public::TreeHashType;
use super::constants_types::{NULLIFIER_SECRET_CONST, VIEVING_SECRET_CONST};
#[derive(Debug)]
///Seed holder. Non-clonable to ensure that different holders use different seeds.
/// Produces `TopSecretKeyHolder` objects.
pub struct SeedHolder {
seed: Scalar,
}
#[derive(Debug, Clone)]
///Secret spending key holder. Produces `UTXOSecretKeyHolder` objects.
pub struct TopSecretKeyHolder {
pub secret_spending_key: Scalar,
}
#[derive(Debug, Clone)]
///Nullifier secret key and viewing secret key holder. Produces public keys. Can produce address. Can produce shared secret for recepient.
pub struct UTXOSecretKeyHolder {
pub nullifier_secret_key: Scalar,
pub viewing_secret_key: Scalar,
}
impl SeedHolder {
pub fn new_os_random() -> Self {
let mut bytes = FieldBytes::default();
OsRng.fill_bytes(&mut bytes);
Self {
seed: Scalar::from_repr(bytes).unwrap(),
}
}
pub fn generate_secret_spending_key_hash(&self) -> TreeHashType {
let mut hasher = sha2::Sha256::new();
hasher.update(self.seed.to_bytes());
<TreeHashType>::from(hasher.finalize_fixed())
}
pub fn generate_secret_spending_key_scalar(&self) -> Scalar {
let hash = self.generate_secret_spending_key_hash();
Scalar::from_repr(hash.into()).unwrap()
}
pub fn produce_top_secret_key_holder(&self) -> TopSecretKeyHolder {
TopSecretKeyHolder {
secret_spending_key: self.generate_secret_spending_key_scalar(),
}
}
}
impl TopSecretKeyHolder {
pub fn generate_nullifier_secret_key(&self) -> Scalar {
let mut hasher = sha2::Sha256::new();
hasher.update(self.secret_spending_key.to_bytes());
hasher.update(NULLIFIER_SECRET_CONST);
let hash = <TreeHashType>::from(hasher.finalize_fixed());
Scalar::from_repr(hash.into()).unwrap()
}
pub fn generate_viewing_secret_key(&self) -> Scalar {
let mut hasher = sha2::Sha256::new();
hasher.update(self.secret_spending_key.to_bytes());
hasher.update(VIEVING_SECRET_CONST);
let hash = <TreeHashType>::from(hasher.finalize_fixed());
Scalar::from_repr(hash.into()).unwrap()
}
pub fn produce_utxo_secret_holder(&self) -> UTXOSecretKeyHolder {
UTXOSecretKeyHolder {
nullifier_secret_key: self.generate_nullifier_secret_key(),
viewing_secret_key: self.generate_viewing_secret_key(),
}
}
}
impl UTXOSecretKeyHolder {
pub fn generate_nullifier_public_key(&self) -> AffinePoint {
(AffinePoint::GENERATOR * self.nullifier_secret_key).into()
}
pub fn generate_viewing_public_key(&self) -> AffinePoint {
(AffinePoint::GENERATOR * self.viewing_secret_key).into()
}
pub fn generate_address(&self) -> TreeHashType {
let npk = self.generate_nullifier_public_key();
let vpk = self.generate_viewing_public_key();
let mut hasher = sha2::Sha256::new();
hasher.update(npk.to_bytes());
hasher.update(vpk.to_bytes());
<TreeHashType>::from(hasher.finalize_fixed())
}
}

View File

@ -1,2 +0,0 @@
pub mod account_core;
pub mod key_management;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +0,0 @@
set -e
curl -L https://risczero.com/install | bash
/Users/runner/.risc0/bin/rzup install
cargo build

View File

@ -1,4 +0,0 @@
set -e
curl -L https://risczero.com/install | bash
/home/runner/.risc0/bin/rzup install
cargo build

84
ci_scripts/deploy.sh Normal file
View File

@ -0,0 +1,84 @@
#!/usr/bin/env bash
set -e
# Base directory for deployment
LSSA_DIR="/home/arjentix/test_deploy/lssa"
# Expect GITHUB_ACTOR to be passed as first argument or environment variable
GITHUB_ACTOR="${1:-${GITHUB_ACTOR:-unknown}}"
# Function to log messages with timestamp
log_deploy() {
echo "[$(date '+%Y-%m-%d %H:%M:%S %Z')] $1" >> "${LSSA_DIR}/deploy.log"
}
# Error handler
handle_error() {
echo "✗ Deployment failed by: ${GITHUB_ACTOR}"
log_deploy "Deployment failed by: ${GITHUB_ACTOR}"
exit 1
}
find_sequencer_runner_pids() {
pgrep -f "sequencer_runner" | grep -v $$
}
# Set trap to catch any errors
trap 'handle_error' ERR
# Log deployment info
log_deploy "Deployment initiated by: ${GITHUB_ACTOR}"
# Navigate to code directory
if [ ! -d "${LSSA_DIR}/code" ]; then
mkdir -p "${LSSA_DIR}/code"
fi
cd "${LSSA_DIR}/code"
# Stop current sequencer if running
if find_sequencer_runner_pids > /dev/null; then
echo "Stopping current sequencer..."
find_sequencer_runner_pids | xargs -r kill -SIGINT || true
sleep 2
# Force kill if still running
find_sequencer_runner_pids | grep -v $$ | xargs -r kill -9 || true
fi
# Clone or update repository
if [ -d ".git" ]; then
echo "Updating existing repository..."
git fetch origin
git checkout main
git reset --hard origin/main
else
echo "Cloning repository..."
git clone https://github.com/vacp2p/nescience-testnet.git .
git checkout main
fi
# Build sequencer_runner and wallet in release mode
echo "Building sequencer_runner"
# That could be just `cargo build --release --bin sequencer_runner --bin wallet`
# but we have `no_docker` feature bug, see issue #179
cd sequencer_runner
cargo build --release
cd ../wallet
cargo build --release
cd ..
# Run sequencer_runner with config
echo "Starting sequencer_runner..."
export RUST_LOG=info
nohup ./target/release/sequencer_runner "${LSSA_DIR}/configs/sequencer" > "${LSSA_DIR}/sequencer.log" 2>&1 &
# Wait 5 seconds and check health using wallet
sleep 5
if ./target/release/wallet check-health; then
echo "✓ Sequencer started successfully and is healthy"
log_deploy "Deployment completed successfully by: ${GITHUB_ACTOR}"
exit 0
else
echo "✗ Sequencer failed health check"
tail -n 50 "${LSSA_DIR}/sequencer.log"
handle_error
fi

View File

@ -1,8 +0,0 @@
set -e
curl -L https://risczero.com/install | bash
/home/runner/.risc0/bin/rzup install
cargo install taplo-cli --locked
cargo fmt -- --check
taplo fmt --check

View File

@ -1,6 +0,0 @@
set -e
curl -L https://risczero.com/install | bash
/home/runner/.risc0/bin/rzup install
cargo test --release

View File

@ -1,17 +1,19 @@
[package]
name = "utxo"
name = "common"
version = "0.1.0"
edition = "2021"
edition = "2024"
[dependencies]
anyhow.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true
serde.workspace = true
monotree.workspace = true
sha2.workspace = true
hex.workspace = true
nssa.workspace = true
nssa_core.workspace = true
[dependencies.storage]
path = "../storage"
anyhow.workspace = true
thiserror.workspace = true
serde_json.workspace = true
serde.workspace = true
reqwest.workspace = true
sha2.workspace = true
log.workspace = true
hex.workspace = true
borsh.workspace = true
base64.workspace = true

98
common/src/block.rs Normal file
View File

@ -0,0 +1,98 @@
use borsh::{BorshDeserialize, BorshSerialize};
use sha2::{Digest, Sha256, digest::FixedOutput};
use crate::transaction::EncodedTransaction;
pub type HashType = [u8; 32];
#[derive(Debug, Clone)]
/// Our own hasher.
/// Currently it is SHA256 hasher wrapper. May change in a future.
pub struct OwnHasher {}
impl OwnHasher {
fn hash(data: &[u8]) -> HashType {
let mut hasher = Sha256::new();
hasher.update(data);
<HashType>::from(hasher.finalize_fixed())
}
}
pub type BlockHash = [u8; 32];
pub type BlockId = u64;
pub type TimeStamp = u64;
#[derive(Debug, Clone)]
pub struct BlockHeader {
pub block_id: BlockId,
pub prev_block_hash: BlockHash,
pub hash: BlockHash,
pub timestamp: TimeStamp,
pub signature: nssa::Signature,
}
#[derive(Debug, Clone)]
pub struct BlockBody {
pub transactions: Vec<EncodedTransaction>,
}
#[derive(Debug, Clone)]
pub struct Block {
pub header: BlockHeader,
pub body: BlockBody,
}
#[derive(Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
pub struct HashableBlockData {
pub block_id: BlockId,
pub prev_block_hash: BlockHash,
pub timestamp: TimeStamp,
pub transactions: Vec<EncodedTransaction>,
}
impl HashableBlockData {
pub fn into_block(self, signing_key: &nssa::PrivateKey) -> Block {
let data_bytes = borsh::to_vec(&self).unwrap();
let signature = nssa::Signature::new(signing_key, &data_bytes);
let hash = OwnHasher::hash(&data_bytes);
Block {
header: BlockHeader {
block_id: self.block_id,
prev_block_hash: self.prev_block_hash,
hash,
timestamp: self.timestamp,
signature,
},
body: BlockBody {
transactions: self.transactions,
},
}
}
}
impl From<Block> for HashableBlockData {
fn from(value: Block) -> Self {
Self {
block_id: value.header.block_id,
prev_block_hash: value.header.prev_block_hash,
timestamp: value.header.timestamp,
transactions: value.body.transactions,
}
}
}
#[cfg(test)]
mod tests {
use crate::{block::HashableBlockData, test_utils};
#[test]
fn test_encoding_roundtrip() {
let transactions = vec![test_utils::produce_dummy_empty_transaction()];
let block = test_utils::produce_dummy_block(1, Some([1; 32]), transactions);
let hashable = HashableBlockData::from(block);
let bytes = borsh::to_vec(&hashable).unwrap();
let block_from_bytes = borsh::from_slice::<HashableBlockData>(&bytes).unwrap();
assert_eq!(hashable, block_from_bytes);
}
}

55
common/src/error.rs Normal file
View File

@ -0,0 +1,55 @@
use nssa::AccountId;
use serde::Deserialize;
use crate::rpc_primitives::errors::RpcError;
#[derive(Debug, Clone, Deserialize)]
pub struct SequencerRpcError {
pub jsonrpc: String,
pub error: RpcError,
pub id: u64,
}
#[derive(thiserror::Error, Debug)]
pub enum SequencerClientError {
#[error("HTTP error")]
HTTPError(reqwest::Error),
#[error("Serde error")]
SerdeError(serde_json::Error),
#[error("Internal error")]
InternalError(SequencerRpcError),
}
impl From<reqwest::Error> for SequencerClientError {
fn from(value: reqwest::Error) -> Self {
SequencerClientError::HTTPError(value)
}
}
impl From<serde_json::Error> for SequencerClientError {
fn from(value: serde_json::Error) -> Self {
SequencerClientError::SerdeError(value)
}
}
impl From<SequencerRpcError> for SequencerClientError {
fn from(value: SequencerRpcError) -> Self {
SequencerClientError::InternalError(value)
}
}
#[derive(Debug, thiserror::Error)]
pub enum ExecutionFailureKind {
#[error("Failed to get account data from sequencer")]
SequencerError,
#[error("Inputs amounts does not match outputs")]
AmountMismatchError,
#[error("Accounts key not found")]
KeyNotFoundError,
#[error("Sequencer client error: {0:?}")]
SequencerClientError(#[from] SequencerClientError),
#[error("Can not pay for operation")]
InsufficientFundsError,
#[error("Account {0} data is invalid")]
AccountDataError(AccountId),
}

12
common/src/lib.rs Normal file
View File

@ -0,0 +1,12 @@
pub mod block;
pub mod error;
pub mod rpc_primitives;
pub mod sequencer_client;
pub mod transaction;
// Module for tests utility functions
// TODO: Compile only for tests
pub mod test_utils;
pub type HashType = [u8; 32];
pub const PINATA_BASE58: &str = "EfQhKQAkX2FJiwNii2WFQsGndjvF1Mzd7RuVe7QdPLw7";

View File

@ -1,6 +1,7 @@
use serde_json::{to_value, Value};
use std::fmt;
use serde_json::{Value, to_value};
#[derive(serde::Serialize)]
pub struct RpcParseError(pub String);
@ -65,7 +66,7 @@ impl RpcError {
return Self::server_error(Some(format!(
"Failed to serialize invalid parameters error: {:?}",
err.to_string()
)))
)));
}
};
RpcError::new(-32_602, "Invalid params".to_owned(), Some(value))
@ -178,7 +179,7 @@ impl From<ServerError> for RpcError {
let error_data = match to_value(&e) {
Ok(value) => value,
Err(_err) => {
return RpcError::new_internal_error(None, "Failed to serialize ServerError")
return RpcError::new_internal_error(None, "Failed to serialize ServerError");
}
};
RpcError::new_internal_error(Some(error_data), e.to_string().as_str())

View File

@ -9,11 +9,14 @@
//!
//! The main entrypoint here is the [Message](enum.Message.html). The others are just building
//! blocks and you should generally work with `Message` instead.
use serde::de::{Deserializer, Error, Unexpected, Visitor};
use serde::ser::{SerializeStruct, Serializer};
use serde_json::{Result as JsonResult, Value};
use std::fmt::{Formatter, Result as FmtResult};
use serde::{
de::{Deserializer, Error, Unexpected, Visitor},
ser::{SerializeStruct, Serializer},
};
use serde_json::{Result as JsonResult, Value};
use super::errors::RpcError;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -59,6 +62,16 @@ pub struct Request {
}
impl Request {
pub fn from_payload_version_2_0(method: String, payload: serde_json::Value) -> Self {
Self {
jsonrpc: Version,
method,
params: payload,
// ToDo: Correct checking of id
id: 1.into(),
}
}
/// Answer the request with a (positive) reply.
///
/// The ID is taken from the request.
@ -69,6 +82,7 @@ impl Request {
id: self.id.clone(),
})
}
/// Answer the request with an error.
pub fn error(&self, error: RpcError) -> Message {
Message::Response(Response {
@ -207,6 +221,7 @@ impl Message {
id,
})
}
/// Create a top-level error (without an ID).
pub fn error(error: RpcError) -> Self {
Message::Response(Response {
@ -215,6 +230,7 @@ impl Message {
id: Value::Null,
})
}
/// A constructor for a notification.
pub fn notification(method: String, params: Value) -> Self {
Message::Notification(Notification {
@ -223,6 +239,7 @@ impl Message {
params,
})
}
/// A constructor for a response.
pub fn response(id: Value, result: Result<Value, RpcError>) -> Self {
Message::Response(Response {
@ -231,6 +248,7 @@ impl Message {
id,
})
}
/// Returns id or Null if there is no id.
pub fn id(&self) -> Value {
match self {
@ -315,10 +333,7 @@ impl From<Message> for Vec<u8> {
#[cfg(test)]
mod tests {
use serde_json::de::from_slice;
use serde_json::json;
use serde_json::ser::to_vec;
use serde_json::Value;
use serde_json::{Value, de::from_slice, json, ser::to_vec};
use super::*;
@ -447,7 +462,7 @@ mod tests {
/// A helper for the `broken` test.
///
/// Check that the given JSON string parses, but is not recognized as a valid RPC message.
///
/// Test things that are almost but not entirely JSONRPC are rejected
///
/// The reject is done by returning it as Unmatched.

View File

@ -1,25 +1,9 @@
use std::time::Duration;
use serde::{Deserialize, Serialize};
pub mod errors;
pub mod message;
pub mod parser;
#[derive(Serialize, Deserialize, Clone, Copy, Debug)]
pub struct RpcPollingConfig {
pub polling_interval: Duration,
pub polling_timeout: Duration,
}
impl Default for RpcPollingConfig {
fn default() -> Self {
Self {
polling_interval: Duration::from_millis(500),
polling_timeout: Duration::from_secs(10),
}
}
}
pub mod requests;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct RpcLimitsConfig {
@ -39,7 +23,6 @@ impl Default for RpcLimitsConfig {
pub struct RpcConfig {
pub addr: String,
pub cors_allowed_origins: Vec<String>,
pub polling_config: RpcPollingConfig,
#[serde(default)]
pub limits_config: RpcLimitsConfig,
}
@ -49,7 +32,6 @@ impl Default for RpcConfig {
RpcConfig {
addr: "0.0.0.0:3040".to_owned(),
cors_allowed_origins: vec!["*".to_owned()],
polling_config: RpcPollingConfig::default(),
limits_config: RpcLimitsConfig::default(),
}
}

View File

@ -1,7 +1,7 @@
use serde::de::DeserializeOwned;
use serde_json::Value;
use crate::errors::RpcParseError;
use super::errors::RpcParseError;
pub trait RpcRequest: Sized {
fn parse(value: Option<Value>) -> Result<Self, RpcParseError>;

View File

@ -0,0 +1,218 @@
use std::collections::HashMap;
use nssa_core::program::ProgramId;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use super::{
errors::RpcParseError,
parser::{RpcRequest, parse_params},
};
use crate::parse_request;
#[derive(Serialize, Deserialize, Debug)]
pub struct HelloRequest {}
#[derive(Serialize, Deserialize, Debug)]
pub struct RegisterAccountRequest {
pub account_id: [u8; 32],
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SendTxRequest {
#[serde(with = "base64_deser")]
pub transaction: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetBlockDataRequest {
pub block_id: u64,
}
/// Get a range of blocks from `start_block_id` to `end_block_id` (inclusive)
#[derive(Serialize, Deserialize, Debug)]
pub struct GetBlockRangeDataRequest {
pub start_block_id: u64,
pub end_block_id: u64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetGenesisIdRequest {}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetLastBlockRequest {}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetInitialTestnetAccountsRequest {}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetAccountBalanceRequest {
pub account_id: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetTransactionByHashRequest {
pub hash: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetAccountsNoncesRequest {
pub account_ids: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetAccountRequest {
pub account_id: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetProofForCommitmentRequest {
pub commitment: nssa_core::Commitment,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetProgramIdsRequest {}
parse_request!(HelloRequest);
parse_request!(RegisterAccountRequest);
parse_request!(SendTxRequest);
parse_request!(GetBlockDataRequest);
parse_request!(GetBlockRangeDataRequest);
parse_request!(GetGenesisIdRequest);
parse_request!(GetLastBlockRequest);
parse_request!(GetInitialTestnetAccountsRequest);
parse_request!(GetAccountBalanceRequest);
parse_request!(GetTransactionByHashRequest);
parse_request!(GetAccountsNoncesRequest);
parse_request!(GetProofForCommitmentRequest);
parse_request!(GetAccountRequest);
parse_request!(GetProgramIdsRequest);
#[derive(Serialize, Deserialize, Debug)]
pub struct HelloResponse {
pub greeting: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct RegisterAccountResponse {
pub status: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SendTxResponse {
pub status: String,
pub tx_hash: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetBlockDataResponse {
#[serde(with = "base64_deser")]
pub block: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetBlockRangeDataResponse {
#[serde(with = "base64_deser::vec")]
pub blocks: Vec<Vec<u8>>,
}
mod base64_deser {
use base64::{Engine as _, engine::general_purpose};
use serde::{self, Deserialize, Deserializer, Serializer, ser::SerializeSeq as _};
pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let base64_string = general_purpose::STANDARD.encode(bytes);
serializer.serialize_str(&base64_string)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
let base64_string: String = Deserialize::deserialize(deserializer)?;
general_purpose::STANDARD
.decode(&base64_string)
.map_err(serde::de::Error::custom)
}
pub mod vec {
use super::*;
pub fn serialize<S>(bytes_vec: &[Vec<u8>], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(bytes_vec.len()))?;
for bytes in bytes_vec {
let s = general_purpose::STANDARD.encode(bytes);
seq.serialize_element(&s)?;
}
seq.end()
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error>
where
D: Deserializer<'de>,
{
let base64_strings: Vec<String> = Deserialize::deserialize(deserializer)?;
base64_strings
.into_iter()
.map(|s| {
general_purpose::STANDARD
.decode(&s)
.map_err(serde::de::Error::custom)
})
.collect()
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetGenesisIdResponse {
pub genesis_id: u64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetLastBlockResponse {
pub last_block: u64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetAccountBalanceResponse {
pub balance: u128,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetAccountsNoncesResponse {
pub nonces: Vec<u128>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetTransactionByHashResponse {
pub transaction: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetAccountResponse {
pub account: nssa::Account,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetProofForCommitmentResponse {
pub membership_proof: Option<nssa_core::MembershipProof>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetProgramIdsResponse {
pub program_ids: HashMap<String, ProgramId>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GetInitialTestnetAccountsResponse {
/// Hex encoded account id
pub account_id: String,
pub balance: u64,
}

View File

@ -0,0 +1,344 @@
use std::{collections::HashMap, ops::RangeInclusive};
use anyhow::Result;
use nssa_core::program::ProgramId;
use reqwest::Client;
use serde::Deserialize;
use serde_json::Value;
use super::rpc_primitives::requests::{
GetAccountBalanceRequest, GetAccountBalanceResponse, GetBlockDataRequest, GetBlockDataResponse,
GetGenesisIdRequest, GetGenesisIdResponse, GetInitialTestnetAccountsRequest,
};
use crate::{
error::{SequencerClientError, SequencerRpcError},
rpc_primitives::{
self,
requests::{
GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest,
GetAccountsNoncesResponse, GetBlockRangeDataRequest, GetBlockRangeDataResponse,
GetInitialTestnetAccountsResponse, GetLastBlockRequest, GetLastBlockResponse,
GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest,
GetProofForCommitmentResponse, GetTransactionByHashRequest,
GetTransactionByHashResponse, SendTxRequest, SendTxResponse,
},
},
transaction::{EncodedTransaction, NSSATransaction},
};
#[derive(Clone)]
pub struct SequencerClient {
pub client: reqwest::Client,
pub sequencer_addr: String,
pub basic_auth: Option<(String, Option<String>)>,
}
impl SequencerClient {
pub fn new(sequencer_addr: String) -> Result<Self> {
Self::new_with_auth(sequencer_addr, None)
}
pub fn new_with_auth(
sequencer_addr: String,
basic_auth: Option<(String, Option<String>)>,
) -> Result<Self> {
Ok(Self {
client: Client::builder()
//Add more fiedls if needed
.timeout(std::time::Duration::from_secs(60))
.build()?,
sequencer_addr,
basic_auth,
})
}
pub async fn call_method_with_payload(
&self,
method: &str,
payload: Value,
) -> Result<Value, SequencerClientError> {
let request =
rpc_primitives::message::Request::from_payload_version_2_0(method.to_string(), payload);
let mut call_builder = self.client.post(&self.sequencer_addr);
if let Some((username, password)) = &self.basic_auth {
call_builder = call_builder.basic_auth(username, password.as_deref());
}
let call_res = call_builder.json(&request).send().await?;
let response_vall = call_res.json::<Value>().await?;
#[derive(Debug, Clone, Deserialize)]
#[allow(dead_code)]
pub struct SequencerRpcResponse {
pub jsonrpc: String,
pub result: serde_json::Value,
pub id: u64,
}
if let Ok(response) = serde_json::from_value::<SequencerRpcResponse>(response_vall.clone())
{
Ok(response.result)
} else {
let err_resp = serde_json::from_value::<SequencerRpcError>(response_vall)?;
Err(err_resp.into())
}
}
/// Get block data at `block_id` from sequencer
pub async fn get_block(
&self,
block_id: u64,
) -> Result<GetBlockDataResponse, SequencerClientError> {
let block_req = GetBlockDataRequest { block_id };
let req = serde_json::to_value(block_req)?;
let resp = self.call_method_with_payload("get_block", req).await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
pub async fn get_block_range(
&self,
range: RangeInclusive<u64>,
) -> Result<GetBlockRangeDataResponse, SequencerClientError> {
let block_req = GetBlockRangeDataRequest {
start_block_id: *range.start(),
end_block_id: *range.end(),
};
let req = serde_json::to_value(block_req)?;
let resp = self
.call_method_with_payload("get_block_range", req)
.await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
/// Get last known `blokc_id` from sequencer
pub async fn get_last_block(&self) -> Result<GetLastBlockResponse, SequencerClientError> {
let block_req = GetLastBlockRequest {};
let req = serde_json::to_value(block_req)?;
let resp = self.call_method_with_payload("get_last_block", req).await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
/// Get account public balance for `account_id`. `account_id` must be a valid hex-string for 32
/// bytes.
pub async fn get_account_balance(
&self,
account_id: String,
) -> Result<GetAccountBalanceResponse, SequencerClientError> {
let block_req = GetAccountBalanceRequest { account_id };
let req = serde_json::to_value(block_req)?;
let resp = self
.call_method_with_payload("get_account_balance", req)
.await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
/// Get accounts nonces for `account_ids`. `account_ids` must be a list of valid hex-strings for
/// 32 bytes.
pub async fn get_accounts_nonces(
&self,
account_ids: Vec<String>,
) -> Result<GetAccountsNoncesResponse, SequencerClientError> {
let block_req = GetAccountsNoncesRequest { account_ids };
let req = serde_json::to_value(block_req)?;
let resp = self
.call_method_with_payload("get_accounts_nonces", req)
.await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
pub async fn get_account(
&self,
account_id: String,
) -> Result<GetAccountResponse, SequencerClientError> {
let block_req = GetAccountRequest { account_id };
let req = serde_json::to_value(block_req)?;
let resp = self.call_method_with_payload("get_account", req).await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
/// Get transaction details for `hash`.
pub async fn get_transaction_by_hash(
&self,
hash: String,
) -> Result<GetTransactionByHashResponse, SequencerClientError> {
let block_req = GetTransactionByHashRequest { hash };
let req = serde_json::to_value(block_req)?;
let resp = self
.call_method_with_payload("get_transaction_by_hash", req)
.await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
/// Send transaction to sequencer
pub async fn send_tx_public(
&self,
transaction: nssa::PublicTransaction,
) -> Result<SendTxResponse, SequencerClientError> {
let transaction = EncodedTransaction::from(NSSATransaction::Public(transaction));
let tx_req = SendTxRequest {
transaction: borsh::to_vec(&transaction).unwrap(),
};
let req = serde_json::to_value(tx_req)?;
let resp = self.call_method_with_payload("send_tx", req).await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
/// Send transaction to sequencer
pub async fn send_tx_private(
&self,
transaction: nssa::PrivacyPreservingTransaction,
) -> Result<SendTxResponse, SequencerClientError> {
let transaction = EncodedTransaction::from(NSSATransaction::PrivacyPreserving(transaction));
let tx_req = SendTxRequest {
transaction: borsh::to_vec(&transaction).unwrap(),
};
let req = serde_json::to_value(tx_req)?;
let resp = self.call_method_with_payload("send_tx", req).await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
/// Get genesis id from sequencer
pub async fn get_genesis_id(&self) -> Result<GetGenesisIdResponse, SequencerClientError> {
let genesis_req = GetGenesisIdRequest {};
let req = serde_json::to_value(genesis_req).unwrap();
let resp = self
.call_method_with_payload("get_genesis", req)
.await
.unwrap();
let resp_deser = serde_json::from_value(resp).unwrap();
Ok(resp_deser)
}
/// Get initial testnet accounts from sequencer
pub async fn get_initial_testnet_accounts(
&self,
) -> Result<Vec<GetInitialTestnetAccountsResponse>, SequencerClientError> {
let acc_req = GetInitialTestnetAccountsRequest {};
let req = serde_json::to_value(acc_req).unwrap();
let resp = self
.call_method_with_payload("get_initial_testnet_accounts", req)
.await
.unwrap();
let resp_deser = serde_json::from_value(resp).unwrap();
Ok(resp_deser)
}
/// Get proof for commitment
pub async fn get_proof_for_commitment(
&self,
commitment: nssa_core::Commitment,
) -> Result<Option<nssa_core::MembershipProof>, SequencerClientError> {
let acc_req = GetProofForCommitmentRequest { commitment };
let req = serde_json::to_value(acc_req).unwrap();
let resp = self
.call_method_with_payload("get_proof_for_commitment", req)
.await
.unwrap();
let resp_deser = serde_json::from_value::<GetProofForCommitmentResponse>(resp)
.unwrap()
.membership_proof;
Ok(resp_deser)
}
pub async fn send_tx_program(
&self,
transaction: nssa::ProgramDeploymentTransaction,
) -> Result<SendTxResponse, SequencerClientError> {
let transaction = EncodedTransaction::from(NSSATransaction::ProgramDeployment(transaction));
let tx_req = SendTxRequest {
transaction: borsh::to_vec(&transaction).unwrap(),
};
let req = serde_json::to_value(tx_req)?;
let resp = self.call_method_with_payload("send_tx", req).await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
/// Get Ids of the programs used by the node
pub async fn get_program_ids(
&self,
) -> Result<HashMap<String, ProgramId>, SequencerClientError> {
let acc_req = GetProgramIdsRequest {};
let req = serde_json::to_value(acc_req).unwrap();
let resp = self
.call_method_with_payload("get_program_ids", req)
.await
.unwrap();
let resp_deser = serde_json::from_value::<GetProgramIdsResponse>(resp)
.unwrap()
.program_ids;
Ok(resp_deser)
}
}

78
common/src/test_utils.rs Normal file
View File

@ -0,0 +1,78 @@
use crate::{
block::{Block, HashableBlockData},
transaction::{EncodedTransaction, NSSATransaction},
};
// Helpers
pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey {
nssa::PrivateKey::try_new([37; 32]).unwrap()
}
// Dummy producers
/// Produce dummy block with
///
/// `id` - block id, provide zero for genesis
///
/// `prev_hash` - hash of previous block, provide None for genesis
///
/// `transactions` - vector of `EncodedTransaction` objects
pub fn produce_dummy_block(
id: u64,
prev_hash: Option<[u8; 32]>,
transactions: Vec<EncodedTransaction>,
) -> Block {
let block_data = HashableBlockData {
block_id: id,
prev_block_hash: prev_hash.unwrap_or_default(),
timestamp: id * 100,
transactions,
};
block_data.into_block(&sequencer_sign_key_for_testing())
}
pub fn produce_dummy_empty_transaction() -> EncodedTransaction {
let program_id = nssa::program::Program::authenticated_transfer_program().id();
let account_ids = vec![];
let nonces = vec![];
let instruction_data: u128 = 0;
let message = nssa::public_transaction::Message::try_new(
program_id,
account_ids,
nonces,
instruction_data,
)
.unwrap();
let private_key = nssa::PrivateKey::try_new([1; 32]).unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&private_key]);
let nssa_tx = nssa::PublicTransaction::new(message, witness_set);
EncodedTransaction::from(NSSATransaction::Public(nssa_tx))
}
pub fn create_transaction_native_token_transfer(
from: [u8; 32],
nonce: u128,
to: [u8; 32],
balance_to_move: u128,
signing_key: nssa::PrivateKey,
) -> EncodedTransaction {
let account_ids = vec![nssa::AccountId::new(from), nssa::AccountId::new(to)];
let nonces = vec![nonce];
let program_id = nssa::program::Program::authenticated_transfer_program().id();
let message = nssa::public_transaction::Message::try_new(
program_id,
account_ids,
nonces,
balance_to_move,
)
.unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]);
let nssa_tx = nssa::PublicTransaction::new(message, witness_set);
EncodedTransaction::from(NSSATransaction::Public(nssa_tx))
}

143
common/src/transaction.rs Normal file
View File

@ -0,0 +1,143 @@
use borsh::{BorshDeserialize, BorshSerialize};
use log::info;
use serde::{Deserialize, Serialize};
use sha2::{Digest, digest::FixedOutput};
pub type HashType = [u8; 32];
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NSSATransaction {
Public(nssa::PublicTransaction),
PrivacyPreserving(nssa::PrivacyPreservingTransaction),
ProgramDeployment(nssa::ProgramDeploymentTransaction),
}
impl From<nssa::PublicTransaction> for NSSATransaction {
fn from(value: nssa::PublicTransaction) -> Self {
Self::Public(value)
}
}
impl From<nssa::PrivacyPreservingTransaction> for NSSATransaction {
fn from(value: nssa::PrivacyPreservingTransaction) -> Self {
Self::PrivacyPreserving(value)
}
}
impl From<nssa::ProgramDeploymentTransaction> for NSSATransaction {
fn from(value: nssa::ProgramDeploymentTransaction) -> Self {
Self::ProgramDeployment(value)
}
}
#[derive(
Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize,
)]
pub enum TxKind {
Public,
PrivacyPreserving,
ProgramDeployment,
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
/// General transaction object
pub struct EncodedTransaction {
pub tx_kind: TxKind,
/// Encoded blobs of data
pub encoded_transaction_data: Vec<u8>,
}
impl From<NSSATransaction> for EncodedTransaction {
fn from(value: NSSATransaction) -> Self {
match value {
NSSATransaction::Public(tx) => Self {
tx_kind: TxKind::Public,
encoded_transaction_data: tx.to_bytes(),
},
NSSATransaction::PrivacyPreserving(tx) => Self {
tx_kind: TxKind::PrivacyPreserving,
encoded_transaction_data: tx.to_bytes(),
},
NSSATransaction::ProgramDeployment(tx) => Self {
tx_kind: TxKind::ProgramDeployment,
encoded_transaction_data: tx.to_bytes(),
},
}
}
}
impl TryFrom<&EncodedTransaction> for NSSATransaction {
type Error = nssa::error::NssaError;
fn try_from(value: &EncodedTransaction) -> Result<Self, Self::Error> {
match value.tx_kind {
TxKind::Public => nssa::PublicTransaction::from_bytes(&value.encoded_transaction_data)
.map(|tx| tx.into()),
TxKind::PrivacyPreserving => {
nssa::PrivacyPreservingTransaction::from_bytes(&value.encoded_transaction_data)
.map(|tx| tx.into())
}
TxKind::ProgramDeployment => {
nssa::ProgramDeploymentTransaction::from_bytes(&value.encoded_transaction_data)
.map(|tx| tx.into())
}
}
}
}
impl EncodedTransaction {
/// Computes and returns the SHA-256 hash of the JSON-serialized representation of `self`.
pub fn hash(&self) -> HashType {
let bytes_to_hash = borsh::to_vec(&self).unwrap();
let mut hasher = sha2::Sha256::new();
hasher.update(&bytes_to_hash);
HashType::from(hasher.finalize_fixed())
}
pub fn log(&self) {
info!("Transaction hash is {:?}", hex::encode(self.hash()));
info!("Transaction tx_kind is {:?}", self.tx_kind);
}
}
#[cfg(test)]
mod tests {
use sha2::{Digest, digest::FixedOutput};
use crate::{
HashType,
transaction::{EncodedTransaction, TxKind},
};
fn test_transaction_body() -> EncodedTransaction {
EncodedTransaction {
tx_kind: TxKind::Public,
encoded_transaction_data: vec![1, 2, 3, 4],
}
}
#[test]
fn test_transaction_hash_is_sha256_of_json_bytes() {
let body = test_transaction_body();
let expected_hash = {
let data = borsh::to_vec(&body).unwrap();
let mut hasher = sha2::Sha256::new();
hasher.update(&data);
HashType::from(hasher.finalize_fixed())
};
let hash = body.hash();
assert_eq!(expected_hash, hash);
}
#[test]
fn test_to_bytes_from_bytes() {
let body = test_transaction_body();
let body_bytes = borsh::to_vec(&body).unwrap();
let body_new = borsh::from_slice::<EncodedTransaction>(&body_bytes).unwrap();
assert_eq!(body, body_new);
}
}

View File

@ -1,15 +0,0 @@
[package]
name = "consensus"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true
serde.workspace = true
tokio.workspace = true
[dependencies.networking]
path = "../networking"

View File

@ -1,22 +0,0 @@
use std::sync::Arc;
use networking::peer_manager::PeerManager;
use tokio::sync::Mutex;
#[derive(Debug)]
///Entrypoint to consensus.
/// Manages consensus protocol.
pub struct ConsensusManager {
pub peer_manager: Arc<Mutex<PeerManager>>,
}
impl ConsensusManager {
pub fn new(peer_manager: Arc<Mutex<PeerManager>>) -> Self {
Self { peer_manager }
}
//ToDo: change block from generic value into struct, when data block will be defined
pub fn vote(&self, _block: serde_json::Value) -> bool {
todo!()
}
}

View File

@ -0,0 +1,12 @@
[package]
name = "program_deployment"
version = "0.1.0"
edition = "2024"
[dependencies]
nssa.workspace = true
nssa_core.workspace = true
wallet.workspace = true
tokio = { workspace = true, features = ["macros"] }
clap.workspace = true

View File

@ -0,0 +1,661 @@
# Program deployment tutorial
This guide walks you through running the sequencer, compiling example programs, deploying a Hello World program, and interacting with accounts.
You'll find:
- Programs: example NSSA programs under `methods/guest/src/bin`.
- Runners: scripts to create and submit transactions to invoke these programs publicly and privately under `src/bin`.
# 0. Install the wallet
From the projects root directory:
```bash
cargo install --path wallet --force
```
# 1. Run the sequencer
From the projects root directory, start the sequencer:
```bash
cd sequencer_runner
RUST_LOG=info cargo run $(pwd)/configs/debug
```
Keep this terminal open. Well use it only to observe the node logs.
> [!NOTE]
> If you have already ran this before you'll see a `rocksdb` directory with stored blocks. Be sure to remove that directory to follow this tutorial.
## Checking and setting up the wallet
For sanity let's check that the wallet can connect to it.
```bash
wallet check-health
```
If this is your first time, the wallet will ask for a password. This is used as seed to deterministically generate all account keys (public and private).
For this tutorial, use: `program-tutorial`
You should see `✅All looks good!` if everything went well.
# 2. Compile the example programs
In a second terminal, from the `lssa` root directory, compile the example Risc0 programs:
```bash
cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml
```
The compiled `.bin` files will appear under:
```
examples/program_deployment/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/
```
For convenience, export this path:
```bash
export EXAMPLE_PROGRAMS_BUILD_DIR=$(pwd)/examples/program_deployment/methods/guest/target/riscv32im-risc0-zkvm-elf/docker
```
> [!IMPORTANT]
> **All remaining commands must be run from the `examples/program_deployment` directory.**
# 3. Hello world example
The Hello world program reads an arbitrary sequence of bytes from its instruction and appends them to the data field of the input account.
Execution succeeds only if the account is:
- Uninitialized, or
- Already owned by this program
If uninitialized, the program will claim the account and emit the updated state.
## Navigate to the example directory
All remaining commands must be run from:
```bash
cd examples/program_deployment
```
## Deploy the Program
Use the wallets built-in program deployment command:
```bash
wallet deploy-program $EXAMPLE_PROGRAMS_BUILD_DIR/hello_world.bin
```
# 4. Public execution of the Hello world example
## Create a Public Account
Generate a new public account:
```bash
wallet account new public
```
You'll see an output similar to:
```bash
Generated new account with account_id Public/BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1YW9ertWH9 at path /0
```
The relevant part is the account id `BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1YW9ertWH9`
## Check the account state
New accounts are always Uninitialized. Verify:
```bash
wallet account get --account-id Public/BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1YW9ertWH9
```
Expected output:
```
Account is Uninitialized
```
The `Public/` prefix tells the wallet to query the public state.
## Execute the Hello world program
Run the example:
```bash
cargo run --bin run_hello_world \
$EXAMPLE_PROGRAMS_BUILD_DIR/hello_world.bin \
BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1YW9ertWH9
```
> [!NOTE]
> - Passing the `.bin` lets the script compute the program ID and build the transaction.
> - Because this program executes publicly, the node performs the execution.
> - The program will claim the account and write data into it.
Monitor the sequencer terminal to confirm execution.
## Inspect the updated account
After the transaction is processed, check the new state:
```bash
wallet account get --account-id Public/BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1YW9ertWH9
```
Example output:
```json
{
"balance": 0,
"program_owner_b64": "o6C6/bbjDmN9VUC51McBpPrta8lxrx2X0iHExhX0yNU=",
"data_b64": "SG9sYSBtdW5kbyE=",
"nonce": 0
}
```
The `data_b64` field contains de data in Base64.
Decode it:
```bash
echo -n SG9sYSBtdW5kbyE= | base64 -d
```
You should see `Hola mundo!`.
# 5. Understanding the code in `hello_world.rs`.
The Hello world example demonstrates the minimal structure of an NSSA program.
Its purpose is very simple: append the instruction bytes to the data field of a single account.
### What this program does in a nutshell
1. Reads the program inputs
- The list of pre-state accounts (`pre_states`)
- The instruction bytes (`instruction`)
- The raw instruction data (used again when writing outputs)
2. Checks that there is exactly one input account: this example operates on a single account, so it expects `pre_states` to contain exactly one entry.
3. Builds the post-state: It clones the input account and appends the instruction bytes to its data field.
4. Handles account claiming logic: If the account is uninitialized (i.e. not yet claimed by any program), its program_owner will equal `DEFAULT_PROGRAM_ID`. In that case, the program issues a claim request, meaning: "This program now owns this account."
5. Outputs the proposed state transition: `write_nssa_outputs` emits:
- The original instruction data
- The original pre-states
- The new post-states
## Code walkthrough
1. Reading inputs:
```rust
let (ProgramInput { pre_states, instruction: greeting }, instruction_data)
= read_nssa_inputs::<Instruction>();
```
2. Extracting the single account:
```rust
let [pre_state] = pre_states
.try_into()
.unwrap_or_else(|_| panic!("Input pre states should consist of a single account"));
```
3. Constructing the updated account post state
```rust
let mut this = pre_state.account.clone();
let mut bytes = this.data.into_inner();
bytes.extend_from_slice(&greeting);
this.data = bytes.try_into().expect("Data should fit within the allowed limits");
```
4. Instantiating the `AccountPostState` with a claiming request only if the account pre state is uninitialized:
```rust
let post_state = if post_account.program_owner == DEFAULT_PROGRAM_ID {
AccountPostState::new_claimed(post_account)
} else {
AccountPostState::new(post_account)
};
```
5. Emmiting the output
```rust
write_nssa_outputs(instruction_data, vec![pre_state], vec![post_state]);
```
# 6. Understanding the runner script `run_hello_world.rs`
The `run_hello_world.rs` example demonstrates how to construct and submit a public transaction that executes the `hello_world` program. Below is a breakdown of what the file does and how the pieces fit together.
### 1. Wallet initialization
```rust
let wallet_config = fetch_config().await.unwrap();
let wallet_core = WalletCore::start_from_config_update_chain(wallet_config)
.await
.unwrap();
```
The example loads the wallet configuration and initializes `WalletCore`.
This gives access to:
- the sequencer client,
- the wallets account storage.
### 2. Parsing inputs
```rust
let program_path = std::env::args_os().nth(1).unwrap().into_string().unwrap();
let account_id: AccountId = std::env::args_os().nth(2).unwrap().into_string().unwrap().parse().unwrap();
```
The program expects two arguments:
- Path to the guest binary
- AccountId of the public account to operate on
This is the account that the program will claim and write data into.
### 3. Loading the program bytecode
```rust
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap();
```
The Risc0 ELF is read from disk and wrapped in a Program object, which can be used to compute the program ID. The ID is used by the node to identify which program is invoked by the transaction.
### 4. Preparing the instruction data
```rust
let greeting: Vec<u8> = vec![72,111,108,97,32,109,117,110,100,111,33];
```
The example hardcodes the ASCII bytes for `Hola mundo!`. These bytes are passed to the program as its “instruction,” which the Hello World program simply appends to the accounts data field.
### 5. Creating the public transaction
```rust
let nonces = vec![];
let signing_keys = [];
let message = Message::try_new(program.id(), vec![account_id], nonces, greeting).unwrap();
let witness_set = WitnessSet::for_message(&message, &signing_keys);
let tx = PublicTransaction::new(message, witness_set);
```
A public transaction consists of:
- a `Message`
- a corresponding `WitnessSet`
For this simple example, no signing or nonces are required. The transaction includes only the program ID, the target account, and the instruction bytes. The Hello World program allows this because it does not explicitly require authorization. In the next example, well see how authorization requirements are enforced and how to construct a transaction that includes signatures and nonces.
### 6. Submitting the transaction
```rust
let response = wallet_core.sequencer_client.send_tx_public(tx).await.unwrap();
```
The transaction is sent to the sequencer, which processes it and updates the public state accordingly.
Once executed, youll be able to query the updated account to see the newly written "Hola mundo!" data.
# 7. Private execution of the Hello world example
This section is very similar to the previous case:
## Create a private account
Generate a new private account:
```bash
wallet account new private
```
You'll see an output similar to:
```bash
Generated new account with account_id Private/7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8X3B89ADeMr at path /0
```
The relevant part for this tutorial is the account id `7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8X3B89ADeMr`
You can check it's uninitialized with
```bash
wallet account get --account-id Private/7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8X3B89ADeMr
```
## Privately executing the Hello world program
### Execute the Hello world program
Run the example:
```bash
cargo run --bin run_hello_world_private \
$EXAMPLE_PROGRAMS_BUILD_DIR/hello_world.bin \
7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8X3B89ADeMr
```
> [!NOTE]
> - This command may take a few minutes to complete. A ZK proof of the Hello world program execution and the privacy preserving circuit are being generated. Depending on the machine this can take from 30 seconds to 4 minutes.
> - We are passing the same `hello_world.bin` binary as in the previous case with public executions. This is because the program is the same, it is the privacy context of the input account that's different.
> - Because this program executes privately, the local machine runs the program and generate the proof of execution.
> - The program will claim the private account and write data into it.
### Syncing the new private account values
The `run_hello_world` script submitted a transaction and it was (hopefully) accepted by the node. On chain there is now a commitment to the new private account values, and the account data is stored encrypted. However, the local client hasnt updated its private state yet. Thats why, if you try to get the private account values now, it still reads the old values from local storage instead.
```bash
wallet account get --account-id Private/7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8X3B89ADeMr
```
This will still show `Account is Uninitialized`. To see the new values locally, you need to run the wallet sync command. Once the client syncs, the local store will reflect the updated account data.
To sync private accounts run:
```bash
wallet account sync-private
```
> [!NOTE]
> - This queries the node for transactions and goes throught the encrypted accounts. Whenever a new value is found for one of the owned private accounts, the local storage is updated.
After this completes, running
```bash
wallet account get --account-id Private/7EDHyxejuynBpmbLuiEym9HMUyCYxZDuF8X3B89ADeMr
```
should show something similar to
```json
{
"balance":0,
"program_owner_b64":"dWgtNRixwjC0C8aA0NL0Iuss3Q26Dw6ECk7bzExW4bI=",
"data_b64":"SG9sYSBtdW5kbyE=",
"nonce":236788677072686551559312843688143377080
}
```
## The `run_hello_world_private.rs` runner
This example extends the public `run_hello_world.rs` flow by constructing a privacy-preserving transaction instead of a public one.
Both runners load a guest program, prepare a transaction, and submit it. But the private version handles encrypted account data, nullifiers, ephemeral keys, and zk proofs.
Unlike the public version, `run_hello_world_private.rs` must:
- prepare the private account pre-state (nullifier keys, membership proof, encrypted values)
- derive a shared secret to encrypt the post-state
- compute the correct visibility mask (initialized vs. uninitialized private account)
- execute the guest program inside the zkVM and produce a proof
- build a PrivacyPreservingTransaction composed of:
- a Message encoding commitments + encrypted post-state
- a WitnessSet embedding the zk proof
Luckily all that complexity is hidden behind the `wallet_core.send_privacy_preserving_tx` function:
```rust
let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)];
// Construct and submit the privacy-preserving transaction
wallet_core
.send_privacy_preserving_tx(
accounts,
&Program::serialize_instruction(greeting).unwrap(),
&program.into(),
)
.await
.unwrap();
```
Check the `run_hello_world_private.rs` file to see how it is used.
# 8. Account authorization mechanism
The Hello world example does not enforce any authorization on the input account. This means any user can execute it on any account, regardless of ownership.
NSSA provides a mechanism for programs to enforce proper authorization before an execution can succeed. The meaning of authorization differs between public and private accounts:
- Public accounts: authorization requires that the transaction is signed with the accounts signing key.
- Private accounts: authorization requires that the circuit verifies knowledge of the accounts nullifier secret key.
From the program development perspective it is very simple: input accounts come with a flag indicating whether they has been properly authorized. And so, the only difference between the program `hello_world.rs` and `hello_world_with_authorization.rs` is in the lines
```rust
// #### Difference with `hello_world` example here:
// Fail if the input account is not authorized
// The `is_authorized` field will be correctly populated or verified by the system if
// authorization is provided.
if !pre_state.is_authorized {
panic!("Missing required authorization");
}
// ####
```
Which just checks the `is_authorized` flag and fails if it is set to false.
# 9. Public execution of the Hello world with authorization example
The workflow to execute it publicly is very similar:
### Deploy the program
```bash
wallet deploy-program $EXAMPLE_PROGRAMS_BUILD_DIR/hello_world_with_authorization.bin
```
### Create a new public account
Our previous public account is already claimed by the simple Hello world program. So we need a new one to work with this other version of the hello program
```bash
wallet account new public
```
Outupt:
```
Generated new account with account_id Public/9Ppqqf8NeCX58pnr8ZqKoHvSoYGqH79dSikZAtLxKgXE at path /1
```
### Run the program
```bash
cargo run --bin run_hello_world_with_authorization \
$EXAMPLE_PROGRAMS_BUILD_DIR/hello_world_with_authorization.bin \
9Ppqqf8NeCX58pnr8ZqKoHvSoYGqH79dSikZAtLxKgXE
```
# 10. Understanding `run_hello_world_with_authorization.rs`
From the runner script perspective, the only difference is that the signing keys are passed to the `WitnessSet` constructor for it to sign it. You can see this in the following parts of the code:
1. Loading the sigining keys from the wallet storage
```rust
// Load signing keys to provide authorization
let signing_key = wallet_core
.storage
.user_data
.get_pub_account_signing_key(&account_id)
.expect("Input account should be a self owned public account");
```
2. Fetching the current public nonce.
```rust
// Construct the public transaction
// Query the current nonce from the node
let nonces = wallet_core
.get_accounts_nonces(vec![account_id])
.await
.expect("Node should be reachable to query account data");
```
2. Instantiate the witness set using the signing keys
```rust
let signing_keys = [signing_key];
let message = Message::try_new(program.id(), vec![account_id], nonces, greeting).unwrap();
// Pass the signing key to sign the message. This will be used by the node
// to flag the pre_state as `is_authorized` when executing the program
let witness_set = WitnessSet::for_message(&message, &signing_keys);
```
## Seeing the mechanism in action
If everything went well you won't notice any difference with the first Hello world, because the runner takes care of signing the transaction to provide authorization and the program just succeeds.
Try using the `run_hello_world.rs` runner with the `hello_world_with_authorization.bin` program. This will fail because the runner will submit the transaction without the corresponding signature.
```bash
cargo run --bin run_hello_world \
$EXAMPLE_PROGRAMS_BUILD_DIR/hello_world_with_authorization.bin \
9Ppqqf8NeCX58pnr8ZqKoHvSoYGqH79dSikZAtLxKgXE
```
You should see something like the following **on the node logs**.
```bash
[2025-12-11T13:43:22Z WARN sequencer_core] Error at transition ProgramExecutionFailed(
"Guest panicked: Missing required authorization",
)
```
# 11. Public and private account interaction example
Previous examples only operated on public or private accounts independently. Those minimal programs were useful to introduce basic concepts, but they couldn't demonstrate how different types of accounts interact within a single program invocation.
The "Hello world with move function" introduces two operations that require one or two input accounts:
- `write`: appends arbitrary bytes to a single account. This is what we already had.
- `move_data`: reads all bytes from one account, clears it, and appends those bytes to another account.
Because these operations may involve multiple accounts, we'll see how public and private accounts can participate together in one execution. It highlights how ownership checks work, when an account needs to be claimed, and how multiple post-states are emitted when several accounts are modified.
> [!NOTE]
> The program logic is completely agnostic to whether input accounts are public or private. It always executes the same way.
> See `methods/guest/src/bin/hello_world_with_move_function.rs`. The program just reads the instruction bytes and updates the accounts state.
> All privacy handling happens on the runner side. When constructing the transaction, the runner decides which accounts are public or private and prepares the appropriate proofs. The program itself can't differentiate between privacy modes.
Let's start by deploying the program
```bash
wallet deploy-program $EXAMPLE_PROGRAMS_BUILD_DIR/hello_world_with_move_function.bin
```
Let's also create a new public account
```bash
wallet account new public
```
Output:
```
Generated new account with account_id Public/95iNQMbmxMRY6jULiHYkCzCkYKPEuysvBh5kEHayDxLs at path /0/0
```
Let's execute the write function
```bash
cargo run --bin run_hello_world_with_move_function \
$EXAMPLE_PROGRAMS_BUILD_DIR/hello_world_with_move_function.bin \
write-public 95iNQMbmxMRY6jULiHYkCzCkYKPEuysvBh5kEHayDxLs mundo!
```
Let's crate a new private account.
```bash
wallet account new private
```
Output:
```
Generated new account with account_id Private/8vzkK7vsdrS2gdPhLk72La8X4FJkgJ5kJLUBRbEVkReU at path /1
```
Let's execute the write function
```bash
cargo run --bin run_hello_world_with_move_function \
$EXAMPLE_PROGRAMS_BUILD_DIR/hello_world_with_move_function.bin \
write-private 8vzkK7vsdrS2gdPhLk72La8X4FJkgJ5kJLUBRbEVkReU Hola
```
To check the values of the accounts are as expected run:
```bash
wallet account get --account-id Public/95iNQMbmxMRY6jULiHYkCzCkYKPEuysvBh5kEHayDxLs
```
and
```bash
wallet account sync-private
wallet account get --account-id Private/8vzkK7vsdrS2gdPhLk72La8X4FJkgJ5kJLUBRbEVkReU
```
and check the (base64 encoded) data values are `mundo!` and `Hola` respectively.
Now we can execute the move function to clear the data on the public account and move it to the private account.
```bash
cargo run --bin run_hello_world_with_move_function \
$EXAMPLE_PROGRAMS_BUILD_DIR/hello_world_with_move_function.bin \
move-data-public-to-private 95iNQMbmxMRY6jULiHYkCzCkYKPEuysvBh5kEHayDxLs 8vzkK7vsdrS2gdPhLk72La8X4FJkgJ5kJLUBRbEVkReU
```
After succeeding, re run the get and sync commands and check that the public account has empty data and the private account data is `Holamundo!`.
# 12. Program composition: tail calls
Programs can chain calls to other programs when they return. This is the tail call or chained call mechanism. It is used by programs that depend on other programs.
The examples include a `guest/src/bin/simple_tail_call.rs` program that shows how to trigger this mechanism. It internally calls the first Hello World program with a fixed greeting: `Hello from tail call`.
> [!NOTE]
> This program hardcodes the ID of the Hello World program. If something fails, check that this ID matches the one produced when building the Hello World program. You can see it in the output of `cargo risczero build` from the earlier sections of this tutorial. If it differs, update the ID in `simple_tail_call.rs` and build again.
As before, let's start by deploying the program
```bash
wallet deploy-program $EXAMPLE_PROGRAMS_BUILD_DIR/simple_tail_call.bin
```
We'll use the first public account of this tutorial. The one with account id `BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1YW9ertWH9`. This account is already owned by the Hello world program and its data reads `Hola mundo!`.
Let's run the tail call program
```bash
cargo run --bin run_hello_world_through_tail_call \
$EXAMPLE_PROGRAMS_BUILD_DIR/simple_tail_call.bin \
BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1YW9ertWH9
```
Once the transaction is processed, query the account values with:
```bash
wallet account get --account-id Public/BzdBoL4JRa5M873cuWb9rbYgASr1pXyaAZ1YW9ertWH9
```
You should se an output similar to
```json
{
"balance":0,
"program_owner_b64":"fpnW4tFY9N6llZcBHaXRwu7xe+7WZnZX9RWzhwNbk1o=",
"data_b64":"SG9sYSBtdW5kbyFIZWxsbyBmcm9tIHRhaWwgY2FsbA==",
"nonce":0
}
```
Decoding the (base64 encoded) data
```bash
echo -n SG9sYSBtdW5kbyFIZWxsbyBmcm9tIHRhaWwgY2FsbA== | base64 -d
```
Output:
```
Hola mundo!Hello from tail call
```
## Private tail-calls
There's support for tail calls in privacy preserving executions too. The `run_hello_world_through_tail_call_private.rs` runner walks you through the process of invoking such an execution.
The only difference is that, since the execution is local, the runner will need both programs: the `simple_tail_call` and it's dependency `hello_world`.
Let's use our existing private account with id `8vzkK7vsdrS2gdPhLk72La8X4FJkgJ5kJLUBRbEVkReU`. This one is already owned by the `hello_world` program.
You can test the privacy tail calls with
```bash
cargo run --bin run_hello_world_through_tail_call_private \
$EXAMPLE_PROGRAMS_BUILD_DIR/simple_tail_call.bin \
$EXAMPLE_PROGRAMS_BUILD_DIR/hello_world.bin \
8vzkK7vsdrS2gdPhLk72La8X4FJkgJ5kJLUBRbEVkReU
```
>[!NOTE]
> The above command may take longer than the previous privacy executions because needs to generate proofs of execution of both the `simple_tail_call` and the `hello_world` programs.
Once finished run the following to see the changes
```bash
wallet account sync-private
wallet account get --account-id Private/8vzkK7vsdrS2gdPhLk72La8X4FJkgJ5kJLUBRbEVkReU
```
# 13. Program derived accounts: authorizing accounts through tail calls
## Digression: account authority vs account program ownership
In NSSA there are two distinct concepts that control who can modify an account:
**Program Ownership:** Each account has a field: `program_owner: ProgramId`.
This indicates which program is allowed to update the accounts state during execution.
- If a program is the program_owner of an account, it can freely mutate its fields.
- If the account is uninitialized (`program_owner = DEFAULT_PROGRAM_ID`), a program may claim it and become its owner.
- If a program is not the owner and the account is not claimable, any attempt to modify it will cause the transition to fail.
Program ownership is about mutation rights during program execution.
**Account authority**: Independent from program ownership, each account also has an authority. The entity that is allowed to set: `is_authorized = true`. This flag indicates that the account has been authorized for use in a transaction.
Who can act as authority?
- User-defined accounts: The user is the authority. They can mark an account as authorized by:
- Signing the transaction (public accounts)
- Providing a valid nullifiers secret key ownership proof (private accounts)
- Program derived accounts: Programs are automatically the authority of a dedicated namespace of public accounts.
Each program owns a non-overlapping space of 2^256 **public** account IDs. They do not overlap with:
- User accounts (public or private)
- Other programs PDAs
> [!NOTE]
> Currently PDAs are restricted to the public state.
A program can be the authority of an account owned by another program, which is the most common case.
During a chained call, a program can mark its PDA accounts as `is_authorized=true` without requiring any user signatures or nullifier secret keys. This enables programs to safely authorize accounts during program composition. Importantly, these flags can only be set to true for PDA accounts through an execution of the program that is their authority. No user and no other program can execute any transition that requires authorization of PDA accounts belonging to a different program.
## Running the example
This tutorial includes an example of PDA usage in `methods/guest/src/bin/tail_call_with_pda.rs.`. That programs sole purpose is to forward one of its own PDA accounts, an account for which it is the authority, to the "Hello World with authorization" program via a chained call. The Hello World program will then claim the account and become its program owner, but the `tail_call_with_pda` program remains the authority. This means it is still the only entity capable of marking that account as `is_authorized=true`.
Deploy the program:
```bash
wallet deploy-program $EXAMPLE_PROGRAMS_BUILD_DIR/tail_call_with_pda.bin
```
There is no need to create a new account for this example, because we simply use one of the PDA accounts belonging to the `tail_call_with_pda` program.
Execute the program
```bash
cargo run --bin run_hello_world_with_authorization_through_tail_call_with_pda $EXAMPLE_PROGRAMS_BUILD_DIR/tail_call_with_pda.bin
```
You'll see an output like the following:
```bash
The program derived account ID is: 3tfTPPuxj3eSE1cLVuNBEk8eSHzpnYS1oqEdeH3Nfsks
```
Then check the status of that account
```bash
wallet account get --account-id Public/3tfTPPuxj3eSE1cLVuNBEk8eSHzpnYS1oqEdeH3Nfsks
```
Output:
```bash
{
"balance":0,
"program_owner_b64":"HZXHYRaKf6YusVo8x00/B15uyY5sGsJb1bzH4KlCY5g=",
"data_b64": "SGVsbG8gZnJvbSB0YWlsIGNhbGwgd2l0aCBQcm9ncmFtIERlcml2ZWQgQWNjb3VudCBJRA==",
"nonce":0"
}
```

View File

@ -0,0 +1,10 @@
[package]
name = "example_program_deployment_methods"
version = "0.1.0"
edition = "2024"
[build-dependencies]
risc0-build.workspace = true
[package.metadata.risc0]
methods = ["guest"]

View File

@ -0,0 +1,11 @@
[package]
name = "example_program_deployment_programs"
version = "0.1.0"
edition = "2024"
[dependencies]
nssa_core.workspace = true
hex.workspace = true
bytemuck.workspace = true
risc0-zkvm.workspace = true

View File

@ -0,0 +1,60 @@
use nssa_core::program::{
AccountPostState, DEFAULT_PROGRAM_ID, ProgramInput, read_nssa_inputs, write_nssa_outputs,
};
// Hello-world example program.
//
// This program reads an arbitrary sequence of bytes as its instruction
// and appends those bytes to the `data` field of the single input account.
//
// Execution succeeds only if the input account is either:
// - uninitialized, or
// - already owned by this program.
//
// In case the input account is uninitialized, the program claims it.
//
// The updated account is emitted as the sole post-state.
type Instruction = Vec<u8>;
fn main() {
// Read inputs
let (
ProgramInput {
pre_states,
instruction: greeting,
},
instruction_data,
) = read_nssa_inputs::<Instruction>();
// Unpack the input account pre state
let [pre_state] = pre_states
.try_into()
.unwrap_or_else(|_| panic!("Input pre states should consist of a single account"));
// Construct the post state account values
let post_account = {
let mut this = pre_state.account.clone();
let mut bytes = this.data.into_inner();
bytes.extend_from_slice(&greeting);
this.data = bytes
.try_into()
.expect("Data should fit within the allowed limits");
this
};
// Wrap the post state account values inside a `AccountPostState` instance.
// This is used to forward the account claiming request if any
let post_state = if post_account.program_owner == DEFAULT_PROGRAM_ID {
// This produces a claim request
AccountPostState::new_claimed(post_account)
} else {
// This doesn't produce a claim request
AccountPostState::new(post_account)
};
// The output is a proposed state difference. It will only succeed if the pre states coincide
// with the previous values of the accounts, and the transition to the post states conforms
// with the NSSA program rules.
write_nssa_outputs(instruction_data, vec![pre_state], vec![post_state]);
}

View File

@ -0,0 +1,69 @@
use nssa_core::program::{
AccountPostState, DEFAULT_PROGRAM_ID, ProgramInput, read_nssa_inputs, write_nssa_outputs,
};
// Hello-world with authorization example program.
//
// This program reads an arbitrary sequence of bytes as its instruction
// and appends those bytes to the `data` field of the single input account.
//
// Execution succeeds only if the input account **is authorized** and is either:
// - uninitialized, or
// - already owned by this program.
//
// In case the input account is uninitialized, the program claims it.
//
// The updated account is emitted as the sole post-state.
type Instruction = Vec<u8>;
fn main() {
// Read inputs
let (
ProgramInput {
pre_states,
instruction: greeting,
},
instruction_data,
) = read_nssa_inputs::<Instruction>();
// Unpack the input account pre state
let [pre_state] = pre_states
.try_into()
.unwrap_or_else(|_| panic!("Input pre states should consist of a single account"));
// #### Difference with `hello_world` example here:
// Fail if the input account is not authorized
// The `is_authorized` field will be correctly populated or verified by the system if
// authorization is provided.
if !pre_state.is_authorized {
panic!("Missing required authorization");
}
// ####
// Construct the post state account values
let post_account = {
let mut this = pre_state.account.clone();
let mut bytes = this.data.into_inner();
bytes.extend_from_slice(&greeting);
this.data = bytes
.try_into()
.expect("Data should fit within the allowed limits");
this
};
// Wrap the post state account values inside a `AccountPostState` instance.
// This is used to forward the account claiming request if any
let post_state = if post_account.program_owner == DEFAULT_PROGRAM_ID {
// This produces a claim request
AccountPostState::new_claimed(post_account)
} else {
// This doesn't produce a claim request
AccountPostState::new(post_account)
};
// The output is a proposed state difference. It will only succeed if the pre states coincide
// with the previous values of the accounts, and the transition to the post states conforms
// with the NSSA program rules.
write_nssa_outputs(instruction_data, vec![pre_state], vec![post_state]);
}

View File

@ -0,0 +1,101 @@
use nssa_core::{
account::{Account, AccountWithMetadata},
program::{
AccountPostState, DEFAULT_PROGRAM_ID, ProgramInput, read_nssa_inputs, write_nssa_outputs,
},
};
// Hello-world with write + move_data example program.
//
// This program reads an instruction of the form `(function_id, data)` and
// dispatches to either:
//
// - `write`: appends `data` to the `data` field of a single input account.
// - `move_data`: moves all bytes from one account to another. The source account is cleared and the
// destination account receives the appended bytes.
//
// Execution succeeds only if:
// - the accounts involved are either uninitialized, or
// - already owned by this program.
//
// In case an input account is uninitialized, the program will claim it when
// producing the post-state.
type Instruction = (u8, Vec<u8>);
const WRITE_FUNCTION_ID: u8 = 0;
const MOVE_DATA_FUNCTION_ID: u8 = 1;
fn build_post_state(post_account: Account) -> AccountPostState {
if post_account.program_owner == DEFAULT_PROGRAM_ID {
// This produces a claim request
AccountPostState::new_claimed(post_account)
} else {
// This doesn't produce a claim request
AccountPostState::new(post_account)
}
}
fn write(pre_state: AccountWithMetadata, greeting: Vec<u8>) -> AccountPostState {
// Construct the post state account values
let post_account = {
let mut this = pre_state.account.clone();
let mut bytes = this.data.into_inner();
bytes.extend_from_slice(&greeting);
this.data = bytes
.try_into()
.expect("Data should fit within the allowed limits");
this
};
build_post_state(post_account)
}
fn move_data(
from_pre: &AccountWithMetadata,
to_pre: &AccountWithMetadata,
) -> Vec<AccountPostState> {
// Construct the post state account values
let from_data: Vec<u8> = from_pre.account.data.clone().into();
let from_post = {
let mut this = from_pre.account.clone();
this.data = Default::default();
build_post_state(this)
};
let to_post = {
let mut this = to_pre.account.clone();
let mut bytes = this.data.into_inner();
bytes.extend_from_slice(&from_data);
this.data = bytes
.try_into()
.expect("Data should fit within the allowed limits");
build_post_state(this)
};
vec![from_post, to_post]
}
fn main() {
// Read input accounts.
let (
ProgramInput {
pre_states,
instruction: (function_id, data),
},
instruction_words,
) = read_nssa_inputs::<Instruction>();
let post_states = match (pre_states.as_slice(), function_id, data.len()) {
([account_pre], WRITE_FUNCTION_ID, _) => {
let post = write(account_pre.clone(), data);
vec![post]
}
([account_from_pre, account_to_pre], MOVE_DATA_FUNCTION_ID, 0) => {
move_data(account_from_pre, account_to_pre)
}
_ => panic!("invalid params"),
};
write_nssa_outputs(instruction_words, pre_states, post_states);
}

View File

@ -0,0 +1,63 @@
use nssa_core::program::{
AccountPostState, ChainedCall, ProgramId, ProgramInput, read_nssa_inputs,
write_nssa_outputs_with_chained_call,
};
// Tail Call example program.
//
// This program shows how to chain execution to another program using `ChainedCall`.
// It reads a single account, emits it unchanged, and then triggers a tail call
// to the Hello World program with a fixed greeting.
/// This needs to be set to the ID of the Hello world program.
/// To get the ID run **from the root directoy of the repository**:
/// `cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml`
/// This compiles the programs and outputs the IDs in hex that can be used to copy here.
const HELLO_WORLD_PROGRAM_ID_HEX: &str =
"e9dfc5a5d03c9afa732adae6e0edfce4bbb44c7a2afb9f148f4309917eb2de6f";
fn hello_world_program_id() -> ProgramId {
let hello_world_program_id_bytes: [u8; 32] = hex::decode(HELLO_WORLD_PROGRAM_ID_HEX)
.unwrap()
.try_into()
.unwrap();
bytemuck::cast(hello_world_program_id_bytes)
}
fn main() {
// Read inputs
let (
ProgramInput {
pre_states,
instruction: _,
},
instruction_data,
) = read_nssa_inputs::<()>();
// Unpack the input account pre state
let [pre_state] = pre_states
.clone()
.try_into()
.unwrap_or_else(|_| panic!("Input pre states should consist of a single account"));
// Create the (unchanged) post state
let post_state = AccountPostState::new(pre_state.account.clone());
// Create the chained call
let chained_call_greeting: Vec<u8> = b"Hello from tail call".to_vec();
let chained_call_instruction_data = risc0_zkvm::serde::to_vec(&chained_call_greeting).unwrap();
let chained_call = ChainedCall {
program_id: hello_world_program_id(),
instruction_data: chained_call_instruction_data,
pre_states,
pda_seeds: vec![],
};
// Write the outputs
write_nssa_outputs_with_chained_call(
instruction_data,
vec![pre_state],
vec![post_state],
vec![chained_call],
);
}

View File

@ -0,0 +1,76 @@
use nssa_core::program::{
AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, read_nssa_inputs,
write_nssa_outputs_with_chained_call,
};
// Tail Call with PDA example program.
//
// Demonstrates how to chain execution to another program using `ChainedCall`
// while authorizing program-derived accounts.
//
// Expects a single input account whose Account ID is derived from this
// programs ID and the fixed PDA seed below (as defined by the
// `<AccountId as From<(&ProgramId, &PdaSeed)>>` implementation).
//
// Emits this account unchanged, then performs a tail call to the
// Hello-World-with-Authorization program with a fixed greeting. The same
// account is passed along but marked with `is_authorized = true`.
const HELLO_WORLD_WITH_AUTHORIZATION_PROGRAM_ID_HEX: &str =
"1d95c761168a7fa62eb15a3cc74d3f075e6ec98e6c1ac25bd5bcc7e0a9426398";
const PDA_SEED: PdaSeed = PdaSeed::new([37; 32]);
fn hello_world_program_id() -> ProgramId {
let hello_world_program_id_bytes: [u8; 32] =
hex::decode(HELLO_WORLD_WITH_AUTHORIZATION_PROGRAM_ID_HEX)
.unwrap()
.try_into()
.unwrap();
bytemuck::cast(hello_world_program_id_bytes)
}
fn main() {
// Read inputs
let (
ProgramInput {
pre_states,
instruction: _,
},
instruction_data,
) = read_nssa_inputs::<()>();
// Unpack the input account pre state
let [pre_state] = pre_states
.clone()
.try_into()
.unwrap_or_else(|_| panic!("Input pre states should consist of a single account"));
// Create the (unchanged) post state
let post_state = AccountPostState::new(pre_state.account.clone());
// Create the chained call
let chained_call_greeting: Vec<u8> =
b"Hello from tail call with Program Derived Account ID".to_vec();
let chained_call_instruction_data = risc0_zkvm::serde::to_vec(&chained_call_greeting).unwrap();
// Flip the `is_authorized` flag to true
let pre_state_for_chained_call = {
let mut this = pre_state.clone();
this.is_authorized = true;
this
};
let chained_call = ChainedCall {
program_id: hello_world_program_id(),
instruction_data: chained_call_instruction_data,
pre_states: vec![pre_state_for_chained_call],
pda_seeds: vec![PDA_SEED],
};
// Write the outputs
write_nssa_outputs_with_chained_call(
instruction_data,
vec![pre_state],
vec![post_state],
vec![chained_call],
);
}

View File

@ -0,0 +1,67 @@
use nssa::{
AccountId, PublicTransaction,
program::Program,
public_transaction::{Message, WitnessSet},
};
use wallet::{WalletCore, helperfunctions::fetch_config};
// Before running this example, compile the `hello_world.rs` guest program with:
//
// cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml
//
// Note: you must run the above command from the root of the `lssa` repository.
// Note: The compiled binary file is stored in
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world.bin
//
//
// Usage:
// cargo run --bin run_hello_world /path/to/guest/binary <account_id>
//
// Example:
// cargo run --bin run_hello_world \
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world.bin \
// Ds8q5PjLcKwwV97Zi7duhRVF9uwA2PuYMoLL7FwCzsXE
#[tokio::main]
async fn main() {
// Load wallet config and storage
let wallet_config = fetch_config().await.unwrap();
let wallet_core = WalletCore::start_from_config_update_chain(wallet_config)
.await
.unwrap();
// Parse arguments
// First argument is the path to the program binary
let program_path = std::env::args_os().nth(1).unwrap().into_string().unwrap();
// Second argument is the account_id
let account_id: AccountId = std::env::args_os()
.nth(2)
.unwrap()
.into_string()
.unwrap()
.parse()
.unwrap();
// Load the program
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap();
// Define the desired greeting in ASCII
let greeting: Vec<u8> = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33];
// Construct the public transaction
// No nonces nor signing keys are needed for this example. Check out the
// `run_hello_world_with_authorization` on how to use them.
let nonces = vec![];
let signing_keys = [];
let message = Message::try_new(program.id(), vec![account_id], nonces, greeting).unwrap();
let witness_set = WitnessSet::for_message(&message, &signing_keys);
let tx = PublicTransaction::new(message, witness_set);
// Submit the transaction
let _response = wallet_core
.sequencer_client
.send_tx_public(tx)
.await
.unwrap();
}

View File

@ -0,0 +1,61 @@
use nssa::{AccountId, program::Program};
use wallet::{PrivacyPreservingAccount, WalletCore, helperfunctions::fetch_config};
// Before running this example, compile the `hello_world.rs` guest program with:
//
// cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml
//
// Note: you must run the above command from the root of the `lssa` repository.
// Note: The compiled binary file is stored in
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world.bin
//
//
// Usage:
// cargo run --bin run_hello_world_private /path/to/guest/binary <account_id>
//
// Note: the provided account_id needs to be of a private self owned account
//
// Example:
// cargo run --bin run_hello_world_private \
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world.bin \
// Ds8q5PjLcKwwV97Zi7duhRVF9uwA2PuYMoLL7FwCzsXE
#[tokio::main]
async fn main() {
// Load wallet config and storage
let wallet_config = fetch_config().await.unwrap();
let wallet_core = WalletCore::start_from_config_update_chain(wallet_config)
.await
.unwrap();
// Parse arguments
// First argument is the path to the program binary
let program_path = std::env::args_os().nth(1).unwrap().into_string().unwrap();
// Second argument is the account_id
let account_id: AccountId = std::env::args_os()
.nth(2)
.unwrap()
.into_string()
.unwrap()
.parse()
.unwrap();
// Load the program
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap();
// Define the desired greeting in ASCII
let greeting: Vec<u8> = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33];
let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)];
// Construct and submit the privacy-preserving transaction
wallet_core
.send_privacy_preserving_tx(
accounts,
&Program::serialize_instruction(greeting).unwrap(),
&program.into(),
)
.await
.unwrap();
}

View File

@ -0,0 +1,63 @@
use nssa::{
AccountId, PublicTransaction,
program::Program,
public_transaction::{Message, WitnessSet},
};
use wallet::{WalletCore, helperfunctions::fetch_config};
// Before running this example, compile the `simple_tail_call.rs` guest program with:
//
// cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml
//
// Note: you must run the above command from the root of the `lssa` repository.
// Note: The compiled binary file is stored in
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/simple_tail_call.bin
//
//
// Usage:
// cargo run --bin run_hello_world_through_tail_call /path/to/guest/binary <account_id>
//
// Example:
// cargo run --bin run_hello_world_through_tail_call \
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/simple_tail_call.bin \
// Ds8q5PjLcKwwV97Zi7duhRVF9uwA2PuYMoLL7FwCzsXE
#[tokio::main]
async fn main() {
// Load wallet config and storage
let wallet_config = fetch_config().await.unwrap();
let wallet_core = WalletCore::start_from_config_update_chain(wallet_config)
.await
.unwrap();
// Parse arguments
// First argument is the path to the program binary
let program_path = std::env::args_os().nth(1).unwrap().into_string().unwrap();
// Second argument is the account_id
let account_id: AccountId = std::env::args_os()
.nth(2)
.unwrap()
.into_string()
.unwrap()
.parse()
.unwrap();
// Load the program
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap();
let instruction_data = ();
let nonces = vec![];
let signing_keys = [];
let message =
Message::try_new(program.id(), vec![account_id], nonces, instruction_data).unwrap();
let witness_set = WitnessSet::for_message(&message, &signing_keys);
let tx = PublicTransaction::new(message, witness_set);
// Submit the transaction
let _response = wallet_core
.sequencer_client
.send_tx_public(tx)
.await
.unwrap();
}

View File

@ -0,0 +1,69 @@
use std::collections::HashMap;
use nssa::{
AccountId, ProgramId, privacy_preserving_transaction::circuit::ProgramWithDependencies,
program::Program,
};
use wallet::{PrivacyPreservingAccount, WalletCore, helperfunctions::fetch_config};
// Before running this example, compile the `simple_tail_call.rs` guest program with:
//
// cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml
//
// Note: you must run the above command from the root of the `lssa` repository.
// Note: The compiled binary file is stored in
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/simple_tail_call.bin
//
//
// Usage:
// cargo run --bin run_hello_world_through_tail_call_private /path/to/guest/binary <account_id>
//
// Example:
// cargo run --bin run_hello_world_through_tail_call \
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/simple_tail_call.bin \
// Ds8q5PjLcKwwV97Zi7duhRVF9uwA2PuYMoLL7FwCzsXE
#[tokio::main]
async fn main() {
// Load wallet config and storage
let wallet_config = fetch_config().await.unwrap();
let wallet_core = WalletCore::start_from_config_update_chain(wallet_config)
.await
.unwrap();
// Parse arguments
// First argument is the path to the simple_tail_call program binary
let simple_tail_call_path = std::env::args_os().nth(1).unwrap().into_string().unwrap();
// Second argument is the path to the hello_world program binary
let hello_world_path = std::env::args_os().nth(2).unwrap().into_string().unwrap();
// Third argument is the account_id
let account_id: AccountId = std::env::args_os()
.nth(3)
.unwrap()
.into_string()
.unwrap()
.parse()
.unwrap();
// Load the program and its dependencies (the hellow world program)
let simple_tail_call_bytecode: Vec<u8> = std::fs::read(simple_tail_call_path).unwrap();
let simple_tail_call = Program::new(simple_tail_call_bytecode).unwrap();
let hello_world_bytecode: Vec<u8> = std::fs::read(hello_world_path).unwrap();
let hello_world = Program::new(hello_world_bytecode).unwrap();
let dependencies: HashMap<ProgramId, Program> =
[(hello_world.id(), hello_world)].into_iter().collect();
let program_with_dependencies = ProgramWithDependencies::new(simple_tail_call, dependencies);
let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)];
// Construct and submit the privacy-preserving transaction
let instruction = ();
wallet_core
.send_privacy_preserving_tx(
accounts,
&Program::serialize_instruction(instruction).unwrap(),
&program_with_dependencies,
)
.await
.unwrap();
}

View File

@ -0,0 +1,80 @@
use nssa::{
AccountId, PublicTransaction,
program::Program,
public_transaction::{Message, WitnessSet},
};
use wallet::{WalletCore, helperfunctions::fetch_config};
// Before running this example, compile the `hello_world_with_authorization.rs` guest program with:
//
// cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml
//
// Note: you must run the above command from the root of the `lssa` repository.
// Note: The compiled binary file is stored in
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world_with_authorization.bin
//
//
// Usage:
// ./run_hello_world_with_authorization /path/to/guest/binary <account_id>
//
// Note: the provided account_id needs to be of a public self owned account
//
// Example:
// cargo run --bin run_hello_world_with_authorization \
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world_with_authorization.bin \
// Ds8q5PjLcKwwV97Zi7duhRVF9uwA2PuYMoLL7FwCzsXE
#[tokio::main]
async fn main() {
// Load wallet config and storage
let wallet_config = fetch_config().await.unwrap();
let wallet_core = WalletCore::start_from_config_update_chain(wallet_config)
.await
.unwrap();
// Parse arguments
// First argument is the path to the program binary
let program_path = std::env::args_os().nth(1).unwrap().into_string().unwrap();
// Second argument is the account_id
let account_id: AccountId = std::env::args_os()
.nth(2)
.unwrap()
.into_string()
.unwrap()
.parse()
.unwrap();
// Load the program
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap();
// Load signing keys to provide authorization
let signing_key = wallet_core
.storage
.user_data
.get_pub_account_signing_key(&account_id)
.expect("Input account should be a self owned public account");
// Define the desired greeting in ASCII
let greeting: Vec<u8> = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33];
// Construct the public transaction
// Query the current nonce from the node
let nonces = wallet_core
.get_accounts_nonces(vec![account_id])
.await
.expect("Node should be reachable to query account data");
let signing_keys = [signing_key];
let message = Message::try_new(program.id(), vec![account_id], nonces, greeting).unwrap();
// Pass the signing key to sign the message. This will be used by the node
// to flag the pre_state as `is_authorized` when executing the program
let witness_set = WitnessSet::for_message(&message, &signing_keys);
let tx = PublicTransaction::new(message, witness_set);
// Submit the transaction
let _response = wallet_core
.sequencer_client
.send_tx_public(tx)
.await
.unwrap();
}

View File

@ -0,0 +1,62 @@
use nssa::{
AccountId, PublicTransaction,
program::Program,
public_transaction::{Message, WitnessSet},
};
use nssa_core::program::PdaSeed;
use wallet::{WalletCore, helperfunctions::fetch_config};
// Before running this example, compile the `simple_tail_call.rs` guest program with:
//
// cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml
//
// Note: you must run the above command from the root of the `lssa` repository.
// Note: The compiled binary file is stored in
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/simple_tail_call.bin
//
//
// Usage:
// cargo run --bin run_hello_world_with_authorization_through_tail_call_with_pda
// /path/to/guest/binary <account_id>
//
// Example:
// cargo run --bin run_hello_world_with_authorization_through_tail_call_with_pda \
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/tail_call_with_pda.bin
const PDA_SEED: PdaSeed = PdaSeed::new([37; 32]);
#[tokio::main]
async fn main() {
// Load wallet config and storage
let wallet_config = fetch_config().await.unwrap();
let wallet_core = WalletCore::start_from_config_update_chain(wallet_config)
.await
.unwrap();
// Parse arguments
// First argument is the path to the program binary
let program_path = std::env::args_os().nth(1).unwrap().into_string().unwrap();
// Load the program
let bytecode: Vec<u8> = std::fs::read(program_path).unwrap();
let program = Program::new(bytecode).unwrap();
// Compute the PDA to pass it as input account to the public execution
let pda = AccountId::from((&program.id(), &PDA_SEED));
let account_ids = vec![pda];
let instruction_data = ();
let nonces = vec![];
let signing_keys = [];
let message = Message::try_new(program.id(), account_ids, nonces, instruction_data).unwrap();
let witness_set = WitnessSet::for_message(&message, &signing_keys);
let tx = PublicTransaction::new(message, witness_set);
// Submit the transaction
let _response = wallet_core
.sequencer_client
.send_tx_public(tx)
.await
.unwrap();
println!("The program derived account id is: {pda}");
}

View File

@ -0,0 +1,155 @@
use clap::{Parser, Subcommand};
use nssa::{PublicTransaction, program::Program, public_transaction};
use wallet::{PrivacyPreservingAccount, WalletCore, helperfunctions::fetch_config};
// Before running this example, compile the `hello_world_with_move_function.rs` guest program with:
//
// cargo risczero build --manifest-path examples/program_deployment/methods/guest/Cargo.toml
//
// Note: you must run the above command from the root of the `lssa` repository.
// Note: The compiled binary file is stored in
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world_with_move_function.bin
//
//
// Usage:
// cargo run --bin run_hello_world_with_move_function /path/to/guest/binary <function> <params>
//
// Example:
// cargo run --bin run_hello_world_with_move_function \
// methods/guest/target/riscv32im-risc0-zkvm-elf/docker/hello_world_with_move_function.bin \
// write-public Ds8q5PjLcKwwV97Zi7duhRVF9uwA2PuYMoLL7FwCzsXE Hola
type Instruction = (u8, Vec<u8>);
const WRITE_FUNCTION_ID: u8 = 0;
const MOVE_DATA_FUNCTION_ID: u8 = 1;
#[derive(Parser, Debug)]
struct Cli {
/// Path to program binary
program_path: String,
#[command(subcommand)]
command: Command,
}
#[derive(Subcommand, Debug)]
enum Command {
/// Write instruction into one account
WritePublic {
account_id: String,
greeting: String,
},
WritePrivate {
account_id: String,
greeting: String,
},
/// Move data between two accounts
MoveDataPublicToPublic {
from: String,
to: String,
},
MoveDataPublicToPrivate {
from: String,
to: String,
},
}
#[tokio::main]
async fn main() {
let cli = Cli::parse();
// Load the program
let bytecode: Vec<u8> = std::fs::read(cli.program_path).unwrap();
let program = Program::new(bytecode).unwrap();
// Load wallet config and storage
let wallet_config = fetch_config().await.unwrap();
let wallet_core = WalletCore::start_from_config_update_chain(wallet_config)
.await
.unwrap();
match cli.command {
Command::WritePublic {
account_id,
greeting,
} => {
let instruction: Instruction = (WRITE_FUNCTION_ID, greeting.into_bytes());
let account_id = account_id.parse().unwrap();
let nonces = vec![];
let message = public_transaction::Message::try_new(
program.id(),
vec![account_id],
nonces,
instruction,
)
.unwrap();
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set);
// Submit the transaction
let _response = wallet_core
.sequencer_client
.send_tx_public(tx)
.await
.unwrap();
}
Command::WritePrivate {
account_id,
greeting,
} => {
let instruction: Instruction = (WRITE_FUNCTION_ID, greeting.into_bytes());
let account_id = account_id.parse().unwrap();
let accounts = vec![PrivacyPreservingAccount::PrivateOwned(account_id)];
wallet_core
.send_privacy_preserving_tx(
accounts,
&Program::serialize_instruction(instruction).unwrap(),
&program.into(),
)
.await
.unwrap();
}
Command::MoveDataPublicToPublic { from, to } => {
let instruction: Instruction = (MOVE_DATA_FUNCTION_ID, vec![]);
let from = from.parse().unwrap();
let to = to.parse().unwrap();
let nonces = vec![];
let message = public_transaction::Message::try_new(
program.id(),
vec![from, to],
nonces,
instruction,
)
.unwrap();
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set);
// Submit the transaction
let _response = wallet_core
.sequencer_client
.send_tx_public(tx)
.await
.unwrap();
}
Command::MoveDataPublicToPrivate { from, to } => {
let instruction: Instruction = (MOVE_DATA_FUNCTION_ID, vec![]);
let from = from.parse().unwrap();
let to = to.parse().unwrap();
let accounts = vec![
PrivacyPreservingAccount::Public(from),
PrivacyPreservingAccount::PrivateOwned(to),
];
wallet_core
.send_privacy_preserving_tx(
accounts,
&Program::serialize_instruction(instruction).unwrap(),
&program.into(),
)
.await
.unwrap();
}
};
}

View File

@ -0,0 +1,26 @@
[package]
name = "integration_tests"
version = "0.1.0"
edition = "2024"
[dependencies]
nssa_core = { workspace = true, features = ["host"] }
nssa.workspace = true
sequencer_core = { workspace = true, features = ["testnet"] }
sequencer_runner.workspace = true
wallet.workspace = true
common.workspace = true
key_protocol.workspace = true
proc_macro_test_attribute = { path = "./proc_macro_test_attribute" }
clap = { workspace = true, features = ["derive", "env"] }
anyhow.workspace = true
env_logger.workspace = true
log.workspace = true
actix.workspace = true
actix-web.workspace = true
base64.workspace = true
tokio.workspace = true
hex.workspace = true
tempfile.workspace = true
borsh.workspace = true

View File

@ -0,0 +1,158 @@
{
"home": "./sequencer",
"override_rust_log": null,
"genesis_id": 1,
"is_genesis_random": true,
"max_num_tx_in_block": 20,
"mempool_max_size": 10000,
"block_create_timeout_millis": 10000,
"port": 3040,
"initial_accounts": [
{
"account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
"balance": 10000
},
{
"account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
"balance": 20000
}
],
"initial_commitments": [
{
"npk": [
63,
202,
178,
231,
183,
82,
237,
212,
216,
221,
215,
255,
153,
101,
177,
161,
254,
210,
128,
122,
54,
190,
230,
151,
183,
64,
225,
229,
113,
1,
228,
97
],
"account": {
"program_owner": [
0,
0,
0,
0,
0,
0,
0,
0
],
"balance": 10000,
"data": [],
"nonce": 0
}
},
{
"npk": [
192,
251,
166,
243,
167,
236,
84,
249,
35,
136,
130,
172,
219,
225,
161,
139,
229,
89,
243,
125,
194,
213,
209,
30,
23,
174,
100,
244,
124,
74,
140,
47
],
"account": {
"program_owner": [
0,
0,
0,
0,
0,
0,
0,
0
],
"balance": 20000,
"data": [],
"nonce": 0
}
}
],
"signing_key": [
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37
]
}

View File

@ -0,0 +1,547 @@
{
"override_rust_log": null,
"sequencer_addr": "http://127.0.0.1:3040",
"seq_poll_timeout_millis": 12000,
"seq_tx_poll_max_blocks": 5,
"seq_poll_max_retries": 5,
"seq_block_poll_max_amount": 100,
"initial_accounts": [
{
"Public": {
"account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
"pub_sign_key": [
16,
162,
106,
154,
236,
125,
52,
184,
35,
100,
238,
174,
69,
197,
41,
77,
187,
10,
118,
75,
0,
11,
148,
238,
185,
181,
133,
17,
220,
72,
124,
77
]
}
},
{
"Public": {
"account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
"pub_sign_key": [
113,
121,
64,
177,
204,
85,
229,
214,
178,
6,
109,
191,
29,
154,
63,
38,
242,
18,
244,
219,
8,
208,
35,
136,
23,
127,
207,
237,
216,
169,
190,
27
]
}
},
{
"Private": {
"account_id": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw",
"account": {
"program_owner": [
0,
0,
0,
0,
0,
0,
0,
0
],
"balance": 10000,
"data": [],
"nonce": 0
},
"key_chain": {
"secret_spending_key": [
251,
82,
235,
1,
146,
96,
30,
81,
162,
234,
33,
15,
123,
129,
116,
0,
84,
136,
176,
70,
190,
224,
161,
54,
134,
142,
154,
1,
18,
251,
242,
189
],
"private_key_holder": {
"nullifier_secret_key": [
29,
250,
10,
187,
35,
123,
180,
250,
246,
97,
216,
153,
44,
156,
16,
93,
241,
26,
174,
219,
72,
84,
34,
247,
112,
101,
217,
243,
189,
173,
75,
20
],
"incoming_viewing_secret_key": [
251,
201,
22,
154,
100,
165,
218,
108,
163,
190,
135,
91,
145,
84,
69,
241,
46,
117,
217,
110,
197,
248,
91,
193,
14,
104,
88,
103,
67,
153,
182,
158
],
"outgoing_viewing_secret_key": [
25,
67,
121,
76,
175,
100,
30,
198,
105,
123,
49,
169,
75,
178,
75,
210,
100,
143,
210,
243,
228,
243,
21,
18,
36,
84,
164,
186,
139,
113,
214,
12
]
},
"nullifer_public_key": [
63,
202,
178,
231,
183,
82,
237,
212,
216,
221,
215,
255,
153,
101,
177,
161,
254,
210,
128,
122,
54,
190,
230,
151,
183,
64,
225,
229,
113,
1,
228,
97
],
"incoming_viewing_public_key": [
3,
235,
139,
131,
237,
177,
122,
189,
6,
177,
167,
178,
202,
117,
246,
58,
28,
65,
132,
79,
220,
139,
119,
243,
187,
160,
212,
121,
61,
247,
116,
72,
205
]
}
}
},
{
"Private": {
"account_id": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX",
"account": {
"program_owner": [
0,
0,
0,
0,
0,
0,
0,
0
],
"balance": 20000,
"data": [],
"nonce": 0
},
"key_chain": {
"secret_spending_key": [
238,
171,
241,
69,
111,
217,
85,
64,
19,
82,
18,
189,
32,
91,
78,
175,
107,
7,
109,
60,
52,
44,
243,
230,
72,
244,
192,
92,
137,
33,
118,
254
],
"private_key_holder": {
"nullifier_secret_key": [
25,
211,
215,
119,
57,
223,
247,
37,
245,
144,
122,
29,
118,
245,
83,
228,
23,
9,
101,
120,
88,
33,
238,
207,
128,
61,
110,
2,
89,
62,
164,
13
],
"incoming_viewing_secret_key": [
193,
181,
14,
196,
142,
84,
15,
65,
128,
101,
70,
196,
241,
47,
130,
221,
23,
146,
161,
237,
221,
40,
19,
126,
59,
15,
169,
236,
25,
105,
104,
231
],
"outgoing_viewing_secret_key": [
20,
170,
220,
108,
41,
23,
155,
217,
247,
190,
175,
168,
247,
34,
105,
134,
114,
74,
104,
91,
211,
62,
126,
13,
130,
100,
241,
214,
250,
236,
38,
150
]
},
"nullifer_public_key": [
192,
251,
166,
243,
167,
236,
84,
249,
35,
136,
130,
172,
219,
225,
161,
139,
229,
89,
243,
125,
194,
213,
209,
30,
23,
174,
100,
244,
124,
74,
140,
47
],
"incoming_viewing_public_key": [
2,
181,
98,
93,
216,
241,
241,
110,
58,
198,
119,
174,
250,
184,
1,
204,
200,
173,
44,
238,
37,
247,
170,
156,
100,
254,
116,
242,
28,
183,
187,
77,
255
]
}
}
}
],
"basic_auth": null
}

View File

@ -0,0 +1,9 @@
[package]
name = "proc_macro_test_attribute"
version = "0.1.0"
edition = "2024"
[dependencies]
[lib]
proc-macro = true

View File

@ -0,0 +1,49 @@
extern crate proc_macro;
use proc_macro::*;
#[proc_macro_attribute]
pub fn nssa_integration_test(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = item.to_string();
let fn_keyword = "fn ";
let fn_keyword_alternative = "fn\n";
let mut start_opt = None;
let mut fn_name = String::new();
if let Some(start) = input.find(fn_keyword) {
start_opt = Some(start);
} else if let Some(start) = input.find(fn_keyword_alternative) {
start_opt = Some(start);
}
if let Some(start) = start_opt {
let rest = &input[start + fn_keyword.len()..];
if let Some(end) = rest.find(|c: char| c == '(' || c.is_whitespace()) {
let name = &rest[..end];
fn_name = name.to_string();
}
} else {
println!("ERROR: keyword fn not found");
}
let extension = format!(
r#"
{input}
function_map.insert("{fn_name}".to_string(), |home_dir: PathBuf| Box::pin(async {{
let res = pre_test(home_dir).await.unwrap();
info!("Waiting for first block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
{fn_name}().await;
post_test(res).await;
}}));
"#
);
extension.parse().unwrap()
}

View File

@ -0,0 +1,189 @@
use std::path::PathBuf;
use actix_web::dev::ServerHandle;
use anyhow::Result;
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
use clap::Parser;
use common::{
sequencer_client::SequencerClient,
transaction::{EncodedTransaction, NSSATransaction},
};
use log::{info, warn};
use nssa::PrivacyPreservingTransaction;
use nssa_core::Commitment;
use sequencer_core::config::SequencerConfig;
use sequencer_runner::startup_sequencer;
use tempfile::TempDir;
use tokio::task::JoinHandle;
use crate::test_suite_map::{prepare_function_map, tps_test};
#[macro_use]
extern crate proc_macro_test_attribute;
pub mod test_suite_map;
mod tps_test_utils;
#[derive(Parser, Debug)]
#[clap(version)]
struct Args {
/// Path to configs
home_dir: PathBuf,
/// Test name
test_name: String,
}
pub const ACC_SENDER: &str = "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
pub const ACC_RECEIVER: &str = "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw";
pub const ACC_SENDER_PRIVATE: &str = "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw";
pub const ACC_RECEIVER_PRIVATE: &str = "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX";
pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &str = "data_changer.bin";
fn make_public_account_input_from_str(account_id: &str) -> String {
format!("Public/{account_id}")
}
fn make_private_account_input_from_str(account_id: &str) -> String {
format!("Private/{account_id}")
}
#[allow(clippy::type_complexity)]
pub async fn pre_test(
home_dir: PathBuf,
) -> Result<(ServerHandle, JoinHandle<Result<()>>, TempDir)> {
wallet::cli::execute_setup("test_pass".to_owned()).await?;
let home_dir_sequencer = home_dir.join("sequencer");
let mut sequencer_config =
sequencer_runner::config::from_file(home_dir_sequencer.join("sequencer_config.json"))
.unwrap();
let temp_dir_sequencer = replace_home_dir_with_temp_dir_in_configs(&mut sequencer_config);
let (seq_http_server_handle, sequencer_loop_handle) =
startup_sequencer(sequencer_config).await?;
Ok((
seq_http_server_handle,
sequencer_loop_handle,
temp_dir_sequencer,
))
}
pub fn replace_home_dir_with_temp_dir_in_configs(
sequencer_config: &mut SequencerConfig,
) -> TempDir {
let temp_dir_sequencer = tempfile::tempdir().unwrap();
sequencer_config.home = temp_dir_sequencer.path().to_path_buf();
temp_dir_sequencer
}
#[allow(clippy::type_complexity)]
pub async fn post_test(residual: (ServerHandle, JoinHandle<Result<()>>, TempDir)) {
let (seq_http_server_handle, sequencer_loop_handle, _) = residual;
info!("Cleanup");
sequencer_loop_handle.abort();
seq_http_server_handle.stop(true).await;
let wallet_home = wallet::helperfunctions::get_home().unwrap();
let persistent_data_home = wallet_home.join("storage.json");
// Removing persistent accounts after run to not affect other executions
// Not necessary an error, if fails as there is tests for failure scenario
let _ = std::fs::remove_file(persistent_data_home)
.inspect_err(|err| warn!("Failed to remove persistent data with err {err:#?}"));
// At this point all of the references to sequencer_core must be lost.
// So they are dropped and tempdirs will be dropped too,
}
pub async fn main_tests_runner() -> Result<()> {
env_logger::init();
let args = Args::parse();
let Args {
home_dir,
test_name,
} = args;
let function_map = prepare_function_map();
match test_name.as_str() {
"all" => {
// Tests that use default config
for (_, fn_pointer) in function_map {
fn_pointer(home_dir.clone()).await;
}
// Run TPS test with its own specific config
tps_test().await;
}
_ => {
let fn_pointer = function_map.get(&test_name).expect("Unknown test name");
fn_pointer(home_dir.clone()).await;
}
}
Ok(())
}
async fn fetch_privacy_preserving_tx(
seq_client: &SequencerClient,
tx_hash: String,
) -> PrivacyPreservingTransaction {
let transaction_encoded = seq_client
.get_transaction_by_hash(tx_hash.clone())
.await
.unwrap()
.transaction
.unwrap();
let tx_base64_decode = BASE64.decode(transaction_encoded).unwrap();
match NSSATransaction::try_from(
&borsh::from_slice::<EncodedTransaction>(&tx_base64_decode).unwrap(),
)
.unwrap()
{
NSSATransaction::PrivacyPreserving(privacy_preserving_transaction) => {
privacy_preserving_transaction
}
_ => panic!("Invalid tx type"),
}
}
async fn verify_commitment_is_in_state(
commitment: Commitment,
seq_client: &SequencerClient,
) -> bool {
matches!(
seq_client.get_proof_for_commitment(commitment).await,
Ok(Some(_))
)
}
#[cfg(test)]
mod tests {
use crate::{make_private_account_input_from_str, make_public_account_input_from_str};
#[test]
fn correct_account_id_from_prefix() {
let account_id1 = "cafecafe";
let account_id2 = "deadbeaf";
let account_id1_pub = make_public_account_input_from_str(account_id1);
let account_id2_priv = make_private_account_input_from_str(account_id2);
assert_eq!(account_id1_pub, "Public/cafecafe".to_string());
assert_eq!(account_id2_priv, "Private/deadbeaf".to_string());
}
}

View File

@ -1,8 +1,7 @@
use anyhow::Result;
use integration_tests::main_tests_runner;
use node_runner::main_runner;
pub const NUM_THREADS: usize = 4;
pub const NUM_THREADS: usize = 8;
fn main() -> Result<()> {
actix::System::with_tokio_rt(|| {
@ -12,5 +11,5 @@ fn main() -> Result<()> {
.build()
.unwrap()
})
.block_on(main_runner())
.block_on(main_tests_runner())
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
use std::time::Duration;
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
use nssa::{
Account, AccountId, PrivacyPreservingTransaction, PrivateKey, PublicKey, PublicTransaction,
privacy_preserving_transaction::{self as pptx, circuit},
program::Program,
public_transaction as putx,
};
use nssa_core::{
MembershipProof, NullifierPublicKey,
account::{AccountWithMetadata, data::Data},
encryption::IncomingViewingPublicKey,
};
use sequencer_core::config::{AccountInitialData, CommitmentsInitialData, SequencerConfig};
pub(crate) struct TpsTestManager {
public_keypairs: Vec<(PrivateKey, AccountId)>,
target_tps: u64,
}
impl TpsTestManager {
/// Generates public account keypairs. These are used to populate the config and to generate
/// valid public transactions for the tps test.
pub(crate) fn new(target_tps: u64, number_transactions: usize) -> Self {
let public_keypairs = (1..(number_transactions + 2))
.map(|i| {
let mut private_key_bytes = [0u8; 32];
private_key_bytes[..8].copy_from_slice(&i.to_le_bytes());
let private_key = PrivateKey::try_new(private_key_bytes).unwrap();
let public_key = PublicKey::new_from_private_key(&private_key);
let account_id = AccountId::from(&public_key);
(private_key, account_id)
})
.collect::<Vec<_>>();
Self {
public_keypairs,
target_tps,
}
}
pub(crate) fn target_time(&self) -> Duration {
let number_transactions = (self.public_keypairs.len() - 1) as u64;
Duration::from_secs_f64(number_transactions as f64 / self.target_tps as f64)
}
/// Build a batch of public transactions to submit to the node.
pub fn build_public_txs(&self) -> Vec<PublicTransaction> {
// Create valid public transactions
let program = Program::authenticated_transfer_program();
let public_txs: Vec<PublicTransaction> = self
.public_keypairs
.windows(2)
.map(|pair| {
let amount: u128 = 1;
let message = putx::Message::try_new(
program.id(),
[pair[0].1, pair[1].1].to_vec(),
[0u128].to_vec(),
amount,
)
.unwrap();
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[&pair[0].0]);
PublicTransaction::new(message, witness_set)
})
.collect();
public_txs
}
/// Generates a sequencer configuration with initial balance in a number of public accounts.
/// The transactions generated with the function `build_public_txs` will be valid in a node
/// started with the config from this method.
pub(crate) fn generate_tps_test_config(&self) -> SequencerConfig {
// Create public public keypairs
let initial_public_accounts = self
.public_keypairs
.iter()
.map(|(_, account_id)| AccountInitialData {
account_id: account_id.to_string(),
balance: 10,
})
.collect();
// Generate an initial commitment to be used with the privacy preserving transaction
// created with the `build_privacy_transaction` function.
let sender_nsk = [1; 32];
let sender_npk = NullifierPublicKey::from(&sender_nsk);
let account = Account {
balance: 100,
nonce: 0xdeadbeef,
program_owner: Program::authenticated_transfer_program().id(),
data: Data::default(),
};
let initial_commitment = CommitmentsInitialData {
npk: sender_npk,
account,
};
SequencerConfig {
home: ".".into(),
override_rust_log: None,
genesis_id: 1,
is_genesis_random: true,
max_num_tx_in_block: 300,
mempool_max_size: 10000,
block_create_timeout_millis: 12000,
port: 3040,
initial_accounts: initial_public_accounts,
initial_commitments: vec![initial_commitment],
signing_key: [37; 32],
}
}
}
/// Builds a single privacy transaction to use in stress tests. This involves generating a proof so
/// it may take a while to run. In normal execution of the node this transaction will be accepted
/// only once. Disabling the node's nullifier uniqueness check allows to submit this transaction
/// multiple times with the purpose of testing the node's processing performance.
#[allow(unused)]
fn build_privacy_transaction() -> PrivacyPreservingTransaction {
let program = Program::authenticated_transfer_program();
let sender_nsk = [1; 32];
let sender_isk = [99; 32];
let sender_ipk = IncomingViewingPublicKey::from_scalar(sender_isk);
let sender_npk = NullifierPublicKey::from(&sender_nsk);
let sender_pre = AccountWithMetadata::new(
Account {
balance: 100,
nonce: 0xdeadbeef,
program_owner: program.id(),
data: Data::default(),
},
true,
AccountId::from(&sender_npk),
);
let recipient_nsk = [2; 32];
let recipient_isk = [99; 32];
let recipient_ipk = IncomingViewingPublicKey::from_scalar(recipient_isk);
let recipient_npk = NullifierPublicKey::from(&recipient_nsk);
let recipient_pre =
AccountWithMetadata::new(Account::default(), false, AccountId::from(&recipient_npk));
let eph_holder_from = EphemeralKeyHolder::new(&sender_npk);
let sender_ss = eph_holder_from.calculate_shared_secret_sender(&sender_ipk);
let sender_epk = eph_holder_from.generate_ephemeral_public_key();
let eph_holder_to = EphemeralKeyHolder::new(&recipient_npk);
let recipient_ss = eph_holder_to.calculate_shared_secret_sender(&recipient_ipk);
let recipient_epk = eph_holder_from.generate_ephemeral_public_key();
let balance_to_move: u128 = 1;
let proof: MembershipProof = (
1,
vec![[
170, 10, 217, 228, 20, 35, 189, 177, 238, 235, 97, 129, 132, 89, 96, 247, 86, 91, 222,
214, 38, 194, 216, 67, 56, 251, 208, 226, 0, 117, 149, 39,
]],
);
let (output, proof) = circuit::execute_and_prove(
&[sender_pre, recipient_pre],
&Program::serialize_instruction(balance_to_move).unwrap(),
&[1, 2],
&[0xdeadbeef1, 0xdeadbeef2],
&[
(sender_npk.clone(), sender_ss),
(recipient_npk.clone(), recipient_ss),
],
&[sender_nsk],
&[Some(proof)],
&program.into(),
)
.unwrap();
let message = pptx::message::Message::try_from_circuit_output(
vec![],
vec![],
vec![
(sender_npk, sender_ipk, sender_epk),
(recipient_npk, recipient_ipk, recipient_epk),
],
output,
)
.unwrap();
let witness_set = pptx::witness_set::WitnessSet::for_message(&message, proof, &[]);
pptx::PrivacyPreservingTransaction::new(message, witness_set)
}

22
key_protocol/Cargo.toml Normal file
View File

@ -0,0 +1,22 @@
[package]
name = "key_protocol"
version = "0.1.0"
edition = "2024"
[dependencies]
nssa.workspace = true
nssa_core.workspace = true
common.workspace = true
anyhow.workspace = true
serde.workspace = true
k256.workspace = true
sha2.workspace = true
rand.workspace = true
base58.workspace = true
hex.workspace = true
aes-gcm.workspace = true
bip39.workspace = true
hmac-sha512.workspace = true
thiserror.workspace = true
itertools.workspace = true

View File

@ -0,0 +1,52 @@
use nssa_core::{
NullifierPublicKey, SharedSecretKey,
encryption::{EphemeralPublicKey, EphemeralSecretKey, IncomingViewingPublicKey},
};
use rand::{RngCore, rngs::OsRng};
use sha2::Digest;
#[derive(Debug)]
/// Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral
/// public keys. Can produce shared secret for sender.
pub struct EphemeralKeyHolder {
ephemeral_secret_key: EphemeralSecretKey,
}
pub fn produce_one_sided_shared_secret_receiver(
ipk: &IncomingViewingPublicKey,
) -> (SharedSecretKey, EphemeralPublicKey) {
let mut esk = [0; 32];
OsRng.fill_bytes(&mut esk);
(
SharedSecretKey::new(&esk, ipk),
EphemeralPublicKey::from_scalar(esk),
)
}
impl EphemeralKeyHolder {
pub fn new(receiver_nullifier_public_key: &NullifierPublicKey) -> Self {
let mut nonce_bytes = [0; 16];
OsRng.fill_bytes(&mut nonce_bytes);
let mut hasher = sha2::Sha256::new();
hasher.update(receiver_nullifier_public_key);
hasher.update(nonce_bytes);
Self {
ephemeral_secret_key: hasher.finalize().into(),
}
}
pub fn generate_ephemeral_public_key(&self) -> EphemeralPublicKey {
EphemeralPublicKey::from_scalar(self.ephemeral_secret_key)
}
pub fn calculate_shared_secret_sender(
&self,
receiver_incoming_viewing_public_key: &IncomingViewingPublicKey,
) -> SharedSecretKey {
SharedSecretKey::new(
&self.ephemeral_secret_key,
receiver_incoming_viewing_public_key,
)
}
}

View File

@ -0,0 +1,298 @@
use std::{fmt::Display, str::FromStr};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize, Hash)]
pub struct ChainIndex(Vec<u32>);
#[derive(thiserror::Error, Debug)]
pub enum ChainIndexError {
#[error("No root found")]
NoRootFound,
#[error("Failed to parse segment into a number")]
ParseIntError(#[from] std::num::ParseIntError),
}
impl FromStr for ChainIndex {
type Err = ChainIndexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if !s.starts_with('/') {
return Err(ChainIndexError::NoRootFound);
}
if s == "/" {
return Ok(ChainIndex(vec![]));
}
let uprooted_substring = s.strip_prefix("/").unwrap();
let splitted_chain: Vec<&str> = uprooted_substring.split("/").collect();
let mut res = vec![];
for split_ch in splitted_chain {
let cci = split_ch.parse()?;
res.push(cci);
}
Ok(Self(res))
}
}
impl Display for ChainIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "/")?;
for cci in &self.0[..(self.0.len().saturating_sub(1))] {
write!(f, "{cci}/")?;
}
if let Some(last) = self.0.last() {
write!(f, "{}", last)?;
}
Ok(())
}
}
impl Default for ChainIndex {
fn default() -> Self {
ChainIndex::from_str("/").expect("Root parsing failure")
}
}
impl ChainIndex {
pub fn root() -> Self {
ChainIndex::default()
}
pub fn chain(&self) -> &[u32] {
&self.0
}
pub fn next_in_line(&self) -> ChainIndex {
let mut chain = self.0.clone();
// ToDo: Add overflow check
if let Some(last_p) = chain.last_mut() {
*last_p += 1
}
ChainIndex(chain)
}
pub fn previous_in_line(&self) -> Option<ChainIndex> {
let mut chain = self.0.clone();
if let Some(last_p) = chain.last_mut() {
*last_p = last_p.checked_sub(1)?;
}
Some(ChainIndex(chain))
}
pub fn parent(&self) -> Option<ChainIndex> {
if self.0.is_empty() {
None
} else {
Some(ChainIndex(self.0[..(self.0.len() - 1)].to_vec()))
}
}
pub fn nth_child(&self, child_id: u32) -> ChainIndex {
let mut chain = self.0.clone();
chain.push(child_id);
ChainIndex(chain)
}
pub fn depth(&self) -> u32 {
self.0.iter().map(|cci| cci + 1).sum()
}
fn collapse_back(&self) -> Option<Self> {
let mut res = self.parent()?;
let last_mut = res.0.last_mut()?;
*last_mut += *(self.0.last()?) + 1;
Some(res)
}
fn shuffle_iter(&self) -> impl Iterator<Item = ChainIndex> {
self.0
.iter()
.permutations(self.0.len())
.unique()
.map(|item| ChainIndex(item.into_iter().cloned().collect()))
}
pub fn chain_ids_at_depth(depth: usize) -> impl Iterator<Item = ChainIndex> {
let mut stack = vec![ChainIndex(vec![0; depth])];
let mut cumulative_stack = vec![ChainIndex(vec![0; depth])];
while let Some(id) = stack.pop() {
if let Some(collapsed_id) = id.collapse_back() {
for id in collapsed_id.shuffle_iter() {
stack.push(id.clone());
cumulative_stack.push(id);
}
}
}
cumulative_stack.into_iter().unique()
}
pub fn chain_ids_at_depth_rev(depth: usize) -> impl Iterator<Item = ChainIndex> {
let mut stack = vec![ChainIndex(vec![0; depth])];
let mut cumulative_stack = vec![ChainIndex(vec![0; depth])];
while let Some(id) = stack.pop() {
if let Some(collapsed_id) = id.collapse_back() {
for id in collapsed_id.shuffle_iter() {
stack.push(id.clone());
cumulative_stack.push(id);
}
}
}
cumulative_stack.into_iter().rev().unique()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_chain_id_root_correct() {
let chain_id = ChainIndex::root();
let chain_id_2 = ChainIndex::from_str("/").unwrap();
assert_eq!(chain_id, chain_id_2);
}
#[test]
fn test_chain_id_deser_correct() {
let chain_id = ChainIndex::from_str("/257").unwrap();
assert_eq!(chain_id.chain(), &[257]);
}
#[test]
fn test_chain_id_deser_failure_no_root() {
let chain_index_error = ChainIndex::from_str("257").err().unwrap();
assert!(matches!(chain_index_error, ChainIndexError::NoRootFound));
}
#[test]
fn test_chain_id_deser_failure_int_parsing_failure() {
let chain_index_error = ChainIndex::from_str("/hello").err().unwrap();
assert!(matches!(
chain_index_error,
ChainIndexError::ParseIntError(_)
));
}
#[test]
fn test_chain_id_next_in_line_correct() {
let chain_id = ChainIndex::from_str("/257").unwrap();
let next_in_line = chain_id.next_in_line();
assert_eq!(next_in_line, ChainIndex::from_str("/258").unwrap());
}
#[test]
fn test_chain_id_child_correct() {
let chain_id = ChainIndex::from_str("/257").unwrap();
let child = chain_id.nth_child(3);
assert_eq!(child, ChainIndex::from_str("/257/3").unwrap());
}
#[test]
fn test_correct_display() {
let chainid = ChainIndex(vec![5, 7, 8]);
let string_index = format!("{chainid}");
assert_eq!(string_index, "/5/7/8".to_string());
}
#[test]
fn test_prev_in_line() {
let chain_id = ChainIndex(vec![1, 7, 3]);
let prev_chain_id = chain_id.previous_in_line().unwrap();
assert_eq!(prev_chain_id, ChainIndex(vec![1, 7, 2]))
}
#[test]
fn test_prev_in_line_no_prev() {
let chain_id = ChainIndex(vec![1, 7, 0]);
let prev_chain_id = chain_id.previous_in_line();
assert_eq!(prev_chain_id, None)
}
#[test]
fn test_parent() {
let chain_id = ChainIndex(vec![1, 7, 3]);
let parent_chain_id = chain_id.parent().unwrap();
assert_eq!(parent_chain_id, ChainIndex(vec![1, 7]))
}
#[test]
fn test_parent_no_parent() {
let chain_id = ChainIndex(vec![]);
let parent_chain_id = chain_id.parent();
assert_eq!(parent_chain_id, None)
}
#[test]
fn test_parent_root() {
let chain_id = ChainIndex(vec![1]);
let parent_chain_id = chain_id.parent().unwrap();
assert_eq!(parent_chain_id, ChainIndex::root())
}
#[test]
fn test_collapse_back() {
let chain_id = ChainIndex(vec![1, 1]);
let collapsed = chain_id.collapse_back().unwrap();
assert_eq!(collapsed, ChainIndex(vec![3]))
}
#[test]
fn test_collapse_back_one() {
let chain_id = ChainIndex(vec![1]);
let collapsed = chain_id.collapse_back();
assert_eq!(collapsed, None)
}
#[test]
fn test_collapse_back_root() {
let chain_id = ChainIndex(vec![]);
let collapsed = chain_id.collapse_back();
assert_eq!(collapsed, None)
}
#[test]
fn test_shuffle() {
for id in ChainIndex::chain_ids_at_depth(5) {
println!("{id}");
}
}
}

View File

@ -0,0 +1,263 @@
use k256::{Scalar, elliptic_curve::PrimeField};
use nssa_core::encryption::IncomingViewingPublicKey;
use serde::{Deserialize, Serialize};
use crate::key_management::{
KeyChain,
key_tree::traits::KeyNode,
secret_holders::{PrivateKeyHolder, SecretSpendingKey},
};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ChildKeysPrivate {
pub value: (KeyChain, nssa::Account),
pub ccc: [u8; 32],
/// Can be [`None`] if root
pub cci: Option<u32>,
}
impl KeyNode for ChildKeysPrivate {
fn root(seed: [u8; 64]) -> Self {
let hash_value = hmac_sha512::HMAC::mac(seed, "NSSA_master_priv");
let ssk = SecretSpendingKey(
*hash_value
.first_chunk::<32>()
.expect("hash_value is 64 bytes, must be safe to get first 32"),
);
let ccc = *hash_value
.last_chunk::<32>()
.expect("hash_value is 64 bytes, must be safe to get last 32");
let nsk = ssk.generate_nullifier_secret_key();
let isk = ssk.generate_incoming_viewing_secret_key();
let ovk = ssk.generate_outgoing_viewing_secret_key();
let npk = (&nsk).into();
let ipk = IncomingViewingPublicKey::from_scalar(isk);
Self {
value: (
KeyChain {
secret_spending_key: ssk,
nullifer_public_key: npk,
incoming_viewing_public_key: ipk,
private_key_holder: PrivateKeyHolder {
nullifier_secret_key: nsk,
incoming_viewing_secret_key: isk,
outgoing_viewing_secret_key: ovk,
},
},
nssa::Account::default(),
),
ccc,
cci: None,
}
}
fn nth_child(&self, cci: u32) -> Self {
let parent_pt = Scalar::from_repr(
self.value
.0
.private_key_holder
.outgoing_viewing_secret_key
.into(),
)
.expect("Key generated as scalar, must be valid representation")
+ Scalar::from_repr(self.value.0.private_key_holder.nullifier_secret_key.into())
.expect("Key generated as scalar, must be valid representation")
* Scalar::from_repr(
self.value
.0
.private_key_holder
.incoming_viewing_secret_key
.into(),
)
.expect("Key generated as scalar, must be valid representation");
let mut input = vec![];
input.extend_from_slice(b"NSSA_seed_priv");
input.extend_from_slice(&parent_pt.to_bytes());
input.extend_from_slice(&cci.to_le_bytes());
let hash_value = hmac_sha512::HMAC::mac(input, self.ccc);
let ssk = SecretSpendingKey(
*hash_value
.first_chunk::<32>()
.expect("hash_value is 64 bytes, must be safe to get first 32"),
);
let ccc = *hash_value
.last_chunk::<32>()
.expect("hash_value is 64 bytes, must be safe to get last 32");
let nsk = ssk.generate_nullifier_secret_key();
let isk = ssk.generate_incoming_viewing_secret_key();
let ovk = ssk.generate_outgoing_viewing_secret_key();
let npk = (&nsk).into();
let ipk = IncomingViewingPublicKey::from_scalar(isk);
Self {
value: (
KeyChain {
secret_spending_key: ssk,
nullifer_public_key: npk,
incoming_viewing_public_key: ipk,
private_key_holder: PrivateKeyHolder {
nullifier_secret_key: nsk,
incoming_viewing_secret_key: isk,
outgoing_viewing_secret_key: ovk,
},
},
nssa::Account::default(),
),
ccc,
cci: Some(cci),
}
}
fn chain_code(&self) -> &[u8; 32] {
&self.ccc
}
fn child_index(&self) -> Option<u32> {
self.cci
}
fn account_id(&self) -> nssa::AccountId {
nssa::AccountId::from(&self.value.0.nullifer_public_key)
}
}
impl<'a> From<&'a ChildKeysPrivate> for &'a (KeyChain, nssa::Account) {
fn from(value: &'a ChildKeysPrivate) -> Self {
&value.value
}
}
impl<'a> From<&'a mut ChildKeysPrivate> for &'a mut (KeyChain, nssa::Account) {
fn from(value: &'a mut ChildKeysPrivate) -> Self {
&mut value.value
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_keys_deterministic_generation() {
let root_keys = ChildKeysPrivate::root([42; 64]);
let child_keys = root_keys.nth_child(5);
assert_eq!(root_keys.cci, None);
assert_eq!(child_keys.cci, Some(5));
assert_eq!(
root_keys.value.0.secret_spending_key.0,
[
249, 83, 253, 32, 174, 204, 185, 44, 253, 167, 61, 92, 128, 5, 152, 4, 220, 21, 88,
84, 167, 180, 154, 249, 44, 77, 33, 136, 59, 131, 203, 152
]
);
assert_eq!(
child_keys.value.0.secret_spending_key.0,
[
16, 242, 229, 242, 252, 158, 153, 210, 234, 120, 70, 85, 83, 196, 5, 53, 28, 26,
187, 230, 22, 193, 146, 232, 237, 3, 166, 184, 122, 1, 233, 93
]
);
assert_eq!(
root_keys.value.0.private_key_holder.nullifier_secret_key,
[
38, 195, 52, 182, 16, 66, 167, 156, 9, 14, 65, 100, 17, 93, 166, 71, 27, 148, 93,
85, 116, 109, 130, 8, 195, 222, 159, 214, 141, 41, 124, 57
]
);
assert_eq!(
child_keys.value.0.private_key_holder.nullifier_secret_key,
[
215, 46, 2, 151, 174, 60, 86, 154, 5, 3, 175, 245, 12, 176, 220, 58, 250, 118, 236,
49, 254, 221, 229, 58, 40, 1, 170, 145, 175, 108, 23, 170
]
);
assert_eq!(
root_keys
.value
.0
.private_key_holder
.incoming_viewing_secret_key,
[
153, 161, 15, 34, 96, 184, 165, 165, 27, 244, 155, 40, 70, 5, 241, 133, 78, 40, 61,
118, 48, 148, 226, 5, 97, 18, 201, 128, 82, 248, 163, 72
]
);
assert_eq!(
child_keys
.value
.0
.private_key_holder
.incoming_viewing_secret_key,
[
192, 155, 55, 43, 164, 115, 71, 145, 227, 225, 21, 57, 55, 12, 226, 44, 10, 103,
39, 73, 230, 173, 60, 69, 69, 122, 110, 241, 164, 3, 192, 57
]
);
assert_eq!(
root_keys
.value
.0
.private_key_holder
.outgoing_viewing_secret_key,
[
205, 87, 71, 129, 90, 242, 217, 200, 140, 252, 124, 46, 207, 7, 33, 156, 83, 166,
150, 81, 98, 131, 182, 156, 110, 92, 78, 140, 125, 218, 152, 154
]
);
assert_eq!(
child_keys
.value
.0
.private_key_holder
.outgoing_viewing_secret_key,
[
131, 202, 219, 172, 219, 29, 48, 120, 226, 209, 209, 10, 216, 173, 48, 167, 233,
17, 35, 155, 30, 217, 176, 120, 72, 146, 250, 226, 165, 178, 255, 90
]
);
assert_eq!(
root_keys.value.0.nullifer_public_key.0,
[
65, 176, 149, 243, 192, 45, 216, 177, 169, 56, 229, 7, 28, 66, 204, 87, 109, 83,
152, 64, 14, 188, 179, 210, 147, 60, 22, 251, 203, 70, 89, 215
]
);
assert_eq!(
child_keys.value.0.nullifer_public_key.0,
[
69, 104, 130, 115, 48, 134, 19, 188, 67, 148, 163, 54, 155, 237, 57, 27, 136, 228,
111, 233, 205, 158, 149, 31, 84, 11, 241, 176, 243, 12, 138, 249
]
);
assert_eq!(
root_keys.value.0.incoming_viewing_public_key.0,
&[
3, 174, 56, 136, 244, 179, 18, 122, 38, 220, 36, 50, 200, 41, 104, 167, 70, 18, 60,
202, 93, 193, 29, 16, 125, 252, 96, 51, 199, 152, 47, 233, 178
]
);
assert_eq!(
child_keys.value.0.incoming_viewing_public_key.0,
&[
3, 18, 202, 246, 79, 141, 169, 51, 55, 202, 120, 169, 244, 201, 156, 162, 216, 115,
126, 53, 46, 94, 235, 125, 114, 178, 215, 81, 171, 93, 93, 88, 117
]
);
}
}

View File

@ -0,0 +1,132 @@
use serde::{Deserialize, Serialize};
use crate::key_management::key_tree::traits::KeyNode;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ChildKeysPublic {
pub csk: nssa::PrivateKey,
pub cpk: nssa::PublicKey,
pub ccc: [u8; 32],
/// Can be [`None`] if root
pub cci: Option<u32>,
}
impl KeyNode for ChildKeysPublic {
fn root(seed: [u8; 64]) -> Self {
let hash_value = hmac_sha512::HMAC::mac(seed, "NSSA_master_pub");
let csk = nssa::PrivateKey::try_new(*hash_value.first_chunk::<32>().unwrap()).unwrap();
let ccc = *hash_value.last_chunk::<32>().unwrap();
let cpk = nssa::PublicKey::new_from_private_key(&csk);
Self {
csk,
cpk,
ccc,
cci: None,
}
}
fn nth_child(&self, cci: u32) -> Self {
let mut hash_input = vec![];
hash_input.extend_from_slice(self.csk.value());
hash_input.extend_from_slice(&cci.to_le_bytes());
let hash_value = hmac_sha512::HMAC::mac(&hash_input, self.ccc);
let csk = nssa::PrivateKey::try_new(
*hash_value
.first_chunk::<32>()
.expect("hash_value is 64 bytes, must be safe to get first 32"),
)
.unwrap();
let ccc = *hash_value
.last_chunk::<32>()
.expect("hash_value is 64 bytes, must be safe to get last 32");
let cpk = nssa::PublicKey::new_from_private_key(&csk);
Self {
csk,
cpk,
ccc,
cci: Some(cci),
}
}
fn chain_code(&self) -> &[u8; 32] {
&self.ccc
}
fn child_index(&self) -> Option<u32> {
self.cci
}
fn account_id(&self) -> nssa::AccountId {
nssa::AccountId::from(&self.cpk)
}
}
impl<'a> From<&'a ChildKeysPublic> for &'a nssa::PrivateKey {
fn from(value: &'a ChildKeysPublic) -> Self {
&value.csk
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_keys_deterministic_generation() {
let root_keys = ChildKeysPublic::root([42; 64]);
let child_keys = root_keys.nth_child(5);
assert_eq!(root_keys.cci, None);
assert_eq!(child_keys.cci, Some(5));
assert_eq!(
root_keys.ccc,
[
61, 30, 91, 26, 133, 91, 236, 192, 231, 53, 186, 139, 11, 221, 202, 11, 178, 215,
254, 103, 191, 60, 117, 112, 1, 226, 31, 156, 83, 104, 150, 224
]
);
assert_eq!(
child_keys.ccc,
[
67, 26, 102, 68, 189, 155, 102, 80, 199, 188, 112, 142, 207, 157, 36, 210, 48, 224,
35, 6, 112, 180, 11, 190, 135, 218, 9, 14, 84, 231, 58, 98
]
);
assert_eq!(
root_keys.csk.value(),
&[
241, 82, 246, 237, 62, 130, 116, 47, 189, 112, 99, 67, 178, 40, 115, 245, 141, 193,
77, 164, 243, 76, 222, 64, 50, 146, 23, 145, 91, 164, 92, 116
]
);
assert_eq!(
child_keys.csk.value(),
&[
11, 151, 27, 212, 167, 26, 77, 234, 103, 145, 53, 191, 184, 25, 240, 191, 156, 25,
60, 144, 65, 22, 193, 163, 246, 227, 212, 81, 49, 170, 33, 158
]
);
assert_eq!(
root_keys.cpk.value(),
&[
220, 170, 95, 177, 121, 37, 86, 166, 56, 238, 232, 72, 21, 106, 107, 217, 158, 74,
133, 91, 143, 244, 155, 15, 2, 230, 223, 169, 13, 20, 163, 138
]
);
assert_eq!(
child_keys.cpk.value(),
&[
152, 249, 236, 111, 132, 96, 184, 122, 21, 179, 240, 15, 234, 155, 164, 144, 108,
110, 120, 74, 176, 147, 196, 168, 243, 186, 203, 79, 97, 17, 194, 52
]
);
}
}

View File

@ -0,0 +1,606 @@
use std::{
collections::{BTreeMap, HashMap},
sync::Arc,
};
use anyhow::Result;
use common::sequencer_client::SequencerClient;
use serde::{Deserialize, Serialize};
use crate::key_management::{
key_tree::{
chain_index::ChainIndex, keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic,
traits::KeyNode,
},
secret_holders::SeedHolder,
};
pub mod chain_index;
pub mod keys_private;
pub mod keys_public;
pub mod traits;
pub const DEPTH_SOFT_CAP: u32 = 20;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct KeyTree<N: KeyNode> {
pub key_map: BTreeMap<ChainIndex, N>,
pub account_id_map: HashMap<nssa::AccountId, ChainIndex>,
}
pub type KeyTreePublic = KeyTree<ChildKeysPublic>;
pub type KeyTreePrivate = KeyTree<ChildKeysPrivate>;
impl<N: KeyNode> KeyTree<N> {
pub fn new(seed: &SeedHolder) -> Self {
let seed_fit: [u8; 64] = seed
.seed
.clone()
.try_into()
.expect("SeedHolder seed is 64 bytes long");
let root_keys = N::root(seed_fit);
let account_id = root_keys.account_id();
let key_map = BTreeMap::from_iter([(ChainIndex::root(), root_keys)]);
let account_id_map = HashMap::from_iter([(account_id, ChainIndex::root())]);
Self {
key_map,
account_id_map,
}
}
pub fn new_from_root(root: N) -> Self {
let account_id_map = HashMap::from_iter([(root.account_id(), ChainIndex::root())]);
let key_map = BTreeMap::from_iter([(ChainIndex::root(), root)]);
Self {
key_map,
account_id_map,
}
}
// ToDo: Add function to create a tree from list of nodes with consistency check.
pub fn find_next_last_child_of_id(&self, parent_id: &ChainIndex) -> Option<u32> {
if !self.key_map.contains_key(parent_id) {
return None;
}
let leftmost_child = parent_id.nth_child(u32::MIN);
if !self.key_map.contains_key(&leftmost_child) {
return Some(0);
}
let mut right = u32::MAX - 1;
let mut left_border = u32::MIN;
let mut right_border = u32::MAX;
loop {
let rightmost_child = parent_id.nth_child(right);
let rightmost_ref = self.key_map.get(&rightmost_child);
let rightmost_ref_next = self.key_map.get(&rightmost_child.next_in_line());
match (&rightmost_ref, &rightmost_ref_next) {
(Some(_), Some(_)) => {
left_border = right;
right = (right + right_border) / 2;
}
(Some(_), None) => {
break Some(right + 1);
}
(None, None) => {
right_border = right;
right = (left_border + right) / 2;
}
(None, Some(_)) => {
unreachable!();
}
}
}
}
pub fn generate_new_node(
&mut self,
parent_cci: &ChainIndex,
) -> Option<(nssa::AccountId, ChainIndex)> {
let parent_keys = self.key_map.get(parent_cci)?;
let next_child_id = self
.find_next_last_child_of_id(parent_cci)
.expect("Can be None only if parent is not present");
let next_cci = parent_cci.nth_child(next_child_id);
let child_keys = parent_keys.nth_child(next_child_id);
let account_id = child_keys.account_id();
self.key_map.insert(next_cci.clone(), child_keys);
self.account_id_map.insert(account_id, next_cci.clone());
Some((account_id, next_cci))
}
fn find_next_slot_layered(&self) -> ChainIndex {
let mut depth = 1;
'outer: loop {
for chain_id in ChainIndex::chain_ids_at_depth_rev(depth) {
if !self.key_map.contains_key(&chain_id) {
break 'outer chain_id;
}
}
depth += 1;
}
}
pub fn fill_node(&mut self, chain_index: &ChainIndex) -> Option<(nssa::AccountId, ChainIndex)> {
let parent_keys = self.key_map.get(&chain_index.parent()?)?;
let child_id = *chain_index.chain().last()?;
let child_keys = parent_keys.nth_child(child_id);
let account_id = child_keys.account_id();
self.key_map.insert(chain_index.clone(), child_keys);
self.account_id_map.insert(account_id, chain_index.clone());
Some((account_id, chain_index.clone()))
}
pub fn generate_new_node_layered(&mut self) -> Option<(nssa::AccountId, ChainIndex)> {
self.fill_node(&self.find_next_slot_layered())
}
pub fn get_node(&self, account_id: nssa::AccountId) -> Option<&N> {
self.account_id_map
.get(&account_id)
.and_then(|chain_id| self.key_map.get(chain_id))
}
pub fn get_node_mut(&mut self, account_id: nssa::AccountId) -> Option<&mut N> {
self.account_id_map
.get(&account_id)
.and_then(|chain_id| self.key_map.get_mut(chain_id))
}
pub fn insert(&mut self, account_id: nssa::AccountId, chain_index: ChainIndex, node: N) {
self.account_id_map.insert(account_id, chain_index.clone());
self.key_map.insert(chain_index, node);
}
pub fn remove(&mut self, addr: nssa::AccountId) -> Option<N> {
let chain_index = self.account_id_map.remove(&addr).unwrap();
self.key_map.remove(&chain_index)
}
/// Populates tree with children.
///
/// For given `depth` adds children to a tree such that their `ChainIndex::depth(&self) <
/// depth`.
///
/// Tree must be empty before start
pub fn generate_tree_for_depth(&mut self, depth: u32) {
let mut id_stack = vec![ChainIndex::root()];
while let Some(curr_id) = id_stack.pop() {
let mut next_id = curr_id.nth_child(0);
while (next_id.depth()) < depth {
self.generate_new_node(&curr_id);
id_stack.push(next_id.clone());
next_id = next_id.next_in_line();
}
}
}
}
impl KeyTree<ChildKeysPrivate> {
/// Cleanup of all non-initialized accounts in a private tree
///
/// For given `depth` checks children to a tree such that their `ChainIndex::depth(&self) <
/// depth`.
///
/// If account is default, removes them.
///
/// Chain must be parsed for accounts beforehand
///
/// Fast, leaves gaps between accounts
pub fn cleanup_tree_remove_uninit_for_depth(&mut self, depth: u32) {
let mut id_stack = vec![ChainIndex::root()];
while let Some(curr_id) = id_stack.pop() {
if let Some(node) = self.key_map.get(&curr_id)
&& node.value.1 == nssa::Account::default()
&& curr_id != ChainIndex::root()
{
let addr = node.account_id();
self.remove(addr);
}
let mut next_id = curr_id.nth_child(0);
while (next_id.depth()) < depth {
id_stack.push(next_id.clone());
next_id = next_id.next_in_line();
}
}
}
/// Cleanup of non-initialized accounts in a private tree
///
/// If account is default, removes them, stops at first non-default account.
///
/// Walks through tree in lairs of same depth using `ChainIndex::chain_ids_at_depth()`
///
/// Chain must be parsed for accounts beforehand
///
/// Slow, maintains tree consistency.
pub fn cleanup_tree_remove_uninit_layered(&mut self, depth: u32) {
'outer: for i in (1..(depth as usize)).rev() {
println!("Cleanup of tree at depth {i}");
for id in ChainIndex::chain_ids_at_depth(i) {
if let Some(node) = self.key_map.get(&id) {
if node.value.1 == nssa::Account::default() {
let addr = node.account_id();
self.remove(addr);
} else {
break 'outer;
}
}
}
}
}
}
impl KeyTree<ChildKeysPublic> {
/// Cleanup of all non-initialized accounts in a public tree
///
/// For given `depth` checks children to a tree such that their `ChainIndex::depth(&self) <
/// depth`.
///
/// If account is default, removes them.
///
/// Fast, leaves gaps between accounts
pub async fn cleanup_tree_remove_ininit_for_depth(
&mut self,
depth: u32,
client: Arc<SequencerClient>,
) -> Result<()> {
let mut id_stack = vec![ChainIndex::root()];
while let Some(curr_id) = id_stack.pop() {
if let Some(node) = self.key_map.get(&curr_id) {
let address = node.account_id();
let node_acc = client.get_account(address.to_string()).await?.account;
if node_acc == nssa::Account::default() && curr_id != ChainIndex::root() {
self.remove(address);
}
}
let mut next_id = curr_id.nth_child(0);
while (next_id.depth()) < depth {
id_stack.push(next_id.clone());
next_id = next_id.next_in_line();
}
}
Ok(())
}
/// Cleanup of non-initialized accounts in a public tree
///
/// If account is default, removes them, stops at first non-default account.
///
/// Walks through tree in lairs of same depth using `ChainIndex::chain_ids_at_depth()`
///
/// Slow, maintains tree consistency.
pub async fn cleanup_tree_remove_uninit_layered(
&mut self,
depth: u32,
client: Arc<SequencerClient>,
) -> Result<()> {
'outer: for i in (1..(depth as usize)).rev() {
println!("Cleanup of tree at depth {i}");
for id in ChainIndex::chain_ids_at_depth(i) {
if let Some(node) = self.key_map.get(&id) {
let address = node.account_id();
let node_acc = client.get_account(address.to_string()).await?.account;
if node_acc == nssa::Account::default() {
let addr = node.account_id();
self.remove(addr);
} else {
break 'outer;
}
}
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::{collections::HashSet, str::FromStr};
use nssa::AccountId;
use super::*;
fn seed_holder_for_tests() -> SeedHolder {
SeedHolder {
seed: [42; 64].to_vec(),
}
}
#[test]
fn test_simple_key_tree() {
let seed_holder = seed_holder_for_tests();
let tree = KeyTreePublic::new(&seed_holder);
assert!(tree.key_map.contains_key(&ChainIndex::root()));
assert!(tree.account_id_map.contains_key(&AccountId::new([
46, 223, 229, 177, 59, 18, 189, 219, 153, 31, 249, 90, 112, 230, 180, 164, 80, 25, 106,
159, 14, 238, 1, 192, 91, 8, 210, 165, 199, 41, 60, 104,
])));
}
#[test]
fn test_small_key_tree() {
let seed_holder = seed_holder_for_tests();
let mut tree = KeyTreePrivate::new(&seed_holder);
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::root())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 0);
tree.generate_new_node(&ChainIndex::root()).unwrap();
assert!(
tree.key_map
.contains_key(&ChainIndex::from_str("/0").unwrap())
);
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::root())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 1);
tree.generate_new_node(&ChainIndex::root()).unwrap();
tree.generate_new_node(&ChainIndex::root()).unwrap();
tree.generate_new_node(&ChainIndex::root()).unwrap();
tree.generate_new_node(&ChainIndex::root()).unwrap();
tree.generate_new_node(&ChainIndex::root()).unwrap();
tree.generate_new_node(&ChainIndex::root()).unwrap();
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::root())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 7);
}
#[test]
fn test_key_tree_can_not_make_child_keys() {
let seed_holder = seed_holder_for_tests();
let mut tree = KeyTreePrivate::new(&seed_holder);
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::root())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 0);
tree.generate_new_node(&ChainIndex::root()).unwrap();
assert!(
tree.key_map
.contains_key(&ChainIndex::from_str("/0").unwrap())
);
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::root())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 1);
let key_opt = tree.generate_new_node(&ChainIndex::from_str("/3").unwrap());
assert_eq!(key_opt, None);
}
#[test]
fn test_key_tree_complex_structure() {
let seed_holder = seed_holder_for_tests();
let mut tree = KeyTreePublic::new(&seed_holder);
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::root())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 0);
tree.generate_new_node(&ChainIndex::root()).unwrap();
assert!(
tree.key_map
.contains_key(&ChainIndex::from_str("/0").unwrap())
);
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::root())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 1);
tree.generate_new_node(&ChainIndex::root()).unwrap();
assert!(
tree.key_map
.contains_key(&ChainIndex::from_str("/1").unwrap())
);
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::root())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 2);
tree.generate_new_node(&ChainIndex::from_str("/0").unwrap())
.unwrap();
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::from_str("/0").unwrap())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 1);
assert!(
tree.key_map
.contains_key(&ChainIndex::from_str("/0/0").unwrap())
);
tree.generate_new_node(&ChainIndex::from_str("/0").unwrap())
.unwrap();
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::from_str("/0").unwrap())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 2);
assert!(
tree.key_map
.contains_key(&ChainIndex::from_str("/0/1").unwrap())
);
tree.generate_new_node(&ChainIndex::from_str("/0").unwrap())
.unwrap();
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::from_str("/0").unwrap())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 3);
assert!(
tree.key_map
.contains_key(&ChainIndex::from_str("/0/2").unwrap())
);
tree.generate_new_node(&ChainIndex::from_str("/0/1").unwrap())
.unwrap();
assert!(
tree.key_map
.contains_key(&ChainIndex::from_str("/0/1/0").unwrap())
);
let next_last_child_for_parent_id = tree
.find_next_last_child_of_id(&ChainIndex::from_str("/0/1").unwrap())
.unwrap();
assert_eq!(next_last_child_for_parent_id, 1);
}
#[test]
fn test_tree_balancing_automatic() {
let seed_holder = seed_holder_for_tests();
let mut tree = KeyTreePublic::new(&seed_holder);
for _ in 0..100 {
tree.generate_new_node_layered().unwrap();
}
let next_slot = tree.find_next_slot_layered();
assert_eq!(next_slot, ChainIndex::from_str("/0/0/2/1").unwrap());
}
#[test]
fn test_cleanup() {
let seed_holder = seed_holder_for_tests();
let mut tree = KeyTreePrivate::new(&seed_holder);
tree.generate_tree_for_depth(10);
let acc = tree
.key_map
.get_mut(&ChainIndex::from_str("/1").unwrap())
.unwrap();
acc.value.1.balance = 2;
let acc = tree
.key_map
.get_mut(&ChainIndex::from_str("/2").unwrap())
.unwrap();
acc.value.1.balance = 3;
let acc = tree
.key_map
.get_mut(&ChainIndex::from_str("/0/1").unwrap())
.unwrap();
acc.value.1.balance = 5;
let acc = tree
.key_map
.get_mut(&ChainIndex::from_str("/1/0").unwrap())
.unwrap();
acc.value.1.balance = 6;
tree.cleanup_tree_remove_uninit_layered(10);
let mut key_set_res = HashSet::new();
key_set_res.insert("/0".to_string());
key_set_res.insert("/1".to_string());
key_set_res.insert("/2".to_string());
key_set_res.insert("/".to_string());
key_set_res.insert("/0/0".to_string());
key_set_res.insert("/0/1".to_string());
key_set_res.insert("/1/0".to_string());
let mut key_set = HashSet::new();
for key in tree.key_map.keys() {
key_set.insert(key.to_string());
}
assert_eq!(key_set, key_set_res);
let acc = tree
.key_map
.get(&ChainIndex::from_str("/1").unwrap())
.unwrap();
assert_eq!(acc.value.1.balance, 2);
let acc = tree
.key_map
.get(&ChainIndex::from_str("/2").unwrap())
.unwrap();
assert_eq!(acc.value.1.balance, 3);
let acc = tree
.key_map
.get(&ChainIndex::from_str("/0/1").unwrap())
.unwrap();
assert_eq!(acc.value.1.balance, 5);
let acc = tree
.key_map
.get(&ChainIndex::from_str("/1/0").unwrap())
.unwrap();
assert_eq!(acc.value.1.balance, 6);
}
}

View File

@ -0,0 +1,14 @@
/// Trait, that reperesents a Node in hierarchical key tree
pub trait KeyNode {
/// Tree root node
fn root(seed: [u8; 64]) -> Self;
/// `cci`'s child of node
fn nth_child(&self, cci: u32) -> Self;
fn chain_code(&self) -> &[u8; 32];
fn child_index(&self) -> Option<u32>;
fn account_id(&self) -> nssa::AccountId;
}

View File

@ -0,0 +1,155 @@
use nssa_core::{
NullifierPublicKey, SharedSecretKey,
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
};
use secret_holders::{PrivateKeyHolder, SecretSpendingKey, SeedHolder};
use serde::{Deserialize, Serialize};
pub type PublicAccountSigningKey = [u8; 32];
pub mod ephemeral_key_holder;
pub mod key_tree;
pub mod secret_holders;
#[derive(Serialize, Deserialize, Clone, Debug)]
/// Entrypoint to key management
pub struct KeyChain {
pub secret_spending_key: SecretSpendingKey,
pub private_key_holder: PrivateKeyHolder,
pub nullifer_public_key: NullifierPublicKey,
pub incoming_viewing_public_key: IncomingViewingPublicKey,
}
impl KeyChain {
pub fn new_os_random() -> Self {
// Currently dropping SeedHolder at the end of initialization.
// Now entirely sure if we need it in the future.
let seed_holder = SeedHolder::new_os_random();
let secret_spending_key = seed_holder.produce_top_secret_key_holder();
let private_key_holder = secret_spending_key.produce_private_key_holder();
let nullifer_public_key = private_key_holder.generate_nullifier_public_key();
let incoming_viewing_public_key = private_key_holder.generate_incoming_viewing_public_key();
Self {
secret_spending_key,
private_key_holder,
nullifer_public_key,
incoming_viewing_public_key,
}
}
pub fn new_mnemonic(passphrase: String) -> Self {
// Currently dropping SeedHolder at the end of initialization.
// Not entirely sure if we need it in the future.
let seed_holder = SeedHolder::new_mnemonic(passphrase);
let secret_spending_key = seed_holder.produce_top_secret_key_holder();
let private_key_holder = secret_spending_key.produce_private_key_holder();
let nullifer_public_key = private_key_holder.generate_nullifier_public_key();
let incoming_viewing_public_key = private_key_holder.generate_incoming_viewing_public_key();
Self {
secret_spending_key,
private_key_holder,
nullifer_public_key,
incoming_viewing_public_key,
}
}
pub fn calculate_shared_secret_receiver(
&self,
ephemeral_public_key_sender: EphemeralPublicKey,
) -> SharedSecretKey {
SharedSecretKey::new(
&self
.secret_spending_key
.generate_incoming_viewing_secret_key(),
&ephemeral_public_key_sender,
)
}
}
#[cfg(test)]
mod tests {
use aes_gcm::aead::OsRng;
use base58::ToBase58;
use k256::{AffinePoint, elliptic_curve::group::GroupEncoding};
use rand::RngCore;
use super::*;
#[test]
fn test_new_os_random() {
// Ensure that a new KeyChain instance can be created without errors.
let account_id_key_holder = KeyChain::new_os_random();
// Check that key holder fields are initialized with expected types
assert_ne!(
account_id_key_holder.nullifer_public_key.as_ref(),
&[0u8; 32]
);
}
#[test]
fn test_calculate_shared_secret_receiver() {
let account_id_key_holder = KeyChain::new_os_random();
// Generate a random ephemeral public key sender
let mut scalar = [0; 32];
OsRng.fill_bytes(&mut scalar);
let ephemeral_public_key_sender = EphemeralPublicKey::from_scalar(scalar);
// Calculate shared secret
let _shared_secret =
account_id_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
}
#[test]
fn key_generation_test() {
let seed_holder = SeedHolder::new_os_random();
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
let utxo_secret_key_holder = top_secret_key_holder.produce_private_key_holder();
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
let viewing_public_key = utxo_secret_key_holder.generate_incoming_viewing_public_key();
let pub_account_signing_key = nssa::PrivateKey::new_os_random();
let public_key = nssa::PublicKey::new_from_private_key(&pub_account_signing_key);
let account = nssa::AccountId::from(&public_key);
println!("======Prerequisites======");
println!();
println!(
"Group generator {:?}",
hex::encode(AffinePoint::GENERATOR.to_bytes())
);
println!();
println!("======Holders======");
println!();
println!("{seed_holder:?}");
println!("{top_secret_key_holder:?}");
println!("{utxo_secret_key_holder:?}");
println!();
println!("======Public data======");
println!();
println!("Account {:?}", account.value().to_base58());
println!(
"Nulifier public key {:?}",
hex::encode(nullifer_public_key.to_byte_array())
);
println!(
"Viewing public key {:?}",
hex::encode(viewing_public_key.to_bytes())
);
}
}

View File

@ -0,0 +1,181 @@
use bip39::Mnemonic;
use common::HashType;
use nssa_core::{
NullifierPublicKey, NullifierSecretKey,
encryption::{IncomingViewingPublicKey, Scalar},
};
use rand::{RngCore, rngs::OsRng};
use serde::{Deserialize, Serialize};
use sha2::{Digest, digest::FixedOutput};
const NSSA_ENTROPY_BYTES: [u8; 32] = [0; 32];
#[derive(Debug)]
/// Seed holder. Non-clonable to ensure that different holders use different seeds.
/// Produces `TopSecretKeyHolder` objects.
pub struct SeedHolder {
// ToDo: Needs to be vec as serde derives is not implemented for [u8; 64]
pub(crate) seed: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Secret spending key object. Can produce `PrivateKeyHolder` objects.
pub struct SecretSpendingKey(pub(crate) [u8; 32]);
pub type IncomingViewingSecretKey = Scalar;
pub type OutgoingViewingSecretKey = Scalar;
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Private key holder. Produces public keys. Can produce account_id. Can produce shared secret for
/// recepient.
pub struct PrivateKeyHolder {
pub nullifier_secret_key: NullifierSecretKey,
pub(crate) incoming_viewing_secret_key: IncomingViewingSecretKey,
pub outgoing_viewing_secret_key: OutgoingViewingSecretKey,
}
impl SeedHolder {
pub fn new_os_random() -> Self {
let mut enthopy_bytes: [u8; 32] = [0; 32];
OsRng.fill_bytes(&mut enthopy_bytes);
let mnemonic = Mnemonic::from_entropy(&enthopy_bytes)
.expect("Enthropy must be a multiple of 32 bytes");
let seed_wide = mnemonic.to_seed("mnemonic");
Self {
seed: seed_wide.to_vec(),
}
}
pub fn new_mnemonic(passphrase: String) -> Self {
let mnemonic = Mnemonic::from_entropy(&NSSA_ENTROPY_BYTES)
.expect("Enthropy must be a multiple of 32 bytes");
let seed_wide = mnemonic.to_seed(passphrase);
Self {
seed: seed_wide.to_vec(),
}
}
pub fn generate_secret_spending_key_hash(&self) -> HashType {
let mut hash = hmac_sha512::HMAC::mac(&self.seed, "NSSA_seed");
for _ in 1..2048 {
hash = hmac_sha512::HMAC::mac(hash, "NSSA_seed");
}
// Safe unwrap
*hash.first_chunk::<32>().unwrap()
}
pub fn produce_top_secret_key_holder(&self) -> SecretSpendingKey {
SecretSpendingKey(self.generate_secret_spending_key_hash())
}
}
impl SecretSpendingKey {
pub fn generate_nullifier_secret_key(&self) -> NullifierSecretKey {
let mut hasher = sha2::Sha256::new();
hasher.update("NSSA_keys");
hasher.update(self.0);
hasher.update([1u8]);
hasher.update([0u8; 22]);
<NullifierSecretKey>::from(hasher.finalize_fixed())
}
pub fn generate_incoming_viewing_secret_key(&self) -> IncomingViewingSecretKey {
let mut hasher = sha2::Sha256::new();
hasher.update("NSSA_keys");
hasher.update(self.0);
hasher.update([2u8]);
hasher.update([0u8; 22]);
<HashType>::from(hasher.finalize_fixed())
}
pub fn generate_outgoing_viewing_secret_key(&self) -> OutgoingViewingSecretKey {
let mut hasher = sha2::Sha256::new();
hasher.update("NSSA_keys");
hasher.update(self.0);
hasher.update([3u8]);
hasher.update([0u8; 22]);
<HashType>::from(hasher.finalize_fixed())
}
pub fn produce_private_key_holder(&self) -> PrivateKeyHolder {
PrivateKeyHolder {
nullifier_secret_key: self.generate_nullifier_secret_key(),
incoming_viewing_secret_key: self.generate_incoming_viewing_secret_key(),
outgoing_viewing_secret_key: self.generate_outgoing_viewing_secret_key(),
}
}
}
impl PrivateKeyHolder {
pub fn generate_nullifier_public_key(&self) -> NullifierPublicKey {
(&self.nullifier_secret_key).into()
}
pub fn generate_incoming_viewing_public_key(&self) -> IncomingViewingPublicKey {
IncomingViewingPublicKey::from_scalar(self.incoming_viewing_secret_key)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn seed_generation_test() {
let seed_holder = SeedHolder::new_os_random();
assert_eq!(seed_holder.seed.len(), 64);
}
#[test]
fn ssk_generation_test() {
let seed_holder = SeedHolder::new_os_random();
assert_eq!(seed_holder.seed.len(), 64);
let _ = seed_holder.generate_secret_spending_key_hash();
}
#[test]
fn ivs_generation_test() {
let seed_holder = SeedHolder::new_os_random();
assert_eq!(seed_holder.seed.len(), 64);
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
let _ = top_secret_key_holder.generate_incoming_viewing_secret_key();
}
#[test]
fn ovs_generation_test() {
let seed_holder = SeedHolder::new_os_random();
assert_eq!(seed_holder.seed.len(), 64);
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
let _ = top_secret_key_holder.generate_outgoing_viewing_secret_key();
}
#[test]
fn two_seeds_generated_same_from_same_mnemonic() {
let mnemonic = "test_pass";
let seed_holder1 = SeedHolder::new_mnemonic(mnemonic.to_string());
let seed_holder2 = SeedHolder::new_mnemonic(mnemonic.to_string());
assert_eq!(seed_holder1.seed, seed_holder2.seed);
}
}

View File

@ -0,0 +1,205 @@
use std::collections::HashMap;
use anyhow::Result;
use k256::AffinePoint;
use serde::{Deserialize, Serialize};
use crate::key_management::{
KeyChain,
key_tree::{KeyTreePrivate, KeyTreePublic, chain_index::ChainIndex},
secret_holders::SeedHolder,
};
pub type PublicKey = AffinePoint;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NSSAUserData {
/// Default public accounts
pub default_pub_account_signing_keys: HashMap<nssa::AccountId, nssa::PrivateKey>,
/// Default private accounts
pub default_user_private_accounts:
HashMap<nssa::AccountId, (KeyChain, nssa_core::account::Account)>,
/// Tree of public keys
pub public_key_tree: KeyTreePublic,
/// Tree of private keys
pub private_key_tree: KeyTreePrivate,
}
impl NSSAUserData {
fn valid_public_key_transaction_pairing_check(
accounts_keys_map: &HashMap<nssa::AccountId, nssa::PrivateKey>,
) -> bool {
let mut check_res = true;
for (account_id, key) in accounts_keys_map {
let expected_account_id =
nssa::AccountId::from(&nssa::PublicKey::new_from_private_key(key));
if &expected_account_id != account_id {
println!("{}, {}", expected_account_id, account_id);
check_res = false;
}
}
check_res
}
fn valid_private_key_transaction_pairing_check(
accounts_keys_map: &HashMap<nssa::AccountId, (KeyChain, nssa_core::account::Account)>,
) -> bool {
let mut check_res = true;
for (account_id, (key, _)) in accounts_keys_map {
let expected_account_id = nssa::AccountId::from(&key.nullifer_public_key);
if expected_account_id != *account_id {
println!("{}, {}", expected_account_id, account_id);
check_res = false;
}
}
check_res
}
pub fn new_with_accounts(
default_accounts_keys: HashMap<nssa::AccountId, nssa::PrivateKey>,
default_accounts_key_chains: HashMap<
nssa::AccountId,
(KeyChain, nssa_core::account::Account),
>,
public_key_tree: KeyTreePublic,
private_key_tree: KeyTreePrivate,
) -> Result<Self> {
if !Self::valid_public_key_transaction_pairing_check(&default_accounts_keys) {
anyhow::bail!(
"Key transaction pairing check not satisfied, there is account_ids, which is not derived from keys"
);
}
if !Self::valid_private_key_transaction_pairing_check(&default_accounts_key_chains) {
anyhow::bail!(
"Key transaction pairing check not satisfied, there is account_ids, which is not derived from keys"
);
}
Ok(Self {
default_pub_account_signing_keys: default_accounts_keys,
default_user_private_accounts: default_accounts_key_chains,
public_key_tree,
private_key_tree,
})
}
/// Generated new private key for public transaction signatures
///
/// Returns the account_id of new account
pub fn generate_new_public_transaction_private_key(
&mut self,
parent_cci: Option<ChainIndex>,
) -> (nssa::AccountId, ChainIndex) {
match parent_cci {
Some(parent_cci) => self
.public_key_tree
.generate_new_node(&parent_cci)
.expect("Parent must be present in a tree"),
None => self
.public_key_tree
.generate_new_node_layered()
.expect("Search for new node slot failed"),
}
}
/// Returns the signing key for public transaction signatures
pub fn get_pub_account_signing_key(
&self,
account_id: &nssa::AccountId,
) -> Option<&nssa::PrivateKey> {
// First seek in defaults
if let Some(key) = self.default_pub_account_signing_keys.get(account_id) {
Some(key)
// Then seek in tree
} else {
self.public_key_tree.get_node(*account_id).map(Into::into)
}
}
/// Generated new private key for privacy preserving transactions
///
/// Returns the account_id of new account
pub fn generate_new_privacy_preserving_transaction_key_chain(
&mut self,
parent_cci: Option<ChainIndex>,
) -> (nssa::AccountId, ChainIndex) {
match parent_cci {
Some(parent_cci) => self
.private_key_tree
.generate_new_node(&parent_cci)
.expect("Parent must be present in a tree"),
None => self
.private_key_tree
.generate_new_node_layered()
.expect("Search for new node slot failed"),
}
}
/// Returns the signing key for public transaction signatures
pub fn get_private_account(
&self,
account_id: &nssa::AccountId,
) -> Option<&(KeyChain, nssa_core::account::Account)> {
// First seek in defaults
if let Some(key) = self.default_user_private_accounts.get(account_id) {
Some(key)
// Then seek in tree
} else {
self.private_key_tree.get_node(*account_id).map(Into::into)
}
}
/// Returns the signing key for public transaction signatures
pub fn get_private_account_mut(
&mut self,
account_id: &nssa::AccountId,
) -> Option<&mut (KeyChain, nssa_core::account::Account)> {
// First seek in defaults
if let Some(key) = self.default_user_private_accounts.get_mut(account_id) {
Some(key)
// Then seek in tree
} else {
self.private_key_tree
.get_node_mut(*account_id)
.map(Into::into)
}
}
}
impl Default for NSSAUserData {
fn default() -> Self {
Self::new_with_accounts(
HashMap::new(),
HashMap::new(),
KeyTreePublic::new(&SeedHolder::new_mnemonic("default".to_string())),
KeyTreePrivate::new(&SeedHolder::new_mnemonic("default".to_string())),
)
.unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_account() {
let mut user_data = NSSAUserData::default();
let (account_id_private, _) = user_data
.generate_new_privacy_preserving_transaction_key_chain(Some(ChainIndex::root()));
let is_key_chain_generated = user_data.get_private_account(&account_id_private).is_some();
assert!(is_key_chain_generated);
let account_id_private_str = account_id_private.to_string();
println!("{account_id_private_str:#?}");
let key_chain = &user_data
.get_private_account(&account_id_private)
.unwrap()
.0;
println!("{key_chain:#?}");
}
}

2
key_protocol/src/lib.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod key_management;
pub mod key_protocol_core;

View File

@ -1,11 +1,10 @@
[package]
name = "mempool"
version = "0.1.0"
edition = "2021"
edition = "2024"
[dependencies]
anyhow.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true
serde.workspace = true
tokio = { workspace = true, features = ["sync"] }
[dev-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }

View File

@ -1,243 +1,99 @@
use std::collections::VecDeque;
use tokio::sync::mpsc::{Receiver, Sender};
use mempoolitem::MemPoolItem;
pub mod mempoolitem;
pub struct MemPool<Item: MemPoolItem> {
items: VecDeque<Item>,
pub struct MemPool<T> {
receiver: Receiver<T>,
}
impl<Item: MemPoolItem> MemPool<Item> {
pub fn new() -> Self {
Self {
items: VecDeque::new(),
}
impl<T> MemPool<T> {
pub fn new(max_size: usize) -> (Self, MemPoolHandle<T>) {
let (sender, receiver) = tokio::sync::mpsc::channel(max_size);
let mem_pool = Self { receiver };
let sender = MemPoolHandle::new(sender);
(mem_pool, sender)
}
pub fn pop_last(&mut self) -> Option<Item> {
self.items.pop_front()
}
pub fn pop(&mut self) -> Option<T> {
use tokio::sync::mpsc::error::TryRecvError;
pub fn peek_last(&self) -> Option<&Item> {
self.items.front()
}
pub fn push_item(&mut self, item: Item) {
self.items.push_back(item);
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn pop_size(&mut self, size: usize) -> Vec<Item> {
let mut ret_vec = vec![];
for _ in 0..size {
let item = self.pop_last();
match item {
Some(item) => ret_vec.push(item),
None => break,
match self.receiver.try_recv() {
Ok(item) => Some(item),
Err(TryRecvError::Empty) => None,
Err(TryRecvError::Disconnected) => {
panic!("Mempool senders disconnected, cannot receive items, this is a bug")
}
}
ret_vec
}
pub fn drain_size(&mut self, remainder: usize) -> Vec<Item> {
self.pop_size(self.len().saturating_sub(remainder))
}
}
impl<Item: MemPoolItem> Default for MemPool<Item> {
fn default() -> Self {
Self::new()
pub struct MemPoolHandle<T> {
sender: Sender<T>,
}
impl<T> MemPoolHandle<T> {
fn new(sender: Sender<T>) -> Self {
Self { sender }
}
/// Send an item to the mempool blocking if max size is reached
pub async fn push(&self, item: T) -> Result<(), tokio::sync::mpsc::error::SendError<T>> {
self.sender.send(item).await
}
}
#[cfg(test)]
mod tests {
use std::vec;
use tokio::test;
use super::*;
pub type ItemId = u64;
#[derive(Debug, PartialEq, Eq)]
pub struct TestItem {
id: ItemId,
}
impl MemPoolItem for TestItem {
type Identifier = ItemId;
fn identifier(&self) -> Self::Identifier {
self.id
}
}
fn test_item_with_id(id: u64) -> TestItem {
TestItem { id }
#[test]
async fn test_mempool_new() {
let (mut pool, _handle): (MemPool<u64>, _) = MemPool::new(10);
assert_eq!(pool.pop(), None);
}
#[test]
fn test_create_empty_mempool() {
let _: MemPool<TestItem> = MemPool::new();
async fn test_push_and_pop() {
let (mut pool, handle) = MemPool::new(10);
handle.push(1).await.unwrap();
let item = pool.pop();
assert_eq!(item, Some(1));
assert_eq!(pool.pop(), None);
}
#[test]
fn test_mempool_new() {
let pool: MemPool<TestItem> = MemPool::new();
assert!(pool.is_empty());
assert_eq!(pool.len(), 0);
async fn test_multiple_push_pop() {
let (mut pool, handle) = MemPool::new(10);
handle.push(1).await.unwrap();
handle.push(2).await.unwrap();
handle.push(3).await.unwrap();
assert_eq!(pool.pop(), Some(1));
assert_eq!(pool.pop(), Some(2));
assert_eq!(pool.pop(), Some(3));
assert_eq!(pool.pop(), None);
}
#[test]
fn test_push_item() {
let mut pool = MemPool::new();
pool.push_item(test_item_with_id(1));
assert!(!pool.is_empty());
assert_eq!(pool.len(), 1);
async fn test_pop_empty() {
let (mut pool, _handle): (MemPool<u64>, _) = MemPool::new(10);
assert_eq!(pool.pop(), None);
}
#[test]
fn test_pop_last() {
let mut pool = MemPool::new();
pool.push_item(test_item_with_id(1));
pool.push_item(test_item_with_id(2));
let item = pool.pop_last();
assert_eq!(item, Some(test_item_with_id(1)));
assert_eq!(pool.len(), 1);
}
async fn test_max_size() {
let (mut pool, handle) = MemPool::new(2);
#[test]
fn test_peek_last() {
let mut pool = MemPool::new();
pool.push_item(test_item_with_id(1));
pool.push_item(test_item_with_id(2));
let item = pool.peek_last();
assert_eq!(item, Some(&test_item_with_id(1)));
}
handle.push(1).await.unwrap();
handle.push(2).await.unwrap();
#[test]
fn test_pop_size() {
let mut pool = MemPool::new();
pool.push_item(test_item_with_id(1));
pool.push_item(test_item_with_id(2));
pool.push_item(test_item_with_id(3));
let items = pool.pop_size(2);
assert_eq!(items, vec![test_item_with_id(1), test_item_with_id(2)]);
assert_eq!(pool.len(), 1);
}
#[test]
fn test_drain_size() {
let mut pool = MemPool::new();
pool.push_item(test_item_with_id(1));
pool.push_item(test_item_with_id(2));
pool.push_item(test_item_with_id(3));
pool.push_item(test_item_with_id(4));
let items = pool.drain_size(2);
assert_eq!(items, vec![test_item_with_id(1), test_item_with_id(2)]);
assert_eq!(pool.len(), 2);
}
#[test]
fn test_default() {
let pool: MemPool<TestItem> = MemPool::default();
assert!(pool.is_empty());
assert_eq!(pool.len(), 0);
}
#[test]
fn test_is_empty() {
let mut pool = MemPool::new();
assert!(pool.is_empty());
pool.push_item(test_item_with_id(1));
assert!(!pool.is_empty());
}
#[test]
fn test_push_pop() {
let mut mempool: MemPool<TestItem> = MemPool::new();
let items = vec![
test_item_with_id(1),
test_item_with_id(2),
test_item_with_id(3),
];
for item in items {
mempool.push_item(item);
}
assert_eq!(mempool.len(), 3);
let item = mempool.pop_last();
assert_eq!(item, Some(TestItem { id: 1 }));
assert_eq!(mempool.len(), 2);
let item = mempool.pop_last();
assert_eq!(item, Some(TestItem { id: 2 }));
assert_eq!(mempool.len(), 1);
let item = mempool.pop_last();
assert_eq!(item, Some(TestItem { id: 3 }));
assert_eq!(mempool.len(), 0);
let item = mempool.pop_last();
assert_eq!(item, None);
}
#[test]
fn test_pop_many() {
let mut mempool: MemPool<TestItem> = MemPool::new();
let mut items = vec![];
for i in 1..11 {
items.push(test_item_with_id(i));
}
for item in items {
mempool.push_item(item);
}
assert_eq!(mempool.len(), 10);
let items1 = mempool.pop_size(4);
assert_eq!(
items1,
vec![
test_item_with_id(1),
test_item_with_id(2),
test_item_with_id(3),
test_item_with_id(4)
]
);
assert_eq!(mempool.len(), 6);
let items2 = mempool.drain_size(2);
assert_eq!(
items2,
vec![
test_item_with_id(5),
test_item_with_id(6),
test_item_with_id(7),
test_item_with_id(8)
]
);
assert_eq!(mempool.len(), 2);
// This should block if buffer is full, but we'll use try_send in a real scenario
// For now, just verify we can pop items
assert_eq!(pool.pop(), Some(1));
assert_eq!(pool.pop(), Some(2));
}
}

View File

@ -1,4 +0,0 @@
pub trait MemPoolItem {
type Identifier;
fn identifier(&self) -> Self::Identifier;
}

View File

@ -1,11 +0,0 @@
[package]
name = "networking"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true
serde.workspace = true

View File

@ -1,5 +0,0 @@
pub mod network_protocol;
pub mod peer;
pub mod peer_manager;
pub mod rate_limiter;
pub mod tcp;

Some files were not shown because too many files have changed in this diff Show More